Page MenuHomec4science

No OneTemporary

File Metadata

Created
Sat, May 25, 18:56
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/LICENSE b/LICENSE
index a0c2723a0..f9489c8cf 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,350 +1,350 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom
to share and change it. By contrast, the GNU General Public License is
intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on,
we want its recipients to know that what they have is not the
original, so that any problems introduced by others will not reflect
on the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at
all.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a
notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the Program
(independent of having been made by running the Program). Whether that
is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy an appropriate copyright notice
and disclaimer of warranty; keep intact all the notices that refer to
this License and to the absence of any warranty; and give any other
recipients of the Program a copy of this License along with the
Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Program or any portion of
it, thus forming a work based on the Program, and copy and distribute
such modifications or work under the terms of Section 1 above,
provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that
in whole or in part contains or is derived from the Program or
any part thereof, to be licensed as a whole at no charge to all
third parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you
provide a warranty) and that users may redistribute the program
under these conditions, and telling the user how to view a copy
of this License. (Exception: if the Program itself is interactive
but does not normally print such an announcement, your work based
on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Sections 1 and 2 above on a medium customarily used for software
interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt otherwise
to copy, modify, sublicense or distribute the Program is void, and
will automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted
herein. You are not responsible for enforcing compliance by third
parties to this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new
versions of the General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Program does not specify a
version number of this License, you may choose any version ever
published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the
author to ask for permission. For software which is copyrighted by the
Free Software Foundation, write to the Free Software Foundation; we
sometimes make exceptions for this. Our decision will be guided by the
two goals of preserving the free status of all derivatives of our free
software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS
AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does.
Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'. This is free software, and you are welcome
to redistribute it under certain conditions; type `show c'
for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the program,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright
interest in the program `Gnomovision'
(which makes passes at compilers) written
by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library,
you may consider it more useful to permit linking proprietary
applications with the library. If this is what you want to do, use the
GNU Library General Public License instead of this License.
diff --git a/bench/FERMI/README b/bench/FERMI/README
index db3f527bd..b66e56077 100644
--- a/bench/FERMI/README
+++ b/bench/FERMI/README
@@ -1,103 +1,51 @@
These are input scripts used to run versions of several of the
-benchmarks in the top-level bench directory using the GPU and
-USER-CUDA accelerator packages. The results of running these scripts
-on two different machines (a desktop with 2 Tesla GPUs and the ORNL
-Titan supercomputer) are shown on the "GPU (Fermi)" section of the
-Benchmark page of the LAMMPS WWW site: lammps.sandia.gov/bench.
+benchmarks in the top-level bench directory using the GPU accelerator
+package. The results of running these scripts on two different machines
+(a desktop with 2 Tesla GPUs and the ORNL Titan supercomputer) are shown
+on the "GPU (Fermi)" section of the Benchmark page of the LAMMPS WWW
+site: lammps.sandia.gov/bench.
Examples are shown below of how to run these scripts. This assumes
-you have built 3 executables with both the GPU and USER-CUDA packages
+you have built 3 executables with the GPU package
installed, e.g.
lmp_linux_single
lmp_linux_mixed
lmp_linux_double
-The precision (single, mixed, double) refers to the GPU and USER-CUDA
-package precision. See the README files in the lib/gpu and lib/cuda
-directories for instructions on how to build the packages with
-different precisions. The GPU and USER-CUDA sub-sections of the
-doc/Section_accelerate.html file also describes this process.
-
-Make.py -d ~/lammps -j 16 -p #all orig -m linux -o cpu -a exe
-Make.py -d ~/lammps -j 16 -p #all opt orig -m linux -o opt -a exe
-Make.py -d ~/lammps -j 16 -p #all omp orig -m linux -o omp -a exe
-Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \
- -gpu mode=double arch=20 -o gpu_double -a libs exe
-Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \
- -gpu mode=mixed arch=20 -o gpu_mixed -a libs exe
-Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \
- -gpu mode=single arch=20 -o gpu_single -a libs exe
-Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \
- -cuda mode=double arch=20 -o cuda_double -a libs exe
-Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \
- -cuda mode=mixed arch=20 -o cuda_mixed -a libs exe
-Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \
- -cuda mode=single arch=20 -o cuda_single -a libs exe
-Make.py -d ~/lammps -j 16 -p #all intel orig -m linux -o intel_cpu -a exe
-Make.py -d ~/lammps -j 16 -p #all kokkos orig -m linux -o kokkos_omp -a exe
-Make.py -d ~/lammps -j 16 -p #all kokkos orig -kokkos cuda arch=20 \
- -m cuda -o kokkos_cuda -a exe
-
-Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \
- -gpu mode=double arch=20 -cuda mode=double arch=20 -m linux \
- -o all -a libs exe
-
-Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \
- -kokkos cuda arch=20 -gpu mode=double arch=20 \
- -cuda mode=double arch=20 -m cuda -o all_cuda -a libs exe
-
------------------------------------------------------------------------
-To run on just CPUs (without using the GPU or USER-CUDA styles),
+To run on just CPUs (without using the GPU styles),
do something like the following:
mpirun -np 1 lmp_linux_double -v x 8 -v y 8 -v z 8 -v t 100 < in.lj
mpirun -np 12 lmp_linux_double -v x 16 -v y 16 -v z 16 -v t 100 < in.eam
The "xyz" settings determine the problem size. The "t" setting
determines the number of timesteps.
These mpirun commands run on a single node. To run on multiple
nodes, scale up the "-np" setting.
------------------------------------------------------------------------
To run with the GPU package, do something like the following:
mpirun -np 12 lmp_linux_single -sf gpu -v x 32 -v y 32 -v z 64 -v t 100 < in.lj
mpirun -np 8 lmp_linux_mixed -sf gpu -pk gpu 2 -v x 32 -v y 32 -v z 64 -v t 100 < in.eam
The "xyz" settings determine the problem size. The "t" setting
determines the number of timesteps. The "np" setting determines how
many MPI tasks (per node) the problem will run on. The numeric
argument to the "-pk" setting is the number of GPUs (per node); 1 GPU
is the default. Note that you can use more MPI tasks than GPUs (per
node) with the GPU package.
These mpirun commands run on a single node. To run on multiple nodes,
scale up the "-np" setting, and control the number of MPI tasks per
node via a "-ppn" setting.
------------------------------------------------------------------------
-To run with the USER-CUDA package, do something like the following:
-
-mpirun -np 1 lmp_linux_single -c on -sf cuda -v x 16 -v y 16 -v z 16 -v t 100 < in.lj
-mpirun -np 2 lmp_linux_double -c on -sf cuda -pk cuda 2 -v x 32 -v y 64 -v z 64 -v t 100 < in.eam
-
-The "xyz" settings determine the problem size. The "t" setting
-determines the number of timesteps. The "np" setting determines how
-many MPI tasks (per node) the problem will run on. The numeric
-argument to the "-pk" setting is the number of GPUs (per node); 1 GPU
-is the default. Note that the number of MPI tasks must equal the
-number of GPUs (both per node) with the USER-CUDA package.
-
-These mpirun commands run on a single node. To run on multiple nodes,
-scale up the "-np" setting, and control the number of MPI tasks per
-node via a "-ppn" setting.
-
-------------------------------------------------------------------------
-
If the script has "titan" in its name, it was run on the Titan
supercomputer at ORNL.
diff --git a/bench/README b/bench/README
index 85d71cbb5..0806fcded 100644
--- a/bench/README
+++ b/bench/README
@@ -1,127 +1,111 @@
LAMMPS benchmark problems
This directory contains 5 benchmark problems which are discussed in
the Benchmark section of the LAMMPS documentation, and on the
Benchmark page of the LAMMPS WWW site (lammps.sandia.gov/bench).
This directory also has several sub-directories:
FERMI benchmark scripts for desktop machine with Fermi GPUs (Tesla)
KEPLER benchmark scripts for GPU cluster with Kepler GPUs
POTENTIALS benchmarks scripts for various potentials in LAMMPS
The results for all of these benchmarks are displayed and discussed on
the Benchmark page of the LAMMPS WWW site: lammps.sandia.gov/bench.
The remainder of this file refers to the 5 problems in the top-level
of this directory and how to run them on CPUs, either in serial or
parallel. The sub-directories have their own README files which you
should refer to before running those scripts.
----------------------------------------------------------------------
Each of the 5 problems has 32,000 atoms and runs for 100 timesteps.
Each can be run as a serial benchmark (on one processor) or in
parallel. In parallel, each benchmark can be run as a fixed-size or
scaled-size problem. For fixed-size benchmarking, the same 32K atom
problem is run on various numbers of processors. For scaled-size
benchmarking, the model size is increased with the number of
processors. E.g. on 8 processors, a 256K-atom problem is run; on 1024
processors, a 32-million atom problem is run, etc.
A few sample log file outputs on different machines and different
numbers of processors are included in this directory to compare your
answers to. E.g. a log file like log.date.chain.lmp.scaled.foo.P is
for a scaled-size version of the Chain benchmark, run on P processors
of machine "foo" with the dated version of LAMMPS. Note that the Eam
and Lj benchmarks may not give identical answers on different machines
because of the "velocity loop geom" option that assigns velocities
based on atom coordinates - see the discussion in the documentation
for the velocity command for details.
The CPU time (in seconds) for the run is in the "Loop time" line
of the log files, e.g.
Loop time of 3.89418 on 8 procs for 100 steps with 32000 atoms
Timing results for these problems run on various machines are listed
on the Benchmarks page of the LAMMPS WWW Site.
----------------------------------------------------------------------
These are the 5 benchmark problems:
LJ = atomic fluid, Lennard-Jones potential with 2.5 sigma cutoff (55
neighbors per atom), NVE integration
Chain = bead-spring polymer melt of 100-mer chains, FENE bonds and LJ
pairwise interactions with a 2^(1/6) sigma cutoff (5 neighbors per
atom), NVE integration
EAM = metallic solid, Cu EAM potential with 4.95 Angstrom cutoff (45
neighbors per atom), NVE integration
Chute = granular chute flow, frictional history potential with 1.1
sigma cutoff (7 neighbors per atom), NVE integration
Rhodo = rhodopsin protein in solvated lipid bilayer, CHARMM force
field with a 10 Angstrom LJ cutoff (440 neighbors per atom),
particle-particle particle-mesh (PPPM) for long-range Coulombics, NPT
integration
----------------------------------------------------------------------
-Here is a src/Make.py command which will perform a parallel build of a
-LAMMPS executable "lmp_mpi" with all the packages needed by all the
-examples. This assumes you have an MPI installed on your machine so
-that "mpicxx" can be used as the wrapper compiler. It also assumes
-you have an Intel compiler to use as the base compiler. You can leave
-off the "-cc mpi wrap=icc" switch if that is not the case. You can
-also leave off the "-fft fftw3" switch if you do not have the FFTW
-(v3) installed as an FFT package, in which case the default KISS FFT
-library will be used.
-
-cd src
-Make.py -j 16 -p none molecule manybody kspace granular rigid orig \
- -cc mpi wrap=icc -fft fftw3 -a file mpi
-
-----------------------------------------------------------------------
-
Here is how to run each problem, assuming the LAMMPS executable is
named lmp_mpi, and you are using the mpirun command to launch parallel
runs:
Serial (one processor runs):
-lmp_mpi < in.lj
-lmp_mpi < in.chain
-lmp_mpi < in.eam
-lmp_mpi < in.chute
-lmp_mpi < in.rhodo
+lmp_mpi -in in.lj
+lmp_mpi -in in.chain
+lmp_mpi -in in.eam
+lmp_mpi -in in.chute
+lmp_mpi -in in.rhodo
Parallel fixed-size runs (on 8 procs in this case):
-mpirun -np 8 lmp_mpi < in.lj
-mpirun -np 8 lmp_mpi < in.chain
-mpirun -np 8 lmp_mpi < in.eam
-mpirun -np 8 lmp_mpi < in.chute
-mpirun -np 8 lmp_mpi < in.rhodo
+mpirun -np 8 lmp_mpi -in in.lj
+mpirun -np 8 lmp_mpi -in in.chain
+mpirun -np 8 lmp_mpi -in in.eam
+mpirun -np 8 lmp_mpi -in in.chute
+mpirun -np 8 lmp_mpi -in in.rhodo
Parallel scaled-size runs (on 16 procs in this case):
-mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.lj
-mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.chain.scaled
-mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.eam
-mpirun -np 16 lmp_mpi -var x 4 -var y 4 < in.chute.scaled
-mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.rhodo.scaled
+mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.lj
+mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.chain.scaled
+mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.eam
+mpirun -np 16 lmp_mpi -var x 4 -var y 4 -in in.chute.scaled
+mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.rhodo.scaled
For each of the scaled-size runs you must set 3 variables as -var
command line switches. The variables x,y,z are used in the input
scripts to scale up the problem size in each dimension. Imagine the P
processors arrayed as a 3d grid, so that P = Px * Py * Pz. For P =
16, you might use Px = 2, Py = 2, Pz = 4. To scale up equally in all
dimensions you roughly want Px = Py = Pz. Using the var switches, set
x = Px, y = Py, and z = Pz.
For Chute runs, you must have Pz = 1. Therefore P = Px * Py and you
only need to set variables x and y.
diff --git a/doc/src/Manual.txt b/doc/src/Manual.txt
index 36391731d..07f0c8df4 100644
--- a/doc/src/Manual.txt
+++ b/doc/src/Manual.txt
@@ -1,339 +1,338 @@
<!-- HTML_ONLY -->
<HEAD>
<TITLE>LAMMPS Users Manual</TITLE>
-<META NAME="docnumber" CONTENT="6 Jul 2017 version">
+<META NAME="docnumber" CONTENT="24 Jul 2017 version">
<META NAME="author" CONTENT="http://lammps.sandia.gov - Sandia National Laboratories">
<META NAME="copyright" CONTENT="Copyright (2003) Sandia Corporation. This software and manual is distributed under the GNU General Public License.">
</HEAD>
<BODY>
<!-- END_HTML_ONLY -->
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
<H1></H1>
LAMMPS Documentation :c,h3
-6 Jul 2017 version :c,h4
+24 Jul 2017 version :c,h4
Version info: :h4
The LAMMPS "version" is the date when it was released, such as 1 May
2010. LAMMPS is updated continuously. Whenever we fix a bug or add a
feature, we release it immediately, and post a notice on "this page of
the WWW site"_bug. Every 2-4 months one of the incremental releases
is subjected to more thorough testing and labeled as a {stable} version.
Each dated copy of LAMMPS contains all the
features and bug-fixes up to and including that version date. The
version date is printed to the screen and logfile every time you run
LAMMPS. It is also in the file src/version.h and in the LAMMPS
directory name created when you unpack a tarball, and at the top of
the first page of the manual (this page).
If you browse the HTML doc pages on the LAMMPS WWW site, they always
describe the most current [development] version of LAMMPS. :ulb,l
If you browse the HTML doc pages included in your tarball, they
describe the version you have. :l
The "PDF file"_Manual.pdf on the WWW site or in the tarball is updated
about once per month. This is because it is large, and we don't want
it to be part of every patch. :l
There is also a "Developer.pdf"_Developer.pdf file in the doc
directory, which describes the internal structure and algorithms of
LAMMPS. :l
:ule
LAMMPS stands for Large-scale Atomic/Molecular Massively Parallel
Simulator.
LAMMPS is a classical molecular dynamics simulation code designed to
run efficiently on parallel computers. It was developed at Sandia
National Laboratories, a US Department of Energy facility, with
funding from the DOE. It is an open-source code, distributed freely
under the terms of the GNU Public License (GPL).
The current core group of LAMMPS developers is at Sandia National
Labs and Temple University:
"Steve Plimpton"_sjp, sjplimp at sandia.gov :ulb,l
Aidan Thompson, athomps at sandia.gov :l
Stan Moore, stamoor at sandia.gov :l
"Axel Kohlmeyer"_ako, akohlmey at gmail.com :l
:ule
Past core developers include Paul Crozier, Ray Shan and Mark Stevens,
all at Sandia. The [LAMMPS home page] at
"http://lammps.sandia.gov"_http://lammps.sandia.gov has more information
about the code and its uses. Interaction with external LAMMPS developers,
bug reports and feature requests are mainly coordinated through the
"LAMMPS project on GitHub."_https://github.com/lammps/lammps
The lammps.org domain, currently hosting "public continuous integration
testing"_https://ci.lammps.org/job/lammps/ and "precompiled Linux
RPM and Windows installer packages"_http://rpm.lammps.org is located
at Temple University and managed by Richard Berger,
richard.berger at temple.edu.
:link(bug,http://lammps.sandia.gov/bug.html)
:link(sjp,http://www.sandia.gov/~sjplimp)
:link(ako,http://goo.gl/1wk0)
:line
The LAMMPS documentation is organized into the following sections. If
you find errors or omissions in this manual or have suggestions for
useful information to add, please send an email to the developers so
we can improve the LAMMPS documentation.
Once you are familiar with LAMMPS, you may want to bookmark "this
page"_Section_commands.html#comm at Section_commands.html#comm since
it gives quick access to documentation for all LAMMPS commands.
"PDF file"_Manual.pdf of the entire manual, generated by
"htmldoc"_http://freecode.com/projects/htmldoc
<!-- RST
.. toctree::
:maxdepth: 2
:numbered:
:caption: User Documentation
:name: userdoc
:includehidden:
Section_intro
Section_start
Section_commands
Section_packages
Section_accelerate
Section_howto
Section_example
Section_perf
Section_tools
Section_modify
Section_python
Section_errors
Section_history
.. toctree::
:caption: Index
:name: index
:hidden:
tutorials
commands
fixes
computes
pairs
bonds
angles
dihedrals
impropers
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
END_RST -->
<!-- HTML_ONLY -->
"Introduction"_Section_intro.html :olb,l
1.1 "What is LAMMPS"_intro_1 :ulb,b
1.2 "LAMMPS features"_intro_2 :b
1.3 "LAMMPS non-features"_intro_3 :b
1.4 "Open source distribution"_intro_4 :b
1.5 "Acknowledgments and citations"_intro_5 :ule,b
"Getting started"_Section_start.html :l
2.1 "What's in the LAMMPS distribution"_start_1 :ulb,b
2.2 "Making LAMMPS"_start_2 :b
2.3 "Making LAMMPS with optional packages"_start_3 :b
2.4 "Building LAMMPS as a library"_start_4 :b
2.5 "Running LAMMPS"_start_5 :b
2.6 "Command-line options"_start_6 :b
2.7 "Screen output"_start_7 :b
2.8 "Tips for users of previous versions"_start_8 :ule,b
"Commands"_Section_commands.html :l
3.1 "LAMMPS input script"_cmd_1 :ulb,b
3.2 "Parsing rules"_cmd_2 :b
3.3 "Input script structure"_cmd_3 :b
3.4 "Commands listed by category"_cmd_4 :b
3.5 "Commands listed alphabetically"_cmd_5 :ule,b
"Packages"_Section_packages.html :l
4.1 "Standard packages"_pkg_1 :ulb,b
4.2 "User packages"_pkg_2 :ule,b
"Accelerating LAMMPS performance"_Section_accelerate.html :l
5.1 "Measuring performance"_acc_1 :ulb,b
5.2 "Algorithms and code options to boost performace"_acc_2 :b
5.3 "Accelerator packages with optimized styles"_acc_3 :b
5.3.1 "GPU package"_accelerate_gpu.html :ulb,b
5.3.2 "USER-INTEL package"_accelerate_intel.html :b
5.3.3 "KOKKOS package"_accelerate_kokkos.html :b
5.3.4 "USER-OMP package"_accelerate_omp.html :b
5.3.5 "OPT package"_accelerate_opt.html :ule,b
5.4 "Comparison of various accelerator packages"_acc_4 :ule,b
"How-to discussions"_Section_howto.html :l
6.1 "Restarting a simulation"_howto_1 :ulb,b
6.2 "2d simulations"_howto_2 :b
6.3 "CHARMM and AMBER force fields"_howto_3 :b
6.4 "Running multiple simulations from one input script"_howto_4 :b
6.5 "Multi-replica simulations"_howto_5 :b
6.6 "Granular models"_howto_6 :b
6.7 "TIP3P water model"_howto_7 :b
6.8 "TIP4P water model"_howto_8 :b
6.9 "SPC water model"_howto_9 :b
6.10 "Coupling LAMMPS to other codes"_howto_10 :b
6.11 "Visualizing LAMMPS snapshots"_howto_11 :b
6.12 "Triclinic (non-orthogonal) simulation boxes"_howto_12 :b
6.13 "NEMD simulations"_howto_13 :b
6.14 "Finite-size spherical and aspherical particles"_howto_14 :b
6.15 "Output from LAMMPS (thermo, dumps, computes, fixes, variables)"_howto_15 :b
6.16 "Thermostatting, barostatting, and compute temperature"_howto_16 :b
6.17 "Walls"_howto_17 :b
6.18 "Elastic constants"_howto_18 :b
6.19 "Library interface to LAMMPS"_howto_19 :b
6.20 "Calculating thermal conductivity"_howto_20 :b
6.21 "Calculating viscosity"_howto_21 :b
6.22 "Calculating a diffusion coefficient"_howto_22 :b
6.23 "Using chunks to calculate system properties"_howto_23 :b
6.24 "Setting parameters for pppm/disp"_howto_24 :b
6.25 "Polarizable models"_howto_25 :b
6.26 "Adiabatic core/shell model"_howto_26 :b
6.27 "Drude induced dipoles"_howto_27 :ule,b
"Example problems"_Section_example.html :l
"Performance & scalability"_Section_perf.html :l
"Additional tools"_Section_tools.html :l
"Modifying & extending LAMMPS"_Section_modify.html :l
10.1 "Atom styles"_mod_1 :ulb,b
10.2 "Bond, angle, dihedral, improper potentials"_mod_2 :b
10.3 "Compute styles"_mod_3 :b
10.4 "Dump styles"_mod_4 :b
10.5 "Dump custom output options"_mod_5 :b
10.6 "Fix styles"_mod_6 :b
10.7 "Input script commands"_mod_7 :b
10.8 "Kspace computations"_mod_8 :b
10.9 "Minimization styles"_mod_9 :b
10.10 "Pairwise potentials"_mod_10 :b
10.11 "Region styles"_mod_11 :b
10.12 "Body styles"_mod_12 :b
10.13 "Thermodynamic output options"_mod_13 :b
10.14 "Variable options"_mod_14 :b
10.15 "Submitting new features for inclusion in LAMMPS"_mod_15 :ule,b
"Python interface"_Section_python.html :l
11.1 "Overview of running LAMMPS from Python"_py_1 :ulb,b
11.2 "Overview of using Python from a LAMMPS script"_py_2 :b
11.3 "Building LAMMPS as a shared library"_py_3 :b
11.4 "Installing the Python wrapper into Python"_py_4 :b
11.5 "Extending Python with MPI to run in parallel"_py_5 :b
11.6 "Testing the Python-LAMMPS interface"_py_6 :b
11.7 "Using LAMMPS from Python"_py_7 :b
11.8 "Example Python scripts that use LAMMPS"_py_8 :ule,b
"Errors"_Section_errors.html :l
12.1 "Common problems"_err_1 :ulb,b
12.2 "Reporting bugs"_err_2 :b
12.3 "Error & warning messages"_err_3 :ule,b
"Future and history"_Section_history.html :l
13.1 "Coming attractions"_hist_1 :ulb,b
13.2 "Past versions"_hist_2 :ule,b
:ole
:link(intro_1,Section_intro.html#intro_1)
:link(intro_2,Section_intro.html#intro_2)
:link(intro_3,Section_intro.html#intro_3)
:link(intro_4,Section_intro.html#intro_4)
:link(intro_5,Section_intro.html#intro_5)
:link(start_1,Section_start.html#start_1)
:link(start_2,Section_start.html#start_2)
:link(start_3,Section_start.html#start_3)
:link(start_4,Section_start.html#start_4)
:link(start_5,Section_start.html#start_5)
:link(start_6,Section_start.html#start_6)
:link(start_7,Section_start.html#start_7)
:link(start_8,Section_start.html#start_8)
-:link(start_9,Section_start.html#start_9)
:link(cmd_1,Section_commands.html#cmd_1)
:link(cmd_2,Section_commands.html#cmd_2)
:link(cmd_3,Section_commands.html#cmd_3)
:link(cmd_4,Section_commands.html#cmd_4)
:link(cmd_5,Section_commands.html#cmd_5)
:link(pkg_1,Section_packages.html#pkg_1)
:link(pkg_2,Section_packages.html#pkg_2)
:link(acc_1,Section_accelerate.html#acc_1)
:link(acc_2,Section_accelerate.html#acc_2)
:link(acc_3,Section_accelerate.html#acc_3)
:link(acc_4,Section_accelerate.html#acc_4)
:link(howto_1,Section_howto.html#howto_1)
:link(howto_2,Section_howto.html#howto_2)
:link(howto_3,Section_howto.html#howto_3)
:link(howto_4,Section_howto.html#howto_4)
:link(howto_5,Section_howto.html#howto_5)
:link(howto_6,Section_howto.html#howto_6)
:link(howto_7,Section_howto.html#howto_7)
:link(howto_8,Section_howto.html#howto_8)
:link(howto_9,Section_howto.html#howto_9)
:link(howto_10,Section_howto.html#howto_10)
:link(howto_11,Section_howto.html#howto_11)
:link(howto_12,Section_howto.html#howto_12)
:link(howto_13,Section_howto.html#howto_13)
:link(howto_14,Section_howto.html#howto_14)
:link(howto_15,Section_howto.html#howto_15)
:link(howto_16,Section_howto.html#howto_16)
:link(howto_17,Section_howto.html#howto_17)
:link(howto_18,Section_howto.html#howto_18)
:link(howto_19,Section_howto.html#howto_19)
:link(howto_20,Section_howto.html#howto_20)
:link(howto_21,Section_howto.html#howto_21)
:link(howto_22,Section_howto.html#howto_22)
:link(howto_23,Section_howto.html#howto_23)
:link(howto_24,Section_howto.html#howto_24)
:link(howto_25,Section_howto.html#howto_25)
:link(howto_26,Section_howto.html#howto_26)
:link(howto_27,Section_howto.html#howto_27)
:link(mod_1,Section_modify.html#mod_1)
:link(mod_2,Section_modify.html#mod_2)
:link(mod_3,Section_modify.html#mod_3)
:link(mod_4,Section_modify.html#mod_4)
:link(mod_5,Section_modify.html#mod_5)
:link(mod_6,Section_modify.html#mod_6)
:link(mod_7,Section_modify.html#mod_7)
:link(mod_8,Section_modify.html#mod_8)
:link(mod_9,Section_modify.html#mod_9)
:link(mod_10,Section_modify.html#mod_10)
:link(mod_11,Section_modify.html#mod_11)
:link(mod_12,Section_modify.html#mod_12)
:link(mod_13,Section_modify.html#mod_13)
:link(mod_14,Section_modify.html#mod_14)
:link(mod_15,Section_modify.html#mod_15)
:link(py_1,Section_python.html#py_1)
:link(py_2,Section_python.html#py_2)
:link(py_3,Section_python.html#py_3)
:link(py_4,Section_python.html#py_4)
:link(py_5,Section_python.html#py_5)
:link(py_6,Section_python.html#py_6)
:link(err_1,Section_errors.html#err_1)
:link(err_2,Section_errors.html#err_2)
:link(err_3,Section_errors.html#err_3)
:link(hist_1,Section_history.html#hist_1)
:link(hist_2,Section_history.html#hist_2)
<!-- END_HTML_ONLY -->
</BODY>
diff --git a/doc/src/PDF/colvars-refman-lammps.pdf b/doc/src/PDF/colvars-refman-lammps.pdf
index 37201275f..a14d93cd6 100644
Binary files a/doc/src/PDF/colvars-refman-lammps.pdf and b/doc/src/PDF/colvars-refman-lammps.pdf differ
diff --git a/doc/src/Section_accelerate.txt b/doc/src/Section_accelerate.txt
index 64b80c1a5..881235888 100644
--- a/doc/src/Section_accelerate.txt
+++ b/doc/src/Section_accelerate.txt
@@ -1,391 +1,391 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
Section"_Section_howto.html :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
5. Accelerating LAMMPS performance :h3
This section describes various methods for improving LAMMPS
performance for different classes of problems running on different
kinds of machines.
There are two thrusts to the discussion that follows. The
first is using code options that implement alternate algorithms
that can speed-up a simulation. The second is to use one
of the several accelerator packages provided with LAMMPS that
contain code optimized for certain kinds of hardware, including
multi-core CPUs, GPUs, and Intel Xeon Phi coprocessors.
5.1 "Measuring performance"_#acc_1 :ulb,l
5.2 "Algorithms and code options to boost performace"_#acc_2 :l
5.3 "Accelerator packages with optimized styles"_#acc_3 :l
5.3.1 "GPU package"_accelerate_gpu.html :l
5.3.2 "USER-INTEL package"_accelerate_intel.html :l
5.3.3 "KOKKOS package"_accelerate_kokkos.html :l
5.3.4 "USER-OMP package"_accelerate_omp.html :l
5.3.5 "OPT package"_accelerate_opt.html :l
5.4 "Comparison of various accelerator packages"_#acc_4 :l
:ule
The "Benchmark page"_http://lammps.sandia.gov/bench.html of the LAMMPS
web site gives performance results for the various accelerator
packages discussed in Section 5.2, for several of the standard LAMMPS
benchmark problems, as a function of problem size and number of
compute nodes, on different hardware platforms.
:line
:line
5.1 Measuring performance :h4,link(acc_1)
Before trying to make your simulation run faster, you should
understand how it currently performs and where the bottlenecks are.
The best way to do this is run the your system (actual number of
atoms) for a modest number of timesteps (say 100 steps) on several
different processor counts, including a single processor if possible.
Do this for an equilibrium version of your system, so that the
100-step timings are representative of a much longer run. There is
typically no need to run for 1000s of timesteps to get accurate
timings; you can simply extrapolate from short runs.
For the set of runs, look at the timing data printed to the screen and
log file at the end of each LAMMPS run. "This
-section"_Section_start.html#start_8 of the manual has an overview.
+section"_Section_start.html#start_7 of the manual has an overview.
Running on one (or a few processors) should give a good estimate of
the serial performance and what portions of the timestep are taking
the most time. Running the same problem on a few different processor
counts should give an estimate of parallel scalability. I.e. if the
simulation runs 16x faster on 16 processors, its 100% parallel
efficient; if it runs 8x faster on 16 processors, it's 50% efficient.
The most important data to look at in the timing info is the timing
breakdown and relative percentages. For example, trying different
options for speeding up the long-range solvers will have little impact
if they only consume 10% of the run time. If the pairwise time is
dominating, you may want to look at GPU or OMP versions of the pair
style, as discussed below. Comparing how the percentages change as
you increase the processor count gives you a sense of how different
operations within the timestep are scaling. Note that if you are
running with a Kspace solver, there is additional output on the
breakdown of the Kspace time. For PPPM, this includes the fraction
spent on FFTs, which can be communication intensive.
Another important detail in the timing info are the histograms of
atoms counts and neighbor counts. If these vary widely across
processors, you have a load-imbalance issue. This often results in
inaccurate relative timing data, because processors have to wait when
communication occurs for other processors to catch up. Thus the
reported times for "Communication" or "Other" may be higher than they
really are, due to load-imbalance. If this is an issue, you can
uncomment the MPI_Barrier() lines in src/timer.cpp, and recompile
LAMMPS, to obtain synchronized timings.
:line
5.2 General strategies :h4,link(acc_2)
NOTE: this section 5.2 is still a work in progress
Here is a list of general ideas for improving simulation performance.
Most of them are only applicable to certain models and certain
bottlenecks in the current performance, so let the timing data you
generate be your guide. It is hard, if not impossible, to predict how
much difference these options will make, since it is a function of
problem size, number of processors used, and your machine. There is
no substitute for identifying performance bottlenecks, and trying out
various options.
rRESPA
2-FFT PPPM
Staggered PPPM
single vs double PPPM
partial charge PPPM
verlet/split run style
processor command for proc layout and numa layout
load-balancing: balance and fix balance :ul
2-FFT PPPM, also called {analytic differentiation} or {ad} PPPM, uses
2 FFTs instead of the 4 FFTs used by the default {ik differentiation}
PPPM. However, 2-FFT PPPM also requires a slightly larger mesh size to
achieve the same accuracy as 4-FFT PPPM. For problems where the FFT
cost is the performance bottleneck (typically large problems running
on many processors), 2-FFT PPPM may be faster than 4-FFT PPPM.
Staggered PPPM performs calculations using two different meshes, one
shifted slightly with respect to the other. This can reduce force
aliasing errors and increase the accuracy of the method, but also
doubles the amount of work required. For high relative accuracy, using
staggered PPPM allows one to half the mesh size in each dimension as
compared to regular PPPM, which can give around a 4x speedup in the
kspace time. However, for low relative accuracy, using staggered PPPM
gives little benefit and can be up to 2x slower in the kspace
time. For example, the rhodopsin benchmark was run on a single
processor, and results for kspace time vs. relative accuracy for the
different methods are shown in the figure below. For this system,
staggered PPPM (using ik differentiation) becomes useful when using a
relative accuracy of slightly greater than 1e-5 and above.
:c,image(JPG/rhodo_staggered.jpg)
NOTE: Using staggered PPPM may not give the same increase in accuracy
of energy and pressure as it does in forces, so some caution must be
used if energy and/or pressure are quantities of interest, such as
when using a barostat.
:line
5.3 Packages with optimized styles :h4,link(acc_3)
Accelerated versions of various "pair_style"_pair_style.html,
"fixes"_fix.html, "computes"_compute.html, and other commands have
been added to LAMMPS, which will typically run faster than the
standard non-accelerated versions. Some require appropriate hardware
to be present on your system, e.g. GPUs or Intel Xeon Phi
coprocessors.
All of these commands are in packages provided with LAMMPS. An
overview of packages is give in "Section
packages"_Section_packages.html.
These are the accelerator packages
currently in LAMMPS, either as standard or user packages:
"GPU Package"_accelerate_gpu.html : for NVIDIA GPUs as well as OpenCL support
"USER-INTEL Package"_accelerate_intel.html : for Intel CPUs and Intel Xeon Phi
"KOKKOS Package"_accelerate_kokkos.html : for Nvidia GPUs, Intel Xeon Phi, and OpenMP threading
"USER-OMP Package"_accelerate_omp.html : for OpenMP threading and generic CPU optimizations
"OPT Package"_accelerate_opt.html : generic CPU optimizations :tb(s=:)
<!-- RST
.. toctree::
:maxdepth: 1
:hidden:
accelerate_gpu
accelerate_intel
accelerate_kokkos
accelerate_omp
accelerate_opt
END_RST -->
Inverting this list, LAMMPS currently has acceleration support for
three kinds of hardware, via the listed packages:
Many-core CPUs : "USER-INTEL"_accelerate_intel.html, "KOKKOS"_accelerate_kokkos.html, "USER-OMP"_accelerate_omp.html, "OPT"_accelerate_opt.html packages
NVIDIA GPUs : "GPU"_accelerate_gpu.html, "KOKKOS"_accelerate_kokkos.html packages
Intel Phi : "USER-INTEL"_accelerate_intel.html, "KOKKOS"_accelerate_kokkos.html packages :tb(s=:)
Which package is fastest for your hardware may depend on the size
problem you are running and what commands (accelerated and
non-accelerated) are invoked by your input script. While these doc
pages include performance guidelines, there is no substitute for
trying out the different packages appropriate to your hardware.
Any accelerated style has the same name as the corresponding standard
style, except that a suffix is appended. Otherwise, the syntax for
the command that uses the style is identical, their functionality is
the same, and the numerical results it produces should also be the
same, except for precision and round-off effects.
For example, all of these styles are accelerated variants of the
Lennard-Jones "pair_style lj/cut"_pair_lj.html:
"pair_style lj/cut/gpu"_pair_lj.html
"pair_style lj/cut/intel"_pair_lj.html
"pair_style lj/cut/kk"_pair_lj.html
"pair_style lj/cut/omp"_pair_lj.html
"pair_style lj/cut/opt"_pair_lj.html :ul
To see what accelerate styles are currently available, see
"Section 3.5"_Section_commands.html#cmd_5 of the manual. The
doc pages for individual commands (e.g. "pair lj/cut"_pair_lj.html or
"fix nve"_fix_nve.html) also list any accelerated variants available
for that style.
To use an accelerator package in LAMMPS, and one or more of the styles
it provides, follow these general steps. Details vary from package to
package and are explained in the individual accelerator doc pages,
listed above:
build the accelerator library |
only for GPU package |
install the accelerator package |
make yes-opt, make yes-user-intel, etc |
add compile/link flags to Makefile.machine in src/MAKE |
only for USER-INTEL, KOKKOS, USER-OMP, OPT packages |
re-build LAMMPS |
make machine |
prepare and test a regular LAMMPS simulation |
lmp_machine -in in.script; mpirun -np 32 lmp_machine -in in.script |
-enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_7, |
+enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_6, |
only needed for KOKKOS package |
-set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_7 or "package"_package.html command, |
+set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_6 or "package"_package.html command, |
only if defaults need to be changed |
-use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_7 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu
+use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_6 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu
:tb(c=2,s=|)
Note that the first 4 steps can be done as a single command, using the
src/Make.py tool. This tool is discussed in "Section
-2.4"_Section_start.html#start_4 of the manual, and its use is
+4"_Section_packages.html of the manual, and its use is
illustrated in the individual accelerator sections. Typically these
steps only need to be done once, to create an executable that uses one
or more accelerator packages.
The last 4 steps can all be done from the command-line when LAMMPS is
launched, without changing your input script, as illustrated in the
individual accelerator sections. Or you can add
"package"_package.html and "suffix"_suffix.html commands to your input
script.
NOTE: With a few exceptions, you can build a single LAMMPS executable
with all its accelerator packages installed. Note however that the
USER-INTEL and KOKKOS packages require you to choose one of their
hardware options when building for a specific platform. I.e. CPU or
Phi option for the USER-INTEL package. Or the OpenMP, Cuda, or Phi
option for the KOKKOS package.
These are the exceptions. You cannot build a single executable with:
both the USER-INTEL Phi and KOKKOS Phi options
the USER-INTEL Phi or Kokkos Phi option, and the GPU package :ul
See the examples/accelerate/README and make.list files for sample
Make.py commands that build LAMMPS with any or all of the accelerator
packages. As an example, here is a command that builds with all the
GPU related packages installed (GPU, KOKKOS with Cuda), including
settings to build the needed auxiliary GPU libraries for Kepler GPUs:
Make.py -j 16 -p omp gpu kokkos -cc nvcc wrap=mpi \
-gpu mode=double arch=35 -kokkos cuda arch=35 lib-all file mpi :pre
The examples/accelerate directory also has input scripts that can be
used with all of the accelerator packages. See its README file for
details.
Likewise, the bench directory has FERMI and KEPLER and PHI
sub-directories with Make.py commands and input scripts for using all
the accelerator packages on various machines. See the README files in
those dirs.
As mentioned above, the "Benchmark
page"_http://lammps.sandia.gov/bench.html of the LAMMPS web site gives
performance results for the various accelerator packages for several
of the standard LAMMPS benchmark problems, as a function of problem
size and number of compute nodes, on different hardware platforms.
Here is a brief summary of what the various packages provide. Details
are in the individual accelerator sections.
Styles with a "gpu" suffix are part of the GPU package, and can be run
on NVIDIA GPUs. The speed-up on a GPU depends on a variety of
factors, discussed in the accelerator sections. :ulb,l
Styles with an "intel" suffix are part of the USER-INTEL
package. These styles support vectorized single and mixed precision
calculations, in addition to full double precision. In extreme cases,
this can provide speedups over 3.5x on CPUs. The package also
supports acceleration in "offload" mode to Intel(R) Xeon Phi(TM)
coprocessors. This can result in additional speedup over 2x depending
on the hardware configuration. :l
Styles with a "kk" suffix are part of the KOKKOS package, and can be
run using OpenMP on multicore CPUs, on an NVIDIA GPU, or on an Intel
Xeon Phi in "native" mode. The speed-up depends on a variety of
factors, as discussed on the KOKKOS accelerator page. :l
Styles with an "omp" suffix are part of the USER-OMP package and allow
a pair-style to be run in multi-threaded mode using OpenMP. This can
be useful on nodes with high-core counts when using less MPI processes
than cores is advantageous, e.g. when running with PPPM so that FFTs
are run on fewer MPI processors or when the many MPI tasks would
overload the available bandwidth for communication. :l
Styles with an "opt" suffix are part of the OPT package and typically
speed-up the pairwise calculations of your simulation by 5-25% on a
CPU. :l
:ule
The individual accelerator package doc pages explain:
what hardware and software the accelerated package requires
how to build LAMMPS with the accelerated package
how to run with the accelerated package either via command-line switches or modifying the input script
speed-ups to expect
guidelines for best performance
restrictions :ul
:line
5.4 Comparison of various accelerator packages :h4,link(acc_4)
NOTE: this section still needs to be re-worked with additional KOKKOS
and USER-INTEL information.
The next section compares and contrasts the various accelerator
options, since there are multiple ways to perform OpenMP threading,
run on GPUs, and run on Intel Xeon Phi coprocessors.
All 3 of these packages accelerate a LAMMPS calculation using NVIDIA
hardware, but they do it in different ways.
As a consequence, for a particular simulation on specific hardware,
one package may be faster than the other. We give guidelines below,
but the best way to determine which package is faster for your input
script is to try both of them on your machine. See the benchmarking
section below for examples where this has been done.
[Guidelines for using each package optimally:]
The GPU package allows you to assign multiple CPUs (cores) to a single
GPU (a common configuration for "hybrid" nodes that contain multicore
CPU(s) and GPU(s)) and works effectively in this mode. :ulb,l
The GPU package moves per-atom data (coordinates, forces)
back-and-forth between the CPU and GPU every timestep. The
KOKKOS/CUDA package only does this on timesteps when a CPU calculation
is required (e.g. to invoke a fix or compute that is non-GPU-ized).
Hence, if you can formulate your input script to only use GPU-ized
fixes and computes, and avoid doing I/O too often (thermo output, dump
file snapshots, restart files), then the data transfer cost of the
KOKKOS/CUDA package can be very low, causing it to run faster than the
GPU package. :l
The GPU package is often faster than the KOKKOS/CUDA package, if the
number of atoms per GPU is smaller. The crossover point, in terms of
atoms/GPU at which the KOKKOS/CUDA package becomes faster depends
strongly on the pair style. For example, for a simple Lennard Jones
system the crossover (in single precision) is often about 50K-100K
atoms per GPU. When performing double precision calculations the
crossover point can be significantly smaller. :l
Both packages compute bonded interactions (bonds, angles, etc) on the
CPU. If the GPU package is running with several MPI processes
assigned to one GPU, the cost of computing the bonded interactions is
spread across more CPUs and hence the GPU package can run faster. :l
When using the GPU package with multiple CPUs assigned to one GPU, its
performance depends to some extent on high bandwidth between the CPUs
and the GPU. Hence its performance is affected if full 16 PCIe lanes
are not available for each GPU. In HPC environments this can be the
case if S2050/70 servers are used, where two devices generally share
one PCIe 2.0 16x slot. Also many multi-GPU mainboards do not provide
full 16 lanes to each of the PCIe 2.0 16x slots. :l
:ule
[Differences between the two packages:]
The GPU package accelerates only pair force, neighbor list, and PPPM
calculations. :ulb,l
The GPU package requires neighbor lists to be built on the CPU when using
exclusion lists, hybrid pair styles, or a triclinic simulation box. :l
:ule
diff --git a/doc/src/Section_errors.txt b/doc/src/Section_errors.txt
index 40e61a248..408c01d52 100644
--- a/doc/src/Section_errors.txt
+++ b/doc/src/Section_errors.txt
@@ -1,11939 +1,11939 @@
"Previous Section"_Section_python.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
Section"_Section_history.html :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
12. Errors :h3
This section describes the errors you can encounter when using LAMMPS,
either conceptually, or as printed out by the program.
12.1 "Common problems"_#err_1
12.2 "Reporting bugs"_#err_2
12.3 "Error & warning messages"_#err_3 :all(b)
:line
:line
12.1 Common problems :link(err_1),h4
If two LAMMPS runs do not produce the exact same answer on different
machines or different numbers of processors, this is typically not a
bug. In theory you should get identical answers on any number of
processors and on any machine. In practice, numerical round-off can
cause slight differences and eventual divergence of molecular dynamics
phase space trajectories within a few 100s or few 1000s of timesteps.
However, the statistical properties of the two runs (e.g. average
energy or temperature) should still be the same.
If the "velocity"_velocity.html command is used to set initial atom
velocities, a particular atom can be assigned a different velocity
when the problem is run on a different number of processors or on
different machines. If this happens, the phase space trajectories of
the two simulations will rapidly diverge. See the discussion of the
{loop} option in the "velocity"_velocity.html command for details and
options that avoid this issue.
Similarly, the "create_atoms"_create_atoms.html command generates a
lattice of atoms. For the same physical system, the ordering and
numbering of atoms by atom ID may be different depending on the number
of processors.
Some commands use random number generators which may be setup to
produce different random number streams on each processor and hence
will produce different effects when run on different numbers of
processors. A commonly-used example is the "fix
langevin"_fix_langevin.html command for thermostatting.
A LAMMPS simulation typically has two stages, setup and run. Most
LAMMPS errors are detected at setup time; others like a bond
stretching too far may not occur until the middle of a run.
LAMMPS tries to flag errors and print informative error messages so
you can fix the problem. For most errors it will also print the last
input script command that it was processing. Of course, LAMMPS cannot
figure out your physics or numerical mistakes, like choosing too big a
timestep, specifying erroneous force field coefficients, or putting 2
atoms on top of each other! If you run into errors that LAMMPS
doesn't catch that you think it should flag, please send an email to
the "developers"_http://lammps.sandia.gov/authors.html.
If you get an error message about an invalid command in your input
script, you can determine what command is causing the problem by
looking in the log.lammps file or using the "echo command"_echo.html
to see it on the screen. If you get an error like "Invalid ...
style", with ... being fix, compute, pair, etc, it means that you
mistyped the style name or that the command is part of an optional
package which was not compiled into your executable. The list of
available styles in your executable can be listed by using "the -h
-command-line argument"_Section_start.html#start_7. The installation
+command-line argument"_Section_start.html#start_6. The installation
and compilation of optional packages is explained in the "installation
instructions"_Section_start.html#start_3.
For a given command, LAMMPS expects certain arguments in a specified
order. If you mess this up, LAMMPS will often flag the error, but it
may also simply read a bogus argument and assign a value that is
valid, but not what you wanted. E.g. trying to read the string "abc"
as an integer value of 0. Careful reading of the associated doc page
for the command should allow you to fix these problems. In most cases,
where LAMMPS expects to read a number, either integer or floating point,
it performs a stringent test on whether the provided input actually
is an integer or floating-point number, respectively, and reject the
input with an error message (for instance, when an integer is required,
but a floating-point number 1.0 is provided):
ERROR: Expected integer parameter in input script or data file :pre
Some commands allow for using variable references in place of numeric
constants so that the value can be evaluated and may change over the
course of a run. This is typically done with the syntax {v_name} for a
parameter, where name is the name of the variable. On the other hand,
immediate variable expansion with the syntax ${name} is performed while
reading the input and before parsing commands,
NOTE: Using a variable reference (i.e. {v_name}) is only allowed if
the documentation of the corresponding command explicitly says it is.
Generally, LAMMPS will print a message to the screen and logfile and
exit gracefully when it encounters a fatal error. Sometimes it will
print a WARNING to the screen and logfile and continue on; you can
decide if the WARNING is important or not. A WARNING message that is
generated in the middle of a run is only printed to the screen, not to
the logfile, to avoid cluttering up thermodynamic output. If LAMMPS
crashes or hangs without spitting out an error message first then it
could be a bug (see "this section"_#err_2) or one of the following
cases:
LAMMPS runs in the available memory a processor allows to be
allocated. Most reasonable MD runs are compute limited, not memory
limited, so this shouldn't be a bottleneck on most platforms. Almost
all large memory allocations in the code are done via C-style malloc's
which will generate an error message if you run out of memory.
Smaller chunks of memory are allocated via C++ "new" statements. If
you are unlucky you could run out of memory just when one of these
small requests is made, in which case the code will crash or hang (in
parallel), since LAMMPS doesn't trap on those errors.
Illegal arithmetic can cause LAMMPS to run slow or crash. This is
typically due to invalid physics and numerics that your simulation is
computing. If you see wild thermodynamic values or NaN values in your
LAMMPS output, something is wrong with your simulation. If you
suspect this is happening, it is a good idea to print out
thermodynamic info frequently (e.g. every timestep) via the
"thermo"_thermo.html so you can monitor what is happening.
Visualizing the atom movement is also a good idea to insure your model
is behaving as you expect.
In parallel, one way LAMMPS can hang is due to how different MPI
implementations handle buffering of messages. If the code hangs
without an error message, it may be that you need to specify an MPI
setting or two (usually via an environment variable) to enable
buffering or boost the sizes of messages that can be buffered.
:line
12.2 Reporting bugs :link(err_2),h4
If you are confident that you have found a bug in LAMMPS, follow these
steps.
Check the "New features and bug
fixes"_http://lammps.sandia.gov/bug.html section of the "LAMMPS WWW
site"_lws to see if the bug has already been reported or fixed or the
"Unfixed bug"_http://lammps.sandia.gov/unbug.html to see if a fix is
pending.
Check the "mailing list"_http://lammps.sandia.gov/mail.html
to see if it has been discussed before.
If not, send an email to the mailing list describing the problem with
any ideas you have as to what is causing it or where in the code the
problem might be. The developers will ask for more info if needed,
such as an input script or data files.
The most useful thing you can do to help us fix the bug is to isolate
the problem. Run it on the smallest number of atoms and fewest number
of processors and with the simplest input script that reproduces the
bug and try to identify what command or combination of commands is
causing the problem.
As a last resort, you can send an email directly to the
"developers"_http://lammps.sandia.gov/authors.html.
:line
12.3 Error & warning messages :h4,link(err_3)
These are two alphabetic lists of the "ERROR"_#error and
"WARNING"_#warn messages LAMMPS prints out and the reason why. If the
explanation here is not sufficient, the documentation for the
offending command may help.
Error and warning messages also list the source file and line number
where the error was generated. For example, this message
ERROR: Illegal velocity command (velocity.cpp:78)
means that line #78 in the file src/velocity.cpp generated the error.
Looking in the source code may help you figure out what went wrong.
Note that error messages from "user-contributed
packages"_Section_start.html#start_3 are not listed here. If such an
error occurs and is not self-explanatory, you'll need to look in the
source code or contact the author of the package.
Errors: :h4,link(error)
:dlb
{1-3 bond count is inconsistent} :dt
An inconsistency was detected when computing the number of 1-3
neighbors for each atom. This likely means something is wrong with
the bond topologies you have defined. :dd
{1-4 bond count is inconsistent} :dt
An inconsistency was detected when computing the number of 1-4
neighbors for each atom. This likely means something is wrong with
the bond topologies you have defined. :dd
{Accelerator sharing is not currently supported on system} :dt
Multiple MPI processes cannot share the accelerator on your
system. For NVIDIA GPUs, see the nvidia-smi command to change this
setting. :dd
{All angle coeffs are not set} :dt
All angle coefficients must be set in the data file or by the
angle_coeff command before running a simulation. :dd
{All atom IDs = 0 but atom_modify id = yes} :dt
Self-explanatory. :dd
{All atoms of a swapped type must have same charge.} :dt
Self-explanatory. :dd
{All atoms of a swapped type must have the same charge.} :dt
Self-explanatory. :dd
{All bond coeffs are not set} :dt
All bond coefficients must be set in the data file or by the
bond_coeff command before running a simulation. :dd
{All dihedral coeffs are not set} :dt
All dihedral coefficients must be set in the data file or by the
dihedral_coeff command before running a simulation. :dd
{All improper coeffs are not set} :dt
All improper coefficients must be set in the data file or by the
improper_coeff command before running a simulation. :dd
{All masses are not set} :dt
For atom styles that define masses for each atom type, all masses must
be set in the data file or by the mass command before running a
simulation. They must also be set before using the velocity
command. :dd
{All mol IDs should be set for fix gcmc group atoms} :dt
The molecule flag is on, yet not all molecule ids in the fix group
have been set to non-zero positive values by the user. This is an
error since all atoms in the fix gcmc group are eligible for deletion,
rotation, and translation and therefore must have valid molecule ids. :dd
{All pair coeffs are not set} :dt
All pair coefficients must be set in the data file or by the
pair_coeff command before running a simulation. :dd
{All read_dump x,y,z fields must be specified for scaled, triclinic coords} :dt
For triclinic boxes and scaled coordinates you must specify all 3 of
the x,y,z fields, else LAMMPS cannot reconstruct the unscaled
coordinates. :dd
{All universe/uloop variables must have same # of values} :dt
Self-explanatory. :dd
{All variables in next command must be same style} :dt
Self-explanatory. :dd
{Angle atom missing in delete_bonds} :dt
The delete_bonds command cannot find one or more atoms in a particular
angle on a particular processor. The pairwise cutoff is too short or
the atoms are too far apart to make a valid angle. :dd
{Angle atom missing in set command} :dt
The set command cannot find one or more atoms in a particular angle on
a particular processor. The pairwise cutoff is too short or the atoms
are too far apart to make a valid angle. :dd
{Angle atoms %d %d %d missing on proc %d at step %ld} :dt
One or more of 3 atoms needed to compute a particular angle are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the angle has blown apart and an atom is
too far away. :dd
{Angle atoms missing on proc %d at step %ld} :dt
One or more of 3 atoms needed to compute a particular angle are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the angle has blown apart and an atom is
too far away. :dd
{Angle coeff for hybrid has invalid style} :dt
Angle style hybrid uses another angle style as one of its
coefficients. The angle style used in the angle_coeff command or read
from a restart file is not recognized. :dd
{Angle coeffs are not set} :dt
No angle coefficients have been assigned in the data file or via the
angle_coeff command. :dd
{Angle extent > half of periodic box length} :dt
This error was detected by the neigh_modify check yes setting. It is
an error because the angle atoms are so far apart it is ambiguous how
it should be defined. :dd
{Angle potential must be defined for SHAKE} :dt
When shaking angles, an angle_style potential must be used. :dd
{Angle style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Angle style hybrid cannot have none as an argument} :dt
Self-explanatory. :dd
{Angle style hybrid cannot use same angle style twice} :dt
Self-explanatory. :dd
{Angle table must range from 0 to 180 degrees} :dt
Self-explanatory. :dd
{Angle table parameters did not set N} :dt
List of angle table parameters must include N setting. :dd
{Angle_coeff command before angle_style is defined} :dt
Coefficients cannot be set in the data file or via the angle_coeff
command until an angle_style has been assigned. :dd
{Angle_coeff command before simulation box is defined} :dt
The angle_coeff command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Angle_coeff command when no angles allowed} :dt
The chosen atom style does not allow for angles to be defined. :dd
{Angle_style command when no angles allowed} :dt
The chosen atom style does not allow for angles to be defined. :dd
{Angles assigned incorrectly} :dt
Angles read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions. :dd
{Angles defined but no angle types} :dt
The data file header lists angles but no angle types. :dd
{Append boundary must be shrink/minimum} :dt
The boundary style of the face where atoms are added
must be of type m (shrink/minimum). :dd
{Arccos of invalid value in variable formula} :dt
Argument of arccos() must be between -1 and 1. :dd
{Arcsin of invalid value in variable formula} :dt
Argument of arcsin() must be between -1 and 1. :dd
{Assigning body parameters to non-body atom} :dt
Self-explanatory. :dd
{Assigning ellipsoid parameters to non-ellipsoid atom} :dt
Self-explanatory. :dd
{Assigning line parameters to non-line atom} :dt
Self-explanatory. :dd
{Assigning quat to non-body atom} :dt
Self-explanatory. :dd
{Assigning tri parameters to non-tri atom} :dt
Self-explanatory. :dd
{At least one atom of each swapped type must be present to define charges.} :dt
Self-explanatory. :dd
{Atom IDs must be consecutive for velocity create loop all} :dt
Self-explanatory. :dd
{Atom IDs must be used for molecular systems} :dt
Atom IDs are used to identify and find partner atoms in bonds. :dd
{Atom count changed in fix neb} :dt
This is not allowed in a NEB calculation. :dd
{Atom count is inconsistent, cannot write data file} :dt
The sum of atoms across processors does not equal the global number
of atoms. Probably some atoms have been lost. :dd
{Atom count is inconsistent, cannot write restart file} :dt
Sum of atoms across processors does not equal initial total count.
This is probably because you have lost some atoms. :dd
{Atom in too many rigid bodies - boost MAXBODY} :dt
Fix poems has a parameter MAXBODY (in fix_poems.cpp) which determines
the maximum number of rigid bodies a single atom can belong to (i.e. a
multibody joint). The bodies you have defined exceed this limit. :dd
{Atom sort did not operate correctly} :dt
This is an internal LAMMPS error. Please report it to the
developers. :dd
{Atom sorting has bin size = 0.0} :dt
The neighbor cutoff is being used as the bin size, but it is zero.
Thus you must explicitly list a bin size in the atom_modify sort
command or turn off sorting. :dd
{Atom style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Atom style hybrid cannot use same atom style twice} :dt
Self-explanatory. :dd
{Atom style template molecule must have atom types} :dt
The defined molecule(s) does not specify atom types. :dd
{Atom style was redefined after using fix property/atom} :dt
This is not allowed. :dd
{Atom type must be zero in fix gcmc mol command} :dt
Self-explanatory. :dd
{Atom vector in equal-style variable formula} :dt
Atom vectors generate one value per atom which is not allowed
in an equal-style variable. :dd
{Atom-style variable in equal-style variable formula} :dt
Atom-style variables generate one value per atom which is not allowed
in an equal-style variable. :dd
{Atom_modify id command after simulation box is defined} :dt
The atom_modify id command cannot be used after a read_data,
read_restart, or create_box command. :dd
{Atom_modify map command after simulation box is defined} :dt
The atom_modify map command cannot be used after a read_data,
read_restart, or create_box command. :dd
{Atom_modify sort and first options cannot be used together} :dt
Self-explanatory. :dd
{Atom_style command after simulation box is defined} :dt
The atom_style command cannot be used after a read_data,
read_restart, or create_box command. :dd
{Atom_style line can only be used in 2d simulations} :dt
Self-explanatory. :dd
{Atom_style tri can only be used in 3d simulations} :dt
Self-explanatory. :dd
{Atomfile variable could not read values} :dt
Check the file assigned to the variable. :dd
{Atomfile variable in equal-style variable formula} :dt
Self-explanatory. :dd
{Atomfile-style variable in equal-style variable formula} :dt
Self-explanatory. :dd
{Attempt to pop empty stack in fix box/relax} :dt
Internal LAMMPS error. Please report it to the developers. :dd
{Attempt to push beyond stack limit in fix box/relax} :dt
Internal LAMMPS error. Please report it to the developers. :dd
{Attempting to rescale a 0.0 temperature} :dt
Cannot rescale a temperature that is already 0.0. :dd
{Bad FENE bond} :dt
Two atoms in a FENE bond have become so far apart that the bond cannot
be computed. :dd
{Bad TIP4P angle type for PPPM/TIP4P} :dt
Specified angle type is not valid. :dd
{Bad TIP4P angle type for PPPMDisp/TIP4P} :dt
Specified angle type is not valid. :dd
{Bad TIP4P bond type for PPPM/TIP4P} :dt
Specified bond type is not valid. :dd
{Bad TIP4P bond type for PPPMDisp/TIP4P} :dt
Specified bond type is not valid. :dd
{Bad fix ID in fix append/atoms command} :dt
The value of the fix_id for keyword spatial must start with 'f_'. :dd
{Bad grid of processors} :dt
The 3d grid of processors defined by the processors command does not
match the number of processors LAMMPS is being run on. :dd
{Bad kspace_modify kmax/ewald parameter} :dt
Kspace_modify values for the kmax/ewald keyword must be integers > 0 :dd
{Bad kspace_modify slab parameter} :dt
Kspace_modify value for the slab/volume keyword must be >= 2.0. :dd
{Bad matrix inversion in mldivide3} :dt
This error should not occur unless the matrix is badly formed. :dd
{Bad principal moments} :dt
Fix rigid did not compute the principal moments of inertia of a rigid
group of atoms correctly. :dd
{Bad quadratic solve for particle/line collision} :dt
This is an internal error. It should normally not occur. :dd
{Bad quadratic solve for particle/tri collision} :dt
This is an internal error. It should normally not occur. :dd
{Bad real space Coulomb cutoff in fix tune/kspace} :dt
Fix tune/kspace tried to find the optimal real space Coulomb cutoff using
the Newton-Rhaphson method, but found a non-positive or NaN cutoff :dd
{Balance command before simulation box is defined} :dt
The balance command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Balance produced bad splits} :dt
This should not occur. It means two or more cutting plane locations
are on top of each other or out of order. Report the problem to the
developers. :dd
{Balance rcb cannot be used with comm_style brick} :dt
Comm_style tiled must be used instead. :dd
{Balance shift string is invalid} :dt
The string can only contain the characters "x", "y", or "z". :dd
{Bias compute does not calculate a velocity bias} :dt
The specified compute must compute a bias for temperature. :dd
{Bias compute does not calculate temperature} :dt
The specified compute must compute temperature. :dd
{Bias compute group does not match compute group} :dt
The specified compute must operate on the same group as the parent
compute. :dd
{Big particle in fix srd cannot be point particle} :dt
Big particles must be extended spheriods or ellipsoids. :dd
{Bigint setting in lmptype.h is invalid} :dt
Size of bigint is less than size of tagint. :dd
{Bigint setting in lmptype.h is not compatible} :dt
Format of bigint stored in restart file is not consistent with LAMMPS
version you are running. See the settings in src/lmptype.h :dd
{Bitmapped lookup tables require int/float be same size} :dt
Cannot use pair tables on this machine, because of word sizes. Use
the pair_modify command with table 0 instead. :dd
{Bitmapped table in file does not match requested table} :dt
Setting for bitmapped table in pair_coeff command must match table
in file exactly. :dd
{Bitmapped table is incorrect length in table file} :dt
Number of table entries is not a correct power of 2. :dd
{Bond and angle potentials must be defined for TIP4P} :dt
Cannot use TIP4P pair potential unless bond and angle potentials
are defined. :dd
{Bond atom missing in box size check} :dt
The 2nd atoms needed to compute a particular bond is missing on this
processor. Typically this is because the pairwise cutoff is set too
short or the bond has blown apart and an atom is too far away. :dd
{Bond atom missing in delete_bonds} :dt
The delete_bonds command cannot find one or more atoms in a particular
bond on a particular processor. The pairwise cutoff is too short or
the atoms are too far apart to make a valid bond. :dd
{Bond atom missing in image check} :dt
The 2nd atom in a particular bond is missing on this processor.
Typically this is because the pairwise cutoff is set too short or the
bond has blown apart and an atom is too far away. :dd
{Bond atom missing in set command} :dt
The set command cannot find one or more atoms in a particular bond on
a particular processor. The pairwise cutoff is too short or the atoms
are too far apart to make a valid bond. :dd
{Bond atoms %d %d missing on proc %d at step %ld} :dt
The 2nd atom needed to compute a particular bond is missing on this
processor. Typically this is because the pairwise cutoff is set too
short or the bond has blown apart and an atom is too far away. :dd
{Bond atoms missing on proc %d at step %ld} :dt
The 2nd atom needed to compute a particular bond is missing on this
processor. Typically this is because the pairwise cutoff is set too
short or the bond has blown apart and an atom is too far away. :dd
{Bond coeff for hybrid has invalid style} :dt
Bond style hybrid uses another bond style as one of its coefficients.
The bond style used in the bond_coeff command or read from a restart
file is not recognized. :dd
{Bond coeffs are not set} :dt
No bond coefficients have been assigned in the data file or via the
bond_coeff command. :dd
{Bond extent > half of periodic box length} :dt
This error was detected by the neigh_modify check yes setting. It is
an error because the bond atoms are so far apart it is ambiguous how
it should be defined. :dd
{Bond potential must be defined for SHAKE} :dt
Cannot use fix shake unless bond potential is defined. :dd
{Bond style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Bond style hybrid cannot have none as an argument} :dt
Self-explanatory. :dd
{Bond style hybrid cannot use same bond style twice} :dt
Self-explanatory. :dd
{Bond style quartic cannot be used with 3,4-body interactions} :dt
No angle, dihedral, or improper styles can be defined when using
bond style quartic. :dd
{Bond style quartic cannot be used with atom style template} :dt
This bond style can change the bond topology which is not
allowed with this atom style. :dd
{Bond style quartic requires special_bonds = 1,1,1} :dt
This is a restriction of the current bond quartic implementation. :dd
{Bond table parameters did not set N} :dt
List of bond table parameters must include N setting. :dd
{Bond table values are not increasing} :dt
The values in the tabulated file must be monotonically increasing. :dd
{BondAngle coeff for hybrid angle has invalid format} :dt
No "ba" field should appear in data file entry. :dd
{BondBond coeff for hybrid angle has invalid format} :dt
No "bb" field should appear in data file entry. :dd
{Bond_coeff command before bond_style is defined} :dt
Coefficients cannot be set in the data file or via the bond_coeff
command until an bond_style has been assigned. :dd
{Bond_coeff command before simulation box is defined} :dt
The bond_coeff command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Bond_coeff command when no bonds allowed} :dt
The chosen atom style does not allow for bonds to be defined. :dd
{Bond_style command when no bonds allowed} :dt
The chosen atom style does not allow for bonds to be defined. :dd
{Bonds assigned incorrectly} :dt
Bonds read in from the data file were not assigned correctly to atoms.
This means there is something invalid about the topology definitions. :dd
{Bonds defined but no bond types} :dt
The data file header lists bonds but no bond types. :dd
{Both restart files must use % or neither} :dt
Self-explanatory. :dd
{Both restart files must use MPI-IO or neither} :dt
Self-explanatory. :dd
{Both sides of boundary must be periodic} :dt
Cannot specify a boundary as periodic only on the lo or hi side. Must
be periodic on both sides. :dd
{Boundary command after simulation box is defined} :dt
The boundary command cannot be used after a read_data, read_restart,
or create_box command. :dd
{Box bounds are invalid} :dt
The box boundaries specified in the read_data file are invalid. The
lo value must be less than the hi value for all 3 dimensions. :dd
{Box command after simulation box is defined} :dt
The box command cannot be used after a read_data, read_restart, or
create_box command. :dd
{CPU neighbor lists must be used for ellipsoid/sphere mix.} :dt
When using Gay-Berne or RE-squared pair styles with both ellipsoidal and
spherical particles, the neighbor list must be built on the CPU :dd
{Can not specify Pxy/Pxz/Pyz in fix box/relax with non-triclinic box} :dt
Only triclinic boxes can be used with off-diagonal pressure components.
See the region prism command for details. :dd
{Can not specify Pxy/Pxz/Pyz in fix nvt/npt/nph with non-triclinic box} :dt
Only triclinic boxes can be used with off-diagonal pressure components.
See the region prism command for details. :dd
{Can only use -plog with multiple partitions} :dt
Self-explanatory. See doc page discussion of command-line switches. :dd
{Can only use -pscreen with multiple partitions} :dt
Self-explanatory. See doc page discussion of command-line switches. :dd
{Can only use Kokkos supported regions with Kokkos package} :dt
Self-explanatory. :dd
{Can only use NEB with 1-processor replicas} :dt
This is current restriction for NEB as implemented in LAMMPS. :dd
{Can only use TAD with 1-processor replicas for NEB} :dt
This is current restriction for NEB as implemented in LAMMPS. :dd
{Cannot (yet) do analytic differentiation with pppm/gpu} :dt
This is a current restriction of this command. :dd
{Cannot (yet) request ghost atoms with Kokkos half neighbor list} :dt
This feature is not yet supported. :dd
{Cannot (yet) use 'electron' units with dipoles} :dt
This feature is not yet supported. :dd
{Cannot (yet) use Ewald with triclinic box and slab correction} :dt
This feature is not yet supported. :dd
{Cannot (yet) use K-space slab correction with compute group/group for triclinic systems} :dt
This option is not yet supported. :dd
{Cannot (yet) use MSM with 2d simulation} :dt
This feature is not yet supported. :dd
{Cannot (yet) use PPPM with triclinic box and TIP4P} :dt
This feature is not yet supported. :dd
{Cannot (yet) use PPPM with triclinic box and kspace_modify diff ad} :dt
This feature is not yet supported. :dd
{Cannot (yet) use PPPM with triclinic box and slab correction} :dt
This feature is not yet supported. :dd
{Cannot (yet) use kspace slab correction with long-range dipoles and non-neutral systems or per-atom energy} :dt
This feature is not yet supported. :dd
{Cannot (yet) use kspace_modify diff ad with compute group/group} :dt
This option is not yet supported. :dd
{Cannot (yet) use kspace_style pppm/stagger with triclinic systems} :dt
This feature is not yet supported. :dd
{Cannot (yet) use molecular templates with Kokkos} :dt
Self-explanatory. :dd
{Cannot (yet) use respa with Kokkos} :dt
Self-explanatory. :dd
{Cannot (yet) use rigid bodies with fix deform and Kokkos} :dt
Self-explanatory. :dd
{Cannot (yet) use rigid bodies with fix nh and Kokkos} :dt
Self-explanatory. :dd
{Cannot (yet) use single precision with MSM (remove -DFFT_SINGLE from Makefile and recompile)} :dt
Single precision cannot be used with MSM. :dd
{Cannot add atoms to fix move variable} :dt
Atoms can not be added afterwards to this fix option. :dd
{Cannot append atoms to a triclinic box} :dt
The simulation box must be defined with edges aligned with the
Cartesian axes. :dd
{Cannot balance in z dimension for 2d simulation} :dt
Self-explanatory. :dd
{Cannot change box ortho/triclinic with certain fixes defined} :dt
This is because those fixes store the shape of the box. You need to
use unfix to discard the fix, change the box, then redefine a new
fix. :dd
{Cannot change box ortho/triclinic with dumps defined} :dt
This is because some dumps store the shape of the box. You need to
use undump to discard the dump, change the box, then redefine a new
dump. :dd
{Cannot change box tilt factors for orthogonal box} :dt
Cannot use tilt factors unless the simulation box is non-orthogonal. :dd
{Cannot change box to orthogonal when tilt is non-zero} :dt
Self-explanatory. :dd
{Cannot change box z boundary to nonperiodic for a 2d simulation} :dt
Self-explanatory. :dd
{Cannot change dump_modify every for dump dcd} :dt
The frequency of writing dump dcd snapshots cannot be changed. :dd
{Cannot change dump_modify every for dump xtc} :dt
The frequency of writing dump xtc snapshots cannot be changed. :dd
{Cannot change timestep once fix srd is setup} :dt
This is because various SRD properties depend on the timestep
size. :dd
{Cannot change timestep with fix pour} :dt
This is because fix pour pre-computes the time delay for particles to
fall out of the insertion volume due to gravity. :dd
{Cannot change to comm_style brick from tiled layout} :dt
Self-explanatory. :dd
{Cannot change_box after reading restart file with per-atom info} :dt
This is because the restart file info cannot be migrated with the
atoms. You can get around this by performing a 0-timestep run which
will assign the restart file info to actual atoms. :dd
{Cannot change_box in xz or yz for 2d simulation} :dt
Self-explanatory. :dd
{Cannot change_box in z dimension for 2d simulation} :dt
Self-explanatory. :dd
{Cannot clear group all} :dt
This operation is not allowed. :dd
{Cannot close restart file - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot compute initial g_ewald_disp} :dt
LAMMPS failed to compute an initial guess for the PPPM_disp g_ewald_6
factor that partitions the computation between real space and k-space
for Dispersion interactions. :dd
{Cannot create an atom map unless atoms have IDs} :dt
The simulation requires a mapping from global atom IDs to local atoms,
but the atoms that have been defined have no IDs. :dd
{Cannot create atoms with undefined lattice} :dt
Must use the lattice command before using the create_atoms
command. :dd
{Cannot create/grow a vector/array of pointers for %s} :dt
LAMMPS code is making an illegal call to the templated memory
allocaters, to create a vector or array of pointers. :dd
{Cannot create_atoms after reading restart file with per-atom info} :dt
The per-atom info was stored to be used when by a fix that you may
re-define. If you add atoms before re-defining the fix, then there
will not be a correct amount of per-atom info. :dd
{Cannot create_box after simulation box is defined} :dt
A simulation box can only be defined once. :dd
{Cannot currently use pair reax with pair hybrid} :dt
This is not yet supported. :dd
{Cannot currently use pppm/gpu with fix balance.} :dt
Self-explanatory. :dd
{Cannot delete group all} :dt
Self-explanatory. :dd
{Cannot delete group currently used by a compute} :dt
Self-explanatory. :dd
{Cannot delete group currently used by a dump} :dt
Self-explanatory. :dd
{Cannot delete group currently used by a fix} :dt
Self-explanatory. :dd
{Cannot delete group currently used by atom_modify first} :dt
Self-explanatory. :dd
{Cannot delete_atoms bond yes for non-molecular systems} :dt
Self-explanatory. :dd
{Cannot displace_atoms after reading restart file with per-atom info} :dt
This is because the restart file info cannot be migrated with the
atoms. You can get around this by performing a 0-timestep run which
will assign the restart file info to actual atoms. :dd
{Cannot do GCMC on atoms in atom_modify first group} :dt
This is a restriction due to the way atoms are organized in a list to
enable the atom_modify first command. :dd
{Cannot do atom/swap on atoms in atom_modify first group} :dt
This is a restriction due to the way atoms are organized in a list to
enable the atom_modify first command. :dd
{Cannot dump sort on atom IDs with no atom IDs defined} :dt
Self-explanatory. :dd
{Cannot dump sort when multiple dump files are written} :dt
In this mode, each processor dumps its atoms to a file, so
no sorting is allowed. :dd
{Cannot embed Python when also extending Python with LAMMPS} :dt
When running LAMMPS via Python through the LAMMPS library interface
you cannot also user the input script python command. :dd
{Cannot evaporate atoms in atom_modify first group} :dt
This is a restriction due to the way atoms are organized in
a list to enable the atom_modify first command. :dd
{Cannot find create_bonds group ID} :dt
Self-explanatory. :dd
{Cannot find delete_bonds group ID} :dt
Group ID used in the delete_bonds command does not exist. :dd
{Cannot find specified group ID for core particles} :dt
Self-explanatory. :dd
{Cannot find specified group ID for shell particles} :dt
Self-explanatory. :dd
{Cannot have both pair_modify shift and tail set to yes} :dt
These 2 options are contradictory. :dd
{Cannot intersect groups using a dynamic group} :dt
This operation is not allowed. :dd
{Cannot mix molecular and molecule template atom styles} :dt
Self-explanatory. :dd
{Cannot open -reorder file} :dt
Self-explanatory. :dd
{Cannot open ADP potential file %s} :dt
The specified ADP potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open AIREBO potential file %s} :dt
The specified AIREBO potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open BOP potential file %s} :dt
The specified BOP potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open COMB potential file %s} :dt
The specified COMB potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open COMB3 lib.comb3 file} :dt
The COMB3 library file cannot be opened. Check that the path and name
are correct. :dd
{Cannot open COMB3 potential file %s} :dt
The specified COMB3 potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open EAM potential file %s} :dt
The specified EAM potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open EIM potential file %s} :dt
The specified EIM potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open LCBOP potential file %s} :dt
The specified LCBOP potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open MEAM potential file %s} :dt
The specified MEAM potential file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open SNAP coefficient file %s} :dt
The specified SNAP coefficient file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open SNAP parameter file %s} :dt
The specified SNAP parameter file cannot be opened. Check that the
path and name are correct. :dd
{Cannot open Stillinger-Weber potential file %s} :dt
The specified SW potential file cannot be opened. Check that the path
and name are correct. :dd
{Cannot open Tersoff potential file %s} :dt
The specified potential file cannot be opened. Check that the path
and name are correct. :dd
{Cannot open Vashishta potential file %s} :dt
The specified Vashishta potential file cannot be opened. Check that the path
and name are correct. :dd
{Cannot open balance output file} :dt
Self-explanatory. :dd
{Cannot open coul/streitz potential file %s} :dt
The specified coul/streitz potential file cannot be opened. Check
that the path and name are correct. :dd
{Cannot open custom file} :dt
Self-explanatory. :dd
{Cannot open data file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open dir to search for restart file} :dt
Using a "*" in the name of the restart file will open the current
directory to search for matching file names. :dd
{Cannot open dump file} :dt
Self-explanatory. :dd
{Cannot open dump file %s} :dt
The output file for the dump command cannot be opened. Check that the
path and name are correct. :dd
{Cannot open file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. If the file is a compressed file, also check that the gzip
executable can be found and run. :dd
{Cannot open file variable file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix ave/chunk file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix ave/correlate file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix ave/histo file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix ave/spatial file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix ave/time file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix balance output file} :dt
Self-explanatory. :dd
{Cannot open fix poems file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix print file %s} :dt
The output file generated by the fix print command cannot be opened :dd
{Cannot open fix qeq parameter file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix qeq/comb file %s} :dt
The output file for the fix qeq/combs command cannot be opened.
Check that the path and name are correct. :dd
{Cannot open fix reax/bonds file %s} :dt
The output file for the fix reax/bonds command cannot be opened.
Check that the path and name are correct. :dd
{Cannot open fix rigid infile %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix rigid restart file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix rigid/small infile %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open fix tmd file %s} :dt
The output file for the fix tmd command cannot be opened. Check that
the path and name are correct. :dd
{Cannot open fix ttm file %s} :dt
The output file for the fix ttm command cannot be opened. Check that
the path and name are correct. :dd
{Cannot open gzipped file} :dt
LAMMPS was compiled without support for reading and writing gzipped
files through a pipeline to the gzip program with -DLAMMPS_GZIP. :dd
{Cannot open input script %s} :dt
Self-explanatory. :dd
{Cannot open log.cite file} :dt
This file is created when you use some LAMMPS features, to indicate
what paper you should cite on behalf of those who implemented
the feature. Check that you have write privileges into the directory
you are running in. :dd
{Cannot open log.lammps for writing} :dt
The default LAMMPS log file cannot be opened. Check that the
directory you are running in allows for files to be created. :dd
{Cannot open logfile} :dt
The LAMMPS log file named in a command-line argument cannot be opened.
Check that the path and name are correct. :dd
{Cannot open logfile %s} :dt
The LAMMPS log file specified in the input script cannot be opened.
Check that the path and name are correct. :dd
{Cannot open molecule file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct. :dd
{Cannot open nb3b/harmonic potential file %s} :dt
The specified potential file cannot be opened. Check that the path
and name are correct. :dd
{Cannot open pair_write file} :dt
The specified output file for pair energies and forces cannot be
opened. Check that the path and name are correct. :dd
{Cannot open polymorphic potential file %s} :dt
The specified polymorphic potential file cannot be opened. Check that
the path and name are correct. :dd
{Cannot open print file %s} :dt
Self-explanatory. :dd
{Cannot open processors output file} :dt
Self-explanatory. :dd
{Cannot open restart file %s} :dt
Self-explanatory. :dd
{Cannot open restart file for reading - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot open restart file for writing - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot open screen file} :dt
The screen file specified as a command-line argument cannot be
opened. Check that the directory you are running in allows for files
to be created. :dd
{Cannot open temporary file for world counter.} :dt
Self-explanatory. :dd
{Cannot open universe log file} :dt
For a multi-partition run, the master log file cannot be opened.
Check that the directory you are running in allows for files to be
created. :dd
{Cannot open universe screen file} :dt
For a multi-partition run, the master screen file cannot be opened.
Check that the directory you are running in allows for files to be
created. :dd
{Cannot read from restart file - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot read_data without add keyword after simulation box is defined} :dt
Self-explanatory. :dd
{Cannot read_restart after simulation box is defined} :dt
The read_restart command cannot be used after a read_data,
read_restart, or create_box command. :dd
{Cannot redefine variable as a different style} :dt
An equal-style variable can be re-defined but only if it was
originally an equal-style variable. :dd
{Cannot replicate 2d simulation in z dimension} :dt
The replicate command cannot replicate a 2d simulation in the z
dimension. :dd
{Cannot replicate with fixes that store atom quantities} :dt
Either fixes are defined that create and store atom-based vectors or a
restart file was read which included atom-based vectors for fixes.
The replicate command cannot duplicate that information for new atoms.
You should use the replicate command before fixes are applied to the
system. :dd
{Cannot reset timestep with a dynamic region defined} :dt
Dynamic regions (see the region command) have a time dependence.
Thus you cannot change the timestep when one or more of these
are defined. :dd
{Cannot reset timestep with a time-dependent fix defined} :dt
You cannot reset the timestep when a fix that keeps track of elapsed
time is in place. :dd
{Cannot run 2d simulation with nonperiodic Z dimension} :dt
Use the boundary command to make the z dimension periodic in order to
run a 2d simulation. :dd
{Cannot set bond topology types for atom style template} :dt
The bond, angle, etc types cannot be changed for this atom style since
they are static settings in the molecule template files. :dd
{Cannot set both respa pair and inner/middle/outer} :dt
In the rRESPA integrator, you must compute pairwise potentials either
all together (pair), or in pieces (inner/middle/outer). You can't do
both. :dd
{Cannot set cutoff/multi before simulation box is defined} :dt
Self-explanatory. :dd
{Cannot set dpd/theta for this atom style} :dt
Self-explanatory. :dd
{Cannot set dump_modify flush for dump xtc} :dt
Self-explanatory. :dd
{Cannot set mass for this atom style} :dt
This atom style does not support mass settings for each atom type.
Instead they are defined on a per-atom basis in the data file. :dd
{Cannot set meso/cv for this atom style} :dt
Self-explanatory. :dd
{Cannot set meso/e for this atom style} :dt
Self-explanatory. :dd
{Cannot set meso/rho for this atom style} :dt
Self-explanatory. :dd
{Cannot set non-zero image flag for non-periodic dimension} :dt
Self-explanatory. :dd
{Cannot set non-zero z velocity for 2d simulation} :dt
Self-explanatory. :dd
{Cannot set quaternion for atom that has none} :dt
Self-explanatory. :dd
{Cannot set quaternion with xy components for 2d system} :dt
Self-explanatory. :dd
{Cannot set respa hybrid and any of pair/inner/middle/outer} :dt
In the rRESPA integrator, you must compute pairwise potentials either
all together (pair), with different cutoff regions (inner/middle/outer),
or per hybrid sub-style (hybrid). You cannot mix those. :dd
{Cannot set respa middle without inner/outer} :dt
In the rRESPA integrator, you must define both a inner and outer
setting in order to use a middle setting. :dd
{Cannot set restart file size - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot set smd/contact/radius for this atom style} :dt
Self-explanatory. :dd
{Cannot set smd/mass/density for this atom style} :dt
Self-explanatory. :dd
{Cannot set temperature for fix rigid/nph} :dt
The temp keyword cannot be specified. :dd
{Cannot set theta for atom that is not a line} :dt
Self-explanatory. :dd
{Cannot set this attribute for this atom style} :dt
The attribute being set does not exist for the defined atom style. :dd
{Cannot set variable z velocity for 2d simulation} :dt
Self-explanatory. :dd
{Cannot skew triclinic box in z for 2d simulation} :dt
Self-explanatory. :dd
{Cannot subtract groups using a dynamic group} :dt
This operation is not allowed. :dd
{Cannot union groups using a dynamic group} :dt
This operation is not allowed. :dd
{Cannot use -cuda on and -kokkos on together} :dt
This is not allowed since both packages can use GPUs. :dd
{Cannot use -cuda on without USER-CUDA installed} :dt
The USER-CUDA package must be installed via "make yes-user-cuda"
before LAMMPS is built. :dd
{Cannot use -kokkos on without KOKKOS installed} :dt
Self-explanatory. :dd
{Cannot use -reorder after -partition} :dt
Self-explanatory. See doc page discussion of command-line switches. :dd
{Cannot use Ewald with 2d simulation} :dt
The kspace style ewald cannot be used in 2d simulations. You can use
2d Ewald in a 3d simulation; see the kspace_modify command. :dd
{Cannot use Ewald/disp solver on system with no charge, dipole, or LJ particles} :dt
No atoms in system have a non-zero charge or dipole, or are LJ
particles. Change charges/dipoles or change options of the kspace
solver/pair style. :dd
{Cannot use EwaldDisp with 2d simulation} :dt
This is a current restriction of this command. :dd
{Cannot use GPU package with USER-CUDA package enabled} :dt
You cannot use both the GPU and USER-CUDA packages
together. Use one or the other. :dd
{Cannot use Kokkos pair style with rRESPA inner/middle} :dt
Self-explanatory. :dd
{Cannot use NEB unless atom map exists} :dt
Use the atom_modify command to create an atom map. :dd
{Cannot use NEB with a single replica} :dt
Self-explanatory. :dd
{Cannot use NEB with atom_modify sort enabled} :dt
This is current restriction for NEB implemented in LAMMPS. :dd
{Cannot use PPPM with 2d simulation} :dt
The kspace style pppm cannot be used in 2d simulations. You can use
2d PPPM in a 3d simulation; see the kspace_modify command. :dd
{Cannot use PPPMDisp with 2d simulation} :dt
The kspace style pppm/disp cannot be used in 2d simulations. You can
use 2d pppm/disp in a 3d simulation; see the kspace_modify command. :dd
{Cannot use PRD with a changing box} :dt
The current box dimensions are not copied between replicas :dd
{Cannot use PRD with a time-dependent fix defined} :dt
PRD alters the timestep in ways that will mess up these fixes. :dd
{Cannot use PRD with a time-dependent region defined} :dt
PRD alters the timestep in ways that will mess up these regions. :dd
{Cannot use PRD with atom_modify sort enabled} :dt
This is a current restriction of PRD. You must turn off sorting,
which is enabled by default, via the atom_modify command. :dd
{Cannot use PRD with multi-processor replicas unless atom map exists} :dt
Use the atom_modify command to create an atom map. :dd
{Cannot use TAD unless atom map exists for NEB} :dt
See atom_modify map command to set this. :dd
{Cannot use TAD with a single replica for NEB} :dt
NEB requires multiple replicas. :dd
{Cannot use TAD with atom_modify sort enabled for NEB} :dt
This is a current restriction of NEB. :dd
{Cannot use a damped dynamics min style with fix box/relax} :dt
This is a current restriction in LAMMPS. Use another minimizer
style. :dd
{Cannot use a damped dynamics min style with per-atom DOF} :dt
This is a current restriction in LAMMPS. Use another minimizer
style. :dd
{Cannot use append/atoms in periodic dimension} :dt
The boundary style of the face where atoms are added can not be of
type p (periodic). :dd
{Cannot use atomfile-style variable unless atom map exists} :dt
Self-explanatory. See the atom_modify command to create a map. :dd
{Cannot use both com and bias with compute temp/chunk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with buck/coul/cut/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with buck/coul/long/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with buck/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with coul/cut/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with coul/debye/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with coul/dsf/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with coul/wolf/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with lj/charmm/coul/charmm/implicit/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/charmm/coul/charmm/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/charmm/coul/long/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/class2/coul/cut/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/class2/coul/long/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/class2/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/cut/coul/cut/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with lj/cut/coul/debye/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/cut/coul/long/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with lj/cut/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with lj/expand/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/gromacs/coul/gromacs/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/gromacs/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with lj/sdk/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with pair eam/kk} :dt
That style is not supported by Kokkos. :dd
{Cannot use chosen neighbor list style with pair eam/kk/alloy} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with pair eam/kk/fs} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with pair sw/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with tersoff/kk} :dt
Self-explanatory. :dd
{Cannot use chosen neighbor list style with tersoff/zbl/kk} :dt
Self-explanatory. :dd
{Cannot use compute chunk/atom bin z for 2d model} :dt
Self-explanatory. :dd
{Cannot use compute cluster/atom unless atoms have IDs} :dt
Atom IDs are used to identify clusters. :dd
{Cannot use create_atoms rotate unless single style} :dt
Self-explanatory. :dd
{Cannot use create_bonds unless atoms have IDs} :dt
This command requires a mapping from global atom IDs to local atoms,
but the atoms that have been defined have no IDs. :dd
{Cannot use create_bonds with non-molecular system} :dt
Self-explanatory. :dd
{Cannot use cwiggle in variable formula between runs} :dt
This is a function of elapsed time. :dd
{Cannot use delete_atoms bond yes with atom_style template} :dt
This is because the bonds for that atom style are hardwired in the
molecule template. :dd
{Cannot use delete_atoms unless atoms have IDs} :dt
Your atoms do not have IDs, so the delete_atoms command cannot be
used. :dd
{Cannot use delete_bonds with non-molecular system} :dt
Your choice of atom style does not have bonds. :dd
{Cannot use dump_modify fileper without % in dump file name} :dt
Self-explanatory. :dd
{Cannot use dump_modify nfile without % in dump file name} :dt
Self-explanatory. :dd
{Cannot use dynamic group with fix adapt atom} :dt
This is not yet supported. :dd
{Cannot use fix TMD unless atom map exists} :dt
Using this fix requires the ability to lookup an atom index, which is
provided by an atom map. An atom map does not exist (by default) for
non-molecular problems. Using the atom_modify map command will force
an atom map to be created. :dd
{Cannot use fix ave/spatial z for 2 dimensional model} :dt
Self-explanatory. :dd
{Cannot use fix bond/break with non-molecular systems} :dt
Only systems with bonds that can be changed can be used. Atom_style
template does not qualify. :dd
{Cannot use fix bond/create with non-molecular systems} :dt
Only systems with bonds that can be changed can be used. Atom_style
template does not qualify. :dd
{Cannot use fix bond/swap with non-molecular systems} :dt
Only systems with bonds that can be changed can be used. Atom_style
template does not qualify. :dd
{Cannot use fix box/relax on a 2nd non-periodic dimension} :dt
When specifying an off-diagonal pressure component, the 2nd of the two
dimensions must be periodic. E.g. if the xy component is specified,
then the y dimension must be periodic. :dd
{Cannot use fix box/relax on a non-periodic dimension} :dt
When specifying a diagonal pressure component, the dimension must be
periodic. :dd
{Cannot use fix box/relax with both relaxation and scaling on a tilt factor} :dt
When specifying scaling on a tilt factor component, that component can not
also be controlled by the barostat. E.g. if scalexy yes is specified and
also keyword tri or xy, this is wrong. :dd
{Cannot use fix box/relax with tilt factor scaling on a 2nd non-periodic dimension} :dt
When specifying scaling on a tilt factor component, the 2nd of the two
dimensions must be periodic. E.g. if the xy component is specified,
then the y dimension must be periodic. :dd
{Cannot use fix deform on a shrink-wrapped boundary} :dt
The x, y, z options cannot be applied to shrink-wrapped
dimensions. :dd
{Cannot use fix deform tilt on a shrink-wrapped 2nd dim} :dt
This is because the shrink-wrapping will change the value
of the strain implied by the tilt factor. :dd
{Cannot use fix deform trate on a box with zero tilt} :dt
The trate style alters the current strain. :dd
{Cannot use fix deposit rigid and not molecule} :dt
Self-explanatory. :dd
{Cannot use fix deposit rigid and shake} :dt
These two attributes are conflicting. :dd
{Cannot use fix deposit shake and not molecule} :dt
Self-explanatory. :dd
{Cannot use fix enforce2d with 3d simulation} :dt
Self-explanatory. :dd
{Cannot use fix gcmc in a 2d simulation} :dt
Fix gcmc is set up to run in 3d only. No 2d simulations with fix gcmc
are allowed. :dd
{Cannot use fix gcmc shake and not molecule} :dt
Self-explanatory. :dd
{Cannot use fix msst without per-type mass defined} :dt
Self-explanatory. :dd
{Cannot use fix npt and fix deform on same component of stress tensor} :dt
This would be changing the same box dimension twice. :dd
{Cannot use fix nvt/npt/nph on a 2nd non-periodic dimension} :dt
When specifying an off-diagonal pressure component, the 2nd of the two
dimensions must be periodic. E.g. if the xy component is specified,
then the y dimension must be periodic. :dd
{Cannot use fix nvt/npt/nph on a non-periodic dimension} :dt
When specifying a diagonal pressure component, the dimension must be
periodic. :dd
{Cannot use fix nvt/npt/nph with both xy dynamics and xy scaling} :dt
Self-explanatory. :dd
{Cannot use fix nvt/npt/nph with both xz dynamics and xz scaling} :dt
Self-explanatory. :dd
{Cannot use fix nvt/npt/nph with both yz dynamics and yz scaling} :dt
Self-explanatory. :dd
{Cannot use fix nvt/npt/nph with xy scaling when y is non-periodic dimension} :dt
The 2nd dimension in the barostatted tilt factor must be periodic. :dd
{Cannot use fix nvt/npt/nph with xz scaling when z is non-periodic dimension} :dt
The 2nd dimension in the barostatted tilt factor must be periodic. :dd
{Cannot use fix nvt/npt/nph with yz scaling when z is non-periodic dimension} :dt
The 2nd dimension in the barostatted tilt factor must be periodic. :dd
{Cannot use fix pour rigid and not molecule} :dt
Self-explanatory. :dd
{Cannot use fix pour rigid and shake} :dt
These two attributes are conflicting. :dd
{Cannot use fix pour shake and not molecule} :dt
Self-explanatory. :dd
{Cannot use fix pour with triclinic box} :dt
This option is not yet supported. :dd
{Cannot use fix press/berendsen and fix deform on same component of stress tensor} :dt
These commands both change the box size/shape, so you cannot use both
together. :dd
{Cannot use fix press/berendsen on a non-periodic dimension} :dt
Self-explanatory. :dd
{Cannot use fix press/berendsen with triclinic box} :dt
Self-explanatory. :dd
{Cannot use fix reax/bonds without pair_style reax} :dt
Self-explanatory. :dd
{Cannot use fix rigid npt/nph and fix deform on same component of stress tensor} :dt
This would be changing the same box dimension twice. :dd
{Cannot use fix rigid npt/nph on a non-periodic dimension} :dt
When specifying a diagonal pressure component, the dimension must be
periodic. :dd
{Cannot use fix rigid/small npt/nph on a non-periodic dimension} :dt
When specifying a diagonal pressure component, the dimension must be
periodic. :dd
{Cannot use fix shake with non-molecular system} :dt
Your choice of atom style does not have bonds. :dd
{Cannot use fix ttm with 2d simulation} :dt
This is a current restriction of this fix due to the grid it creates. :dd
{Cannot use fix ttm with triclinic box} :dt
This is a current restriction of this fix due to the grid it creates. :dd
{Cannot use fix tune/kspace without a kspace style} :dt
Self-explanatory. :dd
{Cannot use fix tune/kspace without a pair style} :dt
This fix (tune/kspace) can only be used when a pair style has been specified. :dd
{Cannot use fix wall in periodic dimension} :dt
Self-explanatory. :dd
{Cannot use fix wall zlo/zhi for a 2d simulation} :dt
Self-explanatory. :dd
{Cannot use fix wall/reflect in periodic dimension} :dt
Self-explanatory. :dd
{Cannot use fix wall/reflect zlo/zhi for a 2d simulation} :dt
Self-explanatory. :dd
{Cannot use fix wall/srd in periodic dimension} :dt
Self-explanatory. :dd
{Cannot use fix wall/srd more than once} :dt
Nor is their a need to since multiple walls can be specified
in one command. :dd
{Cannot use fix wall/srd without fix srd} :dt
Self-explanatory. :dd
{Cannot use fix wall/srd zlo/zhi for a 2d simulation} :dt
Self-explanatory. :dd
{Cannot use fix_deposit unless atoms have IDs} :dt
Self-explanatory. :dd
{Cannot use fix_pour unless atoms have IDs} :dt
Self-explanatory. :dd
{Cannot use include command within an if command} :dt
Self-explanatory. :dd
{Cannot use lines with fix srd unless overlap is set} :dt
This is because line segments are connected to each other. :dd
{Cannot use multiple fix wall commands with pair brownian} :dt
Self-explanatory. :dd
{Cannot use multiple fix wall commands with pair lubricate} :dt
Self-explanatory. :dd
{Cannot use multiple fix wall commands with pair lubricate/poly} :dt
Self-explanatory. :dd
{Cannot use multiple fix wall commands with pair lubricateU} :dt
Self-explanatory. :dd
{Cannot use neigh_modify exclude with GPU neighbor builds} :dt
This is a current limitation of the GPU implementation
in LAMMPS. :dd
{Cannot use neighbor bins - box size << cutoff} :dt
Too many neighbor bins will be created. This typically happens when
the simulation box is very small in some dimension, compared to the
neighbor cutoff. Use the "nsq" style instead of "bin" style. :dd
{Cannot use newton pair with beck/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with born/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with born/coul/wolf/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with born/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with buck/coul/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with buck/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with buck/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with colloid/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with coul/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with coul/debye/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with coul/dsf/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with dipole/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with dipole/sf/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with dpd/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with dpd/tstat/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with eam/alloy/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with eam/fs/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with eam/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with gauss/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with gayberne/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/charmm/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/class2/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/class2/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cubic/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/coul/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/coul/debye/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/coul/dsf/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/coul/msm/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/expand/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/gromacs/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/sdk/coul/long/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj/sdk/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with lj96/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with mie/cut/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with morse/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with resquared/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with soft/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with table/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with yukawa/colloid/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with yukawa/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use newton pair with zbl/gpu pair style} :dt
Self-explanatory. :dd
{Cannot use non-zero forces in an energy minimization} :dt
Fix setforce cannot be used in this manner. Use fix addforce
instead. :dd
{Cannot use nonperiodic boundares with fix ttm} :dt
This fix requires a fully periodic simulation box. :dd
{Cannot use nonperiodic boundaries with Ewald} :dt
For kspace style ewald, all 3 dimensions must have periodic boundaries
unless you use the kspace_modify command to define a 2d slab with a
non-periodic z dimension. :dd
{Cannot use nonperiodic boundaries with EwaldDisp} :dt
For kspace style ewald/disp, all 3 dimensions must have periodic
boundaries unless you use the kspace_modify command to define a 2d
slab with a non-periodic z dimension. :dd
{Cannot use nonperiodic boundaries with PPPM} :dt
For kspace style pppm, all 3 dimensions must have periodic boundaries
unless you use the kspace_modify command to define a 2d slab with a
non-periodic z dimension. :dd
{Cannot use nonperiodic boundaries with PPPMDisp} :dt
For kspace style pppm/disp, all 3 dimensions must have periodic
boundaries unless you use the kspace_modify command to define a 2d
slab with a non-periodic z dimension. :dd
{Cannot use order greater than 8 with pppm/gpu.} :dt
Self-explanatory. :dd
{Cannot use package gpu neigh yes with triclinic box} :dt
This is a current restriction in LAMMPS. :dd
{Cannot use pair hybrid with GPU neighbor list builds} :dt
Neighbor list builds must be done on the CPU for this pair style. :dd
{Cannot use pair tail corrections with 2d simulations} :dt
The correction factors are only currently defined for 3d systems. :dd
{Cannot use processors part command without using partitions} :dt
See the command-line -partition switch. :dd
{Cannot use ramp in variable formula between runs} :dt
This is because the ramp() function is time dependent. :dd
{Cannot use read_data add before simulation box is defined} :dt
Self-explanatory. :dd
{Cannot use read_data extra with add flag} :dt
Self-explanatory. :dd
{Cannot use read_data offset without add flag} :dt
Self-explanatory. :dd
{Cannot use read_data shift without add flag} :dt
Self-explanatory. :dd
{Cannot use region INF or EDGE when box does not exist} :dt
Regions that extend to the box boundaries can only be used after the
create_box command has been used. :dd
{Cannot use set atom with no atom IDs defined} :dt
Atom IDs are not defined, so they cannot be used to identify an atom. :dd
{Cannot use set mol with no molecule IDs defined} :dt
Self-explanatory. :dd
{Cannot use swiggle in variable formula between runs} :dt
This is a function of elapsed time. :dd
{Cannot use tris with fix srd unless overlap is set} :dt
This is because triangles are connected to each other. :dd
{Cannot use variable energy with constant efield in fix efield} :dt
LAMMPS computes the energy itself when the E-field is constant. :dd
{Cannot use variable energy with constant force in fix addforce} :dt
This is because for constant force, LAMMPS can compute the change
in energy directly. :dd
{Cannot use variable every setting for dump dcd} :dt
The format of DCD dump files requires snapshots be output
at a constant frequency. :dd
{Cannot use variable every setting for dump xtc} :dt
The format of this file requires snapshots at regular intervals. :dd
{Cannot use vdisplace in variable formula between runs} :dt
This is a function of elapsed time. :dd
{Cannot use velocity bias command without temp keyword} :dt
Self-explanatory. :dd
{Cannot use velocity create loop all unless atoms have IDs} :dt
Atoms in the simulation to do not have IDs, so this style
of velocity creation cannot be performed. :dd
{Cannot use wall in periodic dimension} :dt
Self-explanatory. :dd
{Cannot use write_restart fileper without % in restart file name} :dt
Self-explanatory. :dd
{Cannot use write_restart nfile without % in restart file name} :dt
Self-explanatory. :dd
{Cannot wiggle and shear fix wall/gran} :dt
Cannot specify both options at the same time. :dd
{Cannot write to restart file - MPI error: %s} :dt
This error was generated by MPI when reading/writing an MPI-IO restart
file. :dd
{Cannot yet use KSpace solver with grid with comm style tiled} :dt
This is current restriction in LAMMPS. :dd
{Cannot yet use comm_style tiled with multi-mode comm} :dt
Self-explanatory. :dd
{Cannot yet use comm_style tiled with triclinic box} :dt
Self-explanatory. :dd
{Cannot yet use compute tally with Kokkos} :dt
This feature is not yet supported. :dd
{Cannot yet use fix bond/break with this improper style} :dt
This is a current restriction in LAMMPS. :dd
{Cannot yet use fix bond/create with this improper style} :dt
This is a current restriction in LAMMPS. :dd
{Cannot yet use minimize with Kokkos} :dt
This feature is not yet supported. :dd
{Cannot yet use pair hybrid with Kokkos} :dt
This feature is not yet supported. :dd
{Cannot zero Langevin force of 0 atoms} :dt
The group has zero atoms, so you cannot request its force
be zeroed. :dd
{Cannot zero gld force for zero atoms} :dt
There are no atoms currently in the group. :dd
{Cannot zero momentum of no atoms} :dt
Self-explanatory. :dd
{Change_box command before simulation box is defined} :dt
Self-explanatory. :dd
{Change_box volume used incorrectly} :dt
The "dim volume" option must be used immediately following one or two
settings for "dim1 ..." (and optionally "dim2 ...") and must be for a
different dimension, i.e. dim != dim1 and dim != dim2. :dd
{Chunk/atom compute does not exist for compute angmom/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute com/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute gyration/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute inertia/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute msd/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute omega/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute property/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute temp/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute torque/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for compute vcm/chunk} :dt
Self-explanatory. :dd
{Chunk/atom compute does not exist for fix ave/chunk} :dt
Self-explanatory. :dd
{Comm tiled invalid index in box drop brick} :dt
Internal error check in comm_style tiled which should not occur.
Contact the developers. :dd
{Comm tiled mis-match in box drop brick} :dt
Internal error check in comm_style tiled which should not occur.
Contact the developers. :dd
{Comm_modify group != atom_modify first group} :dt
Self-explanatory. :dd
{Communication cutoff for comm_style tiled cannot exceed periodic box length} :dt
Self-explanatory. :dd
{Communication cutoff too small for SNAP micro load balancing} :dt
This can happen if you change the neighbor skin after your pair_style
command or if your box dimensions grow during a run. You can set the
cutoff explicitly via the comm_modify cutoff command. :dd
{Compute %s does not allow use of dynamic group} :dt
Dynamic groups have not yet been enabled for this compute. :dd
{Compute ID for compute chunk /atom does not exist} :dt
Self-explanatory. :dd
{Compute ID for compute chunk/atom does not exist} :dt
Self-explanatory. :dd
{Compute ID for compute reduce does not exist} :dt
Self-explanatory. :dd
{Compute ID for compute slice does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/atom does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/chunk does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/correlate does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/histo does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/spatial does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix ave/time does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix store/state does not exist} :dt
Self-explanatory. :dd
{Compute ID for fix vector does not exist} :dt
Self-explanatory. :dd
{Compute ID must be alphanumeric or underscore characters} :dt
Self-explanatory. :dd
{Compute angle/local used when angles are not allowed} :dt
The atom style does not support angles. :dd
{Compute angmom/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute body/local requires atom style body} :dt
Self-explanatory. :dd
{Compute bond/local used when bonds are not allowed} :dt
The atom style does not support bonds. :dd
{Compute centro/atom requires a pair style be defined} :dt
This is because the computation of the centro-symmetry values
uses a pairwise neighbor list. :dd
{Compute chunk/atom bin/cylinder radius is too large for periodic box} :dt
Radius cannot be bigger than 1/2 of a non-axis periodic dimension. :dd
{Compute chunk/atom bin/sphere radius is too large for periodic box} :dt
Radius cannot be bigger than 1/2 of any periodic dimension. :dd
{Compute chunk/atom compute array is accessed out-of-range} :dt
The index for the array is out of bounds. :dd
{Compute chunk/atom compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Compute chunk/atom compute does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Compute chunk/atom compute does not calculate per-atom values} :dt
Self-explanatory. :dd
{Compute chunk/atom cylinder axis must be z for 2d} :dt
Self-explanatory. :dd
{Compute chunk/atom fix array is accessed out-of-range} :dt
the index for the array is out of bounds. :dd
{Compute chunk/atom fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Compute chunk/atom fix does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Compute chunk/atom fix does not calculate per-atom values} :dt
Self-explanatory. :dd
{Compute chunk/atom for triclinic boxes requires units reduced} :dt
Self-explanatory. :dd
{Compute chunk/atom ids once but nchunk is not once} :dt
You cannot assign chunks IDs to atom permanently if the number of
chunks may change. :dd
{Compute chunk/atom molecule for non-molecular system} :dt
Self-explanatory. :dd
{Compute chunk/atom sphere z origin must be 0.0 for 2d} :dt
Self-explanatory. :dd
{Compute chunk/atom stores no IDs for compute property/chunk} :dt
It will only store IDs if its compress option is enabled. :dd
{Compute chunk/atom stores no coord1 for compute property/chunk} :dt
Only certain binning options for compute chunk/atom store coordinates. :dd
{Compute chunk/atom stores no coord2 for compute property/chunk} :dt
Only certain binning options for compute chunk/atom store coordinates. :dd
{Compute chunk/atom stores no coord3 for compute property/chunk} :dt
Only certain binning options for compute chunk/atom store coordinates. :dd
{Compute chunk/atom variable is not atom-style variable} :dt
Self-explanatory. :dd
{Compute chunk/atom without bins cannot use discard mixed} :dt
That discard option only applies to the binning styles. :dd
{Compute cluster/atom cutoff is longer than pairwise cutoff} :dt
Cannot identify clusters beyond cutoff. :dd
{Compute cluster/atom requires a pair style be defined} :dt
This is so that the pair style defines a cutoff distance which
is used to find clusters. :dd
{Compute cna/atom cutoff is longer than pairwise cutoff} :dt
Self-explanatory. :dd
{Compute cna/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute com/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute contact/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute contact/atom requires atom style sphere} :dt
Self-explanatory. :dd
{Compute coord/atom cutoff is longer than pairwise cutoff} :dt
Cannot compute coordination at distances longer than the pair cutoff,
since those atoms are not in the neighbor list. :dd
{Compute coord/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute damage/atom requires peridynamic potential} :dt
Damage is a Peridynamic-specific metric. It requires you
to be running a Peridynamics simulation. :dd
{Compute dihedral/local used when dihedrals are not allowed} :dt
The atom style does not support dihedrals. :dd
{Compute dilatation/atom cannot be used with this pair style} :dt
Self-explanatory. :dd
{Compute dilatation/atom requires Peridynamic pair style} :dt
Self-explanatory. :dd
{Compute does not allow an extra compute or fix to be reset} :dt
This is an internal LAMMPS error. Please report it to the
developers. :dd
{Compute erotate/asphere requires atom style ellipsoid or line or tri} :dt
Self-explanatory. :dd
{Compute erotate/asphere requires extended particles} :dt
This compute cannot be used with point particles. :dd
{Compute erotate/rigid with non-rigid fix-ID} :dt
Self-explanatory. :dd
{Compute erotate/sphere requires atom style sphere} :dt
Self-explanatory. :dd
{Compute erotate/sphere/atom requires atom style sphere} :dt
Self-explanatory. :dd
{Compute event/displace has invalid fix event assigned} :dt
This is an internal LAMMPS error. Please report it to the
developers. :dd
{Compute group/group group ID does not exist} :dt
Self-explanatory. :dd
{Compute gyration/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute heat/flux compute ID does not compute ke/atom} :dt
Self-explanatory. :dd
{Compute heat/flux compute ID does not compute pe/atom} :dt
Self-explanatory. :dd
{Compute heat/flux compute ID does not compute stress/atom} :dt
Self-explanatory. :dd
{Compute hexorder/atom cutoff is longer than pairwise cutoff} :dt
Cannot compute order parameter beyond cutoff. :dd
{Compute hexorder/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute improper/local used when impropers are not allowed} :dt
The atom style does not support impropers. :dd
{Compute inertia/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute ke/rigid with non-rigid fix-ID} :dt
Self-explanatory. :dd
{Compute msd/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute msd/chunk nchunk is not static} :dt
This is required because the MSD cannot be computed consistently if
the number of chunks is changing. Compute chunk/atom allows setting
nchunk to be static. :dd
{Compute nve/asphere requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Compute nvt/nph/npt asphere requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Compute nvt/nph/npt body requires atom style body} :dt
Self-explanatory. :dd
{Compute omega/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute orientorder/atom cutoff is longer than pairwise cutoff} :dt
Cannot compute order parameter beyond cutoff. :dd
{Compute orientorder/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute pair must use group all} :dt
Pair styles accumulate energy on all atoms. :dd
{Compute pe must use group all} :dt
Energies computed by potentials (pair, bond, etc) are computed on all
atoms. :dd
{Compute plasticity/atom cannot be used with this pair style} :dt
Self-explanatory. :dd
{Compute plasticity/atom requires Peridynamic pair style} :dt
Self-explanatory. :dd
{Compute pressure must use group all} :dt
Virial contributions computed by potentials (pair, bond, etc) are
computed on all atoms. :dd
{Compute pressure requires temperature ID to include kinetic energy} :dt
The keflag cannot be used unless a temperature compute is provided. :dd
{Compute pressure temperature ID does not compute temperature} :dt
The compute ID assigned to a pressure computation must compute
temperature. :dd
{Compute property/atom floating point vector does not exist} :dt
The command is accessing a vector added by the fix property/atom
command, that does not exist. :dd
{Compute property/atom for atom property that isn't allocated} :dt
Self-explanatory. :dd
{Compute property/atom integer vector does not exist} :dt
The command is accessing a vector added by the fix property/atom
command, that does not exist. :dd
{Compute property/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute property/local cannot use these inputs together} :dt
Only inputs that generate the same number of datums can be used
together. E.g. bond and angle quantities cannot be mixed. :dd
{Compute property/local does not (yet) work with atom_style template} :dt
Self-explanatory. :dd
{Compute property/local for property that isn't allocated} :dt
Self-explanatory. :dd
{Compute rdf requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute reduce compute array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Compute reduce compute calculates global values} :dt
A compute that calculates peratom or local values is required. :dd
{Compute reduce compute does not calculate a local array} :dt
Self-explanatory. :dd
{Compute reduce compute does not calculate a local vector} :dt
Self-explanatory. :dd
{Compute reduce compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Compute reduce compute does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Compute reduce fix array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Compute reduce fix calculates global values} :dt
A fix that calculates peratom or local values is required. :dd
{Compute reduce fix does not calculate a local array} :dt
Self-explanatory. :dd
{Compute reduce fix does not calculate a local vector} :dt
Self-explanatory. :dd
{Compute reduce fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Compute reduce fix does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Compute reduce replace requires min or max mode} :dt
Self-explanatory. :dd
{Compute reduce variable is not atom-style variable} :dt
Self-explanatory. :dd
{Compute slice compute array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Compute slice compute does not calculate a global array} :dt
Self-explanatory. :dd
{Compute slice compute does not calculate a global vector} :dt
Self-explanatory. :dd
{Compute slice compute does not calculate global vector or array} :dt
Self-explanatory. :dd
{Compute slice compute vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Compute slice fix array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Compute slice fix does not calculate a global array} :dt
Self-explanatory. :dd
{Compute slice fix does not calculate a global vector} :dt
Self-explanatory. :dd
{Compute slice fix does not calculate global vector or array} :dt
Self-explanatory. :dd
{Compute slice fix vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Compute sna/atom cutoff is longer than pairwise cutoff} :dt
Self-explanatory. :dd
{Compute sna/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute snad/atom cutoff is longer than pairwise cutoff} :dt
Self-explanatory. :dd
{Compute snad/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute snav/atom cutoff is longer than pairwise cutoff} :dt
Self-explanatory. :dd
{Compute snav/atom requires a pair style be defined} :dt
Self-explanatory. :dd
{Compute stress/atom temperature ID does not compute temperature} :dt
The specified compute must compute temperature. :dd
{Compute temp/asphere requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Compute temp/asphere requires extended particles} :dt
This compute cannot be used with point particles. :dd
{Compute temp/body requires atom style body} :dt
Self-explanatory. :dd
{Compute temp/body requires bodies} :dt
This compute can only be applied to body particles. :dd
{Compute temp/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute temp/cs requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Compute temp/cs used when bonds are not allowed} :dt
This compute only works on pairs of bonded particles. :dd
{Compute temp/partial cannot use vz for 2d systemx} :dt
Self-explanatory. :dd
{Compute temp/profile cannot bin z for 2d systems} :dt
Self-explanatory. :dd
{Compute temp/profile cannot use vz for 2d systemx} :dt
Self-explanatory. :dd
{Compute temp/sphere requires atom style sphere} :dt
Self-explanatory. :dd
{Compute ti kspace style does not exist} :dt
Self-explanatory. :dd
{Compute ti pair style does not exist} :dt
Self-explanatory. :dd
{Compute ti tail when pair style does not compute tail corrections} :dt
Self-explanatory. :dd
{Compute torque/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Compute used in dump between runs is not current} :dt
The compute was not invoked on the current timestep, therefore it
cannot be used in a dump between runs. :dd
{Compute used in variable between runs is not current} :dt
Computes cannot be invoked by a variable in between runs. Thus they
must have been evaluated on the last timestep of the previous run in
order for their value(s) to be accessed. See the doc page for the
variable command for more info. :dd
{Compute used in variable thermo keyword between runs is not current} :dt
Some thermo keywords rely on a compute to calculate their value(s).
Computes cannot be invoked by a variable in between runs. Thus they
must have been evaluated on the last timestep of the previous run in
order for their value(s) to be accessed. See the doc page for the
variable command for more info. :dd
{Compute vcm/chunk does not use chunk/atom compute} :dt
The style of the specified compute is not chunk/atom. :dd
{Computed temperature for fix temp/berendsen cannot be 0.0} :dt
Self-explanatory. :dd
{Computed temperature for fix temp/rescale cannot be 0.0} :dt
Cannot rescale the temperature to a new value if the current
temperature is 0.0. :dd
{Core/shell partner atom not found} :dt
Could not find one of the atoms in the bond pair. :dd
{Core/shell partners were not all found} :dt
Could not find or more atoms in the bond pairs. :dd
{Could not adjust g_ewald_6} :dt
The Newton-Raphson solver failed to converge to a good value for
g_ewald. This error should not occur for typical problems. Please
send an email to the developers. :dd
{Could not compute g_ewald} :dt
The Newton-Raphson solver failed to converge to a good value for
g_ewald. This error should not occur for typical problems. Please
send an email to the developers. :dd
{Could not compute grid size} :dt
The code is unable to compute a grid size consistent with the desired
accuracy. This error should not occur for typical problems. Please
send an email to the developers. :dd
{Could not compute grid size for Coulomb interaction} :dt
The code is unable to compute a grid size consistent with the desired
accuracy. This error should not occur for typical problems. Please
send an email to the developers. :dd
{Could not compute grid size for Dispersion} :dt
The code is unable to compute a grid size consistent with the desired
accuracy. This error should not occur for typical problems. Please
send an email to the developers. :dd
{Could not create 3d FFT plan} :dt
The FFT setup for the PPPM solver failed, typically due
to lack of memory. This is an unusual error. Check the
size of the FFT grid you are requesting. :dd
{Could not create 3d grid of processors} :dt
The specified constraints did not allow a Px by Py by Pz grid to be
created where Px * Py * Pz = P = total number of processors. :dd
{Could not create 3d remap plan} :dt
The FFT setup in pppm failed. :dd
{Could not create Python function arguments} :dt
This is an internal Python error, possibly because the number
of inputs to the function is too large. :dd
{Could not create numa grid of processors} :dt
The specified constraints did not allow this style of grid to be
created. Usually this is because the total processor count is not a
multiple of the cores/node or the user specified processor count is >
1 in one of the dimensions. :dd
{Could not create twolevel 3d grid of processors} :dt
The specified constraints did not allow this style of grid to be
created. :dd
{Could not evaluate Python function input variable} :dt
Self-explanatory. :dd
{Could not find Python function} :dt
The provided Python code was run successfully, but it not
define a callable function with the required name. :dd
{Could not find atom_modify first group ID} :dt
Self-explanatory. :dd
{Could not find change_box group ID} :dt
Group ID used in the change_box command does not exist. :dd
{Could not find compute ID for PRD} :dt
Self-explanatory. :dd
{Could not find compute ID for TAD} :dt
Self-explanatory. :dd
{Could not find compute ID for temperature bias} :dt
Self-explanatory. :dd
{Could not find compute ID to delete} :dt
Self-explanatory. :dd
{Could not find compute displace/atom fix ID} :dt
Self-explanatory. :dd
{Could not find compute event/displace fix ID} :dt
Self-explanatory. :dd
{Could not find compute group ID} :dt
Self-explanatory. :dd
{Could not find compute heat/flux compute ID} :dt
Self-explanatory. :dd
{Could not find compute msd fix ID} :dt
Self-explanatory. :dd
{Could not find compute msd/chunk fix ID} :dt
The compute creates an internal fix, which has been deleted. :dd
{Could not find compute pressure temperature ID} :dt
The compute ID for calculating temperature does not exist. :dd
{Could not find compute stress/atom temperature ID} :dt
Self-explanatory. :dd
{Could not find compute vacf fix ID} :dt
Self-explanatory. :dd
{Could not find compute/voronoi surface group ID} :dt
Self-explanatory. :dd
{Could not find compute_modify ID} :dt
Self-explanatory. :dd
{Could not find custom per-atom property ID} :dt
Self-explanatory. :dd
{Could not find delete_atoms group ID} :dt
Group ID used in the delete_atoms command does not exist. :dd
{Could not find delete_atoms region ID} :dt
Region ID used in the delete_atoms command does not exist. :dd
{Could not find displace_atoms group ID} :dt
Group ID used in the displace_atoms command does not exist. :dd
{Could not find dump custom compute ID} :dt
Self-explanatory. :dd
{Could not find dump custom fix ID} :dt
Self-explanatory. :dd
{Could not find dump custom variable name} :dt
Self-explanatory. :dd
{Could not find dump group ID} :dt
A group ID used in the dump command does not exist. :dd
{Could not find dump local compute ID} :dt
Self-explanatory. :dd
{Could not find dump local fix ID} :dt
Self-explanatory. :dd
{Could not find dump modify compute ID} :dt
Self-explanatory. :dd
{Could not find dump modify custom atom floating point property ID} :dt
Self-explanatory. :dd
{Could not find dump modify custom atom integer property ID} :dt
Self-explanatory. :dd
{Could not find dump modify fix ID} :dt
Self-explanatory. :dd
{Could not find dump modify variable name} :dt
Self-explanatory. :dd
{Could not find fix ID to delete} :dt
Self-explanatory. :dd
{Could not find fix adapt storage fix ID} :dt
This should not happen unless you explicitly deleted
a secondary fix that fix adapt created internally. :dd
{Could not find fix gcmc exclusion group ID} :dt
Self-explanatory. :dd
{Could not find fix gcmc rotation group ID} :dt
Self-explanatory. :dd
{Could not find fix group ID} :dt
A group ID used in the fix command does not exist. :dd
{Could not find fix msst compute ID} :dt
Self-explanatory. :dd
{Could not find fix poems group ID} :dt
A group ID used in the fix poems command does not exist. :dd
{Could not find fix recenter group ID} :dt
A group ID used in the fix recenter command does not exist. :dd
{Could not find fix rigid group ID} :dt
A group ID used in the fix rigid command does not exist. :dd
{Could not find fix srd group ID} :dt
Self-explanatory. :dd
{Could not find fix_modify ID} :dt
A fix ID used in the fix_modify command does not exist. :dd
{Could not find fix_modify pressure ID} :dt
The compute ID for computing pressure does not exist. :dd
{Could not find fix_modify temperature ID} :dt
The compute ID for computing temperature does not exist. :dd
{Could not find group clear group ID} :dt
Self-explanatory. :dd
{Could not find group delete group ID} :dt
Self-explanatory. :dd
{Could not find pair fix ID} :dt
A fix is created internally by the pair style to store shear
history information. You cannot delete it. :dd
{Could not find set group ID} :dt
Group ID specified in set command does not exist. :dd
{Could not find specified fix gcmc group ID} :dt
Self-explanatory. :dd
{Could not find thermo compute ID} :dt
Compute ID specified in thermo_style command does not exist. :dd
{Could not find thermo custom compute ID} :dt
The compute ID needed by thermo style custom to compute a requested
quantity does not exist. :dd
{Could not find thermo custom fix ID} :dt
The fix ID needed by thermo style custom to compute a requested
quantity does not exist. :dd
{Could not find thermo custom variable name} :dt
Self-explanatory. :dd
{Could not find thermo fix ID} :dt
Fix ID specified in thermo_style command does not exist. :dd
{Could not find thermo variable name} :dt
Self-explanatory. :dd
{Could not find thermo_modify pressure ID} :dt
The compute ID needed by thermo style custom to compute pressure does
not exist. :dd
{Could not find thermo_modify temperature ID} :dt
The compute ID needed by thermo style custom to compute temperature does
not exist. :dd
{Could not find undump ID} :dt
A dump ID used in the undump command does not exist. :dd
{Could not find velocity group ID} :dt
A group ID used in the velocity command does not exist. :dd
{Could not find velocity temperature ID} :dt
The compute ID needed by the velocity command to compute temperature
does not exist. :dd
{Could not find/initialize a specified accelerator device} :dt
Could not initialize at least one of the devices specified for the gpu
package :dd
{Could not grab element entry from EIM potential file} :dt
Self-explanatory :dd
{Could not grab global entry from EIM potential file} :dt
Self-explanatory. :dd
{Could not grab pair entry from EIM potential file} :dt
Self-explanatory. :dd
{Could not initialize embedded Python} :dt
The main module in Python was not accessible. :dd
{Could not open Python file} :dt
The specified file of Python code cannot be opened. Check that the
path and name are correct. :dd
{Could not process Python file} :dt
The Python code in the specified file was not run successfully by
Python, probably due to errors in the Python code. :dd
{Could not process Python string} :dt
The Python code in the here string was not run successfully by Python,
probably due to errors in the Python code. :dd
{Coulomb PPPMDisp order has been reduced below minorder} :dt
The default minimum order is 2. This can be reset by the
kspace_modify minorder command. :dd
{Coulomb cut not supported in pair_style buck/long/coul/coul} :dt
Must use long-range Coulombic interactions. :dd
{Coulomb cut not supported in pair_style lj/long/coul/long} :dt
Must use long-range Coulombic interactions. :dd
{Coulomb cut not supported in pair_style lj/long/tip4p/long} :dt
Must use long-range Coulombic interactions. :dd
{Coulomb cutoffs of pair hybrid sub-styles do not match} :dt
If using a Kspace solver, all Coulomb cutoffs of long pair styles must
be the same. :dd
{Coulombic cut not supported in pair_style lj/long/dipole/long} :dt
Must use long-range Coulombic interactions. :dd
{Cound not find dump_modify ID} :dt
Self-explanatory. :dd
{Create_atoms command before simulation box is defined} :dt
The create_atoms command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Create_atoms molecule has atom IDs, but system does not} :dt
The atom_style id command can be used to force atom IDs to be stored. :dd
{Create_atoms molecule must have atom types} :dt
The defined molecule does not specify atom types. :dd
{Create_atoms molecule must have coordinates} :dt
The defined molecule does not specify coordinates. :dd
{Create_atoms region ID does not exist} :dt
A region ID used in the create_atoms command does not exist. :dd
{Create_bonds command before simulation box is defined} :dt
Self-explanatory. :dd
{Create_bonds command requires no kspace_style be defined} :dt
This is so that atom pairs that are already bonded to not appear
in the neighbor list. :dd
{Create_bonds command requires special_bonds 1-2 weights be 0.0} :dt
This is so that atom pairs that are already bonded to not appear in
the neighbor list. :dd
{Create_bonds max distance > neighbor cutoff} :dt
Can only create bonds for atom pairs that will be in neighbor list. :dd
{Create_bonds requires a pair style be defined} :dt
Self-explanatory. :dd
{Create_box region ID does not exist} :dt
Self-explanatory. :dd
{Create_box region does not support a bounding box} :dt
Not all regions represent bounded volumes. You cannot use
such a region with the create_box command. :dd
{Custom floating point vector for fix store/state does not exist} :dt
The command is accessing a vector added by the fix property/atom
command, that does not exist. :dd
{Custom integer vector for fix store/state does not exist} :dt
The command is accessing a vector added by the fix property/atom
command, that does not exist. :dd
{Custom per-atom property ID is not floating point} :dt
Self-explanatory. :dd
{Custom per-atom property ID is not integer} :dt
Self-explanatory. :dd
{Cut-offs missing in pair_style lj/long/dipole/long} :dt
Self-explanatory. :dd
{Cutoffs missing in pair_style buck/long/coul/long} :dt
Self-explanatory. :dd
{Cutoffs missing in pair_style lj/long/coul/long} :dt
Self-explanatory. :dd
{Cyclic loop in joint connections} :dt
Fix poems cannot (yet) work with coupled bodies whose joints connect
the bodies in a ring (or cycle). :dd
{Degenerate lattice primitive vectors} :dt
Invalid set of 3 lattice vectors for lattice command. :dd
{Delete region ID does not exist} :dt
Self-explanatory. :dd
{Delete_atoms command before simulation box is defined} :dt
The delete_atoms command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Delete_atoms cutoff > max neighbor cutoff} :dt
Can only delete atoms in atom pairs that will be in neighbor list. :dd
{Delete_atoms mol yes requires atom attribute molecule} :dt
Cannot use this option with a non-molecular system. :dd
{Delete_atoms requires a pair style be defined} :dt
This is because atom deletion within a cutoff uses a pairwise
neighbor list. :dd
{Delete_bonds command before simulation box is defined} :dt
The delete_bonds command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Delete_bonds command with no atoms existing} :dt
No atoms are yet defined so the delete_bonds command cannot be used. :dd
{Deposition region extends outside simulation box} :dt
Self-explanatory. :dd
{Did not assign all atoms correctly} :dt
Atoms read in from a data file were not assigned correctly to
processors. This is likely due to some atom coordinates being
outside a non-periodic simulation box. :dd
{Did not assign all restart atoms correctly} :dt
Atoms read in from the restart file were not assigned correctly to
processors. This is likely due to some atom coordinates being outside
a non-periodic simulation box. Normally this should not happen. You
may wish to use the "remap" option on the read_restart command to see
if this helps. :dd
{Did not find all elements in MEAM library file} :dt
The requested elements were not found in the MEAM file. :dd
{Did not find fix shake partner info} :dt
Could not find bond partners implied by fix shake command. This error
can be triggered if the delete_bonds command was used before fix
shake, and it removed bonds without resetting the 1-2, 1-3, 1-4
weighting list via the special keyword. :dd
{Did not find keyword in table file} :dt
Keyword used in pair_coeff command was not found in table file. :dd
{Did not set pressure for fix rigid/nph} :dt
The press keyword must be specified. :dd
{Did not set temp for fix rigid/nvt/small} :dt
Self-explanatory. :dd
{Did not set temp or press for fix rigid/npt/small} :dt
Self-explanatory. :dd
{Did not set temperature for fix rigid/nvt} :dt
The temp keyword must be specified. :dd
{Did not set temperature or pressure for fix rigid/npt} :dt
The temp and press keywords must be specified. :dd
{Dihedral atom missing in delete_bonds} :dt
The delete_bonds command cannot find one or more atoms in a particular
dihedral on a particular processor. The pairwise cutoff is too short
or the atoms are too far apart to make a valid dihedral. :dd
{Dihedral atom missing in set command} :dt
The set command cannot find one or more atoms in a particular dihedral
on a particular processor. The pairwise cutoff is too short or the
atoms are too far apart to make a valid dihedral. :dd
{Dihedral atoms %d %d %d %d missing on proc %d at step %ld} :dt
One or more of 4 atoms needed to compute a particular dihedral are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the dihedral has blown apart and an atom is
too far away. :dd
{Dihedral atoms missing on proc %d at step %ld} :dt
One or more of 4 atoms needed to compute a particular dihedral are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the dihedral has blown apart and an atom is
too far away. :dd
{Dihedral charmm is incompatible with Pair style} :dt
Dihedral style charmm must be used with a pair style charmm
in order for the 1-4 epsilon/sigma parameters to be defined. :dd
{Dihedral coeff for hybrid has invalid style} :dt
Dihedral style hybrid uses another dihedral style as one of its
coefficients. The dihedral style used in the dihedral_coeff command
or read from a restart file is not recognized. :dd
{Dihedral coeffs are not set} :dt
No dihedral coefficients have been assigned in the data file or via
the dihedral_coeff command. :dd
{Dihedral style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Dihedral style hybrid cannot have none as an argument} :dt
Self-explanatory. :dd
{Dihedral style hybrid cannot use same dihedral style twice} :dt
Self-explanatory. :dd
{Dihedral/improper extent > half of periodic box length} :dt
This error was detected by the neigh_modify check yes setting. It is
an error because the dihedral atoms are so far apart it is ambiguous
how it should be defined. :dd
{Dihedral_coeff command before dihedral_style is defined} :dt
Coefficients cannot be set in the data file or via the dihedral_coeff
command until an dihedral_style has been assigned. :dd
{Dihedral_coeff command before simulation box is defined} :dt
The dihedral_coeff command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Dihedral_coeff command when no dihedrals allowed} :dt
The chosen atom style does not allow for dihedrals to be defined. :dd
{Dihedral_style command when no dihedrals allowed} :dt
The chosen atom style does not allow for dihedrals to be defined. :dd
{Dihedrals assigned incorrectly} :dt
Dihedrals read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions. :dd
{Dihedrals defined but no dihedral types} :dt
The data file header lists dihedrals but no dihedral types. :dd
{Dimension command after simulation box is defined} :dt
The dimension command cannot be used after a read_data,
read_restart, or create_box command. :dd
{Dispersion PPPMDisp order has been reduced below minorder} :dt
The default minimum order is 2. This can be reset by the
kspace_modify minorder command. :dd
{Displace_atoms command before simulation box is defined} :dt
The displace_atoms command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Distance must be > 0 for compute event/displace} :dt
Self-explanatory. :dd
{Divide by 0 in influence function} :dt
This should not normally occur. It is likely a problem with your
model. :dd
{Divide by 0 in influence function of pair peri/lps} :dt
This should not normally occur. It is likely a problem with your
model. :dd
{Divide by 0 in variable formula} :dt
Self-explanatory. :dd
{Domain too large for neighbor bins} :dt
The domain has become extremely large so that neighbor bins cannot be
used. Most likely, one or more atoms have been blown out of the
simulation box to a great distance. :dd
{Double precision is not supported on this accelerator} :dt
Self-explanatory :dd
{Dump atom/gz only writes compressed files} :dt
The dump atom/gz output file name must have a .gz suffix. :dd
{Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu} :dt
Self-explanatory. :dd
{Dump cfg arguments must start with 'mass type xs ys zs' or 'mass type xsu ysu zsu'} :dt
This is a requirement of the CFG output format. See the dump cfg doc
page for more details. :dd
{Dump cfg requires one snapshot per file} :dt
Use the wildcard "*" character in the filename. :dd
{Dump cfg/gz only writes compressed files} :dt
The dump cfg/gz output file name must have a .gz suffix. :dd
{Dump custom and fix not computed at compatible times} :dt
The fix must produce per-atom quantities on timesteps that dump custom
needs them. :dd
{Dump custom compute does not calculate per-atom array} :dt
Self-explanatory. :dd
{Dump custom compute does not calculate per-atom vector} :dt
Self-explanatory. :dd
{Dump custom compute does not compute per-atom info} :dt
Self-explanatory. :dd
{Dump custom compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Dump custom fix does not compute per-atom array} :dt
Self-explanatory. :dd
{Dump custom fix does not compute per-atom info} :dt
Self-explanatory. :dd
{Dump custom fix does not compute per-atom vector} :dt
Self-explanatory. :dd
{Dump custom fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Dump custom variable is not atom-style variable} :dt
Only atom-style variables generate per-atom quantities, needed for
dump output. :dd
{Dump custom/gz only writes compressed files} :dt
The dump custom/gz output file name must have a .gz suffix. :dd
{Dump dcd of non-matching # of atoms} :dt
Every snapshot written by dump dcd must contain the same # of atoms. :dd
{Dump dcd requires sorting by atom ID} :dt
Use the dump_modify sort command to enable this. :dd
{Dump every variable returned a bad timestep} :dt
The variable must return a timestep greater than the current timestep. :dd
{Dump file MPI-IO output not allowed with % in filename} :dt
This is because a % signifies one file per processor and MPI-IO
creates one large file for all processors. :dd
{Dump file does not contain requested snapshot} :dt
Self-explanatory. :dd
{Dump file is incorrectly formatted} :dt
Self-explanatory. :dd
{Dump image body yes requires atom style body} :dt
Self-explanatory. :dd
{Dump image bond not allowed with no bond types} :dt
Self-explanatory. :dd
{Dump image cannot perform sorting} :dt
Self-explanatory. :dd
{Dump image line requires atom style line} :dt
Self-explanatory. :dd
{Dump image persp option is not yet supported} :dt
Self-explanatory. :dd
{Dump image requires one snapshot per file} :dt
Use a "*" in the filename. :dd
{Dump image tri requires atom style tri} :dt
Self-explanatory. :dd
{Dump local and fix not computed at compatible times} :dt
The fix must produce per-atom quantities on timesteps that dump local
needs them. :dd
{Dump local attributes contain no compute or fix} :dt
Self-explanatory. :dd
{Dump local cannot sort by atom ID} :dt
This is because dump local does not really dump per-atom info. :dd
{Dump local compute does not calculate local array} :dt
Self-explanatory. :dd
{Dump local compute does not calculate local vector} :dt
Self-explanatory. :dd
{Dump local compute does not compute local info} :dt
Self-explanatory. :dd
{Dump local compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Dump local count is not consistent across input fields} :dt
Every column of output must be the same length. :dd
{Dump local fix does not compute local array} :dt
Self-explanatory. :dd
{Dump local fix does not compute local info} :dt
Self-explanatory. :dd
{Dump local fix does not compute local vector} :dt
Self-explanatory. :dd
{Dump local fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Dump modify bcolor not allowed with no bond types} :dt
Self-explanatory. :dd
{Dump modify bdiam not allowed with no bond types} :dt
Self-explanatory. :dd
{Dump modify compute ID does not compute per-atom array} :dt
Self-explanatory. :dd
{Dump modify compute ID does not compute per-atom info} :dt
Self-explanatory. :dd
{Dump modify compute ID does not compute per-atom vector} :dt
Self-explanatory. :dd
{Dump modify compute ID vector is not large enough} :dt
Self-explanatory. :dd
{Dump modify element names do not match atom types} :dt
Number of element names must equal number of atom types. :dd
{Dump modify fix ID does not compute per-atom array} :dt
Self-explanatory. :dd
{Dump modify fix ID does not compute per-atom info} :dt
Self-explanatory. :dd
{Dump modify fix ID does not compute per-atom vector} :dt
Self-explanatory. :dd
{Dump modify fix ID vector is not large enough} :dt
Self-explanatory. :dd
{Dump modify variable is not atom-style variable} :dt
Self-explanatory. :dd
{Dump sort column is invalid} :dt
Self-explanatory. :dd
{Dump xtc requires sorting by atom ID} :dt
Use the dump_modify sort command to enable this. :dd
{Dump xyz/gz only writes compressed files} :dt
The dump xyz/gz output file name must have a .gz suffix. :dd
{Dump_modify buffer yes not allowed for this style} :dt
Self-explanatory. :dd
{Dump_modify format string is too short} :dt
There are more fields to be dumped in a line of output than your
format string specifies. :dd
{Dump_modify region ID does not exist} :dt
Self-explanatory. :dd
{Dumping an atom property that isn't allocated} :dt
The chosen atom style does not define the per-atom quantity being
dumped. :dd
{Duplicate atom IDs exist} :dt
Self-explanatory. :dd
{Duplicate fields in read_dump command} :dt
Self-explanatory. :dd
{Duplicate particle in PeriDynamic bond - simulation box is too small} :dt
This is likely because your box length is shorter than 2 times
the bond length. :dd
{Electronic temperature dropped below zero} :dt
Something has gone wrong with the fix ttm electron temperature model. :dd
{Element not defined in potential file} :dt
The specified element is not in the potential file. :dd
{Empty brackets in variable} :dt
There is no variable syntax that uses empty brackets. Check
the variable doc page. :dd
{Energy was not tallied on needed timestep} :dt
You are using a thermo keyword that requires potentials to
have tallied energy, but they didn't on this timestep. See the
variable doc page for ideas on how to make this work. :dd
{Epsilon or sigma reference not set by pair style in PPPMDisp} :dt
Self-explanatory. :dd
{Epsilon or sigma reference not set by pair style in ewald/n} :dt
The pair style is not providing the needed epsilon or sigma values. :dd
{Error in vdw spline: inner radius > outer radius} :dt
A pre-tabulated spline is invalid. Likely a problem with the
potential parameters. :dd
{Error writing averaged chunk data} :dt
Something in the output to the file triggered an error. :dd
{Error writing file header} :dt
Something in the output to the file triggered an error. :dd
{Error writing out correlation data} :dt
Something in the output to the file triggered an error. :dd
{Error writing out histogram data} :dt
Something in the output to the file triggered an error. :dd
{Error writing out time averaged data} :dt
Something in the output to the file triggered an error. :dd
{Failed to allocate %ld bytes for array %s} :dt
Your LAMMPS simulation has run out of memory. You need to run a
smaller simulation or on more processors. :dd
{Failed to open FFmpeg pipeline to file %s} :dt
The specified file cannot be opened. Check that the path and name are
correct and writable and that the FFmpeg executable can be found and run. :dd
{Failed to reallocate %ld bytes for array %s} :dt
Your LAMMPS simulation has run out of memory. You need to run a
smaller simulation or on more processors. :dd
{Fewer SRD bins than processors in some dimension} :dt
This is not allowed. Make your SRD bin size smaller. :dd
{File variable could not read value} :dt
Check the file assigned to the variable. :dd
{Final box dimension due to fix deform is < 0.0} :dt
Self-explanatory. :dd
{Fix %s does not allow use of dynamic group} :dt
Dynamic groups have not yet been enabled for this fix. :dd
{Fix ID for compute chunk/atom does not exist} :dt
Self-explanatory. :dd
{Fix ID for compute erotate/rigid does not exist} :dt
Self-explanatory. :dd
{Fix ID for compute ke/rigid does not exist} :dt
Self-explanatory. :dd
{Fix ID for compute reduce does not exist} :dt
Self-explanatory. :dd
{Fix ID for compute slice does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/atom does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/chunk does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/correlate does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/histo does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/spatial does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix ave/time does not exist} :dt
Self-explanatory. :dd
{Fix ID for fix store/state does not exist} :dt
Self-explanatory :dd
{Fix ID for fix vector does not exist} :dt
Self-explanatory. :dd
{Fix ID for read_data does not exist} :dt
Self-explanatory. :dd
{Fix ID for velocity does not exist} :dt
Self-explanatory. :dd
{Fix ID must be alphanumeric or underscore characters} :dt
Self-explanatory. :dd
{Fix SRD: bad bin assignment for SRD advection} :dt
Something has gone wrong in your SRD model; try using more
conservative settings. :dd
{Fix SRD: bad search bin assignment} :dt
Something has gone wrong in your SRD model; try using more
conservative settings. :dd
{Fix SRD: bad stencil bin for big particle} :dt
Something has gone wrong in your SRD model; try using more
conservative settings. :dd
{Fix SRD: too many big particles in bin} :dt
Reset the ATOMPERBIN parameter at the top of fix_srd.cpp
to a larger value, and re-compile the code. :dd
{Fix SRD: too many walls in bin} :dt
This should not happen unless your system has been setup incorrectly. :dd
{Fix adapt interface to this pair style not supported} :dt
New coding for the pair style would need to be done. :dd
{Fix adapt kspace style does not exist} :dt
Self-explanatory. :dd
{Fix adapt pair style does not exist} :dt
Self-explanatory :dd
{Fix adapt pair style param not supported} :dt
The pair style does not know about the parameter you specified. :dd
{Fix adapt requires atom attribute charge} :dt
The atom style being used does not specify an atom charge. :dd
{Fix adapt requires atom attribute diameter} :dt
The atom style being used does not specify an atom diameter. :dd
{Fix adapt type pair range is not valid for pair hybrid sub-style} :dt
Self-explanatory. :dd
{Fix append/atoms requires a lattice be defined} :dt
Use the lattice command for this purpose. :dd
{Fix ave/atom compute array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/atom compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/atom compute does not calculate a per-atom vector} :dt
A compute used by fix ave/atom must generate per-atom values. :dd
{Fix ave/atom compute does not calculate per-atom values} :dt
A compute used by fix ave/atom must generate per-atom values. :dd
{Fix ave/atom fix array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/atom fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/atom fix does not calculate a per-atom vector} :dt
A fix used by fix ave/atom must generate per-atom values. :dd
{Fix ave/atom fix does not calculate per-atom values} :dt
A fix used by fix ave/atom must generate per-atom values. :dd
{Fix ave/atom variable is not atom-style variable} :dt
A variable used by fix ave/atom must generate per-atom values. :dd
{Fix ave/chunk compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/chunk compute does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Fix ave/chunk compute does not calculate per-atom values} :dt
Self-explanatory. :dd
{Fix ave/chunk compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/chunk does not use chunk/atom compute} :dt
The specified compute is not for a compute chunk/atom command. :dd
{Fix ave/chunk fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/chunk fix does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Fix ave/chunk fix does not calculate per-atom values} :dt
Self-explanatory. :dd
{Fix ave/chunk fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/chunk variable is not atom-style variable} :dt
Self-explanatory. :dd
{Fix ave/correlate compute does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix ave/correlate compute does not calculate a vector} :dt
Self-explanatory. :dd
{Fix ave/correlate compute vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/correlate fix does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix ave/correlate fix does not calculate a vector} :dt
Self-explanatory. :dd
{Fix ave/correlate fix vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/correlate variable is not equal-style variable} :dt
Self-explanatory. :dd
{Fix ave/histo cannot input local values in scalar mode} :dt
Self-explanatory. :dd
{Fix ave/histo cannot input per-atom values in scalar mode} :dt
Self-explanatory. :dd
{Fix ave/histo compute array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a global array} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a global scalar} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a global vector} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a local array} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a local vector} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate local values} :dt
Self-explanatory. :dd
{Fix ave/histo compute does not calculate per-atom values} :dt
Self-explanatory. :dd
{Fix ave/histo compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/histo fix array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a global array} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a global scalar} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a global vector} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a local array} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a local vector} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate a per-atom vector} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate local values} :dt
Self-explanatory. :dd
{Fix ave/histo fix does not calculate per-atom values} :dt
Self-explanatory. :dd
{Fix ave/histo fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix ave/histo input is invalid compute} :dt
Self-explanatory. :dd
{Fix ave/histo input is invalid fix} :dt
Self-explanatory. :dd
{Fix ave/histo input is invalid variable} :dt
Self-explanatory. :dd
{Fix ave/histo inputs are not all global, peratom, or local} :dt
All inputs in a single fix ave/histo command must be of the
same style. :dd
{Fix ave/histo/weight value and weight vector lengths do not match} :dt
Self-explanatory. :dd
{Fix ave/spatial compute does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/spatial compute does not calculate a per-atom vector} :dt
A compute used by fix ave/spatial must generate per-atom values. :dd
{Fix ave/spatial compute does not calculate per-atom values} :dt
A compute used by fix ave/spatial must generate per-atom values. :dd
{Fix ave/spatial compute vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/spatial fix does not calculate a per-atom array} :dt
Self-explanatory. :dd
{Fix ave/spatial fix does not calculate a per-atom vector} :dt
A fix used by fix ave/spatial must generate per-atom values. :dd
{Fix ave/spatial fix does not calculate per-atom values} :dt
A fix used by fix ave/spatial must generate per-atom values. :dd
{Fix ave/spatial fix vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/spatial for triclinic boxes requires units reduced} :dt
Self-explanatory. :dd
{Fix ave/spatial settings invalid with changing box size} :dt
If the box size changes, only the units reduced option can be
used. :dd
{Fix ave/spatial variable is not atom-style variable} :dt
A variable used by fix ave/spatial must generate per-atom values. :dd
{Fix ave/time cannot set output array intensive/extensive from these inputs} :dt
One of more of the vector inputs has individual elements which are
flagged as intensive or extensive. Such an input cannot be flagged as
all intensive/extensive when turned into an array by fix ave/time. :dd
{Fix ave/time cannot use variable with vector mode} :dt
Variables produce scalar values. :dd
{Fix ave/time columns are inconsistent lengths} :dt
Self-explanatory. :dd
{Fix ave/time compute array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Fix ave/time compute does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix ave/time compute does not calculate a vector} :dt
Self-explanatory. :dd
{Fix ave/time compute does not calculate an array} :dt
Self-explanatory. :dd
{Fix ave/time compute vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/time fix array cannot be variable length} :dt
Self-explanatory. :dd
{Fix ave/time fix array is accessed out-of-range} :dt
An index for the array is out of bounds. :dd
{Fix ave/time fix does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix ave/time fix does not calculate a vector} :dt
Self-explanatory. :dd
{Fix ave/time fix does not calculate an array} :dt
Self-explanatory. :dd
{Fix ave/time fix vector cannot be variable length} :dt
Self-explanatory. :dd
{Fix ave/time fix vector is accessed out-of-range} :dt
The index for the vector is out of bounds. :dd
{Fix ave/time variable is not equal-style variable} :dt
Self-explanatory. :dd
{Fix balance rcb cannot be used with comm_style brick} :dt
Comm_style tiled must be used instead. :dd
{Fix balance shift string is invalid} :dt
The string can only contain the characters "x", "y", or "z". :dd
{Fix bond/break needs ghost atoms from further away} :dt
This is because the fix needs to walk bonds to a certain distance to
acquire needed info, The comm_modify cutoff command can be used to
extend the communication range. :dd
{Fix bond/create angle type is invalid} :dt
Self-explanatory. :dd
{Fix bond/create cutoff is longer than pairwise cutoff} :dt
This is not allowed because bond creation is done using the
pairwise neighbor list. :dd
{Fix bond/create dihedral type is invalid} :dt
Self-explanatory. :dd
{Fix bond/create improper type is invalid} :dt
Self-explanatory. :dd
{Fix bond/create induced too many angles/dihedrals/impropers per atom} :dt
See the read_data command for info on using the "extra/angle/per/atom",
(or dihedral, improper) keywords to allow for additional
angles, dihedrals, and impropers to be formed. :dd
{Fix bond/create needs ghost atoms from further away} :dt
This is because the fix needs to walk bonds to a certain distance to
acquire needed info, The comm_modify cutoff command can be used to
extend the communication range. :dd
{Fix bond/swap cannot use dihedral or improper styles} :dt
These styles cannot be defined when using this fix. :dd
{Fix bond/swap requires pair and bond styles} :dt
Self-explanatory. :dd
{Fix bond/swap requires special_bonds = 0,1,1} :dt
Self-explanatory. :dd
{Fix box/relax generated negative box length} :dt
The pressure being applied is likely too large. Try applying
it incrementally, to build to the high pressure. :dd
{Fix command before simulation box is defined} :dt
The fix command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Fix deform cannot use yz variable with xy} :dt
The yz setting cannot be a variable if xy deformation is also
specified. This is because LAMMPS cannot determine if the yz setting
will induce a box flip which would be invalid if xy is also changing. :dd
{Fix deform is changing yz too much with xy} :dt
When both yz and xy are changing, it induces changes in xz if the
box must flip from one tilt extreme to another. Thus it is not
allowed for yz to grow so much that a flip is induced. :dd
{Fix deform tilt factors require triclinic box} :dt
Cannot deform the tilt factors of a simulation box unless it
is a triclinic (non-orthogonal) box. :dd
{Fix deform volume setting is invalid} :dt
Cannot use volume style unless other dimensions are being controlled. :dd
{Fix deposit and fix rigid/small not using same molecule template ID} :dt
Self-explanatory. :dd
{Fix deposit and fix shake not using same molecule template ID} :dt
Self-explanatory. :dd
{Fix deposit molecule must have atom types} :dt
The defined molecule does not specify atom types. :dd
{Fix deposit molecule must have coordinates} :dt
The defined molecule does not specify coordinates. :dd
{Fix deposit molecule template ID must be same as atom_style template ID} :dt
When using atom_style template, you cannot deposit molecules that are
not in that template. :dd
{Fix deposit region cannot be dynamic} :dt
Only static regions can be used with fix deposit. :dd
{Fix deposit region does not support a bounding box} :dt
Not all regions represent bounded volumes. You cannot use
such a region with the fix deposit command. :dd
{Fix deposit shake fix does not exist} :dt
Self-explanatory. :dd
{Fix efield requires atom attribute q or mu} :dt
The atom style defined does not have this attribute. :dd
{Fix efield with dipoles cannot use atom-style variables} :dt
This option is not supported. :dd
{Fix evaporate molecule requires atom attribute molecule} :dt
The atom style being used does not define a molecule ID. :dd
{Fix external callback function not set} :dt
This must be done by an external program in order to use this fix. :dd
{Fix for fix ave/atom not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/atom is
requesting a value on a non-allowed timestep. :dd
{Fix for fix ave/chunk not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/chunk is
requesting a value on a non-allowed timestep. :dd
{Fix for fix ave/correlate not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/correlate
is requesting a value on a non-allowed timestep. :dd
{Fix for fix ave/histo not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/histo is
requesting a value on a non-allowed timestep. :dd
{Fix for fix ave/spatial not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/spatial is
requesting a value on a non-allowed timestep. :dd
{Fix for fix ave/time not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix ave/time
is requesting a value on a non-allowed timestep. :dd
{Fix for fix store/state not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix store/state
is requesting a value on a non-allowed timestep. :dd
{Fix for fix vector not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Fix vector is
requesting a value on a non-allowed timestep. :dd
{Fix freeze requires atom attribute torque} :dt
The atom style defined does not have this attribute. :dd
{Fix gcmc and fix shake not using same molecule template ID} :dt
Self-explanatory. :dd
{Fix gcmc atom has charge, but atom style does not} :dt
Self-explanatory. :dd
{Fix gcmc cannot exchange individual atoms belonging to a molecule} :dt
This is an error since you should not delete only one atom of a
molecule. The user has specified atomic (non-molecular) gas
exchanges, but an atom belonging to a molecule could be deleted. :dd
{Fix gcmc does not (yet) work with atom_style template} :dt
Self-explanatory. :dd
{Fix gcmc molecule command requires that atoms have molecule attributes} :dt
Should not choose the gcmc molecule feature if no molecules are being
simulated. The general molecule flag is off, but gcmc's molecule flag
is on. :dd
{Fix gcmc molecule has charges, but atom style does not} :dt
Self-explanatory. :dd
{Fix gcmc molecule must have atom types} :dt
The defined molecule does not specify atom types. :dd
{Fix gcmc molecule must have coordinates} :dt
The defined molecule does not specify coordinates. :dd
{Fix gcmc molecule template ID must be same as atom_style template ID} :dt
When using atom_style template, you cannot insert molecules that are
not in that template. :dd
{Fix gcmc put atom outside box} :dt
This should not normally happen. Contact the developers. :dd
{Fix gcmc ran out of available atom IDs} :dt
See the setting for tagint in the src/lmptype.h file. :dd
{Fix gcmc ran out of available molecule IDs} :dt
See the setting for tagint in the src/lmptype.h file. :dd
{Fix gcmc region cannot be dynamic} :dt
Only static regions can be used with fix gcmc. :dd
{Fix gcmc region does not support a bounding box} :dt
Not all regions represent bounded volumes. You cannot use
such a region with the fix gcmc command. :dd
{Fix gcmc region extends outside simulation box} :dt
Self-explanatory. :dd
{Fix gcmc shake fix does not exist} :dt
Self-explanatory. :dd
{Fix gld c coefficients must be >= 0} :dt
Self-explanatory. :dd
{Fix gld needs more prony series coefficients} :dt
Self-explanatory. :dd
{Fix gld prony terms must be > 0} :dt
Self-explanatory. :dd
{Fix gld series type must be pprony for now} :dt
Self-explanatory. :dd
{Fix gld start temperature must be >= 0} :dt
Self-explanatory. :dd
{Fix gld stop temperature must be >= 0} :dt
Self-explanatory. :dd
{Fix gld tau coefficients must be > 0} :dt
Self-explanatory. :dd
{Fix heat group has no atoms} :dt
Self-explanatory. :dd
{Fix heat kinetic energy of an atom went negative} :dt
This will cause the velocity rescaling about to be performed by fix
heat to be invalid. :dd
{Fix heat kinetic energy went negative} :dt
This will cause the velocity rescaling about to be performed by fix
heat to be invalid. :dd
{Fix in variable not computed at compatible time} :dt
Fixes generate their values on specific timesteps. The variable is
requesting the values on a non-allowed timestep. :dd
{Fix langevin angmom is not yet implemented with kokkos} :dt
This option is not yet available. :dd
{Fix langevin angmom requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Fix langevin angmom requires extended particles} :dt
This fix option cannot be used with point particles. :dd
{Fix langevin omega is not yet implemented with kokkos} :dt
This option is not yet available. :dd
{Fix langevin omega requires atom style sphere} :dt
Self-explanatory. :dd
{Fix langevin omega requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Fix langevin period must be > 0.0} :dt
The time window for temperature relaxation must be > 0 :dd
{Fix langevin variable returned negative temperature} :dt
Self-explanatory. :dd
{Fix momentum group has no atoms} :dt
Self-explanatory. :dd
{Fix move cannot define z or vz variable for 2d problem} :dt
Self-explanatory. :dd
{Fix move cannot rotate aroung non z-axis for 2d problem} :dt
Self-explanatory. :dd
{Fix move cannot set linear z motion for 2d problem} :dt
Self-explanatory. :dd
{Fix move cannot set wiggle z motion for 2d problem} :dt
Self-explanatory. :dd
{Fix msst compute ID does not compute potential energy} :dt
Self-explanatory. :dd
{Fix msst compute ID does not compute pressure} :dt
Self-explanatory. :dd
{Fix msst compute ID does not compute temperature} :dt
Self-explanatory. :dd
{Fix msst requires a periodic box} :dt
Self-explanatory. :dd
{Fix msst tscale must satisfy 0 <= tscale < 1} :dt
Self-explanatory. :dd
{Fix npt/nph has tilted box too far in one step - periodic cell is too far from equilibrium state} :dt
Self-explanatory. The change in the box tilt is too extreme
on a short timescale. :dd
{Fix nve/asphere requires extended particles} :dt
This fix can only be used for particles with a shape setting. :dd
{Fix nve/asphere/noforce requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Fix nve/asphere/noforce requires extended particles} :dt
One of the particles is not an ellipsoid. :dd
{Fix nve/body requires atom style body} :dt
Self-explanatory. :dd
{Fix nve/body requires bodies} :dt
This fix can only be used for particles that are bodies. :dd
{Fix nve/line can only be used for 2d simulations} :dt
Self-explanatory. :dd
{Fix nve/line requires atom style line} :dt
Self-explanatory. :dd
{Fix nve/line requires line particles} :dt
Self-explanatory. :dd
{Fix nve/sphere dipole requires atom attribute mu} :dt
An atom style with this attribute is needed. :dd
{Fix nve/sphere requires atom style sphere} :dt
Self-explanatory. :dd
{Fix nve/sphere requires extended particles} :dt
This fix can only be used for particles of a finite size. :dd
{Fix nve/tri can only be used for 3d simulations} :dt
Self-explanatory. :dd
{Fix nve/tri requires atom style tri} :dt
Self-explanatory. :dd
{Fix nve/tri requires tri particles} :dt
Self-explanatory. :dd
{Fix nvt/nph/npt asphere requires extended particles} :dt
The shape setting for a particle in the fix group has shape = 0.0,
which means it is a point particle. :dd
{Fix nvt/nph/npt body requires bodies} :dt
Self-explanatory. :dd
{Fix nvt/nph/npt sphere requires atom style sphere} :dt
Self-explanatory. :dd
{Fix nvt/npt/nph damping parameters must be > 0.0} :dt
Self-explanatory. :dd
{Fix nvt/npt/nph dilate group ID does not exist} :dt
Self-explanatory. :dd
{Fix nvt/sphere requires extended particles} :dt
This fix can only be used for particles of a finite size. :dd
{Fix orient/fcc file open failed} :dt
The fix orient/fcc command could not open a specified file. :dd
{Fix orient/fcc file read failed} :dt
The fix orient/fcc command could not read the needed parameters from a
specified file. :dd
{Fix orient/fcc found self twice} :dt
The neighbor lists used by fix orient/fcc are messed up. If this
error occurs, it is likely a bug, so send an email to the
"developers"_http://lammps.sandia.gov/authors.html. :dd
{Fix peri neigh does not exist} :dt
Somehow a fix that the pair style defines has been deleted. :dd
{Fix pour and fix rigid/small not using same molecule template ID} :dt
Self-explanatory. :dd
{Fix pour and fix shake not using same molecule template ID} :dt
Self-explanatory. :dd
{Fix pour insertion count per timestep is 0} :dt
Self-explanatory. :dd
{Fix pour molecule must have atom types} :dt
The defined molecule does not specify atom types. :dd
{Fix pour molecule must have coordinates} :dt
The defined molecule does not specify coordinates. :dd
{Fix pour molecule template ID must be same as atom style template ID} :dt
When using atom_style template, you cannot pour molecules that are
not in that template. :dd
{Fix pour polydisperse fractions do not sum to 1.0} :dt
Self-explanatory. :dd
{Fix pour region ID does not exist} :dt
Self-explanatory. :dd
{Fix pour region cannot be dynamic} :dt
Only static regions can be used with fix pour. :dd
{Fix pour region does not support a bounding box} :dt
Not all regions represent bounded volumes. You cannot use
such a region with the fix pour command. :dd
{Fix pour requires atom attributes radius, rmass} :dt
The atom style defined does not have these attributes. :dd
{Fix pour rigid fix does not exist} :dt
Self-explanatory. :dd
{Fix pour shake fix does not exist} :dt
Self-explanatory. :dd
{Fix press/berendsen damping parameters must be > 0.0} :dt
Self-explanatory. :dd
{Fix property/atom cannot specify mol twice} :dt
Self-explanatory. :dd
{Fix property/atom cannot specify q twice} :dt
Self-explanatory. :dd
{Fix property/atom mol when atom_style already has molecule attribute} :dt
Self-explanatory. :dd
{Fix property/atom q when atom_style already has charge attribute} :dt
Self-explanatory. :dd
{Fix property/atom vector name already exists} :dt
The name for an integer or floating-point vector must be unique. :dd
{Fix qeq has negative upper Taper radius cutoff} :dt
Self-explanatory. :dd
{Fix qeq/comb group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/comb requires atom attribute q} :dt
An atom style with charge must be used to perform charge equilibration. :dd
{Fix qeq/dynamic group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/dynamic requires atom attribute q} :dt
Self-explanatory. :dd
{Fix qeq/fire group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/fire requires atom attribute q} :dt
Self-explanatory. :dd
{Fix qeq/point group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/point has insufficient QEq matrix size} :dt
Occurs when number of neighbor atoms for an atom increased too much
during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and
recompile. :dd
{Fix qeq/point requires atom attribute q} :dt
Self-explanatory. :dd
{Fix qeq/shielded group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/shielded has insufficient QEq matrix size} :dt
Occurs when number of neighbor atoms for an atom increased too much
during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and
recompile. :dd
{Fix qeq/shielded requires atom attribute q} :dt
Self-explanatory. :dd
{Fix qeq/slater could not extract params from pair coul/streitz} :dt
This should not happen unless pair coul/streitz has been altered. :dd
{Fix qeq/slater group has no atoms} :dt
Self-explanatory. :dd
{Fix qeq/slater has insufficient QEq matrix size} :dt
Occurs when number of neighbor atoms for an atom increased too much
during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and
recompile. :dd
{Fix qeq/slater requires atom attribute q} :dt
Self-explanatory. :dd
{Fix reax/bonds numbonds > nsbmax_most} :dt
The limit of the number of bonds expected by the ReaxFF force field
was exceeded. :dd
{Fix recenter group has no atoms} :dt
Self-explanatory. :dd
{Fix restrain requires an atom map, see atom_modify} :dt
Self-explanatory. :dd
{Fix rigid atom has non-zero image flag in a non-periodic dimension} :dt
Image flags for non-periodic dimensions should not be set. :dd
{Fix rigid file has no lines} :dt
Self-explanatory. :dd
{Fix rigid langevin period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid molecule requires atom attribute molecule} :dt
Self-explanatory. :dd
{Fix rigid npt/nph dilate group ID does not exist} :dt
Self-explanatory. :dd
{Fix rigid npt/nph does not yet allow triclinic box} :dt
This is a current restriction in LAMMPS. :dd
{Fix rigid npt/nph period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid npt/small t_chain should not be less than 1} :dt
Self-explanatory. :dd
{Fix rigid npt/small t_order must be 3 or 5} :dt
Self-explanatory. :dd
{Fix rigid nvt/npt/nph damping parameters must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid nvt/small t_chain should not be less than 1} :dt
Self-explanatory. :dd
{Fix rigid nvt/small t_iter should not be less than 1} :dt
Self-explanatory. :dd
{Fix rigid nvt/small t_order must be 3 or 5} :dt
Self-explanatory. :dd
{Fix rigid xy torque cannot be on for 2d simulation} :dt
Self-explanatory. :dd
{Fix rigid z force cannot be on for 2d simulation} :dt
Self-explanatory. :dd
{Fix rigid/npt period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/npt temperature order must be 3 or 5} :dt
Self-explanatory. :dd
{Fix rigid/npt/small period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/nvt period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/nvt temperature order must be 3 or 5} :dt
Self-explanatory. :dd
{Fix rigid/nvt/small period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/small atom has non-zero image flag in a non-periodic dimension} :dt
Image flags for non-periodic dimensions should not be set. :dd
{Fix rigid/small langevin period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/small molecule must have atom types} :dt
The defined molecule does not specify atom types. :dd
{Fix rigid/small molecule must have coordinates} :dt
The defined molecule does not specify coordinates. :dd
{Fix rigid/small npt/nph period must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/small nvt/npt/nph damping parameters must be > 0.0} :dt
Self-explanatory. :dd
{Fix rigid/small nvt/npt/nph dilate group ID does not exist} :dt
Self-explanatory. :dd
{Fix rigid/small requires an atom map, see atom_modify} :dt
Self-explanatory. :dd
{Fix rigid/small requires atom attribute molecule} :dt
Self-explanatory. :dd
{Fix rigid: Bad principal moments} :dt
The principal moments of inertia computed for a rigid body
are not within the required tolerances. :dd
{Fix shake cannot be used with minimization} :dt
Cannot use fix shake while doing an energy minimization since
it turns off bonds that should contribute to the energy. :dd
{Fix shake molecule template must have shake info} :dt
The defined molecule does not specify SHAKE information. :dd
{Fix spring couple group ID does not exist} :dt
Self-explanatory. :dd
{Fix srd can only currently be used with comm_style brick} :dt
This is a current restriction in LAMMPS. :dd
{Fix srd lamda must be >= 0.6 of SRD grid size} :dt
This is a requirement for accuracy reasons. :dd
{Fix srd no-slip requires atom attribute torque} :dt
This is because the SRD collisions will impart torque to the solute
particles. :dd
{Fix srd requires SRD particles all have same mass} :dt
Self-explanatory. :dd
{Fix srd requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Fix srd requires newton pair on} :dt
Self-explanatory. :dd
{Fix store/state compute array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix store/state compute does not calculate a per-atom array} :dt
The compute calculates a per-atom vector. :dd
{Fix store/state compute does not calculate a per-atom vector} :dt
The compute calculates a per-atom vector. :dd
{Fix store/state compute does not calculate per-atom values} :dt
Computes that calculate global or local quantities cannot be used
with fix store/state. :dd
{Fix store/state fix array is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix store/state fix does not calculate a per-atom array} :dt
The fix calculates a per-atom vector. :dd
{Fix store/state fix does not calculate a per-atom vector} :dt
The fix calculates a per-atom array. :dd
{Fix store/state fix does not calculate per-atom values} :dt
Fixes that calculate global or local quantities cannot be used with
fix store/state. :dd
{Fix store/state for atom property that isn't allocated} :dt
Self-explanatory. :dd
{Fix store/state variable is not atom-style variable} :dt
Only atom-style variables calculate per-atom quantities. :dd
{Fix temp/berendsen period must be > 0.0} :dt
Self-explanatory. :dd
{Fix temp/berendsen variable returned negative temperature} :dt
Self-explanatory. :dd
{Fix temp/csld is not compatible with fix rattle or fix shake} :dt
These two commands cannot currently be used together with fix temp/csld. :dd
{Fix temp/csld variable returned negative temperature} :dt
Self-explanatory. :dd
{Fix temp/csvr variable returned negative temperature} :dt
Self-explanatory. :dd
{Fix temp/rescale variable returned negative temperature} :dt
Self-explanatory. :dd
{Fix tfmc displacement length must be > 0} :dt
Self-explanatory. :dd
{Fix tfmc is not compatible with fix shake} :dt
These two commands cannot currently be used together. :dd
{Fix tfmc temperature must be > 0} :dt
Self-explanatory. :dd
{Fix thermal/conductivity swap value must be positive} :dt
Self-explanatory. :dd
{Fix tmd must come after integration fixes} :dt
Any fix tmd command must appear in the input script after all time
integration fixes (nve, nvt, npt). See the fix tmd documentation for
details. :dd
{Fix ttm electron temperatures must be > 0.0} :dt
Self-explanatory. :dd
{Fix ttm electronic_density must be > 0.0} :dt
Self-explanatory. :dd
{Fix ttm electronic_specific_heat must be > 0.0} :dt
Self-explanatory. :dd
{Fix ttm electronic_thermal_conductivity must be >= 0.0} :dt
Self-explanatory. :dd
{Fix ttm gamma_p must be > 0.0} :dt
Self-explanatory. :dd
{Fix ttm gamma_s must be >= 0.0} :dt
Self-explanatory. :dd
{Fix ttm number of nodes must be > 0} :dt
Self-explanatory. :dd
{Fix ttm v_0 must be >= 0.0} :dt
Self-explanatory. :dd
{Fix used in compute chunk/atom not computed at compatible time} :dt
The chunk/atom compute cannot query the output of the fix on a timestep
it is needed. :dd
{Fix used in compute reduce not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Compute reduce is
requesting a value on a non-allowed timestep. :dd
{Fix used in compute slice not computed at compatible time} :dt
Fixes generate their values on specific timesteps. Compute slice is
requesting a value on a non-allowed timestep. :dd
{Fix vector cannot set output array intensive/extensive from these inputs} :dt
The inputs to the command have conflicting intensive/extensive attributes.
You need to use more than one fix vector command. :dd
{Fix vector compute does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix vector compute does not calculate a vector} :dt
Self-explanatory. :dd
{Fix vector compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix vector fix does not calculate a scalar} :dt
Self-explanatory. :dd
{Fix vector fix does not calculate a vector} :dt
Self-explanatory. :dd
{Fix vector fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Fix vector variable is not equal-style variable} :dt
Self-explanatory. :dd
{Fix viscosity swap value must be positive} :dt
Self-explanatory. :dd
{Fix viscosity vtarget value must be positive} :dt
Self-explanatory. :dd
{Fix wall cutoff <= 0.0} :dt
Self-explanatory. :dd
{Fix wall/colloid requires atom style sphere} :dt
Self-explanatory. :dd
{Fix wall/colloid requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Fix wall/gran is incompatible with Pair style} :dt
Must use a granular pair style to define the parameters needed for
this fix. :dd
{Fix wall/gran requires atom style sphere} :dt
Self-explanatory. :dd
{Fix wall/piston command only available at zlo} :dt
The face keyword must be zlo. :dd
{Fix wall/region colloid requires atom style sphere} :dt
Self-explanatory. :dd
{Fix wall/region colloid requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Fix wall/region cutoff <= 0.0} :dt
Self-explanatory. :dd
{Fix_modify pressure ID does not compute pressure} :dt
The compute ID assigned to the fix must compute pressure. :dd
{Fix_modify temperature ID does not compute temperature} :dt
The compute ID assigned to the fix must compute temperature. :dd
{For triclinic deformation, specified target stress must be hydrostatic} :dt
Triclinic pressure control is allowed using the tri keyword, but
non-hydrostatic pressure control can not be used in this case. :dd
{Found no restart file matching pattern} :dt
When using a "*" in the restart file name, no matching file was found. :dd
{GPU library not compiled for this accelerator} :dt
Self-explanatory. :dd
{GPU package does not (yet) work with atom_style template} :dt
Self-explanatory. :dd
{GPU particle split must be set to 1 for this pair style.} :dt
For this pair style, you cannot run part of the force calculation on
the host. See the package command. :dd
{GPU split param must be positive for hybrid pair styles} :dt
See the package gpu command. :dd
{GPUs are requested but Kokkos has not been compiled for CUDA} :dt
Recompile Kokkos with CUDA support to use GPUs. :dd
{Ghost velocity forward comm not yet implemented with Kokkos} :dt
This is a current restriction. :dd
{Gmask function in equal-style variable formula} :dt
Gmask is per-atom operation. :dd
{Gravity changed since fix pour was created} :dt
The gravity vector defined by fix gravity must be static. :dd
{Gravity must point in -y to use with fix pour in 2d} :dt
Self-explanatory. :dd
{Gravity must point in -z to use with fix pour in 3d} :dt
Self-explanatory. :dd
{Grmask function in equal-style variable formula} :dt
Grmask is per-atom operation. :dd
{Group ID does not exist} :dt
A group ID used in the group command does not exist. :dd
{Group ID in variable formula does not exist} :dt
Self-explanatory. :dd
{Group all cannot be made dynamic} :dt
This operation is not allowed. :dd
{Group command before simulation box is defined} :dt
The group command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Group dynamic cannot reference itself} :dt
Self-explanatory. :dd
{Group dynamic parent group cannot be dynamic} :dt
Self-explanatory. :dd
{Group dynamic parent group does not exist} :dt
Self-explanatory. :dd
{Group region ID does not exist} :dt
A region ID used in the group command does not exist. :dd
{If read_dump purges it cannot replace or trim} :dt
These operations are not compatible. See the read_dump doc
page for details. :dd
{Illegal ... command} :dt
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line. :dd
{Illegal COMB parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal COMB3 parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal Stillinger-Weber parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal Tersoff parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal Vashishta parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal compute voronoi/atom command (occupation and (surface or edges))} :dt
Self-explanatory. :dd
{Illegal coul/streitz parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal dump_modify sfactor value (must be > 0.0)} :dt
Self-explanatory. :dd
{Illegal dump_modify tfactor value (must be > 0.0)} :dt
Self-explanatory. :dd
{Illegal fix gcmc gas mass <= 0} :dt
The computed mass of the designated gas molecule or atom type was less
than or equal to zero. :dd
{Illegal fix tfmc random seed} :dt
Seeds can only be nonzero positive integers. :dd
{Illegal fix wall/piston velocity} :dt
The piston velocity must be positive. :dd
{Illegal integrate style} :dt
Self-explanatory. :dd
{Illegal nb3b/harmonic parameter} :dt
One or more of the coefficients defined in the potential file is
invalid. :dd
{Illegal number of angle table entries} :dt
There must be at least 2 table entries. :dd
{Illegal number of bond table entries} :dt
There must be at least 2 table entries. :dd
{Illegal number of pair table entries} :dt
There must be at least 2 table entries. :dd
{Illegal or unset periodicity in restart} :dt
This error should not normally occur unless the restart file is invalid. :dd
{Illegal range increment value} :dt
The increment must be >= 1. :dd
{Illegal simulation box} :dt
The lower bound of the simulation box is greater than the upper bound. :dd
{Illegal size double vector read requested} :dt
This error should not normally occur unless the restart file is invalid. :dd
{Illegal size integer vector read requested} :dt
This error should not normally occur unless the restart file is invalid. :dd
{Illegal size string or corrupt restart} :dt
This error should not normally occur unless the restart file is invalid. :dd
{Imageint setting in lmptype.h is invalid} :dt
Imageint must be as large or larger than smallint. :dd
{Imageint setting in lmptype.h is not compatible} :dt
Format of imageint stored in restart file is not consistent with
LAMMPS version you are running. See the settings in src/lmptype.h :dd
{Improper atom missing in delete_bonds} :dt
The delete_bonds command cannot find one or more atoms in a particular
improper on a particular processor. The pairwise cutoff is too short
or the atoms are too far apart to make a valid improper. :dd
{Improper atom missing in set command} :dt
The set command cannot find one or more atoms in a particular improper
on a particular processor. The pairwise cutoff is too short or the
atoms are too far apart to make a valid improper. :dd
{Improper atoms %d %d %d %d missing on proc %d at step %ld} :dt
One or more of 4 atoms needed to compute a particular improper are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the improper has blown apart and an atom is
too far away. :dd
{Improper atoms missing on proc %d at step %ld} :dt
One or more of 4 atoms needed to compute a particular improper are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the improper has blown apart and an atom is
too far away. :dd
{Improper coeff for hybrid has invalid style} :dt
Improper style hybrid uses another improper style as one of its
coefficients. The improper style used in the improper_coeff command
or read from a restart file is not recognized. :dd
{Improper coeffs are not set} :dt
No improper coefficients have been assigned in the data file or via
the improper_coeff command. :dd
{Improper style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Improper style hybrid cannot have none as an argument} :dt
Self-explanatory. :dd
{Improper style hybrid cannot use same improper style twice} :dt
Self-explanatory. :dd
{Improper_coeff command before improper_style is defined} :dt
Coefficients cannot be set in the data file or via the improper_coeff
command until an improper_style has been assigned. :dd
{Improper_coeff command before simulation box is defined} :dt
The improper_coeff command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Improper_coeff command when no impropers allowed} :dt
The chosen atom style does not allow for impropers to be defined. :dd
{Improper_style command when no impropers allowed} :dt
The chosen atom style does not allow for impropers to be defined. :dd
{Impropers assigned incorrectly} :dt
Impropers read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions. :dd
{Impropers defined but no improper types} :dt
The data file header lists improper but no improper types. :dd
{Incomplete use of variables in create_atoms command} :dt
The var and set options must be used together. :dd
{Inconsistent iparam/jparam values in fix bond/create command} :dt
If itype and jtype are the same, then their maxbond and newtype
settings must also be the same. :dd
{Inconsistent line segment in data file} :dt
The end points of the line segment are not equal distances from the
center point which is the atom coordinate. :dd
{Inconsistent triangle in data file} :dt
The centroid of the triangle as defined by the corner points is not
the atom coordinate. :dd
{Inconsistent use of finite-size particles by molecule template molecules} :dt
Not all of the molecules define a radius for their constituent
particles. :dd
{Incorrect # of floating-point values in Bodies section of data file} :dt
See doc page for body style. :dd
{Incorrect # of integer values in Bodies section of data file} :dt
See doc page for body style. :dd
{Incorrect %s format in data file} :dt
A section of the data file being read by fix property/atom does
not have the correct number of values per line. :dd
{Incorrect SNAP parameter file} :dt
The file cannot be parsed correctly, check its internal syntax. :dd
{Incorrect args for angle coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect args for bond coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect args for dihedral coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect args for improper coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect args for pair coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect args in pair_style command} :dt
Self-explanatory. :dd
{Incorrect atom format in data file} :dt
Number of values per atom line in the data file is not consistent with
the atom style. :dd
{Incorrect atom format in neb file} :dt
The number of fields per line is not what expected. :dd
{Incorrect bonus data format in data file} :dt
See the read_data doc page for a description of how various kinds of
bonus data must be formatted for certain atom styles. :dd
{Incorrect boundaries with slab Ewald} :dt
Must have periodic x,y dimensions and non-periodic z dimension to use
2d slab option with Ewald. :dd
{Incorrect boundaries with slab EwaldDisp} :dt
Must have periodic x,y dimensions and non-periodic z dimension to use
2d slab option with Ewald. :dd
{Incorrect boundaries with slab PPPM} :dt
Must have periodic x,y dimensions and non-periodic z dimension to use
2d slab option with PPPM. :dd
{Incorrect boundaries with slab PPPMDisp} :dt
Must have periodic x,y dimensions and non-periodic z dimension to use
2d slab option with pppm/disp. :dd
{Incorrect element names in ADP potential file} :dt
The element names in the ADP file do not match those requested. :dd
{Incorrect element names in EAM potential file} :dt
The element names in the EAM file do not match those requested. :dd
{Incorrect format in COMB potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in COMB3 potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in MEAM potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in SNAP coefficient file} :dt
Incorrect number of words per line in the coefficient file. :dd
{Incorrect format in SNAP parameter file} :dt
Incorrect number of words per line in the parameter file. :dd
{Incorrect format in Stillinger-Weber potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in TMD target file} :dt
Format of file read by fix tmd command is incorrect. :dd
{Incorrect format in Tersoff potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in Vashishta potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in coul/streitz potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect format in nb3b/harmonic potential file} :dt
Incorrect number of words per line in the potential file. :dd
{Incorrect integer value in Bodies section of data file} :dt
See doc page for body style. :dd
{Incorrect multiplicity arg for dihedral coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect number of elements in potential file} :dt
Self-explanatory. :dd
{Incorrect rigid body format in fix rigid file} :dt
The number of fields per line is not what expected. :dd
{Incorrect rigid body format in fix rigid/small file} :dt
The number of fields per line is not what expected. :dd
{Incorrect sign arg for dihedral coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Incorrect table format check for element types} :dt
Self-explanatory. :dd
{Incorrect velocity format in data file} :dt
Each atom style defines a format for the Velocity section
of the data file. The read-in lines do not match. :dd
{Incorrect weight arg for dihedral coefficients} :dt
Self-explanatory. Check the input script or data file. :dd
{Index between variable brackets must be positive} :dt
Self-explanatory. :dd
{Indexed per-atom vector in variable formula without atom map} :dt
Accessing a value from an atom vector requires the ability to lookup
an atom index, which is provided by an atom map. An atom map does not
exist (by default) for non-molecular problems. Using the atom_modify
map command will force an atom map to be created. :dd
{Initial temperatures not all set in fix ttm} :dt
Self-explanatory. :dd
{Input line quote not followed by whitespace} :dt
An end quote must be followed by whitespace. :dd
{Insertion region extends outside simulation box} :dt
Self-explanatory. :dd
{Insufficient Jacobi rotations for POEMS body} :dt
Eigensolve for rigid body was not sufficiently accurate. :dd
{Insufficient Jacobi rotations for body nparticle} :dt
Eigensolve for rigid body was not sufficiently accurate. :dd
{Insufficient Jacobi rotations for rigid body} :dt
Eigensolve for rigid body was not sufficiently accurate. :dd
{Insufficient Jacobi rotations for rigid molecule} :dt
Eigensolve for rigid body was not sufficiently accurate. :dd
{Insufficient Jacobi rotations for triangle} :dt
The calculation of the inertia tensor of the triangle failed. This
should not happen if it is a reasonably shaped triangle. :dd
{Insufficient memory on accelerator} :dt
There is insufficient memory on one of the devices specified for the gpu
package :dd
{Internal error in atom_style body} :dt
This error should not occur. Contact the developers. :dd
{Invalid -reorder N value} :dt
Self-explanatory. :dd
{Invalid Angles section in molecule file} :dt
Self-explanatory. :dd
{Invalid Bonds section in molecule file} :dt
Self-explanatory. :dd
{Invalid Boolean syntax in if command} :dt
Self-explanatory. :dd
{Invalid Charges section in molecule file} :dt
Self-explanatory. :dd
{Invalid Coords section in molecule file} :dt
Self-explanatory. :dd
{Invalid Diameters section in molecule file} :dt
Self-explanatory. :dd
{Invalid Dihedrals section in molecule file} :dt
Self-explanatory. :dd
{Invalid Impropers section in molecule file} :dt
Self-explanatory. :dd
{Invalid Kokkos command-line args} :dt
Self-explanatory. See Section 2.7 of the manual for details. :dd
{Invalid LAMMPS restart file} :dt
The file does not appear to be a LAMMPS restart file since
it doesn't contain the correct magic string at the beginning. :dd
{Invalid Masses section in molecule file} :dt
Self-explanatory. :dd
{Invalid REAX atom type} :dt
There is a mis-match between LAMMPS atom types and the elements
listed in the ReaxFF force field file. :dd
{Invalid Special Bond Counts section in molecule file} :dt
Self-explanatory. :dd
{Invalid Types section in molecule file} :dt
Self-explanatory. :dd
{Invalid angle count in molecule file} :dt
Self-explanatory. :dd
{Invalid angle table length} :dt
Length must be 2 or greater. :dd
{Invalid angle type in Angles section of data file} :dt
Angle type must be positive integer and within range of specified angle
types. :dd
{Invalid angle type in Angles section of molecule file} :dt
Self-explanatory. :dd
{Invalid angle type index for fix shake} :dt
Self-explanatory. :dd
{Invalid args for non-hybrid pair coefficients} :dt
"NULL" is only supported in pair_coeff calls when using pair hybrid :dd
{Invalid argument to factorial %d} :dt
N must be >= 0 and <= 167, otherwise the factorial result is too
large. :dd
{Invalid atom ID in %s section of data file} :dt
An atom in a section of the data file being read by fix property/atom
has an invalid atom ID that is <= 0 or > the maximum existing atom ID. :dd
{Invalid atom ID in Angles section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Angles section of molecule file} :dt
Self-explanatory. :dd
{Invalid atom ID in Atoms section of data file} :dt
Atom IDs must be positive integers. :dd
{Invalid atom ID in Bodies section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Bonds section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Bonds section of molecule file} :dt
Self-explanatory. :dd
{Invalid atom ID in Bonus section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Dihedrals section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Impropers section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in Velocities section of data file} :dt
Atom IDs must be positive integers and within range of defined
atoms. :dd
{Invalid atom ID in dihedrals section of molecule file} :dt
Self-explanatory. :dd
{Invalid atom ID in impropers section of molecule file} :dt
Self-explanatory. :dd
{Invalid atom ID in variable file} :dt
Self-explanatory. :dd
{Invalid atom IDs in neb file} :dt
An ID in the file was not found in the system. :dd
{Invalid atom diameter in molecule file} :dt
Diameters must be >= 0.0. :dd
{Invalid atom mass for fix shake} :dt
Mass specified in fix shake command must be > 0.0. :dd
{Invalid atom mass in molecule file} :dt
Masses must be > 0.0. :dd
{Invalid atom type in Atoms section of data file} :dt
Atom types must range from 1 to specified # of types. :dd
{Invalid atom type in create_atoms command} :dt
The create_box command specified the range of valid atom types.
An invalid type is being requested. :dd
{Invalid atom type in create_atoms mol command} :dt
The atom types in the defined molecule are added to the value
specified in the create_atoms command, as an offset. The final value
for each atom must be between 1 to N, where N is the number of atom
types. :dd
{Invalid atom type in fix atom/swap command} :dt
The atom type specified in the atom/swap command does not exist. :dd
{Invalid atom type in fix bond/create command} :dt
Self-explanatory. :dd
{Invalid atom type in fix deposit command} :dt
Self-explanatory. :dd
{Invalid atom type in fix deposit mol command} :dt
The atom types in the defined molecule are added to the value
specified in the create_atoms command, as an offset. The final value
for each atom must be between 1 to N, where N is the number of atom
types. :dd
{Invalid atom type in fix gcmc command} :dt
The atom type specified in the gcmc command does not exist. :dd
{Invalid atom type in fix pour command} :dt
Self-explanatory. :dd
{Invalid atom type in fix pour mol command} :dt
The atom types in the defined molecule are added to the value
specified in the create_atoms command, as an offset. The final value
for each atom must be between 1 to N, where N is the number of atom
types. :dd
{Invalid atom type in molecule file} :dt
Atom types must range from 1 to specified # of types. :dd
{Invalid atom type in neighbor exclusion list} :dt
Atom types must range from 1 to Ntypes inclusive. :dd
{Invalid atom type index for fix shake} :dt
Atom types must range from 1 to Ntypes inclusive. :dd
{Invalid atom types in pair_write command} :dt
Atom types must range from 1 to Ntypes inclusive. :dd
{Invalid atom vector in variable formula} :dt
The atom vector is not recognized. :dd
{Invalid atom_style body command} :dt
No body style argument was provided. :dd
{Invalid atom_style command} :dt
Self-explanatory. :dd
{Invalid attribute in dump custom command} :dt
Self-explanatory. :dd
{Invalid attribute in dump local command} :dt
Self-explanatory. :dd
{Invalid attribute in dump modify command} :dt
Self-explanatory. :dd
{Invalid basis setting in create_atoms command} :dt
The basis index must be between 1 to N where N is the number of basis
atoms in the lattice. The type index must be between 1 to N where N
is the number of atom types. :dd
{Invalid basis setting in fix append/atoms command} :dt
The basis index must be between 1 to N where N is the number of basis
atoms in the lattice. The type index must be between 1 to N where N
is the number of atom types. :dd
{Invalid bin bounds in compute chunk/atom} :dt
The lo/hi values are inconsistent. :dd
{Invalid bin bounds in fix ave/spatial} :dt
The lo/hi values are inconsistent. :dd
{Invalid body nparticle command} :dt
Arguments in atom-style command are not correct. :dd
{Invalid bond count in molecule file} :dt
Self-explanatory. :dd
{Invalid bond table length} :dt
Length must be 2 or greater. :dd
{Invalid bond type in Bonds section of data file} :dt
Bond type must be positive integer and within range of specified bond
types. :dd
{Invalid bond type in Bonds section of molecule file} :dt
Self-explanatory. :dd
{Invalid bond type in create_bonds command} :dt
Self-explanatory. :dd
{Invalid bond type in fix bond/break command} :dt
Self-explanatory. :dd
{Invalid bond type in fix bond/create command} :dt
Self-explanatory. :dd
{Invalid bond type index for fix shake} :dt
Self-explanatory. Check the fix shake command in the input script. :dd
{Invalid coeffs for this dihedral style} :dt
Cannot set class 2 coeffs in data file for this dihedral style. :dd
{Invalid color in dump_modify command} :dt
The specified color name was not in the list of recognized colors.
See the dump_modify doc page. :dd
{Invalid color map min/max values} :dt
The min/max values are not consistent with either each other or
with values in the color map. :dd
{Invalid command-line argument} :dt
One or more command-line arguments is invalid. Check the syntax of
the command you are using to launch LAMMPS. :dd
{Invalid compute ID in variable formula} :dt
The compute is not recognized. :dd
{Invalid create_atoms rotation vector for 2d model} :dt
The rotation vector can only have a z component. :dd
{Invalid custom OpenCL parameter string.} :dt
There are not enough or too many parameters in the custom string for package
GPU. :dd
{Invalid cutoff in comm_modify command} :dt
Specified cutoff must be >= 0.0. :dd
{Invalid cutoffs in pair_write command} :dt
Inner cutoff must be larger than 0.0 and less than outer cutoff. :dd
{Invalid d1 or d2 value for pair colloid coeff} :dt
Neither d1 or d2 can be < 0. :dd
{Invalid data file section: Angle Coeffs} :dt
Atom style does not allow angles. :dd
{Invalid data file section: AngleAngle Coeffs} :dt
Atom style does not allow impropers. :dd
{Invalid data file section: AngleAngleTorsion Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: AngleTorsion Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Angles} :dt
Atom style does not allow angles. :dd
{Invalid data file section: Bodies} :dt
Atom style does not allow bodies. :dd
{Invalid data file section: Bond Coeffs} :dt
Atom style does not allow bonds. :dd
{Invalid data file section: BondAngle Coeffs} :dt
Atom style does not allow angles. :dd
{Invalid data file section: BondBond Coeffs} :dt
Atom style does not allow angles. :dd
{Invalid data file section: BondBond13 Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Bonds} :dt
Atom style does not allow bonds. :dd
{Invalid data file section: Dihedral Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Dihedrals} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Ellipsoids} :dt
Atom style does not allow ellipsoids. :dd
{Invalid data file section: EndBondTorsion Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Improper Coeffs} :dt
Atom style does not allow impropers. :dd
{Invalid data file section: Impropers} :dt
Atom style does not allow impropers. :dd
{Invalid data file section: Lines} :dt
Atom style does not allow lines. :dd
{Invalid data file section: MiddleBondTorsion Coeffs} :dt
Atom style does not allow dihedrals. :dd
{Invalid data file section: Triangles} :dt
Atom style does not allow triangles. :dd
{Invalid delta_conf in tad command} :dt
The value must be between 0 and 1 inclusive. :dd
{Invalid density in Atoms section of data file} :dt
Density value cannot be <= 0.0. :dd
{Invalid density in set command} :dt
Density must be > 0.0. :dd
{Invalid diameter in set command} :dt
Self-explanatory. :dd
{Invalid dihedral count in molecule file} :dt
Self-explanatory. :dd
{Invalid dihedral type in Dihedrals section of data file} :dt
Dihedral type must be positive integer and within range of specified
dihedral types. :dd
{Invalid dihedral type in dihedrals section of molecule file} :dt
Self-explanatory. :dd
{Invalid dipole length in set command} :dt
Self-explanatory. :dd
{Invalid displace_atoms rotate axis for 2d} :dt
Axis must be in z direction. :dd
{Invalid dump dcd filename} :dt
Filenames used with the dump dcd style cannot be binary or compressed
or cause multiple files to be written. :dd
{Invalid dump frequency} :dt
Dump frequency must be 1 or greater. :dd
{Invalid dump image element name} :dt
The specified element name was not in the standard list of elements.
See the dump_modify doc page. :dd
{Invalid dump image filename} :dt
The file produced by dump image cannot be binary and must
be for a single processor. :dd
{Invalid dump image persp value} :dt
Persp value must be >= 0.0. :dd
{Invalid dump image theta value} :dt
Theta must be between 0.0 and 180.0 inclusive. :dd
{Invalid dump image zoom value} :dt
Zoom value must be > 0.0. :dd
{Invalid dump movie filename} :dt
The file produced by dump movie cannot be binary or compressed
and must be a single file for a single processor. :dd
{Invalid dump xtc filename} :dt
Filenames used with the dump xtc style cannot be binary or compressed
or cause multiple files to be written. :dd
{Invalid dump xyz filename} :dt
Filenames used with the dump xyz style cannot be binary or cause files
to be written by each processor. :dd
{Invalid dump_modify threshold operator} :dt
Operator keyword used for threshold specification in not recognized. :dd
{Invalid entry in -reorder file} :dt
Self-explanatory. :dd
{Invalid fix ID in variable formula} :dt
The fix is not recognized. :dd
{Invalid fix ave/time off column} :dt
Self-explanatory. :dd
{Invalid fix box/relax command for a 2d simulation} :dt
Fix box/relax styles involving the z dimension cannot be used in
a 2d simulation. :dd
{Invalid fix box/relax command pressure settings} :dt
If multiple dimensions are coupled, those dimensions must be specified. :dd
{Invalid fix box/relax pressure settings} :dt
Settings for coupled dimensions must be the same. :dd
{Invalid fix nvt/npt/nph command for a 2d simulation} :dt
Cannot control z dimension in a 2d model. :dd
{Invalid fix nvt/npt/nph command pressure settings} :dt
If multiple dimensions are coupled, those dimensions must be
specified. :dd
{Invalid fix nvt/npt/nph pressure settings} :dt
Settings for coupled dimensions must be the same. :dd
{Invalid fix press/berendsen for a 2d simulation} :dt
The z component of pressure cannot be controlled for a 2d model. :dd
{Invalid fix press/berendsen pressure settings} :dt
Settings for coupled dimensions must be the same. :dd
{Invalid fix qeq parameter file} :dt
Element index > number of atom types. :dd
{Invalid fix rigid npt/nph command for a 2d simulation} :dt
Cannot control z dimension in a 2d model. :dd
{Invalid fix rigid npt/nph command pressure settings} :dt
If multiple dimensions are coupled, those dimensions must be
specified. :dd
{Invalid fix rigid/small npt/nph command for a 2d simulation} :dt
Cannot control z dimension in a 2d model. :dd
{Invalid fix rigid/small npt/nph command pressure settings} :dt
If multiple dimensions are coupled, those dimensions must be
specified. :dd
{Invalid flag in force field section of restart file} :dt
Unrecognized entry in restart file. :dd
{Invalid flag in header section of restart file} :dt
Unrecognized entry in restart file. :dd
{Invalid flag in peratom section of restart file} :dt
The format of this section of the file is not correct. :dd
{Invalid flag in type arrays section of restart file} :dt
Unrecognized entry in restart file. :dd
{Invalid frequency in temper command} :dt
Nevery must be > 0. :dd
{Invalid group ID in neigh_modify command} :dt
A group ID used in the neigh_modify command does not exist. :dd
{Invalid group function in variable formula} :dt
Group function is not recognized. :dd
{Invalid group in comm_modify command} :dt
Self-explanatory. :dd
{Invalid image up vector} :dt
Up vector cannot be (0,0,0). :dd
{Invalid immediate variable} :dt
Syntax of immediate value is incorrect. :dd
{Invalid improper count in molecule file} :dt
Self-explanatory. :dd
{Invalid improper type in Impropers section of data file} :dt
Improper type must be positive integer and within range of specified
improper types. :dd
{Invalid improper type in impropers section of molecule file} :dt
Self-explanatory. :dd
{Invalid index for non-body particles in compute body/local command} :dt
Only indices 1,2,3 can be used for non-body particles. :dd
{Invalid index in compute body/local command} :dt
Self-explanatory. :dd
{Invalid is_active() function in variable formula} :dt
Self-explanatory. :dd
{Invalid is_available() function in variable formula} :dt
Self-explanatory. :dd
{Invalid is_defined() function in variable formula} :dt
Self-explanatory. :dd
{Invalid keyword in angle table parameters} :dt
Self-explanatory. :dd
{Invalid keyword in bond table parameters} :dt
Self-explanatory. :dd
{Invalid keyword in compute angle/local command} :dt
Self-explanatory. :dd
{Invalid keyword in compute bond/local command} :dt
Self-explanatory. :dd
{Invalid keyword in compute dihedral/local command} :dt
Self-explanatory. :dd
{Invalid keyword in compute improper/local command} :dt
Self-explanatory. :dd
{Invalid keyword in compute pair/local command} :dt
Self-explanatory. :dd
{Invalid keyword in compute property/atom command} :dt
Self-explanatory. :dd
{Invalid keyword in compute property/chunk command} :dt
Self-explanatory. :dd
{Invalid keyword in compute property/local command} :dt
Self-explanatory. :dd
{Invalid keyword in dump cfg command} :dt
Self-explanatory. :dd
{Invalid keyword in pair table parameters} :dt
Keyword used in list of table parameters is not recognized. :dd
{Invalid length in set command} :dt
Self-explanatory. :dd
{Invalid mass in set command} :dt
Self-explanatory. :dd
{Invalid mass line in data file} :dt
Self-explanatory. :dd
{Invalid mass value} :dt
Self-explanatory. :dd
{Invalid math function in variable formula} :dt
Self-explanatory. :dd
{Invalid math/group/special function in variable formula} :dt
Self-explanatory. :dd
{Invalid option in lattice command for non-custom style} :dt
Certain lattice keywords are not supported unless the
lattice style is "custom". :dd
{Invalid order of forces within respa levels} :dt
For respa, ordering of force computations within respa levels must
obey certain rules. E.g. bonds cannot be compute less frequently than
angles, pairwise forces cannot be computed less frequently than
kspace, etc. :dd
{Invalid pair table cutoff} :dt
Cutoffs in pair_coeff command are not valid with read-in pair table. :dd
{Invalid pair table length} :dt
Length of read-in pair table is invalid :dd
{Invalid param file for fix qeq/shielded} :dt
Invalid value of gamma. :dd
{Invalid param file for fix qeq/slater} :dt
Zeta value is 0.0. :dd
{Invalid partitions in processors part command} :dt
Valid partitions are numbered 1 to N and the sender and receiver
cannot be the same partition. :dd
{Invalid python command} :dt
Self-explanatory. Check the input script syntax and compare to the
documentation for the command. You can use -echo screen as a
command-line option when running LAMMPS to see the offending line. :dd
{Invalid radius in Atoms section of data file} :dt
Radius must be >= 0.0. :dd
{Invalid random number seed in fix ttm command} :dt
Random number seed must be > 0. :dd
{Invalid random number seed in set command} :dt
Random number seed must be > 0. :dd
{Invalid replace values in compute reduce} :dt
Self-explanatory. :dd
{Invalid rigid body ID in fix rigid file} :dt
The ID does not match the number of an existing ID of rigid bodies
that are defined by the fix rigid command. :dd
{Invalid rigid body ID in fix rigid/small file} :dt
The ID does not match the number of an existing ID of rigid bodies
that are defined by the fix rigid/small command. :dd
{Invalid run command N value} :dt
The number of timesteps must fit in a 32-bit integer. If you want to
run for more steps than this, perform multiple shorter runs. :dd
{Invalid run command start/stop value} :dt
Self-explanatory. :dd
{Invalid run command upto value} :dt
Self-explanatory. :dd
{Invalid seed for Marsaglia random # generator} :dt
The initial seed for this random number generator must be a positive
integer less than or equal to 900 million. :dd
{Invalid seed for Park random # generator} :dt
The initial seed for this random number generator must be a positive
integer. :dd
{Invalid shake angle type in molecule file} :dt
Self-explanatory. :dd
{Invalid shake atom in molecule file} :dt
Self-explanatory. :dd
{Invalid shake bond type in molecule file} :dt
Self-explanatory. :dd
{Invalid shake flag in molecule file} :dt
Self-explanatory. :dd
{Invalid shape in Ellipsoids section of data file} :dt
Self-explanatory. :dd
{Invalid shape in Triangles section of data file} :dt
Two or more of the triangle corners are duplicate points. :dd
{Invalid shape in set command} :dt
Self-explanatory. :dd
{Invalid shear direction for fix wall/gran} :dt
Self-explanatory. :dd
{Invalid special atom index in molecule file} :dt
Self-explanatory. :dd
{Invalid special function in variable formula} :dt
Self-explanatory. :dd
{Invalid style in pair_write command} :dt
Self-explanatory. Check the input script. :dd
{Invalid syntax in variable formula} :dt
Self-explanatory. :dd
{Invalid t_event in prd command} :dt
Self-explanatory. :dd
{Invalid t_event in tad command} :dt
The value must be greater than 0. :dd
{Invalid template atom in Atoms section of data file} :dt
The atom indices must be between 1 to N, where N is the number of
atoms in the template molecule the atom belongs to. :dd
{Invalid template index in Atoms section of data file} :dt
The template indices must be between 1 to N, where N is the number of
molecules in the template. :dd
{Invalid thermo keyword in variable formula} :dt
The keyword is not recognized. :dd
{Invalid threads_per_atom specified.} :dt
For 3-body potentials on the GPU, the threads_per_atom setting cannot be
greater than 4 for NVIDIA GPUs. :dd
{Invalid timestep reset for fix ave/atom} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid timestep reset for fix ave/chunk} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid timestep reset for fix ave/correlate} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid timestep reset for fix ave/histo} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid timestep reset for fix ave/spatial} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid timestep reset for fix ave/time} :dt
Resetting the timestep has invalidated the sequence of timesteps this
fix needs to process. :dd
{Invalid tmax in tad command} :dt
The value must be greater than 0.0. :dd
{Invalid type for mass set} :dt
Mass command must set a type from 1-N where N is the number of atom
types. :dd
{Invalid use of library file() function} :dt
This function is called thru the library interface. This
error should not occur. Contact the developers if it does. :dd
{Invalid value in set command} :dt
The value specified for the setting is invalid, likely because it is
too small or too large. :dd
{Invalid variable evaluation in variable formula} :dt
A variable used in a formula could not be evaluated. :dd
{Invalid variable in next command} :dt
Self-explanatory. :dd
{Invalid variable name} :dt
Variable name used in an input script line is invalid. :dd
{Invalid variable name in variable formula} :dt
Variable name is not recognized. :dd
{Invalid variable style in special function next} :dt
Only file-style or atomfile-style variables can be used with next(). :dd
{Invalid variable style with next command} :dt
Variable styles {equal} and {world} cannot be used in a next
command. :dd
{Invalid volume in set command} :dt
Volume must be > 0.0. :dd
{Invalid wiggle direction for fix wall/gran} :dt
Self-explanatory. :dd
{Invoked angle equil angle on angle style none} :dt
Self-explanatory. :dd
{Invoked angle single on angle style none} :dt
Self-explanatory. :dd
{Invoked bond equil distance on bond style none} :dt
Self-explanatory. :dd
{Invoked bond single on bond style none} :dt
Self-explanatory. :dd
{Invoked pair single on pair style none} :dt
A command (e.g. a dump) attempted to invoke the single() function on a
pair style none, which is illegal. You are probably attempting to
compute per-atom quantities with an undefined pair style. :dd
{Invoking coulombic in pair style lj/coul requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Invoking coulombic in pair style lj/long/dipole/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{KIM neighbor iterator exceeded range} :dt
This should not happen. It likely indicates a bug
in the KIM implementation of the interatomic potential
where it is requesting neighbors incorrectly. :dd
{KOKKOS package does not yet support comm_style tiled} :dt
Self-explanatory. :dd
{KOKKOS package requires a kokkos enabled atom_style} :dt
Self-explanatory. :dd
{KSpace accuracy must be > 0} :dt
The kspace accuracy designated in the input must be greater than zero. :dd
{KSpace accuracy too large to estimate G vector} :dt
Reduce the accuracy request or specify gwald explicitly
via the kspace_modify command. :dd
{KSpace accuracy too low} :dt
Requested accuracy must be less than 1.0. :dd
{KSpace solver requires a pair style} :dt
No pair style is defined. :dd
{KSpace style does not yet support triclinic geometries} :dt
The specified kspace style does not allow for non-orthogonal
simulation boxes. :dd
{KSpace style has not yet been set} :dt
Cannot use kspace_modify command until a kspace style is set. :dd
{KSpace style is incompatible with Pair style} :dt
Setting a kspace style requires that a pair style with matching
long-range Coulombic or dispersion components be used. :dd
{Keyword %s in MEAM parameter file not recognized} :dt
Self-explanatory. :dd
{Kokkos has been compiled for CUDA but no GPUs are requested} :dt
One or more GPUs must be used when Kokkos is compiled for CUDA. :dd
{Kspace style does not support compute group/group} :dt
Self-explanatory. :dd
{Kspace style pppm/disp/tip4p requires newton on} :dt
Self-explanatory. :dd
{Kspace style pppm/tip4p requires newton on} :dt
Self-explanatory. :dd
{Kspace style requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Kspace_modify eigtol must be smaller than one} :dt
Self-explanatory. :dd
{LAMMPS is not built with Python embedded} :dt
This is done by including the PYTHON package before LAMMPS is built.
This is required to use python-style variables. :dd
{LAMMPS unit_style lj not supported by KIM models} :dt
Self-explanatory. Check the input script or data file. :dd
{LJ6 off not supported in pair_style buck/long/coul/long} :dt
Self-explanatory. :dd
{Label wasn't found in input script} :dt
Self-explanatory. :dd
{Lattice orient vectors are not orthogonal} :dt
The three specified lattice orientation vectors must be mutually
orthogonal. :dd
{Lattice orient vectors are not right-handed} :dt
The three specified lattice orientation vectors must create a
right-handed coordinate system such that a1 cross a2 = a3. :dd
{Lattice primitive vectors are collinear} :dt
The specified lattice primitive vectors do not for a unit cell with
non-zero volume. :dd
{Lattice settings are not compatible with 2d simulation} :dt
One or more of the specified lattice vectors has a non-zero z
component. :dd
{Lattice spacings are invalid} :dt
Each x,y,z spacing must be > 0. :dd
{Lattice style incompatible with simulation dimension} :dt
2d simulation can use sq, sq2, or hex lattice. 3d simulation can use
sc, bcc, or fcc lattice. :dd
{Log of zero/negative value in variable formula} :dt
Self-explanatory. :dd
{Lost atoms via balance: original %ld current %ld} :dt
This should not occur. Report the problem to the developers. :dd
{Lost atoms: original %ld current %ld} :dt
Lost atoms are checked for each time thermo output is done. See the
thermo_modify lost command for options. Lost atoms usually indicate
bad dynamics, e.g. atoms have been blown far out of the simulation
box, or moved further than one processor's sub-domain away before
reneighboring. :dd
{MEAM library error %d} :dt
A call to the MEAM Fortran library returned an error. :dd
{MPI_LMP_BIGINT and bigint in lmptype.h are not compatible} :dt
The size of the MPI datatype does not match the size of a bigint. :dd
{MPI_LMP_TAGINT and tagint in lmptype.h are not compatible} :dt
The size of the MPI datatype does not match the size of a tagint. :dd
{MSM can only currently be used with comm_style brick} :dt
This is a current restriction in LAMMPS. :dd
{MSM grid is too large} :dt
The global MSM grid is larger than OFFSET in one or more dimensions.
OFFSET is currently set to 16384. You likely need to decrease the
requested accuracy. :dd
{MSM order must be 4, 6, 8, or 10} :dt
This is a limitation of the MSM implementation in LAMMPS:
the MSM order can only be 4, 6, 8, or 10. :dd
{Mass command before simulation box is defined} :dt
The mass command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Matrix factorization to split dispersion coefficients failed} :dt
This should not normally happen. Contact the developers. :dd
{Min_style command before simulation box is defined} :dt
The min_style command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Minimization could not find thermo_pe compute} :dt
This compute is created by the thermo command. It must have been
explicitly deleted by a uncompute command. :dd
{Minimize command before simulation box is defined} :dt
The minimize command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Mismatched brackets in variable} :dt
Self-explanatory. :dd
{Mismatched compute in variable formula} :dt
A compute is referenced incorrectly or a compute that produces per-atom
values is used in an equal-style variable formula. :dd
{Mismatched fix in variable formula} :dt
A fix is referenced incorrectly or a fix that produces per-atom
values is used in an equal-style variable formula. :dd
{Mismatched variable in variable formula} :dt
A variable is referenced incorrectly or an atom-style variable that
produces per-atom values is used in an equal-style variable
formula. :dd
{Modulo 0 in variable formula} :dt
Self-explanatory. :dd
{Molecule IDs too large for compute chunk/atom} :dt
The IDs must not be larger than can be stored in a 32-bit integer
since chunk IDs are 32-bit integers. :dd
{Molecule auto special bond generation overflow} :dt
Counts exceed maxspecial setting for other atoms in system. :dd
{Molecule file has angles but no nangles setting} :dt
Self-explanatory. :dd
{Molecule file has body params but no setting for them} :dt
Self-explanatory. :dd
{Molecule file has bonds but no nbonds setting} :dt
Self-explanatory. :dd
{Molecule file has dihedrals but no ndihedrals setting} :dt
Self-explanatory. :dd
{Molecule file has impropers but no nimpropers setting} :dt
Self-explanatory. :dd
{Molecule file has no Body Doubles section} :dt
Self-explanatory. :dd
{Molecule file has no Body Integers section} :dt
Self-explanatory. :dd
{Molecule file has special flags but no bonds} :dt
Self-explanatory. :dd
{Molecule file needs both Special Bond sections} :dt
Self-explanatory. :dd
{Molecule file requires atom style body} :dt
Self-explanatory. :dd
{Molecule file shake flags not before shake atoms} :dt
The order of the two sections is important. :dd
{Molecule file shake flags not before shake bonds} :dt
The order of the two sections is important. :dd
{Molecule file shake info is incomplete} :dt
All 3 SHAKE sections are needed. :dd
{Molecule file special list does not match special count} :dt
The number of values in an atom's special list does not match count. :dd
{Molecule file z center-of-mass must be 0.0 for 2d} :dt
Self-explanatory. :dd
{Molecule file z coord must be 0.0 for 2d} :dt
Self-explanatory. :dd
{Molecule natoms must be 1 for body particle} :dt
Self-explanatory. :dd
{Molecule sizescale must be 1.0 for body particle} :dt
Self-explanatory. :dd
{Molecule template ID for atom_style template does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for create_atoms does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for fix deposit does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for fix gcmc does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for fix pour does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for fix rigid/small does not exist} :dt
Self-explanatory. :dd
{Molecule template ID for fix shake does not exist} :dt
Self-explanatory. :dd
{Molecule template ID must be alphanumeric or underscore characters} :dt
Self-explanatory. :dd
{Molecule topology/atom exceeds system topology/atom} :dt
The number of bonds, angles, etc per-atom in the molecule exceeds the
system setting. See the create_box command for how to specify these
values. :dd
{Molecule topology type exceeds system topology type} :dt
The number of bond, angle, etc types in the molecule exceeds the
system setting. See the create_box command for how to specify these
values. :dd
{More than one fix deform} :dt
Only one fix deform can be defined at a time. :dd
{More than one fix freeze} :dt
Only one of these fixes can be defined, since the granular pair
potentials access it. :dd
{More than one fix shake} :dt
Only one fix shake can be defined. :dd
{Mu not allowed when not using semi-grand in fix atom/swap command} :dt
Self-explanatory. :dd
{Must define angle_style before Angle Coeffs} :dt
Must use an angle_style command before reading a data file that
defines Angle Coeffs. :dd
{Must define angle_style before BondAngle Coeffs} :dt
Must use an angle_style command before reading a data file that
defines Angle Coeffs. :dd
{Must define angle_style before BondBond Coeffs} :dt
Must use an angle_style command before reading a data file that
defines Angle Coeffs. :dd
{Must define bond_style before Bond Coeffs} :dt
Must use a bond_style command before reading a data file that
defines Bond Coeffs. :dd
{Must define dihedral_style before AngleAngleTorsion Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines AngleAngleTorsion Coeffs. :dd
{Must define dihedral_style before AngleTorsion Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines AngleTorsion Coeffs. :dd
{Must define dihedral_style before BondBond13 Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines BondBond13 Coeffs. :dd
{Must define dihedral_style before Dihedral Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines Dihedral Coeffs. :dd
{Must define dihedral_style before EndBondTorsion Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines EndBondTorsion Coeffs. :dd
{Must define dihedral_style before MiddleBondTorsion Coeffs} :dt
Must use a dihedral_style command before reading a data file that
defines MiddleBondTorsion Coeffs. :dd
{Must define improper_style before AngleAngle Coeffs} :dt
Must use an improper_style command before reading a data file that
defines AngleAngle Coeffs. :dd
{Must define improper_style before Improper Coeffs} :dt
Must use an improper_style command before reading a data file that
defines Improper Coeffs. :dd
{Must define pair_style before Pair Coeffs} :dt
Must use a pair_style command before reading a data file that defines
Pair Coeffs. :dd
{Must define pair_style before PairIJ Coeffs} :dt
Must use a pair_style command before reading a data file that defines
PairIJ Coeffs. :dd
{Must have more than one processor partition to temper} :dt
Cannot use the temper command with only one processor partition. Use
the -partition command-line option. :dd
{Must read Atoms before Angles} :dt
The Atoms section of a data file must come before an Angles section. :dd
{Must read Atoms before Bodies} :dt
The Atoms section of a data file must come before a Bodies section. :dd
{Must read Atoms before Bonds} :dt
The Atoms section of a data file must come before a Bonds section. :dd
{Must read Atoms before Dihedrals} :dt
The Atoms section of a data file must come before a Dihedrals section. :dd
{Must read Atoms before Ellipsoids} :dt
The Atoms section of a data file must come before a Ellipsoids
section. :dd
{Must read Atoms before Impropers} :dt
The Atoms section of a data file must come before an Impropers
section. :dd
{Must read Atoms before Lines} :dt
The Atoms section of a data file must come before a Lines section. :dd
{Must read Atoms before Triangles} :dt
The Atoms section of a data file must come before a Triangles section. :dd
{Must read Atoms before Velocities} :dt
The Atoms section of a data file must come before a Velocities
section. :dd
{Must set both respa inner and outer} :dt
Cannot use just the inner or outer option with respa without using the
other. :dd
{Must set number of threads via package omp command} :dt
Because you are using the USER-OMP package, set the number of threads
via its settings, not by the pair_style snap nthreads setting. :dd
{Must shrink-wrap piston boundary} :dt
The boundary style of the face where the piston is applied must be of
type s (shrink-wrapped). :dd
{Must specify a region in fix deposit} :dt
The region keyword must be specified with this fix. :dd
{Must specify a region in fix pour} :dt
Self-explanatory. :dd
{Must specify at least 2 types in fix atom/swap command} :dt
Self-explanatory. :dd
{Must use 'kspace_modify pressure/scalar no' for rRESPA with kspace_style MSM} :dt
The kspace scalar pressure option cannot (yet) be used with rRESPA. :dd
{Must use 'kspace_modify pressure/scalar no' for tensor components with kspace_style msm} :dt
Otherwise MSM will compute only a scalar pressure. See the kspace_modify
command for details on this setting. :dd
{Must use 'kspace_modify pressure/scalar no' to obtain per-atom virial with kspace_style MSM} :dt
The kspace scalar pressure option cannot be used to obtain per-atom virial. :dd
{Must use 'kspace_modify pressure/scalar no' with GPU MSM Pair styles} :dt
The kspace scalar pressure option is not (yet) compatible with GPU MSM Pair styles. :dd
{Must use 'kspace_modify pressure/scalar no' with kspace_style msm/cg} :dt
The kspace scalar pressure option is not compatible with kspace_style msm/cg. :dd
{Must use -in switch with multiple partitions} :dt
A multi-partition simulation cannot read the input script from stdin.
The -in command-line option must be used to specify a file. :dd
{Must use Kokkos half/thread or full neighbor list with threads or GPUs} :dt
Using Kokkos half-neighbor lists with threading is not allowed. :dd
{Must use a block or cylinder region with fix pour} :dt
Self-explanatory. :dd
{Must use a block region with fix pour for 2d simulations} :dt
Self-explanatory. :dd
{Must use a bond style with TIP4P potential} :dt
TIP4P potentials assume bond lengths in water are constrained
by a fix shake command. :dd
{Must use a molecular atom style with fix poems molecule} :dt
Self-explanatory. :dd
{Must use a z-axis cylinder region with fix pour} :dt
Self-explanatory. :dd
{Must use an angle style with TIP4P potential} :dt
TIP4P potentials assume angles in water are constrained by a fix shake
command. :dd
{Must use atom map style array with Kokkos} :dt
See the atom_modify map command. :dd
{Must use atom style with molecule IDs with fix bond/swap} :dt
Self-explanatory. :dd
{Must use pair_style comb or comb3 with fix qeq/comb} :dt
Self-explanatory. :dd
{Must use variable energy with fix addforce} :dt
Must define an energy variable when applying a dynamic
force during minimization. :dd
{Must use variable energy with fix efield} :dt
You must define an energy when performing a minimization with a
variable E-field. :dd
{NEB command before simulation box is defined} :dt
Self-explanatory. :dd
{NEB requires damped dynamics minimizer} :dt
Use a different minimization style. :dd
{NEB requires use of fix neb} :dt
Self-explanatory. :dd
{NL ramp in wall/piston only implemented in zlo for now} :dt
The ramp keyword can only be used for piston applied to face zlo. :dd
{Need nswaptypes mu values in fix atom/swap command} :dt
Self-explanatory. :dd
{Needed bonus data not in data file} :dt
Some atom styles require bonus data. See the read_data doc page for
details. :dd
{Needed molecular topology not in data file} :dt
The header of the data file indicated bonds, angles, etc would be
included, but they are not present. :dd
{Neigh_modify exclude molecule requires atom attribute molecule} :dt
Self-explanatory. :dd
{Neigh_modify include group != atom_modify first group} :dt
Self-explanatory. :dd
{Neighbor delay must be 0 or multiple of every setting} :dt
The delay and every parameters set via the neigh_modify command are
inconsistent. If the delay setting is non-zero, then it must be a
multiple of the every setting. :dd
{Neighbor include group not allowed with ghost neighbors} :dt
This is a current restriction within LAMMPS. :dd
{Neighbor list overflow, boost neigh_modify one} :dt
There are too many neighbors of a single atom. Use the neigh_modify
command to increase the max number of neighbors allowed for one atom.
You may also want to boost the page size. :dd
{Neighbor multi not yet enabled for ghost neighbors} :dt
This is a current restriction within LAMMPS. :dd
{Neighbor multi not yet enabled for granular} :dt
Self-explanatory. :dd
{Neighbor multi not yet enabled for rRESPA} :dt
Self-explanatory. :dd
{Neighbor page size must be >= 10x the one atom setting} :dt
This is required to prevent wasting too much memory. :dd
{New atom IDs exceed maximum allowed ID} :dt
See the setting for tagint in the src/lmptype.h file. :dd
{New bond exceeded bonds per atom in create_bonds} :dt
See the read_data command for info on using the "extra/bond/per/atom"
keyword to allow for additional bonds to be formed
{New bond exceeded bonds per atom in fix bond/create} :dt
See the read_data command for info on using the "extra/bond/per/atom"
keyword to allow for additional bonds to be formed :dd
{New bond exceeded special list size in fix bond/create} :dt
See the "special_bonds extra" command
(or the "read_data extra/special/per/atom" command)
for info on how to leave space in the special bonds
list to allow for additional bonds to be formed. :dd
{Newton bond change after simulation box is defined} :dt
The newton command cannot be used to change the newton bond value
after a read_data, read_restart, or create_box command. :dd
{Next command must list all universe and uloop variables} :dt
This is to insure they stay in sync. :dd
{No Kspace style defined for compute group/group} :dt
Self-explanatory. :dd
{No OpenMP support compiled in} :dt
An OpenMP flag is set, but LAMMPS was not built with
OpenMP support. :dd
{No angle style is defined for compute angle/local} :dt
Self-explanatory. :dd
{No angles allowed with this atom style} :dt
Self-explanatory. :dd
{No atoms in data file} :dt
The header of the data file indicated that atoms would be included,
but they are not present. :dd
{No basis atoms in lattice} :dt
Basis atoms must be defined for lattice style user. :dd
{No bodies allowed with this atom style} :dt
Self-explanatory. Check data file. :dd
{No bond style is defined for compute bond/local} :dt
Self-explanatory. :dd
{No bonds allowed with this atom style} :dt
Self-explanatory. :dd
{No box information in dump. You have to use 'box no'} :dt
Self-explanatory. :dd
{No count or invalid atom count in molecule file} :dt
The number of atoms must be specified. :dd
{No dihedral style is defined for compute dihedral/local} :dt
Self-explanatory. :dd
{No dihedrals allowed with this atom style} :dt
Self-explanatory. :dd
{No dump custom arguments specified} :dt
The dump custom command requires that atom quantities be specified to
output to dump file. :dd
{No dump local arguments specified} :dt
Self-explanatory. :dd
{No ellipsoids allowed with this atom style} :dt
Self-explanatory. Check data file. :dd
{No fix gravity defined for fix pour} :dt
Gravity is required to use fix pour. :dd
{No improper style is defined for compute improper/local} :dt
Self-explanatory. :dd
{No impropers allowed with this atom style} :dt
Self-explanatory. :dd
{No input values for fix ave/spatial} :dt
Self-explanatory. :dd
{No lines allowed with this atom style} :dt
Self-explanatory. Check data file. :dd
{No matching element in ADP potential file} :dt
The ADP potential file does not contain elements that match the
requested elements. :dd
{No matching element in EAM potential file} :dt
The EAM potential file does not contain elements that match the
requested elements. :dd
{No molecule topology allowed with atom style template} :dt
The data file cannot specify the number of bonds, angles, etc,
because this info if inferred from the molecule templates. :dd
{No overlap of box and region for create_atoms} :dt
Self-explanatory. :dd
{No pair coul/streitz for fix qeq/slater} :dt
These commands must be used together. :dd
{No pair hbond/dreiding coefficients set} :dt
Self-explanatory. :dd
{No pair style defined for compute group/group} :dt
Cannot calculate group interactions without a pair style defined. :dd
{No pair style is defined for compute pair/local} :dt
Self-explanatory. :dd
{No pair style is defined for compute property/local} :dt
Self-explanatory. :dd
{No rigid bodies defined} :dt
The fix specification did not end up defining any rigid bodies. :dd
{No triangles allowed with this atom style} :dt
Self-explanatory. Check data file. :dd
{No values in fix ave/chunk command} :dt
Self-explanatory. :dd
{No values in fix ave/time command} :dt
Self-explanatory. :dd
{Non digit character between brackets in variable} :dt
Self-explanatory. :dd
{Non integer # of swaps in temper command} :dt
Swap frequency in temper command must evenly divide the total # of
timesteps. :dd
{Non-numeric box dimensions - simulation unstable} :dt
The box size has apparently blown up. :dd
{Non-zero atom IDs with atom_modify id = no} :dt
Self-explanatory. :dd
{Non-zero read_data shift z value for 2d simulation} :dt
Self-explanatory. :dd
{Nprocs not a multiple of N for -reorder} :dt
Self-explanatory. :dd
{Number of core atoms != number of shell atoms} :dt
There must be a one-to-one pairing of core and shell atoms. :dd
{Numeric index is out of bounds} :dt
A command with an argument that specifies an integer or range of
integers is using a value that is less than 1 or greater than the
maximum allowed limit. :dd
{One or more Atom IDs is negative} :dt
Atom IDs must be positive integers. :dd
{One or more atom IDs is too big} :dt
The limit on atom IDs is set by the SMALLBIG, BIGBIG, SMALLSMALL
setting in your Makefile. See Section_start 2.2 of the manual for
more details. :dd
{One or more atom IDs is zero} :dt
Either all atoms IDs must be zero or none of them. :dd
{One or more atoms belong to multiple rigid bodies} :dt
Two or more rigid bodies defined by the fix rigid command cannot
contain the same atom. :dd
{One or more rigid bodies are a single particle} :dt
Self-explanatory. :dd
{One or zero atoms in rigid body} :dt
Any rigid body defined by the fix rigid command must contain 2 or more
atoms. :dd
{Only 2 types allowed when not using semi-grand in fix atom/swap command} :dt
Self-explanatory. :dd
{Only one cut-off allowed when requesting all long} :dt
Self-explanatory. :dd
{Only one cutoff allowed when requesting all long} :dt
Self-explanatory. :dd
{Only zhi currently implemented for fix append/atoms} :dt
Self-explanatory. :dd
{Out of range atoms - cannot compute MSM} :dt
One or more atoms are attempting to map their charge to a MSM grid point
that is not owned by a processor. This is likely for one of two
reasons, both of them bad. First, it may mean that an atom near the
boundary of a processor's sub-domain has moved more than 1/2 the
"neighbor skin distance"_neighbor.html without neighbor lists being
rebuilt and atoms being migrated to new processors. This also means
you may be missing pairwise interactions that need to be computed.
The solution is to change the re-neighboring criteria via the
"neigh_modify"_neigh_modify.html command. The safest settings are
"delay 0 every 1 check yes". Second, it may mean that an atom has
moved far outside a processor's sub-domain or even the entire
simulation box. This indicates bad physics, e.g. due to highly
overlapping atoms, too large a timestep, etc. :dd
{Out of range atoms - cannot compute PPPM} :dt
One or more atoms are attempting to map their charge to a PPPM grid
point that is not owned by a processor. This is likely for one of two
reasons, both of them bad. First, it may mean that an atom near the
boundary of a processor's sub-domain has moved more than 1/2 the
"neighbor skin distance"_neighbor.html without neighbor lists being
rebuilt and atoms being migrated to new processors. This also means
you may be missing pairwise interactions that need to be computed.
The solution is to change the re-neighboring criteria via the
"neigh_modify"_neigh_modify.html command. The safest settings are
"delay 0 every 1 check yes". Second, it may mean that an atom has
moved far outside a processor's sub-domain or even the entire
simulation box. This indicates bad physics, e.g. due to highly
overlapping atoms, too large a timestep, etc. :dd
{Out of range atoms - cannot compute PPPMDisp} :dt
One or more atoms are attempting to map their charge to a PPPM grid
point that is not owned by a processor. This is likely for one of two
reasons, both of them bad. First, it may mean that an atom near the
boundary of a processor's sub-domain has moved more than 1/2 the
"neighbor skin distance"_neighbor.html without neighbor lists being
rebuilt and atoms being migrated to new processors. This also means
you may be missing pairwise interactions that need to be computed.
The solution is to change the re-neighboring criteria via the
"neigh_modify"_neigh_modify.html command. The safest settings are
"delay 0 every 1 check yes". Second, it may mean that an atom has
moved far outside a processor's sub-domain or even the entire
simulation box. This indicates bad physics, e.g. due to highly
overlapping atoms, too large a timestep, etc. :dd
{Overflow of allocated fix vector storage} :dt
This should not normally happen if the fix correctly calculated
how long the vector will grow to. Contact the developers. :dd
{Overlapping large/large in pair colloid} :dt
This potential is infinite when there is an overlap. :dd
{Overlapping small/large in pair colloid} :dt
This potential is infinite when there is an overlap. :dd
{POEMS fix must come before NPT/NPH fix} :dt
NPT/NPH fix must be defined in input script after all poems fixes,
else the fix contribution to the pressure virial is incorrect. :dd
{PPPM can only currently be used with comm_style brick} :dt
This is a current restriction in LAMMPS. :dd
{PPPM grid is too large} :dt
The global PPPM grid is larger than OFFSET in one or more dimensions.
OFFSET is currently set to 4096. You likely need to decrease the
requested accuracy. :dd
{PPPM grid stencil extends beyond nearest neighbor processor} :dt
This is not allowed if the kspace_modify overlap setting is no. :dd
{PPPM order < minimum allowed order} :dt
The default minimum order is 2. This can be reset by the
kspace_modify minorder command. :dd
{PPPM order cannot be < 2 or > than %d} :dt
This is a limitation of the PPPM implementation in LAMMPS. :dd
{PPPMDisp Coulomb grid is too large} :dt
The global PPPM grid is larger than OFFSET in one or more dimensions.
OFFSET is currently set to 4096. You likely need to decrease the
requested accuracy. :dd
{PPPMDisp Dispersion grid is too large} :dt
The global PPPM grid is larger than OFFSET in one or more dimensions.
OFFSET is currently set to 4096. You likely need to decrease the
requested accuracy. :dd
{PPPMDisp can only currently be used with comm_style brick} :dt
This is a current restriction in LAMMPS. :dd
{PPPMDisp coulomb order cannot be greater than %d} :dt
This is a limitation of the PPPM implementation in LAMMPS. :dd
{PPPMDisp used but no parameters set, for further information please see the pppm/disp documentation} :dt
An efficient and accurate usage of the pppm/disp requires settings via the kspace_modify command. Please see the pppm/disp documentation for further instructions. :dd
{PRD command before simulation box is defined} :dt
The prd command cannot be used before a read_data,
read_restart, or create_box command. :dd
{PRD nsteps must be multiple of t_event} :dt
Self-explanatory. :dd
{PRD t_corr must be multiple of t_event} :dt
Self-explanatory. :dd
{Package command after simulation box is defined} :dt
The package command cannot be used afer a read_data, read_restart, or
create_box command. :dd
{Package cuda command without USER-CUDA package enabled} :dt
The USER-CUDA package must be installed via "make yes-user-cuda"
before LAMMPS is built, and the "-c on" must be used to enable the
package. :dd
{Package gpu command without GPU package installed} :dt
The GPU package must be installed via "make yes-gpu" before LAMMPS is
built. :dd
{Package intel command without USER-INTEL package installed} :dt
The USER-INTEL package must be installed via "make yes-user-intel"
before LAMMPS is built. :dd
{Package kokkos command without KOKKOS package enabled} :dt
The KOKKOS package must be installed via "make yes-kokkos" before
LAMMPS is built, and the "-k on" must be used to enable the package. :dd
{Package omp command without USER-OMP package installed} :dt
The USER-OMP package must be installed via "make yes-user-omp" before
LAMMPS is built. :dd
{Pair body requires atom style body} :dt
Self-explanatory. :dd
{Pair body requires body style nparticle} :dt
This pair style is specific to the nparticle body style. :dd
{Pair brownian requires atom style sphere} :dt
Self-explanatory. :dd
{Pair brownian requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Pair brownian requires monodisperse particles} :dt
All particles must be the same finite size. :dd
{Pair brownian/poly requires atom style sphere} :dt
Self-explanatory. :dd
{Pair brownian/poly requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Pair brownian/poly requires newton pair off} :dt
Self-explanatory. :dd
{Pair coeff for hybrid has invalid style} :dt
Style in pair coeff must have been listed in pair_style command. :dd
{Pair coul/wolf requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair cutoff < Respa interior cutoff} :dt
One or more pairwise cutoffs are too short to use with the specified
rRESPA cutoffs. :dd
{Pair dipole/cut requires atom attributes q, mu, torque} :dt
The atom style defined does not have these attributes. :dd
{Pair dipole/cut/gpu requires atom attributes q, mu, torque} :dt
The atom style defined does not have this attribute. :dd
{Pair dipole/long requires atom attributes q, mu, torque} :dt
The atom style defined does not have these attributes. :dd
{Pair dipole/sf/gpu requires atom attributes q, mu, torque} :dt
The atom style defined does not one or more of these attributes. :dd
{Pair distance < table inner cutoff} :dt
Two atoms are closer together than the pairwise table allows. :dd
{Pair distance > table outer cutoff} :dt
Two atoms are further apart than the pairwise table allows. :dd
{Pair dpd requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair gayberne epsilon a,b,c coeffs are not all set} :dt
Each atom type involved in pair_style gayberne must
have these 3 coefficients set at least once. :dd
{Pair gayberne requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Pair gayberne requires atoms with same type have same shape} :dt
Self-explanatory. :dd
{Pair gayberne/gpu requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Pair gayberne/gpu requires atoms with same type have same shape} :dt
Self-explanatory. :dd
{Pair granular requires atom attributes radius, rmass} :dt
The atom style defined does not have these attributes. :dd
{Pair granular requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair granular with shear history requires newton pair off} :dt
This is a current restriction of the implementation of pair
granular styles with history. :dd
{Pair hybrid single calls do not support per sub-style special bond values} :dt
Self-explanatory. :dd
{Pair hybrid sub-style does not support single call} :dt
You are attempting to invoke a single() call on a pair style
that doesn't support it. :dd
{Pair hybrid sub-style is not used} :dt
No pair_coeff command used a sub-style specified in the pair_style
command. :dd
{Pair inner cutoff < Respa interior cutoff} :dt
One or more pairwise cutoffs are too short to use with the specified
rRESPA cutoffs. :dd
{Pair inner cutoff >= Pair outer cutoff} :dt
The specified cutoffs for the pair style are inconsistent. :dd
{Pair line/lj requires atom style line} :dt
Self-explanatory. :dd
{Pair lj/long/dipole/long requires atom attributes mu, torque} :dt
The atom style defined does not have these attributes. :dd
{Pair lubricate requires atom style sphere} :dt
Self-explanatory. :dd
{Pair lubricate requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair lubricate requires monodisperse particles} :dt
All particles must be the same finite size. :dd
{Pair lubricate/poly requires atom style sphere} :dt
Self-explanatory. :dd
{Pair lubricate/poly requires extended particles} :dt
One of the particles has radius 0.0. :dd
{Pair lubricate/poly requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair lubricate/poly requires newton pair off} :dt
Self-explanatory. :dd
{Pair lubricateU requires atom style sphere} :dt
Self-explanatory. :dd
{Pair lubricateU requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair lubricateU requires monodisperse particles} :dt
All particles must be the same finite size. :dd
{Pair lubricateU/poly requires ghost atoms store velocity} :dt
Use the comm_modify vel yes command to enable this. :dd
{Pair lubricateU/poly requires newton pair off} :dt
Self-explanatory. :dd
{Pair peri lattice is not identical in x, y, and z} :dt
The lattice defined by the lattice command must be cubic. :dd
{Pair peri requires a lattice be defined} :dt
Use the lattice command for this purpose. :dd
{Pair peri requires an atom map, see atom_modify} :dt
Even for atomic systems, an atom map is required to find Peridynamic
bonds. Use the atom_modify command to define one. :dd
{Pair resquared epsilon a,b,c coeffs are not all set} :dt
Self-explanatory. :dd
{Pair resquared epsilon and sigma coeffs are not all set} :dt
Self-explanatory. :dd
{Pair resquared requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Pair resquared requires atoms with same type have same shape} :dt
Self-explanatory. :dd
{Pair resquared/gpu requires atom style ellipsoid} :dt
Self-explanatory. :dd
{Pair resquared/gpu requires atoms with same type have same shape} :dt
Self-explanatory. :dd
{Pair style AIREBO requires atom IDs} :dt
This is a requirement to use the AIREBO potential. :dd
{Pair style AIREBO requires newton pair on} :dt
See the newton command. This is a restriction to use the AIREBO
potential. :dd
{Pair style BOP requires atom IDs} :dt
This is a requirement to use the BOP potential. :dd
{Pair style BOP requires newton pair on} :dt
See the newton command. This is a restriction to use the BOP
potential. :dd
{Pair style COMB requires atom IDs} :dt
This is a requirement to use the AIREBO potential. :dd
{Pair style COMB requires atom attribute q} :dt
Self-explanatory. :dd
{Pair style COMB requires newton pair on} :dt
See the newton command. This is a restriction to use the COMB
potential. :dd
{Pair style COMB3 requires atom IDs} :dt
This is a requirement to use the COMB3 potential. :dd
{Pair style COMB3 requires atom attribute q} :dt
Self-explanatory. :dd
{Pair style COMB3 requires newton pair on} :dt
See the newton command. This is a restriction to use the COMB3
potential. :dd
{Pair style LCBOP requires atom IDs} :dt
This is a requirement to use the LCBOP potential. :dd
{Pair style LCBOP requires newton pair on} :dt
See the newton command. This is a restriction to use the Tersoff
potential. :dd
{Pair style MEAM requires newton pair on} :dt
See the newton command. This is a restriction to use the MEAM
potential. :dd
{Pair style SNAP requires newton pair on} :dt
See the newton command. This is a restriction to use the SNAP
potential. :dd
{Pair style Stillinger-Weber requires atom IDs} :dt
This is a requirement to use the SW potential. :dd
{Pair style Stillinger-Weber requires newton pair on} :dt
See the newton command. This is a restriction to use the SW
potential. :dd
{Pair style Tersoff requires atom IDs} :dt
This is a requirement to use the Tersoff potential. :dd
{Pair style Tersoff requires newton pair on} :dt
See the newton command. This is a restriction to use the Tersoff
potential. :dd
{Pair style Vashishta requires atom IDs} :dt
This is a requirement to use the Vashishta potential. :dd
{Pair style Vashishta requires newton pair on} :dt
See the newton command. This is a restriction to use the Vashishta
potential. :dd
{Pair style bop requires comm ghost cutoff at least 3x larger than %g} :dt
Use the communicate ghost command to set this. See the pair bop
doc page for more details. :dd
{Pair style born/coul/long requires atom attribute q} :dt
An atom style that defines this attribute must be used. :dd
{Pair style born/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style born/coul/wolf requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style buck/coul/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style buck/coul/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style buck/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style buck/long/coul/long requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style coul/cut requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style coul/cut/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style coul/debye/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style coul/dsf requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style coul/dsf/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style coul/streitz requires atom attribute q} :dt
Self-explanatory. :dd
{Pair style does not have extra field requested by compute pair/local} :dt
The pair style does not support the pN value requested by the compute
pair/local command. :dd
{Pair style does not support bond_style quartic} :dt
The pair style does not have a single() function, so it can
not be invoked by bond_style quartic. :dd
{Pair style does not support compute group/group} :dt
The pair_style does not have a single() function, so it cannot be
invoked by the compute group/group command. :dd
{Pair style does not support compute pair/local} :dt
The pair style does not have a single() function, so it can
not be invoked by compute pair/local. :dd
{Pair style does not support compute property/local} :dt
The pair style does not have a single() function, so it can
not be invoked by fix bond/swap. :dd
{Pair style does not support fix bond/swap} :dt
The pair style does not have a single() function, so it can
not be invoked by fix bond/swap. :dd
{Pair style does not support pair_write} :dt
The pair style does not have a single() function, so it can
not be invoked by pair write. :dd
{Pair style does not support rRESPA inner/middle/outer} :dt
You are attempting to use rRESPA options with a pair style that
does not support them. :dd
{Pair style granular with history requires atoms have IDs} :dt
Atoms in the simulation do not have IDs, so history effects
cannot be tracked by the granular pair potential. :dd
{Pair style hbond/dreiding requires an atom map, see atom_modify} :dt
Self-explanatory. :dd
{Pair style hbond/dreiding requires atom IDs} :dt
Self-explanatory. :dd
{Pair style hbond/dreiding requires molecular system} :dt
Self-explanatory. :dd
{Pair style hbond/dreiding requires newton pair on} :dt
See the newton command for details. :dd
{Pair style hybrid cannot have hybrid as an argument} :dt
Self-explanatory. :dd
{Pair style hybrid cannot have none as an argument} :dt
Self-explanatory. :dd
{Pair style is incompatible with KSpace style} :dt
If a pair style with a long-range Coulombic component is selected,
then a kspace style must also be used. :dd
{Pair style is incompatible with TIP4P KSpace style} :dt
The pair style does not have the requires TIP4P settings. :dd
{Pair style lj/charmm/coul/charmm requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style lj/charmm/coul/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style lj/charmm/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/class2/coul/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/class2/coul/long requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/class2/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/cut/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/debye/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/dsf requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style lj/cut/coul/dsf/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/long requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/tip4p/cut requires atom IDs} :dt
This is a requirement to use this potential. :dd
{Pair style lj/cut/tip4p/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style lj/cut/tip4p/cut requires newton pair on} :dt
See the newton command. This is a restriction to use this
potential. :dd
{Pair style lj/cut/tip4p/long requires atom IDs} :dt
There are no atom IDs defined in the system and the TIP4P potential
requires them to find O,H atoms with a water molecule. :dd
{Pair style lj/cut/tip4p/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style lj/cut/tip4p/long requires newton pair on} :dt
This is because the computation of constraint forces within a water
molecule adds forces to atoms owned by other processors. :dd
{Pair style lj/gromacs/coul/gromacs requires atom attribute q} :dt
An atom_style with this attribute is needed. :dd
{Pair style lj/long/dipole/long does not currently support respa} :dt
This feature is not yet supported. :dd
{Pair style lj/long/tip4p/long requires atom IDs} :dt
There are no atom IDs defined in the system and the TIP4P potential
requires them to find O,H atoms with a water molecule. :dd
{Pair style lj/long/tip4p/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style lj/long/tip4p/long requires newton pair on} :dt
This is because the computation of constraint forces within a water
molecule adds forces to atoms owned by other processors. :dd
{Pair style lj/sdk/coul/long/gpu requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style nb3b/harmonic requires atom IDs} :dt
This is a requirement to use this potential. :dd
{Pair style nb3b/harmonic requires newton pair on} :dt
See the newton command. This is a restriction to use this potential. :dd
{Pair style nm/cut/coul/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style nm/cut/coul/long requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style peri requires atom style peri} :dt
Self-explanatory. :dd
{Pair style polymorphic requires atom IDs} :dt
This is a requirement to use the polymorphic potential. :dd
{Pair style polymorphic requires newton pair on} :dt
See the newton command. This is a restriction to use the polymorphic
potential. :dd
{Pair style reax requires atom IDs} :dt
This is a requirement to use the ReaxFF potential. :dd
{Pair style reax requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style reax requires newton pair on} :dt
This is a requirement to use the ReaxFF potential. :dd
{Pair style requires a KSpace style} :dt
No kspace style is defined. :dd
{Pair style requires use of kspace_style ewald/disp} :dt
Self-explanatory. :dd
{Pair style sw/gpu requires atom IDs} :dt
This is a requirement to use this potential. :dd
{Pair style sw/gpu requires newton pair off} :dt
See the newton command. This is a restriction to use this potential. :dd
{Pair style vashishta/gpu requires atom IDs} :dt
This is a requirement to use this potential. :dd
{Pair style vashishta/gpu requires newton pair off} :dt
See the newton command. This is a restriction to use this potential. :dd
{Pair style tersoff/gpu requires atom IDs} :dt
This is a requirement to use the tersoff/gpu potential. :dd
{Pair style tersoff/gpu requires newton pair off} :dt
See the newton command. This is a restriction to use this pair style. :dd
{Pair style tip4p/cut requires atom IDs} :dt
This is a requirement to use this potential. :dd
{Pair style tip4p/cut requires atom attribute q} :dt
The atom style defined does not have this attribute. :dd
{Pair style tip4p/cut requires newton pair on} :dt
See the newton command. This is a restriction to use this potential. :dd
{Pair style tip4p/long requires atom IDs} :dt
There are no atom IDs defined in the system and the TIP4P potential
requires them to find O,H atoms with a water molecule. :dd
{Pair style tip4p/long requires atom attribute q} :dt
The atom style defined does not have these attributes. :dd
{Pair style tip4p/long requires newton pair on} :dt
This is because the computation of constraint forces within a water
molecule adds forces to atoms owned by other processors. :dd
{Pair table cutoffs must all be equal to use with KSpace} :dt
When using pair style table with a long-range KSpace solver, the
cutoffs for all atom type pairs must all be the same, since the
long-range solver starts at that cutoff. :dd
{Pair table parameters did not set N} :dt
List of pair table parameters must include N setting. :dd
{Pair tersoff/zbl requires metal or real units} :dt
This is a current restriction of this pair potential. :dd
{Pair tersoff/zbl/kk requires metal or real units} :dt
This is a current restriction of this pair potential. :dd
{Pair tri/lj requires atom style tri} :dt
Self-explanatory. :dd
{Pair yukawa/colloid requires atom style sphere} :dt
Self-explanatory. :dd
{Pair yukawa/colloid requires atoms with same type have same radius} :dt
Self-explanatory. :dd
{Pair yukawa/colloid/gpu requires atom style sphere} :dt
Self-explanatory. :dd
{PairKIM only works with 3D problems} :dt
This is a current limitation. :dd
{Pair_coeff command before pair_style is defined} :dt
Self-explanatory. :dd
{Pair_coeff command before simulation box is defined} :dt
The pair_coeff command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Pair_modify command before pair_style is defined} :dt
Self-explanatory. :dd
{Pair_modify special setting for pair hybrid incompatible with global special_bonds setting} :dt
Cannot override a setting of 0.0 or 1.0 or change a setting between
0.0 and 1.0. :dd
{Pair_write command before pair_style is defined} :dt
Self-explanatory. :dd
{Particle on or inside fix wall surface} :dt
Particles must be "exterior" to the wall in order for energy/force to
be calculated. :dd
{Particle outside surface of region used in fix wall/region} :dt
Particles must be inside the region for energy/force to be calculated.
A particle outside the region generates an error. :dd
{Per-atom compute in equal-style variable formula} :dt
Equal-style variables cannot use per-atom quantities. :dd
{Per-atom energy was not tallied on needed timestep} :dt
You are using a thermo keyword that requires potentials to
have tallied energy, but they didn't on this timestep. See the
variable doc page for ideas on how to make this work. :dd
{Per-atom fix in equal-style variable formula} :dt
Equal-style variables cannot use per-atom quantities. :dd
{Per-atom virial was not tallied on needed timestep} :dt
You are using a thermo keyword that requires potentials to have
tallied the virial, but they didn't on this timestep. See the
variable doc page for ideas on how to make this work. :dd
{Per-processor system is too big} :dt
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer. :dd
{Potential energy ID for fix neb does not exist} :dt
Self-explanatory. :dd
{Potential energy ID for fix nvt/nph/npt does not exist} :dt
A compute for potential energy must be defined. :dd
{Potential file has duplicate entry} :dt
The potential file has more than one entry for the same element. :dd
{Potential file is missing an entry} :dt
The potential file does not have a needed entry. :dd
{Power by 0 in variable formula} :dt
Self-explanatory. :dd
{Pressure ID for fix box/relax does not exist} :dt
The compute ID needed to compute pressure for the fix does not
exist. :dd
{Pressure ID for fix modify does not exist} :dt
Self-explanatory. :dd
{Pressure ID for fix npt/nph does not exist} :dt
Self-explanatory. :dd
{Pressure ID for fix press/berendsen does not exist} :dt
The compute ID needed to compute pressure for the fix does not
exist. :dd
{Pressure ID for fix rigid npt/nph does not exist} :dt
Self-explanatory. :dd
{Pressure ID for thermo does not exist} :dt
The compute ID needed to compute pressure for thermodynamics does not
exist. :dd
{Pressure control can not be used with fix nvt} :dt
Self-explanatory. :dd
{Pressure control can not be used with fix nvt/asphere} :dt
Self-explanatory. :dd
{Pressure control can not be used with fix nvt/body} :dt
Self-explanatory. :dd
{Pressure control can not be used with fix nvt/sllod} :dt
Self-explanatory. :dd
{Pressure control can not be used with fix nvt/sphere} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nph} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nph/asphere} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nph/body} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nph/small} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nph/sphere} :dt
Self-explanatory. :dd
{Pressure control must be used with fix nphug} :dt
A pressure control keyword (iso, aniso, tri, x, y, or z) must be
provided. :dd
{Pressure control must be used with fix npt} :dt
Self-explanatory. :dd
{Pressure control must be used with fix npt/asphere} :dt
Self-explanatory. :dd
{Pressure control must be used with fix npt/body} :dt
Self-explanatory. :dd
{Pressure control must be used with fix npt/sphere} :dt
Self-explanatory. :dd
{Processor count in z must be 1 for 2d simulation} :dt
Self-explanatory. :dd
{Processor partitions do not match number of allocated processors} :dt
The total number of processors in all partitions must match the number
of processors LAMMPS is running on. :dd
{Processors command after simulation box is defined} :dt
The processors command cannot be used after a read_data, read_restart,
or create_box command. :dd
{Processors custom grid file is inconsistent} :dt
The vales in the custom file are not consistent with the number of
processors you are running on or the Px,Py,Pz settings of the
processors command. Or there was not a setting for every processor. :dd
{Processors grid numa and map style are incompatible} :dt
Using numa for gstyle in the processors command requires using
cart for the map option. :dd
{Processors part option and grid style are incompatible} :dt
Cannot use gstyle numa or custom with the part option. :dd
{Processors twogrid requires proc count be a multiple of core count} :dt
Self-explanatory. :dd
{Pstart and Pstop must have the same value} :dt
Self-explanatory. :dd
{Python function evaluation failed} :dt
The Python function did not run successfully and/or did not return a
value (if it is supposed to return a value). This is probably due to
some error condition in the function. :dd
{Python function is not callable} :dt
The provided Python code was run successfully, but it not
define a callable function with the required name. :dd
{Python invoke of undefined function} :dt
Cannot invoke a function that has not been previously defined. :dd
{Python variable does not match Python function} :dt
This matching is defined by the python-style variable and the python
command. :dd
{Python variable has no function} :dt
No python command was used to define the function associated with the
python-style variable. :dd
{QEQ with 'newton pair off' not supported} :dt
See the newton command. This is a restriction to use the QEQ fixes. :dd
{R0 < 0 for fix spring command} :dt
Equilibrium spring length is invalid. :dd
{RATTLE coordinate constraints are not satisfied up to desired tolerance} :dt
Self-explanatory. :dd
{RATTLE determinant = 0.0} :dt
The determinant of the matrix being solved for a single cluster
specified by the fix rattle command is numerically invalid. :dd
{RATTLE failed} :dt
Certain constraints were not satisfied. :dd
{RATTLE velocity constraints are not satisfied up to desired tolerance} :dt
Self-explanatory. :dd
{Read data add offset is too big} :dt
It cannot be larger than the size of atom IDs, e.g. the maximum 32-bit
integer. :dd
{Read dump of atom property that isn't allocated} :dt
Self-explanatory. :dd
{Read rerun dump file timestep > specified stop} :dt
Self-explanatory. :dd
{Read restart MPI-IO input not allowed with % in filename} :dt
This is because a % signifies one file per processor and MPI-IO
creates one large file for all processors. :dd
{Read_data shrink wrap did not assign all atoms correctly} :dt
This is typically because the box-size specified in the data file is
large compared to the actual extent of atoms in a shrink-wrapped
dimension. When LAMMPS shrink-wraps the box atoms will be lost if the
processor they are re-assigned to is too far away. Choose a box
size closer to the actual extent of the atoms. :dd
{Read_dump command before simulation box is defined} :dt
The read_dump command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Read_dump field not found in dump file} :dt
Self-explanatory. :dd
{Read_dump triclinic status does not match simulation} :dt
Both the dump snapshot and the current LAMMPS simulation must
be using either an orthogonal or triclinic box. :dd
{Read_dump xyz fields do not have consistent scaling/wrapping} :dt
Self-explanatory. :dd
{Reading from MPI-IO filename when MPIIO package is not installed} :dt
Self-explanatory. :dd
{Reax_defs.h setting for NATDEF is too small} :dt
Edit the setting in the ReaxFF library and re-compile the
library and re-build LAMMPS. :dd
{Reax_defs.h setting for NNEIGHMAXDEF is too small} :dt
Edit the setting in the ReaxFF library and re-compile the
library and re-build LAMMPS. :dd
{Receiving partition in processors part command is already a receiver} :dt
Cannot specify a partition to be a receiver twice. :dd
{Region ID for compute chunk/atom does not exist} :dt
Self-explanatory. :dd
{Region ID for compute reduce/region does not exist} :dt
Self-explanatory. :dd
{Region ID for compute temp/region does not exist} :dt
Self-explanatory. :dd
{Region ID for dump custom does not exist} :dt
Self-explanatory. :dd
{Region ID for fix addforce does not exist} :dt
Self-explanatory. :dd
{Region ID for fix atom/swap does not exist} :dt
Self-explanatory. :dd
{Region ID for fix ave/spatial does not exist} :dt
Self-explanatory. :dd
{Region ID for fix aveforce does not exist} :dt
Self-explanatory. :dd
{Region ID for fix deposit does not exist} :dt
Self-explanatory. :dd
{Region ID for fix efield does not exist} :dt
Self-explanatory. :dd
{Region ID for fix evaporate does not exist} :dt
Self-explanatory. :dd
{Region ID for fix gcmc does not exist} :dt
Self-explanatory. :dd
{Region ID for fix heat does not exist} :dt
Self-explanatory. :dd
{Region ID for fix setforce does not exist} :dt
Self-explanatory. :dd
{Region ID for fix wall/region does not exist} :dt
Self-explanatory. :dd
{Region ID for group dynamic does not exist} :dt
Self-explanatory. :dd
{Region ID in variable formula does not exist} :dt
Self-explanatory. :dd
{Region cannot have 0 length rotation vector} :dt
Self-explanatory. :dd
{Region for fix oneway does not exist} :dt
Self-explanatory. :dd
{Region intersect region ID does not exist} :dt
Self-explanatory. :dd
{Region union or intersect cannot be dynamic} :dt
The sub-regions can be dynamic, but not the combined region. :dd
{Region union region ID does not exist} :dt
One or more of the region IDs specified by the region union command
does not exist. :dd
{Replacing a fix, but new style != old style} :dt
A fix ID can be used a 2nd time, but only if the style matches the
previous fix. In this case it is assumed you with to reset a fix's
parameters. This error may mean you are mistakenly re-using a fix ID
when you do not intend to. :dd
{Replicate command before simulation box is defined} :dt
The replicate command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Replicate did not assign all atoms correctly} :dt
Atoms replicated by the replicate command were not assigned correctly
to processors. This is likely due to some atom coordinates being
outside a non-periodic simulation box. :dd
{Replicated system atom IDs are too big} :dt
See the setting for tagint in the src/lmptype.h file. :dd
{Replicated system is too big} :dt
See the setting for bigint in the src/lmptype.h file. :dd
{Required border comm not yet implemented with Kokkos} :dt
There are various limitations in the communication options supported
by Kokkos. :dd
{Rerun command before simulation box is defined} :dt
The rerun command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Rerun dump file does not contain requested snapshot} :dt
Self-explanatory. :dd
{Resetting timestep size is not allowed with fix move} :dt
This is because fix move is moving atoms based on elapsed time. :dd
{Respa inner cutoffs are invalid} :dt
The first cutoff must be <= the second cutoff. :dd
{Respa levels must be >= 1} :dt
Self-explanatory. :dd
{Respa middle cutoffs are invalid} :dt
The first cutoff must be <= the second cutoff. :dd
{Restart file MPI-IO output not allowed with % in filename} :dt
This is because a % signifies one file per processor and MPI-IO
creates one large file for all processors. :dd
{Restart file byte ordering is not recognized} :dt
The file does not appear to be a LAMMPS restart file since it doesn't
contain a recognized byte-orderomg flag at the beginning. :dd
{Restart file byte ordering is swapped} :dt
The file was written on a machine with different byte-ordering than
the machine you are reading it on. Convert it to a text data file
instead, on the machine you wrote it on. :dd
{Restart file incompatible with current version} :dt
This is probably because you are trying to read a file created with a
version of LAMMPS that is too old compared to the current version.
Use your older version of LAMMPS and convert the restart file
to a data file. :dd
{Restart file is a MPI-IO file} :dt
The file is inconsistent with the filename you specified for it. :dd
{Restart file is a multi-proc file} :dt
The file is inconsistent with the filename you specified for it. :dd
{Restart file is not a MPI-IO file} :dt
The file is inconsistent with the filename you specified for it. :dd
{Restart file is not a multi-proc file} :dt
The file is inconsistent with the filename you specified for it. :dd
{Restart variable returned a bad timestep} :dt
The variable must return a timestep greater than the current timestep. :dd
{Restrain atoms %d %d %d %d missing on proc %d at step %ld} :dt
The 4 atoms in a restrain dihedral specified by the fix restrain
command are not all accessible to a processor. This probably means an
atom has moved too far. :dd
{Restrain atoms %d %d %d missing on proc %d at step %ld} :dt
The 3 atoms in a restrain angle specified by the fix restrain
command are not all accessible to a processor. This probably means an
atom has moved too far. :dd
{Restrain atoms %d %d missing on proc %d at step %ld} :dt
The 2 atoms in a restrain bond specified by the fix restrain
command are not all accessible to a processor. This probably means an
atom has moved too far. :dd
{Reuse of compute ID} :dt
A compute ID cannot be used twice. :dd
{Reuse of dump ID} :dt
A dump ID cannot be used twice. :dd
{Reuse of molecule template ID} :dt
The template IDs must be unique. :dd
{Reuse of region ID} :dt
A region ID cannot be used twice. :dd
{Rigid body atoms %d %d missing on proc %d at step %ld} :dt
This means that an atom cannot find the atom that owns the rigid body
it is part of, or vice versa. The solution is to use the communicate
cutoff command to insure ghost atoms are acquired from far enough away
to encompass the max distance printed when the fix rigid/small command
was invoked. :dd
{Rigid body has degenerate moment of inertia} :dt
Fix poems will only work with bodies (collections of atoms) that have
non-zero principal moments of inertia. This means they must be 3 or
more non-collinear atoms, even with joint atoms removed. :dd
{Rigid fix must come before NPT/NPH fix} :dt
NPT/NPH fix must be defined in input script after all rigid fixes,
else the rigid fix contribution to the pressure virial is
incorrect. :dd
{Rmask function in equal-style variable formula} :dt
Rmask is per-atom operation. :dd
{Run command before simulation box is defined} :dt
The run command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Run command start value is after start of run} :dt
Self-explanatory. :dd
{Run command stop value is before end of run} :dt
Self-explanatory. :dd
{Run_style command before simulation box is defined} :dt
The run_style command cannot be used before a read_data,
read_restart, or create_box command. :dd
{SRD bin size for fix srd differs from user request} :dt
Fix SRD had to adjust the bin size to fit the simulation box. See the
cubic keyword if you want this message to be an error vs warning. :dd
{SRD bins for fix srd are not cubic enough} :dt
The bin shape is not within tolerance of cubic. See the cubic
keyword if you want this message to be an error vs warning. :dd
{SRD particle %d started inside big particle %d on step %ld bounce %d} :dt
See the inside keyword if you want this message to be an error vs
warning. :dd
{SRD particle %d started inside wall %d on step %ld bounce %d} :dt
See the inside keyword if you want this message to be an error vs
warning. :dd
{Same dimension twice in fix ave/spatial} :dt
Self-explanatory. :dd
{Sending partition in processors part command is already a sender} :dt
Cannot specify a partition to be a sender twice. :dd
{Set command before simulation box is defined} :dt
The set command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Set command floating point vector does not exist} :dt
Self-explanatory. :dd
{Set command integer vector does not exist} :dt
Self-explanatory. :dd
{Set command with no atoms existing} :dt
No atoms are yet defined so the set command cannot be used. :dd
{Set region ID does not exist} :dt
Region ID specified in set command does not exist. :dd
{Shake angles have different bond types} :dt
All 3-atom angle-constrained SHAKE clusters specified by the fix shake
command that are the same angle type, must also have the same bond
types for the 2 bonds in the angle. :dd
{Shake atoms %d %d %d %d missing on proc %d at step %ld} :dt
The 4 atoms in a single shake cluster specified by the fix shake
command are not all accessible to a processor. This probably means
an atom has moved too far. :dd
{Shake atoms %d %d %d missing on proc %d at step %ld} :dt
The 3 atoms in a single shake cluster specified by the fix shake
command are not all accessible to a processor. This probably means
an atom has moved too far. :dd
{Shake atoms %d %d missing on proc %d at step %ld} :dt
The 2 atoms in a single shake cluster specified by the fix shake
command are not all accessible to a processor. This probably means
an atom has moved too far. :dd
{Shake cluster of more than 4 atoms} :dt
A single cluster specified by the fix shake command can have no more
than 4 atoms. :dd
{Shake clusters are connected} :dt
A single cluster specified by the fix shake command must have a single
central atom with up to 3 other atoms bonded to it. :dd
{Shake determinant = 0.0} :dt
The determinant of the matrix being solved for a single cluster
specified by the fix shake command is numerically invalid. :dd
{Shake fix must come before NPT/NPH fix} :dt
NPT fix must be defined in input script after SHAKE fix, else the
SHAKE fix contribution to the pressure virial is incorrect. :dd
{Shear history overflow, boost neigh_modify one} :dt
There are too many neighbors of a single atom. Use the neigh_modify
command to increase the max number of neighbors allowed for one atom.
You may also want to boost the page size. :dd
{Small to big integers are not sized correctly} :dt
This error occurs whenthe sizes of smallint, imageint, tagint, bigint,
as defined in src/lmptype.h are not what is expected. Contact
the developers if this occurs. :dd
{Smallint setting in lmptype.h is invalid} :dt
It has to be the size of an integer. :dd
{Smallint setting in lmptype.h is not compatible} :dt
Smallint stored in restart file is not consistent with LAMMPS version
you are running. :dd
{Special list size exceeded in fix bond/create} :dt
See the special_bonds extra command
(or the read_data extra/special/per/atom command)
for info on how to leave space in the special bonds
list to allow for additional bonds to be formed. :dd
{Specified processors != physical processors} :dt
The 3d grid of processors defined by the processors command does not
match the number of processors LAMMPS is being run on. :dd
{Specified target stress must be uniaxial or hydrostatic} :dt
Self-explanatory. :dd
{Sqrt of negative value in variable formula} :dt
Self-explanatory. :dd
{Subsequent read data induced too many angles per atom} :dt
See the extra/angle/per/atom keyword for the create_box
or the read_data command to set this limit larger :dd
{Subsequent read data induced too many bonds per atom} :dt
See the extra/bond/per/atom keyword for the create_box
or the read_data command to set this limit larger :dd
{Subsequent read data induced too many dihedrals per atom} :dt
See the extra/dihedral/per/atom keyword for the create_box
or the read_data command to set this limit larger :dd
{Subsequent read data induced too many impropers per atom} :dt
See the extra/improper/per/atom keyword for the create_box
or the read_data command to set this limit larger :dd
{Substitution for illegal variable} :dt
Input script line contained a variable that could not be substituted
for. :dd
{Support for writing images in JPEG format not included} :dt
LAMMPS was not built with the -DLAMMPS_JPEG switch in the Makefile. :dd
{Support for writing images in PNG format not included} :dt
LAMMPS was not built with the -DLAMMPS_PNG switch in the Makefile. :dd
{Support for writing movies not included} :dt
LAMMPS was not built with the -DLAMMPS_FFMPEG switch in the Makefile :dd
{System in data file is too big} :dt
See the setting for bigint in the src/lmptype.h file. :dd
{System is not charge neutral, net charge = %g} :dt
The total charge on all atoms on the system is not 0.0.
For some KSpace solvers this is an error. :dd
{TAD nsteps must be multiple of t_event} :dt
Self-explanatory. :dd
{TIP4P hydrogen has incorrect atom type} :dt
The TIP4P pairwise computation found an H atom whose type does not
agree with the specified H type. :dd
{TIP4P hydrogen is missing} :dt
The TIP4P pairwise computation failed to find the correct H atom
within a water molecule. :dd
{TMD target file did not list all group atoms} :dt
The target file for the fix tmd command did not list all atoms in the
fix group. :dd
{Tad command before simulation box is defined} :dt
Self-explanatory. :dd
{Tagint setting in lmptype.h is invalid} :dt
Tagint must be as large or larger than smallint. :dd
{Tagint setting in lmptype.h is not compatible} :dt
Format of tagint stored in restart file is not consistent with LAMMPS
version you are running. See the settings in src/lmptype.h :dd
{Target pressure for fix rigid/nph cannot be < 0.0} :dt
Self-explanatory. :dd
{Target pressure for fix rigid/npt/small cannot be < 0.0} :dt
Self-explanatory. :dd
{Target temperature for fix nvt/npt/nph cannot be 0.0} :dt
Self-explanatory. :dd
{Target temperature for fix rigid/npt cannot be 0.0} :dt
Self-explanatory. :dd
{Target temperature for fix rigid/npt/small cannot be 0.0} :dt
Self-explanatory. :dd
{Target temperature for fix rigid/nvt cannot be 0.0} :dt
Self-explanatory. :dd
{Target temperature for fix rigid/nvt/small cannot be 0.0} :dt
Self-explanatory. :dd
{Temper command before simulation box is defined} :dt
The temper command cannot be used before a read_data, read_restart, or
create_box command. :dd
{Temperature ID for fix bond/swap does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix box/relax does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix nvt/npt does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix press/berendsen does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix rigid nvt/npt/nph does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix temp/berendsen does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix temp/csld does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix temp/csvr does not exist} :dt
Self-explanatory. :dd
{Temperature ID for fix temp/rescale does not exist} :dt
Self-explanatory. :dd
{Temperature compute degrees of freedom < 0} :dt
This should not happen if you are calculating the temperature
on a valid set of atoms. :dd
{Temperature control can not be used with fix nph} :dt
Self-explanatory. :dd
{Temperature control can not be used with fix nph/asphere} :dt
Self-explanatory. :dd
{Temperature control can not be used with fix nph/body} :dt
Self-explanatory. :dd
{Temperature control can not be used with fix nph/sphere} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nphug} :dt
The temp keyword must be provided. :dd
{Temperature control must be used with fix npt} :dt
Self-explanatory. :dd
{Temperature control must be used with fix npt/asphere} :dt
Self-explanatory. :dd
{Temperature control must be used with fix npt/body} :dt
Self-explanatory. :dd
{Temperature control must be used with fix npt/sphere} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nvt} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nvt/asphere} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nvt/body} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nvt/sllod} :dt
Self-explanatory. :dd
{Temperature control must be used with fix nvt/sphere} :dt
Self-explanatory. :dd
{Temperature control must not be used with fix nph/small} :dt
Self-explanatory. :dd
{Temperature for fix nvt/sllod does not have a bias} :dt
The specified compute must compute temperature with a bias. :dd
{Tempering could not find thermo_pe compute} :dt
This compute is created by the thermo command. It must have been
explicitly deleted by a uncompute command. :dd
{Tempering fix ID is not defined} :dt
The fix ID specified by the temper command does not exist. :dd
{Tempering temperature fix is not valid} :dt
The fix specified by the temper command is not one that controls
temperature (nvt or langevin). :dd
{Test_descriptor_string already allocated} :dt
This is an internal error. Contact the developers. :dd
{The package gpu command is required for gpu styles} :dt
Self-explanatory. :dd
{Thermo and fix not computed at compatible times} :dt
Fixes generate values on specific timesteps. The thermo output
does not match these timesteps. :dd
{Thermo compute array is accessed out-of-range} :dt
Self-explanatory. :dd
{Thermo compute does not compute array} :dt
Self-explanatory. :dd
{Thermo compute does not compute scalar} :dt
Self-explanatory. :dd
{Thermo compute does not compute vector} :dt
Self-explanatory. :dd
{Thermo compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Thermo custom variable cannot be indexed} :dt
Self-explanatory. :dd
{Thermo custom variable is not equal-style variable} :dt
Only equal-style variables can be output with thermodynamics, not
atom-style variables. :dd
{Thermo every variable returned a bad timestep} :dt
The variable must return a timestep greater than the current timestep. :dd
{Thermo fix array is accessed out-of-range} :dt
Self-explanatory. :dd
{Thermo fix does not compute array} :dt
Self-explanatory. :dd
{Thermo fix does not compute scalar} :dt
Self-explanatory. :dd
{Thermo fix does not compute vector} :dt
Self-explanatory. :dd
{Thermo fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Thermo keyword in variable requires thermo to use/init pe} :dt
You are using a thermo keyword in a variable that requires
potential energy to be calculated, but your thermo output
does not use it. Add it to your thermo output. :dd
{Thermo keyword in variable requires thermo to use/init press} :dt
You are using a thermo keyword in a variable that requires pressure to
be calculated, but your thermo output does not use it. Add it to your
thermo output. :dd
{Thermo keyword in variable requires thermo to use/init temp} :dt
You are using a thermo keyword in a variable that requires temperature
to be calculated, but your thermo output does not use it. Add it to
your thermo output. :dd
{Thermo style does not use press} :dt
Cannot use thermo_modify to set this parameter since the thermo_style
is not computing this quantity. :dd
{Thermo style does not use temp} :dt
Cannot use thermo_modify to set this parameter since the thermo_style
is not computing this quantity. :dd
{Thermo_modify every variable returned a bad timestep} :dt
The returned timestep is less than or equal to the current timestep. :dd
{Thermo_modify int format does not contain d character} :dt
Self-explanatory. :dd
{Thermo_modify pressure ID does not compute pressure} :dt
The specified compute ID does not compute pressure. :dd
{Thermo_modify temperature ID does not compute temperature} :dt
The specified compute ID does not compute temperature. :dd
{Thermo_style command before simulation box is defined} :dt
The thermo_style command cannot be used before a read_data,
read_restart, or create_box command. :dd
{This variable thermo keyword cannot be used between runs} :dt
Keywords that refer to time (such as cpu, elapsed) do not
make sense in between runs. :dd
{Threshhold for an atom property that isn't allocated} :dt
A dump threshold has been requested on a quantity that is
not defined by the atom style used in this simulation. :dd
{Timestep must be >= 0} :dt
Specified timestep is invalid. :dd
{Too big a problem to use velocity create loop all} :dt
The system size must fit in a 32-bit integer to use this option. :dd
{Too big a timestep for dump dcd} :dt
The timestep must fit in a 32-bit integer to use this dump style. :dd
{Too big a timestep for dump xtc} :dt
The timestep must fit in a 32-bit integer to use this dump style. :dd
{Too few bits for lookup table} :dt
Table size specified via pair_modify command does not work with your
machine's floating point representation. :dd
{Too few lines in %s section of data file} :dt
Self-explanatory. :dd
{Too few values in body lines in data file} :dt
Self-explanatory. :dd
{Too few values in body section of molecule file} :dt
Self-explanatory. :dd
{Too many -pk arguments in command line} :dt
The string formed by concatenating the arguments is too long. Use a
package command in the input script instead. :dd
{Too many MSM grid levels} :dt
The max number of MSM grid levels is hardwired to 10. :dd
{Too many args in variable function} :dt
More args are used than any variable function allows. :dd
{Too many atom pairs for pair bop} :dt
The number of atomic pairs exceeds the expected number. Check your
atomic structure to ensure that it is realistic. :dd
{Too many atom sorting bins} :dt
This is likely due to an immense simulation box that has blown up
to a large size. :dd
{Too many atom triplets for pair bop} :dt
The number of three atom groups for angle determinations exceeds the
expected number. Check your atomic structure to ensure that it is
realistic. :dd
{Too many atoms for dump dcd} :dt
The system size must fit in a 32-bit integer to use this dump
style. :dd
{Too many atoms for dump xtc} :dt
The system size must fit in a 32-bit integer to use this dump
style. :dd
{Too many atoms to dump sort} :dt
Cannot sort when running with more than 2^31 atoms. :dd
{Too many exponent bits for lookup table} :dt
Table size specified via pair_modify command does not work with your
machine's floating point representation. :dd
{Too many groups} :dt
The maximum number of atom groups (including the "all" group) is
given by MAX_GROUP in group.cpp and is 32. :dd
{Too many iterations} :dt
You must use a number of iterations that fit in a 32-bit integer
for minimization. :dd
{Too many lines in one body in data file - boost MAXBODY} :dt
MAXBODY is a setting at the top of the src/read_data.cpp file.
Set it larger and re-compile the code. :dd
{Too many local+ghost atoms for neighbor list} :dt
The number of nlocal + nghost atoms on a processor
is limited by the size of a 32-bit integer with 2 bits
removed for masking 1-2, 1-3, 1-4 neighbors. :dd
{Too many mantissa bits for lookup table} :dt
Table size specified via pair_modify command does not work with your
machine's floating point representation. :dd
{Too many masses for fix shake} :dt
The fix shake command cannot list more masses than there are atom
types. :dd
{Too many molecules for fix poems} :dt
The limit is 2^31 = ~2 billion molecules. :dd
{Too many molecules for fix rigid} :dt
The limit is 2^31 = ~2 billion molecules. :dd
{Too many neighbor bins} :dt
This is likely due to an immense simulation box that has blown up
to a large size. :dd
{Too many timesteps} :dt
The cumulative timesteps must fit in a 64-bit integer. :dd
{Too many timesteps for NEB} :dt
You must use a number of timesteps that fit in a 32-bit integer
for NEB. :dd
{Too many total atoms} :dt
See the setting for bigint in the src/lmptype.h file. :dd
{Too many total bits for bitmapped lookup table} :dt
Table size specified via pair_modify command is too large. Note that
a value of N generates a 2^N size table. :dd
{Too many values in body lines in data file} :dt
Self-explanatory. :dd
{Too many values in body section of molecule file} :dt
Self-explanatory. :dd
{Too much buffered per-proc info for dump} :dt
The size of the buffered string must fit in a 32-bit integer for a
dump. :dd
{Too much per-proc info for dump} :dt
Number of local atoms times number of columns must fit in a 32-bit
integer for dump. :dd
{Tree structure in joint connections} :dt
Fix poems cannot (yet) work with coupled bodies whose joints connect
the bodies in a tree structure. :dd
{Triclinic box skew is too large} :dt
The displacement in a skewed direction must be less than half the box
length in that dimension. E.g. the xy tilt must be between -half and
+half of the x box length. This constraint can be relaxed by using
the box tilt command. :dd
{Tried to convert a double to int, but input_double > INT_MAX} :dt
Self-explanatory. :dd
{Trying to build an occasional neighbor list before initialization completed} :dt
This is not allowed. Source code caller needs to be modified. :dd
{Two fix ave commands using same compute chunk/atom command in incompatible ways} :dt
They are both attempting to "lock" the chunk/atom command so that the
chunk assignments persist for some number of timesteps, but are doing
it in different ways. :dd
{Two groups cannot be the same in fix spring couple} :dt
Self-explanatory. :dd
{USER-CUDA mode requires CUDA variant of min style} :dt
CUDA mode is enabled, so the min style must include a cuda suffix. :dd
{USER-CUDA mode requires CUDA variant of run style} :dt
CUDA mode is enabled, so the run style must include a cuda suffix. :dd
{USER-CUDA package does not yet support comm_style tiled} :dt
Self-explanatory. :dd
{USER-CUDA package requires a cuda enabled atom_style} :dt
Self-explanatory. :dd
{Unable to initialize accelerator for use} :dt
There was a problem initializing an accelerator for the gpu package :dd
{Unbalanced quotes in input line} :dt
No matching end double quote was found following a leading double
quote. :dd
{Unexpected end of -reorder file} :dt
Self-explanatory. :dd
{Unexpected end of AngleCoeffs section} :dt
Read a blank line. :dd
{Unexpected end of BondCoeffs section} :dt
Read a blank line. :dd
{Unexpected end of DihedralCoeffs section} :dt
Read a blank line. :dd
{Unexpected end of ImproperCoeffs section} :dt
Read a blank line. :dd
{Unexpected end of PairCoeffs section} :dt
Read a blank line. :dd
{Unexpected end of custom file} :dt
Self-explanatory. :dd
{Unexpected end of data file} :dt
LAMMPS hit the end of the data file while attempting to read a
section. Something is wrong with the format of the data file. :dd
{Unexpected end of dump file} :dt
A read operation from the file failed. :dd
{Unexpected end of fix rigid file} :dt
A read operation from the file failed. :dd
{Unexpected end of fix rigid/small file} :dt
A read operation from the file failed. :dd
{Unexpected end of molecule file} :dt
Self-explanatory. :dd
{Unexpected end of neb file} :dt
A read operation from the file failed. :dd
{Units command after simulation box is defined} :dt
The units command cannot be used after a read_data, read_restart, or
create_box command. :dd
{Universe/uloop variable count < # of partitions} :dt
A universe or uloop style variable must specify a number of values >= to the
number of processor partitions. :dd
{Unknown angle style} :dt
The choice of angle style is unknown. :dd
{Unknown atom style} :dt
The choice of atom style is unknown. :dd
{Unknown body style} :dt
The choice of body style is unknown. :dd
{Unknown bond style} :dt
The choice of bond style is unknown. :dd
{Unknown category for info is_active()} :dt
Self-explanatory. :dd
{Unknown category for info is_available()} :dt
Self-explanatory. :dd
{Unknown category for info is_defined()} :dt
Self-explanatory. :dd
{Unknown command: %s} :dt
The command is not known to LAMMPS. Check the input script. :dd
{Unknown compute style} :dt
The choice of compute style is unknown. :dd
{Unknown dihedral style} :dt
The choice of dihedral style is unknown. :dd
{Unknown dump reader style} :dt
The choice of dump reader style via the format keyword is unknown. :dd
{Unknown dump style} :dt
The choice of dump style is unknown. :dd
{Unknown error in GPU library} :dt
Self-explanatory. :dd
{Unknown fix style} :dt
The choice of fix style is unknown. :dd
{Unknown identifier in data file: %s} :dt
A section of the data file cannot be read by LAMMPS. :dd
{Unknown improper style} :dt
The choice of improper style is unknown. :dd
{Unknown keyword in thermo_style custom command} :dt
One or more specified keywords are not recognized. :dd
{Unknown kspace style} :dt
The choice of kspace style is unknown. :dd
{Unknown name for info newton category} :dt
Self-explanatory. :dd
{Unknown name for info package category} :dt
Self-explanatory. :dd
{Unknown name for info pair category} :dt
Self-explanatory. :dd
{Unknown pair style} :dt
The choice of pair style is unknown. :dd
{Unknown pair_modify hybrid sub-style} :dt
The choice of sub-style is unknown. :dd
{Unknown region style} :dt
The choice of region style is unknown. :dd
{Unknown section in molecule file} :dt
Self-explanatory. :dd
{Unknown table style in angle style table} :dt
Self-explanatory. :dd
{Unknown table style in bond style table} :dt
Self-explanatory. :dd
{Unknown table style in pair_style command} :dt
Style of table is invalid for use with pair_style table command. :dd
{Unknown unit_style} :dt
Self-explanatory. Check the input script or data file. :dd
{Unrecognized lattice type in MEAM file 1} :dt
The lattice type in an entry of the MEAM library file is not
valid. :dd
{Unrecognized lattice type in MEAM file 2} :dt
The lattice type in an entry of the MEAM parameter file is not
valid. :dd
{Unrecognized pair style in compute pair command} :dt
Self-explanatory. :dd
{Unrecognized virial argument in pair_style command} :dt
Only two options are supported: LAMMPSvirial and KIMvirial :dd
{Unsupported mixing rule in kspace_style ewald/disp} :dt
Only geometric mixing is supported. :dd
{Unsupported order in kspace_style ewald/disp} :dt
Only 1/r^6 dispersion or dipole terms are supported. :dd
{Unsupported order in kspace_style pppm/disp, pair_style %s} :dt
Only pair styles with 1/r and 1/r^6 dependence are currently supported. :dd
{Use cutoff keyword to set cutoff in single mode} :dt
Mode is single so cutoff/multi keyword cannot be used. :dd
{Use cutoff/multi keyword to set cutoff in multi mode} :dt
Mode is multi so cutoff keyword cannot be used. :dd
{Using fix nvt/sllod with inconsistent fix deform remap option} :dt
Fix nvt/sllod requires that deforming atoms have a velocity profile
provided by "remap v" as a fix deform option. :dd
{Using fix nvt/sllod with no fix deform defined} :dt
Self-explanatory. :dd
{Using fix srd with inconsistent fix deform remap option} :dt
When shearing the box in an SRD simulation, the remap v option for fix
deform needs to be used. :dd
{Using pair lubricate with inconsistent fix deform remap option} :dt
Must use remap v option with fix deform with this pair style. :dd
{Using pair lubricate/poly with inconsistent fix deform remap option} :dt
If fix deform is used, the remap v option is required. :dd
{Using suffix cuda without USER-CUDA package enabled} :dt
Self-explanatory. :dd
{Using suffix gpu without GPU package installed} :dt
Self-explanatory. :dd
{Using suffix intel without USER-INTEL package installed} :dt
Self-explanatory. :dd
{Using suffix kk without KOKKOS package enabled} :dt
Self-explanatory. :dd
{Using suffix omp without USER-OMP package installed} :dt
Self-explanatory. :dd
{Using update dipole flag requires atom attribute mu} :dt
Self-explanatory. :dd
{Using update dipole flag requires atom style sphere} :dt
Self-explanatory. :dd
{Variable ID in variable formula does not exist} :dt
Self-explanatory. :dd
{Variable atom ID is too large} :dt
Specified ID is larger than the maximum allowed atom ID. :dd
{Variable evaluation before simulation box is defined} :dt
Cannot evaluate a compute or fix or atom-based value in a variable
before the simulation has been setup. :dd
{Variable evaluation in fix wall gave bad value} :dt
The returned value for epsilon or sigma < 0.0. :dd
{Variable evaluation in region gave bad value} :dt
Variable returned a radius < 0.0. :dd
{Variable for compute ti is invalid style} :dt
Self-explanatory. :dd
{Variable for create_atoms is invalid style} :dt
The variables must be equal-style variables. :dd
{Variable for displace_atoms is invalid style} :dt
It must be an equal-style or atom-style variable. :dd
{Variable for dump every is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for dump image center is invalid style} :dt
Must be an equal-style variable. :dd
{Variable for dump image persp is invalid style} :dt
Must be an equal-style variable. :dd
{Variable for dump image phi is invalid style} :dt
Must be an equal-style variable. :dd
{Variable for dump image theta is invalid style} :dt
Must be an equal-style variable. :dd
{Variable for dump image zoom is invalid style} :dt
Must be an equal-style variable. :dd
{Variable for fix adapt is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix addforce is invalid style} :dt
Self-explanatory. :dd
{Variable for fix aveforce is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix deform is invalid style} :dt
The variable must be an equal-style variable. :dd
{Variable for fix efield is invalid style} :dt
The variable must be an equal- or atom-style variable. :dd
{Variable for fix gravity is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix heat is invalid style} :dt
Only equal-style or atom-style variables can be used. :dd
{Variable for fix indent is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix indent is not equal style} :dt
Only equal-style variables can be used. :dd
{Variable for fix langevin is invalid style} :dt
It must be an equal-style variable. :dd
{Variable for fix move is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix setforce is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix temp/berendsen is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix temp/csld is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix temp/csvr is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix temp/rescale is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix wall is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix wall/reflect is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for fix wall/srd is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for group dynamic is invalid style} :dt
The variable must be an atom-style variable. :dd
{Variable for group is invalid style} :dt
Only atom-style variables can be used. :dd
{Variable for region cylinder is invalid style} :dt
Only equal-style variables are allowed. :dd
{Variable for region is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for region is not equal style} :dt
Self-explanatory. :dd
{Variable for region sphere is invalid style} :dt
Only equal-style variables are allowed. :dd
{Variable for restart is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for set command is invalid style} :dt
Only atom-style variables can be used. :dd
{Variable for thermo every is invalid style} :dt
Only equal-style variables can be used. :dd
{Variable for velocity set is invalid style} :dt
Only atom-style variables can be used. :dd
{Variable for voronoi radius is not atom style} :dt
Self-explanatory. :dd
{Variable formula compute array is accessed out-of-range} :dt
Self-explanatory. :dd
{Variable formula compute vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Variable formula fix array is accessed out-of-range} :dt
Self-explanatory. :dd
{Variable formula fix vector is accessed out-of-range} :dt
Self-explanatory. :dd
{Variable has circular dependency} :dt
A circular dependency is when variable "a" in used by variable "b" and
variable "b" is also used by variable "a". Circular dependencies with
longer chains of dependence are also not allowed. :dd
{Variable name between brackets must be alphanumeric or underscore characters} :dt
Self-explanatory. :dd
{Variable name for compute chunk/atom does not exist} :dt
Self-explanatory. :dd
{Variable name for compute reduce does not exist} :dt
Self-explanatory. :dd
{Variable name for compute ti does not exist} :dt
Self-explanatory. :dd
{Variable name for create_atoms does not exist} :dt
Self-explanatory. :dd
{Variable name for displace_atoms does not exist} :dt
Self-explanatory. :dd
{Variable name for dump every does not exist} :dt
Self-explanatory. :dd
{Variable name for dump image center does not exist} :dt
Self-explanatory. :dd
{Variable name for dump image persp does not exist} :dt
Self-explanatory. :dd
{Variable name for dump image phi does not exist} :dt
Self-explanatory. :dd
{Variable name for dump image theta does not exist} :dt
Self-explanatory. :dd
{Variable name for dump image zoom does not exist} :dt
Self-explanatory. :dd
{Variable name for fix adapt does not exist} :dt
Self-explanatory. :dd
{Variable name for fix addforce does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/atom does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/chunk does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/correlate does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/histo does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/spatial does not exist} :dt
Self-explanatory. :dd
{Variable name for fix ave/time does not exist} :dt
Self-explanatory. :dd
{Variable name for fix aveforce does not exist} :dt
Self-explanatory. :dd
{Variable name for fix deform does not exist} :dt
Self-explanatory. :dd
{Variable name for fix efield does not exist} :dt
Self-explanatory. :dd
{Variable name for fix gravity does not exist} :dt
Self-explanatory. :dd
{Variable name for fix heat does not exist} :dt
Self-explanatory. :dd
{Variable name for fix indent does not exist} :dt
Self-explanatory. :dd
{Variable name for fix langevin does not exist} :dt
Self-explanatory. :dd
{Variable name for fix move does not exist} :dt
Self-explanatory. :dd
{Variable name for fix setforce does not exist} :dt
Self-explanatory. :dd
{Variable name for fix store/state does not exist} :dt
Self-explanatory. :dd
{Variable name for fix temp/berendsen does not exist} :dt
Self-explanatory. :dd
{Variable name for fix temp/csld does not exist} :dt
Self-explanatory. :dd
{Variable name for fix temp/csvr does not exist} :dt
Self-explanatory. :dd
{Variable name for fix temp/rescale does not exist} :dt
Self-explanatory. :dd
{Variable name for fix vector does not exist} :dt
Self-explanatory. :dd
{Variable name for fix wall does not exist} :dt
Self-explanatory. :dd
{Variable name for fix wall/reflect does not exist} :dt
Self-explanatory. :dd
{Variable name for fix wall/srd does not exist} :dt
Self-explanatory. :dd
{Variable name for group does not exist} :dt
Self-explanatory. :dd
{Variable name for group dynamic does not exist} :dt
Self-explanatory. :dd
{Variable name for region cylinder does not exist} :dt
Self-explanatory. :dd
{Variable name for region does not exist} :dt
Self-explanatory. :dd
{Variable name for region sphere does not exist} :dt
Self-explanatory. :dd
{Variable name for restart does not exist} :dt
Self-explanatory. :dd
{Variable name for set command does not exist} :dt
Self-explanatory. :dd
{Variable name for thermo every does not exist} :dt
Self-explanatory. :dd
{Variable name for velocity set does not exist} :dt
Self-explanatory. :dd
{Variable name for voronoi radius does not exist} :dt
Self-explanatory. :dd
{Variable name must be alphanumeric or underscore characters} :dt
Self-explanatory. :dd
{Variable uses atom property that isn't allocated} :dt
Self-explanatory. :dd
{Velocity command before simulation box is defined} :dt
The velocity command cannot be used before a read_data, read_restart,
or create_box command. :dd
{Velocity command with no atoms existing} :dt
A velocity command has been used, but no atoms yet exist. :dd
{Velocity ramp in z for a 2d problem} :dt
Self-explanatory. :dd
{Velocity rigid used with non-rigid fix-ID} :dt
Self-explanatory. :dd
{Velocity temperature ID does calculate a velocity bias} :dt
The specified compute must compute a bias for temperature. :dd
{Velocity temperature ID does not compute temperature} :dt
The compute ID given to the velocity command must compute
temperature. :dd
{Verlet/split can only currently be used with comm_style brick} :dt
This is a current restriction in LAMMPS. :dd
{Verlet/split does not yet support TIP4P} :dt
This is a current limitation. :dd
{Verlet/split requires 2 partitions} :dt
See the -partition command-line switch. :dd
{Verlet/split requires Rspace partition layout be multiple of Kspace partition layout in each dim} :dt
This is controlled by the processors command. :dd
{Verlet/split requires Rspace partition size be multiple of Kspace partition size} :dt
This is so there is an equal number of Rspace processors for every
Kspace processor. :dd
{Virial was not tallied on needed timestep} :dt
You are using a thermo keyword that requires potentials to
have tallied the virial, but they didn't on this timestep. See the
variable doc page for ideas on how to make this work. :dd
{Voro++ error: narea and neigh have a different size} :dt
This error is returned by the Voro++ library. :dd
{Wall defined twice in fix wall command} :dt
Self-explanatory. :dd
{Wall defined twice in fix wall/reflect command} :dt
Self-explanatory. :dd
{Wall defined twice in fix wall/srd command} :dt
Self-explanatory. :dd
{Water H epsilon must be 0.0 for pair style lj/cut/tip4p/cut} :dt
This is because LAMMPS does not compute the Lennard-Jones interactions
with these particles for efficiency reasons. :dd
{Water H epsilon must be 0.0 for pair style lj/cut/tip4p/long} :dt
This is because LAMMPS does not compute the Lennard-Jones interactions
with these particles for efficiency reasons. :dd
{Water H epsilon must be 0.0 for pair style lj/long/tip4p/long} :dt
This is because LAMMPS does not compute the Lennard-Jones interactions
with these particles for efficiency reasons. :dd
{World variable count doesn't match # of partitions} :dt
A world-style variable must specify a number of values equal to the
number of processor partitions. :dd
{Write_data command before simulation box is defined} :dt
Self-explanatory. :dd
{Write_restart command before simulation box is defined} :dt
The write_restart command cannot be used before a read_data,
read_restart, or create_box command. :dd
{Writing to MPI-IO filename when MPIIO package is not installed} :dt
Self-explanatory. :dd
{Zero length rotation vector with displace_atoms} :dt
Self-explanatory. :dd
{Zero length rotation vector with fix move} :dt
Self-explanatory. :dd
{Zero-length lattice orient vector} :dt
Self-explanatory. :dd
:dle
Warnings: :h4,link(warn)
:dlb
{Adjusting Coulombic cutoff for MSM, new cutoff = %g} :dt
The adjust/cutoff command is turned on and the Coulombic cutoff has been
adjusted to match the user-specified accuracy. :dd
{Angle atoms missing at step %ld} :dt
One or more of 3 atoms needed to compute a particular angle are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the angle has blown apart and an atom is
too far away. :dd
{Angle style in data file differs from currently defined angle style} :dt
Self-explanatory. :dd
{Atom style in data file differs from currently defined atom style} :dt
Self-explanatory. :dd
{Bond atom missing in box size check} :dt
The 2nd atoms needed to compute a particular bond is missing on this
processor. Typically this is because the pairwise cutoff is set too
short or the bond has blown apart and an atom is too far away. :dd
{Bond atom missing in image check} :dt
The 2nd atom in a particular bond is missing on this processor.
Typically this is because the pairwise cutoff is set too short or the
bond has blown apart and an atom is too far away. :dd
{Bond atoms missing at step %ld} :dt
The 2nd atom needed to compute a particular bond is missing on this
processor. Typically this is because the pairwise cutoff is set too
short or the bond has blown apart and an atom is too far away. :dd
{Bond style in data file differs from currently defined bond style} :dt
Self-explanatory. :dd
{Bond/angle/dihedral extent > half of periodic box length} :dt
This is a restriction because LAMMPS can be confused about which image
of an atom in the bonded interaction is the correct one to use.
"Extent" in this context means the maximum end-to-end length of the
bond/angle/dihedral. LAMMPS computes this by taking the maximum bond
length, multiplying by the number of bonds in the interaction (e.g. 3
for a dihedral) and adding a small amount of stretch. :dd
{Both groups in compute group/group have a net charge; the Kspace boundary correction to energy will be non-zero} :dt
Self-explanatory. :dd
{Calling write_dump before a full system init.} :dt
The write_dump command is used before the system has been fully
initialized as part of a 'run' or 'minimize' command. Not all dump
styles and features are fully supported at this point and thus the
command may fail or produce incomplete or incorrect output. Insert
a "run 0" command, if a full system init is required. :dd
{Cannot count rigid body degrees-of-freedom before bodies are fully initialized} :dt
This means the temperature associated with the rigid bodies may be
incorrect on this timestep. :dd
{Cannot count rigid body degrees-of-freedom before bodies are initialized} :dt
This means the temperature associated with the rigid bodies may be
incorrect on this timestep. :dd
{Cannot include log terms without 1/r terms; setting flagHI to 1} :dt
Self-explanatory. :dd
{Cannot include log terms without 1/r terms; setting flagHI to 1.} :dt
Self-explanatory. :dd
{Charges are set, but coulombic solver is not used} :dt
Self-explanatory. :dd
{Charges did not converge at step %ld: %lg} :dt
Self-explanatory. :dd
{Communication cutoff is too small for SNAP micro load balancing, increased to %lf} :dt
Self-explanatory. :dd
{Compute cna/atom cutoff may be too large to find ghost atom neighbors} :dt
The neighbor cutoff used may not encompass enough ghost atoms
to perform this operation correctly. :dd
{Computing temperature of portions of rigid bodies} :dt
The group defined by the temperature compute does not encompass all
the atoms in one or more rigid bodies, so the change in
degrees-of-freedom for the atoms in those partial rigid bodies will
not be accounted for. :dd
{Create_bonds max distance > minimum neighbor cutoff} :dt
This means atom pairs for some atom types may not be in the neighbor
list and thus no bond can be created between them. :dd
{Delete_atoms cutoff > minimum neighbor cutoff} :dt
This means atom pairs for some atom types may not be in the neighbor
list and thus an atom in that pair cannot be deleted. :dd
{Dihedral atoms missing at step %ld} :dt
One or more of 4 atoms needed to compute a particular dihedral are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the dihedral has blown apart and an atom is
too far away. :dd
{Dihedral problem} :dt
Conformation of the 4 listed dihedral atoms is extreme; you may want
to check your simulation geometry. :dd
{Dihedral problem: %d %ld %d %d %d %d} :dt
Conformation of the 4 listed dihedral atoms is extreme; you may want
to check your simulation geometry. :dd
{Dihedral style in data file differs from currently defined dihedral style} :dt
Self-explanatory. :dd
{Dump dcd/xtc timestamp may be wrong with fix dt/reset} :dt
If the fix changes the timestep, the dump dcd file will not
reflect the change. :dd
{Energy due to X extra global DOFs will be included in minimizer energies} :dt
When using fixes like box/relax, the potential energy used by the minimizer
is augmented by an additional energy provided by the fix. Thus the printed
converged energy may be different from the total potential energy. :dd
{Energy tally does not account for 'zero yes'} :dt
The energy removed by using the 'zero yes' flag is not accounted
for in the energy tally and thus energy conservation cannot be
monitored in this case. :dd
{Estimated error in splitting of dispersion coeffs is %g} :dt
Error is greater than 0.0001 percent. :dd
{Ewald/disp Newton solver failed, using old method to estimate g_ewald} :dt
Self-explanatory. Choosing a different cutoff value may help. :dd
{FENE bond too long} :dt
A FENE bond has stretched dangerously far. It's interaction strength
will be truncated to attempt to prevent the bond from blowing up. :dd
{FENE bond too long: %ld %d %d %g} :dt
A FENE bond has stretched dangerously far. It's interaction strength
will be truncated to attempt to prevent the bond from blowing up. :dd
{FENE bond too long: %ld %g} :dt
A FENE bond has stretched dangerously far. It's interaction strength
will be truncated to attempt to prevent the bond from blowing up. :dd
{Fix SRD walls overlap but fix srd overlap not set} :dt
You likely want to set this in your input script. :dd
{Fix bond/swap will ignore defined angles} :dt
See the doc page for fix bond/swap for more info on this
restriction. :dd
{Fix deposit near setting < possible overlap separation %g} :dt
This test is performed for finite size particles with a diameter, not
for point particles. The near setting is smaller than the particle
diameter which can lead to overlaps. :dd
{Fix evaporate may delete atom with non-zero molecule ID} :dt
This is probably an error, since you should not delete only one atom
of a molecule. :dd
{Fix gcmc using full_energy option} :dt
Fix gcmc has automatically turned on the full_energy option since it
is required for systems like the one specified by the user. User input
included one or more of the following: kspace, triclinic, a hybrid
pair style, an eam pair style, or no "single" function for the pair
style. :dd
{Fix property/atom mol or charge w/out ghost communication} :dt
A model typically needs these properties defined for ghost atoms. :dd
{Fix qeq CG convergence failed (%g) after %d iterations at %ld step} :dt
Self-explanatory. :dd
{Fix qeq has non-zero lower Taper radius cutoff} :dt
Absolute value must be <= 0.01. :dd
{Fix qeq has very low Taper radius cutoff} :dt
Value should typically be >= 5.0. :dd
{Fix qeq/dynamic tolerance may be too small for damped dynamics} :dt
Self-explanatory. :dd
{Fix qeq/fire tolerance may be too small for damped fires} :dt
Self-explanatory. :dd
{Fix rattle should come after all other integration fixes} :dt
This fix is designed to work after all other integration fixes change
atom positions. Thus it should be the last integration fix specified.
If not, it will not satisfy the desired constraints as well as it
otherwise would. :dd
{Fix recenter should come after all other integration fixes} :dt
Other fixes may change the position of the center-of-mass, so
fix recenter should come last. :dd
{Fix srd SRD moves may trigger frequent reneighboring} :dt
This is because the SRD particles may move long distances. :dd
{Fix srd grid size > 1/4 of big particle diameter} :dt
This may cause accuracy problems. :dd
{Fix srd particle moved outside valid domain} :dt
This may indicate a problem with your simulation parameters. :dd
{Fix srd particles may move > big particle diameter} :dt
This may cause accuracy problems. :dd
{Fix srd viscosity < 0.0 due to low SRD density} :dt
This may cause accuracy problems. :dd
{Fix thermal/conductivity comes before fix ave/spatial} :dt
The order of these 2 fixes in your input script is such that fix
thermal/conductivity comes first. If you are using fix ave/spatial to
measure the temperature profile induced by fix viscosity, then this
may cause a glitch in the profile since you are averaging immediately
after swaps have occurred. Flipping the order of the 2 fixes
typically helps. :dd
{Fix viscosity comes before fix ave/spatial} :dt
The order of these 2 fixes in your input script is such that
fix viscosity comes first. If you are using fix ave/spatial
to measure the velocity profile induced by fix viscosity, then
this may cause a glitch in the profile since you are averaging
immediately after swaps have occurred. Flipping the order
of the 2 fixes typically helps. :dd
{Fixes cannot send data in Kokkos communication, switching to classic communication} :dt
This is current restriction with Kokkos. :dd
{For better accuracy use 'pair_modify table 0'} :dt
The user-specified force accuracy cannot be achieved unless the table
feature is disabled by using 'pair_modify table 0'. :dd
{Geometric mixing assumed for 1/r^6 coefficients} :dt
Self-explanatory. :dd
{Group for fix_modify temp != fix group} :dt
The fix_modify command is specifying a temperature computation that
computes a temperature on a different group of atoms than the fix
itself operates on. This is probably not what you want to do. :dd
{H matrix size has been exceeded: m_fill=%d H.m=%d\n} :dt
This is the size of the matrix. :dd
{Ignoring unknown or incorrect info command flag} :dt
Self-explanatory. An unknown argument was given to the info command.
Compare your input with the documentation. :dd
{Improper atoms missing at step %ld} :dt
One or more of 4 atoms needed to compute a particular improper are
missing on this processor. Typically this is because the pairwise
cutoff is set too short or the improper has blown apart and an atom is
too far away. :dd
{Improper problem: %d %ld %d %d %d %d} :dt
Conformation of the 4 listed improper atoms is extreme; you may want
to check your simulation geometry. :dd
{Improper style in data file differs from currently defined improper style} :dt
Self-explanatory. :dd
{Inconsistent image flags} :dt
The image flags for a pair on bonded atoms appear to be inconsistent.
Inconsistent means that when the coordinates of the two atoms are
unwrapped using the image flags, the two atoms are far apart.
Specifically they are further apart than half a periodic box length.
Or they are more than a box length apart in a non-periodic dimension.
This is usually due to the initial data file not having correct image
flags for the 2 atoms in a bond that straddles a periodic boundary.
They should be different by 1 in that case. This is a warning because
inconsistent image flags will not cause problems for dynamics or most
LAMMPS simulations. However they can cause problems when such atoms
are used with the fix rigid or replicate commands. Note that if you
have an infinite periodic crystal with bonds then it is impossible to
have fully consistent image flags, since some bonds will cross
periodic boundaries and connect two atoms with the same image
flag. :dd
{KIM Model does not provide 'energy'; Potential energy will be zero} :dt
Self-explanatory. :dd
{KIM Model does not provide 'forces'; Forces will be zero} :dt
Self-explanatory. :dd
{KIM Model does not provide 'particleEnergy'; energy per atom will be zero} :dt
Self-explanatory. :dd
{KIM Model does not provide 'particleVirial'; virial per atom will be zero} :dt
Self-explanatory. :dd
{Kspace_modify slab param < 2.0 may cause unphysical behavior} :dt
The kspace_modify slab parameter should be larger to insure periodic
grids padded with empty space do not overlap. :dd
{Less insertions than requested} :dt
The fix pour command was unsuccessful at finding open space
for as many particles as it tried to insert. :dd
{Library error in lammps_gather_atoms} :dt
This library function cannot be used if atom IDs are not defined
or are not consecutively numbered. :dd
{Library error in lammps_scatter_atoms} :dt
This library function cannot be used if atom IDs are not defined or
are not consecutively numbered, or if no atom map is defined. See the
atom_modify command for details about atom maps. :dd
{Lost atoms via change_box: original %ld current %ld} :dt
The command options you have used caused atoms to be lost. :dd
{Lost atoms via displace_atoms: original %ld current %ld} :dt
The command options you have used caused atoms to be lost. :dd
{Lost atoms: original %ld current %ld} :dt
Lost atoms are checked for each time thermo output is done. See the
thermo_modify lost command for options. Lost atoms usually indicate
bad dynamics, e.g. atoms have been blown far out of the simulation
box, or moved further than one processor's sub-domain away before
reneighboring. :dd
{MSM mesh too small, increasing to 2 points in each direction} :dt
Self-explanatory. :dd
{Mismatch between velocity and compute groups} :dt
The temperature computation used by the velocity command will not be
on the same group of atoms that velocities are being set for. :dd
{Mixing forced for lj coefficients} :dt
Self-explanatory. :dd
{Molecule attributes do not match system attributes} :dt
An attribute is specified (e.g. diameter, charge) that is
not defined for the specified atom style. :dd
{Molecule has bond topology but no special bond settings} :dt
This means the bonded atoms will not be excluded in pair-wise
interactions. :dd
{Molecule template for create_atoms has multiple molecules} :dt
The create_atoms command will only create molecules of a single type,
i.e. the first molecule in the template. :dd
{Molecule template for fix gcmc has multiple molecules} :dt
The fix gcmc command will only create molecules of a single type,
i.e. the first molecule in the template. :dd
{Molecule template for fix shake has multiple molecules} :dt
The fix shake command will only recognize molecules of a single
type, i.e. the first molecule in the template. :dd
{More than one compute centro/atom} :dt
It is not efficient to use compute centro/atom more than once. :dd
{More than one compute cluster/atom} :dt
It is not efficient to use compute cluster/atom more than once. :dd
{More than one compute cna/atom defined} :dt
It is not efficient to use compute cna/atom more than once. :dd
{More than one compute contact/atom} :dt
It is not efficient to use compute contact/atom more than once. :dd
{More than one compute coord/atom} :dt
It is not efficient to use compute coord/atom more than once. :dd
{More than one compute damage/atom} :dt
It is not efficient to use compute ke/atom more than once. :dd
{More than one compute dilatation/atom} :dt
Self-explanatory. :dd
{More than one compute erotate/sphere/atom} :dt
It is not efficient to use compute erorate/sphere/atom more than once. :dd
{More than one compute hexorder/atom} :dt
It is not efficient to use compute hexorder/atom more than once. :dd
{More than one compute ke/atom} :dt
It is not efficient to use compute ke/atom more than once. :dd
{More than one compute orientorder/atom} :dt
It is not efficient to use compute orientorder/atom more than once. :dd
{More than one compute plasticity/atom} :dt
Self-explanatory. :dd
{More than one compute sna/atom} :dt
Self-explanatory. :dd
{More than one compute snad/atom} :dt
Self-explanatory. :dd
{More than one compute snav/atom} :dt
Self-explanatory. :dd
{More than one fix poems} :dt
It is not efficient to use fix poems more than once. :dd
{More than one fix rigid} :dt
It is not efficient to use fix rigid more than once. :dd
{Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies} :dt
This is because excluding specific pair interactions also excludes
them from long-range interactions which may not be the desired effect.
The special_bonds command handles this consistently by insuring
excluded (or weighted) 1-2, 1-3, 1-4 interactions are treated
consistently by both the short-range pair style and the long-range
solver. This is not done for exclusions of charged atom pairs via the
neigh_modify exclude command. :dd
{New thermo_style command, previous thermo_modify settings will be lost} :dt
If a thermo_style command is used after a thermo_modify command, the
settings changed by the thermo_modify command will be reset to their
default values. This is because the thermo_modify command acts on
the currently defined thermo style, and a thermo_style command creates
a new style. :dd
{No Kspace calculation with verlet/split} :dt
The 2nd partition performs a kspace calculation so the kspace_style
command must be used. :dd
{No automatic unit conversion to XTC file format conventions possible for units lj} :dt
This means no scaling will be performed. :dd
{No fixes defined, atoms won't move} :dt
If you are not using a fix like nve, nvt, npt then atom velocities and
coordinates will not be updated during timestepping. :dd
{No joints between rigid bodies, use fix rigid instead} :dt
The bodies defined by fix poems are not connected by joints. POEMS
will integrate the body motion, but it would be more efficient to use
fix rigid. :dd
{Not using real units with pair reax} :dt
This is most likely an error, unless you have created your own ReaxFF
parameter file in a different set of units. :dd
{Number of MSM mesh points changed to be a multiple of 2} :dt
MSM requires that the number of grid points in each direction be a multiple
of two and the number of grid points in one or more directions have been
adjusted to meet this requirement. :dd
{OMP_NUM_THREADS environment is not set.} :dt
This environment variable must be set appropriately to use the
USER-OMP package. :dd
{One or more atoms are time integrated more than once} :dt
This is probably an error since you typically do not want to
advance the positions or velocities of an atom more than once
per timestep. :dd
{One or more chunks do not contain all atoms in molecule} :dt
This may not be what you intended. :dd
{One or more dynamic groups may not be updated at correct point in timestep} :dt
If there are other fixes that act immediately after the initial stage
of time integration within a timestep (i.e. after atoms move), then
the command that sets up the dynamic group should appear after those
fixes. This will insure that dynamic group assignments are made
after all atoms have moved. :dd
{One or more respa levels compute no forces} :dt
This is computationally inefficient. :dd
{Pair COMB charge %.10f with force %.10f hit max barrier} :dt
Something is possibly wrong with your model. :dd
{Pair COMB charge %.10f with force %.10f hit min barrier} :dt
Something is possibly wrong with your model. :dd
{Pair brownian needs newton pair on for momentum conservation} :dt
Self-explanatory. :dd
{Pair dpd needs newton pair on for momentum conservation} :dt
Self-explanatory. :dd
{Pair dsmc: num_of_collisions > number_of_A} :dt
Collision model in DSMC is breaking down. :dd
{Pair dsmc: num_of_collisions > number_of_B} :dt
Collision model in DSMC is breaking down. :dd
{Pair style in data file differs from currently defined pair style} :dt
Self-explanatory. :dd
{Particle deposition was unsuccessful} :dt
The fix deposit command was not able to insert as many atoms as
needed. The requested volume fraction may be too high, or other atoms
may be in the insertion region. :dd
{Proc sub-domain size < neighbor skin, could lead to lost atoms} :dt
The decomposition of the physical domain (likely due to load
balancing) has led to a processor's sub-domain being smaller than the
neighbor skin in one or more dimensions. Since reneighboring is
triggered by atoms moving the skin distance, this may lead to lost
atoms, if an atom moves all the way across a neighboring processor's
sub-domain before reneighboring is triggered. :dd
{Reducing PPPM order b/c stencil extends beyond nearest neighbor processor} :dt
This may lead to a larger grid than desired. See the kspace_modify overlap
command to prevent changing of the PPPM order. :dd
{Reducing PPPMDisp Coulomb order b/c stencil extends beyond neighbor processor} :dt
This may lead to a larger grid than desired. See the kspace_modify overlap
command to prevent changing of the PPPM order. :dd
{Reducing PPPMDisp dispersion order b/c stencil extends beyond neighbor processor} :dt
This may lead to a larger grid than desired. See the kspace_modify overlap
command to prevent changing of the PPPM order. :dd
{Replacing a fix, but new group != old group} :dt
The ID and style of a fix match for a fix you are changing with a fix
command, but the new group you are specifying does not match the old
group. :dd
{Replicating in a non-periodic dimension} :dt
The parameters for a replicate command will cause a non-periodic
dimension to be replicated; this may cause unwanted behavior. :dd
{Resetting reneighboring criteria during PRD} :dt
A PRD simulation requires that neigh_modify settings be delay = 0,
every = 1, check = yes. Since these settings were not in place,
LAMMPS changed them and will restore them to their original values
after the PRD simulation. :dd
{Resetting reneighboring criteria during TAD} :dt
A TAD simulation requires that neigh_modify settings be delay = 0,
every = 1, check = yes. Since these settings were not in place,
LAMMPS changed them and will restore them to their original values
after the PRD simulation. :dd
{Resetting reneighboring criteria during minimization} :dt
Minimization requires that neigh_modify settings be delay = 0, every =
1, check = yes. Since these settings were not in place, LAMMPS
changed them and will restore them to their original values after the
minimization. :dd
{Restart file used different # of processors} :dt
The restart file was written out by a LAMMPS simulation running on a
different number of processors. Due to round-off, the trajectories of
your restarted simulation may diverge a little more quickly than if
you ran on the same # of processors. :dd
{Restart file used different 3d processor grid} :dt
The restart file was written out by a LAMMPS simulation running on a
different 3d grid of processors. Due to round-off, the trajectories
of your restarted simulation may diverge a little more quickly than if
you ran on the same # of processors. :dd
{Restart file used different boundary settings, using restart file values} :dt
Your input script cannot change these restart file settings. :dd
{Restart file used different newton bond setting, using restart file value} :dt
The restart file value will override the setting in the input script. :dd
{Restart file used different newton pair setting, using input script value} :dt
The input script value will override the setting in the restart file. :dd
{Restrain problem: %d %ld %d %d %d %d} :dt
Conformation of the 4 listed dihedral atoms is extreme; you may want
to check your simulation geometry. :dd
{Running PRD with only one replica} :dt
This is allowed, but you will get no parallel speed-up. :dd
{SRD bin shifting turned on due to small lamda} :dt
This is done to try to preserve accuracy. :dd
{SRD bin size for fix srd differs from user request} :dt
Fix SRD had to adjust the bin size to fit the simulation box. See the
cubic keyword if you want this message to be an error vs warning. :dd
{SRD bins for fix srd are not cubic enough} :dt
The bin shape is not within tolerance of cubic. See the cubic
keyword if you want this message to be an error vs warning. :dd
{SRD particle %d started inside big particle %d on step %ld bounce %d} :dt
See the inside keyword if you want this message to be an error vs
warning. :dd
{SRD particle %d started inside wall %d on step %ld bounce %d} :dt
See the inside keyword if you want this message to be an error vs
warning. :dd
{Shake determinant < 0.0} :dt
The determinant of the quadratic equation being solved for a single
cluster specified by the fix shake command is numerically suspect. LAMMPS
will set it to 0.0 and continue. :dd
{Shell command '%s' failed with error '%s'} :dt
Self-explanatory. :dd
{Shell command returned with non-zero status} :dt
This may indicate the shell command did not operate as expected. :dd
{Should not allow rigid bodies to bounce off relecting walls} :dt
LAMMPS allows this, but their dynamics are not computed correctly. :dd
{Should not use fix nve/limit with fix shake or fix rattle} :dt
This will lead to invalid constraint forces in the SHAKE/RATTLE
computation. :dd
{Simulations might be very slow because of large number of structure factors} :dt
Self-explanatory. :dd
{Slab correction not needed for MSM} :dt
Slab correction is intended to be used with Ewald or PPPM and is not needed by MSM. :dd
{System is not charge neutral, net charge = %g} :dt
The total charge on all atoms on the system is not 0.0.
For some KSpace solvers this is only a warning. :dd
{Table inner cutoff >= outer cutoff} :dt
You specified an inner cutoff for a Coulombic table that is longer
than the global cutoff. Probably not what you wanted. :dd
{Temperature for MSST is not for group all} :dt
User-assigned temperature to MSST fix does not compute temperature for
all atoms. Since MSST computes a global pressure, the kinetic energy
contribution from the temperature is assumed to also be for all atoms.
Thus the pressure used by MSST could be inaccurate. :dd
{Temperature for NPT is not for group all} :dt
User-assigned temperature to NPT fix does not compute temperature for
all atoms. Since NPT computes a global pressure, the kinetic energy
contribution from the temperature is assumed to also be for all atoms.
Thus the pressure used by NPT could be inaccurate. :dd
{Temperature for fix modify is not for group all} :dt
The temperature compute is being used with a pressure calculation
which does operate on group all, so this may be inconsistent. :dd
{Temperature for thermo pressure is not for group all} :dt
User-assigned temperature to thermo via the thermo_modify command does
not compute temperature for all atoms. Since thermo computes a global
pressure, the kinetic energy contribution from the temperature is
assumed to also be for all atoms. Thus the pressure printed by thermo
could be inaccurate. :dd
{The fix ave/spatial command has been replaced by the more flexible fix ave/chunk and compute chunk/atom commands -- fix ave/spatial will be removed in the summer of 2015} :dt
Self-explanatory. :dd
{The minimizer does not re-orient dipoles when using fix efield} :dt
This means that only the atom coordinates will be minimized,
not the orientation of the dipoles. :dd
{Too many common neighbors in CNA %d times} :dt
More than the maximum # of neighbors was found multiple times. This
was unexpected. :dd
{Too many inner timesteps in fix ttm} :dt
Self-explanatory. :dd
{Too many neighbors in CNA for %d atoms} :dt
More than the maximum # of neighbors was found multiple times. This
was unexpected. :dd
{Triclinic box skew is large} :dt
The displacement in a skewed direction is normally required to be less
than half the box length in that dimension. E.g. the xy tilt must be
between -half and +half of the x box length. You have relaxed the
constraint using the box tilt command, but the warning means that a
LAMMPS simulation may be inefficient as a result. :dd
{Use special bonds = 0,1,1 with bond style fene} :dt
Most FENE models need this setting for the special_bonds command. :dd
{Use special bonds = 0,1,1 with bond style fene/expand} :dt
Most FENE models need this setting for the special_bonds command. :dd
{Using a manybody potential with bonds/angles/dihedrals and special_bond exclusions} :dt
This is likely not what you want to do. The exclusion settings will
eliminate neighbors in the neighbor list, which the manybody potential
needs to calculated its terms correctly. :dd
{Using compute temp/deform with inconsistent fix deform remap option} :dt
Fix nvt/sllod assumes deforming atoms have a velocity profile provided
by "remap v" or "remap none" as a fix deform option. :dd
{Using compute temp/deform with no fix deform defined} :dt
This is probably an error, since it makes little sense to use
compute temp/deform in this case. :dd
{Using fix srd with box deformation but no SRD thermostat} :dt
The deformation will heat the SRD particles so this can
be dangerous. :dd
{Using kspace solver on system with no charge} :dt
Self-explanatory. :dd
{Using largest cut-off for lj/long/dipole/long long long} :dt
Self-explanatory. :dd
{Using largest cutoff for buck/long/coul/long} :dt
Self-explanatory. :dd
{Using largest cutoff for lj/long/coul/long} :dt
Self-explanatory. :dd
{Using largest cutoff for pair_style lj/long/tip4p/long} :dt
Self-explanatory. :dd
{Using package gpu without any pair style defined} :dt
Self-explanatory. :dd
{Using pair potential shift with pair_modify compute no} :dt
The shift effects will thus not be computed. :dd
{Using pair tail corrections with nonperiodic system} :dt
This is probably a bogus thing to do, since tail corrections are
computed by integrating the density of a periodic system out to
infinity. :dd
{Using pair tail corrections with pair_modify compute no} :dt
The tail corrections will thus not be computed. :dd
{pair style reax is now deprecated and will soon be retired. Users should switch to pair_style reax/c} :dt
Self-explanatory. :dd
:dle
diff --git a/doc/src/Section_howto.txt b/doc/src/Section_howto.txt
index f2f2561af..6d699fe24 100644
--- a/doc/src/Section_howto.txt
+++ b/doc/src/Section_howto.txt
@@ -1,2935 +1,2935 @@
"Previous Section"_Section_accelerate.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_example.html :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
6. How-to discussions :h3
This section describes how to perform common tasks using LAMMPS.
6.1 "Restarting a simulation"_#howto_1
6.2 "2d simulations"_#howto_2
6.3 "CHARMM, AMBER, and DREIDING force fields"_#howto_3
6.4 "Running multiple simulations from one input script"_#howto_4
6.5 "Multi-replica simulations"_#howto_5
6.6 "Granular models"_#howto_6
6.7 "TIP3P water model"_#howto_7
6.8 "TIP4P water model"_#howto_8
6.9 "SPC water model"_#howto_9
6.10 "Coupling LAMMPS to other codes"_#howto_10
6.11 "Visualizing LAMMPS snapshots"_#howto_11
6.12 "Triclinic (non-orthogonal) simulation boxes"_#howto_12
6.13 "NEMD simulations"_#howto_13
6.14 "Finite-size spherical and aspherical particles"_#howto_14
6.15 "Output from LAMMPS (thermo, dumps, computes, fixes, variables)"_#howto_15
6.16 "Thermostatting, barostatting and computing temperature"_#howto_16
6.17 "Walls"_#howto_17
6.18 "Elastic constants"_#howto_18
6.19 "Library interface to LAMMPS"_#howto_19
6.20 "Calculating thermal conductivity"_#howto_20
6.21 "Calculating viscosity"_#howto_21
6.22 "Calculating a diffusion coefficient"_#howto_22
6.23 "Using chunks to calculate system properties"_#howto_23
6.24 "Setting parameters for the kspace_style pppm/disp command"_#howto_24
6.25 "Polarizable models"_#howto_25
6.26 "Adiabatic core/shell model"_#howto_26
6.27 "Drude induced dipoles"_#howto_27 :all(b)
The example input scripts included in the LAMMPS distribution and
highlighted in "Section 7"_Section_example.html also show how to
setup and run various kinds of simulations.
:line
:line
6.1 Restarting a simulation :link(howto_1),h4
There are 3 ways to continue a long LAMMPS simulation. Multiple
"run"_run.html commands can be used in the same input script. Each
run will continue from where the previous run left off. Or binary
restart files can be saved to disk using the "restart"_restart.html
command. At a later time, these binary files can be read via a
"read_restart"_read_restart.html command in a new script. Or they can
be converted to text data files using the "-r command-line
-switch"_Section_start.html#start_7 and read by a
+switch"_Section_start.html#start_6 and read by a
"read_data"_read_data.html command in a new script.
Here we give examples of 2 scripts that read either a binary restart
file or a converted data file and then issue a new run command to
continue where the previous run left off. They illustrate what
settings must be made in the new script. Details are discussed in the
documentation for the "read_restart"_read_restart.html and
"read_data"_read_data.html commands.
Look at the {in.chain} input script provided in the {bench} directory
of the LAMMPS distribution to see the original script that these 2
scripts are based on. If that script had the line
restart 50 tmp.restart :pre
added to it, it would produce 2 binary restart files (tmp.restart.50
and tmp.restart.100) as it ran.
This script could be used to read the 1st restart file and re-run the
last 50 timesteps:
read_restart tmp.restart.50 :pre
neighbor 0.4 bin
neigh_modify every 1 delay 1 :pre
fix 1 all nve
fix 2 all langevin 1.0 1.0 10.0 904297 :pre
timestep 0.012 :pre
run 50 :pre
Note that the following commands do not need to be repeated because
their settings are included in the restart file: {units, atom_style,
special_bonds, pair_style, bond_style}. However these commands do
need to be used, since their settings are not in the restart file:
{neighbor, fix, timestep}.
If you actually use this script to perform a restarted run, you will
notice that the thermodynamic data match at step 50 (if you also put a
"thermo 50" command in the original script), but do not match at step
100. This is because the "fix langevin"_fix_langevin.html command
uses random numbers in a way that does not allow for perfect restarts.
As an alternate approach, the restart file could be converted to a data
file as follows:
lmp_g++ -r tmp.restart.50 tmp.restart.data :pre
Then, this script could be used to re-run the last 50 steps:
units lj
atom_style bond
pair_style lj/cut 1.12
pair_modify shift yes
bond_style fene
special_bonds 0.0 1.0 1.0 :pre
read_data tmp.restart.data :pre
neighbor 0.4 bin
neigh_modify every 1 delay 1 :pre
fix 1 all nve
fix 2 all langevin 1.0 1.0 10.0 904297 :pre
timestep 0.012 :pre
reset_timestep 50
run 50 :pre
Note that nearly all the settings specified in the original {in.chain}
script must be repeated, except the {pair_coeff} and {bond_coeff}
commands since the new data file lists the force field coefficients.
Also, the "reset_timestep"_reset_timestep.html command is used to tell
LAMMPS the current timestep. This value is stored in restart files,
but not in data files.
:line
6.2 2d simulations :link(howto_2),h4
Use the "dimension"_dimension.html command to specify a 2d simulation.
Make the simulation box periodic in z via the "boundary"_boundary.html
command. This is the default.
If using the "create box"_create_box.html command to define a
simulation box, set the z dimensions narrow, but finite, so that the
create_atoms command will tile the 3d simulation box with a single z
plane of atoms - e.g.
"create box"_create_box.html 1 -10 10 -10 10 -0.25 0.25 :pre
If using the "read data"_read_data.html command to read in a file of
atom coordinates, set the "zlo zhi" values to be finite but narrow,
similar to the create_box command settings just described. For each
atom in the file, assign a z coordinate so it falls inside the
z-boundaries of the box - e.g. 0.0.
Use the "fix enforce2d"_fix_enforce2d.html command as the last
defined fix to insure that the z-components of velocities and forces
are zeroed out every timestep. The reason to make it the last fix is
so that any forces induced by other fixes will be zeroed out.
Many of the example input scripts included in the LAMMPS distribution
are for 2d models.
NOTE: Some models in LAMMPS treat particles as finite-size spheres, as
opposed to point particles. See the "atom_style
sphere"_atom_style.html and "fix nve/sphere"_fix_nve_sphere.html
commands for details. By default, for 2d simulations, such particles
will still be modeled as 3d spheres, not 2d discs (circles), meaning
their moment of inertia will be that of a sphere. If you wish to
model them as 2d discs, see the "set density/disc"_set.html command
and the {disc} option for the "fix nve/sphere"_fix_nve_sphere.html,
"fix nvt/sphere"_fix_nvt_sphere.html, "fix
nph/sphere"_fix_nph_sphere.html, "fix npt/sphere"_fix_npt_sphere.html
commands.
:line
6.3 CHARMM, AMBER, and DREIDING force fields :link(howto_3),h4
A force field has 2 parts: the formulas that define it and the
coefficients used for a particular system. Here we only discuss
formulas implemented in LAMMPS that correspond to formulas commonly
used in the CHARMM, AMBER, and DREIDING force fields. Setting
coefficients is done in the input data file via the
"read_data"_read_data.html command or in the input script with
commands like "pair_coeff"_pair_coeff.html or
"bond_coeff"_bond_coeff.html. See "Section 9"_Section_tools.html
for additional tools that can use CHARMM or AMBER to assign force
field coefficients and convert their output into LAMMPS input.
See "(MacKerell)"_#howto-MacKerell for a description of the CHARMM force
field. See "(Cornell)"_#howto-Cornell for a description of the AMBER force
field.
:link(charmm,http://www.scripps.edu/brooks)
:link(amber,http://amber.scripps.edu)
These style choices compute force field formulas that are consistent
with common options in CHARMM or AMBER. See each command's
documentation for the formula it computes.
"bond_style"_bond_harmonic.html harmonic
"angle_style"_angle_charmm.html charmm
"dihedral_style"_dihedral_charmm.html charmmfsh
"dihedral_style"_dihedral_charmm.html charmm
"pair_style"_pair_charmm.html lj/charmmfsw/coul/charmmfsh
"pair_style"_pair_charmm.html lj/charmmfsw/coul/long
"pair_style"_pair_charmm.html lj/charmm/coul/charmm
"pair_style"_pair_charmm.html lj/charmm/coul/charmm/implicit
"pair_style"_pair_charmm.html lj/charmm/coul/long :ul
"special_bonds"_special_bonds.html charmm
"special_bonds"_special_bonds.html amber :ul
NOTE: For CHARMM, newer {charmmfsw} or {charmmfsh} styles were
released in March 2017. We recommend they be used instead of the
older {charmm} styles. See discussion of the differences on the "pair
charmm"_pair_charmm.html and "dihedral charmm"_dihedral_charmm.html
doc pages.
DREIDING is a generic force field developed by the "Goddard
group"_http://www.wag.caltech.edu at Caltech and is useful for
predicting structures and dynamics of organic, biological and
main-group inorganic molecules. The philosophy in DREIDING is to use
general force constants and geometry parameters based on simple
hybridization considerations, rather than individual force constants
and geometric parameters that depend on the particular combinations of
atoms involved in the bond, angle, or torsion terms. DREIDING has an
"explicit hydrogen bond term"_pair_hbond_dreiding.html to describe
interactions involving a hydrogen atom on very electronegative atoms
(N, O, F).
See "(Mayo)"_#howto-Mayo for a description of the DREIDING force field
These style choices compute force field formulas that are consistent
with the DREIDING force field. See each command's
documentation for the formula it computes.
"bond_style"_bond_harmonic.html harmonic
"bond_style"_bond_morse.html morse :ul
"angle_style"_angle_harmonic.html harmonic
"angle_style"_angle_cosine.html cosine
"angle_style"_angle_cosine_periodic.html cosine/periodic :ul
"dihedral_style"_dihedral_charmm.html charmm
"improper_style"_improper_umbrella.html umbrella :ul
"pair_style"_pair_buck.html buck
"pair_style"_pair_buck.html buck/coul/cut
"pair_style"_pair_buck.html buck/coul/long
"pair_style"_pair_lj.html lj/cut
"pair_style"_pair_lj.html lj/cut/coul/cut
"pair_style"_pair_lj.html lj/cut/coul/long :ul
"pair_style"_pair_hbond_dreiding.html hbond/dreiding/lj
"pair_style"_pair_hbond_dreiding.html hbond/dreiding/morse :ul
"special_bonds"_special_bonds.html dreiding :ul
:line
6.4 Running multiple simulations from one input script :link(howto_4),h4
This can be done in several ways. See the documentation for
individual commands for more details on how these examples work.
If "multiple simulations" means continue a previous simulation for
more timesteps, then you simply use the "run"_run.html command
multiple times. For example, this script
units lj
atom_style atomic
read_data data.lj
run 10000
run 10000
run 10000
run 10000
run 10000 :pre
would run 5 successive simulations of the same system for a total of
50,000 timesteps.
If you wish to run totally different simulations, one after the other,
the "clear"_clear.html command can be used in between them to
re-initialize LAMMPS. For example, this script
units lj
atom_style atomic
read_data data.lj
run 10000
clear
units lj
atom_style atomic
read_data data.lj.new
run 10000 :pre
would run 2 independent simulations, one after the other.
For large numbers of independent simulations, you can use
"variables"_variable.html and the "next"_next.html and
"jump"_jump.html commands to loop over the same input script
multiple times with different settings. For example, this
script, named in.polymer
variable d index run1 run2 run3 run4 run5 run6 run7 run8
shell cd $d
read_data data.polymer
run 10000
shell cd ..
clear
next d
jump in.polymer :pre
would run 8 simulations in different directories, using a data.polymer
file in each directory. The same concept could be used to run the
same system at 8 different temperatures, using a temperature variable
and storing the output in different log and dump files, for example
variable a loop 8
variable t index 0.8 0.85 0.9 0.95 1.0 1.05 1.1 1.15
log log.$a
read data.polymer
velocity all create $t 352839
fix 1 all nvt $t $t 100.0
dump 1 all atom 1000 dump.$a
run 100000
clear
next t
next a
jump in.polymer :pre
All of the above examples work whether you are running on 1 or
multiple processors, but assumed you are running LAMMPS on a single
partition of processors. LAMMPS can be run on multiple partitions via
the "-partition" command-line switch as described in "this
-section"_Section_start.html#start_7 of the manual.
+section"_Section_start.html#start_6 of the manual.
In the last 2 examples, if LAMMPS were run on 3 partitions, the same
scripts could be used if the "index" and "loop" variables were
replaced with {universe}-style variables, as described in the
"variable"_variable.html command. Also, the "next t" and "next a"
commands would need to be replaced with a single "next a t" command.
With these modifications, the 8 simulations of each script would run
on the 3 partitions one after the other until all were finished.
Initially, 3 simulations would be started simultaneously, one on each
partition. When one finished, that partition would then start
the 4th simulation, and so forth, until all 8 were completed.
:line
6.5 Multi-replica simulations :link(howto_5),h4
Several commands in LAMMPS run mutli-replica simulations, meaning
that multiple instances (replicas) of your simulation are run
simultaneously, with small amounts of data exchanged between replicas
periodically.
These are the relevant commands:
"neb"_neb.html for nudged elastic band calculations
"prd"_prd.html for parallel replica dynamics
"tad"_tad.html for temperature accelerated dynamics
"temper"_temper.html for parallel tempering
"fix pimd"_fix_pimd.html for path-integral molecular dynamics (PIMD) :ul
NEB is a method for finding transition states and barrier energies.
PRD and TAD are methods for performing accelerated dynamics to find
and perform infrequent events. Parallel tempering or replica exchange
runs different replicas at a series of temperature to facilitate
rare-event sampling.
These commands can only be used if LAMMPS was built with the REPLICA
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
PIMD runs different replicas whose individual particles are coupled
together by springs to model a system or ring-polymers.
This commands can only be used if LAMMPS was built with the USER-MISC
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
In all these cases, you must run with one or more processors per
replica. The processors assigned to each replica are determined at
run-time by using the "-partition command-line
-switch"_Section_start.html#start_7 to launch LAMMPS on multiple
+switch"_Section_start.html#start_6 to launch LAMMPS on multiple
partitions, which in this context are the same as replicas. E.g.
these commands:
mpirun -np 16 lmp_linux -partition 8x2 -in in.temper
mpirun -np 8 lmp_linux -partition 8x1 -in in.neb :pre
would each run 8 replicas, on either 16 or 8 processors. Note the use
-of the "-in command-line switch"_Section_start.html#start_7 to specify
+of the "-in command-line switch"_Section_start.html#start_6 to specify
the input script which is required when running in multi-replica mode.
Also note that with MPI installed on a machine (e.g. your desktop),
you can run on more (virtual) processors than you have physical
processors. Thus the above commands could be run on a
single-processor (or few-processor) desktop so that you can run
a multi-replica simulation on more replicas than you have
physical processors.
:line
6.6 Granular models :link(howto_6),h4
Granular system are composed of spherical particles with a diameter,
as opposed to point particles. This means they have an angular
velocity and torque can be imparted to them to cause them to rotate.
To run a simulation of a granular model, you will want to use
the following commands:
"atom_style sphere"_atom_style.html
"fix nve/sphere"_fix_nve_sphere.html
"fix gravity"_fix_gravity.html :ul
This compute
"compute erotate/sphere"_compute_erotate_sphere.html :ul
calculates rotational kinetic energy which can be "output with
thermodynamic info"_Section_howto.html#howto_15.
Use one of these 3 pair potentials, which compute forces and torques
between interacting pairs of particles:
"pair_style"_pair_style.html gran/history
"pair_style"_pair_style.html gran/no_history
"pair_style"_pair_style.html gran/hertzian :ul
These commands implement fix options specific to granular systems:
"fix freeze"_fix_freeze.html
"fix pour"_fix_pour.html
"fix viscous"_fix_viscous.html
"fix wall/gran"_fix_wall_gran.html :ul
The fix style {freeze} zeroes both the force and torque of frozen
atoms, and should be used for granular system instead of the fix style
{setforce}.
For computational efficiency, you can eliminate needless pairwise
computations between frozen atoms by using this command:
"neigh_modify"_neigh_modify.html exclude :ul
NOTE: By default, for 2d systems, granular particles are still modeled
as 3d spheres, not 2d discs (circles), meaning their moment of inertia
will be the same as in 3d. If you wish to model granular particles in
2d as 2d discs, see the note on this topic in "Section
6.2"_Section_howto.html#howto_2, where 2d simulations are disussed.
:line
6.7 TIP3P water model :link(howto_7),h4
The TIP3P water model as implemented in CHARMM
"(MacKerell)"_#howto-MacKerell specifies a 3-site rigid water molecule with
charges and Lennard-Jones parameters assigned to each of the 3 atoms.
In LAMMPS the "fix shake"_fix_shake.html command can be used to hold
the two O-H bonds and the H-O-H angle rigid. A bond style of
{harmonic} and an angle style of {harmonic} or {charmm} should also be
used.
These are the additional parameters (in real units) to set for O and H
atoms and the water molecule to run a rigid TIP3P-CHARMM model with a
cutoff. The K values can be used if a flexible TIP3P model (without
fix shake) is desired. If the LJ epsilon and sigma for HH and OH are
set to 0.0, it corresponds to the original 1983 TIP3P model
"(Jorgensen)"_#Jorgensen1.
O mass = 15.9994
H mass = 1.008
O charge = -0.834
H charge = 0.417
LJ epsilon of OO = 0.1521
LJ sigma of OO = 3.1507
LJ epsilon of HH = 0.0460
LJ sigma of HH = 0.4000
LJ epsilon of OH = 0.0836
LJ sigma of OH = 1.7753
K of OH bond = 450
r0 of OH bond = 0.9572
K of HOH angle = 55
theta of HOH angle = 104.52 :all(b),p
These are the parameters to use for TIP3P with a long-range Coulombic
solver (e.g. Ewald or PPPM in LAMMPS), see "(Price)"_#Price1 for
details:
O mass = 15.9994
H mass = 1.008
O charge = -0.830
H charge = 0.415
LJ epsilon of OO = 0.102
LJ sigma of OO = 3.188
LJ epsilon, sigma of OH, HH = 0.0
K of OH bond = 450
r0 of OH bond = 0.9572
K of HOH angle = 55
theta of HOH angle = 104.52 :all(b),p
Wikipedia also has a nice article on "water
models"_http://en.wikipedia.org/wiki/Water_model.
:line
6.8 TIP4P water model :link(howto_8),h4
The four-point TIP4P rigid water model extends the traditional
three-point TIP3P model by adding an additional site, usually
massless, where the charge associated with the oxygen atom is placed.
This site M is located at a fixed distance away from the oxygen along
the bisector of the HOH bond angle. A bond style of {harmonic} and an
angle style of {harmonic} or {charmm} should also be used.
A TIP4P model is run with LAMMPS using either this command
for a cutoff model:
"pair_style lj/cut/tip4p/cut"_pair_lj.html
or these two commands for a long-range model:
"pair_style lj/cut/tip4p/long"_pair_lj.html
"kspace_style pppm/tip4p"_kspace_style.html :ul
For both models, the bond lengths and bond angles should be held fixed
using the "fix shake"_fix_shake.html command.
These are the additional parameters (in real units) to set for O and H
atoms and the water molecule to run a rigid TIP4P model with a cutoff
"(Jorgensen)"_#Jorgensen1. Note that the OM distance is specified in
the "pair_style"_pair_style.html command, not as part of the pair
coefficients.
O mass = 15.9994
H mass = 1.008
O charge = -1.040
H charge = 0.520
r0 of OH bond = 0.9572
theta of HOH angle = 104.52
OM distance = 0.15
LJ epsilon of O-O = 0.1550
LJ sigma of O-O = 3.1536
LJ epsilon, sigma of OH, HH = 0.0
Coulombic cutoff = 8.5 :all(b),p
For the TIP4/Ice model (J Chem Phys, 122, 234511 (2005);
http://dx.doi.org/10.1063/1.1931662) these values can be used:
O mass = 15.9994
H mass = 1.008
O charge = -1.1794
H charge = 0.5897
r0 of OH bond = 0.9572
theta of HOH angle = 104.52
OM distance = 0.1577
LJ epsilon of O-O = 0.21084
LJ sigma of O-O = 3.1668
LJ epsilon, sigma of OH, HH = 0.0
Coulombic cutoff = 8.5 :all(b),p
For the TIP4P/2005 model (J Chem Phys, 123, 234505 (2005);
http://dx.doi.org/10.1063/1.2121687), these values can be used:
O mass = 15.9994
H mass = 1.008
O charge = -1.1128
H charge = 0.5564
r0 of OH bond = 0.9572
theta of HOH angle = 104.52
OM distance = 0.1546
LJ epsilon of O-O = 0.1852
LJ sigma of O-O = 3.1589
LJ epsilon, sigma of OH, HH = 0.0
Coulombic cutoff = 8.5 :all(b),p
These are the parameters to use for TIP4P with a long-range Coulombic
solver (e.g. Ewald or PPPM in LAMMPS):
O mass = 15.9994
H mass = 1.008
O charge = -1.0484
H charge = 0.5242
r0 of OH bond = 0.9572
theta of HOH angle = 104.52
OM distance = 0.1250
LJ epsilon of O-O = 0.16275
LJ sigma of O-O = 3.16435
LJ epsilon, sigma of OH, HH = 0.0 :all(b),p
Note that the when using the TIP4P pair style, the neighbor list
cutoff for Coulomb interactions is effectively extended by a distance
2 * (OM distance), to account for the offset distance of the
fictitious charges on O atoms in water molecules. Thus it is
typically best in an efficiency sense to use a LJ cutoff >= Coulomb
cutoff + 2*(OM distance), to shrink the size of the neighbor list.
This leads to slightly larger cost for the long-range calculation, so
you can test the trade-off for your model. The OM distance and the LJ
and Coulombic cutoffs are set in the "pair_style
lj/cut/tip4p/long"_pair_lj.html command.
Wikipedia also has a nice article on "water
models"_http://en.wikipedia.org/wiki/Water_model.
:line
6.9 SPC water model :link(howto_9),h4
The SPC water model specifies a 3-site rigid water molecule with
charges and Lennard-Jones parameters assigned to each of the 3 atoms.
In LAMMPS the "fix shake"_fix_shake.html command can be used to hold
the two O-H bonds and the H-O-H angle rigid. A bond style of
{harmonic} and an angle style of {harmonic} or {charmm} should also be
used.
These are the additional parameters (in real units) to set for O and H
atoms and the water molecule to run a rigid SPC model.
O mass = 15.9994
H mass = 1.008
O charge = -0.820
H charge = 0.410
LJ epsilon of OO = 0.1553
LJ sigma of OO = 3.166
LJ epsilon, sigma of OH, HH = 0.0
r0 of OH bond = 1.0
theta of HOH angle = 109.47 :all(b),p
Note that as originally proposed, the SPC model was run with a 9
Angstrom cutoff for both LJ and Coulommbic terms. It can also be used
with long-range Coulombics (Ewald or PPPM in LAMMPS), without changing
any of the parameters above, though it becomes a different model in
that mode of usage.
The SPC/E (extended) water model is the same, except
the partial charge assignments change:
O charge = -0.8476
H charge = 0.4238 :all(b),p
See the "(Berendsen)"_#howto-Berendsen reference for more details on both
the SPC and SPC/E models.
Wikipedia also has a nice article on "water
models"_http://en.wikipedia.org/wiki/Water_model.
:line
6.10 Coupling LAMMPS to other codes :link(howto_10),h4
LAMMPS is designed to allow it to be coupled to other codes. For
example, a quantum mechanics code might compute forces on a subset of
atoms and pass those forces to LAMMPS. Or a continuum finite element
(FE) simulation might use atom positions as boundary conditions on FE
nodal points, compute a FE solution, and return interpolated forces on
MD atoms.
LAMMPS can be coupled to other codes in at least 3 ways. Each has
advantages and disadvantages, which you'll have to think about in the
context of your application.
(1) Define a new "fix"_fix.html command that calls the other code. In
this scenario, LAMMPS is the driver code. During its timestepping,
the fix is invoked, and can make library calls to the other code,
which has been linked to LAMMPS as a library. This is the way the
"POEMS"_poems package that performs constrained rigid-body motion on
groups of atoms is hooked to LAMMPS. See the
"fix poems"_fix_poems.html command for more details. See "this
section"_Section_modify.html of the documentation for info on how to add
a new fix to LAMMPS.
:link(poems,http://www.rpi.edu/~anderk5/lab)
(2) Define a new LAMMPS command that calls the other code. This is
conceptually similar to method (1), but in this case LAMMPS and the
other code are on a more equal footing. Note that now the other code
is not called during the timestepping of a LAMMPS run, but between
runs. The LAMMPS input script can be used to alternate LAMMPS runs
with calls to the other code, invoked via the new command. The
"run"_run.html command facilitates this with its {every} option, which
makes it easy to run a few steps, invoke the command, run a few steps,
invoke the command, etc.
In this scenario, the other code can be called as a library, as in
(1), or it could be a stand-alone code, invoked by a system() call
made by the command (assuming your parallel machine allows one or more
processors to start up another program). In the latter case the
stand-alone code could communicate with LAMMPS thru files that the
command writes and reads.
See "Section 10"_Section_modify.html of the documentation for how
to add a new command to LAMMPS.
(3) Use LAMMPS as a library called by another code. In this case the
other code is the driver and calls LAMMPS as needed. Or a wrapper
code could link and call both LAMMPS and another code as libraries.
Again, the "run"_run.html command has options that allow it to be
invoked with minimal overhead (no setup or clean-up) if you wish to do
multiple short runs, driven by another program.
Examples of driver codes that call LAMMPS as a library are included in
the examples/COUPLE directory of the LAMMPS distribution; see
examples/COUPLE/README for more details:
simple: simple driver programs in C++ and C which invoke LAMMPS as a
library :ulb,l
lammps_quest: coupling of LAMMPS and "Quest"_quest, to run classical
MD with quantum forces calculated by a density functional code :l
lammps_spparks: coupling of LAMMPS and "SPPARKS"_spparks, to couple
a kinetic Monte Carlo model for grain growth using MD to calculate
strain induced across grain boundaries :l
:ule
:link(quest,http://dft.sandia.gov/Quest)
:link(spparks,http://www.sandia.gov/~sjplimp/spparks.html)
"This section"_Section_start.html#start_5 of the documentation
describes how to build LAMMPS as a library. Once this is done, you
can interface with LAMMPS either via C++, C, Fortran, or Python (or
any other language that supports a vanilla C-like interface). For
example, from C++ you could create one (or more) "instances" of
LAMMPS, pass it an input script to process, or execute individual
commands, all by invoking the correct class methods in LAMMPS. From C
or Fortran you can make function calls to do the same things. See
"Section 11"_Section_python.html of the manual for a description
of the Python wrapper provided with LAMMPS that operates through the
LAMMPS library interface.
The files src/library.cpp and library.h contain the C-style interface
to LAMMPS. See "Section 6.19"_Section_howto.html#howto_19 of the
manual for a description of the interface and how to extend it for
your needs.
Note that the lammps_open() function that creates an instance of
LAMMPS takes an MPI communicator as an argument. This means that
instance of LAMMPS will run on the set of processors in the
communicator. Thus the calling code can run LAMMPS on all or a subset
of processors. For example, a wrapper script might decide to
alternate between LAMMPS and another code, allowing them both to run
on all the processors. Or it might allocate half the processors to
LAMMPS and half to the other code and run both codes simultaneously
before syncing them up periodically. Or it might instantiate multiple
instances of LAMMPS to perform different calculations.
:line
6.11 Visualizing LAMMPS snapshots :link(howto_11),h4
LAMMPS itself does not do visualization, but snapshots from LAMMPS
simulations can be visualized (and analyzed) in a variety of ways.
LAMMPS snapshots are created by the "dump"_dump.html command which can
create files in several formats. The native LAMMPS dump format is a
text file (see "dump atom" or "dump custom") which can be visualized
by several popular visualization tools. The "dump image"_dump_image.html
and "dump movie"_dump_image.html styles can output internally rendered
images and convert a sequence of them to a movie during the MD run.
Several programs included with LAMMPS as auxiliary tools can convert
between LAMMPS format files and other formats.
See the "Section 9"_Section_tools.html doc page for details.
A Python-based toolkit distributed by our group can read native LAMMPS
dump files, including custom dump files with additional columns of
user-specified atom information, and convert them to various formats
or pipe them into visualization software directly. See the "Pizza.py
WWW site"_pizza for details. Specifically, Pizza.py can convert
LAMMPS dump files into PDB, XYZ, "Ensight"_ensight, and VTK formats.
Pizza.py can pipe LAMMPS dump files directly into the Raster3d and
RasMol visualization programs. Pizza.py has tools that do interactive
3d OpenGL visualization and one that creates SVG images of dump file
snapshots.
:link(pizza,http://www.sandia.gov/~sjplimp/pizza.html)
:link(ensight,http://www.ensight.com)
:link(atomeye,http://mt.seas.upenn.edu/Archive/Graphics/A)
:line
6.12 Triclinic (non-orthogonal) simulation boxes :link(howto_12),h4
By default, LAMMPS uses an orthogonal simulation box to encompass the
particles. The "boundary"_boundary.html command sets the boundary
conditions of the box (periodic, non-periodic, etc). The orthogonal
box has its "origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors
starting from the origin given by [a] = (xhi-xlo,0,0); [b] =
(0,yhi-ylo,0); [c] = (0,0,zhi-zlo). The 6 parameters
(xlo,xhi,ylo,yhi,zlo,zhi) are defined at the time the simulation box
is created, e.g. by the "create_box"_create_box.html or
"read_data"_read_data.html or "read_restart"_read_restart.html
commands. Additionally, LAMMPS defines box size parameters lx,ly,lz
where lx = xhi-xlo, and similarly in the y and z dimensions. The 6
parameters, as well as lx,ly,lz, can be output via the "thermo_style
custom"_thermo_style.html command.
LAMMPS also allows simulations to be performed in triclinic
(non-orthogonal) simulation boxes shaped as a parallelepiped with
triclinic symmetry. The parallelepiped has its "origin" at
(xlo,ylo,zlo) and is defined by 3 edge vectors starting from the
origin given by [a] = (xhi-xlo,0,0); [b] = (xy,yhi-ylo,0); [c] =
(xz,yz,zhi-zlo). {xy,xz,yz} can be 0.0 or positive or negative values
and are called "tilt factors" because they are the amount of
displacement applied to faces of an originally orthogonal box to
transform it into the parallelepiped. In LAMMPS the triclinic
simulation box edge vectors [a], [b], and [c] cannot be arbitrary
vectors. As indicated, [a] must lie on the positive x axis. [b] must
lie in the xy plane, with strictly positive y component. [c] may have
any orientation with strictly positive z component. The requirement
that [a], [b], and [c] have strictly positive x, y, and z components,
respectively, ensures that [a], [b], and [c] form a complete
right-handed basis. These restrictions impose no loss of generality,
since it is possible to rotate/invert any set of 3 crystal basis
vectors so that they conform to the restrictions.
For example, assume that the 3 vectors [A],[B],[C] are the edge
vectors of a general parallelepiped, where there is no restriction on
[A],[B],[C] other than they form a complete right-handed basis i.e.
[A] x [B] . [C] > 0. The equivalent LAMMPS [a],[b],[c] are a linear
rotation of [A], [B], and [C] and can be computed as follows:
:c,image(Eqs/transform.jpg)
where A = | [A] | indicates the scalar length of [A]. The hat symbol (^)
indicates the corresponding unit vector. {beta} and {gamma} are angles
between the vectors described below. Note that by construction,
[a], [b], and [c] have strictly positive x, y, and z components, respectively.
If it should happen that
[A], [B], and [C] form a left-handed basis, then the above equations
are not valid for [c]. In this case, it is necessary
to first apply an inversion. This can be achieved
by interchanging two basis vectors or by changing the sign of one of them.
For consistency, the same rotation/inversion applied to the basis vectors
must also be applied to atom positions, velocities,
and any other vector quantities.
This can be conveniently achieved by first converting to
fractional coordinates in the
old basis and then converting to distance coordinates in the new basis.
The transformation is given by the following equation:
:c,image(Eqs/rotate.jpg)
where {V} is the volume of the box, [X] is the original vector quantity and
[x] is the vector in the LAMMPS basis.
There is no requirement that a triclinic box be periodic in any
dimension, though it typically should be in at least the 2nd dimension
of the tilt (y in xy) if you want to enforce a shift in periodic
boundary conditions across that boundary. Some commands that work
with triclinic boxes, e.g. the "fix deform"_fix_deform.html and "fix
npt"_fix_nh.html commands, require periodicity or non-shrink-wrap
boundary conditions in specific dimensions. See the command doc pages
for details.
The 9 parameters (xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) are defined at the
time the simulation box is created. This happens in one of 3 ways.
If the "create_box"_create_box.html command is used with a region of
style {prism}, then a triclinic box is setup. See the
"region"_region.html command for details. If the
"read_data"_read_data.html command is used to define the simulation
box, and the header of the data file contains a line with the "xy xz
yz" keyword, then a triclinic box is setup. See the
"read_data"_read_data.html command for details. Finally, if the
"read_restart"_read_restart.html command reads a restart file which
was written from a simulation using a triclinic box, then a triclinic
box will be setup for the restarted simulation.
Note that you can define a triclinic box with all 3 tilt factors =
0.0, so that it is initially orthogonal. This is necessary if the box
will become non-orthogonal, e.g. due to the "fix npt"_fix_nh.html or
"fix deform"_fix_deform.html commands. Alternatively, you can use the
"change_box"_change_box.html command to convert a simulation box from
orthogonal to triclinic and vice versa.
As with orthogonal boxes, LAMMPS defines triclinic box size parameters
lx,ly,lz where lx = xhi-xlo, and similarly in the y and z dimensions.
The 9 parameters, as well as lx,ly,lz, can be output via the
"thermo_style custom"_thermo_style.html command.
To avoid extremely tilted boxes (which would be computationally
inefficient), LAMMPS normally requires that no tilt factor can skew
the box more than half the distance of the parallel box length, which
is the 1st dimension in the tilt factor (x for xz). This is required
both when the simulation box is created, e.g. via the
"create_box"_create_box.html or "read_data"_read_data.html commands,
as well as when the box shape changes dynamically during a simulation,
e.g. via the "fix deform"_fix_deform.html or "fix npt"_fix_nh.html
commands.
For example, if xlo = 2 and xhi = 12, then the x box length is 10 and
the xy tilt factor must be between -5 and 5. Similarly, both xz and
yz must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is
not a limitation, since if the maximum tilt factor is 5 (as in this
example), then configurations with tilt = ..., -15, -5, 5, 15, 25,
... are geometrically all equivalent. If the box tilt exceeds this
limit during a dynamics run (e.g. via the "fix deform"_fix_deform.html
command), then the box is "flipped" to an equivalent shape with a tilt
factor within the bounds, so the run can continue. See the "fix
deform"_fix_deform.html doc page for further details.
One exception to this rule is if the 1st dimension in the tilt
factor (x for xy) is non-periodic. In that case, the limits on the
tilt factor are not enforced, since flipping the box in that dimension
does not change the atom positions due to non-periodicity. In this
mode, if you tilt the system to extreme angles, the simulation will
simply become inefficient, due to the highly skewed simulation box.
The limitation on not creating a simulation box with a tilt factor
skewing the box more than half the distance of the parallel box length
can be overridden via the "box"_box.html command. Setting the {tilt}
keyword to {large} allows any tilt factors to be specified.
Box flips that may occur using the "fix deform"_fix_deform.html or
"fix npt"_fix_nh.html commands can be turned off using the {flip no}
option with either of the commands.
Note that if a simulation box has a large tilt factor, LAMMPS will run
less efficiently, due to the large volume of communication needed to
acquire ghost atoms around a processor's irregular-shaped sub-domain.
For extreme values of tilt, LAMMPS may also lose atoms and generate an
error.
Triclinic crystal structures are often defined using three lattice
constants {a}, {b}, and {c}, and three angles {alpha}, {beta} and
{gamma}. Note that in this nomenclature, the a, b, and c lattice
constants are the scalar lengths of the edge vectors [a], [b], and [c]
defined above. The relationship between these 6 quantities
(a,b,c,alpha,beta,gamma) and the LAMMPS box sizes (lx,ly,lz) =
(xhi-xlo,yhi-ylo,zhi-zlo) and tilt factors (xy,xz,yz) is as follows:
:c,image(Eqs/box.jpg)
The inverse relationship can be written as follows:
:c,image(Eqs/box_inverse.jpg)
The values of {a}, {b}, {c} , {alpha}, {beta} , and {gamma} can be printed
out or accessed by computes using the
"thermo_style custom"_thermo_style.html keywords
{cella}, {cellb}, {cellc}, {cellalpha}, {cellbeta}, {cellgamma},
respectively.
As discussed on the "dump"_dump.html command doc page, when the BOX
BOUNDS for a snapshot is written to a dump file for a triclinic box,
an orthogonal bounding box which encloses the triclinic simulation box
is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic
box, formatted as follows:
ITEM: BOX BOUNDS xy xz yz
xlo_bound xhi_bound xy
ylo_bound yhi_bound xz
zlo_bound zhi_bound yz :pre
This bounding box is convenient for many visualization programs and is
calculated from the 9 triclinic box parameters
(xlo,xhi,ylo,yhi,zlo,zhi,xy,xz,yz) as follows:
xlo_bound = xlo + MIN(0.0,xy,xz,xy+xz)
xhi_bound = xhi + MAX(0.0,xy,xz,xy+xz)
ylo_bound = ylo + MIN(0.0,yz)
yhi_bound = yhi + MAX(0.0,yz)
zlo_bound = zlo
zhi_bound = zhi :pre
These formulas can be inverted if you need to convert the bounding box
back into the triclinic box parameters, e.g. xlo = xlo_bound -
MIN(0.0,xy,xz,xy+xz).
One use of triclinic simulation boxes is to model solid-state crystals
with triclinic symmetry. The "lattice"_lattice.html command can be
used with non-orthogonal basis vectors to define a lattice that will
tile a triclinic simulation box via the
"create_atoms"_create_atoms.html command.
A second use is to run Parinello-Rahman dynamics via the "fix
npt"_fix_nh.html command, which will adjust the xy, xz, yz tilt
factors to compensate for off-diagonal components of the pressure
tensor. The analog for an "energy minimization"_minimize.html is
the "fix box/relax"_fix_box_relax.html command.
A third use is to shear a bulk solid to study the response of the
material. The "fix deform"_fix_deform.html command can be used for
this purpose. It allows dynamic control of the xy, xz, yz tilt
factors as a simulation runs. This is discussed in the next section
on non-equilibrium MD (NEMD) simulations.
:line
6.13 NEMD simulations :link(howto_13),h4
Non-equilibrium molecular dynamics or NEMD simulations are typically
used to measure a fluid's rheological properties such as viscosity.
In LAMMPS, such simulations can be performed by first setting up a
non-orthogonal simulation box (see the preceding Howto section).
A shear strain can be applied to the simulation box at a desired
strain rate by using the "fix deform"_fix_deform.html command. The
"fix nvt/sllod"_fix_nvt_sllod.html command can be used to thermostat
the sheared fluid and integrate the SLLOD equations of motion for the
system. Fix nvt/sllod uses "compute
temp/deform"_compute_temp_deform.html to compute a thermal temperature
by subtracting out the streaming velocity of the shearing atoms. The
velocity profile or other properties of the fluid can be monitored via
the "fix ave/chunk"_fix_ave_chunk.html command.
As discussed in the previous section on non-orthogonal simulation
boxes, the amount of tilt or skew that can be applied is limited by
LAMMPS for computational efficiency to be 1/2 of the parallel box
length. However, "fix deform"_fix_deform.html can continuously strain
a box by an arbitrary amount. As discussed in the "fix
deform"_fix_deform.html command, when the tilt value reaches a limit,
the box is flipped to the opposite limit which is an equivalent tiling
of periodic space. The strain rate can then continue to change as
before. In a long NEMD simulation these box re-shaping events may
occur many times.
In a NEMD simulation, the "remap" option of "fix
deform"_fix_deform.html should be set to "remap v", since that is what
"fix nvt/sllod"_fix_nvt_sllod.html assumes to generate a velocity
profile consistent with the applied shear strain rate.
An alternative method for calculating viscosities is provided via the
"fix viscosity"_fix_viscosity.html command.
NEMD simulations can also be used to measure transport properties of a fluid
through a pore or channel. Simulations of steady-state flow can be performed
using the "fix flow/gauss"_fix_flow_gauss.html command.
:line
6.14 Finite-size spherical and aspherical particles :link(howto_14),h4
Typical MD models treat atoms or particles as point masses. Sometimes
it is desirable to have a model with finite-size particles such as
spheroids or ellipsoids or generalized aspherical bodies. The
difference is that such particles have a moment of inertia, rotational
energy, and angular momentum. Rotation is induced by torque coming
from interactions with other particles.
LAMMPS has several options for running simulations with these kinds of
particles. The following aspects are discussed in turn:
atom styles
pair potentials
time integration
computes, thermodynamics, and dump output
rigid bodies composed of finite-size particles :ul
Example input scripts for these kinds of models are in the body,
colloid, dipole, ellipse, line, peri, pour, and tri directories of the
"examples directory"_Section_example.html in the LAMMPS distribution.
Atom styles :h5
There are several "atom styles"_atom_style.html that allow for
definition of finite-size particles: sphere, dipole, ellipsoid, line,
tri, peri, and body.
The sphere style defines particles that are spheriods and each
particle can have a unique diameter and mass (or density). These
particles store an angular velocity (omega) and can be acted upon by
torque. The "set" command can be used to modify the diameter and mass
of individual particles, after then are created.
The dipole style does not actually define finite-size particles, but
is often used in conjunction with spherical particles, via a command
like
atom_style hybrid sphere dipole :pre
This is because when dipoles interact with each other, they induce
torques, and a particle must be finite-size (i.e. have a moment of
inertia) in order to respond and rotate. See the "atom_style
dipole"_atom_style.html command for details. The "set" command can be
used to modify the orientation and length of the dipole moment of
individual particles, after then are created.
The ellipsoid style defines particles that are ellipsoids and thus can
be aspherical. Each particle has a shape, specified by 3 diameters,
and mass (or density). These particles store an angular momentum and
their orientation (quaternion), and can be acted upon by torque. They
do not store an angular velocity (omega), which can be in a different
direction than angular momentum, rather they compute it as needed.
The "set" command can be used to modify the diameter, orientation, and
mass of individual particles, after then are created. It also has a
brief explanation of what quaternions are.
The line style defines line segment particles with two end points and
a mass (or density). They can be used in 2d simulations, and they can
be joined together to form rigid bodies which represent arbitrary
polygons.
The tri style defines triangular particles with three corner points
and a mass (or density). They can be used in 3d simulations, and they
can be joined together to form rigid bodies which represent arbitrary
particles with a triangulated surface.
The peri style is used with "Peridynamic models"_pair_peri.html and
defines particles as having a volume, that is used internally in the
"pair_style peri"_pair_peri.html potentials.
The body style allows for definition of particles which can represent
complex entities, such as surface meshes of discrete points,
collections of sub-particles, deformable objects, etc. The body style
is discussed in more detail on the "body"_body.html doc page.
Note that if one of these atom styles is used (or multiple styles via
the "atom_style hybrid"_atom_style.html command), not all particles in
the system are required to be finite-size or aspherical.
For example, in the ellipsoid style, if the 3 shape parameters are set
to the same value, the particle will be a sphere rather than an
ellipsoid. If the 3 shape parameters are all set to 0.0 or if the
diameter is set to 0.0, it will be a point particle. In the line or
tri style, if the lineflag or triflag is specified as 0, then it
will be a point particle.
Some of the pair styles used to compute pairwise interactions between
finite-size particles also compute the correct interaction with point
particles as well, e.g. the interaction between a point particle and a
finite-size particle or between two point particles. If necessary,
"pair_style hybrid"_pair_hybrid.html can be used to insure the correct
interactions are computed for the appropriate style of interactions.
Likewise, using groups to partition particles (ellipsoids versus
spheres versus point particles) will allow you to use the appropriate
time integrators and temperature computations for each class of
particles. See the doc pages for various commands for details.
Also note that for "2d simulations"_dimension.html, atom styles sphere
and ellipsoid still use 3d particles, rather than as circular disks or
ellipses. This means they have the same moment of inertia as the 3d
object. When temperature is computed, the correct degrees of freedom
are used for rotation in a 2d versus 3d system.
Pair potentials :h5
When a system with finite-size particles is defined, the particles
will only rotate and experience torque if the force field computes
such interactions. These are the various "pair
styles"_pair_style.html that generate torque:
"pair_style gran/history"_pair_gran.html
"pair_style gran/hertzian"_pair_gran.html
"pair_style gran/no_history"_pair_gran.html
"pair_style dipole/cut"_pair_dipole.html
"pair_style gayberne"_pair_gayberne.html
"pair_style resquared"_pair_resquared.html
"pair_style brownian"_pair_brownian.html
"pair_style lubricate"_pair_lubricate.html
"pair_style line/lj"_pair_line_lj.html
"pair_style tri/lj"_pair_tri_lj.html
"pair_style body"_pair_body.html :ul
The granular pair styles are used with spherical particles. The
dipole pair style is used with the dipole atom style, which could be
applied to spherical or ellipsoidal particles. The GayBerne and
REsquared potentials require ellipsoidal particles, though they will
also work if the 3 shape parameters are the same (a sphere). The
Brownian and lubrication potentials are used with spherical particles.
The line, tri, and body potentials are used with line segment,
triangular, and body particles respectively.
Time integration :h5
There are several fixes that perform time integration on finite-size
spherical particles, meaning the integrators update the rotational
orientation and angular velocity or angular momentum of the particles:
"fix nve/sphere"_fix_nve_sphere.html
"fix nvt/sphere"_fix_nvt_sphere.html
"fix npt/sphere"_fix_npt_sphere.html :ul
Likewise, there are 3 fixes that perform time integration on
ellipsoidal particles:
"fix nve/asphere"_fix_nve_asphere.html
"fix nvt/asphere"_fix_nvt_asphere.html
"fix npt/asphere"_fix_npt_asphere.html :ul
The advantage of these fixes is that those which thermostat the
particles include the rotational degrees of freedom in the temperature
calculation and thermostatting. The "fix langevin"_fix_langevin
command can also be used with its {omgea} or {angmom} options to
thermostat the rotational degrees of freedom for spherical or
ellipsoidal particles. Other thermostatting fixes only operate on the
translational kinetic energy of finite-size particles.
These fixes perform constant NVE time integration on line segment,
triangular, and body particles:
"fix nve/line"_fix_nve_line.html
"fix nve/tri"_fix_nve_tri.html
"fix nve/body"_fix_nve_body.html :ul
Note that for mixtures of point and finite-size particles, these
integration fixes can only be used with "groups"_group.html which
contain finite-size particles.
Computes, thermodynamics, and dump output :h5
There are several computes that calculate the temperature or
rotational energy of spherical or ellipsoidal particles:
"compute temp/sphere"_compute_temp_sphere.html
"compute temp/asphere"_compute_temp_asphere.html
"compute erotate/sphere"_compute_erotate_sphere.html
"compute erotate/asphere"_compute_erotate_asphere.html :ul
These include rotational degrees of freedom in their computation. If
you wish the thermodynamic output of temperature or pressure to use
one of these computes (e.g. for a system entirely composed of
finite-size particles), then the compute can be defined and the
"thermo_modify"_thermo_modify.html command used. Note that by default
thermodynamic quantities will be calculated with a temperature that
only includes translational degrees of freedom. See the
"thermo_style"_thermo_style.html command for details.
These commands can be used to output various attributes of finite-size
particles:
"dump custom"_dump.html
"compute property/atom"_compute_property_atom.html
"dump local"_dump.html
"compute body/local"_compute_body_local.html :ul
Attributes include the dipole moment, the angular velocity, the
angular momentum, the quaternion, the torque, the end-point and
corner-point coordinates (for line and tri particles), and
sub-particle attributes of body particles.
Rigid bodies composed of finite-size particles :h5
The "fix rigid"_fix_rigid.html command treats a collection of
particles as a rigid body, computes its inertia tensor, sums the total
force and torque on the rigid body each timestep due to forces on its
constituent particles, and integrates the motion of the rigid body.
If any of the constituent particles of a rigid body are finite-size
particles (spheres or ellipsoids or line segments or triangles), then
their contribution to the inertia tensor of the body is different than
if they were point particles. This means the rotational dynamics of
the rigid body will be different. Thus a model of a dimer is
different if the dimer consists of two point masses versus two
spheroids, even if the two particles have the same mass. Finite-size
particles that experience torque due to their interaction with other
particles will also impart that torque to a rigid body they are part
of.
See the "fix rigid" command for example of complex rigid-body models
it is possible to define in LAMMPS.
Note that the "fix shake"_fix_shake.html command can also be used to
treat 2, 3, or 4 particles as a rigid body, but it always assumes the
particles are point masses.
Also note that body particles cannot be modeled with the "fix
rigid"_fix_rigid.html command. Body particles are treated by LAMMPS
as single particles, though they can store internal state, such as a
list of sub-particles. Individual body partices are typically treated
as rigid bodies, and their motion integrated with a command like "fix
nve/body"_fix_nve_body.html. Interactions between pairs of body
particles are computed via a command like "pair_style
body"_pair_body.html.
:line
6.15 Output from LAMMPS (thermo, dumps, computes, fixes, variables) :link(howto_15),h4
There are four basic kinds of LAMMPS output:
"Thermodynamic output"_thermo_style.html, which is a list
of quantities printed every few timesteps to the screen and logfile. :ulb,l
"Dump files"_dump.html, which contain snapshots of atoms and various
per-atom values and are written at a specified frequency. :l
Certain fixes can output user-specified quantities to files: "fix
ave/time"_fix_ave_time.html for time averaging, "fix
ave/chunk"_fix_ave_chunk.html for spatial or other averaging, and "fix
print"_fix_print.html for single-line output of
"variables"_variable.html. Fix print can also output to the
screen. :l
"Restart files"_restart.html. :l
:ule
A simulation prints one set of thermodynamic output and (optionally)
restart files. It can generate any number of dump files and fix
output files, depending on what "dump"_dump.html and "fix"_fix.html
commands you specify.
As discussed below, LAMMPS gives you a variety of ways to determine
what quantities are computed and printed when the thermodynamics,
dump, or fix commands listed above perform output. Throughout this
discussion, note that users can also "add their own computes and fixes
to LAMMPS"_Section_modify.html which can then generate values that can
then be output with these commands.
The following sub-sections discuss different LAMMPS command related
to output and the kind of data they operate on and produce:
"Global/per-atom/local data"_#global
"Scalar/vector/array data"_#scalar
"Thermodynamic output"_#thermo
"Dump file output"_#dump
"Fixes that write output files"_#fixoutput
"Computes that process output quantities"_#computeoutput
"Fixes that process output quantities"_#fixprocoutput
"Computes that generate values to output"_#compute
"Fixes that generate values to output"_#fix
"Variables that generate values to output"_#variable
"Summary table of output options and data flow between commands"_#table :ul
Global/per-atom/local data :h5,link(global)
Various output-related commands work with three different styles of
data: global, per-atom, or local. A global datum is one or more
system-wide values, e.g. the temperature of the system. A per-atom
datum is one or more values per atom, e.g. the kinetic energy of each
atom. Local datums are calculated by each processor based on the
atoms it owns, but there may be zero or more per atom, e.g. a list of
bond distances.
Scalar/vector/array data :h5,link(scalar)
Global, per-atom, and local datums can each come in three kinds: a
single scalar value, a vector of values, or a 2d array of values. The
doc page for a "compute" or "fix" or "variable" that generates data
will specify both the style and kind of data it produces, e.g. a
per-atom vector.
When a quantity is accessed, as in many of the output commands
discussed below, it can be referenced via the following bracket
notation, where ID in this case is the ID of a compute. The leading
"c_" would be replaced by "f_" for a fix, or "v_" for a variable:
c_ID | entire scalar, vector, or array
c_ID\[I\] | one element of vector, one column of array
c_ID\[I\]\[J\] | one element of array :tb(s=|)
In other words, using one bracket reduces the dimension of the data
once (vector -> scalar, array -> vector). Using two brackets reduces
the dimension twice (array -> scalar). Thus a command that uses
scalar values as input can typically also process elements of a vector
or array.
Thermodynamic output :h5,link(thermo)
The frequency and format of thermodynamic output is set by the
"thermo"_thermo.html, "thermo_style"_thermo_style.html, and
"thermo_modify"_thermo_modify.html commands. The
"thermo_style"_thermo_style.html command also specifies what values
are calculated and written out. Pre-defined keywords can be specified
(e.g. press, etotal, etc). Three additional kinds of keywords can
also be specified (c_ID, f_ID, v_name), where a "compute"_compute.html
or "fix"_fix.html or "variable"_variable.html provides the value to be
output. In each case, the compute, fix, or variable must generate
global values for input to the "thermo_style custom"_dump.html
command.
Note that thermodynamic output values can be "extensive" or
"intensive". The former scale with the number of atoms in the system
(e.g. total energy), the latter do not (e.g. temperature). The
setting for "thermo_modify norm"_thermo_modify.html determines whether
extensive quantities are normalized or not. Computes and fixes
produce either extensive or intensive values; see their individual doc
pages for details. "Equal-style variables"_variable.html produce only
intensive values; you can include a division by "natoms" in the
formula if desired, to make an extensive calculation produce an
intensive result.
Dump file output :h5,link(dump)
Dump file output is specified by the "dump"_dump.html and
"dump_modify"_dump_modify.html commands. There are several
pre-defined formats (dump atom, dump xtc, etc).
There is also a "dump custom"_dump.html format where the user
specifies what values are output with each atom. Pre-defined atom
attributes can be specified (id, x, fx, etc). Three additional kinds
of keywords can also be specified (c_ID, f_ID, v_name), where a
"compute"_compute.html or "fix"_fix.html or "variable"_variable.html
provides the values to be output. In each case, the compute, fix, or
variable must generate per-atom values for input to the "dump
custom"_dump.html command.
There is also a "dump local"_dump.html format where the user specifies
what local values to output. A pre-defined index keyword can be
specified to enumerate the local values. Two additional kinds of
keywords can also be specified (c_ID, f_ID), where a
"compute"_compute.html or "fix"_fix.html or "variable"_variable.html
provides the values to be output. In each case, the compute or fix
must generate local values for input to the "dump local"_dump.html
command.
Fixes that write output files :h5,link(fixoutput)
Several fixes take various quantities as input and can write output
files: "fix ave/time"_fix_ave_time.html, "fix
ave/chunk"_fix_ave_chunk.html, "fix ave/histo"_fix_ave_histo.html,
"fix ave/correlate"_fix_ave_correlate.html, and "fix
print"_fix_print.html.
The "fix ave/time"_fix_ave_time.html command enables direct output to
a file and/or time-averaging of global scalars or vectors. The user
specifies one or more quantities as input. These can be global
"compute"_compute.html values, global "fix"_fix.html values, or
"variables"_variable.html of any style except the atom style which
produces per-atom values. Since a variable can refer to keywords used
by the "thermo_style custom"_thermo_style.html command (like temp or
press) and individual per-atom values, a wide variety of quantities
can be time averaged and/or output in this way. If the inputs are one
or more scalar values, then the fix generate a global scalar or vector
of output. If the inputs are one or more vector values, then the fix
generates a global vector or array of output. The time-averaged
output of this fix can also be used as input to other output commands.
The "fix ave/chunk"_fix_ave_chunk.html command enables direct output
to a file of chunk-averaged per-atom quantities like those output in
dump files. Chunks can represent spatial bins or other collections of
atoms, e.g. individual molecules. The per-atom quantities can be atom
density (mass or number) or atom attributes such as position,
velocity, force. They can also be per-atom quantities calculated by a
"compute"_compute.html, by a "fix"_fix.html, or by an atom-style
"variable"_variable.html. The chunk-averaged output of this fix can
also be used as input to other output commands.
The "fix ave/histo"_fix_ave_histo.html command enables direct output
to a file of histogrammed quantities, which can be global or per-atom
or local quantities. The histogram output of this fix can also be
used as input to other output commands.
The "fix ave/correlate"_fix_ave_correlate.html command enables direct
output to a file of time-correlated quantities, which can be global
values. The correlation matrix output of this fix can also be used as
input to other output commands.
The "fix print"_fix_print.html command can generate a line of output
written to the screen and log file or to a separate file, periodically
during a running simulation. The line can contain one or more
"variable"_variable.html values for any style variable except the
vector or atom styles). As explained above, variables themselves can
contain references to global values generated by "thermodynamic
keywords"_thermo_style.html, "computes"_compute.html,
"fixes"_fix.html, or other "variables"_variable.html, or to per-atom
values for a specific atom. Thus the "fix print"_fix_print.html
command is a means to output a wide variety of quantities separate
from normal thermodynamic or dump file output.
Computes that process output quantities :h5,link(computeoutput)
The "compute reduce"_compute_reduce.html and "compute
reduce/region"_compute_reduce.html commands take one or more per-atom
or local vector quantities as inputs and "reduce" them (sum, min, max,
ave) to scalar quantities. These are produced as output values which
can be used as input to other output commands.
The "compute slice"_compute_slice.html command take one or more global
vector or array quantities as inputs and extracts a subset of their
values to create a new vector or array. These are produced as output
values which can be used as input to other output commands.
The "compute property/atom"_compute_property_atom.html command takes a
list of one or more pre-defined atom attributes (id, x, fx, etc) and
stores the values in a per-atom vector or array. These are produced
as output values which can be used as input to other output commands.
The list of atom attributes is the same as for the "dump
custom"_dump.html command.
The "compute property/local"_compute_property_local.html command takes
a list of one or more pre-defined local attributes (bond info, angle
info, etc) and stores the values in a local vector or array. These
are produced as output values which can be used as input to other
output commands.
Fixes that process output quantities :h5,link(fixprocoutput)
The "fix vector"_fix_vector.html command can create global vectors as
output from global scalars as input, accumulating them one element at
a time.
The "fix ave/atom"_fix_ave_atom.html command performs time-averaging
of per-atom vectors. The per-atom quantities can be atom attributes
such as position, velocity, force. They can also be per-atom
quantities calculated by a "compute"_compute.html, by a
"fix"_fix.html, or by an atom-style "variable"_variable.html. The
time-averaged per-atom output of this fix can be used as input to
other output commands.
The "fix store/state"_fix_store_state.html command can archive one or
more per-atom attributes at a particular time, so that the old values
can be used in a future calculation or output. The list of atom
attributes is the same as for the "dump custom"_dump.html command,
including per-atom quantities calculated by a "compute"_compute.html,
by a "fix"_fix.html, or by an atom-style "variable"_variable.html.
The output of this fix can be used as input to other output commands.
Computes that generate values to output :h5,link(compute)
Every "compute"_compute.html in LAMMPS produces either global or
per-atom or local values. The values can be scalars or vectors or
arrays of data. These values can be output using the other commands
described in this section. The doc page for each compute command
describes what it produces. Computes that produce per-atom or local
values have the word "atom" or "local" in their style name. Computes
without the word "atom" or "local" produce global values.
Fixes that generate values to output :h5,link(fix)
Some "fixes"_fix.html in LAMMPS produces either global or per-atom or
local values which can be accessed by other commands. The values can
be scalars or vectors or arrays of data. These values can be output
using the other commands described in this section. The doc page for
each fix command tells whether it produces any output quantities and
describes them.
Variables that generate values to output :h5,link(variable)
"Variables"_variable.html defined in an input script can store one or
more strings. But equal-style, vector-style, and atom-style or
atomfile-style variables generate a global scalar value, global vector
or values, or a per-atom vector, respectively, when accessed. The
formulas used to define these variables can contain references to the
thermodynamic keywords and to global and per-atom data generated by
computes, fixes, and other variables. The values generated by
variables can be used as input to and thus output by the other
commands described in this section.
Summary table of output options and data flow between commands :h5,link(table)
This table summarizes the various commands that can be used for
generating output from LAMMPS. Each command produces output data of
some kind and/or writes data to a file. Most of the commands can take
data from other commands as input. Thus you can link many of these
commands together in pipeline form, where data produced by one command
is used as input to another command and eventually written to the
screen or to a file. Note that to hook two commands together the
output and input data types must match, e.g. global/per-atom/local
data and scalar/vector/array data.
Also note that, as described above, when a command takes a scalar as
input, that could be an element of a vector or array. Likewise a
vector input could be a column of an array.
Command: Input: Output:
"thermo_style custom"_thermo_style.html: global scalars: screen, log file:
"dump custom"_dump.html: per-atom vectors: dump file:
"dump local"_dump.html: local vectors: dump file:
"fix print"_fix_print.html: global scalar from variable: screen, file:
"print"_print.html: global scalar from variable: screen:
"computes"_compute.html: N/A: global/per-atom/local scalar/vector/array:
"fixes"_fix.html: N/A: global/per-atom/local scalar/vector/array:
"variables"_variable.html: global scalars and vectors, per-atom vectors: global scalar and vector, per-atom vector:
"compute reduce"_compute_reduce.html: per-atom/local vectors: global scalar/vector:
"compute slice"_compute_slice.html: global vectors/arrays: global vector/array:
"compute property/atom"_compute_property_atom.html: per-atom vectors: per-atom vector/array:
"compute property/local"_compute_property_local.html: local vectors: local vector/array:
"fix vector"_fix_vector.html: global scalars: global vector:
"fix ave/atom"_fix_ave_atom.html: per-atom vectors: per-atom vector/array:
"fix ave/time"_fix_ave_time.html: global scalars/vectors: global scalar/vector/array, file:
"fix ave/chunk"_fix_ave_chunk.html: per-atom vectors: global array, file:
"fix ave/histo"_fix_ave_histo.html: global/per-atom/local scalars and vectors: global array, file:
"fix ave/correlate"_fix_ave_correlate.html: global scalars: global array, file:
"fix store/state"_fix_store_state.html: per-atom vectors: per-atom vector/array :tb(c=3,s=:)
:line
6.16 Thermostatting, barostatting, and computing temperature :link(howto_16),h4
Thermostatting means controlling the temperature of particles in an MD
simulation. Barostatting means controlling the pressure. Since the
pressure includes a kinetic component due to particle velocities, both
these operations require calculation of the temperature. Typically a
target temperature (T) and/or pressure (P) is specified by the user,
and the thermostat or barostat attempts to equilibrate the system to
the requested T and/or P.
Temperature is computed as kinetic energy divided by some number of
degrees of freedom (and the Boltzmann constant). Since kinetic energy
is a function of particle velocity, there is often a need to
distinguish between a particle's advection velocity (due to some
aggregate motion of particles) and its thermal velocity. The sum of
the two is the particle's total velocity, but the latter is often what
is wanted to compute a temperature.
LAMMPS has several options for computing temperatures, any of which
can be used in thermostatting and barostatting. These "compute
commands"_compute.html calculate temperature, and the "compute
pressure"_compute_pressure.html command calculates pressure.
"compute temp"_compute_temp.html
"compute temp/sphere"_compute_temp_sphere.html
"compute temp/asphere"_compute_temp_asphere.html
"compute temp/com"_compute_temp_com.html
"compute temp/deform"_compute_temp_deform.html
"compute temp/partial"_compute_temp_partial.html
"compute temp/profile"_compute_temp_profile.html
"compute temp/ramp"_compute_temp_ramp.html
"compute temp/region"_compute_temp_region.html :ul
All but the first 3 calculate velocity biases directly (e.g. advection
velocities) that are removed when computing the thermal temperature.
"Compute temp/sphere"_compute_temp_sphere.html and "compute
temp/asphere"_compute_temp_asphere.html compute kinetic energy for
finite-size particles that includes rotational degrees of freedom.
They both allow for velocity biases indirectly, via an optional extra
argument, another temperature compute that subtracts a velocity bias.
This allows the translational velocity of spherical or aspherical
particles to be adjusted in prescribed ways.
Thermostatting in LAMMPS is performed by "fixes"_fix.html, or in one
case by a pair style. Several thermostatting fixes are available:
Nose-Hoover (nvt), Berendsen, CSVR, Langevin, and direct rescaling
(temp/rescale). Dissipative particle dynamics (DPD) thermostatting
can be invoked via the {dpd/tstat} pair style:
"fix nvt"_fix_nh.html
"fix nvt/sphere"_fix_nvt_sphere.html
"fix nvt/asphere"_fix_nvt_asphere.html
"fix nvt/sllod"_fix_nvt_sllod.html
"fix temp/berendsen"_fix_temp_berendsen.html
"fix temp/csvr"_fix_temp_csvr.html
"fix langevin"_fix_langevin.html
"fix temp/rescale"_fix_temp_rescale.html
"pair_style dpd/tstat"_pair_dpd.html :ul
"Fix nvt"_fix_nh.html only thermostats the translational velocity of
particles. "Fix nvt/sllod"_fix_nvt_sllod.html also does this, except
that it subtracts out a velocity bias due to a deforming box and
integrates the SLLOD equations of motion. See the "NEMD
simulations"_#howto_13 section of this page for further details. "Fix
nvt/sphere"_fix_nvt_sphere.html and "fix
nvt/asphere"_fix_nvt_asphere.html thermostat not only translation
velocities but also rotational velocities for spherical and aspherical
particles.
DPD thermostatting alters pairwise interactions in a manner analogous
to the per-particle thermostatting of "fix
langevin"_fix_langevin.html.
Any of the thermostatting fixes can use temperature computes that
remove bias which has two effects. First, the current calculated
temperature, which is compared to the requested target temperature, is
calculated with the velocity bias removed. Second, the thermostat
adjusts only the thermal temperature component of the particle's
velocities, which are the velocities with the bias removed. The
removed bias is then added back to the adjusted velocities. See the
doc pages for the individual fixes and for the
"fix_modify"_fix_modify.html command for instructions on how to assign
a temperature compute to a thermostatting fix. For example, you can
apply a thermostat to only the x and z components of velocity by using
it in conjunction with "compute
temp/partial"_compute_temp_partial.html. Of you could thermostat only
the thermal temperature of a streaming flow of particles without
affecting the streaming velocity, by using "compute
temp/profile"_compute_temp_profile.html.
NOTE: Only the nvt fixes perform time integration, meaning they update
the velocities and positions of particles due to forces and velocities
respectively. The other thermostat fixes only adjust velocities; they
do NOT perform time integration updates. Thus they should be used in
conjunction with a constant NVE integration fix such as these:
"fix nve"_fix_nve.html
"fix nve/sphere"_fix_nve_sphere.html
"fix nve/asphere"_fix_nve_asphere.html :ul
Barostatting in LAMMPS is also performed by "fixes"_fix.html. Two
barosttating methods are currently available: Nose-Hoover (npt and
nph) and Berendsen:
"fix npt"_fix_nh.html
"fix npt/sphere"_fix_npt_sphere.html
"fix npt/asphere"_fix_npt_asphere.html
"fix nph"_fix_nh.html
"fix press/berendsen"_fix_press_berendsen.html :ul
The "fix npt"_fix_nh.html commands include a Nose-Hoover thermostat
and barostat. "Fix nph"_fix_nh.html is just a Nose/Hoover barostat;
it does no thermostatting. Both "fix nph"_fix_nh.html and "fix
press/berendsen"_fix_press_berendsen.html can be used in conjunction
with any of the thermostatting fixes.
As with the thermostats, "fix npt"_fix_nh.html and "fix
nph"_fix_nh.html only use translational motion of the particles in
computing T and P and performing thermo/barostatting. "Fix
npt/sphere"_fix_npt_sphere.html and "fix
npt/asphere"_fix_npt_asphere.html thermo/barostat using not only
translation velocities but also rotational velocities for spherical
and aspherical particles.
All of the barostatting fixes use the "compute
pressure"_compute_pressure.html compute to calculate a current
pressure. By default, this compute is created with a simple "compute
temp"_compute_temp.html (see the last argument of the "compute
pressure"_compute_pressure.html command), which is used to calculated
the kinetic component of the pressure. The barostatting fixes can
also use temperature computes that remove bias for the purpose of
computing the kinetic component which contributes to the current
pressure. See the doc pages for the individual fixes and for the
"fix_modify"_fix_modify.html command for instructions on how to assign
a temperature or pressure compute to a barostatting fix.
NOTE: As with the thermostats, the Nose/Hoover methods ("fix
npt"_fix_nh.html and "fix nph"_fix_nh.html) perform time integration.
"Fix press/berendsen"_fix_press_berendsen.html does NOT, so it should
be used with one of the constant NVE fixes or with one of the NVT
fixes.
Finally, thermodynamic output, which can be setup via the
"thermo_style"_thermo_style.html command, often includes temperature
and pressure values. As explained on the doc page for the
"thermo_style"_thermo_style.html command, the default T and P are
setup by the thermo command itself. They are NOT the ones associated
with any thermostatting or barostatting fix you have defined or with
any compute that calculates a temperature or pressure. Thus if you
want to view these values of T and P, you need to specify them
explicitly via a "thermo_style custom"_thermo_style.html command. Or
you can use the "thermo_modify"_thermo_modify.html command to
re-define what temperature or pressure compute is used for default
thermodynamic output.
:line
6.17 Walls :link(howto_17),h4
Walls in an MD simulation are typically used to bound particle motion,
i.e. to serve as a boundary condition.
Walls in LAMMPS can be of rough (made of particles) or idealized
surfaces. Ideal walls can be smooth, generating forces only in the
normal direction, or frictional, generating forces also in the
tangential direction.
Rough walls, built of particles, can be created in various ways. The
particles themselves can be generated like any other particle, via the
"lattice"_lattice.html and "create_atoms"_create_atoms.html commands,
or read in via the "read_data"_read_data.html command.
Their motion can be constrained by many different commands, so that
they do not move at all, move together as a group at constant velocity
or in response to a net force acting on them, move in a prescribed
fashion (e.g. rotate around a point), etc. Note that if a time
integration fix like "fix nve"_fix_nve.html or "fix nvt"_fix_nh.html
is not used with the group that contains wall particles, their
positions and velocities will not be updated.
"fix aveforce"_fix_aveforce.html - set force on particles to average value, so they move together
"fix setforce"_fix_setforce.html - set force on particles to a value, e.g. 0.0
"fix freeze"_fix_freeze.html - freeze particles for use as granular walls
"fix nve/noforce"_fix_nve_noforce.html - advect particles by their velocity, but without force
"fix move"_fix_move.html - prescribe motion of particles by a linear velocity, oscillation, rotation, variable :ul
The "fix move"_fix_move.html command offers the most generality, since
the motion of individual particles can be specified with
"variable"_variable.html formula which depends on time and/or the
particle position.
For rough walls, it may be useful to turn off pairwise interactions
between wall particles via the "neigh_modify
exclude"_neigh_modify.html command.
Rough walls can also be created by specifying frozen particles that do
not move and do not interact with mobile particles, and then tethering
other particles to the fixed particles, via a "bond"_bond_style.html.
The bonded particles do interact with other mobile particles.
Idealized walls can be specified via several fix commands. "Fix
wall/gran"_fix_wall_gran.html creates frictional walls for use with
granular particles; all the other commands create smooth walls.
"fix wall/reflect"_fix_wall_reflect.html - reflective flat walls
"fix wall/lj93"_fix_wall.html - flat walls, with Lennard-Jones 9/3 potential
"fix wall/lj126"_fix_wall.html - flat walls, with Lennard-Jones 12/6 potential
"fix wall/colloid"_fix_wall.html - flat walls, with "pair_style colloid"_pair_colloid.html potential
"fix wall/harmonic"_fix_wall.html - flat walls, with repulsive harmonic spring potential
"fix wall/region"_fix_wall_region.html - use region surface as wall
"fix wall/gran"_fix_wall_gran.html - flat or curved walls with "pair_style granular"_pair_gran.html potential :ul
The {lj93}, {lj126}, {colloid}, and {harmonic} styles all allow the
flat walls to move with a constant velocity, or oscillate in time.
The "fix wall/region"_fix_wall_region.html command offers the most
generality, since the region surface is treated as a wall, and the
geometry of the region can be a simple primitive volume (e.g. a
sphere, or cube, or plane), or a complex volume made from the union
and intersection of primitive volumes. "Regions"_region.html can also
specify a volume "interior" or "exterior" to the specified primitive
shape or {union} or {intersection}. "Regions"_region.html can also be
"dynamic" meaning they move with constant velocity, oscillate, or
rotate.
The only frictional idealized walls currently in LAMMPS are flat or
curved surfaces specified by the "fix wall/gran"_fix_wall_gran.html
command. At some point we plan to allow regoin surfaces to be used as
frictional walls, as well as triangulated surfaces.
:line
6.18 Elastic constants :link(howto_18),h4
Elastic constants characterize the stiffness of a material. The formal
definition is provided by the linear relation that holds between the
stress and strain tensors in the limit of infinitesimal deformation.
In tensor notation, this is expressed as s_ij = C_ijkl * e_kl, where
the repeated indices imply summation. s_ij are the elements of the
symmetric stress tensor. e_kl are the elements of the symmetric strain
tensor. C_ijkl are the elements of the fourth rank tensor of elastic
constants. In three dimensions, this tensor has 3^4=81 elements. Using
Voigt notation, the tensor can be written as a 6x6 matrix, where C_ij
is now the derivative of s_i w.r.t. e_j. Because s_i is itself a
derivative w.r.t. e_i, it follows that C_ij is also symmetric, with at
most 7*6/2 = 21 distinct elements.
At zero temperature, it is easy to estimate these derivatives by
deforming the simulation box in one of the six directions using the
"change_box"_change_box.html command and measuring the change in the
stress tensor. A general-purpose script that does this is given in the
examples/elastic directory described in "this
section"_Section_example.html.
Calculating elastic constants at finite temperature is more
challenging, because it is necessary to run a simulation that perfoms
time averages of differential properties. One way to do this is to
measure the change in average stress tensor in an NVT simulations when
the cell volume undergoes a finite deformation. In order to balance
the systematic and statistical errors in this method, the magnitude of
the deformation must be chosen judiciously, and care must be taken to
fully equilibrate the deformed cell before sampling the stress
tensor. Another approach is to sample the triclinic cell fluctuations
that occur in an NPT simulation. This method can also be slow to
converge and requires careful post-processing "(Shinoda)"_#Shinoda1
:line
6.19 Library interface to LAMMPS :link(howto_19),h4
As described in "Section 2.5"_Section_start.html#start_5, LAMMPS
can be built as a library, so that it can be called by another code,
used in a "coupled manner"_Section_howto.html#howto_10 with other
codes, or driven through a "Python interface"_Section_python.html.
All of these methodologies use a C-style interface to LAMMPS that is
provided in the files src/library.cpp and src/library.h. The
functions therein have a C-style argument list, but contain C++ code
you could write yourself in a C++ application that was invoking LAMMPS
directly. The C++ code in the functions illustrates how to invoke
internal LAMMPS operations. Note that LAMMPS classes are defined
within a LAMMPS namespace (LAMMPS_NS) if you use them from another C++
application.
Library.cpp contains these functions for creating and destroying an
instance of LAMMPS and sending it commands to execute. See the
documentation in the src/library.cpp file for details:
void lammps_open(int, char **, MPI_Comm, void **)
void lammps_open_no_mpi(int, char **, void **)
void lammps_close(void *)
int lammps_version(void *)
void lammps_file(void *, char *)
char *lammps_command(void *, char *)
void lammps_commands_list(void *, int, char **)
void lammps_commands_string(void *, char *)
void lammps_free(void *) :pre
The lammps_open() function is used to initialize LAMMPS, passing in a
list of strings as if they were "command-line
-arguments"_Section_start.html#start_7 when LAMMPS is run in
+arguments"_Section_start.html#start_6 when LAMMPS is run in
stand-alone mode from the command line, and a MPI communicator for
LAMMPS to run under. It returns a ptr to the LAMMPS object that is
created, and which is used in subsequent library calls. The
lammps_open() function can be called multiple times, to create
multiple instances of LAMMPS.
LAMMPS will run on the set of processors in the communicator. This
means the calling code can run LAMMPS on all or a subset of
processors. For example, a wrapper script might decide to alternate
between LAMMPS and another code, allowing them both to run on all the
processors. Or it might allocate half the processors to LAMMPS and
half to the other code and run both codes simultaneously before
syncing them up periodically. Or it might instantiate multiple
instances of LAMMPS to perform different calculations.
The lammps_open_no_mpi() function is similar except that no MPI
communicator is passed from the caller. Instead, MPI_COMM_WORLD is
used to instantiate LAMMPS, and MPI is initialized if necessary.
The lammps_close() function is used to shut down an instance of LAMMPS
and free all its memory.
The lammps_version() function can be used to determined the specific
version of the underlying LAMMPS code. This is particularly useful
when loading LAMMPS as a shared library via dlopen(). The code using
the library interface can than use this information to adapt to
changes to the LAMMPS command syntax between versions. The returned
LAMMPS version code is an integer (e.g. 2 Sep 2015 results in
20150902) that grows with every new LAMMPS version.
The lammps_file(), lammps_command(), lammps_commands_list(), and
lammps_commands_string() functions are used to pass one or more
commands to LAMMPS to execute, the same as if they were coming from an
input script.
Via these functions, the calling code can read or generate a series of
LAMMPS commands one or multiple at a time and pass it thru the library
interface to setup a problem and then run it in stages. The caller
can interleave the command function calls with operations it performs,
calls to extract information from or set information within LAMMPS, or
calls to another code's library.
The lammps_file() function passes the filename of an input script.
The lammps_command() function passes a single command as a string.
The lammps_commands_list() function passes multiple commands in a
char** list. In both lammps_command() and lammps_commands_list(),
individual commands may or may not have a trailing newline. The
lammps_commands_string() function passes multiple commands
concatenated into one long string, separated by newline characters.
In both lammps_commands_list() and lammps_commands_string(), a single
command can be spread across multiple lines, if the last printable
character of all but the last line is "&", the same as if the lines
appeared in an input script.
The lammps_free() function is a clean-up function to free memory that
the library allocated previously via other function calls. See
comments in src/library.cpp file for which other functions need this
clean-up.
Library.cpp also contains these functions for extracting information
from LAMMPS and setting value within LAMMPS. Again, see the
documentation in the src/library.cpp file for details, including
which quantities can be queried by name:
void *lammps_extract_global(void *, char *)
void lammps_extract_box(void *, double *, double *,
double *, double *, double *, int *, int *)
void *lammps_extract_atom(void *, char *)
void *lammps_extract_compute(void *, char *, int, int)
void *lammps_extract_fix(void *, char *, int, int, int, int)
void *lammps_extract_variable(void *, char *, char *) :pre
void lammps_reset_box(void *, double *, double *, double, double, double)
int lammps_set_variable(void *, char *, char *) :pre
double lammps_get_thermo(void *, char *)
int lammps_get_natoms(void *)
void lammps_gather_atoms(void *, double *)
void lammps_scatter_atoms(void *, double *) :pre
void lammps_create_atoms(void *, int, tagint *, int *, double *, double *,
imageint *, int) :pre
The extract functions return a pointer to various global or per-atom
quantities stored in LAMMPS or to values calculated by a compute, fix,
or variable. The pointer returned by the extract_global() function
can be used as a permanent reference to a value which may change. For
the extract_atom() method, see the extract() method in the
src/atom.cpp file for a list of valid per-atom properties. New names
could easily be added if the property you want is not listed. For the
other extract functions, the underlying storage may be reallocated as
LAMMPS runs, so you need to re-call the function to assure a current
pointer or returned value(s).
The lammps_reset_box() function resets the size and shape of the
simulation box, e.g. as part of restoring a previously extracted and
saved state of a simulation.
The lammps_set_variable() function can set an existing string-style
variable to a new string value, so that subsequent LAMMPS commands can
access the variable.
The lammps_get_thermo() function returns the current value of a thermo
keyword as a double precision value.
The lammps_get_natoms() function returns the total number of atoms in
the system and can be used by the caller to allocate space for the
lammps_gather_atoms() and lammps_scatter_atoms() functions. The
gather function collects peratom info of the requested type (atom
coords, types, forces, etc) from all processors, orders them by atom
ID, and returns a full list to each calling processor. The scatter
function does the inverse. It distributes the same peratom values,
passed by the caller, to each atom owned by individual processors.
Both methods are thus a means to extract or assign (overwrite) any
peratom quantities within LAMMPS. See the extract() method in the
src/atom.cpp file for a list of valid per-atom properties. New names
could easily be added if the property you want is not listed.
A special treatment is applied for accessing image flags via the
"image" property. Image flags are stored in a packed format with all
three image flags stored in a single integer. When signaling to access
the image flags as 3 individual values per atom instead of 1, the data
is transparently packed or unpacked by the library interface.
The lammps_create_atoms() function takes a list of N atoms as input
with atom types and coords (required), an optionally atom IDs and
velocities and image flags. It uses the coords of each atom to assign
it as a new atom to the processor that owns it. This function is
useful to add atoms to a simulation or (in tandem with
lammps_reset_box()) to restore a previously extracted and saved state
of a simulation. Additional properties for the new atoms can then be
assigned via the lammps_scatter_atoms() or lammps_extract_atom()
functions.
The examples/COUPLE and python directories have example C++ and C and
Python codes which show how a driver code can link to LAMMPS as a
library, run LAMMPS on a subset of processors, grab data from LAMMPS,
change it, and put it back into LAMMPS.
NOTE: You can write code for additional functions as needed to define
how your code talks to LAMMPS and add them to src/library.cpp and
src/library.h, as well as to the "Python
interface"_Section_python.html. The added functions can access or
change any LAMMPS data you wish.
:line
6.20 Calculating thermal conductivity :link(howto_20),h4
The thermal conductivity kappa of a material can be measured in at
least 4 ways using various options in LAMMPS. See the examples/KAPPA
directory for scripts that implement the 4 methods discussed here for
a simple Lennard-Jones fluid model. Also, see "this
section"_Section_howto.html#howto_21 of the manual for an analogous
discussion for viscosity.
The thermal conductivity tensor kappa is a measure of the propensity
of a material to transmit heat energy in a diffusive manner as given
by Fourier's law
J = -kappa grad(T)
where J is the heat flux in units of energy per area per time and
grad(T) is the spatial gradient of temperature. The thermal
conductivity thus has units of energy per distance per time per degree
K and is often approximated as an isotropic quantity, i.e. as a
scalar.
The first method is to setup two thermostatted regions at opposite
ends of a simulation box, or one in the middle and one at the end of a
periodic box. By holding the two regions at different temperatures
with a "thermostatting fix"_Section_howto.html#howto_13, the energy
added to the hot region should equal the energy subtracted from the
cold region and be proportional to the heat flux moving between the
regions. See the papers by "Ikeshoji and Hafskjold"_#howto-Ikeshoji
and "Wirnsberger et al"_#howto-Wirnsberger for details of this idea.
Note that thermostatting fixes such as "fix nvt"_fix_nh.html, "fix
langevin"_fix_langevin.html, and "fix
temp/rescale"_fix_temp_rescale.html store the cumulative energy they
add/subtract.
Alternatively, as a second method, the "fix heat"_fix_heat.html or
"fix ehex"_fix_ehex.html commands can be used in place of thermostats
on each of two regions to add/subtract specified amounts of energy to
both regions. In both cases, the resulting temperatures of the two
regions can be monitored with the "compute temp/region" command and
the temperature profile of the intermediate region can be monitored
with the "fix ave/chunk"_fix_ave_chunk.html and "compute
ke/atom"_compute_ke_atom.html commands.
The third method is to perform a reverse non-equilibrium MD simulation
using the "fix thermal/conductivity"_fix_thermal_conductivity.html
command which implements the rNEMD algorithm of Muller-Plathe.
Kinetic energy is swapped between atoms in two different layers of the
simulation box. This induces a temperature gradient between the two
layers which can be monitored with the "fix
ave/chunk"_fix_ave_chunk.html and "compute
ke/atom"_compute_ke_atom.html commands. The fix tallies the
cumulative energy transfer that it performs. See the "fix
thermal/conductivity"_fix_thermal_conductivity.html command for
details.
The fourth method is based on the Green-Kubo (GK) formula which
relates the ensemble average of the auto-correlation of the heat flux
to kappa. The heat flux can be calculated from the fluctuations of
per-atom potential and kinetic energies and per-atom stress tensor in
a steady-state equilibrated simulation. This is in contrast to the
two preceding non-equilibrium methods, where energy flows continuously
between hot and cold regions of the simulation box.
The "compute heat/flux"_compute_heat_flux.html command can calculate
the needed heat flux and describes how to implement the Green_Kubo
formalism using additional LAMMPS commands, such as the "fix
ave/correlate"_fix_ave_correlate.html command to calculate the needed
auto-correlation. See the doc page for the "compute
heat/flux"_compute_heat_flux.html command for an example input script
that calculates the thermal conductivity of solid Ar via the GK
formalism.
:line
6.21 Calculating viscosity :link(howto_21),h4
The shear viscosity eta of a fluid can be measured in at least 5 ways
using various options in LAMMPS. See the examples/VISCOSITY directory
for scripts that implement the 5 methods discussed here for a simple
Lennard-Jones fluid model. Also, see "this
section"_Section_howto.html#howto_20 of the manual for an analogous
discussion for thermal conductivity.
Eta is a measure of the propensity of a fluid to transmit momentum in
a direction perpendicular to the direction of velocity or momentum
flow. Alternatively it is the resistance the fluid has to being
sheared. It is given by
J = -eta grad(Vstream)
where J is the momentum flux in units of momentum per area per time.
and grad(Vstream) is the spatial gradient of the velocity of the fluid
moving in another direction, normal to the area through which the
momentum flows. Viscosity thus has units of pressure-time.
The first method is to perform a non-equilibrium MD (NEMD) simulation
by shearing the simulation box via the "fix deform"_fix_deform.html
command, and using the "fix nvt/sllod"_fix_nvt_sllod.html command to
thermostat the fluid via the SLLOD equations of motion.
Alternatively, as a second method, one or more moving walls can be
used to shear the fluid in between them, again with some kind of
thermostat that modifies only the thermal (non-shearing) components of
velocity to prevent the fluid from heating up.
In both cases, the velocity profile setup in the fluid by this
procedure can be monitored by the "fix
ave/chunk"_fix_ave_chunk.html command, which determines
grad(Vstream) in the equation above. E.g. the derivative in the
y-direction of the Vx component of fluid motion or grad(Vstream) =
dVx/dy. The Pxy off-diagonal component of the pressure or stress
tensor, as calculated by the "compute pressure"_compute_pressure.html
command, can also be monitored, which is the J term in the equation
above. See "this section"_Section_howto.html#howto_13 of the manual
for details on NEMD simulations.
The third method is to perform a reverse non-equilibrium MD simulation
using the "fix viscosity"_fix_viscosity.html command which implements
the rNEMD algorithm of Muller-Plathe. Momentum in one dimension is
swapped between atoms in two different layers of the simulation box in
a different dimension. This induces a velocity gradient which can be
monitored with the "fix ave/chunk"_fix_ave_chunk.html command.
The fix tallies the cumulative momentum transfer that it performs.
See the "fix viscosity"_fix_viscosity.html command for details.
The fourth method is based on the Green-Kubo (GK) formula which
relates the ensemble average of the auto-correlation of the
stress/pressure tensor to eta. This can be done in a fully
equilibrated simulation which is in contrast to the two preceding
non-equilibrium methods, where momentum flows continuously through the
simulation box.
Here is an example input script that calculates the viscosity of
liquid Ar via the GK formalism:
# Sample LAMMPS input script for viscosity of liquid Ar :pre
units real
variable T equal 86.4956
variable V equal vol
variable dt equal 4.0
variable p equal 400 # correlation length
variable s equal 5 # sample interval
variable d equal $p*$s # dump interval :pre
# convert from LAMMPS real units to SI :pre
variable kB equal 1.3806504e-23 # \[J/K/] Boltzmann
variable atm2Pa equal 101325.0
variable A2m equal 1.0e-10
variable fs2s equal 1.0e-15
variable convert equal $\{atm2Pa\}*$\{atm2Pa\}*$\{fs2s\}*$\{A2m\}*$\{A2m\}*$\{A2m\} :pre
# setup problem :pre
dimension 3
boundary p p p
lattice fcc 5.376 orient x 1 0 0 orient y 0 1 0 orient z 0 0 1
region box block 0 4 0 4 0 4
create_box 1 box
create_atoms 1 box
mass 1 39.948
pair_style lj/cut 13.0
pair_coeff * * 0.2381 3.405
timestep $\{dt\}
thermo $d :pre
# equilibration and thermalization :pre
velocity all create $T 102486 mom yes rot yes dist gaussian
fix NVT all nvt temp $T $T 10 drag 0.2
run 8000 :pre
# viscosity calculation, switch to NVE if desired :pre
#unfix NVT
#fix NVE all nve :pre
reset_timestep 0
variable pxy equal pxy
variable pxz equal pxz
variable pyz equal pyz
fix SS all ave/correlate $s $p $d &
v_pxy v_pxz v_pyz type auto file S0St.dat ave running
variable scale equal $\{convert\}/($\{kB\}*$T)*$V*$s*$\{dt\}
variable v11 equal trap(f_SS\[3\])*$\{scale\}
variable v22 equal trap(f_SS\[4\])*$\{scale\}
variable v33 equal trap(f_SS\[5\])*$\{scale\}
thermo_style custom step temp press v_pxy v_pxz v_pyz v_v11 v_v22 v_v33
run 100000
variable v equal (v_v11+v_v22+v_v33)/3.0
variable ndens equal count(all)/vol
print "average viscosity: $v \[Pa.s\] @ $T K, $\{ndens\} /A^3" :pre
The fifth method is related to the above Green-Kubo method,
but uses the Einstein formulation, analogous to the Einstein
mean-square-displacement formulation for self-diffusivity. The
time-integrated momentum fluxes play the role of Cartesian
coordinates, whose mean-square displacement increases linearly
with time at sufficiently long times.
:line
6.22 Calculating a diffusion coefficient :link(howto_22),h4
The diffusion coefficient D of a material can be measured in at least
2 ways using various options in LAMMPS. See the examples/DIFFUSE
directory for scripts that implement the 2 methods discussed here for
a simple Lennard-Jones fluid model.
The first method is to measure the mean-squared displacement (MSD) of
the system, via the "compute msd"_compute_msd.html command. The slope
of the MSD versus time is proportional to the diffusion coefficient.
The instantaneous MSD values can be accumulated in a vector via the
"fix vector"_fix_vector.html command, and a line fit to the vector to
compute its slope via the "variable slope"_variable.html function, and
thus extract D.
The second method is to measure the velocity auto-correlation function
(VACF) of the system, via the "compute vacf"_compute_vacf.html
command. The time-integral of the VACF is proportional to the
diffusion coefficient. The instantaneous VACF values can be
accumulated in a vector via the "fix vector"_fix_vector.html command,
and time integrated via the "variable trap"_variable.html function,
and thus extract D.
:line
6.23 Using chunks to calculate system properties :link(howto_23),h4
In LAMMS, "chunks" are collections of atoms, as defined by the
"compute chunk/atom"_compute_chunk_atom.html command, which assigns
each atom to a chunk ID (or to no chunk at all). The number of chunks
and the assignment of chunk IDs to atoms can be static or change over
time. Examples of "chunks" are molecules or spatial bins or atoms
with similar values (e.g. coordination number or potential energy).
The per-atom chunk IDs can be used as input to two other kinds of
commands, to calculate various properties of a system:
"fix ave/chunk"_fix_ave_chunk.html
any of the "compute */chunk"_compute.html commands :ul
Here, each of the 3 kinds of chunk-related commands is briefly
overviewed. Then some examples are given of how to compute different
properties with chunk commands.
Compute chunk/atom command: :h5
This compute can assign atoms to chunks of various styles. Only atoms
in the specified group and optional specified region are assigned to a
chunk. Here are some possible chunk definitions:
atoms in same molecule | chunk ID = molecule ID |
atoms of same atom type | chunk ID = atom type |
all atoms with same atom property (charge, radius, etc) | chunk ID = output of compute property/atom |
atoms in same cluster | chunk ID = output of "compute cluster/atom"_compute_cluster_atom.html command |
atoms in same spatial bin | chunk ID = bin ID |
atoms in same rigid body | chunk ID = molecule ID used to define rigid bodies |
atoms with similar potential energy | chunk ID = output of "compute pe/atom"_compute_pe_atom.html |
atoms with same local defect structure | chunk ID = output of "compute centro/atom"_compute_centro_atom.html or "compute coord/atom"_compute_coord_atom.html command :tb(s=|,c=2)
Note that chunk IDs are integer values, so for atom properties or
computes that produce a floating point value, they will be truncated
to an integer. You could also use the compute in a variable that
scales the floating point value to spread it across multiple integers.
Spatial bins can be of various kinds, e.g. 1d bins = slabs, 2d bins =
pencils, 3d bins = boxes, spherical bins, cylindrical bins.
This compute also calculates the number of chunks {Nchunk}, which is
used by other commands to tally per-chunk data. {Nchunk} can be a
static value or change over time (e.g. the number of clusters). The
chunk ID for an individual atom can also be static (e.g. a molecule
ID), or dynamic (e.g. what spatial bin an atom is in as it moves).
Note that this compute allows the per-atom output of other
"computes"_compute.html, "fixes"_fix.html, and
"variables"_variable.html to be used to define chunk IDs for each
atom. This means you can write your own compute or fix to output a
per-atom quantity to use as chunk ID. See
"Section 10"_Section_modify.html of the documentation for how to
do this. You can also define a "per-atom variable"_variable.html in
the input script that uses a formula to generate a chunk ID for each
atom.
Fix ave/chunk command: :h5
This fix takes the ID of a "compute
chunk/atom"_compute_chunk_atom.html command as input. For each chunk,
it then sums one or more specified per-atom values over the atoms in
each chunk. The per-atom values can be any atom property, such as
velocity, force, charge, potential energy, kinetic energy, stress,
etc. Additional keywords are defined for per-chunk properties like
density and temperature. More generally any per-atom value generated
by other "computes"_compute.html, "fixes"_fix.html, and "per-atom
variables"_variable.html, can be summed over atoms in each chunk.
Similar to other averaging fixes, this fix allows the summed per-chunk
values to be time-averaged in various ways, and output to a file. The
fix produces a global array as output with one row of values per
chunk.
Compute */chunk commands: :h5
Currently the following computes operate on chunks of atoms to produce
per-chunk values.
"compute com/chunk"_compute_com_chunk.html
"compute gyration/chunk"_compute_gyration_chunk.html
"compute inertia/chunk"_compute_inertia_chunk.html
"compute msd/chunk"_compute_msd_chunk.html
"compute property/chunk"_compute_property_chunk.html
"compute temp/chunk"_compute_temp_chunk.html
"compute torque/chunk"_compute_vcm_chunk.html
"compute vcm/chunk"_compute_vcm_chunk.html :ul
They each take the ID of a "compute
chunk/atom"_compute_chunk_atom.html command as input. As their names
indicate, they calculate the center-of-mass, radius of gyration,
moments of inertia, mean-squared displacement, temperature, torque,
and velocity of center-of-mass for each chunk of atoms. The "compute
property/chunk"_compute_property_chunk.html command can tally the
count of atoms in each chunk and extract other per-chunk properties.
The reason these various calculations are not part of the "fix
ave/chunk command"_fix_ave_chunk.html, is that each requires a more
complicated operation than simply summing and averaging over per-atom
values in each chunk. For example, many of them require calculation
of a center of mass, which requires summing mass*position over the
atoms and then dividing by summed mass.
All of these computes produce a global vector or global array as
output, wih one or more values per chunk. They can be used
in various ways:
As input to the "fix ave/time"_fix_ave_time.html command, which can
write the values to a file and optionally time average them. :ulb,l
As input to the "fix ave/histo"_fix_ave_histo.html command to
histogram values across chunks. E.g. a histogram of cluster sizes or
molecule diffusion rates. :l
As input to special functions of "equal-style
variables"_variable.html, like sum() and max(). E.g. to find the
largest cluster or fastest diffusing molecule. :l
:ule
Example calculations with chunks :h5
Here are examples using chunk commands to calculate various
properties:
(1) Average velocity in each of 1000 2d spatial bins:
compute cc1 all chunk/atom bin/2d x 0.0 0.1 y lower 0.01 units reduced
fix 1 all ave/chunk 100 10 1000 cc1 vx vy file tmp.out :pre
(2) Temperature in each spatial bin, after subtracting a flow
velocity:
compute cc1 all chunk/atom bin/2d x 0.0 0.1 y lower 0.1 units reduced
compute vbias all temp/profile 1 0 0 y 10
fix 1 all ave/chunk 100 10 1000 cc1 temp bias vbias file tmp.out :pre
(3) Center of mass of each molecule:
compute cc1 all chunk/atom molecule
compute myChunk all com/chunk cc1
fix 1 all ave/time 100 1 100 c_myChunk\[*\] file tmp.out mode vector :pre
(4) Total force on each molecule and ave/max across all molecules:
compute cc1 all chunk/atom molecule
fix 1 all ave/chunk 1000 1 1000 cc1 fx fy fz file tmp.out
variable xave equal ave(f_1\[2\])
variable xmax equal max(f_1\[2\])
thermo 1000
thermo_style custom step temp v_xave v_xmax :pre
(5) Histogram of cluster sizes:
compute cluster all cluster/atom 1.0
compute cc1 all chunk/atom c_cluster compress yes
compute size all property/chunk cc1 count
fix 1 all ave/histo 100 1 100 0 20 20 c_size mode vector ave running beyond ignore file tmp.histo :pre
:line
6.24 Setting parameters for the "kspace_style pppm/disp"_kspace_style.html command :link(howto_24),h4
The PPPM method computes interactions by splitting the pair potential
into two parts, one of which is computed in a normal pairwise fashion,
the so-called real-space part, and one of which is computed using the
Fourier transform, the so called reciprocal-space or kspace part. For
both parts, the potential is not computed exactly but is approximated.
Thus, there is an error in both parts of the computation, the
real-space and the kspace error. The just mentioned facts are true
both for the PPPM for Coulomb as well as dispersion interactions. The
deciding difference - and also the reason why the parameters for
pppm/disp have to be selected with more care - is the impact of the
errors on the results: The kspace error of the PPPM for Coulomb and
dispersion interaction and the real-space error of the PPPM for
Coulomb interaction have the character of noise. In contrast, the
real-space error of the PPPM for dispersion has a clear physical
interpretation: the underprediction of cohesion. As a consequence, the
real-space error has a much stronger effect than the kspace error on
simulation results for pppm/disp. Parameters must thus be chosen in a
way that this error is much smaller than the kspace error.
When using pppm/disp and not making any specifications on the PPPM
parameters via the kspace modify command, parameters will be tuned
such that the real-space error and the kspace error are equal. This
will result in simulations that are either inaccurate or slow, both of
which is not desirable. For selecting parameters for the pppm/disp
that provide fast and accurate simulations, there are two approaches,
which both have their up- and downsides.
The first approach is to set desired real-space an kspace accuracies
via the {kspace_modify force/disp/real} and {kspace_modify
force/disp/kspace} commands. Note that the accuracies have to be
specified in force units and are thus dependent on the chosen unit
settings. For real units, 0.0001 and 0.002 seem to provide reasonable
accurate and efficient computations for the real-space and kspace
accuracies. 0.002 and 0.05 work well for most systems using lj
units. PPPM parameters will be generated based on the desired
accuracies. The upside of this approach is that it usually provides a
good set of parameters and will work for both the {kspace_modify diff
ad} and {kspace_modify diff ik} options. The downside of the method
is that setting the PPPM parameters will take some time during the
initialization of the simulation.
The second approach is to set the parameters for the pppm/disp
explicitly using the {kspace_modify mesh/disp}, {kspace_modify
order/disp}, and {kspace_modify gewald/disp} commands. This approach
requires a more experienced user who understands well the impact of
the choice of parameters on the simulation accuracy and
performance. This approach provides a fast initialization of the
simulation. However, it is sensitive to errors: A combination of
parameters that will perform well for one system might result in
far-from-optimal conditions for other simulations. For example,
parameters that provide accurate and fast computations for
all-atomistic force fields can provide insufficient accuracy or
united-atomistic force fields (which is related to that the latter
typically have larger dispersion coefficients).
To avoid inaccurate or inefficient simulations, the pppm/disp stops
simulations with an error message if no action is taken to control the
PPPM parameters. If the automatic parameter generation is desired and
real-space and kspace accuracies are desired to be equal, this error
message can be suppressed using the {kspace_modify disp/auto yes}
command.
A reasonable approach that combines the upsides of both methods is to
make the first run using the {kspace_modify force/disp/real} and
{kspace_modify force/disp/kspace} commands, write down the PPPM
parameters from the outut, and specify these parameters using the
second approach in subsequent runs (which have the same composition,
force field, and approximately the same volume).
Concerning the performance of the pppm/disp there are two more things
to consider. The first is that when using the pppm/disp, the cutoff
parameter does no longer affect the accuracy of the simulation
(subject to that gewald/disp is adjusted when changing the cutoff).
The performance can thus be increased by examining different values
for the cutoff parameter. A lower bound for the cutoff is only set by
the truncation error of the repulsive term of pair potentials.
The second is that the mixing rule of the pair style has an impact on
the computation time when using the pppm/disp. Fastest computations
are achieved when using the geometric mixing rule. Using the
arithmetic mixing rule substantially increases the computational cost.
The computational overhead can be reduced using the {kspace_modify
mix/disp geom} and {kspace_modify splittol} commands. The first
command simply enforces geometric mixing of the dispersion
coefficients in kspace computations. This introduces some error in
the computations but will also significantly speed-up the
simulations. The second keyword sets the accuracy with which the
dispersion coefficients are approximated using a matrix factorization
approach. This may result in better accuracy then using the first
command, but will usually also not provide an equally good increase of
efficiency.
Finally, pppm/disp can also be used when no mixing rules apply.
This can be achieved using the {kspace_modify mix/disp none} command.
Note that the code does not check automatically whether any mixing
rule is fulfilled. If mixing rules do not apply, the user will have
to specify this command explicitly.
:line
6.25 Polarizable models :link(howto_25),h4
In polarizable force fields the charge distributions in molecules and
materials respond to their electrostatic environments. Polarizable
systems can be simulated in LAMMPS using three methods:
the fluctuating charge method, implemented in the "QEQ"_fix_qeq.html
package, :ulb,l
the adiabatic core-shell method, implemented in the
"CORESHELL"_#howto_26 package, :l
the thermalized Drude dipole method, implemented in the
"USER-DRUDE"_#howto_27 package. :l
:ule
The fluctuating charge method calculates instantaneous charges on
interacting atoms based on the electronegativity equalization
principle. It is implemented in the "fix qeq"_fix_qeq.html which is
available in several variants. It is a relatively efficient technique
since no additional particles are introduced. This method allows for
charge transfer between molecules or atom groups. However, because the
charges are located at the interaction sites, off-plane components of
polarization cannot be represented in planar molecules or atom groups.
The two other methods share the same basic idea: polarizable atoms are
split into one core atom and one satellite particle (called shell or
Drude particle) attached to it by a harmonic spring. Both atoms bear
a charge and they represent collectively an induced electric dipole.
These techniques are computationally more expensive than the QEq
method because of additional particles and bonds. These two
charge-on-spring methods differ in certain features, with the
core-shell model being normally used for ionic/crystalline materials,
whereas the so-called Drude model is normally used for molecular
systems and fluid states.
The core-shell model is applicable to crystalline materials where the
high symmetry around each site leads to stable trajectories of the
core-shell pairs. However, bonded atoms in molecules can be so close
that a core would interact too strongly or even capture the Drude
particle of a neighbor. The Drude dipole model is relatively more
complex in order to remediate this and other issues. Specifically, the
Drude model includes specific thermostating of the core-Drude pairs
and short-range damping of the induced dipoles.
The three polarization methods can be implemented through a
self-consistent calculation of charges or induced dipoles at each
timestep. In the fluctuating charge scheme this is done by the matrix
inversion method in "fix qeq/point"_fix_qeq.html, but for core-shell
or Drude-dipoles the relaxed-dipoles technique would require an slow
iterative procedure. These self-consistent solutions yield accurate
trajectories since the additional degrees of freedom representing
polarization are massless. An alternative is to attribute a mass to
the additional degrees of freedom and perform time integration using
an extended Lagrangian technique. For the fluctuating charge scheme
this is done by "fix qeq/dynamic"_fix_qeq.html, and for the
charge-on-spring models by the methods outlined in the next two
sections. The assignment of masses to the additional degrees of
freedom can lead to unphysical trajectories if care is not exerted in
choosing the parameters of the polarizable models and the simulation
conditions.
In the core-shell model the vibration of the shells is kept faster
than the ionic vibrations to mimic the fast response of the
polarizable electrons. But in molecular systems thermalizing the
core-Drude pairs at temperatures comparable to the rest of the
simulation leads to several problems (kinetic energy transfer, too
short a timestep, etc.) In order to avoid these problems the relative
motion of the Drude particles with respect to their cores is kept
"cold" so the vibration of the core-Drude pairs is very slow,
approaching the self-consistent regime. In both models the
temperature is regulated using the velocities of the center of mass of
core+shell (or Drude) pairs, but in the Drude model the actual
relative core-Drude particle motion is thermostated separately as
well.
:line
6.26 Adiabatic core/shell model :link(howto_26),h4
The adiabatic core-shell model by "Mitchell and
Fincham"_#MitchellFincham is a simple method for adding
polarizability to a system. In order to mimic the electron shell of
an ion, a satellite particle is attached to it. This way the ions are
split into a core and a shell where the latter is meant to react to
the electrostatic environment inducing polarizability.
Technically, shells are attached to the cores by a spring force f =
k*r where k is a parametrized spring constant and r is the distance
between the core and the shell. The charges of the core and the shell
add up to the ion charge, thus q(ion) = q(core) + q(shell). This
setup introduces the ion polarizability (alpha) given by
alpha = q(shell)^2 / k. In a
similar fashion the mass of the ion is distributed on the core and the
shell with the core having the larger mass.
To run this model in LAMMPS, "atom_style"_atom_style.html {full} can
be used since atom charge and bonds are needed. Each kind of
core/shell pair requires two atom types and a bond type. The core and
shell of a core/shell pair should be bonded to each other with a
harmonic bond that provides the spring force. For example, a data file
for NaCl, as found in examples/coreshell, has this format:
432 atoms # core and shell atoms
216 bonds # number of core/shell springs :pre
4 atom types # 2 cores and 2 shells for Na and Cl
2 bond types :pre
0.0 24.09597 xlo xhi
0.0 24.09597 ylo yhi
0.0 24.09597 zlo zhi :pre
Masses # core/shell mass ratio = 0.1 :pre
1 20.690784 # Na core
2 31.90500 # Cl core
3 2.298976 # Na shell
4 3.54500 # Cl shell :pre
Atoms :pre
1 1 2 1.5005 0.00000000 0.00000000 0.00000000 # core of core/shell pair 1
2 1 4 -2.5005 0.00000000 0.00000000 0.00000000 # shell of core/shell pair 1
3 2 1 1.5056 4.01599500 4.01599500 4.01599500 # core of core/shell pair 2
4 2 3 -0.5056 4.01599500 4.01599500 4.01599500 # shell of core/shell pair 2
(...) :pre
Bonds # Bond topology for spring forces :pre
1 2 1 2 # spring for core/shell pair 1
2 2 3 4 # spring for core/shell pair 2
(...) :pre
Non-Coulombic (e.g. Lennard-Jones) pairwise interactions are only
defined between the shells. Coulombic interactions are defined
between all cores and shells. If desired, additional bonds can be
specified between cores.
The "special_bonds"_special_bonds.html command should be used to
turn-off the Coulombic interaction within core/shell pairs, since that
interaction is set by the bond spring. This is done using the
"special_bonds"_special_bonds.html command with a 1-2 weight = 0.0,
which is the default value. It needs to be considered whether one has
to adjust the "special_bonds"_special_bonds.html weighting according
to the molecular topology since the interactions of the shells are
bypassed over an extra bond.
Note that this core/shell implementation does not require all ions to
be polarized. One can mix core/shell pairs and ions without a
satellite particle if desired.
Since the core/shell model permits distances of r = 0.0 between the
core and shell, a pair style with a "cs" suffix needs to be used to
implement a valid long-range Coulombic correction. Several such pair
styles are provided in the CORESHELL package. See "this doc
page"_pair_cs.html for details. All of the core/shell enabled pair
styles require the use of a long-range Coulombic solver, as specified
by the "kspace_style"_kspace_style.html command. Either the PPPM or
Ewald solvers can be used.
For the NaCL example problem, these pair style and bond style settings
are used:
pair_style born/coul/long/cs 20.0 20.0
pair_coeff * * 0.0 1.000 0.00 0.00 0.00
pair_coeff 3 3 487.0 0.23768 0.00 1.05 0.50 #Na-Na
pair_coeff 3 4 145134.0 0.23768 0.00 6.99 8.70 #Na-Cl
pair_coeff 4 4 405774.0 0.23768 0.00 72.40 145.40 #Cl-Cl :pre
bond_style harmonic
bond_coeff 1 63.014 0.0
bond_coeff 2 25.724 0.0 :pre
When running dynamics with the adiabatic core/shell model, the
following issues should be considered. The relative motion of
the core and shell particles corresponds to the polarization,
hereby an instantaneous relaxation of the shells is approximated
and a fast core/shell spring frequency ensures a nearly constant
internal kinetic energy during the simulation.
Thermostats can alter this polarization behaviour, by scaling the
internal kinetic energy, meaning the shell will not react freely to
its electrostatic environment.
Therefore it is typically desirable to decouple the relative motion of
the core/shell pair, which is an imaginary degree of freedom, from the
real physical system. To do that, the "compute
temp/cs"_compute_temp_cs.html command can be used, in conjunction with
any of the thermostat fixes, such as "fix nvt"_fix_nh.html or "fix
langevin"_fix_langevin. This compute uses the center-of-mass velocity
of the core/shell pairs to calculate a temperature, and insures that
velocity is what is rescaled for thermostatting purposes. This
compute also works for a system with both core/shell pairs and
non-polarized ions (ions without an attached satellite particle). The
"compute temp/cs"_compute_temp_cs.html command requires input of two
groups, one for the core atoms, another for the shell atoms.
Non-polarized ions which might also be included in the treated system
should not be included into either of these groups, they are taken
into account by the {group-ID} (2nd argument) of the compute. The
groups can be defined using the "group {type}"_group.html command.
Note that to perform thermostatting using this definition of
temperature, the "fix modify temp"_fix_modify.html command should be
used to assign the compute to the thermostat fix. Likewise the
"thermo_modify temp"_thermo_modify.html command can be used to make
this temperature be output for the overall system.
For the NaCl example, this can be done as follows:
group cores type 1 2
group shells type 3 4
compute CSequ all temp/cs cores shells
fix thermoberendsen all temp/berendsen 1427 1427 0.4 # thermostat for the true physical system
fix thermostatequ all nve # integrator as needed for the berendsen thermostat
fix_modify thermoberendsen temp CSequ
thermo_modify temp CSequ # output of center-of-mass derived temperature :pre
The pressure for the core/shell system is computed via the regular
LAMMPS convention by "treating the cores and shells as individual
particles"_#MitchellFincham2. For the thermo output of the pressure
as well as for the application of a barostat, it is necessary to
use an additional "pressure"_compute_pressure compute based on the
default "temperature"_compute_temp and specifying it as a second
argument in "fix modify"_fix_modify.html and
"thermo_modify"_thermo_modify.html resulting in:
(...)
compute CSequ all temp/cs cores shells
compute thermo_press_lmp all pressure thermo_temp # pressure for individual particles
thermo_modify temp CSequ press thermo_press_lmp # modify thermo to regular pressure
fix press_bar all npt temp 300 300 0.04 iso 0 0 0.4
fix_modify press_bar temp CSequ press thermo_press_lmp # pressure modification for correct kinetic scalar :pre
If "compute temp/cs"_compute_temp_cs.html is used, the decoupled
relative motion of the core and the shell should in theory be
stable. However numerical fluctuation can introduce a small
momentum to the system, which is noticable over long trajectories.
Therefore it is recommendable to use the "fix
momentum"_fix_momentum.html command in combination with "compute
temp/cs"_compute_temp_cs.html when equilibrating the system to
prevent any drift.
When initializing the velocities of a system with core/shell pairs, it
is also desirable to not introduce energy into the relative motion of
the core/shell particles, but only assign a center-of-mass velocity to
the pairs. This can be done by using the {bias} keyword of the
"velocity create"_velocity.html command and assigning the "compute
temp/cs"_compute_temp_cs.html command to the {temp} keyword of the
"velocity"_velocity.html command, e.g.
velocity all create 1427 134 bias yes temp CSequ
velocity all scale 1427 temp CSequ :pre
To maintain the correct polarizability of the core/shell pairs, the
kinetic energy of the internal motion shall remain nearly constant.
Therefore the choice of spring force and mass ratio need to ensure
much faster relative motion of the 2 atoms within the core/shell pair
than their center-of-mass velocity. This allows the shells to
effectively react instantaneously to the electrostatic environment and
limits energy transfer to or from the core/shell oscillators.
This fast movement also dictates the timestep that can be used.
The primary literature of the adiabatic core/shell model suggests that
the fast relative motion of the core/shell pairs only allows negligible
energy transfer to the environment.
The mentioned energy transfer will typically lead to a small drift
in total energy over time. This internal energy can be monitored
using the "compute chunk/atom"_compute_chunk_atom.html and "compute
temp/chunk"_compute_temp_chunk.html commands. The internal kinetic
energies of each core/shell pair can then be summed using the sum()
special function of the "variable"_variable.html command. Or they can
be time/averaged and output using the "fix ave/time"_fix_ave_time.html
command. To use these commands, each core/shell pair must be defined
as a "chunk". If each core/shell pair is defined as its own molecule,
the molecule ID can be used to define the chunks. If cores are bonded
to each other to form larger molecules, the chunks can be identified
by the "fix property/atom"_fix_property_atom.html via assigning a
core/shell ID to each atom using a special field in the data file read
by the "read_data"_read_data.html command. This field can then be
accessed by the "compute property/atom"_compute_property_atom.html
command, to use as input to the "compute
chunk/atom"_compute_chunk_atom.html command to define the core/shell
pairs as chunks.
For example if core/shell pairs are the only molecules:
read_data NaCl_CS_x0.1_prop.data
compute prop all property/atom molecule
compute cs_chunk all chunk/atom c_prop
compute cstherm all temp/chunk cs_chunk temp internal com yes cdof 3.0 # note the chosen degrees of freedom for the core/shell pairs
fix ave_chunk all ave/time 10 1 10 c_cstherm file chunk.dump mode vector :pre
For example if core/shell pairs and other molecules are present:
fix csinfo all property/atom i_CSID # property/atom command
read_data NaCl_CS_x0.1_prop.data fix csinfo NULL CS-Info # atom property added in the data-file
compute prop all property/atom i_CSID
(...) :pre
The additional section in the date file would be formatted like this:
CS-Info # header of additional section :pre
1 1 # column 1 = atom ID, column 2 = core/shell ID
2 1
3 2
4 2
5 3
6 3
7 4
8 4
(...) :pre
:line
6.27 Drude induced dipoles :link(howto_27),h4
The thermalized Drude model, similarly to the "core-shell"_#howto_26
model, represents induced dipoles by a pair of charges (the core atom
and the Drude particle) connected by a harmonic spring. The Drude
model has a number of features aimed at its use in molecular systems
("Lamoureux and Roux"_#howto-Lamoureux):
Thermostating of the additional degrees of freedom associated with the
induced dipoles at very low temperature, in terms of the reduced
coordinates of the Drude particles with respect to their cores. This
makes the trajectory close to that of relaxed induced dipoles. :ulb,l
Consistent definition of 1-2 to 1-4 neighbors. A core-Drude particle
pair represents a single (polarizable) atom, so the special screening
factors in a covalent structure should be the same for the core and
the Drude particle. Drude particles have to inherit the 1-2, 1-3, 1-4
special neighbor relations from their respective cores. :l
Stabilization of the interactions between induced dipoles. Drude
dipoles on covalently bonded atoms interact too strongly due to the
short distances, so an atom may capture the Drude particle of a
neighbor, or the induced dipoles within the same molecule may align
too much. To avoid this, damping at short range can be done by Thole
functions (for which there are physical grounds). This Thole damping
is applied to the point charges composing the induced dipole (the
charge of the Drude particle and the opposite charge on the core, not
to the total charge of the core atom). :l
:ule
A detailed tutorial covering the usage of Drude induced dipoles in
LAMMPS is "available here"_tutorial_drude.html.
As with the core-shell model, the cores and Drude particles should
appear in the data file as standard atoms. The same holds for the
springs between them, which are described by standard harmonic bonds.
The nature of the atoms (core, Drude particle or non-polarizable) is
specified via the "fix drude"_fix_drude.html command. The special
list of neighbors is automatically refactored to account for the
equivalence of core and Drude particles as regards special 1-2 to 1-4
screening. It may be necessary to use the {extra} keyword of the
"special_bonds"_special_bonds.html command. If using "fix
shake"_fix_shake.html, make sure no Drude particle is in this fix
group.
There are two ways to thermostat the Drude particles at a low
temperature: use either "fix langevin/drude"_fix_langevin_drude.html
for a Langevin thermostat, or "fix
drude/transform/*"_fix_drude_transform.html for a Nose-Hoover
thermostat. The former requires use of the command "comm_modify vel
yes"_comm_modify.html. The latter requires two separate integration
fixes like {nvt} or {npt}. The correct temperatures of the reduced
degrees of freedom can be calculated using the "compute
temp/drude"_compute_temp_drude.html. This requires also to use the
command {comm_modify vel yes}.
Short-range damping of the induced dipole interactions can be achieved
using Thole functions through the "pair style
thole"_pair_thole.html in "pair_style hybrid/overlay"_pair_hybrid.html
with a Coulomb pair style. It may be useful to use {coul/long/cs} or
similar from the CORESHELL package if the core and Drude particle come
too close, which can cause numerical issues.
:line
:line
:link(howto-Berendsen)
[(Berendsen)] Berendsen, Grigera, Straatsma, J Phys Chem, 91,
6269-6271 (1987).
:link(howto-Cornell)
[(Cornell)] Cornell, Cieplak, Bayly, Gould, Merz, Ferguson,
Spellmeyer, Fox, Caldwell, Kollman, JACS 117, 5179-5197 (1995).
:link(Horn)
[(Horn)] Horn, Swope, Pitera, Madura, Dick, Hura, and Head-Gordon,
J Chem Phys, 120, 9665 (2004).
:link(howto-Ikeshoji)
[(Ikeshoji)] Ikeshoji and Hafskjold, Molecular Physics, 81, 251-261
(1994).
:link(howto-Wirnsberger)
[(Wirnsberger)] Wirnsberger, Frenkel, and Dellago, J Chem Phys, 143, 124104
(2015).
:link(howto-MacKerell)
[(MacKerell)] MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field,
Fischer, Gao, Guo, Ha, et al, J Phys Chem, 102, 3586 (1998).
:link(howto-Mayo)
[(Mayo)] Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909
(1990).
:link(Jorgensen1)
[(Jorgensen)] Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem
Phys, 79, 926 (1983).
:link(Price1)
[(Price)] Price and Brooks, J Chem Phys, 121, 10096 (2004).
:link(Shinoda1)
[(Shinoda)] Shinoda, Shiga, and Mikami, Phys Rev B, 69, 134103 (2004).
:link(MitchellFincham)
[(Mitchell and Fincham)] Mitchell, Fincham, J Phys Condensed Matter,
5, 1031-1038 (1993).
:link(MitchellFincham2)
[(Fincham)] Fincham, Mackrodt and Mitchell, J Phys Condensed Matter,
6, 393-404 (1994).
:link(howto-Lamoureux)
[(Lamoureux and Roux)] G. Lamoureux, B. Roux, J. Chem. Phys 119, 3025 (2003)
diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt
index 76f88b8ab..54a2685b8 100644
--- a/doc/src/Section_packages.txt
+++ b/doc/src/Section_packages.txt
@@ -1,2634 +1,2634 @@
"Previous Section"_Section_commands.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next
Section"_Section_accelerate.html :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
4. Packages :h3
This section gives an overview of the optional packages that extend
LAMMPS functionality with instructions on how to build LAMMPS with
each of them. Packages are groups of files that enable a specific set
of features. For example, force fields for molecular systems or
granular systems are in packages. You can see the list of all
packages and "make" commands to manage them by typing "make package"
from within the src directory of the LAMMPS distribution. "Section
2.3"_Section_start.html#start_3 gives general info on how to install
and un-install packages as part of the LAMMPS build process.
There are two kinds of packages in LAMMPS, standard and user packages:
"Table of standard packages"_#table_standard
"Table of user packages"_#table_user :ul
Standard packages are supported by the LAMMPS developers and are
written in a syntax and style consistent with the rest of LAMMPS.
This means the developers will answer questions about them, debug and
fix them if necessary, and keep them compatible with future changes to
LAMMPS.
User packages have been contributed by users, and begin with the
"user" prefix. If they are a single command (single file), they are
typically in the user-misc package. User packages don't necessarily
meet the requirements of the standard packages. If you have problems
using a feature provided in a user package, you may need to contact
the contributor directly to get help. Information on how to submit
additions you make to LAMMPS as single files or as a standard or user
package are given in "this section"_Section_modify.html#mod_15 of the
manual.
Following the next two tables is a sub-section for each package. It
lists authors (if applicable) and summarizes the package contents. It
has specific instructions on how to install the package, including (if
necessary) downloading or building any extra library it requires. It
also gives links to documentation, example scripts, and
pictures/movies (if available) that illustrate use of the package.
NOTE: To see the complete list of commands a package adds to LAMMPS,
just look at the files in its src directory, e.g. "ls src/GRANULAR".
Files with names that start with fix, compute, atom, pair, bond,
angle, etc correspond to commands with the same style names.
In these two tables, the "Example" column is a sub-directory in the
examples directory of the distribution which has an input script that
uses the package. E.g. "peptide" refers to the examples/peptide
directory; USER/atc refers to the examples/USER/atc directory. The
"Library" column indicates whether an extra library is needed to build
and use the package:
dash = no library
sys = system library: you likely have it on your machine
int = internal library: provided with LAMMPS, but you may need to build it
ext = external library: you will need to download and install it on your machine :ul
:line
:line
[Standard packages] :link(table_standard),p
Package, Description, Doc page, Example, Library
"ASPHERE"_#ASPHERE, aspherical particle models, "Section 6.6.14"_Section_howto.html#howto_14, ellipse, -
"BODY"_#BODY, body-style particles, "body"_body.html, body, -
"CLASS2"_#CLASS2, class 2 force fields, "pair_style lj/class2"_pair_class2.html, -, -
"COLLOID"_#COLLOID, colloidal particles, "atom_style colloid"_atom_style.html, colloid, -
"COMPRESS"_#COMPRESS, I/O compression, "dump */gz"_dump.html, -, sys
"CORESHELL"_#CORESHELL, adiabatic core/shell model, "Section 6.6.25"_Section_howto.html#howto_25, coreshell, -
"DIPOLE"_#DIPOLE, point dipole particles, "pair_style dipole/cut"_pair_dipole.html, dipole, -
"GPU"_#GPU, GPU-enabled styles, "Section 5.3.1"_accelerate_gpu.html, WWW bench, int
"GRANULAR"_#GRANULAR, granular systems, "Section 6.6.6"_Section_howto.html#howto_6, pour, -
"KIM"_#KIM, openKIM wrapper, "pair_style kim"_pair_kim.html, kim, ext
"KOKKOS"_#KOKKOS, Kokkos-enabled styles, "Section 5.3.3"_accelerate_kokkos.html, WWW bench, -
"KSPACE"_#KSPACE, long-range Coulombic solvers, "kspace_style"_kspace_style.html, peptide, -
"MANYBODY"_#MANYBODY, many-body potentials, "pair_style tersoff"_pair_tersoff.html, shear, -
"MC"_#MC, Monte Carlo options, "fix gcmc"_fix_gcmc.html, -, -
"MEAM"_#MEAM, modified EAM potential, "pair_style meam"_pair_meam.html, meam, int
"MISC"_#MISC, miscellanous single-file commands, -, -, -
"MOLECULE"_#MOLECULE, molecular system force fields, "Section 6.6.3"_Section_howto.html#howto_3, peptide, -
"MPIIO"_#MPIIO, MPI parallel I/O dump and restart, "dump"_dump.html, -, -
"MSCG"_#MSCG, multi-scale coarse-graining wrapper, "fix mscg"_fix_mscg.html, mscg, ext
"OPT"_#OPT, optimized pair styles, "Section 5.3.5"_accelerate_opt.html, WWW bench, -
"PERI"_#PERI, Peridynamics models, "pair_style peri"_pair_peri.html, peri, -
"POEMS"_#POEMS, coupled rigid body motion, "fix poems"_fix_poems.html, rigid, int
"PYTHON"_#PYTHON, embed Python code in an input script, "python"_python.html, python, sys
"QEQ"_#QEQ, QEq charge equilibration, "fix qeq"_fix_qeq.html, qeq, -
"REAX"_#REAX, ReaxFF potential (Fortran), "pair_style reax"_pair_reax.html, reax, int
"REPLICA"_#REPLICA, multi-replica methods, "Section 6.6.5"_Section_howto.html#howto_5, tad, -
"RIGID"_#RIGID, rigid bodies and constraints, "fix rigid"_fix_rigid.html, rigid, -
"SHOCK"_#SHOCK, shock loading methods, "fix msst"_fix_msst.html, -, -
"SNAP"_#SNAP, quantum-fitted potential, "pair snap"_pair_snap.html, snap, -
"SRD"_#SRD, stochastic rotation dynamics, "fix srd"_fix_srd.html, srd, -
"VORONOI"_#VORONOI, Voronoi tesselation, "compute voronoi/atom"_compute_voronoi_atom.html, -, ext
:tb(ea=c,ca1=l)
[USER packages] :link(table_user),p
Package, Description, Doc page, Example, Library
"USER-ATC"_#USER-ATC, atom-to-continuum coupling, "fix atc"_fix_atc.html, USER/atc, int
"USER-AWPMD"_#USER-AWPMD, wave-packet MD, "pair_style awpmd/cut"_pair_awpmd.html, USER/awpmd, int
"USER-CGDNA"_#USER-CGDNA, coarse-grained DNA force fields, src/USER-CGDNA/README, USER/cgdna, -
"USER-CGSDK"_#USER-CGSDK, SDK coarse-graining model, "pair_style lj/sdk"_pair_sdk.html, USER/cgsdk, -
"USER-COLVARS"_#USER-COLVARS, collective variables library, "fix colvars"_fix_colvars.html, USER/colvars, int
"USER-DIFFRACTION"_#USER-DIFFRACTION, virtual x-ray and electron diffraction,"compute xrd"_compute_xrd.html, USER/diffraction, -
"USER-DPD"_#USER-DPD, reactive dissipative particle dynamics, src/USER-DPD/README, USER/dpd, -
"USER-DRUDE"_#USER-DRUDE, Drude oscillators, "tutorial"_tutorial_drude.html, USER/drude, -
"USER-EFF"_#USER-EFF, electron force field,"pair_style eff/cut"_pair_eff.html, USER/eff, -
"USER-FEP"_#USER-FEP, free energy perturbation,"compute fep"_compute_fep.html, USER/fep, -
"USER-H5MD"_#USER-H5MD, dump output via HDF5,"dump h5md"_dump_h5md.html, -, ext
"USER-INTEL"_#USER-INTEL, optimized Intel CPU and KNL styles,"Section 5.3.2"_accelerate_intel.html, WWW bench, -
"USER-LB"_#USER-LB, Lattice Boltzmann fluid,"fix lb/fluid"_fix_lb_fluid.html, USER/lb, -
"USER-MANIFOLD"_#USER-MANIFOLD, motion on 2d surfaces,"fix manifoldforce"_fix_manifoldforce.html, USER/manifold, -
"USER-MEAMC"_#USER-MEAMC, modified EAM potential (C++), "pair_style meam/c"_pair_meam.html, meam, -
"USER-MGPT"_#USER-MGPT, fast MGPT multi-ion potentials, "pair_style mgpt"_pair_mgpt.html, USER/mgpt, -
"USER-MISC"_#USER-MISC, single-file contributions, USER-MISC/README, USER/misc, -
"USER-MOLFILE"_#USER-MOLFILE, "VMD"_vmd_home molfile plug-ins,"dump molfile"_dump_molfile.html, -, ext
"USER-NETCDF"_#USER-NETCDF, dump output via NetCDF,"dump netcdf"_dump_netcdf.html, -, ext
"USER-OMP"_#USER-OMP, OpenMP-enabled styles,"Section 5.3.4"_accelerate_omp.html, WWW bench, -
"USER-PHONON"_#USER-PHONON, phonon dynamical matrix,"fix phonon"_fix_phonon.html, USER/phonon, -
"USER-QMMM"_#USER-QMMM, QM/MM coupling,"fix qmmm"_fix_qmmm.html, USER/qmmm, ext
"USER-QTB"_#USER-QTB, quantum nuclear effects,"fix qtb"_fix_qtb.html "fix qbmsst"_fix_qbmsst.html, qtb, -
"USER-QUIP"_#USER-QUIP, QUIP/libatoms interface,"pair_style quip"_pair_quip.html, USER/quip, ext
"USER-REAXC"_#USER-REAXC, ReaxFF potential (C/C++) ,"pair_style reaxc"_pair_reaxc.html, reax, -
"USER-SMD"_#USER-SMD, smoothed Mach dynamics,"SMD User Guide"_PDF/SMD_LAMMPS_userguide.pdf, USER/smd, ext
"USER-SMTBQ"_#USER-SMTBQ, second moment tight binding QEq potential,"pair_style smtbq"_pair_smtbq.html, USER/smtbq, -
"USER-SPH"_#USER-SPH, smoothed particle hydrodynamics,"SPH User Guide"_PDF/SPH_LAMMPS_userguide.pdf, USER/sph, -
"USER-TALLY"_#USER-TALLY, pairwise tally computes,"compute XXX/tally"_compute_tally.html, USER/tally, -
"USER-VTK"_#USER-VTK, dump output via VTK, "compute vtk"_dump_vtk.html, -, ext
:tb(ea=c,ca1=l)
:line
:line
ASPHERE package :link(ASPHERE),h4
[Contents:]
Computes, time-integration fixes, and pair styles for aspherical
particle models including ellipsoids, 2d lines, and 3d triangles.
[Install or un-install:]
make yes-asphere
make machine :pre
make no-asphere
make machine :pre
[Supporting info:]
src/ASPHERE: filenames -> commands
"Section 6.14"_Section_howto.html#howto_14
"pair_style gayberne"_pair_gayberne.html
"pair_style resquared"_pair_resquared.html
"doc/PDF/pair_gayberne_extra.pdf"_PDF/pair_gayberne_extra.pdf
"doc/PDF/pair_resquared_extra.pdf"_PDF/pair_resquared_extra.pdf
examples/ASPHERE
examples/ellipse
http://lammps.sandia.gov/movies.html#line
http://lammps.sandia.gov/movies.html#tri :ul
:line
BODY package :link(BODY),h4
[Contents:]
Body-style particles with internal structure. Computes,
time-integration fixes, pair styles, as well as the body styles
themselves. See the "body"_body.html doc page for an overview.
[Install or un-install:]
make yes-body
make machine :pre
make no-body
make machine :pre
[Supporting info:]
src/BODY filenames -> commands
"body"_body.html
"atom_style body"_atom_style.html
"fix nve/body"_fix_nve_body.html
"pair_style body"_pair_body.html
examples/body :ul
:line
CLASS2 package :link(CLASS2),h4
[Contents:]
Bond, angle, dihedral, improper, and pair styles for the COMPASS
CLASS2 molecular force field.
[Install or un-install:]
make yes-class2
make machine :pre
make no-class2
make machine :pre
[Supporting info:]
src/CLASS2: filenames -> commands
"bond_style class2"_bond_class2.html
"angle_style class2"_angle_class2.html
"dihedral_style class2"_dihedral_class2.html
"improper_style class2"_improper_class2.html
"pair_style lj/class2"_pair_class2.html :ul
:line
COLLOID package :link(COLLOID),h4
[Contents:]
Coarse-grained finite-size colloidal particles. Pair stayle and fix
wall styles for colloidal interactions. Includes the Fast Lubrication
Dynamics (FLD) method for hydrodynamic interactions, which is a
simplified approximation to Stokesian dynamics.
[Authors:] This package includes Fast Lubrication Dynamics pair styles
which were created by Amit Kumar and Michael Bybee from Jonathan
Higdon's group at UIUC.
[Install or un-install:]
make yes-colloid
make machine :pre
make no-colloid
make machine :pre
[Supporting info:]
src/COLLOID: filenames -> commands
"fix wall/colloid"_fix_wall.html
"pair_style colloid"_pair_colloid.html
"pair_style yukawa/colloid"_pair_yukawa_colloid.html
"pair_style brownian"_pair_brownian.html
"pair_style lubricate"_pair_lubricate.html
"pair_style lubricateU"_pair_lubricateU.html
examples/colloid
examples/srd :ul
:line
COMPRESS package :link(COMPRESS),h4
[Contents:]
Compressed output of dump files via the zlib compression library,
using dump styles with a "gz" in their style name.
To use this package you must have the zlib compression library
available on your system.
[Author:] Axel Kohlmeyer (Temple U).
[Install or un-install:]
Note that building with this package assumes you have the zlib
compression library available on your system. The LAMMPS build uses
the settings in the lib/compress/Makefile.lammps file in the
compile/link process. You should only need to edit this file if the
LAMMPS build fails on your system.
make yes-compress
make machine :pre
make no-compress
make machine :pre
[Supporting info:]
src/COMPRESS: filenames -> commands
src/COMPRESS/README
lib/compress/README
"dump atom/gz"_dump.html
"dump cfg/gz"_dump.html
"dump custom/gz"_dump.html
"dump xyz/gz"_dump.html :ul
:line
CORESHELL package :link(CORESHELL),h4
[Contents:]
Compute and pair styles that implement the adiabatic core/shell model
for polarizability. The pair styles augment Born, Buckingham, and
Lennard-Jones styles with core/shell capabilities. The "compute
temp/cs"_compute_temp_cs.html command calculates the temperature of a
system with core/shell particles. See "Section
6.26"_Section_howto.html#howto_26 for an overview of how to use this
package.
[Author:] Hendrik Heenen (Technical U of Munich).
[Install or un-install:]
make yes-coreshell
make machine :pre
make no-coreshell
make machine :pre
[Supporting info:]
src/CORESHELL: filenames -> commands
"Section 6.26"_Section_howto.html#howto_26
"Section 6.25"_Section_howto.html#howto_25
"compute temp/cs"_compute_temp_cs.html
"pair_style born/coul/long/cs"_pair_cs.html
"pair_style buck/coul/long/cs"_pair_cs.html
"pair_style lj/cut/coul/long/cs"_pair_lj.html
examples/coreshell :ul
:line
DIPOLE package :link(DIPOLE),h4
[Contents:]
An atom style and several pair styles for point dipole models with
short-range or long-range interactions.
[Install or un-install:]
make yes-dipole
make machine :pre
make no-dipole
make machine :pre
[Supporting info:]
src/DIPOLE: filenames -> commands
"atom_style dipole"_atom_style.html
"pair_style lj/cut/dipole/cut"_pair_dipole.html
"pair_style lj/cut/dipole/long"_pair_dipole.html
"pair_style lj/long/dipole/long"_pair_dipole.html
examples/dipole :ul
:line
GPU package :link(GPU),h4
[Contents:]
Dozens of pair styles and a version of the PPPM long-range Coulombic
solver optimized for NVIDIA GPUs. All such styles have a "gpu" as a
suffix in their style name. "Section 5.3.1"_accelerate_gpu.html gives
details of what hardware and Cuda software is required on your system,
and details on how to build and use this package. Its styles can be
invoked at run time via the "-sf gpu" or "-suffix gpu" "command-line
-switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS
+switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS
package, which has GPU-enabled styles.
[Authors:] Mike Brown (Intel) while at Sandia and ORNL and Trung Nguyen
(Northwestern U) while at ORNL.
[Install or un-install:]
Before building LAMMPS with this package, you must first build the GPU
library in lib/gpu from a set of provided C and Cuda files. You can
do this manually if you prefer; follow the instructions in
lib/gpu/README. You can also do it in one step from the lammps/src
dir, using a command like these, which simply invoke the
lib/gpu/Install.py script with the specified args:
make lib-gpu # print help message
make lib-gpu args="-m" # build GPU library with default Makefile.linux
make lib-gpu args="-i xk7 -p single -o xk7.single" # create new Makefile.xk7.single, altered for single-precision
make lib-gpu args="-i xk7 -p single -o xk7.single -m" # ditto, also build GPU library
Note that this procedure starts with one of the existing
Makefile.machine files in lib/gpu. It allows you to alter 4 important
settings in that Makefile, via the -h, -a, -p, -e switches,
and save the new Makefile, if desired:
CUDA_HOME = where NVIDIA Cuda software is installed on your system
CUDA_ARCH = what GPU hardware you have (see help message for details)
CUDA_PRECISION = precision (double, mixed, single)
EXTRAMAKE = which Makefile.lammps.* file to copy to Makefile.lammps :ul
If the library build is successful, 2 files should be created:
lib/gpu/libgpu.a and lib/gpu/Makefile.lammps. The latter has settings
that enable LAMMPS to link with Cuda libraries. If the settings in
Makefile.lammps for your machine are not correct, the LAMMPS build
will fail.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-gpu
make machine :pre
make no-gpu
make machine :pre
NOTE: If you re-build the GPU library in lib/gpu, you should always
un-install the GPU package, then re-install it and re-build LAMMPS.
This is because the compilation of files in the GPU package use the
library settings from the lib/gpu/Makefile.machine used to build the
GPU library.
[Supporting info:]
src/GPU: filenames -> commands
src/GPU/README
lib/gpu/README
"Section 5.3"_Section_accelerate.html#acc_3
"Section 5.3.1"_accelerate_gpu.html
-"Section 2.7 -sf gpu"_Section_start.html#start_7
-"Section 2.7 -pk gpu"_Section_start.html#start_7
+"Section 2.6 -sf gpu"_Section_start.html#start_6
+"Section 2.6 -pk gpu"_Section_start.html#start_6
"package gpu"_package.html
Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (g)
"Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul
:line
GRANULAR package :link(GRANULAR),h4
[Contents:]
Pair styles and fixes for finite-size granular particles, which
interact with each other and boundaries via frictional and dissipative
potentials.
[Install or un-install:]
make yes-granular
make machine :pre
make no-granular
make machine :pre
[Supporting info:]
src/GRANULAR: filenames -> commands
"Section 6.6"_Section_howto.html#howto_6,
"fix pour"_fix_pour.html
"fix wall/gran"_fix_wall_gran.html
"pair_style gran/hooke"_pair_gran.html
"pair_style gran/hertz/history"_pair_gran.html
examples/granregion
examples/pour
bench/in.chute
http://lammps.sandia.gov/pictures.html#jamming
http://lammps.sandia.gov/movies.html#hopper
http://lammps.sandia.gov/movies.html#dem
http://lammps.sandia.gov/movies.html#brazil
http://lammps.sandia.gov/movies.html#granregion :ul
:line
KIM package :link(KIM),h4
[Contents:]
A "pair_style kim"_pair_kim.html command which is a wrapper on the
Knowledge Base for Interatomic Models (KIM) repository of interatomic
potentials, enabling any of them to be used in LAMMPS simulations.
To use this package you must have the KIM library available on your
system.
Information about the KIM project can be found at its website:
https://openkim.org. The KIM project is led by Ellad Tadmor and Ryan
Elliott (U Minnesota) and James Sethna (Cornell U).
[Authors:] Ryan Elliott (U Minnesota) is the main developer for the KIM
API which the "pair_style kim"_pair_kim.html command uses. He
developed the pair style in collaboration with Valeriu Smirichinski (U
Minnesota).
[Install or un-install:]
Using this package requires the KIM library and its models
(interatomic potentials) to be downloaded and installed on your
system. The library can be downloaded and built in lib/kim or
elsewhere on your system. Details of the download, build, and install
process for KIM are given in the lib/kim/README file.
Once that process is complete, you can then install/un-install the
package and build LAMMPS in the usual manner:
make yes-kim
make machine :pre
make no-kim
make machine :pre
[Supporting info:]
src/KIM: filenames -> commands
src/KIM/README
lib/kim/README
"pair_style kim"_pair_kim.html
examples/kim :ul
:line
KOKKOS package :link(KOKKOS),h4
[Contents:]
Dozens of atom, pair, bond, angle, dihedral, improper, fix, compute
styles adapted to compile using the Kokkos library which can convert
them to OpenMP or Cuda code so that they run efficiently on multicore
CPUs, KNLs, or GPUs. All the styles have a "kk" as a suffix in their
style name. "Section 5.3.3"_accelerate_kokkos.html gives details of
what hardware and software is required on your system, and how to
build and use this package. Its styles can be invoked at run time via
the "-sf kk" or "-suffix kk" "command-line
-switches"_Section_start.html#start_7. Also see the "GPU"_#GPU,
+switches"_Section_start.html#start_6. Also see the "GPU"_#GPU,
"OPT"_#OPT, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP
packages, which have styles optimized for CPUs, KNLs, and GPUs.
You must have a C++11 compatible compiler to use this package.
[Authors:] The KOKKOS package was created primarily by Christian Trott
and Stan Moore (Sandia), with contributions from other folks as well.
It uses the open-source "Kokkos library"_https://github.com/kokkos
which was developed by Carter Edwards, Christian Trott, and others at
Sandia, and which is included in the LAMMPS distribution in
lib/kokkos.
[Install or un-install:]
For the KOKKOS package, you have 3 choices when building. You can
build with either CPU or KNL or GPU support. Each choice requires
additional settings in your Makefile.machine for the KOKKOS_DEVICES
and KOKKOS_ARCH settings. See the src/MAKE/OPTIONS/Makefile.kokkos*
files for examples.
For multicore CPUs using OpenMP:
KOKKOS_DEVICES = OpenMP
KOKKOS_ARCH = HSW # HSW = Haswell, SNB = SandyBridge, BDW = Broadwell, etc
For Intel KNLs using OpenMP:
KOKKOS_DEVICES = OpenMP
KOKKOS_ARCH = KNL
For NVIDIA GPUs using Cuda:
KOKKOS_DEVICES = Cuda
KOKKOS_ARCH = Pascal60,Power8 # P100 hosted by an IBM Power8, etc
KOKKOS_ARCH = Kepler37,Power8 # K80 hosted by an IBM Power8, etc
For GPUs, you also need these 2 lines in your Makefile.machine before
the CC line is defined, in this case for use with OpenMPI mpicxx. The
2 lines define a nvcc wrapper compiler, which will use nvcc for
compiling Cuda files or use a C++ compiler for non-Kokkos, non-Cuda
files.
KOKKOS_ABSOLUTE_PATH = $(shell cd $(KOKKOS_PATH); pwd)
export OMPI_CXX = $(KOKKOS_ABSOLUTE_PATH)/config/nvcc_wrapper
CC = mpicxx
Once you have an appropriate Makefile.machine, you can
install/un-install the package and build LAMMPS in the usual manner.
Note that you cannot build one executable to run on multiple hardware
targets (CPU or KNL or GPU). You need to build LAMMPS once for each
hardware target, to produce a separate executable. Also note that we
do not recommend building with other acceleration packages installed
(GPU, OPT, USER-INTEL, USER-OMP) when also building with KOKKOS.
make yes-kokkos
make machine :pre
make no-kokkos
make machine :pre
[Supporting info:]
src/KOKKOS: filenames -> commands
src/KOKKOS/README
lib/kokkos/README
"Section 5.3"_Section_accelerate.html#acc_3
"Section 5.3.3"_accelerate_kokkos.html
-"Section 2.7 -k on ..."_Section_start.html#start_7
-"Section 2.7 -sf kk"_Section_start.html#start_7
-"Section 2.7 -pk kokkos"_Section_start.html#start_7
+"Section 2.6 -k on ..."_Section_start.html#start_6
+"Section 2.6 -sf kk"_Section_start.html#start_6
+"Section 2.6 -pk kokkos"_Section_start.html#start_6
"package kokkos"_package.html
Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (k)
"Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul
:line
KSPACE package :link(KSPACE),h4
[Contents:]
A variety of long-range Coulombic solvers, as well as pair styles
which compute the corresponding short-range pairwise Coulombic
interactions. These include Ewald, particle-particle particle-mesh
(PPPM), and multilevel summation method (MSM) solvers.
[Install or un-install:]
Building with this package requires a 1d FFT library be present on
your system for use by the PPPM solvers. This can be the KISS FFT
library provided with LAMMPS, 3rd party libraries like FFTW, or a
vendor-supplied FFT library. See step 6 of "Section
2.2.2"_Section_start.html#start_2_2 of the manual for details on how
to select different FFT options in your machine Makefile.
make yes-kspace
make machine :pre
make no-kspace
make machine :pre
[Supporting info:]
src/KSPACE: filenames -> commands
"kspace_style"_kspace_style.html
"doc/PDF/kspace.pdf"_PDF/kspace.pdf
"Section 6.7"_Section_howto.html#howto_7
"Section 6.8"_Section_howto.html#howto_8
"Section 6.9"_Section_howto.html#howto_9
"pair_style coul"_pair_coul.html
Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 with "long" or "msm" in pair style name
examples/peptide
bench/in.rhodo :ul
:line
MANYBODY package :link(MANYBODY),h4
[Contents:]
A variety of manybody and bond-order potentials. These include
(AI)REBO, BOP, EAM, EIM, Stillinger-Weber, and Tersoff potentials.
[Install or un-install:]
make yes-manybody
make machine :pre
make no-manybody
make machine :pre
[Supporting info:]
src/MANYBODY: filenames -> commands
Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5
examples/comb
examples/eim
examples/nb3d
examples/shear
examples/streitz
examples/vashishta
bench/in.eam :ul
:line
MC package :link(MC),h4
[Contents:]
Several fixes and a pair style that have Monte Carlo (MC) or MC-like
attributes. These include fixes for creating, breaking, and swapping
bonds, for performing atomic swaps, and performing grand-canonical MC
(GCMC) in conjuction with dynamics.
[Install or un-install:]
make yes-mc
make machine :pre
make no-mc
make machine :pre
[Supporting info:]
src/MC: filenames -> commands
"fix atom/swap"_fix_atom_swap.html
"fix bond/break"_fix_bond_break.html
"fix bond/create"_fix_bond_create.html
"fix bond/swap"_fix_bond_swap.html
"fix gcmc"_fix_gcmc.html
"pair_style dsmc"_pair_dsmc.html
http://lammps.sandia.gov/movies.html#gcmc :ul
:line
MEAM package :link(MEAM),h4
[Contents:]
A pair style for the modified embedded atom (MEAM) potential.
[Author:] Greg Wagner (Northwestern U) while at Sandia.
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
MEAM library in lib/meam. You can do this manually if you prefer;
follow the instructions in lib/meam/README. You can also do it in one
step from the lammps/src dir, using a command like these, which simply
invoke the lib/meam/Install.py script with the specified args:
make lib-meam # print help message
make lib-meam args="-m gfortran" # build with GNU Fortran compiler
make lib-meam args="-m ifort" # build with Intel ifort compiler :pre
The build should produce two files: lib/meam/libmeam.a and
lib/meam/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to link C++ (LAMMPS) with
Fortran (MEAM library). Typically the two compilers used for LAMMPS
and the MEAM library need to be consistent (e.g. both Intel or both
GNU compilers). If necessary, you can edit/create a new
lib/meam/Makefile.machine file for your system, which should define an
EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine
file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-meam
make machine :pre
make no-meam
make machine :pre
NOTE: You should test building the MEAM library with both the Intel
and GNU compilers to see if a simulation runs faster with one versus
the other on your system.
[Supporting info:]
src/MEAM: filenames -> commands
src/meam/README
lib/meam/README
"pair_style meam"_pair_meam.html
examples/meam :ul
:line
MISC package :link(MISC),h4
[Contents:]
A variety of compute, fix, pair, dump styles with specialized
capabilities that don't align with other packages. Do a directory
listing, "ls src/MISC", to see the list of commands.
[Install or un-install:]
make yes-misc
make machine :pre
make no-misc
make machine :pre
[Supporting info:]
src/MISC: filenames -> commands
"compute ti"_compute_ti.html
"fix evaporate"_fix_evaporate.html
"fix orient/fcc"_fix_orient.html
"fix ttm"_fix_ttm.html
"fix thermal/conductivity"_fix_thermal_conductivity.html
"fix viscosity"_fix_viscosity.html
examples/KAPPA
examples/VISCOSITY
http://lammps.sandia.gov/pictures.html#ttm
http://lammps.sandia.gov/movies.html#evaporation :ul
:line
MOLECULE package :link(MOLECULE),h4
[Contents:]
A large number of atom, pair, bond, angle, dihedral, improper styles
that are used to model molecular systems with fixed covalent bonds.
The pair styles include the Dreiding (hydrogen-bonding) and CHARMM
force fields, and a TIP4P water model.
[Install or un-install:]
make yes-molecule
make machine :pre
make no-molecule
make machine :pre
[Supporting info:]
src/MOLECULE: filenames -> commands
"atom_style"_atom_style.html
"bond_style"_bond_style.html
"angle_style"_angle_style.html
"dihedral_style"_dihedral_style.html
"improper_style"_improper_style.html
"pair_style hbond/dreiding/lj"_pair_hbond_dreiding.html
"pair_style lj/charmm/coul/charmm"_pair_charmm.html
"Section 6.3"_Section_howto.html#howto_3
examples/cmap
examples/dreiding
examples/micelle,
examples/peptide
bench/in.chain
bench/in.rhodo :ul
:line
MPIIO package :link(MPIIO),h4
[Contents:]
Support for parallel output/input of dump and restart files via the
MPIIO library. It adds "dump styles"_dump.html with a "mpiio" in
their style name. Restart files with an ".mpiio" suffix are also
written and read in parallel.
[Install or un-install:]
Note that MPIIO is part of the standard message-passing interface
(MPI) library, so you should not need any additional compiler or link
settings, beyond what LAMMPS normally uses for MPI on your system.
make yes-mpiio
make machine :pre
make no-mpiio
make machine :pre
[Supporting info:]
src/MPIIO: filenames -> commands
"dump"_dump.html
"restart"_restart.html
"write_restart"_write_restart.html
"read_restart"_read_restart.html :ul
:line
MSCG package :link(mscg),h4
[Contents:]
A "fix mscg"_fix_mscg.html command which can parameterize a
Mulit-Scale Coarse-Graining (MSCG) model using the open-source "MS-CG
library"_mscg_home.
:link(mscg_home,https://github.com/uchicago-voth/MSCG-release)
To use this package you must have the MS-CG library available on your
system.
[Authors:] The fix was written by Lauren Abbott (Sandia). The MS-CG
library was developed by Jacob Wagner in Greg Voth's group at the
University of Chicago.
[Install or un-install:]
Before building LAMMPS with this package, you must first download and
build the MS-CG library. Building the MS-CG library and using it from
LAMMPS requires a C++11 compatible compiler, and that LAPACK and GSL
(GNU Scientific Library) libraries be installed on your machine. See
the lib/mscg/README and MSCG/Install files for more details.
Assuming these libraries are in place, you can do the download and
build of MS-CG manually if you prefer; follow the instructions in
lib/mscg/README. You can also do it in one step from the lammps/src
dir, using a command like these, which simply invoke the
lib/mscg/Install.py script with the specified args:
make lib-mscg # print help message
make lib-mscg args="-g -b -l" # download and build in default lib/mscg/MSCG-release-master
make lib-mscg args="-h . MSCG -g -b -l" # download and build in lib/mscg/MSCG
make lib-mscg args="-h ~ MSCG -g -b -l" # download and build in ~/mscg :pre
Note that the final -l switch is to create 2 symbolic (soft) links,
"includelink" and "liblink", in lib/mscg to point to the MS-CG src
dir. When LAMMPS builds it will use these links. You should not need
to edit the lib/mscg/Makefile.lammps file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-mscg
make machine :pre
make no-mscg
make machine :pre
[Supporting info:]
src/MSCG: filenames -> commands
src/MSCG/README
lib/mscg/README
examples/mscg :ul
:line
OPT package :link(OPT),h4
[Contents:]
A handful of pair styles which are optimized for improved CPU
performance on single or multiple cores. These include EAM, LJ,
CHARMM, and Morse potentials. The styles have an "opt" suffix in
their style name. "Section 5.3.5"_accelerate_opt.html gives details
of how to build and use this package. Its styles can be invoked at
run time via the "-sf opt" or "-suffix opt" "command-line
-switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS,
+switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS,
"USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which
have styles optimized for CPU performance.
[Authors:] James Fischer (High Performance Technologies), David Richie,
and Vincent Natoli (Stone Ridge Technolgy).
[Install or un-install:]
make yes-opt
make machine :pre
make no-opt
make machine :pre
NOTE: The compile flag "-restrict" must be used to build LAMMPS with
the OPT package. It should be added to the CCFLAGS line of your
Makefile.machine. See Makefile.opt in src/MAKE/OPTIONS for an
example.
CCFLAGS: add -restrict :ul
[Supporting info:]
src/OPT: filenames -> commands
"Section 5.3"_Section_accelerate.html#acc_3
"Section 5.3.5"_accelerate_opt.html
-"Section 2.7 -sf opt"_Section_start.html#start_7
+"Section 2.6 -sf opt"_Section_start.html#start_6
Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (t)
"Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul
:line
PERI package :link(PERI),h4
[Contents:]
An atom style, several pair styles which implement different
Peridynamics materials models, and several computes which calculate
diagnostics. Peridynamics is a a particle-based meshless continuum
model.
[Authors:] The original package was created by Mike Parks (Sandia).
Additional Peridynamics models were added by Rezwanur Rahman and John
Foster (UTSA).
[Install or un-install:]
make yes-peri
make machine :pre
make no-peri
make machine :pre
[Supporting info:]
src/PERI: filenames -> commands
"doc/PDF/PDLammps_overview.pdf"_PDF/PDLammps_overview.pdf
"doc/PDF/PDLammps_EPS.pdf"_PDF/PDLammps_EPS.pdf
"doc/PDF/PDLammps_VES.pdf"_PDF/PDLammps_VES.pdf
"atom_style peri"_atom_style.html
"pair_style peri/*"_pair_peri.html
"compute damage/atom"_compute_damage_atom.html
"compute plasticity/atom"_compute_plasticity_atom.html
examples/peri
http://lammps.sandia.gov/movies.html#peri :ul
:line
POEMS package :link(POEMS),h4
[Contents:]
A fix that wraps the Parallelizable Open source Efficient Multibody
Software (POEMS) library, which is able to simulate the dynamics of
articulated body systems. These are systems with multiple rigid
bodies (collections of particles) whose motion is coupled by
connections at hinge points.
[Author:] Rudra Mukherjee (JPL) while at RPI.
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
POEMS library in lib/poems. You can do this manually if you prefer;
follow the instructions in lib/poems/README. You can also do it in
one step from the lammps/src dir, using a command like these, which
simply invoke the lib/poems/Install.py script with the specified args:
make lib-poems # print help message
make lib-poems args="-m g++" # build with GNU g++ compiler
make lib-poems args="-m icc" # build with Intel icc compiler :pre
The build should produce two files: lib/poems/libpoems.a and
lib/poems/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the
POEMS library (though typically the settings are just blank). If
necessary, you can edit/create a new lib/poems/Makefile.machine file
for your system, which should define an EXTRAMAKE variable to specify
a corresponding Makefile.lammps.machine file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-poems
make machine :pre
make no-meam
make machine :pre
[Supporting info:]
src/POEMS: filenames -> commands
src/POEMS/README
lib/poems/README
"fix poems"_fix_poems.html
examples/rigid :ul
:line
PYTHON package :link(PYTHON),h4
[Contents:]
A "python"_python.html command which allow you to execute Python code
from a LAMMPS input script. The code can be in a separate file or
embedded in the input script itself. See "Section
11.2"_Section_python.html#py_2 for an overview of using Python from
LAMMPS in this manner and the entire section for other ways to use
LAMMPS and Python together.
[Install or un-install:]
make yes-python
make machine :pre
make no-python
make machine :pre
NOTE: Building with the PYTHON package assumes you have a Python
shared library available on your system, which needs to be a Python 2
version, 2.6 or later. Python 3 is not yet supported. See the
lib/python/README for more details. Note that the build uses the
lib/python/Makefile.lammps file in the compile/link process. You
should only need to create a new Makefile.lammps.* file (and copy it
to Makefile.lammps) if the LAMMPS build fails.
[Supporting info:]
src/PYTHON: filenames -> commands
"Section 11"_Section_python.html
lib/python/README
examples/python :ul
:line
QEQ package :link(QEQ),h4
[Contents:]
Several fixes for performing charge equilibration (QEq) via different
algorithms. These can be used with pair styles that perform QEq as
part of their formulation.
[Install or un-install:]
make yes-qeq
make machine :pre
make no-qeq
make machine :pre
[Supporting info:]
src/QEQ: filenames -> commands
"fix qeq/*"_fix_qeq.html
examples/qeq
examples/streitz :ul
:line
REAX package :link(REAX),h4
[Contents:]
A pair style which wraps a Fortran library which implements the ReaxFF
potential, which is a universal reactive force field. See the
"USER-REAXC package"_#USER-REAXC for an alternate implementation in
C/C++. Also a "fix reax/bonds"_fix_reax_bonds.html command for
monitoring molecules as bonds are created and destroyed.
[Author:] Aidan Thompson (Sandia).
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
REAX library in lib/reax. You can do this manually if you prefer;
follow the instructions in lib/reax/README. You can also do it in one
step from the lammps/src dir, using a command like these, which simply
invoke the lib/reax/Install.py script with the specified args:
make lib-reax # print help message
make lib-reax args="-m gfortran" # build with GNU Fortran compiler
make lib-reax args="-m ifort" # build with Intel ifort compiler :pre
The build should produce two files: lib/reax/libreax.a and
lib/reax/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to link C++ (LAMMPS) with
Fortran (REAX library). Typically the two compilers used for LAMMPS
and the REAX library need to be consistent (e.g. both Intel or both
GNU compilers). If necessary, you can edit/create a new
lib/reax/Makefile.machine file for your system, which should define an
EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine
file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-reax
make machine :pre
make no-reax
make machine :pre
[Supporting info:]
src/REAX: filenames -> commands
lib/reax/README
"pair_style reax"_pair_reax.html
"fix reax/bonds"_fix_reax_bonds.html
examples/reax :ul
:line
REPLICA package :link(REPLICA),h4
[Contents:]
A collection of multi-replica methods which can be used when running
multiple LAMMPS simulations (replicas). See "Section
6.5"_Section_howto.html#howto_5 for an overview of how to run
multi-replica simulations in LAMMPS. Methods in the package include
nudged elastic band (NEB), parallel replica dynamics (PRD),
temperature accelerated dynamics (TAD), parallel tempering, and a
verlet/split algorithm for performing long-range Coulombics on one set
of processors, and the remainder of the force field calcalation on
another set.
[Install or un-install:]
make yes-replica
make machine :pre
make no-replica
make machine :pre
[Supporting info:]
src/REPLICA: filenames -> commands
"Section 6.5"_Section_howto.html#howto_5
"neb"_neb.html
"prd"_prd.html
"tad"_tad.html
"temper"_temper.html,
"run_style verlet/split"_run_style.html
examples/neb
examples/prd
examples/tad :ul
:line
RIGID package :link(RIGID),h4
[Contents:]
Fixes which enforce rigid constraints on collections of atoms or
particles. This includes SHAKE and RATTLE, as well as varous
rigid-body integrators for a few large bodies or many small bodies.
Also several computes which calculate properties of rigid bodies.
To install/build:
make yes-rigid
make machine :pre
To un-install/re-build:
make no-rigid
make machine :pre
[Supporting info:]
src/RIGID: filenames -> commands
"compute erotate/rigid"_compute_erotate_rigid.html
fix shake"_fix_shake.html
"fix rattle"_fix_shake.html
"fix rigid/*"_fix_rigid.html
examples/ASPHERE
examples/rigid
bench/in.rhodo
http://lammps.sandia.gov/movies.html#box
http://lammps.sandia.gov/movies.html#star :ul
:line
SHOCK package :link(SHOCK),h4
[Contents:]
Fixes for running impact simulations where a shock-wave passes through
a material.
[Install or un-install:]
make yes-shock
make machine :pre
make no-shock
make machine :pre
[Supporting info:]
src/SHOCK: filenames -> commands
"fix append/atoms"_fix_append_atoms.html
"fix msst"_fix_msst.html
"fix nphug"_fix_nphug.html
"fix wall/piston"_fix_wall_piston.html
examples/hugoniostat
examples/msst :ul
:line
SNAP package :link(SNAP),h4
[Contents:]
A pair style for the spectral neighbor analysis potential (SNAP).
SNAP is methodology for deriving a highly accurate classical potential
fit to a large archive of quantum mechanical (DFT) data. Also several
computes which analyze attributes of the potential.
[Author:] Aidan Thompson (Sandia).
[Install or un-install:]
make yes-snap
make machine :pre
make no-snap
make machine :pre
[Supporting info:]
src/SNAP: filenames -> commands
"pair snap"_pair_snap.html
"compute sna/atom"_compute_sna_atom.html
"compute snad/atom"_compute_sna_atom.html
"compute snav/atom"_compute_sna_atom.html
examples/snap :ul
:line
SRD package :link(SRD),h4
[Contents:]
A pair of fixes which implement the Stochastic Rotation Dynamics (SRD)
method for coarse-graining of a solvent, typically around large
colloidal particles.
To install/build:
make yes-srd
make machine :pre
To un-install/re-build:
make no-srd
make machine :pre
[Supporting info:]
src/SRD: filenames -> commands
"fix srd"_fix_srd.html
"fix wall/srd"_fix_wall_srd.html
examples/srd
examples/ASPHERE
http://lammps.sandia.gov/movies.html#tri
http://lammps.sandia.gov/movies.html#line
http://lammps.sandia.gov/movies.html#poly :ul
:line
VORONOI package :link(VORONOI),h4
[Contents:]
A compute command which calculates the Voronoi tesselation of a
collection of atoms by wrapping the "Voro++ library"_voro_home. This
can be used to calculate the local volume or each atoms or its near
neighbors.
:link(voro_home,http://math.lbl.gov/voro++)
To use this package you must have the Voro++ library available on your
system.
[Author:] Daniel Schwen (INL) while at LANL. The open-source Voro++
library was written by Chris Rycroft (Harvard U) while at UC Berkeley
and LBNL.
[Install or un-install:]
Before building LAMMPS with this package, you must first download and
build the Voro++ library. You can do this manually if you prefer;
follow the instructions in lib/voronoi/README. You can also do it in
one step from the lammps/src dir, using a command like these, which
simply invoke the lib/voronoi/Install.py script with the specified
args:
make lib-voronoi # print help message
make lib-voronoi args="-g -b -l" # download and build in default lib/voronoi/voro++-0.4.6
make lib-voronoi args="-h . voro++ -g -b -l" # download and build in lib/voronoi/voro++
make lib-voronoi args="-h ~ voro++ -g -b -l" # download and build in ~/voro++ :pre
Note that the final -l switch is to create 2 symbolic (soft) links,
"includelink" and "liblink", in lib/voronoi to point to the Voro++ src
dir. When LAMMPS builds it will use these links. You should not need
to edit the lib/voronoi/Makefile.lammps file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-voronoi
make machine :pre
make no-voronoi
make machine :pre
[Supporting info:]
src/VORONOI: filenames -> commands
src/VORONOI/README
lib/voronoi/README
"compute voronoi/atom"_compute_voronoi_atom.html
examples/voronoi :ul
:line
:line
USER-ATC package :link(USER-ATC),h4
[Contents:]
ATC stands for atoms-to-continuum. This package implements a "fix
atc"_fix_atc.html command to either couple molecular dynamics with
continuum finite element equations or perform on-the-fly conversion of
atomic information to continuum fields.
[Authors:] Reese Jones, Jeremy Templeton, Jon Zimmerman (Sandia).
[Install or un-install:]
Before building LAMMPS with this package, you must first build the ATC
library in lib/atc. You can do this manually if you prefer; follow
the instructions in lib/atc/README. You can also do it in one step
from the lammps/src dir, using a command like these, which simply
invoke the lib/atc/Install.py script with the specified args:
make lib-atc # print help message
make lib-atc args="-m g++" # build with GNU g++ compiler
make lib-atc args="-m icc" # build with Intel icc compiler :pre
The build should produce two files: lib/atc/libatc.a and
lib/atc/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the ATC
library. If necessary, you can edit/create a new
lib/atc/Makefile.machine file for your system, which should define an
EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine
file.
Note that the Makefile.lammps file has settings for the BLAS and
LAPACK linear algebra libraries. As explained in lib/atc/README these
can either exist on your system, or you can use the files provided in
lib/linalg. In the latter case you also need to build the library
in lib/linalg with a command like these:
make lib-linalg # print help message
make lib-atc args="-m gfortran" # build with GNU Fortran compiler
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-atc
make machine :pre
make no-user-atc
make machine :pre
[Supporting info:]
src/USER-ATC: filenames -> commands
src/USER-ATC/README
"fix atc"_fix_atc.html
examples/USER/atc
http://lammps.sandia.gov/pictures.html#atc :ul
:line
USER-AWPMD package :link(USER-AWPMD),h4
[Contents:]
AWPMD stands for Antisymmetrized Wave Packet Molecular Dynamics. This
package implements an atom, pair, and fix style which allows electrons
to be treated as explicit particles in a classical molecular dynamics
model.
[Author:] Ilya Valuev (JIHT, Russia).
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
AWPMD library in lib/awpmd. You can do this manually if you prefer;
follow the instructions in lib/awpmd/README. You can also do it in
one step from the lammps/src dir, using a command like these, which
simply invoke the lib/awpmd/Install.py script with the specified args:
make lib-awpmd # print help message
make lib-awpmd args="-m g++" # build with GNU g++ compiler
make lib-awpmd args="-m icc" # build with Intel icc compiler :pre
The build should produce two files: lib/awpmd/libawpmd.a and
lib/awpmd/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the
AWPMD library. If necessary, you can edit/create a new
lib/awpmd/Makefile.machine file for your system, which should define
an EXTRAMAKE variable to specify a corresponding
Makefile.lammps.machine file.
Note that the Makefile.lammps file has settings for the BLAS and
LAPACK linear algebra libraries. As explained in lib/awpmd/README
these can either exist on your system, or you can use the files
provided in lib/linalg. In the latter case you also need to build the
library in lib/linalg with a command like these:
make lib-linalg # print help message
make lib-atc args="-m gfortran" # build with GNU Fortran compiler
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-awpmd
make machine :pre
make no-user-awpmd
make machine :pre
[Supporting info:]
src/USER-AWPMD: filenames -> commands
src/USER-AWPMD/README
"pair awpmd/cut"_pair_awpmd.html
examples/USER/awpmd :ul
:line
USER-CGDNA package :link(USER-CGDNA),h4
[Contents:]
Several pair styles, a bond style, and integration fixes for
coarse-grained models of single- and double-stranded DNA based on the
oxDNA model of Doye, Louis and Ouldridge at the University of Oxford.
This includes Langevin-type rigid-body integrators with improved
stability.
[Author:] Oliver Henrich (University of Strathclyde, Glasgow).
[Install or un-install:]
make yes-user-cgdna
make machine :pre
make no-user-cgdna
make machine :pre
[Supporting info:]
src/USER-CGDNA: filenames -> commands
/src/USER-CGDNA/README
"pair_style oxdna/*"_pair_oxdna.html
"pair_style oxdna2/*"_pair_oxdna2.html
"bond_style oxdna/*"_bond_oxdna.html
"bond_style oxdna2/*"_bond_oxdna.html
"fix nve/dotc/langevin"_fix_nve_dotc_langevin.html :ul
:line
USER-CGSDK package :link(USER-CGSDK),h4
[Contents:]
Several pair styles and an angle style which implement the
coarse-grained SDK model of Shinoda, DeVane, and Klein which enables
simulation of ionic liquids, electrolytes, lipids and charged amino
acids.
[Author:] Axel Kohlmeyer (Temple U).
[Install or un-install:]
make yes-user-cgsdk
make machine :pre
make no-user-cgsdk
make machine :pre
[Supporting info:]
src/USER-CGSDK: filenames -> commands
src/USER-CGSDK/README
"pair_style lj/sdk/*"_pair_sdk.html
"angle_style sdk"_angle_sdk.html
examples/USER/cgsdk
http://lammps.sandia.gov/pictures.html#cg :ul
:line
USER-COLVARS package :link(USER-COLVARS),h4
[Contents:]
COLVARS stands for collective variables, which can be used to
implement various enhanced sampling methods, including Adaptive
Biasing Force, Metadynamics, Steered MD, Umbrella Sampling and
Restraints. A "fix colvars"_fix_colvars.html command is implemented
which wraps a COLVARS library, which implements these methods.
simulations.
[Authors:] Axel Kohlmeyer (Temple U). The COLVARS library was written
by Giacomo Fiorin (ICMS, Temple University, Philadelphia, PA, USA) and
Jerome Henin (LISM, CNRS, Marseille, France).
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
COLVARS library in lib/colvars. You can do this manually if you
prefer; follow the instructions in lib/colvars/README. You can also
do it in one step from the lammps/src dir, using a command like these,
which simply invoke the lib/colvars/Install.py script with the
specified args:
make lib-colvars # print help message
make lib-colvars args="-m g++" # build with GNU g++ compiler :pre
The build should produce two files: lib/colvars/libcolvars.a and
lib/colvars/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the
COLVARS library (though typically the settings are just blank). If
necessary, you can edit/create a new lib/colvars/Makefile.machine file
for your system, which should define an EXTRAMAKE variable to specify
a corresponding Makefile.lammps.machine file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-colvars
make machine :pre
make no-user-colvars
make machine :pre
[Supporting info:]
src/USER-COLVARS: filenames -> commands
"doc/PDF/colvars-refman-lammps.pdf"_PDF/colvars-refman-lammps.pdf
src/USER-COLVARS/README
lib/colvars/README
"fix colvars"_fix_colvars.html
examples/USER/colvars :ul
:line
USER-DIFFRACTION package :link(USER-DIFFRACTION),h4
[Contents:]
Two computes and a fix for calculating x-ray and electron diffraction
intensities based on kinematic diffraction theory.
[Author:] Shawn Coleman while at the U Arkansas.
[Install or un-install:]
make yes-user-diffraction
make machine :pre
make no-user-diffraction
make machine :pre
[Supporting info:]
src/USER-DIFFRACTION: filenames -> commands
"compute saed"_compute_saed.html
"compute xrd"_compute_xrd.html
"fix saed/vtk"_fix_saed_vtk.html
examples/USER/diffraction :ul
:line
USER-DPD package :link(USER-DPD),h4
[Contents:]
DPD stands for dissipative particle dynamics. This package implements
coarse-grained DPD-based models for energetic, reactive molecular
crystalline materials. It includes many pair styles specific to these
systems, including for reactive DPD, where each particle has internal
state for multiple species and a coupled set of chemical reaction ODEs
are integrated each timestep. Highly accurate time intergrators for
isothermal, isoenergetic, isobaric and isenthalpic conditions are
included. These enable long timesteps via the Shardlow splitting
algorithm.
[Authors:] Jim Larentzos (ARL), Tim Mattox (Engility Corp), and and John
Brennan (ARL).
[Install or un-install:]
make yes-user-dpd
make machine :pre
make no-user-dpd
make machine :pre
[Supporting info:]
src/USER-DPD: filenames -> commands
/src/USER-DPD/README
"compute dpd"_compute_dpd.html
"compute dpd/atom"_compute_dpd_atom.html
"fix eos/cv"_fix_eos_table.html
"fix eos/table"_fix_eos_table.html
"fix eos/table/rx"_fix_eos_table_rx.html
"fix shardlow"_fix_shardlow.html
"fix rx"_fix_rx.html
"pair table/rx"_pair_table_rx.html
"pair dpd/fdt"_pair_dpd_fdt.html
"pair dpd/fdt/energy"_pair_dpd_fdt.html
"pair exp6/rx"_pair_exp6_rx.html
"pair multi/lucy"_pair_multi_lucy.html
"pair multi/lucy/rx"_pair_multi_lucy_rx.html
examples/USER/dpd :ul
:line
USER-DRUDE package :link(USER-DRUDE),h4
[Contents:]
Fixes, pair styles, and a compute to simulate thermalized Drude
oscillators as a model of polarization. See "Section
6.27"_Section_howto.html#howto_27 for an overview of how to use the
package. There are auxiliary tools for using this package in
tools/drude.
[Authors:] Alain Dequidt (U Blaise Pascal Clermont-Ferrand), Julien
Devemy (CNRS), and Agilio Padua (U Blaise Pascal).
[Install or un-install:]
make yes-user-drude
make machine :pre
make no-user-drude
make machine :pre
[Supporting info:]
src/USER-DRUDE: filenames -> commands
"Section 6.27"_Section_howto.html#howto_27
"Section 6.25"_Section_howto.html#howto_25
src/USER-DRUDE/README
"fix drude"_fix_drude.html
"fix drude/transform/*"_fix_drude_transform.html
"compute temp/drude"_compute_temp_drude.html
"pair thole"_pair_thole.html
"pair lj/cut/thole/long"_pair_thole.html
examples/USER/drude
tools/drude :ul
:line
USER-EFF package :link(USER-EFF),h4
[Contents:]
EFF stands for electron force field which allows a classical MD code
to model electrons as particles of variable radius. This package
contains atom, pair, fix and compute styles which implement the eFF as
described in A. Jaramillo-Botero, J. Su, Q. An, and W.A. Goddard III,
JCC, 2010. The eFF potential was first introduced by Su and Goddard,
in 2007. There are auxiliary tools for using this package in
tools/eff; see its README file.
[Author:] Andres Jaramillo-Botero (CalTech).
[Install or un-install:]
make yes-user-eff
make machine :pre
make no-user-eff
make machine :pre
[Supporting info:]
src/USER-EFF: filenames -> commands
src/USER-EFF/README
"atom_style electron"_atom_style.html
"fix nve/eff"_fix_nve_eff.html
"fix nvt/eff"_fix_nh_eff.html
"fix npt/eff"_fix_nh_eff.html
"fix langevin/eff"_fix_langevin_eff.html
"compute temp/eff"_compute_temp_eff.html
"pair eff/cut"_pair_eff.html
"pair eff/inline"_pair_eff.html
examples/USER/eff
tools/eff/README
tools/eff
http://lammps.sandia.gov/movies.html#eff :ul
:line
USER-FEP package :link(USER-FEP),h4
[Contents:]
FEP stands for free energy perturbation. This package provides
methods for performing FEP simulations by using a "fix
adapt/fep"_fix_adapt_fep.html command with soft-core pair potentials,
which have a "soft" in their style name. There are auxiliary tools
for using this package in tools/fep; see its README file.
[Author:] Agilio Padua (Universite Blaise Pascal Clermont-Ferrand)
[Install or un-install:]
make yes-user-fep
make machine :pre
make no-user-fep
make machine :pre
[Supporting info:]
src/USER-FEP: filenames -> commands
src/USER-FEP/README
"fix adapt/fep"_fix_adapt_fep.html
"compute fep"_compute_fep.html
"pair_style */soft"_pair_lj_soft.html
examples/USER/fep
tools/fep/README
tools/fep :ul
:line
USER-H5MD package :link(USER-H5MD),h4
[Contents:]
H5MD stands for HDF5 for MD. "HDF5"_HDF5 is a portable, binary,
self-describing file format, used by many scientific simulations.
H5MD is a format for molecular simulations, built on top of HDF5.
This package implements a "dump h5md"_dump_h5md.html command to output
LAMMPS snapshots in this format.
:link(HDF5,http://www.hdfgroup.org/HDF5)
To use this package you must have the HDF5 library available on your
system.
[Author:] Pierre de Buyl (KU Leuven) created both the package and the
H5MD format.
[Install or un-install:]
Note that to follow these steps to compile and link to the CH5MD
library, you need the standard HDF5 software package installed on your
system, which should include the h5cc compiler and the HDF5 library.
Before building LAMMPS with this package, you must first build the
CH5MD library in lib/h5md. You can do this manually if you prefer;
follow the instructions in lib/h5md/README. You can also do it in one
step from the lammps/src dir, using a command like these, which simply
invoke the lib/h5md/Install.py script with the specified args:
make lib-h5md # print help message
make lib-hm5d args="-m h5cc" # build with h5cc compiler :pre
The build should produce two files: lib/h5md/libch5md.a and
lib/h5md/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the
system HDF5 library. If necessary, you can edit/create a new
lib/h5md/Makefile.machine file for your system, which should define an
EXTRAMAKE variable to specify a corresponding Makefile.lammps.machine
file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-h5md
make machine :pre
make no-user-h5md
make machine :pre
[Supporting info:]
src/USER-H5MD: filenames -> commands
src/USER-H5MD/README
lib/h5md/README
"dump h5md"_dump_h5md.html :ul
:line
USER-INTEL package :link(USER-INTEL),h4
[Contents:]
Dozens of pair, fix, bond, angle, dihedral, improper, and kspace
styles which are optimized for Intel CPUs and KNLs (Knights Landing).
All of them have an "intel" in their style name. "Section
5.3.2"_accelerate_intel.html gives details of what hardware and
compilers are required on your system, and how to build and use this
package. Its styles can be invoked at run time via the "-sf intel" or
-"-suffix intel" "command-line switches"_Section_start.html#start_7.
+"-suffix intel" "command-line switches"_Section_start.html#start_6.
Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-OMP"_#USER-OMP
packages, which have styles optimized for CPUs and KNLs.
You need to have an Intel compiler, version 14 or higher to take full
advantage of this package.
[Author:] Mike Brown (Intel).
[Install or un-install:]
For the USER-INTEL package, you have 2 choices when building. You can
build with either CPU or KNL support. Each choice requires additional
settings in your Makefile.machine for CCFLAGS and LINKFLAGS and
optimized malloc libraries. See the
src/MAKE/OPTIONS/Makefile.intel_cpu and src/MAKE/OPTIONS/Makefile.knl
files for examples.
For CPUs:
OPTFLAGS = -xHost -O2 -fp-model fast=2 -no-prec-div -qoverride-limits
CCFLAGS = -g -qopenmp -DLAMMPS_MEMALIGN=64 -no-offload \
-fno-alias -ansi-alias -restrict $(OPTFLAGS)
LINKFLAGS = -g -qopenmp $(OPTFLAGS)
LIB = -ltbbmalloc -ltbbmalloc_proxy
For KNLs:
OPTFLAGS = -xMIC-AVX512 -O2 -fp-model fast=2 -no-prec-div -qoverride-limits
CCFLAGS = -g -qopenmp -DLAMMPS_MEMALIGN=64 -no-offload \
-fno-alias -ansi-alias -restrict $(OPTFLAGS)
LINKFLAGS = -g -qopenmp $(OPTFLAGS)
LIB = -ltbbmalloc
Once you have an appropriate Makefile.machine, you can
install/un-install the package and build LAMMPS in the usual manner.
Note that you cannot build one executable to run on multiple hardware
targets (Intel CPUs or KNL). You need to build LAMMPS once for each
hardware target, to produce a separate executable.
You should also typically install the USER-OMP package, as it can be
used in tandem with the USER-INTEL package to good effect, as
explained in "Section 5.3.2"_accelerate_intel.html.
make yes-user-intel yes-user-omp
make machine :pre
make no-user-intel no-user-omp
make machine :pre
[Supporting info:]
src/USER-INTEL: filenames -> commands
src/USER-INTEL/README
"Section 5.3"_Section_accelerate.html#acc_3
"Section 5.3.2"_accelerate_gpu.html
-"Section 2.7 -sf intel"_Section_start.html#start_7
-"Section 2.7 -pk intel"_Section_start.html#start_7
+"Section 2.6 -sf intel"_Section_start.html#start_6
+"Section 2.6 -pk intel"_Section_start.html#start_6
"package intel"_package.html
Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (i)
src/USER-INTEL/TEST
"Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul
:line
USER-LB package :link(USER-LB),h4
[Contents:]
Fixes which implement a background Lattice-Boltzmann (LB) fluid, which
can be used to model MD particles influenced by hydrodynamic forces.
[Authors:] Frances Mackay and Colin Denniston (University of Western
Ontario).
[Install or un-install:]
make yes-user-lb
make machine :pre
make no-user-lb
make machine :pre
[Supporting info:]
src/USER-LB: filenames -> commands
src/USER-LB/README
"fix lb/fluid"_fix_lb_fluid.html
"fix lb/momentum"_fix_lb_momentum.html
"fix lb/viscous"_fix_lb_viscous.html
examples/USER/lb :ul
:line
USER-MGPT package :link(USER-MGPT),h4
[Contents:]
A pair style which provides a fast implementation of the quantum-based
MGPT multi-ion potentials. The MGPT or model GPT method derives from
first-principles DFT-based generalized pseudopotential theory (GPT)
through a series of systematic approximations valid for mid-period
transition metals with nearly half-filled d bands. The MGPT method
was originally developed by John Moriarty at LLNL. The pair style in
this package calculates forces and energies using an optimized
matrix-MGPT algorithm due to Tomas Oppelstrup at LLNL.
[Authors:] Tomas Oppelstrup and John Moriarty (LLNL).
[Install or un-install:]
make yes-user-mgpt
make machine :pre
make no-user-mgpt
make machine :pre
[Supporting info:]
src/USER-MGPT: filenames -> commands
src/USER-MGPT/README
"pair_style mgpt"_pair_mgpt.html
examples/USER/mgpt :ul
:line
USER-MISC package :link(USER-MISC),h4
[Contents:]
A potpourri of (mostly) unrelated features contributed to LAMMPS by
users. Each feature is a single fix, compute, pair, bond, angle,
dihedral, improper, or command style.
[Authors:] The author for each style in the package is listed in the
src/USER-MISC/README file.
[Install or un-install:]
make yes-user-misc
make machine :pre
make no-user-misc
make machine :pre
[Supporting info:]
src/USER-MISC: filenames -> commands
src/USER-MISC/README
one doc page per individual command listed in src/USER-MISC/README
examples/USER/misc :ul
:line
USER-MANIFOLD package :link(USER-MANIFOLD),h4
[Contents:]
Several fixes and a "manifold" class which enable simulations of
particles constrained to a manifold (a 2D surface within the 3D
simulation box). This is done by applying the RATTLE constraint
algorithm to formulate single-particle constraint functions
g(xi,yi,zi) = 0 and their derivative (i.e. the normal of the manifold)
n = grad(g).
[Author:] Stefan Paquay (until 2017: Eindhoven University of Technology (TU/e), The
Netherlands; since 2017: Brandeis University, Waltham, MA, USA)
[Install or un-install:]
make yes-user-manifold
make machine :pre
make no-user-manifold
make machine :pre
[Supporting info:]
src/USER-MANIFOLD: filenames -> commands
src/USER-MANIFOLD/README
"doc/manifolds"_manifolds.html
"fix manifoldforce"_fix_manifoldforce.html
"fix nve/manifold/rattle"_fix_nve_manifold_rattle.html
"fix nvt/manifold/rattle"_fix_nvt_manifold_rattle.html
examples/USER/manifold
http://lammps.sandia.gov/movies.html#manifold :ul
:line
USER-MEAMC package :link(USER-MEAMC),h4
[Contents:]
A pair style for the modified embedded atom (MEAM) potential
translated from the Fortran version in the "MEAM"_MEAM package
to plain C++. In contrast to the MEAM package, no library
needs to be compiled and the pair style can be instantiated
multiple times.
[Author:] Sebastian Huetter, (Otto-von-Guericke University Magdeburg)
based on the Fortran version of Greg Wagner (Northwestern U) while at
Sandia.
[Install or un-install:]
make yes-user-meamc
make machine :pre
make no-user-meamc
make machine :pre
[Supporting info:]
src/USER-MEAMC: filenames -> commands
src/USER-MEAMC/README
"pair meam/c"_pair_meam.html
examples/meam :ul
:line
USER-MOLFILE package :link(USER-MOLFILE),h4
[Contents:]
A "dump molfile"_dump_molfile.html command which uses molfile plugins
that are bundled with the "VMD"_vmd_home
molecular visualization and analysis program, to enable LAMMPS to dump
snapshots in formats compatible with various molecular simulation
tools.
:link(vmd_home,http://www.ks.uiuc.edu/Research/vmd)
To use this package you must have the desired VMD plugins available on
your system.
Note that this package only provides the interface code, not the
plugins themselves, which will be accessed when requesting a specific
plugin via the "dump molfile"_dump_molfile.html command. Plugins can
be obtained from a VMD installation which has to match the platform
that you are using to compile LAMMPS for. By adding plugins to VMD,
support for new file formats can be added to LAMMPS (or VMD or other
programs that use them) without having to recompile the application
itself. More information about the VMD molfile plugins can be found
at
"http://www.ks.uiuc.edu/Research/vmd/plugins/molfile"_http://www.ks.uiuc.edu/Research/vmd/plugins/molfile.
[Author:] Axel Kohlmeyer (Temple U).
[Install or un-install:]
Note that the lib/molfile/Makefile.lammps file has a setting for a
dynamic loading library libdl.a that should is typically present on
all systems, which is required for LAMMPS to link with this package.
If the setting is not valid for your system, you will need to edit the
Makefile.lammps file. See lib/molfile/README and
lib/molfile/Makefile.lammps for details.
make yes-user-molfile
make machine :pre
make no-user-molfile
make machine :pre
[Supporting info:]
src/USER-MOLFILE: filenames -> commands
src/USER-MOLFILE/README
lib/molfile/README
"dump molfile"_dump_molfile.html :ul
:line
USER-NETCDF package :link(USER-NETCDF),h4
[Contents:]
Dump styles for writing NetCDF formatted dump files. NetCDF is a
portable, binary, self-describing file format developed on top of
HDF5. The file contents follow the AMBER NetCDF trajectory conventions
(http://ambermd.org/netcdf/nctraj.xhtml), but include extensions.
To use this package you must have the NetCDF library available on your
system.
Note that NetCDF files can be directly visualized with the following
tools:
"Ovito"_ovito (Ovito supports the AMBER convention and the extensions mentioned above)
"VMD"_vmd_home
"AtomEye"_atomeye (the libAtoms version of AtomEye contains a NetCDF reader not present in the standard distribution) :ul
:link(ovito,http://www.ovito.org)
:link(atomeye,http://www.libatoms.org)
[Author:] Lars Pastewka (Karlsruhe Institute of Technology).
[Install or un-install:]
Note that to follow these steps, you need the standard NetCDF software
package installed on your system. The lib/netcdf/Makefile.lammps file
has settings for NetCDF include and library files that LAMMPS needs to
compile and linkk with this package. If the settings are not valid
for your system, you will need to edit the Makefile.lammps file. See
lib/netcdf/README for details.
make yes-user-netcdf
make machine :pre
make no-user-netcdf
make machine :pre
[Supporting info:]
src/USER-NETCDF: filenames -> commands
src/USER-NETCDF/README
lib/netcdf/README
"dump netcdf"_dump_netcdf.html :ul
:line
USER-OMP package :link(USER-OMP),h4
[Contents:]
Hundreds of pair, fix, compute, bond, angle, dihedral, improper, and
kspace styles which are altered to enable threading on many-core CPUs
via OpenMP directives. All of them have an "omp" in their style name.
"Section 5.3.4"_accelerate_omp.html gives details of what hardware and
compilers are required on your system, and how to build and use this
package. Its styles can be invoked at run time via the "-sf omp" or
-"-suffix omp" "command-line switches"_Section_start.html#start_7.
+"-suffix omp" "command-line switches"_Section_start.html#start_6.
Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and
"USER-INTEL"_#USER-INTEL packages, which have styles optimized for
CPUs.
[Author:] Axel Kohlmeyer (Temple U).
NOTE: The compile flags "-restrict" and "-fopenmp" must be used to
build LAMMPS with the USER-OMP package, as well as the link flag
"-fopenmp". They should be added to the CCFLAGS and LINKFLAGS lines
of your Makefile.machine. See src/MAKE/OPTIONS/Makefile.omp for an
example.
Once you have an appropriate Makefile.machine, you can
install/un-install the package and build LAMMPS in the usual manner:
[Install or un-install:]
make yes-user-omp
make machine :pre
make no-user-omp
make machine :pre
CCFLAGS: add -fopenmp and -restrict
LINKFLAGS: add -fopenmp :ul
[Supporting info:]
src/USER-OMP: filenames -> commands
src/USER-OMP/README
"Section 5.3"_Section_accelerate.html#acc_3
"Section 5.3.4"_accelerate_omp.html
-"Section 2.7 -sf omp"_Section_start.html#start_7
-"Section 2.7 -pk omp"_Section_start.html#start_7
+"Section 2.6 -sf omp"_Section_start.html#start_6
+"Section 2.6 -pk omp"_Section_start.html#start_6
"package omp"_package.html
Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (o)
"Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul
:line
USER-PHONON package :link(USER-PHONON),h4
[Contents:]
A "fix phonon"_fix_phonon.html command that calculates dynamical
matrices, which can then be used to compute phonon dispersion
relations, directly from molecular dynamics simulations.
[Author:] Ling-Ti Kong (Shanghai Jiao Tong University).
[Install or un-install:]
make yes-user-phonon
make machine :pre
make no-user-phonon
make machine :pre
[Supporting info:]
src/USER-PHONON: filenames -> commands
src/USER-PHONON/README
"fix phonon"_fix_phonon.html
examples/USER/phonon :ul
:line
USER-QMMM package :link(USER-QMMM),h4
[Contents:]
A "fix qmmm"_fix_qmmm.html command which allows LAMMPS to be used in a
QM/MM simulation, currently only in combination with the "Quantum
ESPRESSO"_espresso package.
:link(espresso,http://www.quantum-espresso.org)
To use this package you must have Quantum ESPRESSO available on your
system.
The current implementation only supports an ONIOM style mechanical
coupling to the Quantum ESPRESSO plane wave DFT package.
Electrostatic coupling is in preparation and the interface has been
written in a manner that coupling to other QM codes should be possible
without changes to LAMMPS itself.
[Author:] Axel Kohlmeyer (Temple U).
[Install or un-install:]
Before building LAMMPS with this package, you must first build the
QMMM library in lib/qmmm. You can do this manually if you prefer;
follow the first two steps explained in lib/colvars/README. You can
also do it in one step from the lammps/src dir, using a command like
these, which simply invoke the lib/colvars/Install.py script with the
specified args:
make lib-qmmm # print help message
make lib-qmmm args="-m gfortran" # build with GNU Fortran compiler :pre
The build should produce two files: lib/qmmm/libqmmm.a and
lib/qmmm/Makefile.lammps. The latter is copied from an existing
Makefile.lammps.* and has settings needed to build LAMMPS with the
QMMM library (though typically the settings are just blank). If
necessary, you can edit/create a new lib/qmmm/Makefile.machine file
for your system, which should define an EXTRAMAKE variable to specify
a corresponding Makefile.lammps.machine file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-qmmm
make machine :pre
make no-user-qmmm
make machine :pre
NOTE: The LAMMPS executable these steps produce is not yet functional
for a QM/MM simulation. You must also build Quantum ESPRESSO and
create a new executable which links LAMMPS and Quanutm ESPRESSO
together. These are steps 3 and 4 described in the lib/qmmm/README
file.
[Supporting info:]
src/USER-QMMM: filenames -> commands
src/USER-QMMM/README
lib/qmmm/README
"fix phonon"_fix_phonon.html
lib/qmmm/example-ec/README
lib/qmmm/example-mc/README :ul
:line
USER-QTB package :link(USER-QTB),h4
[Contents:]
Two fixes which provide a self-consistent quantum treatment of
vibrational modes in a classical molecular dynamics simulation. By
coupling the MD simulation to a colored thermostat, it introduces zero
point energy into the system, altering the energy power spectrum and
the heat capacity to account for their quantum nature. This is useful
when modeling systems at temperatures lower than their classical
limits or when temperatures ramp across the classical limits in a
simulation.
[Author:] Yuan Shen (Stanford U).
[Install or un-install:]
make yes-user-qtb
make machine :pre
make no-user-qtb
make machine :pre
[Supporting info:]
src/USER-QTB: filenames -> commands
src/USER-QTB/README
"fix qtb"_fix_qtb.html
"fix qbmsst"_fix_qbmsst.html
examples/USER/qtb :ul
:line
USER-QUIP package :link(USER-QUIP),h4
[Contents:]
A "pair_style quip"_pair_quip.html command which wraps the "QUIP
libAtoms library"_quip, which includes a variety of interatomic
potentials, including Gaussian Approximation Potential (GAP) models
developed by the Cambridge University group.
:link(quip,https://github.com/libAtoms/QUIP)
To use this package you must have the QUIP libAatoms library available
on your system.
[Author:] Albert Bartok (Cambridge University)
[Install or un-install:]
Note that to follow these steps to compile and link to the QUIP
library, you must first download and build QUIP on your systems. It
can be obtained from GitHub. See step 1 and step 1.1 in the
lib/quip/README file for details on how to do this. Note that it
requires setting two environment variables, QUIP_ROOT and QUIP_ARCH,
which will be accessed by the lib/quip/Makefile.lammps file which is
used when you compile and link LAMMPS with this package. You should
only need to edit this file if the LAMMPS build can not use its
settings to successfully build on your system.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-quip
make machine :pre
make no-user-quip
make machine :pre
[Supporting info:]
src/USER-QUIP: filenames -> commands
src/USER-QUIP/README
"pair_style quip"_pair_quip.html
examples/USER/quip :ul
:line
USER-REAXC package :link(USER-REAXC),h4
[Contents:]
A pair style which implements the ReaxFF potential in C/C++ (in
contrast to the "REAX package"_#REAX and its Fortran library). ReaxFF
is universal reactive force field. See the src/USER-REAXC/README file
for more info on differences between the two packages. Also two fixes
for monitoring molecules as bonds are created and destroyed.
[Author:] Hasan Metin Aktulga (MSU) while at Purdue University.
[Install or un-install:]
make yes-user-reaxc
make machine :pre
make no-user-reaxc
make machine :pre
[Supporting info:]
src/USER-REAXC: filenames -> commands
src/USER-REAXC/README
"pair_style reax/c"_pair_reaxc.html
"fix reax/c/bonds"_fix_reax_bonds.html
"fix reax/c/species"_fix_reaxc_species.html
examples/reax :ul
:line
USER-SMD package :link(USER-SMD),h4
[Contents:]
An atom style, fixes, computes, and several pair styles which
implements smoothed Mach dynamics (SMD) for solids, which is a model
related to smoothed particle hydrodynamics (SPH) for liquids (see the
"USER-SPH package"_#USER-SPH).
This package solves solids mechanics problems via a state of the art
stabilized meshless method with hourglass control. It can specify
hydrostatic interactions independently from material strength models,
i.e. pressure and deviatoric stresses are separated. It provides many
material models (Johnson-Cook, plasticity with hardening,
Mie-Grueneisen, Polynomial EOS) and allows new material models to be
added. It implements rigid boundary conditions (walls) which can be
specified as surface geometries from *.STL files.
[Author:] Georg Ganzenmuller (Fraunhofer-Institute for High-Speed
Dynamics, Ernst Mach Institute, Germany).
[Install or un-install:]
Before building LAMMPS with this package, you must first download the
Eigen library. Eigen is a template library, so you do not need to
build it, just download it. You can do this manually if you prefer;
follow the instructions in lib/smd/README. You can also do it in one
step from the lammps/src dir, using a command like these, which simply
invoke the lib/smd/Install.py script with the specified args:
make lib-smd # print help message
make lib-smd args="-g -l" # download in default lib/smd/eigen-eigen-*
make lib-smd args="-h . eigen -g -l" # download in lib/smd/eigen
make lib-smd args="-h ~ eigen -g -l" # download and build in ~/eigen :pre
Note that the final -l switch is to create a symbolic (soft) link
named "includelink" in lib/smd to point to the Eigen dir. When LAMMPS
builds it will use this link. You should not need to edit the
lib/smd/Makefile.lammps file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-smd
make machine :pre
make no-user-smd
make machine :pre
[Supporting info:]
src/USER-SMD: filenames -> commands
src/USER-SMD/README
doc/PDF/SMD_LAMMPS_userguide.pdf
examples/USER/smd
http://lammps.sandia.gov/movies.html#smd :ul
:line
USER-SMTBQ package :link(USER-SMTBQ),h4
[Contents:]
A pair style which implements a Second Moment Tight Binding model with
QEq charge equilibration (SMTBQ) potential for the description of
ionocovalent bonds in oxides.
[Authors:] Nicolas Salles, Emile Maras, Olivier Politano, and Robert
Tetot (LAAS-CNRS, France).
[Install or un-install:]
make yes-user-smtbq
make machine :pre
make no-user-smtbq
make machine :pre
[Supporting info:]
src/USER-SMTBQ: filenames -> commands
src/USER-SMTBQ/README
"pair_style smtbq"_pair_smtbq.html
examples/USER/smtbq :ul
:line
USER-SPH package :link(USER-SPH),h4
[Contents:]
An atom style, fixes, computes, and several pair styles which
implements smoothed particle hydrodynamics (SPH) for liquids. See the
related "USER-SMD package"_#USER-SMD package for smooth Mach dynamics
(SMD) for solids.
This package contains ideal gas, Lennard-Jones equation of states,
Tait, and full support for complete (i.e. internal-energy dependent)
equations of state. It allows for plain or Monaghans XSPH integration
of the equations of motion. It has options for density continuity or
density summation to propagate the density field. It has
"set"_set.html command options to set the internal energy and density
of particles from the input script and allows the same quantities to
be output with thermodynamic output or to dump files via the "compute
property/atom"_compute_property_atom.html command.
[Author:] Georg Ganzenmuller (Fraunhofer-Institute for High-Speed
Dynamics, Ernst Mach Institute, Germany).
[Install or un-install:]
make yes-user-sph
make machine :pre
make no-user-sph
make machine :pre
[Supporting info:]
src/USER-SPH: filenames -> commands
src/USER-SPH/README
doc/PDF/SPH_LAMMPS_userguide.pdf
examples/USER/sph
http://lammps.sandia.gov/movies.html#sph :ul
:line
USER-TALLY package :link(USER-TALLY),h4
[Contents:]
Several compute styles that can be called when pairwise interactions
are calculated to tally information (forces, heat flux, energy,
stress, etc) about individual interactions.
[Author:] Axel Kohlmeyer (Temple U).
[Install or un-install:]
make yes-user-tally
make machine :pre
make no-user-tally
make machine :pre
[Supporting info:]
src/USER-TALLY: filenames -> commands
src/USER-TALLY/README
"compute */tally"_compute_tally.html
examples/USER/tally :ul
:line
USER-VTK package :link(USER-VTK),h4
[Contents:]
A "dump vtk"_dump_vtk.html command which outputs
snapshot info in the "VTK format"_vtk, enabling visualization by
"Paraview"_paraview or other visuzlization packages.
:link(vtk,http://www.vtk.org)
:link(paraview,http://www.paraview.org)
To use this package you must have VTK library available on your
system.
[Authors:] Richard Berger (JKU) and Daniel Queteschiner (DCS Computing).
[Install or un-install:]
The lib/vtk/Makefile.lammps file has settings for accessing VTK files
and its library, which are required for LAMMPS to build and link with
this package. If the settings are not valid for your system, check if
one of the other lib/vtk/Makefile.lammps.* files is compatible and
copy it to Makefile.lammps. If none of the provided files work, you
will need to edit the Makefile.lammps file.
You can then install/un-install the package and build LAMMPS in the
usual manner:
make yes-user-vtk
make machine :pre
make no-user-vtk
make machine :pre
[Supporting info:]
src/USER-VTK: filenames -> commands
src/USER-VTK/README
lib/vtk/README
"dump vtk"_dump_vtk.html :ul
diff --git a/doc/src/Section_python.txt b/doc/src/Section_python.txt
index 1e67fca32..f4b6bdad9 100644
--- a/doc/src/Section_python.txt
+++ b/doc/src/Section_python.txt
@@ -1,866 +1,866 @@
"Previous Section"_Section_modify.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
11. Python interface to LAMMPS :h3
LAMMPS can work together with Python in three ways. First, Python can
wrap LAMMPS through the "LAMMPS library
interface"_Section_howto.html#howto_19, so that a Python script can
create one or more instances of LAMMPS and launch one or more
simulations. In Python lingo, this is "extending" Python with LAMMPS.
Second, the low-level Python interface can be used indirectly through the
PyLammps and IPyLammps wrapper classes in Python. These wrappers try to
simplify the usage of LAMMPS in Python by providing an object-based interface
to common LAMMPS functionality. It also reduces the amount of code necessary to
parameterize LAMMPS scripts through Python and makes variables and computes
directly accessible. See "PyLammps interface"_#py_9 for more details.
Third, LAMMPS can use the Python interpreter, so that a LAMMPS input
script can invoke Python code, and pass information back-and-forth
between the input script and Python functions you write. The Python
code can also callback to LAMMPS to query or change its attributes.
In Python lingo, this is "embedding" Python in LAMMPS.
This section describes how to use these three approaches.
11.1 "Overview of running LAMMPS from Python"_#py_1
11.2 "Overview of using Python from a LAMMPS script"_#py_2
11.3 "Building LAMMPS as a shared library"_#py_3
11.4 "Installing the Python wrapper into Python"_#py_4
11.5 "Extending Python with MPI to run in parallel"_#py_5
11.6 "Testing the Python-LAMMPS interface"_#py_6
11.7 "Using LAMMPS from Python"_#py_7
11.8 "Example Python scripts that use LAMMPS"_#py_8
11.9 "PyLammps interface"_#py_9 :ul
If you are not familiar with it, "Python"_http://www.python.org is a
powerful scripting and programming language which can essentially do
anything that faster, lower-level languages like C or C++ can do, but
typically with much fewer lines of code. When used in embedded mode,
Python can perform operations that the simplistic LAMMPS input script
syntax cannot. Python can be also be used as a "glue" language to
drive a program through its library interface, or to hook multiple
pieces of software together, such as a simulation package plus a
visualization package, or to run a coupled multiscale or multiphysics
model.
See "Section 6.10"_Section_howto.html#howto_10 of the manual and
the couple directory of the distribution for more ideas about coupling
LAMMPS to other codes. See "Section
6.19"_Section_howto.html#howto_19 for a description of the LAMMPS
library interface provided in src/library.cpp and src/library.h, and
how to extend it for your needs. As described below, that interface
is what is exposed to Python either when calling LAMMPS from Python or
when calling Python from a LAMMPS input script and then calling back
to LAMMPS from Python code. The library interface is designed to be
easy to add functions to. Thus the Python interface to LAMMPS is also
easy to extend as well.
If you create interesting Python scripts that run LAMMPS or
interesting Python functions that can be called from a LAMMPS input
script, that you think would be useful to other users, please "email
them to the developers"_http://lammps.sandia.gov/authors.html. We can
include them in the LAMMPS distribution.
:line
:line
11.1 Overview of running LAMMPS from Python :link(py_1),h4
The LAMMPS distribution includes a python directory with all you need
to run LAMMPS from Python. The python/lammps.py file wraps the LAMMPS
library interface, with one wrapper function per LAMMPS library
function. This file makes it is possible to do the following either
from a Python script, or interactively from a Python prompt: create
one or more instances of LAMMPS, invoke LAMMPS commands or give it an
input script, run LAMMPS incrementally, extract LAMMPS results, an
modify internal LAMMPS variables. From a Python script you can do
this in serial or parallel. Running Python interactively in parallel
does not generally work, unless you have a version of Python that
extends standard Python to enable multiple instances of Python to read
what you type.
To do all of this, you must first build LAMMPS as a shared library,
then insure that your Python can find the python/lammps.py file and
the shared library. These steps are explained in subsequent sections
11.3 and 11.4. Sections 11.5 and 11.6 discuss using MPI from a
parallel Python program and how to test that you are ready to use
LAMMPS from Python. Section 11.7 lists all the functions in the
current LAMMPS library interface and how to call them from Python.
Section 11.8 gives some examples of coupling LAMMPS to other tools via
Python. For example, LAMMPS can easily be coupled to a GUI or other
visualization tools that display graphs or animations in real time as
LAMMPS runs. Examples of such scripts are included in the python
directory.
Two advantages of using Python to run LAMMPS are how concise the
language is, and that it can be run interactively, enabling rapid
development and debugging of programs. If you use it to mostly invoke
costly operations within LAMMPS, such as running a simulation for a
reasonable number of timesteps, then the overhead cost of invoking
LAMMPS thru Python will be negligible.
The Python wrapper for LAMMPS uses the amazing and magical (to me)
"ctypes" package in Python, which auto-generates the interface code
needed between Python and a set of C interface routines for a library.
Ctypes is part of standard Python for versions 2.5 and later. You can
check which version of Python you have installed, by simply typing
"python" at a shell prompt.
:line
11.2 Overview of using Python from a LAMMPS script :link(py_2),h4
LAMMPS has several commands which can be used to invoke Python
code directly from an input script:
"python"_python.html
"variable python"_variable.html
"fix python"_fix_python.html
"pair_style python"_pair_python.html :ul
The "python"_python.html command which can be used to define and
execute a Python function that you write the code for. The Python
function can also be assigned to a LAMMPS python-style variable via
the "variable"_variable.html command. Each time the variable is
evaluated, either in the LAMMPS input script itself, or by another
LAMMPS command that uses the variable, this will trigger the Python
function to be invoked.
The Python code for the function can be included directly in the input
script or in an auxiliary file. The function can have arguments which
are mapped to LAMMPS variables (also defined in the input script) and
it can return a value to a LAMMPS variable. This is thus a mechanism
for your input script to pass information to a piece of Python code,
ask Python to execute the code, and return information to your input
script.
Note that a Python function can be arbitrarily complex. It can import
other Python modules, instantiate Python classes, call other Python
functions, etc. The Python code that you provide can contain more
code than the single function. It can contain other functions or
Python classes, as well as global variables or other mechanisms for
storing state between calls from LAMMPS to the function.
The Python function you provide can consist of "pure" Python code that
only performs operations provided by standard Python. However, the
Python function can also "call back" to LAMMPS through its
Python-wrapped library interface, in the manner described in the
previous section 11.1. This means it can issue LAMMPS input script
commands or query and set internal LAMMPS state. As an example, this
can be useful in an input script to create a more complex loop with
branching logic, than can be created using the simple looping and
branching logic enabled by the "next"_next.html and "if"_if.html
commands.
See the "python"_python.html doc page and the "variable"_variable.html
doc page for its python-style variables for more info, including
examples of Python code you can write for both pure Python operations
and callbacks to LAMMPS.
The "fix python"_fix_python.html command can execute
Python code at selected timesteps during a simulation run.
The "pair_style python"_pair_python command allows you to define
pairwise potentials as python code which encodes a single pairwise
interaction. This is useful for rapid-developement and debugging of a
new potential.
To use any of these commands, you only need to build LAMMPS with the
PYTHON package installed:
make yes-python
make machine :pre
Note that this will link LAMMPS with the Python library on your
system, which typically requires several auxiliary system libraries to
also be linked. The list of these libraries and the paths to find
them are specified in the lib/python/Makefile.lammps file. You need
to insure that file contains the correct information for your version
of Python and your machine to successfully build LAMMPS. See the
lib/python/README file for more info.
If you want to write Python code with callbacks to LAMMPS, then you
must also follow the steps overviewed in the preceding section (11.1)
for running LAMMPS from Python. I.e. you must build LAMMPS as a
shared library and insure that Python can find the python/lammps.py
file and the shared library.
:line
11.3 Building LAMMPS as a shared library :link(py_3),h4
Instructions on how to build LAMMPS as a shared library are given in
-"Section 2.5"_Section_start.html#start_5. A shared library is one
+"Section 2.4"_Section_start.html#start_4. A shared library is one
that is dynamically loadable, which is what Python requires to wrap
LAMMPS. On Linux this is a library file that ends in ".so", not ".a".
From the src directory, type
make foo mode=shlib :pre
where foo is the machine target name, such as linux or g++ or serial.
This should create the file liblammps_foo.so in the src directory, as
well as a soft link liblammps.so, which is what the Python wrapper will
load by default. Note that if you are building multiple machine
versions of the shared library, the soft link is always set to the
most recently built version.
NOTE: If you are building LAMMPS with an MPI or FFT library or other
auxiliary libraries (used by various packages), then all of these
extra libraries must also be shared libraries. If the LAMMPS
shared-library build fails with an error complaining about this, see
-"Section 2.5"_Section_start.html#start_5 for more details.
+"Section 2.4"_Section_start.html#start_4 for more details.
:line
11.4 Installing the Python wrapper into Python :link(py_4),h4
For Python to invoke LAMMPS, there are 2 files it needs to know about:
python/lammps.py
src/liblammps.so :ul
Lammps.py is the Python wrapper on the LAMMPS library interface.
Liblammps.so is the shared LAMMPS library that Python loads, as
described above.
You can insure Python can find these files in one of two ways:
set two environment variables
run the python/install.py script :ul
If you set the paths to these files as environment variables, you only
have to do it once. For the csh or tcsh shells, add something like
this to your ~/.cshrc file, one line for each of the two files:
setenv PYTHONPATH $\{PYTHONPATH\}:/home/sjplimp/lammps/python
setenv LD_LIBRARY_PATH $\{LD_LIBRARY_PATH\}:/home/sjplimp/lammps/src :pre
If you use the python/install.py script, you need to invoke it every
time you rebuild LAMMPS (as a shared library) or make changes to the
python/lammps.py file.
You can invoke install.py from the python directory as
% python install.py \[libdir\] \[pydir\] :pre
The optional libdir is where to copy the LAMMPS shared library to; the
default is /usr/local/lib. The optional pydir is where to copy the
lammps.py file to; the default is the site-packages directory of the
version of Python that is running the install script.
Note that libdir must be a location that is in your default
LD_LIBRARY_PATH, like /usr/local/lib or /usr/lib. And pydir must be a
location that Python looks in by default for imported modules, like
its site-packages dir. If you want to copy these files to
non-standard locations, such as within your own user space, you will
need to set your PYTHONPATH and LD_LIBRARY_PATH environment variables
accordingly, as above.
If the install.py script does not allow you to copy files into system
directories, prefix the python command with "sudo". If you do this,
make sure that the Python that root runs is the same as the Python you
run. E.g. you may need to do something like
% sudo /usr/local/bin/python install.py \[libdir\] \[pydir\] :pre
You can also invoke install.py from the make command in the src
directory as
% make install-python :pre
In this mode you cannot append optional arguments. Again, you may
need to prefix this with "sudo". In this mode you cannot control
which Python is invoked by root.
Note that if you want Python to be able to load different versions of
the LAMMPS shared library (see "this section"_#py_5 below), you will
need to manually copy files like liblammps_g++.so into the appropriate
system directory. This is not needed if you set the LD_LIBRARY_PATH
environment variable as described above.
:line
11.5 Extending Python with MPI to run in parallel :link(py_5),h4
If you wish to run LAMMPS in parallel from Python, you need to extend
your Python with an interface to MPI. This also allows you to
make MPI calls directly from Python in your script, if you desire.
There are several Python packages available that purport to wrap MPI
as a library and allow MPI functions to be called from Python. However,
development on most of them seems to be halted except on:
"mpi4py"_https://bitbucket.org/mpi4py/mpi4py
"PyPar"_https://github.com/daleroberts/pypar :ul
Both packages, PyPar and mpi4py have been successfully tested with
LAMMPS. PyPar is simpler and easy to set up and use, but supports
only a subset of MPI. Mpi4py is more MPI-feature complete, but also a
bit more complex to use. As of version 2.0.0, mpi4py is the only
python MPI wrapper that allows passing a custom MPI communicator to
the LAMMPS constructor, which means one can easily run one or more
LAMMPS instances on subsets of the total MPI ranks.
:line
PyPar requires the ubiquitous "Numpy package"_http://numpy.scipy.org
be installed in your Python. After launching Python, type
import numpy :pre
to see if it is installed. If not, here is how to install it (version
1.3.0b1 as of April 2009). Unpack the numpy tarball and from its
top-level directory, type
python setup.py build
sudo python setup.py install :pre
The "sudo" is only needed if required to copy Numpy files into your
Python distribution's site-packages directory.
To install PyPar (version pypar-2.1.4_94 as of Aug 2012), unpack it
and from its "source" directory, type
python setup.py build
sudo python setup.py install :pre
Again, the "sudo" is only needed if required to copy PyPar files into
your Python distribution's site-packages directory.
If you have successfully installed PyPar, you should be able to run
Python and type
import pypar :pre
without error. You should also be able to run python in parallel
on a simple test script
% mpirun -np 4 python test.py :pre
where test.py contains the lines
import pypar
print "Proc %d out of %d procs" % (pypar.rank(),pypar.size()) :pre
and see one line of output for each processor you run on.
NOTE: To use PyPar and LAMMPS in parallel from Python, you must insure
both are using the same version of MPI. If you only have one MPI
installed on your system, this is not an issue, but it can be if you
have multiple MPIs. Your LAMMPS build is explicit about which MPI it
is using, since you specify the details in your lo-level
src/MAKE/Makefile.foo file. PyPar uses the "mpicc" command to find
information about the MPI it uses to build against. And it tries to
load "libmpi.so" from the LD_LIBRARY_PATH. This may or may not find
the MPI library that LAMMPS is using. If you have problems running
both PyPar and LAMMPS together, this is an issue you may need to
address, e.g. by moving other MPI installations so that PyPar finds
the right one.
:line
To install mpi4py (version mpi4py-2.0.0 as of Oct 2015), unpack it
and from its main directory, type
python setup.py build
sudo python setup.py install :pre
Again, the "sudo" is only needed if required to copy mpi4py files into
your Python distribution's site-packages directory. To install with
user privilege into the user local directory type
python setup.py install --user :pre
If you have successfully installed mpi4py, you should be able to run
Python and type
from mpi4py import MPI :pre
without error. You should also be able to run python in parallel
on a simple test script
% mpirun -np 4 python test.py :pre
where test.py contains the lines
from mpi4py import MPI
comm = MPI.COMM_WORLD
print "Proc %d out of %d procs" % (comm.Get_rank(),comm.Get_size()) :pre
and see one line of output for each processor you run on.
NOTE: To use mpi4py and LAMMPS in parallel from Python, you must
insure both are using the same version of MPI. If you only have one
MPI installed on your system, this is not an issue, but it can be if
you have multiple MPIs. Your LAMMPS build is explicit about which MPI
it is using, since you specify the details in your lo-level
src/MAKE/Makefile.foo file. Mpi4py uses the "mpicc" command to find
information about the MPI it uses to build against. And it tries to
load "libmpi.so" from the LD_LIBRARY_PATH. This may or may not find
the MPI library that LAMMPS is using. If you have problems running
both mpi4py and LAMMPS together, this is an issue you may need to
address, e.g. by moving other MPI installations so that mpi4py finds
the right one.
:line
11.6 Testing the Python-LAMMPS interface :link(py_6),h4
To test if LAMMPS is callable from Python, launch Python interactively
and type:
>>> from lammps import lammps
>>> lmp = lammps() :pre
If you get no errors, you're ready to use LAMMPS from Python. If the
2nd command fails, the most common error to see is
OSError: Could not load LAMMPS dynamic library :pre
which means Python was unable to load the LAMMPS shared library. This
typically occurs if the system can't find the LAMMPS shared library or
one of the auxiliary shared libraries it depends on, or if something
about the library is incompatible with your Python. The error message
should give you an indication of what went wrong.
You can also test the load directly in Python as follows, without
first importing from the lammps.py file:
>>> from ctypes import CDLL
>>> CDLL("liblammps.so") :pre
If an error occurs, carefully go thru the steps in "Section
-2.5"_Section_start.html#start_5 and above about building a shared
+2.4"_Section_start.html#start_4 and above about building a shared
library and about insuring Python can find the necessary two files
it needs.
[Test LAMMPS and Python in serial:] :h5
To run a LAMMPS test in serial, type these lines into Python
interactively from the bench directory:
>>> from lammps import lammps
>>> lmp = lammps()
>>> lmp.file("in.lj") :pre
Or put the same lines in the file test.py and run it as
% python test.py :pre
Either way, you should see the results of running the in.lj benchmark
on a single processor appear on the screen, the same as if you had
typed something like:
lmp_g++ -in in.lj :pre
[Test LAMMPS and Python in parallel:] :h5
To run LAMMPS in parallel, assuming you have installed the
"PyPar"_https://github.com/daleroberts/pypar package as discussed
above, create a test.py file containing these lines:
import pypar
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
print "Proc %d out of %d procs has" % (pypar.rank(),pypar.size()),lmp
pypar.finalize() :pre
To run LAMMPS in parallel, assuming you have installed the
"mpi4py"_https://bitbucket.org/mpi4py/mpi4py package as discussed
above, create a test.py file containing these lines:
from mpi4py import MPI
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
me = MPI.COMM_WORLD.Get_rank()
nprocs = MPI.COMM_WORLD.Get_size()
print "Proc %d out of %d procs has" % (me,nprocs),lmp
MPI.Finalize() :pre
You can either script in parallel as:
% mpirun -np 4 python test.py :pre
and you should see the same output as if you had typed
% mpirun -np 4 lmp_g++ -in in.lj :pre
Note that if you leave out the 3 lines from test.py that specify PyPar
commands you will instantiate and run LAMMPS independently on each of
the P processors specified in the mpirun command. In this case you
should get 4 sets of output, each showing that a LAMMPS run was made
on a single processor, instead of one set of output showing that
LAMMPS ran on 4 processors. If the 1-processor outputs occur, it
means that PyPar is not working correctly.
Also note that once you import the PyPar module, PyPar initializes MPI
for you, and you can use MPI calls directly in your Python script, as
described in the PyPar documentation. The last line of your Python
script should be pypar.finalize(), to insure MPI is shut down
correctly.
[Running Python scripts:] :h5
Note that any Python script (not just for LAMMPS) can be invoked in
one of several ways:
% python foo.script
% python -i foo.script
% foo.script :pre
The last command requires that the first line of the script be
something like this:
#!/usr/local/bin/python
#!/usr/local/bin/python -i :pre
where the path points to where you have Python installed, and that you
have made the script file executable:
% chmod +x foo.script :pre
Without the "-i" flag, Python will exit when the script finishes.
With the "-i" flag, you will be left in the Python interpreter when
the script finishes, so you can type subsequent commands. As
mentioned above, you can only run Python interactively when running
Python on a single processor, not in parallel.
:line
:line
11.7 Using LAMMPS from Python :link(py_7),h4
As described above, the Python interface to LAMMPS consists of a
Python "lammps" module, the source code for which is in
python/lammps.py, which creates a "lammps" object, with a set of
methods that can be invoked on that object. The sample Python code
below assumes you have first imported the "lammps" module in your
Python script, as follows:
from lammps import lammps :pre
These are the methods defined by the lammps module. If you look at
the files src/library.cpp and src/library.h you will see that they
correspond one-to-one with calls you can make to the LAMMPS library
from a C++ or C or Fortran program, and which are described in
"Section 6.19"_Section_howto.html#howto_19 of the manual.
lmp = lammps() # create a LAMMPS object using the default liblammps.so library
# 4 optional args are allowed: name, cmdargs, ptr, comm
lmp = lammps(ptr=lmpptr) # use lmpptr as previously created LAMMPS object
lmp = lammps(comm=split) # create a LAMMPS object with a custom communicator, requires mpi4py 2.0.0 or later
lmp = lammps(name="g++") # create a LAMMPS object using the liblammps_g++.so library
lmp = lammps(name="g++",cmdargs=list) # add LAMMPS command-line args, e.g. list = \["-echo","screen"\] :pre
lmp.close() # destroy a LAMMPS object :pre
version = lmp.version() # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
lmp.file(file) # run an entire input script, file = "in.lj"
lmp.command(cmd) # invoke a single LAMMPS command, cmd = "run 100" :pre
lmp.commands_list(cmdlist) # invoke commands in cmdlist = ["run 10", "run 20"]
lmp.commands_string(multicmd) # invoke commands in multicmd = "run 10\nrun 20"
xlo = lmp.extract_global(name,type) # extract a global quantity
# name = "boxxlo", "nlocal", etc
# type = 0 = int
# 1 = double :pre
coords = lmp.extract_atom(name,type) # extract a per-atom quantity
# name = "x", "type", etc
# type = 0 = vector of ints
# 1 = array of ints
# 2 = vector of doubles
# 3 = array of doubles :pre
eng = lmp.extract_compute(id,style,type) # extract value(s) from a compute
v3 = lmp.extract_fix(id,style,type,i,j) # extract value(s) from a fix
# id = ID of compute or fix
# style = 0 = global data
# 1 = per-atom data
# 2 = local data
# type = 0 = scalar
# 1 = vector
# 2 = array
# i,j = indices of value in global vector or array :pre
var = lmp.extract_variable(name,group,flag) # extract value(s) from a variable
# name = name of variable
# group = group ID (ignored for equal-style variables)
# flag = 0 = equal-style variable
# 1 = atom-style variable :pre
flag = lmp.set_variable(name,value) # set existing named string-style variable to value, flag = 0 if successful
value = lmp.get_thermo(name) # return current value of a thermo keyword
natoms = lmp.get_natoms() # total # of atoms as int
data = lmp.gather_atoms(name,type,count) # return per-atom property of all atoms gathered into data, ordered by atom ID
# name = "x", "charge", "type", etc
# count = # of per-atom values, 1 or 3, etc
lmp.scatter_atoms(name,type,count,data) # scatter per-atom property to all atoms from data, ordered by atom ID
# name = "x", "charge", "type", etc
# count = # of per-atom values, 1 or 3, etc :pre
:line
The lines
from lammps import lammps
lmp = lammps() :pre
create an instance of LAMMPS, wrapped in a Python class by the lammps
Python module, and return an instance of the Python class as lmp. It
is used to make all subsequent calls to the LAMMPS library.
Additional arguments to lammps() can be used to tell Python the name
of the shared library to load or to pass arguments to the LAMMPS
instance, the same as if LAMMPS were launched from a command-line
prompt.
If the ptr argument is set like this:
lmp = lammps(ptr=lmpptr) :pre
then lmpptr must be an argument passed to Python via the LAMMPS
"python"_python.html command, when it is used to define a Python
function that is invoked by the LAMMPS input script. This mode of
using Python with LAMMPS is described above in 11.2. The variable
lmpptr refers to the instance of LAMMPS that called the embedded
Python interpreter. Using it as an argument to lammps() allows the
returned Python class instance "lmp" to make calls to that instance of
LAMMPS. See the "python"_python.html command doc page for examples
using this syntax.
Note that you can create multiple LAMMPS objects in your Python
script, and coordinate and run multiple simulations, e.g.
from lammps import lammps
lmp1 = lammps()
lmp2 = lammps()
lmp1.file("in.file1")
lmp2.file("in.file2") :pre
The file(), command(), commands_list(), commands_string() methods
allow an input script, a single command, or multiple commands to be
invoked.
The extract_global(), extract_atom(), extract_compute(),
extract_fix(), and extract_variable() methods return values or
pointers to data structures internal to LAMMPS.
For extract_global() see the src/library.cpp file for the list of
valid names. New names could easily be added. A double or integer is
returned. You need to specify the appropriate data type via the type
argument.
For extract_atom(), a pointer to internal LAMMPS atom-based data is
returned, which you can use via normal Python subscripting. See the
extract() method in the src/atom.cpp file for a list of valid names.
Again, new names could easily be added if the property you want is not
listed. A pointer to a vector of doubles or integers, or a pointer to
an array of doubles (double **) or integers (int **) is returned. You
need to specify the appropriate data type via the type argument.
For extract_compute() and extract_fix(), the global, per-atom, or
local data calculated by the compute or fix can be accessed. What is
returned depends on whether the compute or fix calculates a scalar or
vector or array. For a scalar, a single double value is returned. If
the compute or fix calculates a vector or array, a pointer to the
internal LAMMPS data is returned, which you can use via normal Python
subscripting. The one exception is that for a fix that calculates a
global vector or array, a single double value from the vector or array
is returned, indexed by I (vector) or I and J (array). I,J are
zero-based indices. The I,J arguments can be left out if not needed.
See "Section 6.15"_Section_howto.html#howto_15 of the manual for a
discussion of global, per-atom, and local data, and of scalar, vector,
and array data types. See the doc pages for individual
"computes"_compute.html and "fixes"_fix.html for a description of what
they calculate and store.
For extract_variable(), an "equal-style or atom-style
variable"_variable.html is evaluated and its result returned.
For equal-style variables a single double value is returned and the
group argument is ignored. For atom-style variables, a vector of
doubles is returned, one value per atom, which you can use via normal
Python subscripting. The values will be zero for atoms not in the
specified group.
The get_natoms() method returns the total number of atoms in the
simulation, as an int.
The gather_atoms() method allows any per-atom property (coordinates,
velocities, etc) to be extracted from LAMMPS. It returns a ctypes
vector of ints or doubles as specified by type, of length
count*natoms, for the named property for all atoms in the simulation.
The data is ordered by count and then by atom ID. See the extract()
method in the src/atom.cpp file for a list of valid names. Again, new
names could easily be added if the property you want is missing. The
vector can be used via normal Python subscripting. If atom IDs are
not consecutively ordered within LAMMPS, a None is returned as
indication of an error. A special treatment is applied for image flags
stored in the "image" property. All three image flags are stored in
a packed format in a single integer, so count would be 1 to retrieve
that integer, however also a count value of 3 can be used and then
the image flags will be unpacked into 3 individual integers, ordered
in a similar fashion as coordinates.
Note that the data structure gather_atoms("x") returns is different
from the data structure returned by extract_atom("x") in four ways.
(1) Gather_atoms() returns a vector which you index as x\[i\];
extract_atom() returns an array which you index as x\[i\]\[j\]. (2)
Gather_atoms() orders the atoms by atom ID while extract_atom() does
not. (3) Gathert_atoms() returns a list of all atoms in the
simulation; extract_atoms() returns just the atoms local to each
processor. (4) Finally, the gather_atoms() data structure is a copy
of the atom coords stored internally in LAMMPS, whereas extract_atom()
returns an array that effectively points directly to the internal
data. This means you can change values inside LAMMPS from Python by
assigning a new values to the extract_atom() array. To do this with
the gather_atoms() vector, you need to change values in the vector,
then invoke the scatter_atoms() method.
The scatter_atoms() method allows any per-atom property (coordinates,
velocities, etc) to be inserted into LAMMPS, overwriting the current
property. It takes a vector of ints or doubles as specified by type,
of length count*natoms, for the named property for all atoms in the
simulation. The data should be ordered by count and then by atom ID.
See the extract() method in the src/atom.cpp file for a list of valid
names. Again, new names could easily be added if the property you
want is missing. It uses the vector of data to overwrite the
corresponding properties for each atom inside LAMMPS. This requires
LAMMPS to have its "map" option enabled; see the
"atom_modify"_atom_modify.html command for details. If it is not, or
if atom IDs are not consecutively ordered, no coordinates are reset.
Similar as for gather_atoms() a special treatment is applied for image
flags, which can be provided in packed (count = 1) or unpacked (count = 3)
format and in the latter case, they will be packed before applied to
atoms.
The array of coordinates passed to scatter_atoms() must be a ctypes
vector of ints or doubles, allocated and initialized something like
this:
from ctypes import *
natoms = lmp.get_natoms()
n3 = 3*natoms
x = (n3*c_double)()
x\[0\] = x coord of atom with ID 1
x\[1\] = y coord of atom with ID 1
x\[2\] = z coord of atom with ID 1
x\[3\] = x coord of atom with ID 2
...
x\[n3-1\] = z coord of atom with ID natoms
lmp.scatter_atoms("x",1,3,x) :pre
Alternatively, you can just change values in the vector returned by
gather_atoms("x",1,3), since it is a ctypes vector of doubles.
:line
As noted above, these Python class methods correspond one-to-one with
the functions in the LAMMPS library interface in src/library.cpp and
library.h. This means you can extend the Python wrapper via the
following steps:
Add a new interface function to src/library.cpp and
src/library.h. :ulb,l
Rebuild LAMMPS as a shared library. :l
Add a wrapper method to python/lammps.py for this interface
function. :l
You should now be able to invoke the new interface function from a
Python script. Isn't ctypes amazing? :l
:ule
:line
:line
11.8 Example Python scripts that use LAMMPS :link(py_8),h4
These are the Python scripts included as demos in the python/examples
directory of the LAMMPS distribution, to illustrate the kinds of
things that are possible when Python wraps LAMMPS. If you create your
own scripts, send them to us and we can include them in the LAMMPS
distribution.
trivial.py, read/run a LAMMPS input script thru Python,
demo.py, invoke various LAMMPS library interface routines,
simple.py, run in parallel, similar to examples/COUPLE/simple/simple.cpp,
split.py, same as simple.py but running in parallel on a subset of procs,
gui.py, GUI go/stop/temperature-slider to control LAMMPS,
plot.py, real-time temperature plot with GnuPlot via Pizza.py,
viz_tool.py, real-time viz via some viz package,
vizplotgui_tool.py, combination of viz_tool.py and plot.py and gui.py :tb(c=2)
:line
For the viz_tool.py and vizplotgui_tool.py commands, replace "tool"
with "gl" or "atomeye" or "pymol" or "vmd", depending on what
visualization package you have installed.
Note that for GL, you need to be able to run the Pizza.py GL tool,
which is included in the pizza sub-directory. See the "Pizza.py doc
pages"_pizza for more info:
:link(pizza,http://www.sandia.gov/~sjplimp/pizza.html)
Note that for AtomEye, you need version 3, and there is a line in the
scripts that specifies the path and name of the executable. See the
AtomEye WWW pages "here"_atomeye or "here"_atomeye3 for more details:
http://mt.seas.upenn.edu/Archive/Graphics/A
http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html :pre
:link(atomeye,http://mt.seas.upenn.edu/Archive/Graphics/A)
:link(atomeye3,http://mt.seas.upenn.edu/Archive/Graphics/A3/A3.html)
The latter link is to AtomEye 3 which has the scriping
capability needed by these Python scripts.
Note that for PyMol, you need to have built and installed the
open-source version of PyMol in your Python, so that you can import it
from a Python script. See the PyMol WWW pages "here"_pymolhome or
"here"_pymolopen for more details:
http://www.pymol.org
http://sourceforge.net/scm/?type=svn&group_id=4546 :pre
:link(pymolhome,http://www.pymol.org)
:link(pymolopen,http://sourceforge.net/scm/?type=svn&group_id=4546)
The latter link is to the open-source version.
Note that for VMD, you need a fairly current version (1.8.7 works for
me) and there are some lines in the pizza/vmd.py script for 4 PIZZA
variables that have to match the VMD installation on your system.
:line
See the python/README file for instructions on how to run them and the
source code for individual scripts for comments about what they do.
Here are screenshots of the vizplotgui_tool.py script in action for
different visualization package options. Click to see larger images:
:image(JPG/screenshot_gl_small.jpg,JPG/screenshot_gl.jpg)
:image(JPG/screenshot_atomeye_small.jpg,JPG/screenshot_atomeye.jpg)
:image(JPG/screenshot_pymol_small.jpg,JPG/screenshot_pymol.jpg)
:image(JPG/screenshot_vmd_small.jpg,JPG/screenshot_vmd.jpg)
11.9 PyLammps interface :link(py_9),h4
Please see the "PyLammps Tutorial"_tutorial_pylammps.html.
diff --git a/doc/src/Section_start.txt b/doc/src/Section_start.txt
index b7a471c3f..c798005f5 100644
--- a/doc/src/Section_start.txt
+++ b/doc/src/Section_start.txt
@@ -1,1799 +1,1799 @@
"Previous Section"_Section_intro.html - "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc - "Next Section"_Section_commands.html :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
2. Getting Started :h3
This section describes how to build and run LAMMPS, for both new and
experienced users.
2.1 "What's in the LAMMPS distribution"_#start_1
2.2 "Making LAMMPS"_#start_2
2.3 "Making LAMMPS with optional packages"_#start_3
-2.5 "Building LAMMPS as a library"_#start_4
-2.6 "Running LAMMPS"_#start_5
-2.7 "Command-line options"_#start_6
-2.8 "Screen output"_#start_7
-2.9 "Tips for users of previous versions"_#start_8 :all(b)
+2.4 "Building LAMMPS as a library"_#start_4
+2.5 "Running LAMMPS"_#start_5
+2.6 "Command-line options"_#start_6
+2.7 "Screen output"_#start_7
+2.8 "Tips for users of previous versions"_#start_8 :all(b)
:line
2.1 What's in the LAMMPS distribution :h4,link(start_1)
When you download a LAMMPS tarball you will need to unzip and untar
the downloaded file with the following commands, after placing the
tarball in an appropriate directory.
tar -xzvf lammps*.tar.gz :pre
This will create a LAMMPS directory containing two files and several
sub-directories:
README: text file
LICENSE: the GNU General Public License (GPL)
bench: benchmark problems
doc: documentation
examples: simple test problems
potentials: embedded atom method (EAM) potential files
src: source files
tools: pre- and post-processing tools :tb(s=:)
Note that the "download page"_download also has links to download
pre-build Windows installers, as well as pre-built packages for
several widely used Linux distributions. It also has instructions
for how to download/install LAMMPS for Macs (via Homebrew), and to
download and update LAMMPS from SVN and Git repositories, which gives
you access to the up-to-date sources that are used by the LAMMPS
core developers.
:link(download,http://lammps.sandia.gov/download.html)
The Windows and Linux packages for serial or parallel include
only selected packages and bug-fixes/upgrades listed on "this
page"_http://lammps.sandia.gov/bug.html up to a certain date, as
stated on the download page. If you want an executable with
non-included packages or that is more current, then you'll need to
build LAMMPS yourself, as discussed in the next section.
Skip to the "Running LAMMPS"_#start_6 sections for info on how to
launch a LAMMPS Windows executable on a Windows box.
:line
2.2 Making LAMMPS :h4,link(start_2)
This section has the following sub-sections:
2.2.1 "Read this first"_#start_2_1
2.2.1 "Steps to build a LAMMPS executable"_#start_2_2
2.2.3 "Common errors that can occur when making LAMMPS"_#start_2_3
2.2.4 "Additional build tips"_#start_2_4
2.2.5 "Building for a Mac"_#start_2_5
2.2.6 "Building for Windows"_#start_2_6 :all(b)
:line
Read this first :h5,link(start_2_1)
If you want to avoid building LAMMPS yourself, read the preceeding
section about options available for downloading and installing
executables. Details are discussed on the "download"_download page.
Building LAMMPS can be simple or not-so-simple. If all you need are
the default packages installed in LAMMPS, and MPI is already installed
on your machine, or you just want to run LAMMPS in serial, then you
can typically use the Makefile.mpi or Makefile.serial files in
src/MAKE by typing one of these lines (from the src dir):
make mpi
make serial :pre
Note that on a facility supercomputer, there are often "modules"
loaded in your environment that provide the compilers and MPI you
should use. In this case, the "mpicxx" compile/link command in
Makefile.mpi should simply work by accessing those modules.
It may be the case that one of the other Makefile.machine files in the
src/MAKE sub-directories is a better match to your system (type "make"
to see a list), you can use it as-is by typing (for example):
make stampede :pre
If any of these builds (with an existing Makefile.machine) works on
your system, then you're done!
If you need to install an optional package with a LAMMPS command you
want to use, and the package does not depend on an extra library, you
can simply type
make name :pre
before invoking (or re-invoking) the above steps. "Name" is the
lower-case name of the package, e.g. replica or user-misc.
If you want to do one of the following:
use a LAMMPS command that requires an extra library (e.g. "dump image"_dump_image.html)
build with a package that requires an extra library
build with an accelerator package that requires special compiler/linker settings
run on a machine that has its own compilers, settings, or libraries :ul
then building LAMMPS is more complicated. You may need to find where
extra libraries exist on your machine or install them if they don't.
You may need to build extra libraries that are included in the LAMMPS
distribution, before building LAMMPS itself. You may need to edit a
Makefile.machine file to make it compatible with your system.
Please read the following sections carefully. If you are not
comfortable with makefiles, or building codes on a Unix platform, or
running an MPI job on your machine, please find a local expert to help
you. Many compilation, linking, and run problems users experience are
often not LAMMPS issues - they are peculiar to the user's system,
compilers, libraries, etc. Such questions are better answered by a
local expert.
If you have a build problem that you are convinced is a LAMMPS issue
(e.g. the compiler complains about a line of LAMMPS source code), then
please post the issue to the "LAMMPS mail
list"_http://lammps.sandia.gov/mail.html.
If you succeed in building LAMMPS on a new kind of machine, for which
there isn't a similar machine Makefile included in the
src/MAKE/MACHINES directory, then send it to the developers and we can
include it in the LAMMPS distribution.
:line
Steps to build a LAMMPS executable :h5,link(start_2_2)
Step 0 :h6
The src directory contains the C++ source and header files for LAMMPS.
It also contains a top-level Makefile and a MAKE sub-directory with
low-level Makefile.* files for many systems and machines. See the
src/MAKE/README file for a quick overview of what files are available
and what sub-directories they are in.
The src/MAKE dir has a few files that should work as-is on many
platforms. The src/MAKE/OPTIONS dir has more that invoke additional
compiler, MPI, and other setting options commonly used by LAMMPS, to
illustrate their syntax. The src/MAKE/MACHINES dir has many more that
have been tweaked or optimized for specific machines. These files are
all good starting points if you find you need to change them for your
machine. Put any file you edit into the src/MAKE/MINE directory and
it will be never be touched by any LAMMPS updates.
>From within the src directory, type "make" or "gmake". You should see
a list of available choices from src/MAKE and all of its
sub-directories. If one of those has the options you want or is the
machine you want, you can type a command like:
make mpi :pre
or
make serial :pre
or
gmake mac :pre
Note that the corresponding Makefile.machine can exist in src/MAKE or
any of its sub-directories. If a file with the same name appears in
multiple places (not a good idea), the order they are used is as
follows: src/MAKE/MINE, src/MAKE, src/MAKE/OPTIONS, src/MAKE/MACHINES.
This gives preference to a file you have created/edited and put in
src/MAKE/MINE.
Note that on a multi-processor or multi-core platform you can launch a
parallel make, by using the "-j" switch with the make command, which
will build LAMMPS more quickly.
If you get no errors and an executable like [lmp_mpi] or [lmp_serial]
or [lmp_mac] is produced, then you're done; it's your lucky day.
Note that by default only a few of LAMMPS optional packages are
installed. To build LAMMPS with optional packages, see "this
section"_#start_3 below.
Step 1 :h6
If Step 0 did not work, you will need to create a low-level Makefile
for your machine, like Makefile.foo. You should make a copy of an
existing Makefile.* in src/MAKE or one of its sub-directories as a
starting point. The only portions of the file you need to edit are
the first line, the "compiler/linker settings" section, and the
"LAMMPS-specific settings" section. When it works, put the edited
file in src/MAKE/MINE and it will not be altered by any future LAMMPS
updates.
Step 2 :h6
Change the first line of Makefile.foo to list the word "foo" after the
"#", and whatever other options it will set. This is the line you
will see if you just type "make".
Step 3 :h6
The "compiler/linker settings" section lists compiler and linker
settings for your C++ compiler, including optimization flags. You can
use g++, the open-source GNU compiler, which is available on all Unix
systems. You can also use mpicxx which will typically be available if
MPI is installed on your system, though you should check which actual
compiler it wraps. Vendor compilers often produce faster code. On
boxes with Intel CPUs, we suggest using the Intel icc compiler, which
can be downloaded from "Intel's compiler site"_intel.
:link(intel,http://www.intel.com/software/products/noncom)
If building a C++ code on your machine requires additional libraries,
then you should list them as part of the LIB variable. You should
not need to do this if you use mpicxx.
The DEPFLAGS setting is what triggers the C++ compiler to create a
dependency list for a source file. This speeds re-compilation when
source (*.cpp) or header (*.h) files are edited. Some compilers do
not support dependency file creation, or may use a different switch
than -D. GNU g++ and Intel icc works with -D. If your compiler can't
create dependency files, then you'll need to create a Makefile.foo
patterned after Makefile.storm, which uses different rules that do not
involve dependency files. Note that when you build LAMMPS for the
first time on a new platform, a long list of *.d files will be printed
out rapidly. This is not an error; it is the Makefile doing its
normal creation of dependencies.
Step 4 :h6
The "system-specific settings" section has several parts. Note that
if you change any -D setting in this section, you should do a full
re-compile, after typing "make clean" (which will describe different
clean options).
The LMP_INC variable is used to include options that turn on ifdefs
within the LAMMPS code. The options that are currently recogized are:
-DLAMMPS_GZIP
-DLAMMPS_JPEG
-DLAMMPS_PNG
-DLAMMPS_FFMPEG
-DLAMMPS_MEMALIGN
-DLAMMPS_XDR
-DLAMMPS_SMALLBIG
-DLAMMPS_BIGBIG
-DLAMMPS_SMALLSMALL
-DLAMMPS_LONGLONG_TO_LONG
-DLAMMPS_EXCEPTIONS
-DPACK_ARRAY
-DPACK_POINTER
-DPACK_MEMCPY :ul
The read_data and dump commands will read/write gzipped files if you
compile with -DLAMMPS_GZIP. It requires that your machine supports
the "popen()" function in the standard runtime library and that a gzip
executable can be found by LAMMPS during a run.
NOTE: on some clusters with high-speed networks, using the fork()
library calls (required by popen()) can interfere with the fast
communication library and lead to simulations using compressed output
or input to hang or crash. For selected operations, compressed file
I/O is also available using a compression library instead, which are
provided in the COMPRESS package. From more details about compiling
LAMMPS with packages, please see below.
If you use -DLAMMPS_JPEG, the "dump image"_dump_image.html command
will be able to write out JPEG image files. For JPEG files, you must
also link LAMMPS with a JPEG library, as described below. If you use
-DLAMMPS_PNG, the "dump image"_dump.html command will be able to write
out PNG image files. For PNG files, you must also link LAMMPS with a
PNG library, as described below. If neither of those two defines are
used, LAMMPS will only be able to write out uncompressed PPM image
files.
If you use -DLAMMPS_FFMPEG, the "dump movie"_dump_image.html command
will be available to support on-the-fly generation of rendered movies
the need to store intermediate image files. It requires that your
machines supports the "popen" function in the standard runtime library
and that an FFmpeg executable can be found by LAMMPS during the run.
NOTE: Similar to the note above, this option can conflict with
high-speed networks, because it uses popen().
Using -DLAMMPS_MEMALIGN=<bytes> enables the use of the
posix_memalign() call instead of malloc() when large chunks or memory
are allocated by LAMMPS. This can help to make more efficient use of
vector instructions of modern CPUS, since dynamically allocated memory
has to be aligned on larger than default byte boundaries (e.g. 16
bytes instead of 8 bytes on x86 type platforms) for optimal
performance.
If you use -DLAMMPS_XDR, the build will include XDR compatibility
files for doing particle dumps in XTC format. This is only necessary
if your platform does have its own XDR files available. See the
Restrictions section of the "dump"_dump.html command for details.
Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG,
-DLAMMPS_SMALLSMALL settings. The default is -DLAMMPS_SMALLBIG. These
settings refer to use of 4-byte (small) vs 8-byte (big) integers
within LAMMPS, as specified in src/lmptype.h. The only reason to use
the BIGBIG setting is to enable simulation of huge molecular systems
(which store bond topology info) with more than 2 billion atoms, or to
track the image flags of moving atoms that wrap around a periodic box
more than 512 times. Normally, the only reason to use SMALLSMALL is
if your machine does not support 64-bit integers, though you can use
SMALLSMALL setting if you are running in serial or on a desktop
machine or small cluster where you will never run large systems or for
long time (more than 2 billion atoms, more than 2 billion timesteps).
See the "Additional build tips"_#start_2_4 section below for more
details on these settings.
Note that the USER-ATC package is not currently compatible with
-DLAMMPS_BIGBIG. Also the GPU package requires the lib/gpu library to
be compiled with the same setting, or the link will fail.
The -DLAMMPS_LONGLONG_TO_LONG setting may be needed if your system or
MPI version does not recognize "long long" data types. In this case a
"long" data type is likely already 64-bits, in which case this setting
will convert to that data type.
The -DLAMMPS_EXCEPTIONS setting can be used to activate alternative
versions of error handling inside of LAMMPS. This is useful when
external codes drive LAMMPS as a library. Using this option, LAMMPS
errors do not kill the caller. Instead, the call stack is unwound and
control returns to the caller. The library interface provides the
lammps_has_error() and lammps_get_last_error_message() functions to
detect and find out more about a LAMMPS error.
Using one of the -DPACK_ARRAY, -DPACK_POINTER, and -DPACK_MEMCPY
options can make for faster parallel FFTs (in the PPPM solver) on some
platforms. The -DPACK_ARRAY setting is the default. See the
"kspace_style"_kspace_style.html command for info about PPPM. See
Step 6 below for info about building LAMMPS with an FFT library.
Step 5 :h6
The 3 MPI variables are used to specify an MPI library to build LAMMPS
with. Note that you do not need to set these if you use the MPI
compiler mpicxx for your CC and LINK setting in the section above.
The MPI wrapper knows where to find the needed files.
If you want LAMMPS to run in parallel, you must have an MPI library
installed on your platform. If MPI is installed on your system in the
usual place (under /usr/local), you also may not need to specify these
3 variables, assuming /usr/local is in your path. On some large
parallel machines which use "modules" for their compile/link
environements, you may simply need to include the correct module in
your build environment, before building LAMMPS. Or the parallel
machine may have a vendor-provided MPI which the compiler has no
trouble finding.
Failing this, these 3 variables can be used to specify where the mpi.h
file (MPI_INC) and the MPI library file (MPI_PATH) are found and the
name of the library file (MPI_LIB).
If you are installing MPI yourself, we recommend Argonne's MPICH2
or OpenMPI. MPICH can be downloaded from the "Argonne MPI
site"_http://www.mcs.anl.gov/research/projects/mpich2/. OpenMPI can
be downloaded from the "OpenMPI site"_http://www.open-mpi.org.
Other MPI packages should also work. If you are running on a big
parallel platform, your system people or the vendor should have
already installed a version of MPI, which is likely to be faster
than a self-installed MPICH or OpenMPI, so find out how to build
and link with it. If you use MPICH or OpenMPI, you will have to
configure and build it for your platform. The MPI configure script
should have compiler options to enable you to use the same compiler
you are using for the LAMMPS build, which can avoid problems that can
arise when linking LAMMPS to the MPI library.
If you just want to run LAMMPS on a single processor, you can use the
dummy MPI library provided in src/STUBS, since you don't need a true
MPI library installed on your system. See src/MAKE/Makefile.serial
for how to specify the 3 MPI variables in this case. You will also
need to build the STUBS library for your platform before making LAMMPS
itself. Note that if you are building with src/MAKE/Makefile.serial,
e.g. by typing "make serial", then the STUBS library is built for you.
To build the STUBS library from the src directory, type "make
mpi-stubs", or from the src/STUBS dir, type "make". This should
create a libmpi_stubs.a file suitable for linking to LAMMPS. If the
build fails, you will need to edit the STUBS/Makefile for your
platform.
The file STUBS/mpi.c provides a CPU timer function called MPI_Wtime()
that calls gettimeofday() . If your system doesn't support
gettimeofday() , you'll need to insert code to call another timer.
Note that the ANSI-standard function clock() rolls over after an hour
or so, and is therefore insufficient for timing long LAMMPS
simulations.
Step 6 :h6
The 3 FFT variables allow you to specify an FFT library which LAMMPS
uses (for performing 1d FFTs) when running the particle-particle
particle-mesh (PPPM) option for long-range Coulombics via the
"kspace_style"_kspace_style.html command.
LAMMPS supports common open-source or vendor-supplied FFT libraries
for this purpose. If you leave these 3 variables blank, LAMMPS will
use the open-source "KISS FFT library"_http://kissfft.sf.net, which is
included in the LAMMPS distribution. This library is portable to all
platforms and for typical LAMMPS simulations is almost as fast as FFTW
or vendor optimized libraries. If you are not including the KSPACE
package in your build, you can also leave the 3 variables blank.
Otherwise, select which kinds of FFTs to use as part of the FFT_INC
setting by a switch of the form -DFFT_XXX. Recommended values for XXX
are: MKL or FFTW3. FFTW2 and NONE are supported as legacy options.
Selecting -DFFT_FFTW will use the FFTW3 library and -DFFT_NONE will
use the KISS library described above.
You may also need to set the FFT_INC, FFT_PATH, and FFT_LIB variables,
so the compiler and linker can find the needed FFT header and library
files. Note that on some large parallel machines which use "modules"
for their compile/link environements, you may simply need to include
the correct module in your build environment. Or the parallel machine
may have a vendor-provided FFT library which the compiler has no
trouble finding. See the src/MAKE/OPTIONS/Makefile.fftw file for an
example of how to specify these variables to use the FFTW3 library.
FFTW is fast, portable library that should also work on any platform
and typically be faster than KISS FFT. You can download it from
"www.fftw.org"_http://www.fftw.org. Both the legacy version 2.1.X and
the newer 3.X versions are supported as -DFFT_FFTW2 or -DFFT_FFTW3.
Building FFTW for your box should be as simple as ./configure; make;
make install. The install command typically requires root privileges
(e.g. invoke it via sudo), unless you specify a local directory with
the "--prefix" option of configure. Type "./configure --help" to see
various options.
If you wish to have FFTW support for single-precision FFTs (see below
about -DFFT_SINGLE) in addition to the default double-precision FFTs,
you will need to build FFTW a second time for single-precision. For
FFTW3, do this via:
make clean
./configure --enable-single; make; make install :pre
which should produce the additional library libfftw3f.a.
For FFTW2, do this:
make clean
./configure --enable-float --enable-type-prefix; make; make install :pre
which should produce the additional library libsfftw.a and additional
include file sfttw.a. Note that on some platforms FFTW2 has been
pre-installed for both single- and double-precision, and may already
have these files as well as libdfftw.a and dfftw.h for double
precision.
The FFT_INC variable also allows for a -DFFT_SINGLE setting that will
use single-precision FFTs with PPPM, which can speed-up long-range
calulations, particularly in parallel or on GPUs. Fourier transform
and related PPPM operations are somewhat insensitive to floating point
truncation errors and thus do not always need to be performed in
double precision. Using the -DFFT_SINGLE setting trades off a little
accuracy for reduced memory use and parallel communication costs for
transposing 3d FFT data. Note that single precision FFTs have only
been tested with the FFTW3, FFTW2, MKL, and KISS FFT options.
When using -DFFT_SINGLE with FFTW3 or FFTW2, you need to build FFTW
with support for single-precision, as explained above. For FFTW3 you
also need to include -lfftw3f with the FFT_LIB setting, in addition to
-lfftw3. For FFTW2, you also need to specify -DFFT_SIZE with the
FFT_INC setting and -lsfftw with the FFT_LIB setting (in place of
-lfftw). Similarly, if FFTW2 has been preinstalled with an explicit
double-precision library (libdfftw.a and not the default libfftw.a),
then you can specify -DFFT_SIZE (and not -DFFT_SINGLE), and specify
-ldfftw to use double-precision FFTs.
Step 7 :h6
The 3 JPG variables allow you to specify a JPEG and/or PNG library
which LAMMPS uses when writing out JPEG or PNG files via the "dump
image"_dump_image.html command. These can be left blank if you do not
use the -DLAMMPS_JPEG or -DLAMMPS_PNG switches discussed above in Step
4, since in that case JPEG/PNG output will be disabled.
A standard JPEG library usually goes by the name libjpeg.a or
libjpeg.so and has an associated header file jpeglib.h. Whichever
JPEG library you have on your platform, you'll need to set the
appropriate JPG_INC, JPG_PATH, and JPG_LIB variables, so that the
compiler and linker can find it.
A standard PNG library usually goes by the name libpng.a or libpng.so
and has an associated header file png.h. Whichever PNG library you
have on your platform, you'll need to set the appropriate JPG_INC,
JPG_PATH, and JPG_LIB variables, so that the compiler and linker can
find it.
As before, if these header and library files are in the usual place on
your machine, you may not need to set these variables.
Step 8 :h6
Note that by default only a few of LAMMPS optional packages are
installed. To build LAMMPS with optional packages, see "this
section"_#start_3 below, before proceeding to Step 9.
Step 9 :h6
That's it. Once you have a correct Makefile.foo, and you have
pre-built any other needed libraries (e.g. MPI, FFT, etc) all you need
to do from the src directory is type something like this:
make foo
make -j N foo
gmake foo
gmake -j N foo :pre
The -j or -j N switches perform a parallel build which can be much
faster, depending on how many cores your compilation machine has. N
is the number of cores the build runs on.
You should get the executable lmp_foo when the build is complete.
:line
Errors that can occur when making LAMMPS: h5 :link(start_2_3)
If an error occurs when building LAMMPS, the compiler or linker will
state very explicitly what the problem is. The error message should
give you a hint as to which of the steps above has failed, and what
you need to do in order to fix it. Building a code with a Makefile is
a very logical process. The compiler and linker need to find the
appropriate files and those files need to be compatible with LAMMPS
settings and source files. When a make fails, there is usually a very
simple reason, which you or a local expert will need to fix.
Here are two non-obvious errors that can occur:
(1) If the make command breaks immediately with errors that indicate
it can't find files with a "*" in their names, this can be because
your machine's native make doesn't support wildcard expansion in a
makefile. Try gmake instead of make. If that doesn't work, try using
a -f switch with your make command to use a pre-generated
Makefile.list which explicitly lists all the needed files, e.g.
make makelist
make -f Makefile.list linux
gmake -f Makefile.list mac :pre
The first "make" command will create a current Makefile.list with all
the file names in your src dir. The 2nd "make" command (make or
gmake) will use it to build LAMMPS. Note that you should
include/exclude any desired optional packages before using the "make
makelist" command.
(2) If you get an error that says something like 'identifier "atoll"
is undefined', then your machine does not support "long long"
integers. Try using the -DLAMMPS_LONGLONG_TO_LONG setting described
above in Step 4.
:line
Additional build tips :h5,link(start_2_4)
Building LAMMPS for multiple platforms. :h6
You can make LAMMPS for multiple platforms from the same src
directory. Each target creates its own object sub-directory called
Obj_target where it stores the system-specific *.o files.
Cleaning up. :h6
Typing "make clean-all" or "make clean-machine" will delete *.o object
files created when LAMMPS is built, for either all builds or for a
particular machine.
Changing the LAMMPS size limits via -DLAMMPS_SMALLBIG or
-DLAMMPS_BIGBIG or -DLAMMPS_SMALLSMALL :h6
As explained above, any of these 3 settings can be specified on the
LMP_INC line in your low-level src/MAKE/Makefile.foo.
The default is -DLAMMPS_SMALLBIG which allows for systems with up to
2^63 atoms and 2^63 timesteps (about 9e18). The atom limit is for
atomic systems which do not store bond topology info and thus do not
require atom IDs. If you use atom IDs for atomic systems (which is
the default) or if you use a molecular model, which stores bond
topology info and thus requires atom IDs, the limit is 2^31 atoms
(about 2 billion). This is because the IDs are stored in 32-bit
integers.
Likewise, with this setting, the 3 image flags for each atom (see the
"dump"_dump.html doc page for a discussion) are stored in a 32-bit
integer, which means the atoms can only wrap around a periodic box (in
each dimension) at most 512 times. If atoms move through the periodic
box more than this many times, the image flags will "roll over",
e.g. from 511 to -512, which can cause diagnostics like the
mean-squared displacement, as calculated by the "compute
msd"_compute_msd.html command, to be faulty.
To allow for larger atomic systems with atom IDs or larger molecular
systems or larger image flags, compile with -DLAMMPS_BIGBIG. This
stores atom IDs and image flags in 64-bit integers. This enables
atomic or molecular systems with atom IDS of up to 2^63 atoms (about
9e18). And image flags will not "roll over" until they reach 2^20 =
1048576.
If your system does not support 8-byte integers, you will need to
compile with the -DLAMMPS_SMALLSMALL setting. This will restrict the
total number of atoms (for atomic or molecular systems) and timesteps
to 2^31 (about 2 billion). Image flags will roll over at 2^9 = 512.
Note that in src/lmptype.h there are definitions of all these data
types as well as the MPI data types associated with them. The MPI
types need to be consistent with the associated C data types, or else
LAMMPS will generate a run-time error. As far as we know, the
settings defined in src/lmptype.h are portable and work on every
current system.
In all cases, the size of problem that can be run on a per-processor
basis is limited by 4-byte integer storage to 2^31 atoms per processor
(about 2 billion). This should not normally be a limitation since such
a problem would have a huge per-processor memory footprint due to
neighbor lists and would run very slowly in terms of CPU secs/timestep.
:line
Building for a Mac :h5,link(start_2_5)
OS X is a derivative of BSD Unix, so it should just work. See the
src/MAKE/MACHINES/Makefile.mac and Makefile.mac_mpi files.
:line
Building for Windows :h5,link(start_2_6)
If you want to build a Windows version of LAMMPS, you can build it
yourself, but it may require some effort. LAMMPS expects a Unix-like
build environment for the default build procedure. This can be done
using either Cygwin or MinGW; the latter also exists as a ready-to-use
Linux-to-Windows cross-compiler in several Linux distributions. In
these cases, you can do the installation after installing several
unix-style commands like make, grep, sed and bash with some shell
utilities.
For Cygwin and the MinGW cross-compilers, suitable makefiles are
provided in src/MAKE/MACHINES. When using other compilers, like
Visual C++ or Intel compilers for Windows, you may have to implement
your own build system. Since none of the current LAMMPS core developers
has significant experience building executables on Windows, we are
happy to distribute contributed instructions and modifications, but
we cannot provide support for those.
With the so-called "Anniversary Update" to Windows 10, there is a
Ubuntu Linux subsystem available for Windows, that can be installed
and then used to compile/install LAMMPS as if you are running on a
Ubuntu Linux system instead of Windows.
As an alternative, you can download "daily builds" (and some older
versions) of the installer packages from
"rpm.lammps.org/windows.html"_http://rpm.lammps.org/windows.html.
These executables are built with most optional packages and the
download includes documentation, potential files, some tools and
many examples, but no source code.
:line
2.3 Making LAMMPS with optional packages :h4,link(start_3)
This section has the following sub-sections:
2.3.1 "Package basics"_#start_3_1
2.3.2 "Including/excluding packages"_#start_3_2
2.3.3 "Packages that require extra libraries"_#start_3_3 :all(b)
:line
Package basics: :h5,link(start_3_1)
The source code for LAMMPS is structured as a set of core files which
are always included, plus optional packages. Packages are groups of
files that enable a specific set of features. For example, force
fields for molecular systems or granular systems are in packages.
"Section 4"_Section_packages.html in the manual has details about all
the packages, which come in two flavors: [standard] and [user]
packages. It also has specific instructions for building LAMMPS with
any package which requires an extra library. General instructions are
below.
You can see the list of all packages by typing "make package" from
within the src directory of the LAMMPS distribution. It will also
list various make commands that can be used to manage packages.
If you use a command in a LAMMPS input script that is part of a
package, you must have built LAMMPS with that package, else you will
get an error that the style is invalid or the command is unknown.
Every command's doc page specfies if it is part of a package. You can
type
lmp_machine -h :pre
to run your executable with the optional "-h command-line
-switch"_#start_7 for "help", which will list the styles and commands
+switch"_#start_6 for "help", which will list the styles and commands
known to your executable, and immediately exit.
:line
Including/excluding packages :h5,link(start_3_2)
To use (or not use) a package you must install it (or un-install it)
before building LAMMPS. From the src directory, this is as simple as:
make yes-colloid
make mpi :pre
or
make no-user-omp
make mpi :pre
NOTE: You should NOT install/un-install packages and build LAMMPS in a
single make command using multiple targets, e.g. make yes-colloid mpi.
This is because the make procedure creates a list of source files that
will be out-of-date for the build if the package configuration changes
within the same command.
Any package can be installed or not in a LAMMPS build, independent of
all other packages. However, some packages include files derived from
files in other packages. LAMMPS checks for this and does the right
thing. I.e. individual files are only included if their dependencies
are already included. Likewise, if a package is excluded, other files
dependent on that package are also excluded.
NOTE: The one exception is that we do not recommend building with both
the KOKKOS package installed and any of the other acceleration
packages (GPU, OPT, USER-INTEL, USER-OMP) also installed. This is
because of how Kokkos sometimes builds using a wrapper compiler which
can make it difficult to invoke all the compile/link flags correctly
for both Kokkos and non-Kokkos files.
If you will never run simulations that use the features in a
particular packages, there is no reason to include it in your build.
For some packages, this will keep you from having to build extra
libraries, and will also produce a smaller executable which may run a
bit faster.
When you download a LAMMPS tarball, three packages are pre-installed
in the src directory -- KSPACE, MANYBODY, MOLECULE -- because they are
so commonly used. When you download LAMMPS source files from the SVN
or Git repositories, no packages are pre-installed.
Packages are installed or un-installed by typing
make yes-name
make no-name :pre
where "name" is the name of the package in lower-case, e.g. name =
kspace for the KSPACE package or name = user-atc for the USER-ATC
package. You can also type any of these commands:
make yes-all | install all packages
make no-all | un-install all packages
make yes-standard or make yes-std | install standard packages
make no-standard or make no-std| un-install standard packages
make yes-user | install user packages
make no-user | un-install user packages
make yes-lib | install packages that require extra libraries
make no-lib | un-install packages that require extra libraries
make yes-ext | install packages that require external libraries
make no-ext | un-install packages that require external libraries :tb(s=|)
which install/un-install various sets of packages. Typing "make
package" will list all the these commands.
NOTE: Installing or un-installing a package works by simply moving
files back and forth between the main src directory and
sub-directories with the package name (e.g. src/KSPACE, src/USER-ATC),
so that the files are included or excluded when LAMMPS is built.
After you have installed or un-installed a package, you must re-build
LAMMPS for the action to take effect.
The following make commands help manage files that exist in both the
src directory and in package sub-directories. You do not normally
need to use these commands unless you are editing LAMMPS files or have
downloaded a patch from the LAMMPS web site.
Typing "make package-status" or "make ps" will show which packages are
currently installed. For those that are installed, it will list any
files that are different in the src directory and package
sub-directory.
Typing "make package-update" or "make pu" will overwrite src files
with files from the package sub-directories if the package is
installed. It should be used after a patch has been applied, since
patches only update the files in the package sub-directory, but not
the src files.
Typing "make package-overwrite" will overwrite files in the package
sub-directories with src files.
Typing "make package-diff" lists all differences between these files.
Again, just type "make package" to see all of the package-related make
options.
:line
Packages that require extra libraries :h5,link(start_3_3)
A few of the standard and user packages require extra libraries. See
"Section 4"_Section_packages.html for two tables of packages which
indicate which ones require libraries. For each such package, the
Section 4 doc page gives details on how to build the extra library,
including how to download it if necessary. The basic ideas are
summarized here.
[System libraries:]
Packages in the tables "Section 4"_Section_packages.html with a "sys"
in the last column link to system libraries that typically already
exist on your machine. E.g. the python package links to a system
Python library. If your machine does not have the required library,
you will have to download and install it on your machine, in either
the system or user space.
[Internal libraries:]
Packages in the tables "Section 4"_Section_packages.html with an "int"
in the last column link to internal libraries whose source code is
included with LAMMPS, in the lib/name directory where name is the
package name. You must first build the library in that directory
before building LAMMPS with that package installed. E.g. the gpu
package links to a library you build in the lib/gpu dir. You can
often do the build in one step by typing "make lib-name args=..."
from the src dir, with appropriate arguments. You can leave off the
args to see a help message. See "Section 4"_Section_packages.html for
details for each package.
[External libraries:]
Packages in the tables "Section 4"_Section_packages.html with an "ext"
in the last column link to exernal libraries whose source code is not
included with LAMMPS. You must first download and install the library
before building LAMMPS with that package installed. E.g. the voronoi
package links to the freely available "Voro++ library"_voro_home2. You
can often do the download/build in one step by typing "make lib-name
args=..." from the src dir, with appropriate arguments. You can leave
off the args to see a help message. See "Section
4"_Section_packages.html for details for each package.
:link(voro_home2,http://math.lbl.gov/voro++)
[Possible errors:]
There are various common errors which can occur when building extra
libraries or when building LAMMPS with packages that require the extra
libraries.
If you cannot build the extra library itself successfully, you may
need to edit or create an appropriate Makefile for your machine, e.g.
with appropriate compiler or system settings. Provided makefiles are
typically in the lib/name directory. E.g. see the Makefile.* files in
lib/gpu.
The LAMMPS build often uses settings in a lib/name/Makefile.lammps
file which either exists in the LAMMPS distribution or is created or
copied from a lib/name/Makefile.lammps.* file when the library is
built. If those settings are not correct for your machine you will
need to edit or create an appropriate Makefile.lammps file.
Package-specific details for these steps are given in "Section
4"_Section_packages.html an in README files in the lib/name
directories.
[Compiler options needed for accelerator packages:]
Several packages contain code that is optimized for specific hardware,
e.g. CPU, KNL, or GPU. These are the OPT, GPU, KOKKOS, USER-INTEL,
and USER-OMP packages. Compiling and linking the source files in
these accelerator packages for optimal performance requires specific
settings in the Makefile.machine file you use.
A summary of the Makefile.machine settings needed for each of these
packages is given in "Section 4"_Section_packages.html. More info is
given on the doc pages that describe each package in detail:
5.3.1 "USER-INTEL package"_accelerate_intel.html
5.3.2 "GPU package"_accelerate_intel.html
5.3.3 "KOKKOS package"_accelerate_kokkos.html
5.3.4 "USER-OMP package"_accelerate_omp.html
5.3.5 "OPT package"_accelerate_opt.html :all(b)
You can also use or examine the following machine Makefiles in
src/MAKE/OPTIONS, which include the settings. Note that the
USER-INTEL and KOKKOS packages can use settings that build LAMMPS for
different hardware. The USER-INTEL package can be compiled for Intel
CPUs and KNLs; the KOKKOS package builds for CPUs (OpenMP), GPUs
(Cuda), and Intel KNLs.
Makefile.intel_cpu
Makefile.intel_phi
Makefile.kokkos_omp
Makefile.kokkos_cuda
Makefile.kokkos_phi
Makefile.omp
Makefile.opt :ul
:line
2.4 Building LAMMPS as a library :h4,link(start_4)
LAMMPS can be built as either a static or shared library, which can
then be called from another application or a scripting language. See
"this section"_Section_howto.html#howto_10 for more info on coupling
LAMMPS to other codes. See "this section"_Section_python.html for
more info on wrapping and running LAMMPS from Python.
Static library :h5
To build LAMMPS as a static library (*.a file on Linux), type
make foo mode=lib :pre
where foo is the machine name. This kind of library is typically used
to statically link a driver application to LAMMPS, so that you can
insure all dependencies are satisfied at compile time. This will use
the ARCHIVE and ARFLAGS settings in src/MAKE/Makefile.foo. The build
will create the file liblammps_foo.a which another application can
link to. It will also create a soft link liblammps.a, which will
point to the most recently built static library.
Shared library :h5
To build LAMMPS as a shared library (*.so file on Linux), which can be
dynamically loaded, e.g. from Python, type
make foo mode=shlib :pre
where foo is the machine name. This kind of library is required when
wrapping LAMMPS with Python; see "Section 11"_Section_python.html
for details. This will use the SHFLAGS and SHLIBFLAGS settings in
src/MAKE/Makefile.foo and perform the build in the directory
Obj_shared_foo. This is so that each file can be compiled with the
-fPIC flag which is required for inclusion in a shared library. The
build will create the file liblammps_foo.so which another application
can link to dyamically. It will also create a soft link liblammps.so,
which will point to the most recently built shared library. This is
the file the Python wrapper loads by default.
Note that for a shared library to be usable by a calling program, all
the auxiliary libraries it depends on must also exist as shared
libraries. This will be the case for libraries included with LAMMPS,
such as the dummy MPI library in src/STUBS or any package libraries in
lib/packages, since they are always built as shared libraries using
the -fPIC switch. However, if a library like MPI or FFTW does not
exist as a shared library, the shared library build will generate an
error. This means you will need to install a shared library version
of the auxiliary library. The build instructions for the library
should tell you how to do this.
Here is an example of such errors when the system FFTW or provided
lib/colvars library have not been built as shared libraries:
/usr/bin/ld: /usr/local/lib/libfftw3.a(mapflags.o): relocation
R_X86_64_32 against '.rodata' can not be used when making a shared
object; recompile with -fPIC
/usr/local/lib/libfftw3.a: could not read symbols: Bad value :pre
/usr/bin/ld: ../../lib/colvars/libcolvars.a(colvarmodule.o):
relocation R_X86_64_32 against '__pthread_key_create' can not be used
when making a shared object; recompile with -fPIC
../../lib/colvars/libcolvars.a: error adding symbols: Bad value :pre
As an example, here is how to build and install the "MPICH
library"_mpich, a popular open-source version of MPI, distributed by
Argonne National Labs, as a shared library in the default
/usr/local/lib location:
:link(mpich,http://www-unix.mcs.anl.gov/mpi)
./configure --enable-shared
make
make install :pre
You may need to use "sudo make install" in place of the last line if
you do not have write privileges for /usr/local/lib. The end result
should be the file /usr/local/lib/libmpich.so.
[Additional requirement for using a shared library:] :h5
The operating system finds shared libraries to load at run-time using
the environment variable LD_LIBRARY_PATH. So you may wish to copy the
file src/liblammps.so or src/liblammps_g++.so (for example) to a place
the system can find it by default, such as /usr/local/lib, or you may
wish to add the LAMMPS src directory to LD_LIBRARY_PATH, so that the
current version of the shared library is always available to programs
that use it.
For the csh or tcsh shells, you would add something like this to your
~/.cshrc file:
setenv LD_LIBRARY_PATH $\{LD_LIBRARY_PATH\}:/home/sjplimp/lammps/src :pre
Calling the LAMMPS library :h5
Either flavor of library (static or shared) allows one or more LAMMPS
objects to be instantiated from the calling program.
When used from a C++ program, all of LAMMPS is wrapped in a LAMMPS_NS
namespace; you can safely use any of its classes and methods from
within the calling code, as needed.
When used from a C or Fortran program or a scripting language like
Python, the library has a simple function-style interface, provided in
src/library.cpp and src/library.h.
See the sample codes in examples/COUPLE/simple for examples of C++ and
C and Fortran codes that invoke LAMMPS thru its library interface.
There are other examples as well in the COUPLE directory which are
discussed in "Section 6.10"_Section_howto.html#howto_10 of the
manual. See "Section 11"_Section_python.html of the manual for a
description of the Python wrapper provided with LAMMPS that operates
through the LAMMPS library interface.
The files src/library.cpp and library.h define the C-style API for
using LAMMPS as a library. See "Section
6.19"_Section_howto.html#howto_19 of the manual for a description of the
interface and how to extend it for your needs.
:line
2.5 Running LAMMPS :h4,link(start_5)
By default, LAMMPS runs by reading commands from standard input. Thus
if you run the LAMMPS executable by itself, e.g.
lmp_linux :pre
it will simply wait, expecting commands from the keyboard. Typically
you should put commands in an input script and use I/O redirection,
e.g.
lmp_linux < in.file :pre
For parallel environments this should also work. If it does not, use
the '-in' command-line switch, e.g.
lmp_linux -in in.file :pre
"This section"_Section_commands.html describes how input scripts are
structured and what commands they contain.
You can test LAMMPS on any of the sample inputs provided in the
examples or bench directory. Input scripts are named in.* and sample
outputs are named log.*.name.P where name is a machine and P is the
number of processors it was run on.
Here is how you might run a standard Lennard-Jones benchmark on a
Linux box, using mpirun to launch a parallel job:
cd src
make linux
cp lmp_linux ../bench
cd ../bench
mpirun -np 4 lmp_linux -in in.lj :pre
See "this page"_bench for timings for this and the other benchmarks on
various platforms. Note that some of the example scripts require
LAMMPS to be built with one or more of its optional packages.
:link(bench,http://lammps.sandia.gov/bench.html)
:line
On a Windows box, you can skip making LAMMPS and simply download an
installer package from "here"_http://rpm.lammps.org/windows.html
For running the non-MPI executable, follow these steps:
Get a command prompt by going to Start->Run... ,
then typing "cmd". :ulb,l
Move to the directory where you have your input, e.g. a copy of
the [in.lj] input from the bench folder. (e.g. by typing: cd "Documents"). :l
At the command prompt, type "lmp_serial -in in.lj", replacing [in.lj]
with the name of your LAMMPS input script. :l
:ule
For the MPI version, which allows you to run LAMMPS under Windows on
multiple processors, follow these steps:
Download and install
"MPICH2"_http://www.mcs.anl.gov/research/projects/mpich2/downloads/index.php?s=downloads
for Windows. :ulb,l
The LAMMPS Windows installer packages will automatically adjust your
path for the default location of this MPI package. After the installation
of the MPICH software, it needs to be integrated into the system.
For this you need to start a Command Prompt in {Administrator Mode}
(right click on the icon and select it). Change into the MPICH2
installation directory, then into the subdirectory [bin] and execute
[smpd.exe -install]. Exit the command window.
Get a new, regular command prompt by going to Start->Run... ,
then typing "cmd". :l
Move to the directory where you have your input file
(e.g. by typing: cd "Documents"). :l
Then type something like this:
mpiexec -localonly 4 lmp_mpi -in in.lj :pre
or
mpiexec -np 4 lmp_mpi -in in.lj :pre
replacing in.lj with the name of your LAMMPS input script. For the latter
case, you may be prompted to enter your password. :l
In this mode, output may not immediately show up on the screen, so if
your input script takes a long time to execute, you may need to be
patient before the output shows up. :l
The parallel executable can also run on a single processor by typing
something like:
lmp_mpi -in in.lj :pre
:ule
:line
The screen output from LAMMPS is described in a section below. As it
runs, LAMMPS also writes a log.lammps file with the same information.
Note that this sequence of commands copies the LAMMPS executable
(lmp_linux) to the directory with the input files. This may not be
necessary, but some versions of MPI reset the working directory to
where the executable is, rather than leave it as the directory where
you launch mpirun from (if you launch lmp_linux on its own and not
under mpirun). If that happens, LAMMPS will look for additional input
files and write its output files to the executable directory, rather
than your working directory, which is probably not what you want.
If LAMMPS encounters errors in the input script or while running a
simulation it will print an ERROR message and stop or a WARNING
message and continue. See "Section 12"_Section_errors.html for a
discussion of the various kinds of errors LAMMPS can or can't detect,
a list of all ERROR and WARNING messages, and what to do about them.
LAMMPS can run a problem on any number of processors, including a
single processor. In theory you should get identical answers on any
number of processors and on any machine. In practice, numerical
round-off can cause slight differences and eventual divergence of
molecular dynamics phase space trajectories.
LAMMPS can run as large a problem as will fit in the physical memory
of one or more processors. If you run out of memory, you must run on
more processors or setup a smaller problem.
:line
2.6 Command-line options :h4,link(start_6)
At run time, LAMMPS recognizes several optional command-line switches
which may be used in any order. Either the full word or a one-or-two
letter abbreviation can be used:
-e or -echo
-h or -help
-i or -in
-k or -kokkos
-l or -log
-nc or -nocite
-pk or -package
-p or -partition
-pl or -plog
-ps or -pscreen
-r or -restart
-ro or -reorder
-sc or -screen
-sf or -suffix
-v or -var :ul
For example, lmp_ibm might be launched as follows:
mpirun -np 16 lmp_ibm -v f tmp.out -l my.log -sc none -in in.alloy
mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none -in in.alloy :pre
Here are the details on the options:
-echo style :pre
Set the style of command echoing. The style can be {none} or {screen}
or {log} or {both}. Depending on the style, each command read from
the input script will be echoed to the screen and/or logfile. This
can be useful to figure out which line of your script is causing an
input error. The default value is {log}. The echo style can also be
set by using the "echo"_echo.html command in the input script itself.
-help :pre
Print a brief help summary and a list of options compiled into this
executable for each LAMMPS style (atom_style, fix, compute,
pair_style, bond_style, etc). This can tell you if the command you
want to use was included via the appropriate package at compile time.
LAMMPS will print the info and immediately exit if this switch is
used.
-in file :pre
Specify a file to use as an input script. This is an optional switch
when running LAMMPS in one-partition mode. If it is not specified,
LAMMPS reads its script from standard input, typically from a script
via I/O redirection; e.g. lmp_linux < in.run. I/O redirection should
also work in parallel, but if it does not (in the unlikely case that
an MPI implementation does not support it), then use the -in flag.
Note that this is a required switch when running LAMMPS in
multi-partition mode, since multiple processors cannot all read from
stdin.
-kokkos on/off keyword/value ... :pre
Explicitly enable or disable KOKKOS support, as provided by the KOKKOS
package. Even if LAMMPS is built with this package, as described
above in "Section 2.3"_#start_3, this switch must be set to enable
running with the KOKKOS-enabled styles the package provides. If the
switch is not set (the default), LAMMPS will operate as if the KOKKOS
package were not installed; i.e. you can run standard LAMMPS or with
the GPU or USER-OMP packages, for testing or benchmarking purposes.
Additional optional keyword/value pairs can be specified which
determine how Kokkos will use the underlying hardware on your
platform. These settings apply to each MPI task you launch via the
"mpirun" or "mpiexec" command. You may choose to run one or more MPI
tasks per physical node. Note that if you are running on a desktop
machine, you typically have one physical node. On a cluster or
supercomputer there may be dozens or 1000s of physical nodes.
Either the full word or an abbreviation can be used for the keywords.
Note that the keywords do not use a leading minus sign. I.e. the
keyword is "t", not "-t". Also note that each of the keywords has a
default setting. Example of when to use these options and what
settings to use on different platforms is given in "Section
5.3"_Section_accelerate.html#acc_3.
d or device
g or gpus
t or threads
n or numa :ul
device Nd :pre
This option is only relevant if you built LAMMPS with CUDA=yes, you
have more than one GPU per node, and if you are running with only one
MPI task per node. The Nd setting is the ID of the GPU on the node to
run on. By default Nd = 0. If you have multiple GPUs per node, they
have consecutive IDs numbered as 0,1,2,etc. This setting allows you
to launch multiple independent jobs on the node, each with a single
MPI task per node, and assign each job to run on a different GPU.
gpus Ng Ns :pre
This option is only relevant if you built LAMMPS with CUDA=yes, you
have more than one GPU per node, and you are running with multiple MPI
tasks per node (up to one per GPU). The Ng setting is how many GPUs
you will use. The Ns setting is optional. If set, it is the ID of a
GPU to skip when assigning MPI tasks to GPUs. This may be useful if
your desktop system reserves one GPU to drive the screen and the rest
are intended for computational work like running LAMMPS. By default
Ng = 1 and Ns is not set.
Depending on which flavor of MPI you are running, LAMMPS will look for
one of these 3 environment variables
SLURM_LOCALID (various MPI variants compiled with SLURM support)
MV2_COMM_WORLD_LOCAL_RANK (Mvapich)
OMPI_COMM_WORLD_LOCAL_RANK (OpenMPI) :pre
which are initialized by the "srun", "mpirun" or "mpiexec" commands.
The environment variable setting for each MPI rank is used to assign a
unique GPU ID to the MPI task.
threads Nt :pre
This option assigns Nt number of threads to each MPI task for
performing work when Kokkos is executing in OpenMP or pthreads mode.
The default is Nt = 1, which essentially runs in MPI-only mode. If
there are Np MPI tasks per physical node, you generally want Np*Nt =
the number of physical cores per node, to use your available hardware
optimally. This also sets the number of threads used by the host when
LAMMPS is compiled with CUDA=yes.
numa Nm :pre
This option is only relevant when using pthreads with hwloc support.
In this case Nm defines the number of NUMA regions (typicaly sockets)
on a node which will be utilizied by a single MPI rank. By default Nm
= 1. If this option is used the total number of worker-threads per
MPI rank is threads*numa. Currently it is always almost better to
assign at least one MPI rank per NUMA region, and leave numa set to
its default value of 1. This is because letting a single process span
multiple NUMA regions induces a significant amount of cross NUMA data
traffic which is slow.
-log file :pre
Specify a log file for LAMMPS to write status information to. In
one-partition mode, if the switch is not used, LAMMPS writes to the
file log.lammps. If this switch is used, LAMMPS writes to the
specified file. In multi-partition mode, if the switch is not used, a
log.lammps file is created with hi-level status information. Each
partition also writes to a log.lammps.N file where N is the partition
ID. If the switch is specified in multi-partition mode, the hi-level
logfile is named "file" and each partition also logs information to a
file.N. For both one-partition and multi-partition mode, if the
specified file is "none", then no log files are created. Using a
"log"_log.html command in the input script will override this setting.
Option -plog will override the name of the partition log files file.N.
-nocite :pre
Disable writing the log.cite file which is normally written to list
references for specific cite-able features used during a LAMMPS run.
See the "citation page"_http://lammps.sandia.gov/cite.html for more
details.
-package style args .... :pre
Invoke the "package"_package.html command with style and args. The
syntax is the same as if the command appeared at the top of the input
script. For example "-package gpu 2" or "-pk gpu 2" is the same as
"package gpu 2"_package.html in the input script. The possible styles
and args are documented on the "package"_package.html doc page. This
switch can be used multiple times, e.g. to set options for the
USER-INTEL and USER-OMP packages which can be used together.
Along with the "-suffix" command-line switch, this is a convenient
mechanism for invoking accelerator packages and their options without
having to edit an input script.
-partition 8x2 4 5 ... :pre
Invoke LAMMPS in multi-partition mode. When LAMMPS is run on P
processors and this switch is not used, LAMMPS runs in one partition,
i.e. all P processors run a single simulation. If this switch is
used, the P processors are split into separate partitions and each
partition runs its own simulation. The arguments to the switch
specify the number of processors in each partition. Arguments of the
form MxN mean M partitions, each with N processors. Arguments of the
form N mean a single partition with N processors. The sum of
processors in all partitions must equal P. Thus the command
"-partition 8x2 4 5" has 10 partitions and runs on a total of 25
processors.
Running with multiple partitions can e useful for running
"multi-replica simulations"_Section_howto.html#howto_5, where each
replica runs on on one or a few processors. Note that with MPI
installed on a machine (e.g. your desktop), you can run on more
(virtual) processors than you have physical processors.
To run multiple independent simulatoins from one input script, using
multiple partitions, see "Section 6.4"_Section_howto.html#howto_4
of the manual. World- and universe-style "variables"_variable.html
are useful in this context.
-plog file :pre
Specify the base name for the partition log files, so partition N
writes log information to file.N. If file is none, then no partition
log files are created. This overrides the filename specified in the
-log command-line option. This option is useful when working with
large numbers of partitions, allowing the partition log files to be
suppressed (-plog none) or placed in a sub-directory (-plog
replica_files/log.lammps) If this option is not used the log file for
partition N is log.lammps.N or whatever is specified by the -log
command-line option.
-pscreen file :pre
Specify the base name for the partition screen file, so partition N
writes screen information to file.N. If file is none, then no
partition screen files are created. This overrides the filename
specified in the -screen command-line option. This option is useful
when working with large numbers of partitions, allowing the partition
screen files to be suppressed (-pscreen none) or placed in a
sub-directory (-pscreen replica_files/screen). If this option is not
used the screen file for partition N is screen.N or whatever is
specified by the -screen command-line option.
-restart restartfile {remap} datafile keyword value ... :pre
Convert the restart file into a data file and immediately exit. This
is the same operation as if the following 2-line input script were
run:
read_restart restartfile {remap}
write_data datafile keyword value ... :pre
Note that the specified restartfile and datafile can have wild-card
characters ("*",%") as described by the
"read_restart"_read_restart.html and "write_data"_write_data.html
commands. But a filename such as file.* will need to be enclosed in
quotes to avoid shell expansion of the "*" character.
Note that following restartfile, the optional flag {remap} can be
used. This has the same effect as adding it to the
"read_restart"_read_restart.html command, as explained on its doc
page. This is only useful if the reading of the restart file triggers
an error that atoms have been lost. In that case, use of the remap
flag should allow the data file to still be produced.
Also note that following datafile, the same optional keyword/value
pairs can be listed as used by the "write_data"_write_data.html
command.
-reorder nth N
-reorder custom filename :pre
Reorder the processors in the MPI communicator used to instantiate
LAMMPS, in one of several ways. The original MPI communicator ranks
all P processors from 0 to P-1. The mapping of these ranks to
physical processors is done by MPI before LAMMPS begins. It may be
useful in some cases to alter the rank order. E.g. to insure that
cores within each node are ranked in a desired order. Or when using
the "run_style verlet/split"_run_style.html command with 2 partitions
to insure that a specific Kspace processor (in the 2nd partition) is
matched up with a specific set of processors in the 1st partition.
See the "Section 5"_Section_accelerate.html doc pages for
more details.
If the keyword {nth} is used with a setting {N}, then it means every
Nth processor will be moved to the end of the ranking. This is useful
when using the "run_style verlet/split"_run_style.html command with 2
partitions via the -partition command-line switch. The first set of
processors will be in the first partition, the 2nd set in the 2nd
partition. The -reorder command-line switch can alter this so that
the 1st N procs in the 1st partition and one proc in the 2nd partition
will be ordered consecutively, e.g. as the cores on one physical node.
This can boost performance. For example, if you use "-reorder nth 4"
and "-partition 9 3" and you are running on 12 processors, the
processors will be reordered from
0 1 2 3 4 5 6 7 8 9 10 11 :pre
to
0 1 2 4 5 6 8 9 10 3 7 11 :pre
so that the processors in each partition will be
0 1 2 4 5 6 8 9 10
3 7 11 :pre
See the "processors" command for how to insure processors from each
partition could then be grouped optimally for quad-core nodes.
If the keyword is {custom}, then a file that specifies a permutation
of the processor ranks is also specified. The format of the reorder
file is as follows. Any number of initial blank or comment lines
(starting with a "#" character) can be present. These should be
followed by P lines of the form:
I J :pre
where P is the number of processors LAMMPS was launched with. Note
that if running in multi-partition mode (see the -partition switch
above) P is the total number of processors in all partitions. The I
and J values describe a permutation of the P processors. Every I and
J should be values from 0 to P-1 inclusive. In the set of P I values,
every proc ID should appear exactly once. Ditto for the set of P J
values. A single I,J pairing means that the physical processor with
rank I in the original MPI communicator will have rank J in the
reordered communicator.
Note that rank ordering can also be specified by many MPI
implementations, either by environment variables that specify how to
order physical processors, or by config files that specify what
physical processors to assign to each MPI rank. The -reorder switch
simply gives you a portable way to do this without relying on MPI
itself. See the "processors out"_processors.html command for how
to output info on the final assignment of physical processors to
the LAMMPS simulation domain.
-screen file :pre
Specify a file for LAMMPS to write its screen information to. In
one-partition mode, if the switch is not used, LAMMPS writes to the
screen. If this switch is used, LAMMPS writes to the specified file
instead and you will see no screen output. In multi-partition mode,
if the switch is not used, hi-level status information is written to
the screen. Each partition also writes to a screen.N file where N is
the partition ID. If the switch is specified in multi-partition mode,
the hi-level screen dump is named "file" and each partition also
writes screen information to a file.N. For both one-partition and
multi-partition mode, if the specified file is "none", then no screen
output is performed. Option -pscreen will override the name of the
partition screen files file.N.
-suffix style args :pre
Use variants of various styles if they exist. The specified style can
be {cuda}, {gpu}, {intel}, {kk}, {omp}, {opt}, or {hybrid}. These
refer to optional packages that LAMMPS can be built with, as described
above in "Section 2.3"_#start_3. The "gpu" style corresponds to the
GPU package, the "intel" style to the USER-INTEL package, the "kk"
style to the KOKKOS package, the "opt" style to the OPT package, and
the "omp" style to the USER-OMP package. The hybrid style is the only
style that accepts arguments. It allows for two packages to be
specified. The first package specified is the default and will be used
if it is available. If no style is available for the first package,
the style for the second package will be used if available. For
example, "-suffix hybrid intel omp" will use styles from the
USER-INTEL package if they are installed and available, but styles for
the USER-OMP package otherwise.
Along with the "-package" command-line switch, this is a convenient
mechanism for invoking accelerator packages and their options without
having to edit an input script.
As an example, all of the packages provide a "pair_style
lj/cut"_pair_lj.html variant, with style names lj/cut/gpu,
lj/cut/intel, lj/cut/kk, lj/cut/omp, and lj/cut/opt. A variant style
can be specified explicitly in your input script, e.g. pair_style
lj/cut/gpu. If the -suffix switch is used the specified suffix
(gpu,intel,kk,omp,opt) is automatically appended whenever your input
script command creates a new "atom"_atom_style.html,
"pair"_pair_style.html, "fix"_fix.html, "compute"_compute.html, or
"run"_run_style.html style. If the variant version does not exist,
the standard version is created.
For the GPU package, using this command-line switch also invokes the
default GPU settings, as if the command "package gpu 1" were used at
the top of your input script. These settings can be changed by using
the "-package gpu" command-line switch or the "package
gpu"_package.html command in your script.
For the USER-INTEL package, using this command-line switch also
invokes the default USER-INTEL settings, as if the command "package
intel 1" were used at the top of your input script. These settings
can be changed by using the "-package intel" command-line switch or
the "package intel"_package.html command in your script. If the
USER-OMP package is also installed, the hybrid style with "intel omp"
arguments can be used to make the omp suffix a second choice, if a
requested style is not available in the USER-INTEL package. It will
also invoke the default USER-OMP settings, as if the command "package
omp 0" were used at the top of your input script. These settings can
be changed by using the "-package omp" command-line switch or the
"package omp"_package.html command in your script.
For the KOKKOS package, using this command-line switch also invokes
the default KOKKOS settings, as if the command "package kokkos" were
used at the top of your input script. These settings can be changed
by using the "-package kokkos" command-line switch or the "package
kokkos"_package.html command in your script.
For the OMP package, using this command-line switch also invokes the
default OMP settings, as if the command "package omp 0" were used at
the top of your input script. These settings can be changed by using
the "-package omp" command-line switch or the "package
omp"_package.html command in your script.
The "suffix"_suffix.html command can also be used within an input
script to set a suffix, or to turn off or back on any suffix setting
made via the command line.
-var name value1 value2 ... :pre
Specify a variable that will be defined for substitution purposes when
the input script is read. This switch can be used multiple times to
define multiple variables. "Name" is the variable name which can be a
single character (referenced as $x in the input script) or a full
string (referenced as $\{abc\}). An "index-style
variable"_variable.html will be created and populated with the
subsequent values, e.g. a set of filenames. Using this command-line
option is equivalent to putting the line "variable name index value1
value2 ..." at the beginning of the input script. Defining an index
variable as a command-line argument overrides any setting for the same
index variable in the input script, since index variables cannot be
re-defined. See the "variable"_variable.html command for more info on
defining index and other kinds of variables and "this
section"_Section_commands.html#cmd_2 for more info on using variables
in input scripts.
NOTE: Currently, the command-line parser looks for arguments that
start with "-" to indicate new switches. Thus you cannot specify
multiple variable values if any of they start with a "-", e.g. a
negative numeric value. It is OK if the first value1 starts with a
"-", since it is automatically skipped.
:line
2.7 LAMMPS screen output :h4,link(start_7)
As LAMMPS reads an input script, it prints information to both the
screen and a log file about significant actions it takes to setup a
simulation. When the simulation is ready to begin, LAMMPS performs
various initializations and prints the amount of memory (in MBytes per
processor) that the simulation requires. It also prints details of
the initial thermodynamic state of the system. During the run itself,
thermodynamic information is printed periodically, every few
timesteps. When the run concludes, LAMMPS prints the final
thermodynamic state and a total run time for the simulation. It then
appends statistics about the CPU time and storage requirements for the
simulation. An example set of statistics is shown here:
Loop time of 2.81192 on 4 procs for 300 steps with 2004 atoms :pre
Performance: 18.436 ns/day 1.302 hours/ns 106.689 timesteps/s
97.0% CPU use with 4 MPI tasks x no OpenMP threads :pre
MPI task timings breakdown:
Section | min time | avg time | max time |%varavg| %total
---------------------------------------------------------------
Pair | 1.9808 | 2.0134 | 2.0318 | 1.4 | 71.60
Bond | 0.0021894 | 0.0060319 | 0.010058 | 4.7 | 0.21
Kspace | 0.3207 | 0.3366 | 0.36616 | 3.1 | 11.97
Neigh | 0.28411 | 0.28464 | 0.28516 | 0.1 | 10.12
Comm | 0.075732 | 0.077018 | 0.07883 | 0.4 | 2.74
Output | 0.00030518 | 0.00042665 | 0.00078821 | 1.0 | 0.02
Modify | 0.086606 | 0.086631 | 0.086668 | 0.0 | 3.08
Other | | 0.007178 | | | 0.26 :pre
Nlocal: 501 ave 508 max 490 min
Histogram: 1 0 0 0 0 0 1 1 0 1
Nghost: 6586.25 ave 6628 max 6548 min
Histogram: 1 0 1 0 0 0 1 0 0 1
Neighs: 177007 ave 180562 max 170212 min
Histogram: 1 0 0 0 0 0 0 1 1 1 :pre
Total # of neighbors = 708028
Ave neighs/atom = 353.307
Ave special neighs/atom = 2.34032
Neighbor list builds = 26
Dangerous builds = 0 :pre
The first section provides a global loop timing summary. The {loop time}
is the total wall time for the section. The {Performance} line is
provided for convenience to help predicting the number of loop
continuations required and for comparing performance with other,
similar MD codes. The {CPU use} line provides the CPU utilzation per
MPI task; it should be close to 100% times the number of OpenMP
threads (or 1 of no OpenMP). Lower numbers correspond to delays due
to file I/O or insufficient thread utilization.
The MPI task section gives the breakdown of the CPU run time (in
seconds) into major categories:
{Pair} stands for all non-bonded force computation
{Bond} stands for bonded interactions: bonds, angles, dihedrals, impropers
{Kspace} stands for reciprocal space interactions: Ewald, PPPM, MSM
{Neigh} stands for neighbor list construction
{Comm} stands for communicating atoms and their properties
{Output} stands for writing dumps and thermo output
{Modify} stands for fixes and computes called by them
{Other} is the remaining time :ul
For each category, there is a breakdown of the least, average and most
amount of wall time a processor spent on this section. Also you have the
variation from the average time. Together these numbers allow to gauge
the amount of load imbalance in this segment of the calculation. Ideally
the difference between minimum, maximum and average is small and thus
the variation from the average close to zero. The final column shows
the percentage of the total loop time is spent in this section.
When using the "timer full"_timer.html setting, an additional column
is present that also prints the CPU utilization in percent. In
addition, when using {timer full} and the "package omp"_package.html
command are active, a similar timing summary of time spent in threaded
regions to monitor thread utilization and load balance is provided. A
new entry is the {Reduce} section, which lists the time spent in
reducing the per-thread data elements to the storage for non-threaded
computation. These thread timings are taking from the first MPI rank
only and and thus, as the breakdown for MPI tasks can change from MPI
rank to MPI rank, this breakdown can be very different for individual
ranks. Here is an example output for this section:
Thread timings breakdown (MPI rank 0):
Total threaded time 0.6846 / 90.6%
Section | min time | avg time | max time |%varavg| %total
---------------------------------------------------------------
Pair | 0.5127 | 0.5147 | 0.5167 | 0.3 | 75.18
Bond | 0.0043139 | 0.0046779 | 0.0050418 | 0.5 | 0.68
Kspace | 0.070572 | 0.074541 | 0.07851 | 1.5 | 10.89
Neigh | 0.084778 | 0.086969 | 0.089161 | 0.7 | 12.70
Reduce | 0.0036485 | 0.003737 | 0.0038254 | 0.1 | 0.55 :pre
The third section lists the number of owned atoms (Nlocal), ghost atoms
(Nghost), and pair-wise neighbors stored per processor. The max and min
values give the spread of these values across processors with a 10-bin
histogram showing the distribution. The total number of histogram counts
is equal to the number of processors.
The last section gives aggregate statistics for pair-wise neighbors
and special neighbors that LAMMPS keeps track of (see the
"special_bonds"_special_bonds.html command). The number of times
neighbor lists were rebuilt during the run is given as well as the
number of potentially "dangerous" rebuilds. If atom movement
triggered neighbor list rebuilding (see the
"neigh_modify"_neigh_modify.html command), then dangerous
reneighborings are those that were triggered on the first timestep
atom movement was checked for. If this count is non-zero you may wish
to reduce the delay factor to insure no force interactions are missed
by atoms moving beyond the neighbor skin distance before a rebuild
takes place.
If an energy minimization was performed via the
"minimize"_minimize.html command, additional information is printed,
e.g.
Minimization stats:
Stopping criterion = linesearch alpha is zero
Energy initial, next-to-last, final =
-6372.3765206 -8328.46998942 -8328.46998942
Force two-norm initial, final = 1059.36 5.36874
Force max component initial, final = 58.6026 1.46872
Final line search alpha, max atom move = 2.7842e-10 4.0892e-10
Iterations, force evaluations = 701 1516 :pre
The first line prints the criterion that determined the minimization
to be completed. The third line lists the initial and final energy,
as well as the energy on the next-to-last iteration. The next 2 lines
give a measure of the gradient of the energy (force on all atoms).
The 2-norm is the "length" of this force vector; the inf-norm is the
largest component. Then some information about the line search and
statistics on how many iterations and force-evaluations the minimizer
required. Multiple force evaluations are typically done at each
iteration to perform a 1d line minimization in the search direction.
If a "kspace_style"_kspace_style.html long-range Coulombics solve was
performed during the run (PPPM, Ewald), then additional information is
printed, e.g.
FFT time (% of Kspce) = 0.200313 (8.34477)
FFT Gflps 3d 1d-only = 2.31074 9.19989 :pre
The first line gives the time spent doing 3d FFTs (4 per timestep) and
the fraction it represents of the total KSpace time (listed above).
Each 3d FFT requires computation (3 sets of 1d FFTs) and communication
(transposes). The total flops performed is 5Nlog_2(N), where N is the
number of points in the 3d grid. The FFTs are timed with and without
the communication and a Gflop rate is computed. The 3d rate is with
communication; the 1d rate is without (just the 1d FFTs). Thus you
can estimate what fraction of your FFT time was spent in
communication, roughly 75% in the example above.
:line
2.8 Tips for users of previous LAMMPS versions :h4,link(start_8)
The current C++ began with a complete rewrite of LAMMPS 2001, which
was written in F90. Features of earlier versions of LAMMPS are listed
in "Section 13"_Section_history.html. The F90 and F77 versions
(2001 and 99) are also freely distributed as open-source codes; check
the "LAMMPS WWW Site"_lws for distribution information if you prefer
those versions. The 99 and 2001 versions are no longer under active
development; they do not have all the features of C++ LAMMPS.
If you are a previous user of LAMMPS 2001, these are the most
significant changes you will notice in C++ LAMMPS:
(1) The names and arguments of many input script commands have
changed. All commands are now a single word (e.g. read_data instead
of read data).
(2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS,
but you may need to specify the relevant commands in different ways.
(3) The format of the data file can be streamlined for some problems.
See the "read_data"_read_data.html command for details. The data file
section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS.
(4) Binary restart files written by LAMMPS 2001 cannot be read by C++
LAMMPS with a "read_restart"_read_restart.html command. This is
because they were output by F90 which writes in a different binary
format than C or C++ writes or reads. Use the {restart2data} tool
provided with LAMMPS 2001 to convert the 2001 restart file to a text
data file. Then edit the data file as necessary before using the C++
LAMMPS "read_data"_read_data.html command to read it in.
(5) There are numerous small numerical changes in C++ LAMMPS that mean
you will not get identical answers when comparing to a 2001 run.
However, your initial thermodynamic energy and MD trajectory should be
close if you have setup the problem for both codes the same.
diff --git a/doc/src/accelerate_gpu.txt b/doc/src/accelerate_gpu.txt
index 2ac7d62f6..68e9fa477 100644
--- a/doc/src/accelerate_gpu.txt
+++ b/doc/src/accelerate_gpu.txt
@@ -1,254 +1,254 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
"Return to Section accelerate overview"_Section_accelerate.html
5.3.1 GPU package :h5
The GPU package was developed by Mike Brown at ORNL and his
collaborators, particularly Trung Nguyen (ORNL). It provides GPU
versions of many pair styles, including the 3-body Stillinger-Weber
pair style, and for "kspace_style pppm"_kspace_style.html for
long-range Coulombics. It has the following general features:
It is designed to exploit common GPU hardware configurations where one
or more GPUs are coupled to many cores of one or more multi-core CPUs,
e.g. within a node of a parallel machine. :ulb,l
Atom-based data (e.g. coordinates, forces) moves back-and-forth
between the CPU(s) and GPU every timestep. :l
Neighbor lists can be built on the CPU or on the GPU :l
The charge assignment and force interpolation portions of PPPM can be
run on the GPU. The FFT portion, which requires MPI communication
between processors, runs on the CPU. :l
Asynchronous force computations can be performed simultaneously on the
CPU(s) and GPU. :l
It allows for GPU computations to be performed in single or double
precision, or in mixed-mode precision, where pairwise forces are
computed in single precision, but accumulated into double-precision
force vectors. :l
LAMMPS-specific code is in the GPU package. It makes calls to a
generic GPU library in the lib/gpu directory. This library provides
NVIDIA support as well as more general OpenCL support, so that the
same functionality can eventually be supported on a variety of GPU
hardware. :l
:ule
Here is a quick overview of how to enable and use the GPU package:
build the library in lib/gpu for your GPU hardware with the desired precision settings
install the GPU package and build LAMMPS as usual
use the mpirun command to set the number of MPI tasks/node which determines the number of MPI tasks/GPU
specify the # of GPUs per node
use GPU styles in your input script :ul
The latter two steps can be done using the "-pk gpu" and "-sf gpu"
-"command-line switches"_Section_start.html#start_7 respectively. Or
+"command-line switches"_Section_start.html#start_6 respectively. Or
the effect of the "-pk" or "-sf" switches can be duplicated by adding
the "package gpu"_package.html or "suffix gpu"_suffix.html commands
respectively to your input script.
[Required hardware/software:]
To use this package, you currently need to have an NVIDIA GPU and
install the NVIDIA Cuda software on your system:
Check if you have an NVIDIA GPU: cat /proc/driver/nvidia/gpus/0/information
Go to http://www.nvidia.com/object/cuda_get.html
Install a driver and toolkit appropriate for your system (SDK is not necessary)
Run lammps/lib/gpu/nvc_get_devices (after building the GPU library, see below) to list supported devices and properties :ul
[Building LAMMPS with the GPU package:]
This requires two steps (a,b): build the GPU library, then build
LAMMPS with the GPU package.
You can do both these steps in one line, using the src/Make.py script,
-described in "Section 2.4"_Section_start.html#start_4 of the manual.
+described in "Section 4"_Section_packages.html of the manual.
Type "Make.py -h" for help. If run from the src directory, this
command will create src/lmp_gpu using src/MAKE/Makefile.mpi as the
starting Makefile.machine:
Make.py -p gpu -gpu mode=single arch=31 -o gpu -a lib-gpu file mpi :pre
Or you can follow these two (a,b) steps:
(a) Build the GPU library
The GPU library is in lammps/lib/gpu. Select a Makefile.machine (in
lib/gpu) appropriate for your system. You should pay special
attention to 3 settings in this makefile.
CUDA_HOME = needs to be where NVIDIA Cuda software is installed on your system
CUDA_ARCH = needs to be appropriate to your GPUs
CUDA_PREC = precision (double, mixed, single) you desire :ul
See lib/gpu/Makefile.linux.double for examples of the ARCH settings
for different GPU choices, e.g. Fermi vs Kepler. It also lists the
possible precision settings:
CUDA_PREC = -D_SINGLE_SINGLE # single precision for all calculations
CUDA_PREC = -D_DOUBLE_DOUBLE # double precision for all calculations
CUDA_PREC = -D_SINGLE_DOUBLE # accumulation of forces, etc, in double :pre
The last setting is the mixed mode referred to above. Note that your
GPU must support double precision to use either the 2nd or 3rd of
these settings.
To build the library, type:
make -f Makefile.machine :pre
If successful, it will produce the files libgpu.a and Makefile.lammps.
The latter file has 3 settings that need to be appropriate for the
paths and settings for the CUDA system software on your machine.
Makefile.lammps is a copy of the file specified by the EXTRAMAKE
setting in Makefile.machine. You can change EXTRAMAKE or create your
own Makefile.lammps.machine if needed.
Note that to change the precision of the GPU library, you need to
re-build the entire library. Do a "clean" first, e.g. "make -f
Makefile.linux clean", followed by the make command above.
(b) Build LAMMPS with the GPU package
cd lammps/src
make yes-gpu
make machine :pre
No additional compile/link flags are needed in Makefile.machine.
Note that if you change the GPU library precision (discussed above)
and rebuild the GPU library, then you also need to re-install the GPU
package and re-build LAMMPS, so that all affected files are
re-compiled and linked to the new GPU library.
[Run with the GPU package from the command line:]
The mpirun or mpiexec command sets the total number of MPI tasks used
by LAMMPS (one or multiple per compute node) and the number of MPI
tasks used per node. E.g. the mpirun command in MPICH does this via
its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode.
When using the GPU package, you cannot assign more than one GPU to a
single MPI task. However multiple MPI tasks can share the same GPU,
and in many cases it will be more efficient to run this way. Likewise
it may be more efficient to use less MPI tasks/node than the available
# of CPU cores. Assignment of multiple MPI tasks to a GPU will happen
automatically if you create more MPI tasks/node than there are
GPUs/mode. E.g. with 8 MPI tasks/node and 2 GPUs, each GPU will be
shared by 4 MPI tasks.
-Use the "-sf gpu" "command-line switch"_Section_start.html#start_7,
+Use the "-sf gpu" "command-line switch"_Section_start.html#start_6,
which will automatically append "gpu" to styles that support it. Use
-the "-pk gpu Ng" "command-line switch"_Section_start.html#start_7 to
+the "-pk gpu Ng" "command-line switch"_Section_start.html#start_6 to
set Ng = # of GPUs/node to use.
lmp_machine -sf gpu -pk gpu 1 -in in.script # 1 MPI task uses 1 GPU
mpirun -np 12 lmp_machine -sf gpu -pk gpu 2 -in in.script # 12 MPI tasks share 2 GPUs on a single 16-core (or whatever) node
mpirun -np 48 -ppn 12 lmp_machine -sf gpu -pk gpu 2 -in in.script # ditto on 4 16-core nodes :pre
Note that if the "-sf gpu" switch is used, it also issues a default
"package gpu 1"_package.html command, which sets the number of
GPUs/node to 1.
Using the "-pk" switch explicitly allows for setting of the number of
GPUs/node to use and additional options. Its syntax is the same as
same as the "package gpu" command. See the "package"_package.html
command doc page for details, including the default values used for
all its options if it is not specified.
Note that the default for the "package gpu"_package.html command is to
set the Newton flag to "off" pairwise interactions. It does not
affect the setting for bonded interactions (LAMMPS default is "on").
The "off" setting for pairwise interaction is currently required for
GPU package pair styles.
[Or run with the GPU package by editing an input script:]
The discussion above for the mpirun/mpiexec command, MPI tasks/node,
and use of multiple MPI tasks/GPU is the same.
Use the "suffix gpu"_suffix.html command, or you can explicitly add an
"gpu" suffix to individual styles in your input script, e.g.
pair_style lj/cut/gpu 2.5 :pre
You must also use the "package gpu"_package.html command to enable the
GPU package, unless the "-sf gpu" or "-pk gpu" "command-line
-switches"_Section_start.html#start_7 were used. It specifies the
+switches"_Section_start.html#start_6 were used. It specifies the
number of GPUs/node to use, as well as other options.
[Speed-ups to expect:]
The performance of a GPU versus a multi-core CPU is a function of your
hardware, which pair style is used, the number of atoms/GPU, and the
precision used on the GPU (double, single, mixed).
See the "Benchmark page"_http://lammps.sandia.gov/bench.html of the
LAMMPS web site for performance of the GPU package on various
hardware, including the Titan HPC platform at ORNL.
You should also experiment with how many MPI tasks per GPU to use to
give the best performance for your problem and machine. This is also
a function of the problem size and the pair style being using.
Likewise, you should experiment with the precision setting for the GPU
library to see if single or mixed precision will give accurate
results, since they will typically be faster.
[Guidelines for best performance:]
Using multiple MPI tasks per GPU will often give the best performance,
as allowed my most multi-core CPU/GPU configurations. :ulb,l
If the number of particles per MPI task is small (e.g. 100s of
particles), it can be more efficient to run with fewer MPI tasks per
GPU, even if you do not use all the cores on the compute node. :l
The "package gpu"_package.html command has several options for tuning
performance. Neighbor lists can be built on the GPU or CPU. Force
calculations can be dynamically balanced across the CPU cores and
GPUs. GPU-specific settings can be made which can be optimized
for different hardware. See the "packakge"_package.html command
doc page for details. :l
As described by the "package gpu"_package.html command, GPU
accelerated pair styles can perform computations asynchronously with
CPU computations. The "Pair" time reported by LAMMPS will be the
maximum of the time required to complete the CPU pair style
computations and the time required to complete the GPU pair style
computations. Any time spent for GPU-enabled pair styles for
computations that run simultaneously with "bond"_bond_style.html,
"angle"_angle_style.html, "dihedral"_dihedral_style.html,
"improper"_improper_style.html, and "long-range"_kspace_style.html
calculations will not be included in the "Pair" time. :l
When the {mode} setting for the package gpu command is force/neigh,
the time for neighbor list calculations on the GPU will be added into
the "Pair" time, not the "Neigh" time. An additional breakdown of the
times required for various tasks on the GPU (data copy, neighbor
calculations, force computations, etc) are output only with the LAMMPS
screen output (not in the log file) at the end of each run. These
timings represent total time spent on the GPU for each routine,
regardless of asynchronous CPU calculations. :l
The output section "GPU Time Info (average)" reports "Max Mem / Proc".
This is the maximum memory used at one time on the GPU for data
storage by a single MPI process. :l
:ule
[Restrictions:]
None.
diff --git a/doc/src/accelerate_intel.txt b/doc/src/accelerate_intel.txt
index 155e29e36..74ae9d9a4 100644
--- a/doc/src/accelerate_intel.txt
+++ b/doc/src/accelerate_intel.txt
@@ -1,517 +1,517 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
"Return to Section accelerate overview"_Section_accelerate.html
5.3.2 USER-INTEL package :h5
The USER-INTEL package is maintained by Mike Brown at Intel
Corporation. It provides two methods for accelerating simulations,
depending on the hardware you have. The first is acceleration on
Intel CPUs by running in single, mixed, or double precision with
vectorization. The second is acceleration on Intel Xeon Phi
coprocessors via offloading neighbor list and non-bonded force
calculations to the Phi. The same C++ code is used in both cases.
When offloading to a coprocessor from a CPU, the same routine is run
twice, once on the CPU and once with an offload flag. This allows
LAMMPS to run on the CPU cores and coprocessor cores simultaneously.
[Currently Available USER-INTEL Styles:]
Angle Styles: charmm, harmonic :ulb,l
Bond Styles: fene, harmonic :l
Dihedral Styles: charmm, harmonic, opls :l
Fixes: nve, npt, nvt, nvt/sllod :l
Improper Styles: cvff, harmonic :l
Pair Styles: buck/coul/cut, buck/coul/long, buck, eam, gayberne,
charmm/coul/long, lj/cut, lj/cut/coul/long, lj/long/coul/long, sw, tersoff :l
K-Space Styles: pppm, pppm/disp :l
:ule
[Speed-ups to expect:]
The speedups will depend on your simulation, the hardware, which
styles are used, the number of atoms, and the floating-point
precision mode. Performance improvements are shown compared to
LAMMPS {without using other acceleration packages} as these are
under active development (and subject to performance changes). The
measurements were performed using the input files available in
the src/USER-INTEL/TEST directory with the provided run script.
These are scalable in size; the results given are with 512K
particles (524K for Liquid Crystal). Most of the simulations are
standard LAMMPS benchmarks (indicated by the filename extension in
parenthesis) with modifications to the run length and to add a
warmup run (for use with offload benchmarks).
:c,image(JPG/user_intel.png)
Results are speedups obtained on Intel Xeon E5-2697v4 processors
(code-named Broadwell) and Intel Xeon Phi 7250 processors
(code-named Knights Landing) with "June 2017" LAMMPS built with
Intel Parallel Studio 2017 update 2. Results are with 1 MPI task
per physical core. See {src/USER-INTEL/TEST/README} for the raw
simulation rates and instructions to reproduce.
:line
[Accuracy and order of operations:]
In most molecular dynamics software, parallelization parameters
(# of MPI, OpenMP, and vectorization) can change the results due
to changing the order of operations with finite-precision
calculations. The USER-INTEL package is deterministic. This means
that the results should be reproducible from run to run with the
{same} parallel configurations and when using determinstic
libraries or library settings (MPI, OpenMP, FFT). However, there
are differences in the USER-INTEL package that can change the
order of operations compared to LAMMPS without acceleration:
Neighbor lists can be created in a different order :ulb,l
Bins used for sorting atoms can be oriented differently :l
The default stencil order for PPPM is 7. By default, LAMMPS will
calculate other PPPM parameters to fit the desired acuracy with
this order :l
The {newton} setting applies to all atoms, not just atoms shared
between MPI tasks :l
Vectorization can change the order for adding pairwise forces :l
:ule
The precision mode (described below) used with the USER-INTEL
package can change the {accuracy} of the calculations. For the
default {mixed} precision option, calculations between pairs or
triplets of atoms are performed in single precision, intended to
be within the inherent error of MD simulations. All accumulation
is performed in double precision to prevent the error from growing
with the number of atoms in the simulation. {Single} precision
mode should not be used without appropriate validation.
:line
[Quick Start for Experienced Users:]
LAMMPS should be built with the USER-INTEL package installed.
Simulations should be run with 1 MPI task per physical {core},
not {hardware thread}.
Edit src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi as necessary. :ulb,l
Set the environment variable KMP_BLOCKTIME=0 :l
"-pk intel 0 omp $t -sf intel" added to LAMMPS command-line :l
$t should be 2 for Intel Xeon CPUs and 2 or 4 for Intel Xeon Phi :l
For some of the simple 2-body potentials without long-range
electrostatics, performance and scalability can be better with
the "newton off" setting added to the input script :l
For simulations on higher node counts, add "processors * * * grid
numa" to the beginning of the input script for better scalability :l
If using {kspace_style pppm} in the input script, add
"kspace_modify diff ad" for better performance :l
:ule
For Intel Xeon Phi CPUs:
Runs should be performed using MCDRAM. :ulb,l
:ule
For simulations using {kspace_style pppm} on Intel CPUs
supporting AVX-512:
Add "kspace_modify diff ad" to the input script :ulb,l
The command-line option should be changed to
"-pk intel 0 omp $r lrt yes -sf intel" where $r is the number of
threads minus 1. :l
Do not use thread affinity (set KMP_AFFINITY=none) :l
The "newton off" setting may provide better scalability :l
:ule
For Intel Xeon Phi coprocessors (Offload):
Edit src/MAKE/OPTIONS/Makefile.intel_coprocessor as necessary :ulb,l
"-pk intel N omp 1" added to command-line where N is the number of
coprocessors per node. :l
:ule
:line
[Required hardware/software:]
In order to use offload to coprocessors, an Intel Xeon Phi
coprocessor and an Intel compiler are required. For this, the
recommended version of the Intel compiler is 14.0.1.106 or
versions 15.0.2.044 and higher.
Although any compiler can be used with the USER-INTEL package,
currently, vectorization directives are disabled by default when
not using Intel compilers due to lack of standard support and
observations of decreased performance. The OpenMP standard now
supports directives for vectorization and we plan to transition the
code to this standard once it is available in most compilers. We
expect this to allow improved performance and support with other
compilers.
For Intel Xeon Phi x200 series processors (code-named Knights
Landing), there are multiple configuration options for the hardware.
For best performance, we recommend that the MCDRAM is configured in
"Flat" mode and with the cluster mode set to "Quadrant" or "SNC4".
"Cache" mode can also be used, although the performance might be
slightly lower.
[Notes about Simultaneous Multithreading:]
Modern CPUs often support Simultaneous Multithreading (SMT). On
Intel processors, this is called Hyper-Threading (HT) technology.
SMT is hardware support for running multiple threads efficiently on
a single core. {Hardware threads} or {logical cores} are often used
to refer to the number of threads that are supported in hardware.
For example, the Intel Xeon E5-2697v4 processor is described
as having 36 cores and 72 threads. This means that 36 MPI processes
or OpenMP threads can run simultaneously on separate cores, but that
up to 72 MPI processes or OpenMP threads can be running on the CPU
without costly operating system context switches.
Molecular dynamics simulations will often run faster when making use
of SMT. If a thread becomes stalled, for example because it is
waiting on data that has not yet arrived from memory, another thread
can start running so that the CPU pipeline is still being used
efficiently. Although benefits can be seen by launching a MPI task
for every hardware thread, for multinode simulations, we recommend
that OpenMP threads are used for SMT instead, either with the
USER-INTEL package, "USER-OMP package"_accelerate_omp.html, or
"KOKKOS package"_accelerate_kokkos.html. In the example above, up
to 36X speedups can be observed by using all 36 physical cores with
LAMMPS. By using all 72 hardware threads, an additional 10-30%
performance gain can be achieved.
The BIOS on many platforms allows SMT to be disabled, however, we do
not recommend this on modern processors as there is little to no
benefit for any software package in most cases. The operating system
will report every hardware thread as a separate core allowing one to
determine the number of hardware threads available. On Linux systems,
this information can normally be obtained with:
cat /proc/cpuinfo :pre
[Building LAMMPS with the USER-INTEL package:]
NOTE: See the src/USER-INTEL/README file for additional flags that
might be needed for best performance on Intel server processors
code-named "Skylake".
The USER-INTEL package must be installed into the source directory:
make yes-user-intel :pre
Several example Makefiles for building with the Intel compiler are
included with LAMMPS in the src/MAKE/OPTIONS/ directory:
Makefile.intel_cpu_intelmpi # Intel Compiler, Intel MPI, No Offload
Makefile.knl # Intel Compiler, Intel MPI, No Offload
Makefile.intel_cpu_mpich # Intel Compiler, MPICH, No Offload
Makefile.intel_cpu_openpmi # Intel Compiler, OpenMPI, No Offload
Makefile.intel_coprocessor # Intel Compiler, Intel MPI, Offload :pre
Makefile.knl is identical to Makefile.intel_cpu_intelmpi except that
it explicitly specifies that vectorization should be for Intel
Xeon Phi x200 processors making it easier to cross-compile. For
users with recent installations of Intel Parallel Studio, the
process can be as simple as:
make yes-user-intel
source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh
# or psxevars.csh for C-shell
make intel_cpu_intelmpi :pre
Alternatively, the build can be accomplished with the src/Make.py
-script, described in "Section 2.4"_Section_start.html#start_4 of the
+script, described in "Section 4"_Section_packages.html of the
manual. Type "Make.py -h" for help. For an example:
Make.py -v -p intel omp -intel cpu -a file intel_cpu_intelmpi :pre
Note that if you build with support for a Phi coprocessor, the same
binary can be used on nodes with or without coprocessors installed.
However, if you do not have coprocessors on your system, building
without offload support will produce a smaller binary.
The general requirements for Makefiles with the USER-INTEL package
are as follows. "-DLAMMPS_MEMALIGN=64" is required for CCFLAGS. When
using Intel compilers, "-restrict" is required and "-qopenmp" is
highly recommended for CCFLAGS and LINKFLAGS. LIB should include
"-ltbbmalloc". For builds supporting offload, "-DLMP_INTEL_OFFLOAD"
is required for CCFLAGS and "-qoffload" is required for LINKFLAGS.
Other recommended CCFLAG options for best performance are
"-O2 -fno-alias -ansi-alias -qoverride-limits fp-model fast=2
-no-prec-div". The Make.py command will add all of these
automatically.
NOTE: The vectorization and math capabilities can differ depending on
the CPU. For Intel compilers, the "-x" flag specifies the type of
processor for which to optimize. "-xHost" specifies that the compiler
should build for the processor used for compiling. For Intel Xeon Phi
x200 series processors, this option is "-xMIC-AVX512". For fourth
generation Intel Xeon (v4/Broadwell) processors, "-xCORE-AVX2" should
be used. For older Intel Xeon processors, "-xAVX" will perform best
in general for the different simulations in LAMMPS. The default
in most of the example Makefiles is to use "-xHost", however this
should not be used when cross-compiling.
[Running LAMMPS with the USER-INTEL package:]
Running LAMMPS with the USER-INTEL package is similar to normal use
with the exceptions that one should 1) specify that LAMMPS should use
the USER-INTEL package, 2) specify the number of OpenMP threads, and
3) optionally specify the specific LAMMPS styles that should use the
USER-INTEL package. 1) and 2) can be performed from the command-line
or by editing the input script. 3) requires editing the input script.
Advanced performance tuning options are also described below to get
the best performance.
When running on a single node (including runs using offload to a
coprocessor), best performance is normally obtained by using 1 MPI
task per physical core and additional OpenMP threads with SMT. For
Intel Xeon processors, 2 OpenMP threads should be used for SMT.
For Intel Xeon Phi CPUs, 2 or 4 OpenMP threads should be used
(best choice depends on the simulation). In cases where the user
specifies that LRT mode is used (described below), 1 or 3 OpenMP
threads should be used. For multi-node runs, using 1 MPI task per
physical core will often perform best, however, depending on the
machine and scale, users might get better performance by decreasing
the number of MPI tasks and using more OpenMP threads. For
performance, the product of the number of MPI tasks and OpenMP
threads should not exceed the number of available hardware threads in
almost all cases.
NOTE: Setting core affinity is often used to pin MPI tasks and OpenMP
threads to a core or group of cores so that memory access can be
uniform. Unless disabled at build time, affinity for MPI tasks and
OpenMP threads on the host (CPU) will be set by default on the host
{when using offload to a coprocessor}. In this case, it is unnecessary
to use other methods to control affinity (e.g. taskset, numactl,
I_MPI_PIN_DOMAIN, etc.). This can be disabled with the {no_affinity}
option to the "package intel"_package.html command or by disabling the
option at build time (by adding -DINTEL_OFFLOAD_NOAFFINITY to the
CCFLAGS line of your Makefile). Disabling this option is not
recommended, especially when running on a machine with Intel
Hyper-Threading technology disabled.
[Run with the USER-INTEL package from the command line:]
To enable USER-INTEL optimizations for all available styles used in
the input script, the "-sf intel"
-"command-line switch"_Section_start.html#start_7 can be used without
+"command-line switch"_Section_start.html#start_6 can be used without
any requirement for editing the input script. This switch will
automatically append "intel" to styles that support it. It also
invokes a default command: "package intel 1"_package.html. This
package command is used to set options for the USER-INTEL package.
The default package command will specify that USER-INTEL calculations
are performed in mixed precision, that the number of OpenMP threads
is specified by the OMP_NUM_THREADS environment variable, and that
if coprocessors are present and the binary was built with offload
support, that 1 coprocessor per node will be used with automatic
balancing of work between the CPU and the coprocessor.
You can specify different options for the USER-INTEL package by using
-the "-pk intel Nphi" "command-line switch"_Section_start.html#start_7
+the "-pk intel Nphi" "command-line switch"_Section_start.html#start_6
with keyword/value pairs as specified in the documentation. Here,
Nphi = # of Xeon Phi coprocessors/node (ignored without offload
support). Common options to the USER-INTEL package include {omp} to
override any OMP_NUM_THREADS setting and specify the number of OpenMP
threads, {mode} to set the floating-point precision mode, and
{lrt} to enable Long-Range Thread mode as described below. See the
"package intel"_package.html command for details, including the
default values used for all its options if not specified, and how to
set the number of OpenMP threads via the OMP_NUM_THREADS environment
variable if desired.
Examples (see documentation for your MPI/Machine for differences in
launching MPI applications):
mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script # 2 nodes, 36 MPI tasks/node, $OMP_NUM_THREADS OpenMP Threads
mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script -pk intel 0 omp 2 mode double # Don't use any coprocessors that might be available, use 2 OpenMP threads for each task, use double precision :pre
[Or run with the USER-INTEL package by editing an input script:]
As an alternative to adding command-line arguments, the input script
can be edited to enable the USER-INTEL package. This requires adding
the "package intel"_package.html command to the top of the input
script. For the second example above, this would be:
package intel 0 omp 2 mode double :pre
To enable the USER-INTEL package only for individual styles, you can
add an "intel" suffix to the individual style, e.g.:
pair_style lj/cut/intel 2.5 :pre
Alternatively, the "suffix intel"_suffix.html command can be added to
the input script to enable USER-INTEL styles for the commands that
follow in the input script.
[Tuning for Performance:]
NOTE: The USER-INTEL package will perform better with modifications
to the input script when "PPPM"_kspace_style.html is used:
"kspace_modify diff ad"_kspace_modify.html should be added to the
input script.
Long-Range Thread (LRT) mode is an option to the "package
intel"_package.html command that can improve performance when using
"PPPM"_kspace_style.html for long-range electrostatics on processors
with SMT. It generates an extra pthread for each MPI task. The thread
is dedicated to performing some of the PPPM calculations and MPI
communications. On Intel Xeon Phi x200 series CPUs, this will likely
always improve performance, even on a single node. On Intel Xeon
processors, using this mode might result in better performance when
using multiple nodes, depending on the machine. To use this mode,
specify that the number of OpenMP threads is one less than would
normally be used for the run and add the "lrt yes" option to the "-pk"
command-line suffix or "package intel" command. For example, if a run
would normally perform best with "-pk intel 0 omp 4", instead use
"-pk intel 0 omp 3 lrt yes". When using LRT, you should set the
environment variable "KMP_AFFINITY=none". LRT mode is not supported
when using offload.
NOTE: Changing the "newton"_newton.html setting to off can improve
performance and/or scalability for simple 2-body potentials such as
lj/cut or when using LRT mode on processors supporting AVX-512.
Not all styles are supported in the USER-INTEL package. You can mix
the USER-INTEL package with styles from the "OPT"_accelerate_opt.html
package or the "USER-OMP package"_accelerate_omp.html. Of course,
this requires that these packages were installed at build time. This
can performed automatically by using "-sf hybrid intel opt" or
"-sf hybrid intel omp" command-line options. Alternatively, the "opt"
and "omp" suffixes can be appended manually in the input script. For
the latter, the "package omp"_package.html command must be in the
input script or the "-pk omp Nt" "command-line
-switch"_Section_start.html#start_7 must be used where Nt is the
+switch"_Section_start.html#start_6 must be used where Nt is the
number of OpenMP threads. The number of OpenMP threads should not be
set differently for the different packages. Note that the "suffix
hybrid intel omp"_suffix.html command can also be used within the
input script to automatically append the "omp" suffix to styles when
USER-INTEL styles are not available.
NOTE: For simulations on higher node counts, add "processors * * *
grid numa"_processors.html" to the beginning of the input script for
better scalability.
When running on many nodes, performance might be better when using
fewer OpenMP threads and more MPI tasks. This will depend on the
simulation and the machine. Using the "verlet/split"_run_style.html
run style might also give better performance for simulations with
"PPPM"_kspace_style.html electrostatics. Note that this is an
alternative to LRT mode and the two cannot be used together.
Currently, when using Intel MPI with Intel Xeon Phi x200 series
CPUs, better performance might be obtained by setting the
environment variable "I_MPI_SHM_LMT=shm" for Linux kernels that do
not yet have full support for AVX-512. Runs on Intel Xeon Phi x200
series processors will always perform better using MCDRAM. Please
consult your system documentation for the best approach to specify
that MPI runs are performed in MCDRAM.
[Tuning for Offload Performance:]
The default settings for offload should give good performance.
When using LAMMPS with offload to Intel coprocessors, best performance
will typically be achieved with concurrent calculations performed on
both the CPU and the coprocessor. This is achieved by offloading only
a fraction of the neighbor and pair computations to the coprocessor or
using "hybrid"_pair_hybrid.html pair styles where only one style uses
the "intel" suffix. For simulations with long-range electrostatics or
bond, angle, dihedral, improper calculations, computation and data
transfer to the coprocessor will run concurrently with computations
and MPI communications for these calculations on the host CPU. This
is illustrated in the figure below for the rhodopsin protein benchmark
running on E5-2697v2 processors with a Intel Xeon Phi 7120p
coprocessor. In this plot, the vertical access is time and routines
running at the same time are running concurrently on both the host and
the coprocessor.
:c,image(JPG/offload_knc.png)
The fraction of the offloaded work is controlled by the {balance}
keyword in the "package intel"_package.html command. A balance of 0
runs all calculations on the CPU. A balance of 1 runs all
supported calculations on the coprocessor. A balance of 0.5 runs half
of the calculations on the coprocessor. Setting the balance to -1
(the default) will enable dynamic load balancing that continously
adjusts the fraction of offloaded work throughout the simulation.
Because data transfer cannot be timed, this option typically produces
results within 5 to 10 percent of the optimal fixed balance.
If running short benchmark runs with dynamic load balancing, adding a
short warm-up run (10-20 steps) will allow the load-balancer to find a
near-optimal setting that will carry over to additional runs.
The default for the "package intel"_package.html command is to have
all the MPI tasks on a given compute node use a single Xeon Phi
coprocessor. In general, running with a large number of MPI tasks on
each node will perform best with offload. Each MPI task will
automatically get affinity to a subset of the hardware threads
available on the coprocessor. For example, if your card has 61 cores,
with 60 cores available for offload and 4 hardware threads per core
(240 total threads), running with 24 MPI tasks per node will cause
each MPI task to use a subset of 10 threads on the coprocessor. Fine
tuning of the number of threads to use per MPI task or the number of
threads to use per core can be accomplished with keyword settings of
the "package intel"_package.html command.
The USER-INTEL package has two modes for deciding which atoms will be
handled by the coprocessor. This choice is controlled with the {ghost}
keyword of the "package intel"_package.html command. When set to 0,
ghost atoms (atoms at the borders between MPI tasks) are not offloaded
to the card. This allows for overlap of MPI communication of forces
with computation on the coprocessor when the "newton"_newton.html
setting is "on". The default is dependent on the style being used,
however, better performance may be achieved by setting this option
explicitly.
When using offload with CPU Hyper-Threading disabled, it may help
performance to use fewer MPI tasks and OpenMP threads than available
cores. This is due to the fact that additional threads are generated
internally to handle the asynchronous offload tasks.
If pair computations are being offloaded to an Intel Xeon Phi
coprocessor, a diagnostic line is printed to the screen (not to the
log file), during the setup phase of a run, indicating that offload
mode is being used and indicating the number of coprocessor threads
per MPI task. Additionally, an offload timing summary is printed at
the end of each run. When offloading, the frequency for "atom
sorting"_atom_modify.html is changed to 1 so that the per-atom data is
effectively sorted at every rebuild of the neighbor lists. All the
available coprocessor threads on each Phi will be divided among MPI
tasks, unless the {tptask} option of the "-pk intel" "command-line
-switch"_Section_start.html#start_7 is used to limit the coprocessor
+switch"_Section_start.html#start_6 is used to limit the coprocessor
threads per MPI task.
[Restrictions:]
When offloading to a coprocessor, "hybrid"_pair_hybrid.html styles
that require skip lists for neighbor builds cannot be offloaded.
Using "hybrid/overlay"_pair_hybrid.html is allowed. Only one intel
accelerated style may be used with hybrid styles.
"Special_bonds"_special_bonds.html exclusion lists are not currently
supported with offload, however, the same effect can often be
accomplished by setting cutoffs for excluded atom types to 0. None of
the pair styles in the USER-INTEL package currently support the
"inner", "middle", "outer" options for rRESPA integration via the
"run_style respa"_run_style.html command; only the "pair" option is
supported.
[References:]
Brown, W.M., Carrillo, J.-M.Y., Mishra, B., Gavhane, N., Thakker, F.M., De Kraker, A.R., Yamada, M., Ang, J.A., Plimpton, S.J., "Optimizing Classical Molecular Dynamics in LAMMPS," in Intel Xeon Phi Processor High Performance Programming: Knights Landing Edition, J. Jeffers, J. Reinders, A. Sodani, Eds. Morgan Kaufmann. :ulb,l
Brown, W. M., Semin, A., Hebenstreit, M., Khvostov, S., Raman, K., Plimpton, S.J. "Increasing Molecular Dynamics Simulation Rates with an 8-Fold Increase in Electrical Power Efficiency."_http://dl.acm.org/citation.cfm?id=3014915 2016 High Performance Computing, Networking, Storage and Analysis, SC16: International Conference (pp. 82-95). :l
Brown, W.M., Carrillo, J.-M.Y., Gavhane, N., Thakkar, F.M., Plimpton, S.J. Optimizing Legacy Molecular Dynamics Software with Directive-Based Offload. Computer Physics Communications. 2015. 195: p. 95-101. :l
:ule
diff --git a/doc/src/accelerate_kokkos.txt b/doc/src/accelerate_kokkos.txt
index 602c3191f..6ccd69584 100644
--- a/doc/src/accelerate_kokkos.txt
+++ b/doc/src/accelerate_kokkos.txt
@@ -1,496 +1,496 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
"Return to Section accelerate overview"_Section_accelerate.html
5.3.3 KOKKOS package :h5
The KOKKOS package was developed primarily by Christian Trott (Sandia)
with contributions of various styles by others, including Sikandar
Mashayak (UIUC), Stan Moore (Sandia), and Ray Shan (Sandia). The
underlying Kokkos library was written primarily by Carter Edwards,
Christian Trott, and Dan Sunderland (all Sandia).
The KOKKOS package contains versions of pair, fix, and atom styles
that use data structures and macros provided by the Kokkos library,
which is included with LAMMPS in lib/kokkos.
The Kokkos library is part of
"Trilinos"_http://trilinos.sandia.gov/packages/kokkos and can also be
downloaded from "Github"_https://github.com/kokkos/kokkos. Kokkos is a
templated C++ library that provides two key abstractions for an
application like LAMMPS. First, it allows a single implementation of
an application kernel (e.g. a pair style) to run efficiently on
different kinds of hardware, such as a GPU, Intel Phi, or many-core
CPU.
The Kokkos library also provides data abstractions to adjust (at
compile time) the memory layout of basic data structures like 2d and
3d arrays and allow the transparent utilization of special hardware
load and store operations. Such data structures are used in LAMMPS to
store atom coordinates or forces or neighbor lists. The layout is
chosen to optimize performance on different platforms. Again this
functionality is hidden from the developer, and does not affect how
the kernel is coded.
These abstractions are set at build time, when LAMMPS is compiled with
the KOKKOS package installed. All Kokkos operations occur within the
context of an individual MPI task running on a single node of the
machine. The total number of MPI tasks used by LAMMPS (one or
multiple per compute node) is set in the usual manner via the mpirun
or mpiexec commands, and is independent of Kokkos.
Kokkos currently provides support for 3 modes of execution (per MPI
task). These are OpenMP (for many-core CPUs), Cuda (for NVIDIA GPUs),
and OpenMP (for Intel Phi). Note that the KOKKOS package supports
running on the Phi in native mode, not offload mode like the
USER-INTEL package supports. You choose the mode at build time to
produce an executable compatible with specific hardware.
Here is a quick overview of how to use the KOKKOS package
for CPU acceleration, assuming one or more 16-core nodes.
More details follow.
use a C++11 compatible compiler
make yes-kokkos
make mpi KOKKOS_DEVICES=OpenMP # build with the KOKKOS package
make kokkos_omp # or Makefile.kokkos_omp already has variable set
Make.py -v -p kokkos -kokkos omp -o mpi -a file mpi # or one-line build via Make.py :pre
mpirun -np 16 lmp_mpi -k on -sf kk -in in.lj # 1 node, 16 MPI tasks/node, no threads
mpirun -np 2 -ppn 1 lmp_mpi -k on t 16 -sf kk -in in.lj # 2 nodes, 1 MPI task/node, 16 threads/task
mpirun -np 2 lmp_mpi -k on t 8 -sf kk -in in.lj # 1 node, 2 MPI tasks/node, 8 threads/task
mpirun -np 32 -ppn 4 lmp_mpi -k on t 4 -sf kk -in in.lj # 8 nodes, 4 MPI tasks/node, 4 threads/task :pre
specify variables and settings in your Makefile.machine that enable OpenMP, GPU, or Phi support
include the KOKKOS package and build LAMMPS
enable the KOKKOS package and its hardware options via the "-k on" command-line switch use KOKKOS styles in your input script :ul
Here is a quick overview of how to use the KOKKOS package for GPUs,
assuming one or more nodes, each with 16 cores and a GPU. More
details follow.
discuss use of NVCC, which Makefiles to examine
use a C++11 compatible compiler
KOKKOS_DEVICES = Cuda, OpenMP
KOKKOS_ARCH = Kepler35
make yes-kokkos
make machine
Make.py -p kokkos -kokkos cuda arch=31 -o kokkos_cuda -a file kokkos_cuda :pre
mpirun -np 1 lmp_cuda -k on t 6 -sf kk -in in.lj # one MPI task, 6 threads on CPU
mpirun -np 4 -ppn 1 lmp_cuda -k on t 6 -sf kk -in in.lj # ditto on 4 nodes :pre
mpirun -np 2 lmp_cuda -k on t 8 g 2 -sf kk -in in.lj # two MPI tasks, 8 threads per CPU
mpirun -np 32 -ppn 2 lmp_cuda -k on t 8 g 2 -sf kk -in in.lj # ditto on 16 nodes :pre
Here is a quick overview of how to use the KOKKOS package
for the Intel Phi:
use a C++11 compatible compiler
KOKKOS_DEVICES = OpenMP
KOKKOS_ARCH = KNC
make yes-kokkos
make machine
Make.py -p kokkos -kokkos phi -o kokkos_phi -a file mpi :pre
host=MIC, Intel Phi with 61 cores (240 threads/phi via 4x hardware threading):
mpirun -np 1 lmp_g++ -k on t 240 -sf kk -in in.lj # 1 MPI task on 1 Phi, 1*240 = 240
mpirun -np 30 lmp_g++ -k on t 8 -sf kk -in in.lj # 30 MPI tasks on 1 Phi, 30*8 = 240
mpirun -np 12 lmp_g++ -k on t 20 -sf kk -in in.lj # 12 MPI tasks on 1 Phi, 12*20 = 240
mpirun -np 96 -ppn 12 lmp_g++ -k on t 20 -sf kk -in in.lj # ditto on 8 Phis :pre
[Required hardware/software:]
Kokkos support within LAMMPS must be built with a C++11 compatible
compiler. If using gcc, version 4.7.2 or later is required.
To build with Kokkos support for CPUs, your compiler must support the
OpenMP interface. You should have one or more multi-core CPUs so that
multiple threads can be launched by each MPI task running on a CPU.
To build with Kokkos support for NVIDIA GPUs, NVIDIA Cuda software
version 7.5 or later must be installed on your system. See the
discussion for the "GPU"_accelerate_gpu.html package for details of
how to check and do this.
NOTE: For good performance of the KOKKOS package on GPUs, you must
have Kepler generation GPUs (or later). The Kokkos library exploits
texture cache options not supported by Telsa generation GPUs (or
older).
To build with Kokkos support for Intel Xeon Phi coprocessors, your
sysmte must be configured to use them in "native" mode, not "offload"
mode like the USER-INTEL package supports.
[Building LAMMPS with the KOKKOS package:]
You must choose at build time whether to build for CPUs (OpenMP),
GPUs, or Phi.
You can do any of these in one line, using the src/Make.py script,
-described in "Section 2.4"_Section_start.html#start_4 of the manual.
+described in "Section 4"_Section_packages.html of the manual.
Type "Make.py -h" for help. If run from the src directory, these
commands will create src/lmp_kokkos_omp, lmp_kokkos_cuda, and
lmp_kokkos_phi. Note that the OMP and PHI options use
src/MAKE/Makefile.mpi as the starting Makefile.machine. The CUDA
option uses src/MAKE/OPTIONS/Makefile.kokkos_cuda.
The latter two steps can be done using the "-k on", "-pk kokkos" and
-"-sf kk" "command-line switches"_Section_start.html#start_7
+"-sf kk" "command-line switches"_Section_start.html#start_6
respectively. Or the effect of the "-pk" or "-sf" switches can be
duplicated by adding the "package kokkos"_package.html or "suffix
kk"_suffix.html commands respectively to your input script.
Or you can follow these steps:
CPU-only (run all-MPI or with OpenMP threading):
cd lammps/src
make yes-kokkos
make kokkos_omp :pre
CPU-only (only MPI, no threading):
cd lammps/src
make yes-kokkos
make kokkos_mpi :pre
Intel Xeon Phi (Intel Compiler, Intel MPI):
cd lammps/src
make yes-kokkos
make kokkos_phi :pre
CPUs and GPUs (with MPICH):
cd lammps/src
make yes-kokkos
make kokkos_cuda_mpich :pre
These examples set the KOKKOS-specific OMP, MIC, CUDA variables on the
make command line which requires a GNU-compatible make command. Try
"gmake" if your system's standard make complains.
NOTE: If you build using make line variables and re-build LAMMPS twice
with different KOKKOS options and the *same* target, e.g. g++ in the
first two examples above, then you *must* perform a "make clean-all"
or "make clean-machine" before each build. This is to force all the
KOKKOS-dependent files to be re-compiled with the new options.
NOTE: Currently, there are no precision options with the KOKKOS
package. All compilation and computation is performed in double
precision.
There are other allowed options when building with the KOKKOS package.
As above, they can be set either as variables on the make command line
or in Makefile.machine. This is the full list of options, including
those discussed above, Each takes a value shown below. The
default value is listed, which is set in the
lib/kokkos/Makefile.kokkos file.
#Default settings specific options
#Options: force_uvm,use_ldg,rdc
KOKKOS_DEVICES, values = {OpenMP}, {Serial}, {Pthreads}, {Cuda}, default = {OpenMP}
KOKKOS_ARCH, values = {KNC}, {SNB}, {HSW}, {Kepler}, {Kepler30}, {Kepler32}, {Kepler35}, {Kepler37}, {Maxwell}, {Maxwell50}, {Maxwell52}, {Maxwell53}, {ARMv8}, {BGQ}, {Power7}, {Power8}, default = {none}
KOKKOS_DEBUG, values = {yes}, {no}, default = {no}
KOKKOS_USE_TPLS, values = {hwloc}, {librt}, default = {none}
KOKKOS_CUDA_OPTIONS, values = {force_uvm}, {use_ldg}, {rdc} :ul
KOKKOS_DEVICE sets the parallelization method used for Kokkos code
(within LAMMPS). KOKKOS_DEVICES=OpenMP means that OpenMP will be
used. KOKKOS_DEVICES=Pthreads means that pthreads will be used.
KOKKOS_DEVICES=Cuda means an NVIDIA GPU running CUDA will be used.
If KOKKOS_DEVICES=Cuda, then the lo-level Makefile in the src/MAKE
directory must use "nvcc" as its compiler, via its CC setting. For
best performance its CCFLAGS setting should use -O3 and have a
KOKKOS_ARCH setting that matches the compute capability of your NVIDIA
hardware and software installation, e.g. KOKKOS_ARCH=Kepler30. Note
the minimal required compute capability is 2.0, but this will give
significantly reduced performance compared to Kepler generation GPUs
with compute capability 3.x. For the LINK setting, "nvcc" should not
be used; instead use g++ or another compiler suitable for linking C++
applications. Often you will want to use your MPI compiler wrapper
for this setting (i.e. mpicxx). Finally, the lo-level Makefile must
also have a "Compilation rule" for creating *.o files from *.cu files.
See src/Makefile.cuda for an example of a lo-level Makefile with all
of these settings.
KOKKOS_USE_TPLS=hwloc binds threads to hardware cores, so they do not
migrate during a simulation. KOKKOS_USE_TPLS=hwloc should always be
used if running with KOKKOS_DEVICES=Pthreads for pthreads. It is not
necessary for KOKKOS_DEVICES=OpenMP for OpenMP, because OpenMP
provides alternative methods via environment variables for binding
threads to hardware cores. More info on binding threads to cores is
given in "Section 5.3"_Section_accelerate.html#acc_3.
KOKKOS_ARCH=KNC enables compiler switches needed when compiling for an
Intel Phi processor.
KOKKOS_USE_TPLS=librt enables use of a more accurate timer mechanism
on most Unix platforms. This library is not available on all
platforms.
KOKKOS_DEBUG is only useful when developing a Kokkos-enabled style
within LAMMPS. KOKKOS_DEBUG=yes enables printing of run-time
debugging information that can be useful. It also enables runtime
bounds checking on Kokkos data structures.
KOKKOS_CUDA_OPTIONS are additional options for CUDA.
For more information on Kokkos see the Kokkos programmers' guide here:
/lib/kokkos/doc/Kokkos_PG.pdf.
[Run with the KOKKOS package from the command line:]
The mpirun or mpiexec command sets the total number of MPI tasks used
by LAMMPS (one or multiple per compute node) and the number of MPI
tasks used per node. E.g. the mpirun command in MPICH does this via
its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode.
When using KOKKOS built with host=OMP, you need to choose how many
OpenMP threads per MPI task will be used (via the "-k" command-line
switch discussed below). Note that the product of MPI tasks * OpenMP
threads/task should not exceed the physical number of cores (on a
node), otherwise performance will suffer.
When using the KOKKOS package built with device=CUDA, you must use
exactly one MPI task per physical GPU.
When using the KOKKOS package built with host=MIC for Intel Xeon Phi
coprocessor support you need to insure there are one or more MPI tasks
per coprocessor, and choose the number of coprocessor threads to use
per MPI task (via the "-k" command-line switch discussed below). The
product of MPI tasks * coprocessor threads/task should not exceed the
maximum number of threads the coprocessor is designed to run,
otherwise performance will suffer. This value is 240 for current
generation Xeon Phi(TM) chips, which is 60 physical cores * 4
threads/core. Note that with the KOKKOS package you do not need to
specify how many Phi coprocessors there are per node; each
coprocessors is simply treated as running some number of MPI tasks.
You must use the "-k on" "command-line
-switch"_Section_start.html#start_7 to enable the KOKKOS package. It
+switch"_Section_start.html#start_6 to enable the KOKKOS package. It
takes additional arguments for hardware settings appropriate to your
system. Those arguments are "documented
-here"_Section_start.html#start_7. The two most commonly used
+here"_Section_start.html#start_6. The two most commonly used
options are:
-k on t Nt g Ng :pre
The "t Nt" option applies to host=OMP (even if device=CUDA) and
host=MIC. For host=OMP, it specifies how many OpenMP threads per MPI
task to use with a node. For host=MIC, it specifies how many Xeon Phi
threads per MPI task to use within a node. The default is Nt = 1.
Note that for host=OMP this is effectively MPI-only mode which may be
fine. But for host=MIC you will typically end up using far less than
all the 240 available threads, which could give very poor performance.
The "g Ng" option applies to device=CUDA. It specifies how many GPUs
per compute node to use. The default is 1, so this only needs to be
specified is you have 2 or more GPUs per compute node.
The "-k on" switch also issues a "package kokkos" command (with no
additional arguments) which sets various KOKKOS options to default
values, as discussed on the "package"_package.html command doc page.
-Use the "-sf kk" "command-line switch"_Section_start.html#start_7,
+Use the "-sf kk" "command-line switch"_Section_start.html#start_6,
which will automatically append "kk" to styles that support it. Use
-the "-pk kokkos" "command-line switch"_Section_start.html#start_7 if
+the "-pk kokkos" "command-line switch"_Section_start.html#start_6 if
you wish to change any of the default "package kokkos"_package.html
optionns set by the "-k on" "command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
Note that the default for the "package kokkos"_package.html command is
to use "full" neighbor lists and set the Newton flag to "off" for both
pairwise and bonded interactions. This typically gives fastest
performance. If the "newton"_newton.html command is used in the input
script, it can override the Newton flag defaults.
However, when running in MPI-only mode with 1 thread per MPI task, it
will typically be faster to use "half" neighbor lists and set the
Newton flag to "on", just as is the case for non-accelerated pair
styles. You can do this with the "-pk" "command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
[Or run with the KOKKOS package by editing an input script:]
The discussion above for the mpirun/mpiexec command and setting
appropriate thread and GPU values for host=OMP or host=MIC or
device=CUDA are the same.
You must still use the "-k on" "command-line
-switch"_Section_start.html#start_7 to enable the KOKKOS package, and
+switch"_Section_start.html#start_6 to enable the KOKKOS package, and
specify its additional arguments for hardware options appropriate to
your system, as documented above.
Use the "suffix kk"_suffix.html command, or you can explicitly add a
"kk" suffix to individual styles in your input script, e.g.
pair_style lj/cut/kk 2.5 :pre
You only need to use the "package kokkos"_package.html command if you
wish to change any of its option defaults, as set by the "-k on"
-"command-line switch"_Section_start.html#start_7.
+"command-line switch"_Section_start.html#start_6.
[Speed-ups to expect:]
The performance of KOKKOS running in different modes is a function of
your hardware, which KOKKOS-enable styles are used, and the problem
size.
Generally speaking, the following rules of thumb apply:
When running on CPUs only, with a single thread per MPI task,
performance of a KOKKOS style is somewhere between the standard
(un-accelerated) styles (MPI-only mode), and those provided by the
USER-OMP package. However the difference between all 3 is small (less
than 20%). :ulb,l
When running on CPUs only, with multiple threads per MPI task,
performance of a KOKKOS style is a bit slower than the USER-OMP
package. :l
When running large number of atoms per GPU, KOKKOS is typically faster
than the GPU package. :l
When running on Intel Xeon Phi, KOKKOS is not as fast as
the USER-INTEL package, which is optimized for that hardware. :l
:ule
See the "Benchmark page"_http://lammps.sandia.gov/bench.html of the
LAMMPS web site for performance of the KOKKOS package on different
hardware.
[Guidelines for best performance:]
Here are guidline for using the KOKKOS package on the different
hardware configurations listed above.
Many of the guidelines use the "package kokkos"_package.html command
See its doc page for details and default settings. Experimenting with
its options can provide a speed-up for specific calculations.
[Running on a multi-core CPU:]
If N is the number of physical cores/node, then the number of MPI
tasks/node * number of threads/task should not exceed N, and should
typically equal N. Note that the default threads/task is 1, as set by
the "t" keyword of the "-k" "command-line
-switch"_Section_start.html#start_7. If you do not change this, no
+switch"_Section_start.html#start_6. If you do not change this, no
additional parallelism (beyond MPI) will be invoked on the host
CPU(s).
You can compare the performance running in different modes:
run with 1 MPI task/node and N threads/task
run with N MPI tasks/node and 1 thread/task
run with settings in between these extremes :ul
Examples of mpirun commands in these modes are shown above.
When using KOKKOS to perform multi-threading, it is important for
performance to bind both MPI tasks to physical cores, and threads to
physical cores, so they do not migrate during a simulation.
If you are not certain MPI tasks are being bound (check the defaults
for your MPI installation), binding can be forced with these flags:
OpenMPI 1.8: mpirun -np 2 -bind-to socket -map-by socket ./lmp_openmpi ...
Mvapich2 2.0: mpiexec -np 2 -bind-to socket -map-by socket ./lmp_mvapich ... :pre
For binding threads with the KOKKOS OMP option, use thread affinity
environment variables to force binding. With OpenMP 3.1 (gcc 4.7 or
later, intel 12 or later) setting the environment variable
OMP_PROC_BIND=true should be sufficient. For binding threads with the
KOKKOS pthreads option, compile LAMMPS the KOKKOS HWLOC=yes option
(see "this section"_Section_packages.html#KOKKOS of the manual for
details).
[Running on GPUs:]
Insure the -arch setting in the machine makefile you are using,
e.g. src/MAKE/Makefile.cuda, is correct for your GPU hardware/software.
(see "this section"_Section_packages.html#KOKKOS of the manual for
details).
The -np setting of the mpirun command should set the number of MPI
tasks/node to be equal to the # of physical GPUs on the node.
-Use the "-k" "command-line switch"_Section_commands.html#start_7 to
+Use the "-k" "command-line switch"_Section_commands.html#start_6 to
specify the number of GPUs per node, and the number of threads per MPI
task. As above for multi-core CPUs (and no GPU), if N is the number
of physical cores/node, then the number of MPI tasks/node * number of
threads/task should not exceed N. With one GPU (and one MPI task) it
may be faster to use less than all the available cores, by setting
threads/task to a smaller value. This is because using all the cores
on a dual-socket node will incur extra cost to copy memory from the
2nd socket to the GPU.
Examples of mpirun commands that follow these rules are shown above.
NOTE: When using a GPU, you will achieve the best performance if your
input script does not use any fix or compute styles which are not yet
Kokkos-enabled. This allows data to stay on the GPU for multiple
timesteps, without being copied back to the host CPU. Invoking a
non-Kokkos fix or compute, or performing I/O for
"thermo"_thermo_style.html or "dump"_dump.html output will cause data
to be copied back to the CPU.
You cannot yet assign multiple MPI tasks to the same GPU with the
KOKKOS package. We plan to support this in the future, similar to the
GPU package in LAMMPS.
You cannot yet use both the host (multi-threaded) and device (GPU)
together to compute pairwise interactions with the KOKKOS package. We
hope to support this in the future, similar to the GPU package in
LAMMPS.
[Running on an Intel Phi:]
Kokkos only uses Intel Phi processors in their "native" mode, i.e.
not hosted by a CPU.
As illustrated above, build LAMMPS with OMP=yes (the default) and
MIC=yes. The latter insures code is correctly compiled for the Intel
Phi. The OMP setting means OpenMP will be used for parallelization on
the Phi, which is currently the best option within Kokkos. In the
future, other options may be added.
Current-generation Intel Phi chips have either 61 or 57 cores. One
core should be excluded for running the OS, leaving 60 or 56 cores.
Each core is hyperthreaded, so there are effectively N = 240 (4*60) or
N = 224 (4*56) cores to run on.
The -np setting of the mpirun command sets the number of MPI
tasks/node. The "-k on t Nt" command-line switch sets the number of
threads/task as Nt. The product of these 2 values should be N, i.e.
240 or 224. Also, the number of threads/task should be a multiple of
4 so that logical threads from more than one MPI task do not run on
the same physical core.
Examples of mpirun commands that follow these rules are shown above.
[Restrictions:]
As noted above, if using GPUs, the number of MPI tasks per compute
node should equal to the number of GPUs per compute node. In the
future Kokkos will support assigning multiple MPI tasks to a single
GPU.
Currently Kokkos does not support AMD GPUs due to limits in the
available backend programming models. Specifically, Kokkos requires
extensive C++ support from the Kernel language. This is expected to
change in the future.
diff --git a/doc/src/accelerate_omp.txt b/doc/src/accelerate_omp.txt
index c8dd34386..81b7a5adc 100644
--- a/doc/src/accelerate_omp.txt
+++ b/doc/src/accelerate_omp.txt
@@ -1,187 +1,187 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
"Return to Section 5 overview"_Section_accelerate.html
5.3.4 USER-OMP package :h5
The USER-OMP package was developed by Axel Kohlmeyer at Temple
University. It provides multi-threaded versions of most pair styles,
nearly all bonded styles (bond, angle, dihedral, improper), several
Kspace styles, and a few fix styles. The package currently uses the
OpenMP interface for multi-threading.
Here is a quick overview of how to use the USER-OMP package, assuming
one or more 16-core nodes. More details follow.
use -fopenmp with CCFLAGS and LINKFLAGS in Makefile.machine
make yes-user-omp
make mpi # build with USER-OMP package, if settings added to Makefile.mpi
make omp # or Makefile.omp already has settings
Make.py -v -p omp -o mpi -a file mpi # or one-line build via Make.py :pre
lmp_mpi -sf omp -pk omp 16 < in.script # 1 MPI task, 16 threads
mpirun -np 4 lmp_mpi -sf omp -pk omp 4 -in in.script # 4 MPI tasks, 4 threads/task
mpirun -np 32 -ppn 4 lmp_mpi -sf omp -pk omp 4 -in in.script # 8 nodes, 4 MPI tasks/node, 4 threads/task :pre
[Required hardware/software:]
Your compiler must support the OpenMP interface. You should have one
or more multi-core CPUs so that multiple threads can be launched by
each MPI task running on a CPU.
[Building LAMMPS with the USER-OMP package:]
The lines above illustrate how to include/build with the USER-OMP
package in two steps, using the "make" command. Or how to do it with
one command via the src/Make.py script, described in "Section
-2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for
+4"_Section_packages.html of the manual. Type "Make.py -h" for
help.
Note that the CCFLAGS and LINKFLAGS settings in Makefile.machine must
include "-fopenmp". Likewise, if you use an Intel compiler, the
CCFLAGS setting must include "-restrict". The Make.py command will
add these automatically.
[Run with the USER-OMP package from the command line:]
The mpirun or mpiexec command sets the total number of MPI tasks used
by LAMMPS (one or multiple per compute node) and the number of MPI
tasks used per node. E.g. the mpirun command in MPICH does this via
its -np and -ppn switches. Ditto for OpenMPI via -np and -npernode.
You need to choose how many OpenMP threads per MPI task will be used
by the USER-OMP package. Note that the product of MPI tasks *
threads/task should not exceed the physical number of cores (on a
node), otherwise performance will suffer.
As in the lines above, use the "-sf omp" "command-line
-switch"_Section_start.html#start_7, which will automatically append
+switch"_Section_start.html#start_6, which will automatically append
"omp" to styles that support it. The "-sf omp" switch also issues a
default "package omp 0"_package.html command, which will set the
number of threads per MPI task via the OMP_NUM_THREADS environment
variable.
You can also use the "-pk omp Nt" "command-line
-switch"_Section_start.html#start_7, to explicitly set Nt = # of OpenMP
+switch"_Section_start.html#start_6, to explicitly set Nt = # of OpenMP
threads per MPI task to use, as well as additional options. Its
syntax is the same as the "package omp"_package.html command whose doc
page gives details, including the default values used if it is not
specified. It also gives more details on how to set the number of
threads via the OMP_NUM_THREADS environment variable.
[Or run with the USER-OMP package by editing an input script:]
The discussion above for the mpirun/mpiexec command, MPI tasks/node,
and threads/MPI task is the same.
Use the "suffix omp"_suffix.html command, or you can explicitly add an
"omp" suffix to individual styles in your input script, e.g.
pair_style lj/cut/omp 2.5 :pre
You must also use the "package omp"_package.html command to enable the
USER-OMP package. When you do this you also specify how many threads
per MPI task to use. The command doc page explains other options and
how to set the number of threads via the OMP_NUM_THREADS environment
variable.
[Speed-ups to expect:]
Depending on which styles are accelerated, you should look for a
reduction in the "Pair time", "Bond time", "KSpace time", and "Loop
time" values printed at the end of a run.
You may see a small performance advantage (5 to 20%) when running a
USER-OMP style (in serial or parallel) with a single thread per MPI
task, versus running standard LAMMPS with its standard un-accelerated
styles (in serial or all-MPI parallelization with 1 task/core). This
is because many of the USER-OMP styles contain similar optimizations
to those used in the OPT package, described in "Section
5.3.5"_accelerate_opt.html.
With multiple threads/task, the optimal choice of number of MPI
tasks/node and OpenMP threads/task can vary a lot and should always be
tested via benchmark runs for a specific simulation running on a
specific machine, paying attention to guidelines discussed in the next
sub-section.
A description of the multi-threading strategy used in the USER-OMP
package and some performance examples are "presented
here"_http://sites.google.com/site/akohlmey/software/lammps-icms/lammps-icms-tms2011-talk.pdf?attredirects=0&d=1
[Guidelines for best performance:]
For many problems on current generation CPUs, running the USER-OMP
package with a single thread/task is faster than running with multiple
threads/task. This is because the MPI parallelization in LAMMPS is
often more efficient than multi-threading as implemented in the
USER-OMP package. The parallel efficiency (in a threaded sense) also
varies for different USER-OMP styles.
Using multiple threads/task can be more effective under the following
circumstances:
Individual compute nodes have a significant number of CPU cores but
the CPU itself has limited memory bandwidth, e.g. for Intel Xeon 53xx
(Clovertown) and 54xx (Harpertown) quad-core processors. Running one
MPI task per CPU core will result in significant performance
degradation, so that running with 4 or even only 2 MPI tasks per node
is faster. Running in hybrid MPI+OpenMP mode will reduce the
inter-node communication bandwidth contention in the same way, but
offers an additional speedup by utilizing the otherwise idle CPU
cores. :ulb,l
The interconnect used for MPI communication does not provide
sufficient bandwidth for a large number of MPI tasks per node. For
example, this applies to running over gigabit ethernet or on Cray XT4
or XT5 series supercomputers. As in the aforementioned case, this
effect worsens when using an increasing number of nodes. :l
The system has a spatially inhomogeneous particle density which does
not map well to the "domain decomposition scheme"_processors.html or
"load-balancing"_balance.html options that LAMMPS provides. This is
because multi-threading achives parallelism over the number of
particles, not via their distribution in space. :l
A machine is being used in "capability mode", i.e. near the point
where MPI parallelism is maxed out. For example, this can happen when
using the "PPPM solver"_kspace_style.html for long-range
electrostatics on large numbers of nodes. The scaling of the KSpace
calculation (see the "kspace_style"_kspace_style.html command) becomes
the performance-limiting factor. Using multi-threading allows less
MPI tasks to be invoked and can speed-up the long-range solver, while
increasing overall performance by parallelizing the pairwise and
bonded calculations via OpenMP. Likewise additional speedup can be
sometimes be achived by increasing the length of the Coulombic cutoff
and thus reducing the work done by the long-range solver. Using the
"run_style verlet/split"_run_style.html command, which is compatible
with the USER-OMP package, is an alternative way to reduce the number
of MPI tasks assigned to the KSpace calculation. :l
:ule
Additional performance tips are as follows:
The best parallel efficiency from {omp} styles is typically achieved
when there is at least one MPI task per physical CPU chip, i.e. socket
or die. :ulb,l
It is usually most efficient to restrict threading to a single
socket, i.e. use one or more MPI task per socket. :l
NOTE: By default, several current MPI implementations use a processor
affinity setting that restricts each MPI task to a single CPU core.
Using multi-threading in this mode will force all threads to share the
one core and thus is likely to be counterproductive. Instead, binding
MPI tasks to a (multi-core) socket, should solve this issue. :l
:ule
[Restrictions:]
None.
diff --git a/doc/src/accelerate_opt.txt b/doc/src/accelerate_opt.txt
index 704321ca0..5a2a5eac0 100644
--- a/doc/src/accelerate_opt.txt
+++ b/doc/src/accelerate_opt.txt
@@ -1,71 +1,71 @@
"Previous Section"_Section_packages.html - "LAMMPS WWW Site"_lws -
"LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
"Return to Section accelerate overview"_Section_accelerate.html
5.3.5 OPT package :h5
The OPT package was developed by James Fischer (High Performance
Technologies), David Richie, and Vincent Natoli (Stone Ridge
Technologies). It contains a handful of pair styles whose compute()
methods were rewritten in C++ templated form to reduce the overhead
due to if tests and other conditional code.
Here is a quick overview of how to use the OPT package. More details
follow.
make yes-opt
make mpi # build with the OPT package
Make.py -v -p opt -o mpi -a file mpi # or one-line build via Make.py :pre
lmp_mpi -sf opt -in in.script # run in serial
mpirun -np 4 lmp_mpi -sf opt -in in.script # run in parallel :pre
[Required hardware/software:]
None.
[Building LAMMPS with the OPT package:]
The lines above illustrate how to build LAMMPS with the OPT package in
two steps, using the "make" command. Or how to do it with one command
via the src/Make.py script, described in "Section
-2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for
+4"_Section_packages.html of the manual. Type "Make.py -h" for
help.
Note that if you use an Intel compiler to build with the OPT package,
the CCFLAGS setting in your Makefile.machine must include "-restrict".
The Make.py command will add this automatically.
[Run with the OPT package from the command line:]
As in the lines above, use the "-sf opt" "command-line
-switch"_Section_start.html#start_7, which will automatically append
+switch"_Section_start.html#start_6, which will automatically append
"opt" to styles that support it.
[Or run with the OPT package by editing an input script:]
Use the "suffix opt"_suffix.html command, or you can explicitly add an
"opt" suffix to individual styles in your input script, e.g.
pair_style lj/cut/opt 2.5 :pre
[Speed-ups to expect:]
You should see a reduction in the "Pair time" value printed at the end
of a run. On most machines for reasonable problem sizes, it will be a
5 to 20% savings.
[Guidelines for best performance:]
Just try out an OPT pair style to see how it performs.
[Restrictions:]
None.
diff --git a/doc/src/angle_charmm.txt b/doc/src/angle_charmm.txt
index a02e60425..7ff7ef8fd 100644
--- a/doc/src/angle_charmm.txt
+++ b/doc/src/angle_charmm.txt
@@ -1,90 +1,90 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style charmm command :h3
angle_style charmm/intel command :h3
angle_style charmm/kk command :h3
angle_style charmm/omp command :h3
[Syntax:]
angle_style charmm :pre
[Examples:]
angle_style charmm
angle_coeff 1 300.0 107.0 50.0 3.0 :pre
[Description:]
The {charmm} angle style uses the potential
:c,image(Eqs/angle_charmm.jpg)
with an additional Urey_Bradley term based on the distance {r} between
the 1st and 3rd atoms in the angle. K, theta0, Kub, and Rub are
coefficients defined for each angle type.
See "(MacKerell)"_#angle-MacKerell for a description of the CHARMM force
field.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/radian^2)
theta0 (degrees)
K_ub (energy/distance^2)
r_ub (distance) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of K are in energy/radian^2.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
:line
:link(angle-MacKerell)
[(MacKerell)] MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field,
Fischer, Gao, Guo, Ha, et al, J Phys Chem, 102, 3586 (1998).
diff --git a/doc/src/angle_class2.txt b/doc/src/angle_class2.txt
index 74f2544cd..71a508d69 100644
--- a/doc/src/angle_class2.txt
+++ b/doc/src/angle_class2.txt
@@ -1,120 +1,120 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style class2 command :h3
angle_style class2/omp command :h3
angle_style class2/kk command :h3
[Syntax:]
angle_style class2 :pre
[Examples:]
angle_style class2
angle_coeff * 75.0
angle_coeff 1 bb 10.5872 1.0119 1.5228
angle_coeff * ba 3.6551 24.895 1.0119 1.5228 :pre
[Description:]
The {class2} angle style uses the potential
:c,image(Eqs/angle_class2.jpg)
where Ea is the angle term, Ebb is a bond-bond term, and Eba is a
bond-angle term. Theta0 is the equilibrium angle and r1 and r2 are
the equilibrium bond lengths.
See "(Sun)"_#angle-Sun for a description of the COMPASS class2 force field.
Coefficients for the Ea, Ebb, and Eba formulas must be defined for
each angle type via the "angle_coeff"_angle_coeff.html command as in
the example above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands.
These are the 4 coefficients for the Ea formula:
theta0 (degrees)
K2 (energy/radian^2)
K3 (energy/radian^3)
K4 (energy/radian^4) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of the various K are in per-radian.
For the Ebb formula, each line in a "angle_coeff"_angle_coeff.html
command in the input script lists 4 coefficients, the first of which
is "bb" to indicate they are BondBond coefficients. In a data file,
these coefficients should be listed under a "BondBond Coeffs" heading
and you must leave out the "bb", i.e. only list 3 coefficients after
the angle type.
bb
M (energy/distance^2)
r1 (distance)
r2 (distance) :ul
For the Eba formula, each line in a "angle_coeff"_angle_coeff.html
command in the input script lists 5 coefficients, the first of which
is "ba" to indicate they are BondAngle coefficients. In a data file,
these coefficients should be listed under a "BondAngle Coeffs" heading
and you must leave out the "ba", i.e. only list 4 coefficients after
the angle type.
ba
N1 (energy/distance^2)
N2 (energy/distance^2)
r1 (distance)
r2 (distance) :ul
The theta0 value in the Eba formula is not specified, since it is the
same value from the Ea formula.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the CLASS2
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
:line
:link(angle-Sun)
[(Sun)] Sun, J Phys Chem B 102, 7338-7364 (1998).
diff --git a/doc/src/angle_cosine.txt b/doc/src/angle_cosine.txt
index 4fb2ccaf7..c0ce3c930 100644
--- a/doc/src/angle_cosine.txt
+++ b/doc/src/angle_cosine.txt
@@ -1,71 +1,71 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine command :h3
angle_style cosine/omp command :h3
[Syntax:]
angle_style cosine :pre
[Examples:]
angle_style cosine
angle_coeff * 75.0 :pre
[Description:]
The {cosine} angle style uses the potential
:c,image(Eqs/angle_cosine.jpg)
where K is defined for each angle type.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_cosine_delta.txt b/doc/src/angle_cosine_delta.txt
index 6ab214508..830fd6db5 100644
--- a/doc/src/angle_cosine_delta.txt
+++ b/doc/src/angle_cosine_delta.txt
@@ -1,77 +1,77 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine/delta command :h3
angle_style cosine/delta/omp command :h3
[Syntax:]
angle_style cosine/delta :pre
[Examples:]
angle_style cosine/delta
angle_coeff 2*4 75.0 100.0 :pre
[Description:]
The {cosine/delta} angle style uses the potential
:c,image(Eqs/angle_cosine_delta.jpg)
where theta0 is the equilibrium value of the angle, and K is a
prefactor. Note that the usual 1/2 factor is included in K.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
theta0 (degrees) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html, "angle_style
cosine/squared"_angle_cosine_squared.html
[Default:] none
diff --git a/doc/src/angle_cosine_periodic.txt b/doc/src/angle_cosine_periodic.txt
index c6cd57e41..b5c53b1b0 100644
--- a/doc/src/angle_cosine_periodic.txt
+++ b/doc/src/angle_cosine_periodic.txt
@@ -1,90 +1,90 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine/periodic command :h3
angle_style cosine/periodic/omp command :h3
[Syntax:]
angle_style cosine/periodic :pre
[Examples:]
angle_style cosine/periodic
angle_coeff * 75.0 1 6 :pre
[Description:]
The {cosine/periodic} angle style uses the following potential, which
is commonly used in the "DREIDING"_Section_howto.html#howto_4 force
field, particularly for organometallic systems where {n} = 4 might be
used for an octahedral complex and {n} = 3 might be used for a
trigonal center:
:c,image(Eqs/angle_cosine_periodic.jpg)
where C, B and n are coefficients defined for each angle type.
See "(Mayo)"_#cosine-Mayo for a description of the DREIDING force field
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
C (energy)
B = 1 or -1
n = 1, 2, 3, 4, 5 or 6 for periodicity :ul
Note that the prefactor C is specified and not the overall force
constant K = C / n^2. When B = 1, it leads to a minimum for the
linear geometry. When B = -1, it leads to a maximum for the linear
geometry.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
:line
:link(cosine-Mayo)
[(Mayo)] Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909
(1990).
diff --git a/doc/src/angle_cosine_shift.txt b/doc/src/angle_cosine_shift.txt
index dc1a29a86..6ed9fe215 100644
--- a/doc/src/angle_cosine_shift.txt
+++ b/doc/src/angle_cosine_shift.txt
@@ -1,75 +1,75 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine/shift command :h3
angle_style cosine/shift/omp command :h3
[Syntax:]
angle_style cosine/shift :pre
[Examples:]
angle_style cosine/shift
angle_coeff * 10.0 45.0 :pre
[Description:]
The {cosine/shift} angle style uses the potential
:c,image(Eqs/angle_cosine_shift.jpg)
where theta0 is the equilibrium angle. The potential is bounded
between -Umin and zero. In the neighborhood of the minimum E=- Umin +
Umin/4(theta-theta0)^2 hence the spring constant is umin/2.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
umin (energy)
theta (angle) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html,
"angle_cosine_shift_exp"_angle_cosine_shift_exp.html
[Default:] none
diff --git a/doc/src/angle_cosine_shift_exp.txt b/doc/src/angle_cosine_shift_exp.txt
index 48af5ba76..44a68c108 100644
--- a/doc/src/angle_cosine_shift_exp.txt
+++ b/doc/src/angle_cosine_shift_exp.txt
@@ -1,88 +1,88 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine/shift/exp command :h3
angle_style cosine/shift/exp/omp command :h3
[Syntax:]
angle_style cosine/shift/exp :pre
[Examples:]
angle_style cosine/shift/exp
angle_coeff * 10.0 45.0 2.0 :pre
[Description:]
The {cosine/shift/exp} angle style uses the potential
:c,image(Eqs/angle_cosine_shift_exp.jpg)
where Umin, theta, and a are defined for each angle type.
The potential is bounded between \[-Umin:0\] and the minimum is
located at the angle theta0. The a parameter can be both positive or
negative and is used to control the spring constant at the
equilibrium.
The spring constant is given by k = A exp(A) Umin / \[2 (Exp(a)-1)\].
For a > 3, k/Umin = a/2 to better than 5% relative error. For negative
values of the a parameter, the spring constant is essentially zero,
and anharmonic terms takes over. The potential is furthermore well
behaved in the limit a -> 0, where it has been implemented to linear
order in a for a < 0.001. In this limit the potential reduces to the
cosineshifted potential.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
umin (energy)
theta (angle)
A (real number) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html,
"angle_cosine_shift"_angle_cosine_shift.html,
"dihedral_cosine_shift_exp"_dihedral_cosine_shift_exp.html
[Default:] none
diff --git a/doc/src/angle_cosine_squared.txt b/doc/src/angle_cosine_squared.txt
index 23e1b150a..065cdad54 100644
--- a/doc/src/angle_cosine_squared.txt
+++ b/doc/src/angle_cosine_squared.txt
@@ -1,76 +1,76 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style cosine/squared command :h3
angle_style cosine/squared/omp command :h3
[Syntax:]
angle_style cosine/squared :pre
[Examples:]
angle_style cosine/squared
angle_coeff 2*4 75.0 100.0 :pre
[Description:]
The {cosine/squared} angle style uses the potential
:c,image(Eqs/angle_cosine_squared.jpg)
where theta0 is the equilibrium value of the angle, and K is a
prefactor. Note that the usual 1/2 factor is included in K.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
theta0 (degrees) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_fourier.txt b/doc/src/angle_fourier.txt
index f58ae8e4f..da39e7cf3 100644
--- a/doc/src/angle_fourier.txt
+++ b/doc/src/angle_fourier.txt
@@ -1,72 +1,72 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style fourier command :h3
angle_style fourier/omp command :h3
[Syntax:]
angle_style fourier :pre
[Examples:]
angle_style fourier
angle_coeff 75.0 1.0 1.0 1.0
[Description:]
The {fourier} angle style uses the potential
:c,image(Eqs/angle_fourier.jpg)
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
C0 (real)
C1 (real)
C2 (real) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_fourier_simple.txt b/doc/src/angle_fourier_simple.txt
index 9da8ffed2..5adda6cb3 100644
--- a/doc/src/angle_fourier_simple.txt
+++ b/doc/src/angle_fourier_simple.txt
@@ -1,71 +1,71 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style fourier/simple command :h3
angle_style fourier/simple/omp command :h3
[Syntax:]
angle_style fourier/simple :pre
[Examples:]
angle_style fourier/simple
angle_coeff 100.0 -1.0 1.0
[Description:]
The {fourier/simple} angle style uses the potential
:c,image(Eqs/angle_fourier_simple.jpg)
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
c (real)
n (real) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_harmonic.txt b/doc/src/angle_harmonic.txt
index 12ee80521..4c7476396 100644
--- a/doc/src/angle_harmonic.txt
+++ b/doc/src/angle_harmonic.txt
@@ -1,78 +1,78 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style harmonic command :h3
angle_style harmonic/intel command :h3
angle_style harmonic/kk command :h3
angle_style harmonic/omp command :h3
[Syntax:]
angle_style harmonic :pre
[Examples:]
angle_style harmonic
angle_coeff 1 300.0 107.0 :pre
[Description:]
The {harmonic} angle style uses the potential
:c,image(Eqs/angle_harmonic.jpg)
where theta0 is the equilibrium value of the angle, and K is a
prefactor. Note that the usual 1/2 factor is included in K.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/radian^2)
theta0 (degrees) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of K are in energy/radian^2.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_quartic.txt b/doc/src/angle_quartic.txt
index fea2eb9e0..f7640bdfb 100644
--- a/doc/src/angle_quartic.txt
+++ b/doc/src/angle_quartic.txt
@@ -1,78 +1,78 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style quartic command :h3
angle_style quartic/omp command :h3
[Syntax:]
angle_style quartic :pre
[Examples:]
angle_style quartic
angle_coeff 1 129.1948 56.8726 -25.9442 -14.2221 :pre
[Description:]
The {quartic} angle style uses the potential
:c,image(Eqs/angle_quartic.jpg)
where theta0 is the equilibrium value of the angle, and K is a
prefactor. Note that the usual 1/2 factor is included in K.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
theta0 (degrees)
K2 (energy/radian^2)
K3 (energy/radian^3)
K4 (energy/radian^4) :ul
Theta0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of K are in energy/radian^2.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/angle_table.txt b/doc/src/angle_table.txt
index 61dd7b041..bd6e167bd 100644
--- a/doc/src/angle_table.txt
+++ b/doc/src/angle_table.txt
@@ -1,157 +1,157 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
angle_style table command :h3
angle_style table/omp command :h3
[Syntax:]
angle_style table style N :pre
style = {linear} or {spline} = method of interpolation
N = use N values in table :ul
[Examples:]
angle_style table linear 1000
angle_coeff 3 file.table ENTRY1 :pre
[Description:]
Style {table} creates interpolation tables of length {N} from angle
potential and derivative values listed in a file(s) as a function of
angle The files are read by the "angle_coeff"_angle_coeff.html
command.
The interpolation tables are created by fitting cubic splines to the
file values and interpolating energy and derivative values at each of
{N} angles. During a simulation, these tables are used to interpolate
energy and force values on individual atoms as needed. The
interpolation is done in one of 2 styles: {linear} or {spline}.
For the {linear} style, the angle is used to find 2 surrounding table
values from which an energy or its derivative is computed by linear
interpolation.
For the {spline} style, a cubic spline coefficients are computed and
stored at each of the {N} values in the table. The angle is used to
find the appropriate set of coefficients which are used to evaluate a
cubic polynomial which computes the energy or derivative.
The following coefficients must be defined for each angle type via the
"angle_coeff"_angle_coeff.html command as in the example above.
filename
keyword :ul
The filename specifies a file containing tabulated energy and
derivative values. The keyword specifies a section of the file. The
format of this file is described below.
:line
The format of a tabulated file is as follows (without the
parenthesized comments):
# Angle potential for harmonic (one or more comment or blank lines) :pre
HAM (keyword is the first text on line)
N 181 FP 0 0 EQ 90.0 (N, FP, EQ parameters)
(blank line)
N 181 FP 0 0 (N, FP parameters)
1 0.0 200.5 2.5 (index, angle, energy, derivative)
2 1.0 198.0 2.5
...
181 180.0 0.0 0.0 :pre
A section begins with a non-blank line whose 1st character is not a
"#"; blank lines or lines starting with "#" can be used as comments
between sections. The first line begins with a keyword which
identifies the section. The line can contain additional text, but the
initial text must match the argument specified in the
"angle_coeff"_angle_coeff.html command. The next line lists (in any
order) one or more parameters for the table. Each parameter is a
keyword followed by one or more numeric values.
The parameter "N" is required and its value is the number of table
entries that follow. Note that this may be different than the {N}
specified in the "angle_style table"_angle_style.html command. Let
Ntable = {N} in the angle_style command, and Nfile = "N" in the
tabulated file. What LAMMPS does is a preliminary interpolation by
creating splines using the Nfile tabulated values as nodal points. It
uses these to interpolate as needed to generate energy and derivative
values at Ntable different points. The resulting tables of length
Ntable are then used as described above, when computing energy and
force for individual angles and their atoms. This means that if you
want the interpolation tables of length Ntable to match exactly what
is in the tabulated file (with effectively no preliminary
interpolation), you should set Ntable = Nfile.
The "FP" parameter is optional. If used, it is followed by two values
fplo and fphi, which are the 2nd derivatives at the innermost and
outermost angle settings. These values are needed by the spline
construction routines. If not specified by the "FP" parameter, they
are estimated (less accurately) by the first two and last two
derivative values in the table.
The "EQ" parameter is also optional. If used, it is followed by a the
equilibrium angle value, which is used, for example, by the "fix
shake"_fix_shake.html command. If not used, the equilibrium angle is
set to 180.0.
Following a blank line, the next N lines list the tabulated values.
On each line, the 1st value is the index from 1 to N, the 2nd value is
the angle value (in degrees), the 3rd value is the energy (in energy
units), and the 4th is -dE/d(theta) (also in energy units). The 3rd
term is the energy of the 3-atom configuration for the specified
angle. The last term is the derivative of the energy with respect to
the angle (in degrees, not radians). Thus the units of the last term
are still energy, not force. The angle values must increase from one
line to the next. The angle values must also begin with 0.0 and end
with 180.0, i.e. span the full range of possible angles.
Note that one file can contain many sections, each with a tabulated
potential. LAMMPS reads the file section by section until it finds
one that matches the specified keyword.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"angle_coeff"_angle_coeff.html
[Default:] none
diff --git a/doc/src/balance.txt b/doc/src/balance.txt
index 79728d656..da6f59900 100644
--- a/doc/src/balance.txt
+++ b/doc/src/balance.txt
@@ -1,518 +1,518 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
balance command :h3
[Syntax:]
balance thresh style args ... keyword args ... :pre
thresh = imbalance threshold that must be exceeded to perform a re-balance :ulb,l
one style/arg pair can be used (or multiple for {x},{y},{z}) :l
style = {x} or {y} or {z} or {shift} or {rcb} :l
{x} args = {uniform} or Px-1 numbers between 0 and 1
{uniform} = evenly spaced cuts between processors in x dimension
numbers = Px-1 ascending values between 0 and 1, Px - # of processors in x dimension
{x} can be specified together with {y} or {z}
{y} args = {uniform} or Py-1 numbers between 0 and 1
{uniform} = evenly spaced cuts between processors in y dimension
numbers = Py-1 ascending values between 0 and 1, Py - # of processors in y dimension
{y} can be specified together with {x} or {z}
{z} args = {uniform} or Pz-1 numbers between 0 and 1
{uniform} = evenly spaced cuts between processors in z dimension
numbers = Pz-1 ascending values between 0 and 1, Pz - # of processors in z dimension
{z} can be specified together with {x} or {y}
{shift} args = dimstr Niter stopthresh
dimstr = sequence of letters containing "x" or "y" or "z", each not more than once
Niter = # of times to iterate within each dimension of dimstr sequence
stopthresh = stop balancing when this imbalance threshold is reached
{rcb} args = none :pre
zero or more keyword/arg pairs may be appended :l
keyword = {weight} or {out} :l
{weight} style args = use weighted particle counts for the balancing
{style} = {group} or {neigh} or {time} or {var} or {store}
{group} args = Ngroup group1 weight1 group2 weight2 ...
Ngroup = number of groups with assigned weights
group1, group2, ... = group IDs
weight1, weight2, ... = corresponding weight factors
{neigh} factor = compute weight based on number of neighbors
factor = scaling factor (> 0)
{time} factor = compute weight based on time spend computing
factor = scaling factor (> 0)
{var} name = take weight from atom-style variable
name = name of the atom-style variable
{store} name = store weight in custom atom property defined by "fix property/atom"_fix_property_atom.html command
name = atom property name (without d_ prefix)
{out} arg = filename
filename = write each processor's sub-domain to a file :pre
:ule
[Examples:]
balance 0.9 x uniform y 0.4 0.5 0.6
balance 1.2 shift xz 5 1.1
balance 1.0 shift xz 5 1.1
balance 1.1 rcb
balance 1.0 shift x 10 1.1 weight group 2 fast 0.5 slow 2.0
balance 1.0 shift x 10 1.1 weight time 0.8 weight neigh 0.5 weight store balance
balance 1.0 shift x 20 1.0 out tmp.balance :pre
[Description:]
This command adjusts the size and shape of processor sub-domains
within the simulation box, to attempt to balance the number of atoms
or particles and thus indirectly the computational cost (load) more
evenly across processors. The load balancing is "static" in the sense
that this command performs the balancing once, before or between
simulations. The processor sub-domains will then remain static during
the subsequent run. To perform "dynamic" balancing, see the "fix
balance"_fix_balance.html command, which can adjust processor
sub-domain sizes and shapes on-the-fly during a "run"_run.html.
Load-balancing is typically most useful if the particles in the
simulation box have a spatially-varying density distribution or when
the computational cost varies significantly between different
particles. E.g. a model of a vapor/liquid interface, or a solid with
an irregular-shaped geometry containing void regions, or "hybrid pair
style simulations"_pair_hybrid.html which combine pair styles with
different computational cost. In these cases, the LAMMPS default of
dividing the simulation box volume into a regular-spaced grid of 3d
bricks, with one equal-volume sub-domain per processor, may assign
numbers of particles per processor in a way that the computational
effort varies significantly. This can lead to poor performance when
the simulation is run in parallel.
The balancing can be performed with or without per-particle weighting.
With no weighting, the balancing attempts to assign an equal number of
particles to each processor. With weighting, the balancing attempts
to assign an equal aggregate computational weight to each processor,
which typically induces a different number of atoms assigned to each
processor. Details on the various weighting options and examples for
how they can be used are "given below"_#weighted_balance.
Note that the "processors"_processors.html command allows some control
over how the box volume is split across processors. Specifically, for
a Px by Py by Pz grid of processors, it allows choice of Px, Py, and
Pz, subject to the constraint that Px * Py * Pz = P, the total number
of processors. This is sufficient to achieve good load-balance for
some problems on some processor counts. However, all the processor
sub-domains will still have the same shape and same volume.
The requested load-balancing operation is only performed if the
current "imbalance factor" in particles owned by each processor
exceeds the specified {thresh} parameter. The imbalance factor is
defined as the maximum number of particles (or weight) owned by any
processor, divided by the average number of particles (or weight) per
processor. Thus an imbalance factor of 1.0 is perfect balance.
As an example, for 10000 particles running on 10 processors, if the
most heavily loaded processor has 1200 particles, then the factor is
1.2, meaning there is a 20% imbalance. Note that a re-balance can be
forced even if the current balance is perfect (1.0) be specifying a
{thresh} < 1.0.
NOTE: Balancing is performed even if the imbalance factor does not
exceed the {thresh} parameter if a "grid" style is specified when the
current partitioning is "tiled". The meaning of "grid" vs "tiled" is
explained below. This is to allow forcing of the partitioning to
"grid" so that the "comm_style brick"_comm_style.html command can then
be used to replace a current "comm_style tiled"_comm_style.html
setting.
When the balance command completes, it prints statistics about the
result, including the change in the imbalance factor and the change in
the maximum number of particles on any processor. For "grid" methods
(defined below) that create a logical 3d grid of processors, the
positions of all cutting planes in each of the 3 dimensions (as
fractions of the box length) are also printed.
NOTE: This command attempts to minimize the imbalance factor, as
defined above. But depending on the method a perfect balance (1.0)
may not be achieved. For example, "grid" methods (defined below) that
create a logical 3d grid cannot achieve perfect balance for many
irregular distributions of particles. Likewise, if a portion of the
system is a perfect lattice, e.g. the initial system is generated by
the "create_atoms"_create_atoms.html command, then "grid" methods may
be unable to achieve exact balance. This is because entire lattice
planes will be owned or not owned by a single processor.
NOTE: The imbalance factor is also an estimate of the maximum speed-up
you can hope to achieve by running a perfectly balanced simulation
versus an imbalanced one. In the example above, the 10000 particle
simulation could run up to 20% faster if it were perfectly balanced,
versus when imbalanced. However, computational cost is not strictly
proportional to particle count, and changing the relative size and
shape of processor sub-domains may lead to additional computational
and communication overheads, e.g. in the PPPM solver used via the
"kspace_style"_kspace_style.html command. Thus you should benchmark
the run times of a simulation before and after balancing.
:line
The method used to perform a load balance is specified by one of the
listed styles (or more in the case of {x},{y},{z}), which are
described in detail below. There are 2 kinds of styles.
The {x}, {y}, {z}, and {shift} styles are "grid" methods which produce
a logical 3d grid of processors. They operate by changing the cutting
planes (or lines) between processors in 3d (or 2d), to adjust the
volume (area in 2d) assigned to each processor, as in the following 2d
diagram where processor sub-domains are shown and particles are
colored by the processor that owns them. The leftmost diagram is the
default partitioning of the simulation box across processors (one
sub-box for each of 16 processors); the middle diagram is after a
"grid" method has been applied.
:image(JPG/balance_uniform_small.jpg,JPG/balance_uniform.jpg),image(JPG/balance_nonuniform_small.jpg,JPG/balance_nonuniform.jpg),image(JPG/balance_rcb_small.jpg,JPG/balance_rcb.jpg)
:c
The {rcb} style is a "tiling" method which does not produce a logical
3d grid of processors. Rather it tiles the simulation domain with
rectangular sub-boxes of varying size and shape in an irregular
fashion so as to have equal numbers of particles (or weight) in each
sub-box, as in the rightmost diagram above.
The "grid" methods can be used with either of the
"comm_style"_comm_style.html command options, {brick} or {tiled}. The
"tiling" methods can only be used with "comm_style
tiled"_comm_style.html. Note that it can be useful to use a "grid"
method with "comm_style tiled"_comm_style.html to return the domain
partitioning to a logical 3d grid of processors so that "comm_style
brick" can afterwords be specified for subsequent "run"_run.html
commands.
When a "grid" method is specified, the current domain partitioning can
be either a logical 3d grid or a tiled partitioning. In the former
case, the current logical 3d grid is used as a starting point and
changes are made to improve the imbalance factor. In the latter case,
the tiled partitioning is discarded and a logical 3d grid is created
with uniform spacing in all dimensions. This becomes the starting
point for the balancing operation.
When a "tiling" method is specified, the current domain partitioning
("grid" or "tiled") is ignored, and a new partitioning is computed
from scratch.
:line
The {x}, {y}, and {z} styles invoke a "grid" method for balancing, as
described above. Note that any or all of these 3 styles can be
specified together, one after the other, but they cannot be used with
any other style. This style adjusts the position of cutting planes
between processor sub-domains in specific dimensions. Only the
specified dimensions are altered.
The {uniform} argument spaces the planes evenly, as in the left
diagrams above. The {numeric} argument requires listing Ps-1 numbers
that specify the position of the cutting planes. This requires
knowing Ps = Px or Py or Pz = the number of processors assigned by
LAMMPS to the relevant dimension. This assignment is made (and the
Px, Py, Pz values printed out) when the simulation box is created by
the "create_box" or "read_data" or "read_restart" command and is
influenced by the settings of the "processors"_processors.html
command.
Each of the numeric values must be between 0 and 1, and they must be
listed in ascending order. They represent the fractional position of
the cutting place. The left (or lower) edge of the box is 0.0, and
the right (or upper) edge is 1.0. Neither of these values is
specified. Only the interior Ps-1 positions are specified. Thus is
there are 2 processors in the x dimension, you specify a single value
such as 0.75, which would make the left processor's sub-domain 3x
larger than the right processor's sub-domain.
:line
The {shift} style invokes a "grid" method for balancing, as
described above. It changes the positions of cutting planes between
processors in an iterative fashion, seeking to reduce the imbalance
factor, similar to how the "fix balance shift"_fix_balance.html
command operates.
The {dimstr} argument is a string of characters, each of which must be
an "x" or "y" or "z". Eacn character can appear zero or one time,
since there is no advantage to balancing on a dimension more than
once. You should normally only list dimensions where you expect there
to be a density variation in the particles.
Balancing proceeds by adjusting the cutting planes in each of the
dimensions listed in {dimstr}, one dimension at a time. For a single
dimension, the balancing operation (described below) is iterated on up
to {Niter} times. After each dimension finishes, the imbalance factor
is re-computed, and the balancing operation halts if the {stopthresh}
criterion is met.
A rebalance operation in a single dimension is performed using a
recursive multisectioning algorithm, where the position of each
cutting plane (line in 2d) in the dimension is adjusted independently.
This is similar to a recursive bisectioning for a single value, except
that the bounds used for each bisectioning take advantage of
information from neighboring cuts if possible. At each iteration, the
count of particles on either side of each plane is tallied. If the
counts do not match the target value for the plane, the position of
the cut is adjusted to be halfway between a low and high bound. The
low and high bounds are adjusted on each iteration, using new count
information, so that they become closer together over time. Thus as
the recursion progresses, the count of particles on either side of the
plane gets closer to the target value.
Once the rebalancing is complete and final processor sub-domains
assigned, particles are migrated to their new owning processor, and
the balance procedure ends.
NOTE: At each rebalance operation, the bisectioning for each cutting
plane (line in 2d) typically starts with low and high bounds separated
by the extent of a processor's sub-domain in one dimension. The size
of this bracketing region shrinks by 1/2 every iteration. Thus if
{Niter} is specified as 10, the cutting plane will typically be
positioned to 1 part in 1000 accuracy (relative to the perfect target
position). For {Niter} = 20, it will be accurate to 1 part in a
million. Thus there is no need ot set {Niter} to a large value.
LAMMPS will check if the threshold accuracy is reached (in a
dimension) is less iterations than {Niter} and exit early. However,
{Niter} should also not be set too small, since it will take roughly
the same number of iterations to converge even if the cutting plane is
initially close to the target value.
:line
The {rcb} style invokes a "tiled" method for balancing, as described
above. It performs a recursive coordinate bisectioning (RCB) of the
simulation domain. The basic idea is as follows.
The simulation domain is cut into 2 boxes by an axis-aligned cut in
one of the dimensions, leaving one new sub-box on either side of the
cut. Which dimension is chosen for the cut depends on the particle
(weight) distribution within the parent box. Normally the longest
dimension of the box is cut, but if all (or most) of the particles are
at one end of the box, a cut may be performed in another dimension to
induce sub-boxes that are more cube-ish (3d) or square-ish (2d) in
shape.
After the cut is made, all the processors are also partitioned into 2
groups, half assigned to the box on the lower side of the cut, and
half to the box on the upper side. (If the processor count is odd,
one side gets an extra processor.) The cut is positioned so that the
number of (weighted) particles in the lower box is exactly the number
that the processors assigned to that box should own for load balance
to be perfect. This also makes load balance for the upper box
perfect. The positioning of the cut is done iteratively, by a
bisectioning method (median search). Note that counting particles on
either side of the cut requires communication between all processors
at each iteration.
That is the procedure for the first cut. Subsequent cuts are made
recursively, in exactly the same manner. The subset of processors
assigned to each box make a new cut in one dimension of that box,
splitting the box, the subset of processors, and the particles in the
box in two. The recursion continues until every processor is assigned
a sub-box of the entire simulation domain, and owns the (weighted)
particles in that sub-box.
:line
This sub-section describes how to perform weighted load balancing
using the {weight} keyword. :link(weighted_balance)
By default, all particles have a weight of 1.0, which means each
particle is assumed to require the same amount of computation during a
timestep. There are, however, scenarios where this is not a good
assumption. Measuring the computational cost for each particle
accurately would be impractical and slow down the computation.
Instead the {weight} keyword implements several ways to influence the
per-particle weights empirically by properties readily available or
using the user's knowledge of the system. Note that the absolute
value of the weights are not important; only their relative ratios
affect which particle is assigned to which processor. A particle with
a weight of 2.5 is assumed to require 5x more computational than a
particle with a weight of 0.5. For all the options below the weight
assigned to a particle must be a positive value; an error will be be
generated if a weight is <= 0.0.
Below is a list of possible weight options with a short description of
their usage and some example scenarios where they might be applicable.
It is possible to apply multiple weight flags and the weightings they
induce will be combined through multiplication. Most of the time,
however, it is sufficient to use just one method.
The {group} weight style assigns weight factors to specified
"groups"_group.html of particles. The {group} style keyword is
followed by the number of groups, then pairs of group IDs and the
corresponding weight factor. If a particle belongs to none of the
specified groups, its weight is not changed. If it belongs to
multiple groups, its weight is the product of the weight factors.
This weight style is useful in combination with pair style
"hybrid"_pair_hybrid.html, e.g. when combining a more costly manybody
potential with a fast pair-wise potential. It is also useful when
using "run_style respa"_run_style.html where some portions of the
system have many bonded interactions and others none. It assumes that
the computational cost for each group remains constant over time.
This is a purely empirical weighting, so a series test runs to tune
the assigned weight factors for optimal performance is recommended.
The {neigh} weight style assigns the same weight to each particle
owned by a processor based on the total count of neighbors in the
neighbor list owned by that processor. The motivation is that more
neighbors means a higher computational cost. The style does not use
neighbors per atom to assign a unique weight to each atom, because
that value can vary depending on how the neighbor list is built.
The {factor} setting is applied as an overall scale factor to the
{neigh} weights which allows adjustment of their impact on the
balancing operation. The specified {factor} value must be positive.
A value > 1.0 will increase the weights so that the ratio of max
weight to min weight increases by {factor}. A value < 1.0 will
decrease the weights so that the ratio of max weight to min weight
decreases by {factor}. In both cases the intermediate weight values
increase/decrease proportionally as well. A value = 1.0 has no effect
on the {neigh} weights. As a rule of thumb, we have found a {factor}
of about 0.8 often results in the best performance, since the number
of neighbors is likely to overestimate the ideal weight.
This weight style is useful for systems where there are different
cutoffs used for different pairs of interactions, or the density
fluctuates, or a large number of particles are in the vicinity of a
wall, or a combination of these effects. If a simulation uses
multiple neighbor lists, this weight style will use the first suitable
neighbor list it finds. It will not request or compute a new list. A
warning will be issued if there is no suitable neighbor list available
or if it is not current, e.g. if the balance command is used before a
"run"_run.html or "minimize"_minimize.html command is used, in which
case the neighbor list may not yet have been built. In this case no
weights are computed. Inserting a "run 0 post no"_run.html command
before issuing the {balance} command, may be a workaround for this
case, as it will induce the neighbor list to be built.
The {time} weight style uses "timer data"_timer.html to estimate
weights. It assigns the same weight to each particle owned by a
processor based on the total computational time spent by that
processor. See details below on what time window is used. It uses
the same timing information as is used for the "MPI task timing
-breakdown"_Section_start.html#start_8, namely, for sections {Pair},
+breakdown"_Section_start.html#start_7, namely, for sections {Pair},
{Bond}, {Kspace}, and {Neigh}. The time spent in those portions of
the timestep are measured for each MPI rank, summed, then divided by
the number of particles owned by that processor. I.e. the weight is
an effective CPU time/particle averaged over the particles on that
processor.
The {factor} setting is applied as an overall scale factor to the
{time} weights which allows adjustment of their impact on the
balancing operation. The specified {factor} value must be positive.
A value > 1.0 will increase the weights so that the ratio of max
weight to min weight increases by {factor}. A value < 1.0 will
decrease the weights so that the ratio of max weight to min weight
decreases by {factor}. In both cases the intermediate weight values
increase/decrease proportionally as well. A value = 1.0 has no effect
on the {time} weights. As a rule of thumb, effective values to use
are typically between 0.5 and 1.2. Note that the timer quantities
mentioned above can be affected by communication which occurs in the
middle of the operations, e.g. pair styles with intermediate exchange
of data witin the force computation, and likewise for KSpace solves.
When using the {time} weight style with the {balance} command, the
timing data is taken from the preceding run command, i.e. the timings
are for the entire previous run. For the {fix balance} command the
timing data is for only the timesteps since the last balancing
operation was performed. If timing information for the required
sections is not available, e.g. at the beginning of a run, or when the
"timer"_timer.html command is set to either {loop} or {off}, a warning
is issued. In this case no weights are computed.
NOTE: The {time} weight style is the most generic option, and should
be tried first, unless the {group} style is easily applicable.
However, since the computed cost function is averaged over all
particles on a processor, the weights may not be highly accurate.
This style can also be effective as a secondary weight in combination
with either {group} or {neigh} to offset some of inaccuracies in
either of those heuristics.
The {var} weight style assigns per-particle weights by evaluating an
"atom-style variable"_variable.html specified by {name}. This is
provided as a more flexible alternative to the {group} weight style,
allowing definition of a more complex heuristics based on information
(global and per atom) available inside of LAMMPS. For example,
atom-style variables can reference the position of a particle, its
velocity, the volume of its Voronoi cell, etc.
The {store} weight style does not compute a weight factor. Instead it
stores the current accumulated weights in a custom per-atom property
specified by {name}. This must be a property defined as {d_name} via
the "fix property/atom"_fix_property_atom.html command. Note that
these custom per-atom properties can be output in a "dump"_dump.html
file, so this is a way to examine, debug, or visualize the
per-particle weights computed during the load-balancing operation.
:line
The {out} keyword writes a text file to the specified {filename} with
the results of the balancing operation. The file contains the bounds
of the sub-domain for each processor after the balancing operation
completes. The format of the file is compatible with the
"Pizza.py"_pizza {mdump} tool which has support for manipulating and
visualizing mesh files. An example is shown here for a balancing by 4
processors for a 2d problem:
ITEM: TIMESTEP
0
ITEM: NUMBER OF NODES
16
ITEM: BOX BOUNDS
0 10
0 10
0 10
ITEM: NODES
1 1 0 0 0
2 1 5 0 0
3 1 5 5 0
4 1 0 5 0
5 1 5 0 0
6 1 10 0 0
7 1 10 5 0
8 1 5 5 0
9 1 0 5 0
10 1 5 5 0
11 1 5 10 0
12 1 10 5 0
13 1 5 5 0
14 1 10 5 0
15 1 10 10 0
16 1 5 10 0
ITEM: TIMESTEP
0
ITEM: NUMBER OF SQUARES
4
ITEM: SQUARES
1 1 1 2 3 4
2 1 5 6 7 8
3 1 9 10 11 12
4 1 13 14 15 16 :pre
The coordinates of all the vertices are listed in the NODES section, 5
per processor. Note that the 4 sub-domains share vertices, so there
will be duplicate nodes in the list.
The "SQUARES" section lists the node IDs of the 4 vertices in a
rectangle for each processor (1 to 4).
For a 3d problem, the syntax is similar with 8 vertices listed for
each processor, instead of 4, and "SQUARES" replaced by "CUBES".
:line
[Restrictions:]
For 2d simulations, the {z} style cannot be used. Nor can a "z"
appear in {dimstr} for the {shift} style.
[Related commands:]
"group"_group.html, "processors"_processors.html,
"fix balance"_fix_balance.html
[Default:] none
diff --git a/doc/src/bond_class2.txt b/doc/src/bond_class2.txt
index aa0541238..9687a6316 100644
--- a/doc/src/bond_class2.txt
+++ b/doc/src/bond_class2.txt
@@ -1,82 +1,82 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style class2 command :h3
bond_style class2/omp command :h3
bond_style class2/kk command :h3
[Syntax:]
bond_style class2 :pre
[Examples:]
bond_style class2
bond_coeff 1 1.0 100.0 80.0 80.0 :pre
[Description:]
The {class2} bond style uses the potential
:c,image(Eqs/bond_class2.jpg)
where r0 is the equilibrium bond distance.
See "(Sun)"_#bond-Sun for a description of the COMPASS class2 force field.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
R0 (distance)
K2 (energy/distance^2)
K3 (energy/distance^3)
K4 (energy/distance^4) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the CLASS2
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
:line
:link(bond-Sun)
[(Sun)] Sun, J Phys Chem B 102, 7338-7364 (1998).
diff --git a/doc/src/bond_fene.txt b/doc/src/bond_fene.txt
index 80d2a805c..9050c3bf5 100644
--- a/doc/src/bond_fene.txt
+++ b/doc/src/bond_fene.txt
@@ -1,89 +1,89 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style fene command :h3
bond_style fene/intel command :h3
bond_style fene/kk command :h3
bond_style fene/omp command :h3
[Syntax:]
bond_style fene :pre
[Examples:]
bond_style fene
bond_coeff 1 30.0 1.5 1.0 1.0 :pre
[Description:]
The {fene} bond style uses the potential
:c,image(Eqs/bond_fene.jpg)
to define a finite extensible nonlinear elastic (FENE) potential
"(Kremer)"_#fene-Kremer, used for bead-spring polymer models. The first
term is attractive, the 2nd Lennard-Jones term is repulsive. The
first term extends to R0, the maximum extent of the bond. The 2nd
term is cutoff at 2^(1/6) sigma, the minimum of the LJ potential.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/distance^2)
R0 (distance)
epsilon (energy)
sigma (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
You typically should specify "special_bonds fene"_special_bonds.html
or "special_bonds lj/coul 0 1 1"_special_bonds.html to use this bond
style. LAMMPS will issue a warning it that's not the case.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
:line
:link(fene-Kremer)
[(Kremer)] Kremer, Grest, J Chem Phys, 92, 5057 (1990).
diff --git a/doc/src/bond_fene_expand.txt b/doc/src/bond_fene_expand.txt
index 3908c16a7..ff687444a 100644
--- a/doc/src/bond_fene_expand.txt
+++ b/doc/src/bond_fene_expand.txt
@@ -1,92 +1,92 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style fene/expand command :h3
bond_style fene/expand/omp command :h3
[Syntax:]
bond_style fene/expand :pre
[Examples:]
bond_style fene/expand
bond_coeff 1 30.0 1.5 1.0 1.0 0.5 :pre
[Description:]
The {fene/expand} bond style uses the potential
:c,image(Eqs/bond_fene_expand.jpg)
to define a finite extensible nonlinear elastic (FENE) potential
"(Kremer)"_#feneexpand-Kremer, used for bead-spring polymer models. The first
term is attractive, the 2nd Lennard-Jones term is repulsive.
The {fene/expand} bond style is similar to {fene} except that an extra
shift factor of delta (positive or negative) is added to {r} to
effectively change the bead size of the bonded atoms. The first term
now extends to R0 + delta and the 2nd term is cutoff at 2^(1/6) sigma
+ delta.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/distance^2)
R0 (distance)
epsilon (energy)
sigma (distance)
delta (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
You typically should specify "special_bonds fene"_special_bonds.html
or "special_bonds lj/coul 0 1 1"_special_bonds.html to use this bond
style. LAMMPS will issue a warning it that's not the case.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
:line
:link(feneexpand-Kremer)
[(Kremer)] Kremer, Grest, J Chem Phys, 92, 5057 (1990).
diff --git a/doc/src/bond_harmonic.txt b/doc/src/bond_harmonic.txt
index 1cbd897da..c18a7e0fd 100644
--- a/doc/src/bond_harmonic.txt
+++ b/doc/src/bond_harmonic.txt
@@ -1,75 +1,75 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style harmonic command :h3
bond_style harmonic/intel command :h3
bond_style harmonic/kk command :h3
bond_style harmonic/omp command :h3
[Syntax:]
bond_style harmonic :pre
[Examples:]
bond_style harmonic
bond_coeff 5 80.0 1.2 :pre
[Description:]
The {harmonic} bond style uses the potential
:c,image(Eqs/bond_harmonic.jpg)
where r0 is the equilibrium bond distance. Note that the usual 1/2
factor is included in K.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/distance^2)
r0 (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
diff --git a/doc/src/bond_harmonic_shift.txt b/doc/src/bond_harmonic_shift.txt
index 8cb2d2ce7..bf3b3c115 100644
--- a/doc/src/bond_harmonic_shift.txt
+++ b/doc/src/bond_harmonic_shift.txt
@@ -1,77 +1,77 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style harmonic/shift command :h3
bond_style harmonic/shift/omp command :h3
[Syntax:]
bond_style harmonic/shift :pre
[Examples:]
bond_style harmonic/shift
bond_coeff 5 10.0 0.5 1.0 :pre
[Description:]
The {harmonic/shift} bond style is a shifted harmonic bond that uses
the potential
:c,image(Eqs/bond_harmonic_shift.jpg)
where r0 is the equilibrium bond distance, and rc the critical distance.
The potential is -Umin at r0 and zero at rc. The spring constant is
k = Umin / \[ 2 (r0-rc)^2\].
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
Umin (energy) :ul
r0 (distance) :ul
rc (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html,
"bond_harmonic"_bond_harmonic.html
[Default:] none
diff --git a/doc/src/bond_harmonic_shift_cut.txt b/doc/src/bond_harmonic_shift_cut.txt
index 836d6afda..1918ce00b 100644
--- a/doc/src/bond_harmonic_shift_cut.txt
+++ b/doc/src/bond_harmonic_shift_cut.txt
@@ -1,78 +1,78 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style harmonic/shift/cut command :h3
bond_style harmonic/shift/cut/omp command :h3
[Syntax:]
bond_style harmonic/shift/cut :pre
[Examples:]
bond_style harmonic/shift/cut
bond_coeff 5 10.0 0.5 1.0 :pre
[Description:]
The {harmonic/shift/cut} bond style is a shifted harmonic bond that
uses the potential
:c,image(Eqs/bond_harmonic_shift_cut.jpg)
where r0 is the equilibrium bond distance, and rc the critical distance.
The bond potential is zero for distances r > rc. The potential is -Umin
at r0 and zero at rc. The spring constant is k = Umin / \[ 2 (r0-rc)^2\].
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
Umin (energy)
r0 (distance)
rc (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html,
"bond_harmonic"_bond_harmonic.html,
"bond_harmonic_shift"_bond_harmonic_shift.html
[Default:] none
diff --git a/doc/src/bond_morse.txt b/doc/src/bond_morse.txt
index 12e51f9be..4f6a32e34 100644
--- a/doc/src/bond_morse.txt
+++ b/doc/src/bond_morse.txt
@@ -1,74 +1,74 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style morse command :h3
bond_style morse/omp command :h3
[Syntax:]
bond_style morse :pre
[Examples:]
bond_style morse
bond_coeff 5 1.0 2.0 1.2 :pre
[Description:]
The {morse} bond style uses the potential
:c,image(Eqs/bond_morse.jpg)
where r0 is the equilibrium bond distance, alpha is a stiffness
parameter, and D determines the depth of the potential well.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
D (energy)
alpha (inverse distance)
r0 (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
diff --git a/doc/src/bond_nonlinear.txt b/doc/src/bond_nonlinear.txt
index ac9f3369c..434af6250 100644
--- a/doc/src/bond_nonlinear.txt
+++ b/doc/src/bond_nonlinear.txt
@@ -1,79 +1,79 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style nonlinear command :h3
bond_style nonlinear/omp command :h3
[Syntax:]
bond_style nonlinear :pre
[Examples:]
bond_style nonlinear
bond_coeff 2 100.0 1.1 1.4 :pre
[Description:]
The {nonlinear} bond style uses the potential
:c,image(Eqs/bond_nonlinear.jpg)
to define an anharmonic spring "(Rector)"_#Rector of equilibrium
length r0 and maximum extension lamda.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
epsilon (energy)
r0 (distance)
lamda (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
:line
:link(Rector)
[(Rector)] Rector, Van Swol, Henderson, Molecular Physics, 82, 1009 (1994).
diff --git a/doc/src/bond_quartic.txt b/doc/src/bond_quartic.txt
index e61f4f034..4dc7ad4a3 100644
--- a/doc/src/bond_quartic.txt
+++ b/doc/src/bond_quartic.txt
@@ -1,113 +1,113 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style quartic command :h3
bond_style quartic/omp command :h3
[Syntax:]
bond_style quartic :pre
[Examples:]
bond_style quartic
bond_coeff 2 1200 -0.55 0.25 1.3 34.6878 :pre
[Description:]
The {quartic} bond style uses the potential
:c,image(Eqs/bond_quartic.jpg)
to define a bond that can be broken as the simulation proceeds (e.g.
due to a polymer being stretched). The sigma and epsilon used in the
LJ portion of the formula are both set equal to 1.0 by LAMMPS.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy/distance^4)
B1 (distance)
B2 (distance)
Rc (distance)
U0 (energy) :ul
This potential was constructed to mimic the FENE bond potential for
coarse-grained polymer chains. When monomers with sigma = epsilon =
1.0 are used, the following choice of parameters gives a quartic
potential that looks nearly like the FENE potential: K = 1200, B1 =
-0.55, B2 = 0.25, Rc = 1.3, and U0 = 34.6878. Different parameters
can be specified using the "bond_coeff"_bond_coeff.html command, but
you will need to choose them carefully so they form a suitable bond
potential.
Rc is the cutoff length at which the bond potential goes smoothly to a
local maximum. If a bond length ever becomes > Rc, LAMMPS "breaks"
the bond, which means two things. First, the bond potential is turned
off by setting its type to 0, and is no longer computed. Second, a
pairwise interaction between the two atoms is turned on, since they
are no longer bonded.
LAMMPS does the second task via a computational sleight-of-hand. It
subtracts the pairwise interaction as part of the bond computation.
When the bond breaks, the subtraction stops. For this to work, the
pairwise interaction must always be computed by the
"pair_style"_pair_style.html command, whether the bond is broken or
not. This means that "special_bonds"_special_bonds.html must be set
to 1,1,1, as indicated as a restriction below.
Note that when bonds are dumped to a file via the "dump
local"_dump.html command, bonds with type 0 are not included. The
"delete_bonds"_delete_bonds.html command can also be used to query the
status of broken bonds or permanently delete them, e.g.:
delete_bonds all stats
delete_bonds all bond 0 remove :pre
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
The {quartic} style requires that "special_bonds"_special_bonds.html
parameters be set to 1,1,1. Three- and four-body interactions (angle,
dihedral, etc) cannot be used with {quartic} bonds.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
diff --git a/doc/src/bond_table.txt b/doc/src/bond_table.txt
index cb096fba1..906d3e5d7 100644
--- a/doc/src/bond_table.txt
+++ b/doc/src/bond_table.txt
@@ -1,154 +1,154 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
bond_style table command :h3
bond_style table/omp command :h3
[Syntax:]
bond_style table style N :pre
style = {linear} or {spline} = method of interpolation
N = use N values in table :ul
[Examples:]
bond_style table linear 1000
bond_coeff 1 file.table ENTRY1 :pre
[Description:]
Style {table} creates interpolation tables of length {N} from bond
potential and force values listed in a file(s) as a function of bond
length. The files are read by the "bond_coeff"_bond_coeff.html
command.
The interpolation tables are created by fitting cubic splines to the
file values and interpolating energy and force values at each of {N}
distances. During a simulation, these tables are used to interpolate
energy and force values as needed. The interpolation is done in one
of 2 styles: {linear} or {spline}.
For the {linear} style, the bond length is used to find 2 surrounding
table values from which an energy or force is computed by linear
interpolation.
For the {spline} style, a cubic spline coefficients are computed and
stored at each of the {N} values in the table. The bond length is
used to find the appropriate set of coefficients which are used to
evaluate a cubic polynomial which computes the energy or force.
The following coefficients must be defined for each bond type via the
"bond_coeff"_bond_coeff.html command as in the example above.
filename
keyword :ul
The filename specifies a file containing tabulated energy and force
values. The keyword specifies a section of the file. The format of
this file is described below.
:line
The format of a tabulated file is as follows (without the
parenthesized comments):
# Bond potential for harmonic (one or more comment or blank lines) :pre
HAM (keyword is the first text on line)
N 101 FP 0 0 EQ 0.5 (N, FP, EQ parameters)
(blank line)
1 0.00 338.0000 1352.0000 (index, bond-length, energy, force)
2 0.01 324.6152 1324.9600
...
101 1.00 338.0000 -1352.0000 :pre
A section begins with a non-blank line whose 1st character is not a
"#"; blank lines or lines starting with "#" can be used as comments
between sections. The first line begins with a keyword which
identifies the section. The line can contain additional text, but the
initial text must match the argument specified in the
"bond_coeff"_bond_coeff.html command. The next line lists (in any
order) one or more parameters for the table. Each parameter is a
keyword followed by one or more numeric values.
The parameter "N" is required and its value is the number of table
entries that follow. Note that this may be different than the {N}
specified in the "bond_style table"_bond_style.html command. Let
Ntable = {N} in the bond_style command, and Nfile = "N" in the
tabulated file. What LAMMPS does is a preliminary interpolation by
creating splines using the Nfile tabulated values as nodal points. It
uses these to interpolate as needed to generate energy and force
values at Ntable different points. The resulting tables of length
Ntable are then used as described above, when computing energy and
force for individual bond lengths. This means that if you want the
interpolation tables of length Ntable to match exactly what is in the
tabulated file (with effectively no preliminary interpolation), you
should set Ntable = Nfile.
The "FP" parameter is optional. If used, it is followed by two values
fplo and fphi, which are the derivatives of the force at the innermost
and outermost bond lengths. These values are needed by the spline
construction routines. If not specified by the "FP" parameter, they
are estimated (less accurately) by the first two and last two force
values in the table.
The "EQ" parameter is also optional. If used, it is followed by a the
equilibrium bond length, which is used, for example, by the "fix
shake"_fix_shake.html command. If not used, the equilibrium bond
length is to the distance in the table with the lowest potential energy.
Following a blank line, the next N lines list the tabulated values.
On each line, the 1st value is the index from 1 to N, the 2nd value is
the bond length r (in distance units), the 3rd value is the energy (in
energy units), and the 4th is the force (in force units). The bond
lengths must range from a LO value to a HI value, and increase from
one line to the next. If the actual bond length is ever smaller than
the LO value or larger than the HI value, then the bond energy and
force is evaluated as if the bond were the LO or HI length.
Note that one file can contain many sections, each with a tabulated
potential. LAMMPS reads the file section by section until it finds
one that matches the specified keyword.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This bond style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"bond_coeff"_bond_coeff.html, "delete_bonds"_delete_bonds.html
[Default:] none
diff --git a/doc/src/compute_pressure.txt b/doc/src/compute_pressure.txt
index 292e779f7..f0691ad20 100644
--- a/doc/src/compute_pressure.txt
+++ b/doc/src/compute_pressure.txt
@@ -1,154 +1,154 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
compute pressure command :h3
[Syntax:]
compute ID group-ID pressure temp-ID keyword ... :pre
ID, group-ID are documented in "compute"_compute.html command
pressure = style name of this compute command
temp-ID = ID of compute that calculates temperature, can be NULL if not needed
zero or more keywords may be appended
keyword = {ke} or {pair} or {bond} or {angle} or {dihedral} or {improper} or {kspace} or {fix} or {virial} :ul
[Examples:]
compute 1 all pressure thermo_temp
compute 1 all pressure NULL pair bond :pre
[Description:]
Define a computation that calculates the pressure of the entire system
of atoms. The specified group must be "all". See the "compute
stress/atom"_compute_stress_atom.html command if you want per-atom
pressure (stress). These per-atom values could be summed for a group
of atoms via the "compute reduce"_compute_reduce.html command.
The pressure is computed by the formula
:c,image(Eqs/pressure.jpg)
where N is the number of atoms in the system (see discussion of DOF
below), Kb is the Boltzmann constant, T is the temperature, d is the
dimensionality of the system (2 or 3 for 2d/3d), and V is the system
volume (or area in 2d). The second term is the virial, equal to
-dU/dV, computed for all pairwise as well as 2-body, 3-body, 4-body,
manybody, and long-range interactions, where r_i and f_i are the
position and force vector of atom i, and the black dot indicates a dot
product. When periodic boundary conditions are used, N' necessarily
includes periodic image (ghost) atoms outside the central box, and the
position and force vectors of ghost atoms are thus included in the
summation. When periodic boundary conditions are not used, N' = N =
the number of atoms in the system. "Fixes"_fix.html that impose
constraints (e.g. the "fix shake"_fix_shake.html command) also
contribute to the virial term.
A symmetric pressure tensor, stored as a 6-element vector, is also
calculated by this compute. The 6 components of the vector are
ordered xx, yy, zz, xy, xz, yz. The equation for the I,J components
(where I and J = x,y,z) is similar to the above formula, except that
the first term uses components of the kinetic energy tensor and the
second term uses components of the virial tensor:
:c,image(Eqs/pressure_tensor.jpg)
If no extra keywords are listed, the entire equations above are
calculated. This includes a kinetic energy (temperature) term and the
virial as the sum of pair, bond, angle, dihedral, improper, kspace
(long-range), and fix contributions to the force on each atom. If any
extra keywords are listed, then only those components are summed to
compute temperature or ke and/or the virial. The {virial} keyword
means include all terms except the kinetic energy {ke}.
Details of how LAMMPS computes the virial efficiently for the entire
system, including for manybody potentials and accounting for the
effects of periodic boundary conditions are discussed in
"(Thompson)"_#Thompson1.
The temperature and kinetic energy tensor is not calculated by this
compute, but rather by the temperature compute specified with the
command. If the kinetic energy is not included in the pressure, than
the temperature compute is not used and can be specified as NULL.
Normally the temperature compute used by compute pressure should
calculate the temperature of all atoms for consistency with the virial
term, but any compute style that calculates temperature can be used,
e.g. one that excludes frozen atoms or other degrees of freedom.
Note that if desired the specified temperature compute can be one that
subtracts off a bias to calculate a temperature using only the thermal
velocity of the atoms, e.g. by subtracting a background streaming
velocity. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias.
Also note that the N in the first formula above is really
degrees-of-freedom divided by d = dimensionality, where the DOF value
is calculated by the temperature compute. See the various "compute
temperature"_compute.html styles for details.
A compute of this style with the ID of "thermo_press" is created when
LAMMPS starts up, as if this command were in the input script:
compute thermo_press all pressure thermo_temp :pre
where "thermo_temp" is the ID of a similarly defined compute of style
"temp". See the "thermo_style" command for more details.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Output info:]
This compute calculates a global scalar (the pressure) and a global
vector of length 6 (pressure tensor), which can be accessed by indices
1-6. These values can be used by any command that uses global scalar
or vector values from a compute as input. See "this
section"_Section_howto.html#howto_15 for an overview of LAMMPS output
options.
The scalar and vector values calculated by this compute are
"intensive". The scalar and vector values will be in pressure
"units"_units.html.
[Restrictions:] none
[Related commands:]
"compute temp"_compute_temp.html, "compute
stress/atom"_compute_stress_atom.html,
"thermo_style"_thermo_style.html,
[Default:] none
:line
:link(Thompson1)
[(Thompson)] Thompson, Plimpton, Mattson, J Chem Phys, 131, 154107 (2009).
diff --git a/doc/src/compute_temp.txt b/doc/src/compute_temp.txt
index 0bd2d4b12..b88be79e2 100644
--- a/doc/src/compute_temp.txt
+++ b/doc/src/compute_temp.txt
@@ -1,113 +1,113 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
compute temp command :h3
compute temp/kk command :h3
[Syntax:]
compute ID group-ID temp :pre
ID, group-ID are documented in "compute"_compute.html command
temp = style name of this compute command :ul
[Examples:]
compute 1 all temp
compute myTemp mobile temp :pre
[Description:]
Define a computation that calculates the temperature of a group of
atoms. A compute of this style can be used by any command that
computes a temperature, e.g. "thermo_modify"_thermo_modify.html, "fix
temp/rescale"_fix_temp_rescale.html, "fix npt"_fix_nh.html, etc.
The temperature is calculated by the formula KE = dim/2 N k T, where
KE = total kinetic energy of the group of atoms (sum of 1/2 m v^2),
dim = 2 or 3 = dimensionality of the simulation, N = number of atoms
in the group, k = Boltzmann constant, and T = temperature.
A kinetic energy tensor, stored as a 6-element vector, is also
calculated by this compute for use in the computation of a pressure
tensor. The formula for the components of the tensor is the same as
the above formula, except that v^2 is replaced by vx*vy for the xy
component, etc. The 6 components of the vector are ordered xx, yy,
zz, xy, xz, yz.
The number of atoms contributing to the temperature is assumed to be
constant for the duration of the run; use the {dynamic} option of the
"compute_modify"_compute_modify.html command if this is not the case.
This compute subtracts out degrees-of-freedom due to fixes that
constrain molecular motion, such as "fix shake"_fix_shake.html and
"fix rigid"_fix_rigid.html. This means the temperature of groups of
atoms that include these constraints will be computed correctly. If
needed, the subtracted degrees-of-freedom can be altered using the
{extra} option of the "compute_modify"_compute_modify.html command.
A compute of this style with the ID of "thermo_temp" is created when
LAMMPS starts up, as if this command were in the input script:
compute thermo_temp all temp :pre
See the "thermo_style" command for more details.
See "this howto section"_Section_howto.html#howto_16 of the manual for
a discussion of different ways to compute temperature and perform
thermostatting.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Output info:]
This compute calculates a global scalar (the temperature) and a global
vector of length 6 (KE tensor), which can be accessed by indices 1-6.
These values can be used by any command that uses global scalar or
vector values from a compute as input. See "this
section"_Section_howto.html#howto_15 for an overview of LAMMPS output
options.
The scalar value calculated by this compute is "intensive". The
vector values are "extensive".
The scalar value will be in temperature "units"_units.html. The
vector values will be in energy "units"_units.html.
[Restrictions:] none
[Related commands:]
"compute temp/partial"_compute_temp_partial.html, "compute
temp/region"_compute_temp_region.html, "compute
pressure"_compute_pressure.html
[Default:] none
diff --git a/doc/src/compute_temp_partial.txt b/doc/src/compute_temp_partial.txt
index 163a00af5..fe2420b4e 100644
--- a/doc/src/compute_temp_partial.txt
+++ b/doc/src/compute_temp_partial.txt
@@ -1,120 +1,120 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
compute temp/partial command :h3
[Syntax:]
compute ID group-ID temp/partial xflag yflag zflag :pre
ID, group-ID are documented in "compute"_compute.html command
temp/partial = style name of this compute command
xflag,yflag,zflag = 0/1 for whether to exclude/include this dimension :ul
[Examples:]
compute newT flow temp/partial 1 1 0 :pre
[Description:]
Define a computation that calculates the temperature of a group of
atoms, after excluding one or more velocity components. A compute of
this style can be used by any command that computes a temperature,
e.g. "thermo_modify"_thermo_modify.html, "fix
temp/rescale"_fix_temp_rescale.html, "fix npt"_fix_nh.html, etc.
The temperature is calculated by the formula KE = dim/2 N k T, where
KE = total kinetic energy of the group of atoms (sum of 1/2 m v^2),
dim = dimensionality of the simulation, N = number of atoms in the
group, k = Boltzmann constant, and T = temperature. The calculation
of KE excludes the x, y, or z dimensions if xflag, yflag, or zflag =
0. The dim parameter is adjusted to give the correct number of
degrees of freedom.
A kinetic energy tensor, stored as a 6-element vector, is also
calculated by this compute for use in the calculation of a pressure
tensor. The formula for the components of the tensor is the same as
the above formula, except that v^2 is replaced by vx*vy for the xy
component, etc. The 6 components of the vector are ordered xx, yy,
zz, xy, xz, yz.
The number of atoms contributing to the temperature is assumed to be
constant for the duration of the run; use the {dynamic} option of the
"compute_modify"_compute_modify.html command if this is not the case.
The removal of velocity components by this fix is essentially
computing the temperature after a "bias" has been removed from the
velocity of the atoms. If this compute is used with a fix command
that performs thermostatting then this bias will be subtracted from
each atom, thermostatting of the remaining thermal velocity will be
performed, and the bias will be added back in. Thermostatting fixes
that work in this way include "fix nvt"_fix_nh.html, "fix
temp/rescale"_fix_temp_rescale.html, "fix
temp/berendsen"_fix_temp_berendsen.html, and "fix
langevin"_fix_langevin.html.
This compute subtracts out degrees-of-freedom due to fixes that
constrain molecular motion, such as "fix shake"_fix_shake.html and
"fix rigid"_fix_rigid.html. This means the temperature of groups of
atoms that include these constraints will be computed correctly. If
needed, the subtracted degrees-of-freedom can be altered using the
{extra} option of the "compute_modify"_compute_modify.html command.
See "this howto section"_Section_howto.html#howto_16 of the manual for
a discussion of different ways to compute temperature and perform
thermostatting.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Output info:]
This compute calculates a global scalar (the temperature) and a global
vector of length 6 (KE tensor), which can be accessed by indices 1-6.
These values can be used by any command that uses global scalar or
vector values from a compute as input. See "this
section"_Section_howto.html#howto_15 for an overview of LAMMPS output
options.
The scalar value calculated by this compute is "intensive". The
vector values are "extensive".
The scalar value will be in temperature "units"_units.html. The
vector values will be in energy "units"_units.html.
[Restrictions:] none
[Related commands:]
"compute temp"_compute_temp.html, "compute
temp/region"_compute_temp_region.html, "compute
pressure"_compute_pressure.html
[Default:] none
diff --git a/doc/src/dihedral_charmm.txt b/doc/src/dihedral_charmm.txt
index 73dc67cde..06abe054e 100644
--- a/doc/src/dihedral_charmm.txt
+++ b/doc/src/dihedral_charmm.txt
@@ -1,167 +1,167 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style charmm command :h3
dihedral_style charmm/intel command :h3
dihedral_style charmm/kk command :h3
dihedral_style charmm/omp command :h3
dihedral_style charmmfsw command :h3
[Syntax:]
dihedral_style style :pre
style = {charmm} or {charmmfsw} :ul
[Examples:]
dihedral_style charmm
dihedral_style charmmfsw
dihedral_coeff 1 0.2 1 180 1.0
dihedral_coeff 2 1.8 1 0 1.0
dihedral_coeff 1 3.1 2 180 0.5 :pre
[Description:]
The {charmm} and {charmmfsw} dihedral styles use the potential
:c,image(Eqs/dihedral_charmm.jpg)
See "(MacKerell)"_#dihedral-MacKerell for a description of the CHARMM
force field. This dihedral style can also be used for the AMBER force
field (see comment on weighting factors below). See
"(Cornell)"_#dihedral-Cornell for a description of the AMBER force
field.
NOTE: The newer {charmmfsw} style was released in March 2017. We
recommend it be used instead of the older {charmm} style when running
a simulation with the CHARMM force field, either with long-range
Coulombics or a Coulomb cutoff, via the "pair_style
lj/charmmfsw/coul/long"_pair_charmm.html and "pair_style
lj/charmmfsw/coul/charmmfsh"_pair_charmm.html commands respectively.
Otherwise the older {charmm} style is fine to use. See the discussion
below and more details on the "pair_style charmm"_pair_charmm.html doc
page.
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
n (integer >= 0)
d (integer value of degrees)
weighting factor (1.0, 0.5, or 0.0) :ul
The weighting factor is required to correct for double counting
pairwise non-bonded Lennard-Jones interactions in cyclic systems or
when using the CHARMM dihedral style with non-CHARMM force fields.
With the CHARMM dihedral style, interactions between the 1st and 4th
atoms in a dihedral are skipped during the normal non-bonded force
computation and instead evaluated as part of the dihedral using
special epsilon and sigma values specified with the
"pair_coeff"_pair_charmm.html command of pair styles that contain
"lj/charmm" (e.g. "pair_style lj/charmm/coul/long"_pair_charmm.html)
In 6-membered rings, the same 1-4 interaction would be computed twice
(once for the clockwise 1-4 pair in dihedral 1-2-3-4 and once in the
counterclockwise dihedral 1-6-5-4) and thus the weighting factor has
to be 0.5 in this case. In 4-membered or 5-membered rings, the 1-4
dihedral also is counted as a 1-2 or 1-3 interaction when going around
the ring in the opposite direction and thus the weighting factor is
0.0, as the 1-2 and 1-3 exclusions take precedence.
Note that this dihedral weighting factor is unrelated to the scaling
factor specified by the "special bonds"_special_bonds.html command
which applies to all 1-4 interactions in the system. For CHARMM force
fields, the special_bonds 1-4 interaction scaling factor should be set
to 0.0. Since the corresponding 1-4 non-bonded interactions are
computed with the dihedral. This means that if any of the weighting
factors defined as dihedral coefficients (4th coeff above) are
non-zero, then you must use a pair style with "lj/charmm" and set the
special_bonds 1-4 scaling factor to 0.0 (which is the
default). Otherwise 1-4 non-bonded interactions in dihedrals will be
computed twice.
For simulations using the CHARMM force field with a Coulomb cutoff,
the difference between the {charmm} and {charmmfsw} styles is in the
computation of the 1-4 non-bond interactions, though only if the
distance between the two atoms is within the switching region of the
pairwise potential defined by the corresponding CHARMM pair style,
i.e. within the outer cutoff specified for the pair style. The
{charmmfsw} style should only be used when using the corresponding
"pair_style lj/charmmfsw/coul/charmmfsw"_pair_charmm.html or
"pair_style lj/charmmfsw/coul/long"_pair_charmm.html commands. Use
the {charmm} style with the older "pair_style"_pair_charmm.html
commands that have just "charmm" in their style name. See the
discussion on the "CHARMM pair_style"_pair_charmm.html doc page for
details.
Note that for AMBER force fields, which use pair styles with "lj/cut",
the special_bonds 1-4 scaling factor should be set to the AMBER
defaults (1/2 and 5/6) and all the dihedral weighting factors (4th
coeff above) must be set to 0.0. In this case, you can use any pair
style you wish, since the dihedral does not need any Lennard-Jones
parameter information and will not compute any 1-4 non-bonded
interactions. Likewise the {charmm} or {charmmfsw} styles are
identical in this case since no 1-4 non-bonded interactions are
computed.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
When using run_style "respa"_run_style.html, these dihedral styles
must be assigned to the same r-RESPA level as {pair} or {outer}.
When used in combination with CHARMM pair styles, the 1-4
"special_bonds"_special_bonds.html scaling factors must be set to 0.0.
Otherwise non-bonded contributions for these 1-4 pairs will be
computed multiple times.
These dihedral styles can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
:line
:link(dihedral-Cornell)
[(Cornell)] Cornell, Cieplak, Bayly, Gould, Merz, Ferguson,
Spellmeyer, Fox, Caldwell, Kollman, JACS 117, 5179-5197 (1995).
:link(dihedral-MacKerell)
[(MacKerell)] MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field,
Fischer, Gao, Guo, Ha, et al, J Phys Chem B, 102, 3586 (1998).
diff --git a/doc/src/dihedral_class2.txt b/doc/src/dihedral_class2.txt
index 91ab6f373..cb9fc72c2 100644
--- a/doc/src/dihedral_class2.txt
+++ b/doc/src/dihedral_class2.txt
@@ -1,179 +1,179 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style class2 command :h3
dihedral_style class2/omp command :h3
dihedral_style class2/kk command :h3
[Syntax:]
dihedral_style class2 :pre
[Examples:]
dihedral_style class2
dihedral_coeff 1 100 75 100 70 80 60
dihedral_coeff * mbt 3.5945 0.1704 -0.5490 1.5228
dihedral_coeff * ebt 0.3417 0.3264 -0.9036 0.1368 0.0 -0.8080 1.0119 1.1010
dihedral_coeff 2 at 0.0 -0.1850 -0.7963 -2.0220 0.0 -0.3991 110.2453 105.1270
dihedral_coeff * aat -13.5271 110.2453 105.1270
dihedral_coeff * bb13 0.0 1.0119 1.1010 :pre
[Description:]
The {class2} dihedral style uses the potential
:c,image(Eqs/dihedral_class2.jpg)
where Ed is the dihedral term, Embt is a middle-bond-torsion term,
Eebt is an end-bond-torsion term, Eat is an angle-torsion term, Eaat
is an angle-angle-torsion term, and Ebb13 is a bond-bond-13 term.
Theta1 and theta2 are equilibrium angles and r1 r2 r3 are equilibrium
bond lengths.
See "(Sun)"_#dihedral-Sun for a description of the COMPASS class2 force field.
Coefficients for the Ed, Embt, Eebt, Eat, Eaat, and Ebb13 formulas
must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above,
or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands.
These are the 6 coefficients for the Ed formula:
K1 (energy)
phi1 (degrees)
K2 (energy)
phi2 (degrees)
K3 (energy)
phi3 (degrees) :ul
For the Embt formula, each line in a
"dihedral_coeff"_dihedral_coeff.html command in the input script lists
5 coefficients, the first of which is "mbt" to indicate they are
MiddleBondTorsion coefficients. In a data file, these coefficients
should be listed under a "MiddleBondTorsion Coeffs" heading and you
must leave out the "mbt", i.e. only list 4 coefficients after the
dihedral type.
mbt
A1 (energy/distance)
A2 (energy/distance)
A3 (energy/distance)
r2 (distance) :ul
For the Eebt formula, each line in a
"dihedral_coeff"_dihedral_coeff.html command in the input script lists
9 coefficients, the first of which is "ebt" to indicate they are
EndBondTorsion coefficients. In a data file, these coefficients
should be listed under a "EndBondTorsion Coeffs" heading and you must
leave out the "ebt", i.e. only list 8 coefficients after the dihedral
type.
ebt
B1 (energy/distance)
B2 (energy/distance)
B3 (energy/distance)
C1 (energy/distance)
C2 (energy/distance)
C3 (energy/distance)
r1 (distance)
r3 (distance) :ul
For the Eat formula, each line in a
"dihedral_coeff"_dihedral_coeff.html command in the input script lists
9 coefficients, the first of which is "at" to indicate they are
AngleTorsion coefficients. In a data file, these coefficients should
be listed under a "AngleTorsion Coeffs" heading and you must leave out
the "at", i.e. only list 8 coefficients after the dihedral type.
at
D1 (energy/radian)
D2 (energy/radian)
D3 (energy/radian)
E1 (energy/radian)
E2 (energy/radian)
E3 (energy/radian)
theta1 (degrees)
theta2 (degrees) :ul
Theta1 and theta2 are specified in degrees, but LAMMPS converts them
to radians internally; hence the units of D and E are in
energy/radian.
For the Eaat formula, each line in a
"dihedral_coeff"_dihedral_coeff.html command in the input script lists
4 coefficients, the first of which is "aat" to indicate they are
AngleAngleTorsion coefficients. In a data file, these coefficients
should be listed under a "AngleAngleTorsion Coeffs" heading and you
must leave out the "aat", i.e. only list 3 coefficients after the
dihedral type.
aat
M (energy/radian^2)
theta1 (degrees)
theta2 (degrees) :ul
Theta1 and theta2 are specified in degrees, but LAMMPS converts them
to radians internally; hence the units of M are in energy/radian^2.
For the Ebb13 formula, each line in a
"dihedral_coeff"_dihedral_coeff.html command in the input script lists
4 coefficients, the first of which is "bb13" to indicate they are
BondBond13 coefficients. In a data file, these coefficients should be
listed under a "BondBond13 Coeffs" heading and you must leave out the
"bb13", i.e. only list 3 coefficients after the dihedral type.
bb13
N (energy/distance^2)
r1 (distance)
r3 (distance) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
CLASS2 package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
:line
:link(dihedral-Sun)
[(Sun)] Sun, J Phys Chem B 102, 7338-7364 (1998).
diff --git a/doc/src/dihedral_cosine_shift_exp.txt b/doc/src/dihedral_cosine_shift_exp.txt
index 89614a3fd..715682aff 100644
--- a/doc/src/dihedral_cosine_shift_exp.txt
+++ b/doc/src/dihedral_cosine_shift_exp.txt
@@ -1,86 +1,86 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style cosine/shift/exp command :h3
dihedral_style cosine/shift/exp/omp command :h3
[Syntax:]
dihedral_style cosine/shift/exp :pre
[Examples:]
dihedral_style cosine/shift/exp
dihedral_coeff 1 10.0 45.0 2.0 :pre
[Description:]
The {cosine/shift/exp} dihedral style uses the potential
:c,image(Eqs/dihedral_cosine_shift_exp.jpg)
where Umin, theta, and a are defined for each dihedral type.
The potential is bounded between \[-Umin:0\] and the minimum is located
at the angle theta0. The a parameter can be both positive or negative
and is used to control the spring constant at the equilibrium.
The spring constant is given by k=a exp(a) Umin/ \[2 (Exp(a)-1)\].
For a>3 k/Umin = a/2 to better than 5% relative error. For negative
values of the a parameter, the spring constant is essentially zero,
and anharmonic terms takes over. The potential is furthermore well
behaved in the limit a->0, where it has been implemented to linear
order in a for a < 0.001.
The following coefficients must be defined for each dihedral type via
the "dihedral_coeff"_dihedral_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
umin (energy)
theta (angle)
A (real number) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html,
"angle_cosine_shift_exp"_angle_cosine_shift_exp.html
[Default:] none
diff --git a/doc/src/dihedral_fourier.txt b/doc/src/dihedral_fourier.txt
index 5682309b8..da892b59d 100644
--- a/doc/src/dihedral_fourier.txt
+++ b/doc/src/dihedral_fourier.txt
@@ -1,77 +1,77 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style fourier command :h3
dihedral_style fourier/omp command :h3
[Syntax:]
dihedral_style fourier :pre
[Examples:]
dihedral_style fourier
dihedral_coeff 1 3 -0.846200 3 0.0 7.578800 1 0 0.138000 2 -180.0 :pre
[Description:]
The {fourier} dihedral style uses the potential:
:c,image(Eqs/dihedral_fourier.jpg)
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
m (integer >=1)
K1 (energy)
n1 (integer >= 0)
d1 (degrees)
\[...\]
Km (energy)
nm (integer >= 0)
dm (degrees) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
diff --git a/doc/src/dihedral_harmonic.txt b/doc/src/dihedral_harmonic.txt
index c763dcce2..d9a48ff38 100644
--- a/doc/src/dihedral_harmonic.txt
+++ b/doc/src/dihedral_harmonic.txt
@@ -1,86 +1,86 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style harmonic command :h3
dihedral_style harmonic/intel command :h3
dihedral_style harmonic/omp command :h3
[Syntax:]
dihedral_style harmonic :pre
[Examples:]
dihedral_style harmonic
dihedral_coeff 1 80.0 1 2 :pre
[Description:]
The {harmonic} dihedral style uses the potential
:c,image(Eqs/dihedral_harmonic.jpg)
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K (energy)
d (+1 or -1)
n (integer >= 0) :ul
NOTE: Here are important points to take note of when defining LAMMPS
dihedral coefficients for the harmonic style, so that they are
compatible with how harmonic dihedrals are defined by other force
fields:
The LAMMPS convention is that the trans position = 180 degrees, while
in some force fields trans = 0 degrees. :ulb,l
Some force fields reverse the sign convention on {d}. :l
Some force fields let {n} be positive or negative which corresponds to
{d} = 1 or -1 for the harmonic style. :l
:ule
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
diff --git a/doc/src/dihedral_helix.txt b/doc/src/dihedral_helix.txt
index fced983db..1e907557b 100644
--- a/doc/src/dihedral_helix.txt
+++ b/doc/src/dihedral_helix.txt
@@ -1,84 +1,84 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style helix command :h3
dihedral_style helix/omp command :h3
[Syntax:]
dihedral_style helix :pre
[Examples:]
dihedral_style helix
dihedral_coeff 1 80.0 100.0 40.0 :pre
[Description:]
The {helix} dihedral style uses the potential
:c,image(Eqs/dihedral_helix.jpg)
This coarse-grain dihedral potential is described in "(Guo)"_#Guo.
For dihedral angles in the helical region, the energy function is
represented by a standard potential consisting of three minima, one
corresponding to the trans (t) state and the other to gauche states
(g+ and g-). The paper describes how the A,B,C parameters are chosen
so as to balance secondary (largely driven by local interactions) and
tertiary structure (driven by long-range interactions).
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
A (energy)
B (energy)
C (energy) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
:line
:link(Guo)
[(Guo)] Guo and Thirumalai, Journal of Molecular Biology, 263, 323-43 (1996).
diff --git a/doc/src/dihedral_multi_harmonic.txt b/doc/src/dihedral_multi_harmonic.txt
index 5774a6768..7d3c2ea08 100644
--- a/doc/src/dihedral_multi_harmonic.txt
+++ b/doc/src/dihedral_multi_harmonic.txt
@@ -1,73 +1,73 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style multi/harmonic command :h3
dihedral_style multi/harmonic/omp command :h3
[Syntax:]
dihedral_style multi/harmonic :pre
[Examples:]
dihedral_style multi/harmonic
dihedral_coeff 1 20 20 20 20 20 :pre
[Description:]
The {multi/harmonic} dihedral style uses the potential
:c,image(Eqs/dihedral_multi_harmonic.jpg)
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
A1 (energy)
A2 (energy)
A3 (energy)
A4 (energy)
A5 (energy) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
diff --git a/doc/src/dihedral_nharmonic.txt b/doc/src/dihedral_nharmonic.txt
index 0df28a05d..8392d8389 100644
--- a/doc/src/dihedral_nharmonic.txt
+++ b/doc/src/dihedral_nharmonic.txt
@@ -1,73 +1,73 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style nharmonic command :h3
dihedral_style nharmonic/omp command :h3
[Syntax:]
dihedral_style nharmonic :pre
[Examples:]
dihedral_style nharmonic
dihedral_coeff 3 10.0 20.0 30.0 :pre
[Description:]
The {nharmonic} dihedral style uses the potential:
:c,image(Eqs/dihedral_nharmonic.jpg)
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
n (integer >=1)
A1 (energy)
A2 (energy)
...
An (energy) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
diff --git a/doc/src/dihedral_opls.txt b/doc/src/dihedral_opls.txt
index afcc5d351..d1a6ba3ff 100644
--- a/doc/src/dihedral_opls.txt
+++ b/doc/src/dihedral_opls.txt
@@ -1,86 +1,86 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style opls command :h3
dihedral_style opls/intel command :h3
dihedral_style opls/kk command :h3
dihedral_style opls/omp command :h3
[Syntax:]
dihedral_style opls :pre
[Examples:]
dihedral_style opls
dihedral_coeff 1 1.740 -0.157 0.279 0.00 # CT-CT-CT-CT
dihedral_coeff 2 0.000 0.000 0.366 0.000 # CT-CT-CT-HC
dihedral_coeff 3 0.000 0.000 0.318 0.000 # HC-CT-CT-HC :pre
[Description:]
The {opls} dihedral style uses the potential
:c,image(Eqs/dihedral_opls.jpg)
Note that the usual 1/2 factor is not included in the K values.
This dihedral potential is used in the OPLS force field and is
described in "(Watkins)"_#Watkins.
The following coefficients must be defined for each dihedral type via the
"dihedral_coeff"_dihedral_coeff.html command as in the example above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands:
K1 (energy)
K2 (energy)
K3 (energy)
K4 (energy) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This dihedral style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
:line
:link(Watkins)
[(Watkins)] Watkins and Jorgensen, J Phys Chem A, 105, 4118-4125 (2001).
diff --git a/doc/src/dihedral_quadratic.txt b/doc/src/dihedral_quadratic.txt
index 526b469f6..ca2f5aed4 100644
--- a/doc/src/dihedral_quadratic.txt
+++ b/doc/src/dihedral_quadratic.txt
@@ -1,75 +1,75 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
dihedral_style quadratic command :h3
dihedral_style quadratic/omp command :h3
[Syntax:]
dihedral_style quadratic :pre
[Examples:]
dihedral_style quadratic
dihedral_coeff 100.0 80.0 :pre
[Description:]
The {quadratic} dihedral style uses the potential:
:c,image(Eqs/dihedral_quadratic.jpg)
This dihedral potential can be used to keep a dihedral in a predefined
value (cis=zero, right-hand convention is used).
The following coefficients must be defined for each dihedral type via
the "dihedral_coeff"_dihedral_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy/radian^2)
phi0 (degrees) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"dihedral_coeff"_dihedral_coeff.html
[Default:] none
diff --git a/doc/src/echo.txt b/doc/src/echo.txt
index 8ef8ad05f..3141c7a71 100644
--- a/doc/src/echo.txt
+++ b/doc/src/echo.txt
@@ -1,38 +1,38 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
echo command :h3
[Syntax:]
echo style :pre
style = {none} or {screen} or {log} or {both} :ul
[Examples:]
echo both
echo log :pre
[Description:]
This command determines whether LAMMPS echoes each input script
command to the screen and/or log file as it is read and processed. If
an input script has errors, it can be useful to look at echoed output
to see the last command processed.
-The "command-line switch"_Section_start.html#start_5 -echo can be used
+The "command-line switch"_Section_start.html#start_6 -echo can be used
in place of this command.
[Restrictions:] none
[Related commands:] none
[Default:]
echo log :pre
diff --git a/doc/src/fix_addforce.txt b/doc/src/fix_addforce.txt
index da9f98a6d..1cc0a1533 100644
--- a/doc/src/fix_addforce.txt
+++ b/doc/src/fix_addforce.txt
@@ -1,176 +1,176 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix addforce command :h3
[Syntax:]
fix ID group-ID addforce fx fy fz keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
addforce = style name of this fix command :l
fx,fy,fz = force component values (force units) :l
any of fx,fy,fz can be a variable (see below) :pre
zero or more keyword/value pairs may be appended to args :l
keyword = {every} or {region} or {energy} :l
{every} value = Nevery
Nevery = add force every this many timesteps
{region} value = region-ID
region-ID = ID of region atoms must be in to have added force
{energy} value = v_name
v_name = variable with name that calculates the potential energy of each atom in the added force field :pre
:ule
[Examples:]
fix kick flow addforce 1.0 0.0 0.0
fix kick flow addforce 1.0 0.0 v_oscillate
fix ff boundary addforce 0.0 0.0 v_push energy v_espace :pre
[Description:]
Add fx,fy,fz to the corresponding component of force for each atom in
the group. This command can be used to give an additional push to
atoms in a simulation, such as for a simulation of Poiseuille flow in
a channel.
Any of the 3 quantities defining the force components can be specified
as an equal-style or atom-style "variable"_variable.html, namely {fx},
{fy}, {fz}. If the value is a variable, it should be specified as
v_name, where name is the variable name. In this case, the variable
will be evaluated each timestep, and its value(s) used to determine
the force component.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent force field.
Atom-style variables can specify the same formulas as equal-style
variables but can also include per-atom values, such as atom
coordinates. Thus it is easy to specify a spatially-dependent force
field with optional time-dependence as well.
If the {every} keyword is used, the {Nevery} setting determines how
often the forces are applied. The default value is 1, for every
timestep.
If the {region} keyword is used, the atom must also be in the
specified geometric "region"_region.html in order to have force added
to it.
:line
Adding a force to atoms implies a change in their potential energy as
they move due to the applied force field. For dynamics via the "run"
command, this energy can be optionally added to the system's potential
energy for thermodynamic output (see below). For energy minimization
via the "minimize" command, this energy must be added to the system's
potential energy to formulate a self-consistent minimization problem
(see below).
The {energy} keyword is not allowed if the added force is a constant
vector F = (fx,fy,fz), with all components defined as numeric
constants and not as variables. This is because LAMMPS can compute
the energy for each atom directly as E = -x dot F = -(x*fx + y*fy +
z*fz), so that -Grad(E) = F.
The {energy} keyword is optional if the added force is defined with
one or more variables, and if you are performing dynamics via the
"run"_run.html command. If the keyword is not used, LAMMPS will set
the energy to 0.0, which is typically fine for dynamics.
The {energy} keyword is required if the added force is defined with
one or more variables, and you are performing energy minimization via
the "minimize" command. The keyword specifies the name of an
atom-style "variable"_variable.html which is used to compute the
energy of each atom as function of its position. Like variables used
for {fx}, {fy}, {fz}, the energy variable is specified as v_name,
where name is the variable name.
Note that when the {energy} keyword is used during an energy
minimization, you must insure that the formula defined for the
atom-style "variable"_variable.html is consistent with the force
variable formulas, i.e. that -Grad(E) = F. For example, if the force
were a spring-like F = kx, then the energy formula should be E =
-0.5kx^2. If you don't do this correctly, the minimization will not
converge properly.
:line
Styles with a suffix are functionally the same as the corresponding
style without the suffix. They have been optimized to run faster,
depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the potential "energy" inferred by the added force to the
system's potential energy as part of "thermodynamic
output"_thermo_style.html. This is a fictitious quantity but is
needed so that the "minimize"_minimize.html command can include the
forces added by this fix in a consistent manner. I.e. there is a
decrease in potential energy when atoms move in the direction of the
added force.
The "fix_modify"_fix_modify.html {respa} option is supported by this
fix. This allows to set at which level of the "r-RESPA"_run_style.html
integrator the fix is adding its forces. Default is the outermost
level.
This fix computes a global scalar and a global 3-vector of forces,
which can be accessed by various "output
commands"_Section_howto.html#howto_15. The scalar is the potential
energy discussed above. The vector is the total force on the group of
atoms before the forces on individual atoms are changed by the fix.
The scalar and vector values calculated by this fix are "extensive".
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command.
The forces due to this fix are imposed during an energy minimization,
invoked by the "minimize"_minimize.html command. You should not
specify force components with a variable that has time-dependence for
use with a minimizer, since the minimizer increments the timestep as
the iteration count during the minimization.
NOTE: If you want the fictitious potential energy associated with the
added forces to be included in the total potential energy of the
system (the quantity being minimized), you MUST enable the
"fix_modify"_fix_modify.html {energy} option for this fix.
[Restrictions:] none
[Related commands:]
"fix setforce"_fix_setforce.html, "fix aveforce"_fix_aveforce.html
[Default:]
The option default for the every keyword is every = 1.
diff --git a/doc/src/fix_aveforce.txt b/doc/src/fix_aveforce.txt
index d980e9a21..5d7dec3e6 100644
--- a/doc/src/fix_aveforce.txt
+++ b/doc/src/fix_aveforce.txt
@@ -1,118 +1,118 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix aveforce command :h3
[Syntax:]
fix ID group-ID aveforce fx fy fz keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
aveforce = style name of this fix command :l
fx,fy,fz = force component values (force units) :l
any of fx,fy,fz can be a variable (see below) :pre
zero or more keyword/value pairs may be appended to args :l
keyword = {region} :l
{region} value = region-ID
region-ID = ID of region atoms must be in to have added force :pre
:ule
[Examples:]
fix pressdown topwall aveforce 0.0 -1.0 0.0
fix 2 bottomwall aveforce NULL -1.0 0.0 region top
fix 2 bottomwall aveforce NULL -1.0 v_oscillate region top :pre
[Description:]
Apply an additional external force to a group of atoms in such a way
that every atom experiences the same force. This is useful for
pushing on wall or boundary atoms so that the structure of the wall
does not change over time.
The existing force is averaged for the group of atoms, component by
component. The actual force on each atom is then set to the average
value plus the component specified in this command. This means each
atom in the group receives the same force.
Any of the fx,fy,fz values can be specified as NULL which means the
force in that dimension is not changed. Note that this is not the
same as specifying a 0.0 value, since that sets all forces to the same
average value without adding in any additional force.
Any of the 3 quantities defining the force components can be specified
as an equal-style "variable"_variable.html, namely {fx}, {fy}, {fz}.
If the value is a variable, it should be specified as v_name, where
name is the variable name. In this case, the variable will be
evaluated each timestep, and its value used to determine the average
force.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent average force.
If the {region} keyword is used, the atom must also be in the
specified geometric "region"_region.html in order to have force added
to it.
:line
Styles with a suffix are functionally the same as the corresponding
style without the suffix. They have been optimized to run faster,
depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html.
The "fix_modify"_fix_modify.html {respa} option is supported by this
fix. This allows to set at which level of the "r-RESPA"_run_style.html
integrator the fix is adding its forces. Default is the outermost level.
This fix computes a global 3-vector of forces, which can be accessed
by various "output commands"_Section_howto.html#howto_15. This is the
total force on the group of atoms before the forces on individual
atoms are changed by the fix. The vector values calculated by this
fix are "extensive".
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command.
The forces due to this fix are imposed during an energy minimization,
invoked by the "minimize"_minimize.html command. You should not
specify force components with a variable that has time-dependence for
use with a minimizer, since the minimizer increments the timestep as
the iteration count during the minimization.
[Restrictions:] none
[Related commands:]
"fix setforce"_fix_setforce.html, "fix addforce"_fix_addforce.html
[Default:] none
diff --git a/doc/src/fix_deform.txt b/doc/src/fix_deform.txt
index d3254eece..63d872ede 100644
--- a/doc/src/fix_deform.txt
+++ b/doc/src/fix_deform.txt
@@ -1,596 +1,596 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix deform command :h3
fix deform/kk command :h3
[Syntax:]
fix ID group-ID deform N parameter args ... keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
deform = style name of this fix command :l
N = perform box deformation every this many timesteps :l
one or more parameter/arg pairs may be appended :l
parameter = {x} or {y} or {z} or {xy} or {xz} or {yz}
{x}, {y}, {z} args = style value(s)
style = {final} or {delta} or {scale} or {vel} or {erate} or {trate} or {volume} or {wiggle} or {variable}
{final} values = lo hi
lo hi = box boundaries at end of run (distance units)
{delta} values = dlo dhi
dlo dhi = change in box boundaries at end of run (distance units)
{scale} values = factor
factor = multiplicative factor for change in box length at end of run
{vel} value = V
V = change box length at this velocity (distance/time units),
effectively an engineering strain rate
{erate} value = R
R = engineering strain rate (1/time units)
{trate} value = R
R = true strain rate (1/time units)
{volume} value = none = adjust this dim to preserve volume of system
{wiggle} values = A Tp
A = amplitude of oscillation (distance units)
Tp = period of oscillation (time units)
{variable} values = v_name1 v_name2
v_name1 = variable with name1 for box length change as function of time
v_name2 = variable with name2 for change rate as function of time
{xy}, {xz}, {yz} args = style value
style = {final} or {delta} or {vel} or {erate} or {trate} or {wiggle}
{final} value = tilt
tilt = tilt factor at end of run (distance units)
{delta} value = dtilt
dtilt = change in tilt factor at end of run (distance units)
{vel} value = V
V = change tilt factor at this velocity (distance/time units),
effectively an engineering shear strain rate
{erate} value = R
R = engineering shear strain rate (1/time units)
{trate} value = R
R = true shear strain rate (1/time units)
{wiggle} values = A Tp
A = amplitude of oscillation (distance units)
Tp = period of oscillation (time units)
{variable} values = v_name1 v_name2
v_name1 = variable with name1 for tilt change as function of time
v_name2 = variable with name2 for change rate as function of time :pre
zero or more keyword/value pairs may be appended :l
keyword = {remap} or {flip} or {units} :l
{remap} value = {x} or {v} or {none}
x = remap coords of atoms in group into deforming box
v = remap velocities of all atoms when they cross periodic boundaries
none = no remapping of x or v
{flip} value = {yes} or {no}
allow or disallow box flips when it becomes highly skewed
{units} value = {lattice} or {box}
lattice = distances are defined in lattice units
box = distances are defined in simulation box units :pre
:ule
[Examples:]
fix 1 all deform 1 x final 0.0 9.0 z final 0.0 5.0 units box
fix 1 all deform 1 x trate 0.1 y volume z volume
fix 1 all deform 1 xy erate 0.001 remap v
fix 1 all deform 10 y delta -0.5 0.5 xz vel 1.0 :pre
[Description:]
Change the volume and/or shape of the simulation box during a dynamics
run. Orthogonal simulation boxes have 3 adjustable parameters
(x,y,z). Triclinic (non-orthogonal) simulation boxes have 6
adjustable parameters (x,y,z,xy,xz,yz). Any or all of them can be
adjusted independently and simultaneously by this command. This fix
can be used to perform non-equilibrium MD (NEMD) simulations of a
continuously strained system. See the "fix
nvt/sllod"_fix_nvt_sllod.html and "compute
temp/deform"_compute_temp_deform.html commands for more details.
For the {x}, {y}, {z} parameters, the associated dimension cannot be
shrink-wrapped. For the {xy}, {yz}, {xz} parameters, the associated
2nd dimension cannot be shrink-wrapped. Dimensions not varied by this
command can be periodic or non-periodic. Dimensions corresponding to
unspecified parameters can also be controlled by a "fix
npt"_fix_nh.html or "fix nph"_fix_nh.html command.
The size and shape of the simulation box at the beginning of the
simulation run were either specified by the
"create_box"_create_box.html or "read_data"_read_data.html or
"read_restart"_read_restart.html command used to setup the simulation
initially if it is the first run, or they are the values from the end
of the previous run. The "create_box"_create_box.html, "read
data"_read_data.html, and "read_restart"_read_restart.html commands
specify whether the simulation box is orthogonal or non-orthogonal
(triclinic) and explain the meaning of the xy,xz,yz tilt factors. If
fix deform changes the xy,xz,yz tilt factors, then the simulation box
must be triclinic, even if its initial tilt factors are 0.0.
As described below, the desired simulation box size and shape at the
end of the run are determined by the parameters of the fix deform
command. Every Nth timestep during the run, the simulation box is
expanded, contracted, or tilted to ramped values between the initial
and final values.
:line
For the {x}, {y}, and {z} parameters, this is the meaning of their
styles and values.
The {final}, {delta}, {scale}, {vel}, and {erate} styles all change
the specified dimension of the box via "constant displacement" which
is effectively a "constant engineering strain rate". This means the
box dimension changes linearly with time from its initial to final
value.
For style {final}, the final lo and hi box boundaries of a dimension
are specified. The values can be in lattice or box distance units.
See the discussion of the units keyword below.
For style {delta}, plus or minus changes in the lo/hi box boundaries
of a dimension are specified. The values can be in lattice or box
distance units. See the discussion of the units keyword below.
For style {scale}, a multiplicative factor to apply to the box length
of a dimension is specified. For example, if the initial box length
is 10, and the factor is 1.1, then the final box length will be 11. A
factor less than 1.0 means compression.
For style {vel}, a velocity at which the box length changes is
specified in units of distance/time. This is effectively a "constant
engineering strain rate", where rate = V/L0 and L0 is the initial box
length. The distance can be in lattice or box distance units. See
the discussion of the units keyword below. For example, if the
initial box length is 100 Angstroms, and V is 10 Angstroms/psec, then
after 10 psec, the box length will have doubled. After 20 psec, it
will have tripled.
The {erate} style changes a dimension of the box at a "constant
engineering strain rate". The units of the specified strain rate are
1/time. See the "units"_units.html command for the time units
associated with different choices of simulation units,
e.g. picoseconds for "metal" units). Tensile strain is unitless and
is defined as delta/L0, where L0 is the original box length and delta
is the change relative to the original length. The box length L as a
function of time will change as
L(t) = L0 (1 + erate*dt) :pre
where dt is the elapsed time (in time units). Thus if {erate} R is
specified as 0.1 and time units are picoseconds, this means the box
length will increase by 10% of its original length every picosecond.
I.e. strain after 1 psec = 0.1, strain after 2 psec = 0.2, etc. R =
-0.01 means the box length will shrink by 1% of its original length
every picosecond. Note that for an "engineering" rate the change is
based on the original box length, so running with R = 1 for 10
picoseconds expands the box length by a factor of 11 (strain of 10),
which is different that what the {trate} style would induce.
The {trate} style changes a dimension of the box at a "constant true
strain rate". Note that this is not an "engineering strain rate", as
the other styles are. Rather, for a "true" rate, the rate of change
is constant, which means the box dimension changes non-linearly with
time from its initial to final value. The units of the specified
strain rate are 1/time. See the "units"_units.html command for the
time units associated with different choices of simulation units,
e.g. picoseconds for "metal" units). Tensile strain is unitless and
is defined as delta/L0, where L0 is the original box length and delta
is the change relative to the original length.
The box length L as a function of time will change as
L(t) = L0 exp(trate*dt) :pre
where dt is the elapsed time (in time units). Thus if {trate} R is
specified as ln(1.1) and time units are picoseconds, this means the
box length will increase by 10% of its current (not original) length
every picosecond. I.e. strain after 1 psec = 0.1, strain after 2 psec
= 0.21, etc. R = ln(2) or ln(3) means the box length will double or
triple every picosecond. R = ln(0.99) means the box length will
shrink by 1% of its current length every picosecond. Note that for a
"true" rate the change is continuous and based on the current length,
so running with R = ln(2) for 10 picoseconds does not expand the box
length by a factor of 11 as it would with {erate}, but by a factor of
1024 since the box length will double every picosecond.
Note that to change the volume (or cross-sectional area) of the
simulation box at a constant rate, you can change multiple dimensions
via {erate} or {trate}. E.g. to double the box volume in a picosecond
picosecond, you could set "x erate M", "y erate M", "z erate M", with
M = pow(2,1/3) - 1 = 0.26, since if each box dimension grows by 26%,
the box volume doubles. Or you could set "x trate M", "y trate M", "z
trate M", with M = ln(1.26) = 0.231, and the box volume would double
every picosecond.
The {volume} style changes the specified dimension in such a way that
the box volume remains constant while other box dimensions are changed
explicitly via the styles discussed above. For example, "x scale 1.1
y scale 1.1 z volume" will shrink the z box length as the x,y box
lengths increase, to keep the volume constant (product of x,y,z
lengths). If "x scale 1.1 z volume" is specified and parameter {y} is
unspecified, then the z box length will shrink as x increases to keep
the product of x,z lengths constant. If "x scale 1.1 y volume z
volume" is specified, then both the y,z box lengths will shrink as x
increases to keep the volume constant (product of x,y,z lengths). In
this case, the y,z box lengths shrink so as to keep their relative
aspect ratio constant.
For solids or liquids, note that when one dimension of the box is
expanded via fix deform (i.e. tensile strain), it may be physically
undesirable to hold the other 2 box lengths constant (unspecified by
fix deform) since that implies a density change. Using the {volume}
style for those 2 dimensions to keep the box volume constant may make
more physical sense, but may also not be correct for materials and
potentials whose Poisson ratio is not 0.5. An alternative is to use
"fix npt aniso"_fix_nh.html with zero applied pressure on those 2
dimensions, so that they respond to the tensile strain dynamically.
The {wiggle} style oscillates the specified box length dimension
sinusoidally with the specified amplitude and period. I.e. the box
length L as a function of time is given by
L(t) = L0 + A sin(2*pi t/Tp) :pre
where L0 is its initial length. If the amplitude A is a positive
number the box initially expands, then contracts, etc. If A is
negative then the box initially contracts, then expands, etc. The
amplitude can be in lattice or box distance units. See the discussion
of the units keyword below.
The {variable} style changes the specified box length dimension by
evaluating a variable, which presumably is a function of time. The
variable with {name1} must be an "equal-style variable"_variable.html
and should calculate a change in box length in units of distance.
Note that this distance is in box units, not lattice units; see the
discussion of the {units} keyword below. The formula associated with
variable {name1} can reference the current timestep. Note that it
should return the "change" in box length, not the absolute box length.
This means it should evaluate to 0.0 when invoked on the initial
timestep of the run following the definition of fix deform. It should
evaluate to a value > 0.0 to dilate the box at future times, or a
value < 0.0 to compress the box.
The variable {name2} must also be an "equal-style
variable"_variable.html and should calculate the rate of box length
change, in units of distance/time, i.e. the time-derivative of the
{name1} variable. This quantity is used internally by LAMMPS to reset
atom velocities when they cross periodic boundaries. It is computed
internally for the other styles, but you must provide it when using an
arbitrary variable.
Here is an example of using the {variable} style to perform the same
box deformation as the {wiggle} style formula listed above, where we
assume that the current timestep = 0.
variable A equal 5.0
variable Tp equal 10.0
variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)"
variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)"
fix 2 all deform 1 x variable v_displace v_rate remap v :pre
For the {scale}, {vel}, {erate}, {trate}, {volume}, {wiggle}, and
{variable} styles, the box length is expanded or compressed around its
mid point.
:line
For the {xy}, {xz}, and {yz} parameters, this is the meaning of their
styles and values. Note that changing the tilt factors of a triclinic
box does not change its volume.
The {final}, {delta}, {vel}, and {erate} styles all change the shear
strain at a "constant engineering shear strain rate". This means the
tilt factor changes linearly with time from its initial to final
value.
For style {final}, the final tilt factor is specified. The value
can be in lattice or box distance units. See the discussion of the
units keyword below.
For style {delta}, a plus or minus change in the tilt factor is
specified. The value can be in lattice or box distance units. See
the discussion of the units keyword below.
For style {vel}, a velocity at which the tilt factor changes is
specified in units of distance/time. This is effectively an
"engineering shear strain rate", where rate = V/L0 and L0 is the
initial box length perpendicular to the direction of shear. The
distance can be in lattice or box distance units. See the discussion
of the units keyword below. For example, if the initial tilt factor
is 5 Angstroms, and the V is 10 Angstroms/psec, then after 1 psec, the
tilt factor will be 15 Angstroms. After 2 psec, it will be 25
Angstroms.
The {erate} style changes a tilt factor at a "constant engineering
shear strain rate". The units of the specified shear strain rate are
1/time. See the "units"_units.html command for the time units
associated with different choices of simulation units,
e.g. picoseconds for "metal" units). Shear strain is unitless and is
defined as offset/length, where length is the box length perpendicular
to the shear direction (e.g. y box length for xy deformation) and
offset is the displacement distance in the shear direction (e.g. x
direction for xy deformation) from the unstrained orientation.
The tilt factor T as a function of time will change as
T(t) = T0 + L0*erate*dt :pre
where T0 is the initial tilt factor, L0 is the original length of the
box perpendicular to the shear direction (e.g. y box length for xy
deformation), and dt is the elapsed time (in time units). Thus if
{erate} R is specified as 0.1 and time units are picoseconds, this
means the shear strain will increase by 0.1 every picosecond. I.e. if
the xy shear strain was initially 0.0, then strain after 1 psec = 0.1,
strain after 2 psec = 0.2, etc. Thus the tilt factor would be 0.0 at
time 0, 0.1*ybox at 1 psec, 0.2*ybox at 2 psec, etc, where ybox is the
original y box length. R = 1 or 2 means the tilt factor will increase
by 1 or 2 every picosecond. R = -0.01 means a decrease in shear
strain by 0.01 every picosecond.
The {trate} style changes a tilt factor at a "constant true shear
strain rate". Note that this is not an "engineering shear strain
rate", as the other styles are. Rather, for a "true" rate, the rate
of change is constant, which means the tilt factor changes
non-linearly with time from its initial to final value. The units of
the specified shear strain rate are 1/time. See the
"units"_units.html command for the time units associated with
different choices of simulation units, e.g. picoseconds for "metal"
units). Shear strain is unitless and is defined as offset/length,
where length is the box length perpendicular to the shear direction
(e.g. y box length for xy deformation) and offset is the displacement
distance in the shear direction (e.g. x direction for xy deformation)
from the unstrained orientation.
The tilt factor T as a function of time will change as
T(t) = T0 exp(trate*dt) :pre
where T0 is the initial tilt factor and dt is the elapsed time (in
time units). Thus if {trate} R is specified as ln(1.1) and time units
are picoseconds, this means the shear strain or tilt factor will
increase by 10% every picosecond. I.e. if the xy shear strain was
initially 0.1, then strain after 1 psec = 0.11, strain after 2 psec =
0.121, etc. R = ln(2) or ln(3) means the tilt factor will double or
triple every picosecond. R = ln(0.99) means the tilt factor will
shrink by 1% every picosecond. Note that the change is continuous, so
running with R = ln(2) for 10 picoseconds does not change the tilt
factor by a factor of 10, but by a factor of 1024 since it doubles
every picosecond. Note that the initial tilt factor must be non-zero
to use the {trate} option.
Note that shear strain is defined as the tilt factor divided by the
perpendicular box length. The {erate} and {trate} styles control the
tilt factor, but assume the perpendicular box length remains constant.
If this is not the case (e.g. it changes due to another fix deform
parameter), then this effect on the shear strain is ignored.
The {wiggle} style oscillates the specified tilt factor sinusoidally
with the specified amplitude and period. I.e. the tilt factor T as a
function of time is given by
T(t) = T0 + A sin(2*pi t/Tp) :pre
where T0 is its initial value. If the amplitude A is a positive
number the tilt factor initially becomes more positive, then more
negative, etc. If A is negative then the tilt factor initially
becomes more negative, then more positive, etc. The amplitude can be
in lattice or box distance units. See the discussion of the units
keyword below.
The {variable} style changes the specified tilt factor by evaluating a
variable, which presumably is a function of time. The variable with
{name1} must be an "equal-style variable"_variable.html and should
calculate a change in tilt in units of distance. Note that this
distance is in box units, not lattice units; see the discussion of the
{units} keyword below. The formula associated with variable {name1}
can reference the current timestep. Note that it should return the
"change" in tilt factor, not the absolute tilt factor. This means it
should evaluate to 0.0 when invoked on the initial timestep of the run
following the definition of fix deform.
The variable {name2} must also be an "equal-style
variable"_variable.html and should calculate the rate of tilt change,
in units of distance/time, i.e. the time-derivative of the {name1}
variable. This quantity is used internally by LAMMPS to reset atom
velocities when they cross periodic boundaries. It is computed
internally for the other styles, but you must provide it when using an
arbitrary variable.
Here is an example of using the {variable} style to perform the same
box deformation as the {wiggle} style formula listed above, where we
assume that the current timestep = 0.
variable A equal 5.0
variable Tp equal 10.0
variable displace equal "v_A * sin(2*PI * step*dt/v_Tp)"
variable rate equal "2*PI*v_A/v_Tp * cos(2*PI * step*dt/v_Tp)"
fix 2 all deform 1 xy variable v_displace v_rate remap v :pre
:line
All of the tilt styles change the xy, xz, yz tilt factors during a
simulation. In LAMMPS, tilt factors (xy,xz,yz) for triclinic boxes
are normally bounded by half the distance of the parallel box length.
See the discussion of the {flip} keyword below, to allow this bound to
be exceeded, if desired.
For example, if xlo = 2 and xhi = 12, then the x box length is 10 and
the xy tilt factor must be between -5 and 5. Similarly, both xz and
yz must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is
not a limitation, since if the maximum tilt factor is 5 (as in this
example), then configurations with tilt = ..., -15, -5, 5, 15, 25,
... are all equivalent.
To obey this constraint and allow for large shear deformations to be
applied via the {xy}, {xz}, or {yz} parameters, the following
algorithm is used. If {prd} is the associated parallel box length (10
in the example above), then if the tilt factor exceeds the accepted
range of -5 to 5 during the simulation, then the box is flipped to the
other limit (an equivalent box) and the simulation continues. Thus
for this example, if the initial xy tilt factor was 0.0 and "xy final
100.0" was specified, then during the simulation the xy tilt factor
would increase from 0.0 to 5.0, the box would be flipped so that the
tilt factor becomes -5.0, the tilt factor would increase from -5.0 to
5.0, the box would be flipped again, etc. The flip occurs 10 times
and the final tilt factor at the end of the simulation would be 0.0.
During each flip event, atoms are remapped into the new box in the
appropriate manner.
The one exception to this rule is if the 1st dimension in the tilt
factor (x for xy) is non-periodic. In that case, the limits on the
tilt factor are not enforced, since flipping the box in that dimension
does not change the atom positions due to non-periodicity. In this
mode, if you tilt the system to extreme angles, the simulation will
simply become inefficient due to the highly skewed simulation box.
:line
Each time the box size or shape is changed, the {remap} keyword
determines whether atom positions are remapped to the new box. If
{remap} is set to {x} (the default), atoms in the fix group are
remapped; otherwise they are not. Note that their velocities are not
changed, just their positions are altered. If {remap} is set to {v},
then any atom in the fix group that crosses a periodic boundary will
have a delta added to its velocity equal to the difference in
velocities between the lo and hi boundaries. Note that this velocity
difference can include tilt components, e.g. a delta in the x velocity
when an atom crosses the y periodic boundary. If {remap} is set to
{none}, then neither of these remappings take place.
Conceptually, setting {remap} to {x} forces the atoms to deform via an
affine transformation that exactly matches the box deformation. This
setting is typically appropriate for solids. Note that though the
atoms are effectively "moving" with the box over time, it is not due
to their having a velocity that tracks the box change, but only due to
the remapping. By contrast, setting {remap} to {v} is typically
appropriate for fluids, where you want the atoms to respond to the
change in box size/shape on their own and acquire a velocity that
matches the box change, so that their motion will naturally track the
box without explicit remapping of their coordinates.
NOTE: When non-equilibrium MD (NEMD) simulations are performed using
this fix, the option "remap v" should normally be used. This is
because "fix nvt/sllod"_fix_nvt_sllod.html adjusts the atom positions
and velocities to induce a velocity profile that matches the changing
box size/shape. Thus atom coordinates should NOT be remapped by fix
deform, but velocities SHOULD be when atoms cross periodic boundaries,
since that is consistent with maintaining the velocity profile already
created by fix nvt/sllod. LAMMPS will warn you if the {remap} setting
is not consistent with fix nvt/sllod.
NOTE: For non-equilibrium MD (NEMD) simulations using "remap v" it is
usually desirable that the fluid (or flowing material, e.g. granular
particles) stream with a velocity profile consistent with the
deforming box. As mentioned above, using a thermostat such as "fix
nvt/sllod"_fix_nvt_sllod.html or "fix lavgevin"_fix_langevin.html
(with a bias provided by "compute
temp/deform"_compute_temp_deform.html), will typically accomplish
that. If you do not use a thermostat, then there is no driving force
pushing the atoms to flow in a manner consistent with the deforming
box. E.g. for a shearing system the box deformation velocity may vary
from 0 at the bottom to 10 at the top of the box. But the stream
velocity profile of the atoms may vary from -5 at the bottom to +5 at
the top. You can monitor these effects using the "fix
ave/chunk"_fix_ave_chunk.html, "compute
temp/deform"_compute_temp_deform.html, and "compute
temp/profile"_compute_temp_profile.html commands. One way to induce
atoms to stream consistent with the box deformation is to give them an
initial velocity profile, via the "velocity ramp"_velocity.html
command, that matches the box deformation rate. This also typically
helps the system come to equilibrium more quickly, even if a
thermostat is used.
NOTE: If a "fix rigid"_fix_rigid.html is defined for rigid bodies, and
{remap} is set to {x}, then the center-of-mass coordinates of rigid
bodies will be remapped to the changing simulation box. This will be
done regardless of whether atoms in the rigid bodies are in the fix
deform group or not. The velocity of the centers of mass are not
remapped even if {remap} is set to {v}, since "fix
nvt/sllod"_fix_nvt_sllod.html does not currently do anything special
for rigid particles. If you wish to perform a NEMD simulation of
rigid particles, you can either thermostat them independently or
include a background fluid and thermostat the fluid via "fix
nvt/sllod"_fix_nvt_sllod.html.
The {flip} keyword allows the tilt factors for a triclinic box to
exceed half the distance of the parallel box length, as discussed
above. If the {flip} value is set to {yes}, the bound is enforced by
flipping the box when it is exceeded. If the {flip} value is set to
{no}, the tilt will continue to change without flipping. Note that if
you apply large deformations, this means the box shape can tilt
dramatically LAMMPS will run less efficiently, due to the large volume
of communication needed to acquire ghost atoms around a processor's
irregular-shaped sub-domain. For extreme values of tilt, LAMMPS may
also lose atoms and generate an error.
The {units} keyword determines the meaning of the distance units used
to define various arguments. A {box} value selects standard distance
units as defined by the "units"_units.html command, e.g. Angstroms for
units = real or metal. A {lattice} value means the distance units are
in lattice spacings. The "lattice"_lattice.html command must have
been previously used to define the lattice spacing. Note that the
units choice also affects the {vel} style parameters since it is
defined in terms of distance/time. Also note that the units keyword
does not affect the {variable} style. You should use the {xlat},
{ylat}, {zlat} keywords of the "thermo_style"_thermo_style.html
command if you want to include lattice spacings in a variable formula.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix will restore the initial box settings from "binary restart
files"_restart.html, which allows the fix to be properly continue
deformation, when using the start/stop options of the "run"_run.html
command. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15.
This fix can perform deformation over multiple runs, using the {start}
and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
You cannot apply x, y, or z deformations to a dimension that is
shrink-wrapped via the "boundary"_boundary.html command.
You cannot apply xy, yz, or xz deformations to a 2nd dimension (y in
xy) that is shrink-wrapped via the "boundary"_boundary.html command.
[Related commands:]
"change_box"_change_box.html
[Default:]
The option defaults are remap = x, flip = yes, and units = lattice.
diff --git a/doc/src/fix_enforce2d.txt b/doc/src/fix_enforce2d.txt
index 1dce62003..5d04e9667 100644
--- a/doc/src/fix_enforce2d.txt
+++ b/doc/src/fix_enforce2d.txt
@@ -1,68 +1,68 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix enforce2d command :h3
[Syntax:]
fix ID group-ID enforce2d :pre
ID, group-ID are documented in "fix"_fix.html command
enforce2d = style name of this fix command :ul
[Examples:]
fix 5 all enforce2d :pre
[Description:]
Zero out the z-dimension velocity and force on each atom in the group.
This is useful when running a 2d simulation to insure that atoms do
not move from their initial z coordinate.
:line
Styles with a suffix are functionally the same as the corresponding
style without the suffix. They have been optimized to run faster,
depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
The forces due to this fix are imposed during an energy minimization,
invoked by the "minimize"_minimize.html command.
[Restrictions:] none
[Related commands:] none
[Default:] none
diff --git a/doc/src/fix_freeze.txt b/doc/src/fix_freeze.txt
index 6a4f6c2fc..a63ee4cb3 100644
--- a/doc/src/fix_freeze.txt
+++ b/doc/src/fix_freeze.txt
@@ -1,87 +1,87 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix freeze command :h3
[Syntax:]
fix ID group-ID freeze :pre
ID, group-ID are documented in "fix"_fix.html command
freeze = style name of this fix command :ul
[Examples:]
fix 2 bottom freeze :pre
[Description:]
Zero out the force and torque on a granular particle. This is useful
for preventing certain particles from moving in a simulation. The
"granular pair styles"_pair_gran.html also detect if this fix has been
defined and compute interactions between frozen and non-frozen
particles appropriately, as if the frozen particle has infinite mass.
A similar functionality for normal (point) particles can be obtained
using "fix setforce"_fix_setforce.html.
:line
Styles with a suffix are functionally the same as the corresponding
style without the suffix. They have been optimized to run faster,
depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix.
This fix computes a global 3-vector of forces, which can be accessed
by various "output commands"_Section_howto.html#howto_15. This is the
total force on the group of atoms before the forces on individual
atoms are changed by the fix. The vector values calculated by this
fix are "extensive".
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command. This fix is not invoked during "energy
minimization"_minimize.html.
[Restrictions:]
This fix is part of the GRANULAR package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
There can only be a single freeze fix defined. This is because other
the "granular pair styles"_pair_gran.html treat frozen particles
differently and need to be able to reference a single group to which
this fix is applied.
[Related commands:]
"atom_style sphere"_atom_style.html, "fix setforce"_fix_setforce.html
[Default:] none
diff --git a/doc/src/fix_gravity.txt b/doc/src/fix_gravity.txt
index 2cf1665c3..dae8ac5ed 100644
--- a/doc/src/fix_gravity.txt
+++ b/doc/src/fix_gravity.txt
@@ -1,144 +1,144 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix gravity command :h3
fix gravity/omp command :h3
[Syntax:]
fix ID group gravity magnitude style args :pre
ID, group are documented in "fix"_fix.html command :ulb,l
gravity = style name of this fix command :l
magnitude = size of acceleration (force/mass units) :l
magnitude can be a variable (see below) :l
style = {chute} or {spherical} or {gradient} or {vector} :l
{chute} args = angle
angle = angle in +x away from -z or -y axis in 3d/2d (in degrees)
angle can be a variable (see below)
{spherical} args = phi theta
phi = azimuthal angle from +x axis (in degrees)
theta = angle from +z or +y axis in 3d/2d (in degrees)
phi or theta can be a variable (see below)
{vector} args = x y z
x y z = vector direction to apply the acceleration
x or y or z can be a variable (see below) :pre
:ule
[Examples:]
fix 1 all gravity 1.0 chute 24.0
fix 1 all gravity v_increase chute 24.0
fix 1 all gravity 1.0 spherical 0.0 -180.0
fix 1 all gravity 10.0 spherical v_phi v_theta
fix 1 all gravity 100.0 vector 1 1 0 :pre
[Description:]
Impose an additional acceleration on each particle in the group. This
fix is typically used with granular systems to include a "gravity"
term acting on the macroscopic particles. More generally, it can
represent any kind of driving field, e.g. a pressure gradient inducing
a Poiseuille flow in a fluid. Note that this fix operates differently
than the "fix addforce"_fix_addforce.html command. The addforce fix
adds the same force to each atom, independent of its mass. This
command imparts the same acceleration to each atom (force/mass).
The {magnitude} of the acceleration is specified in force/mass units.
For granular systems (LJ units) this is typically 1.0. See the
"units"_units.html command for details.
Style {chute} is typically used for simulations of chute flow where
the specified {angle} is the chute angle, with flow occurring in the +x
direction. For 3d systems, the tilt is away from the z axis; for 2d
systems, the tilt is away from the y axis.
Style {spherical} allows an arbitrary 3d direction to be specified for
the acceleration vector. {Phi} and {theta} are defined in the usual
spherical coordinates. Thus for acceleration acting in the -z
direction, {theta} would be 180.0 (or -180.0). {Theta} = 90.0 and
{phi} = -90.0 would mean acceleration acts in the -y direction. For
2d systems, {phi} is ignored and {theta} is an angle in the xy plane
where {theta} = 0.0 is the y-axis.
Style {vector} imposes an acceleration in the vector direction given
by (x,y,z). Only the direction of the vector is important; it's
length is ignored. For 2d systems, the {z} component is ignored.
Any of the quantities {magnitude}, {angle}, {phi}, {theta}, {x}, {y},
{z} which define the gravitational magnitude and direction, can be
specified as an equal-style "variable"_variable.html. If the value is
a variable, it should be specified as v_name, where name is the
variable name. In this case, the variable will be evaluated each
timestep, and its value used to determine the quantity. You should
insure that the variable calculates a result in the appropriate units,
e.g. force/mass or degrees.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent gravitational
field.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the gravitational potential energy of the system to the
system's potential energy as part of "thermodynamic
output"_thermo_style.html.
The "fix_modify"_fix_modify.html {respa} option is supported by this
fix. This allows to set at which level of the "r-RESPA"_run_style.html
integrator the fix is adding its forces. Default is the outermost level.
This fix computes a global scalar which can be accessed by various
"output commands"_Section_howto.html#howto_15. This scalar is the
gravitational potential energy of the particles in the defined field,
namely mass * (g dot x) for each particles, where x and mass are the
particles position and mass, and g is the gravitational field. The
scalar value calculated by this fix is "extensive".
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command. This fix is not invoked during "energy
minimization"_minimize.html.
[Restrictions:] none
[Related commands:]
"atom_style sphere"_atom_style.html, "fix addforce"_fix_addforce.html
[Default:] none
diff --git a/doc/src/fix_langevin.txt b/doc/src/fix_langevin.txt
index 534d83f6a..93c73f5a5 100644
--- a/doc/src/fix_langevin.txt
+++ b/doc/src/fix_langevin.txt
@@ -1,344 +1,344 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix langevin command :h3
fix langevin/kk command :h3
[Syntax:]
fix ID group-ID langevin Tstart Tstop damp seed keyword values ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
langevin = style name of this fix command :l
Tstart,Tstop = desired temperature at start/end of run (temperature units) :l
Tstart can be a variable (see below) :l
damp = damping parameter (time units) :l
seed = random number seed to use for white noise (positive integer) :l
zero or more keyword/value pairs may be appended :l
keyword = {angmom} or {omega} or {scale} or {tally} or {zero} :l
{angmom} value = {no} or factor
{no} = do not thermostat rotational degrees of freedom via the angular momentum
factor = do thermostat rotational degrees of freedom via the angular momentum and apply numeric scale factor as discussed below
{gjf} value = {no} or {yes}
{no} = use standard formulation
{yes} = use Gronbech-Jensen/Farago formulation
{omega} value = {no} or {yes}
{no} = do not thermostat rotational degrees of freedom via the angular velocity
{yes} = do thermostat rotational degrees of freedom via the angular velocity
{scale} values = type ratio
type = atom type (1-N)
ratio = factor by which to scale the damping coefficient
{tally} value = {no} or {yes}
{no} = do not tally the energy added/subtracted to atoms
{yes} = do tally the energy added/subtracted to atoms
{zero} value = {no} or {yes}
{no} = do not set total random force to zero
{yes} = set total random force to zero :pre
:ule
[Examples:]
fix 3 boundary langevin 1.0 1.0 1000.0 699483
fix 1 all langevin 1.0 1.1 100.0 48279 scale 3 1.5
fix 1 all langevin 1.0 1.1 100.0 48279 angmom 3.333 :pre
[Description:]
Apply a Langevin thermostat as described in "(Schneider)"_#Schneider1
to a group of atoms which models an interaction with a background
implicit solvent. Used with "fix nve"_fix_nve.html, this command
performs Brownian dynamics (BD), since the total force on each atom
will have the form:
F = Fc + Ff + Fr
Ff = - (m / damp) v
Fr is proportional to sqrt(Kb T m / (dt damp)) :pre
Fc is the conservative force computed via the usual inter-particle
interactions ("pair_style"_pair_style.html,
"bond_style"_bond_style.html, etc).
The Ff and Fr terms are added by this fix on a per-particle basis.
See the "pair_style dpd/tstat"_pair_dpd.html command for a
thermostatting option that adds similar terms on a pairwise basis to
pairs of interacting particles.
Ff is a frictional drag or viscous damping term proportional to the
particle's velocity. The proportionality constant for each atom is
computed as m/damp, where m is the mass of the particle and damp is
the damping factor specified by the user.
Fr is a force due to solvent atoms at a temperature T randomly bumping
into the particle. As derived from the fluctuation/dissipation
theorem, its magnitude as shown above is proportional to sqrt(Kb T m /
dt damp), where Kb is the Boltzmann constant, T is the desired
temperature, m is the mass of the particle, dt is the timestep size,
and damp is the damping factor. Random numbers are used to randomize
the direction and magnitude of this force as described in
"(Dunweg)"_#Dunweg1, where a uniform random number is used (instead of
a Gaussian random number) for speed.
Note that unless you use the {omega} or {angmom} keywords, the
thermostat effect of this fix is applied to only the translational
degrees of freedom for the particles, which is an important
consideration for finite-size particles, which have rotational degrees
of freedom, are being thermostatted. The translational degrees of
freedom can also have a bias velocity removed from them before
thermostatting takes place; see the description below.
NOTE: Unlike the "fix nvt"_fix_nh.html command which performs
Nose/Hoover thermostatting AND time integration, this fix does NOT
perform time integration. It only modifies forces to effect
thermostatting. Thus you must use a separate time integration fix,
like "fix nve"_fix_nve.html to actually update the velocities and
positions of atoms using the modified forces. Likewise, this fix
should not normally be used on atoms that also have their temperature
controlled by another fix - e.g. by "fix nvt"_fix_nh.html or "fix
temp/rescale"_fix_temp_rescale.html commands.
See "this howto section"_Section_howto.html#howto_16 of the manual for
a discussion of different ways to compute temperature and perform
thermostatting.
The desired temperature at each timestep is a ramped value during the
run from {Tstart} to {Tstop}.
{Tstart} can be specified as an equal-style or atom-style
"variable"_variable.html. In this case, the {Tstop} setting is
ignored. If the value is a variable, it should be specified as
v_name, where name is the variable name. In this case, the variable
will be evaluated each timestep, and its value used to determine the
target temperature.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent temperature.
Atom-style variables can specify the same formulas as equal-style
variables but can also include per-atom values, such as atom
coordinates. Thus it is easy to specify a spatially-dependent
temperature with optional time-dependence as well.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that remove a "bias" from the
atom velocities. E.g. removing the center-of-mass velocity from a
group of atoms or removing the x-component of velocity from the
calculation. This is not done by default, but only if the
"fix_modify"_fix_modify.html command is used to assign a temperature
compute to this fix that includes such a bias term. See the doc pages
for individual "compute commands"_compute.html to determine which ones
include a bias. In this case, the thermostat works in the following
manner: bias is removed from each atom, thermostatting is performed on
the remaining thermal degrees of freedom, and the bias is added back
in.
The {damp} parameter is specified in time units and determines how
rapidly the temperature is relaxed. For example, a value of 100.0
means to relax the temperature in a timespan of (roughly) 100 time
units (tau or fmsec or psec - see the "units"_units.html command).
The damp factor can be thought of as inversely related to the
viscosity of the solvent. I.e. a small relaxation time implies a
hi-viscosity solvent and vice versa. See the discussion about gamma
and viscosity in the documentation for the "fix
viscous"_fix_viscous.html command for more details.
The random # {seed} must be a positive integer. A Marsaglia random
number generator is used. Each processor uses the input seed to
generate its own unique seed and its own stream of random numbers.
Thus the dynamics of the system will not be identical on two runs on
different numbers of processors.
:line
The keyword/value option pairs are used in the following ways.
The keyword {angmom} and {omega} keywords enable thermostatting of
rotational degrees of freedom in addition to the usual translational
degrees of freedom. This can only be done for finite-size particles.
A simulation using atom_style sphere defines an omega for finite-size
spheres. A simulation using atom_style ellipsoid defines a finite
size and shape for aspherical particles and an angular momentum.
The Langevin formulas for thermostatting the rotational degrees of
freedom are the same as those above, where force is replaced by
torque, m is replaced by the moment of inertia I, and v is replaced by
omega (which is derived from the angular momentum in the case of
aspherical particles).
The rotational temperature of the particles can be monitored by the
"compute temp/sphere"_compute_temp_sphere.html and "compute
temp/asphere"_compute_temp_asphere.html commands with their rotate
options.
For the {omega} keyword there is also a scale factor of 10.0/3.0 that
is applied as a multiplier on the Ff (damping) term in the equation
above and of sqrt(10.0/3.0) as a multiplier on the Fr term. This does
not affect the thermostatting behaviour of the Langevin formalism but
insures that the randomized rotational diffusivity of spherical
particles is correct.
For the {angmom} keyword a similar scale factor is needed which is
10.0/3.0 for spherical particles, but is anisotropic for aspherical
particles (e.g. ellipsoids). Currently LAMMPS only applies an
isotropic scale factor, and you can choose its magnitude as the
specified value of the {angmom} keyword. If your aspherical particles
are (nearly) spherical than a value of 10.0/3.0 = 3.333 is a good
choice. If they are highly aspherical, a value of 1.0 is as good a
choice as any, since the effects on rotational diffusivity of the
particles will be incorrect regardless. Note that for any reasonable
scale factor, the thermostatting effect of the {angmom} keyword on the
rotational temperature of the aspherical particles should still be
valid.
The keyword {scale} allows the damp factor to be scaled up or down by
the specified factor for atoms of that type. This can be useful when
different atom types have different sizes or masses. It can be used
multiple times to adjust damp for several atom types. Note that
specifying a ratio of 2 increases the relaxation time which is
equivalent to the solvent's viscosity acting on particles with 1/2 the
diameter. This is the opposite effect of scale factors used by the
"fix viscous"_fix_viscous.html command, since the damp factor in fix
{langevin} is inversely related to the gamma factor in fix {viscous}.
Also note that the damping factor in fix {langevin} includes the
particle mass in Ff, unlike fix {viscous}. Thus the mass and size of
different atom types should be accounted for in the choice of ratio
values.
The keyword {tally} enables the calculation of the cumulative energy
added/subtracted to the atoms as they are thermostatted. Effectively
it is the energy exchanged between the infinite thermal reservoir and
the particles. As described below, this energy can then be printed
out or added to the potential energy of the system to monitor energy
conservation.
NOTE: this accumulated energy does NOT include kinetic energy removed
by the {zero} flag. LAMMPS will print a warning when both options are
active.
The keyword {zero} can be used to eliminate drift due to the
thermostat. Because the random forces on different atoms are
independent, they do not sum exactly to zero. As a result, this fix
applies a small random force to the entire system, and the
center-of-mass of the system undergoes a slow random walk. If the
keyword {zero} is set to {yes}, the total random force is set exactly
to zero by subtracting off an equal part of it from each atom in the
group. As a result, the center-of-mass of a system with zero initial
momentum will not drift over time.
The keyword {gjf} can be used to run the "Gronbech-Jensen/Farago
"_#Gronbech-Jensen time-discretization of the Langevin model. As
described in the papers cited below, the purpose of this method is to
enable longer timesteps to be used (up to the numerical stability
limit of the integrator), while still producing the correct Boltzmann
distribution of atom positions. It is implemented within LAMMPS, by
changing how the random force is applied so that it is composed of
the average of two random forces representing half-contributions from
the previous and current time intervals.
In common with all methods based on Verlet integration, the
discretized velocities generated by this method in conjunction with
velocity-Verlet time integration are not exactly conjugate to the
positions. As a result the temperature (computed from the discretized
velocities) will be systematically lower than the target temperature,
by a small amount which grows with the timestep. Nonetheless, the
distribution of atom positions will still be consistent with the
target temperature.
As an example of using the {gjf} keyword, for molecules containing C-H
bonds, configurational properties generated with dt = 2.5 fs and tdamp
= 100 fs are indistinguishable from dt = 0.5 fs. Because the velocity
distribution systematically decreases with increasing timestep, the
method should not be used to generate properties that depend on the
velocity distribution, such as the velocity autocorrelation function
(VACF). In this example, the velocity distribution at dt = 2.5fs
generates an average temperature of 220 K, instead of 300 K.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. Because the state of the random number generator
is not saved in restart files, this means you cannot do "exact"
restarts with this fix, where the simulation continues on the same as
if no restart had taken place. However, in a statistical sense, a
restarted simulation should produce the same behavior.
The "fix_modify"_fix_modify.html {temp} option is supported by this
fix. You can use it to assign a temperature "compute"_compute.html
you have defined to this fix which will be used in its thermostatting
procedure, as described above. For consistency, the group used by
this fix and by the compute should be the same.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Langevin thermostatting to the
system's potential energy as part of "thermodynamic
output"_thermo_style.html. Note that use of this option requires
setting the {tally} keyword to {yes}.
This fix computes a global scalar which can be accessed by various
"output commands"_Section_howto.html#howto_15. The scalar is the
cumulative energy change due to this fix. The scalar value
calculated by this fix is "extensive". Note that calculation of this
quantity requires setting the {tally} keyword to {yes}.
This fix can ramp its target temperature over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:] none
[Related commands:]
"fix nvt"_fix_nh.html, "fix temp/rescale"_fix_temp_rescale.html, "fix
viscous"_fix_viscous.html, "fix nvt"_fix_nh.html, "pair_style
dpd/tstat"_pair_dpd.html
[Default:]
The option defaults are angmom = no, omega = no, scale = 1.0 for all
types, tally = no, zero = no, gjf = no.
:line
:link(Dunweg1)
[(Dunweg)] Dunweg and Paul, Int J of Modern Physics C, 2, 817-27 (1991).
:link(Schneider1)
[(Schneider)] Schneider and Stoll, Phys Rev B, 17, 1302 (1978).
:link(Gronbech-Jensen)
[(Gronbech-Jensen)] Gronbech-Jensen and Farago, Mol Phys, 111, 983
(2013); Gronbech-Jensen, Hayre, and Farago, Comp Phys Comm,
185, 524 (2014)
diff --git a/doc/src/fix_momentum.txt b/doc/src/fix_momentum.txt
index 4f94e2a85..bcf4465fb 100644
--- a/doc/src/fix_momentum.txt
+++ b/doc/src/fix_momentum.txt
@@ -1,98 +1,98 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix momentum command :h3
fix momentum/kk command :h3
[Syntax:]
fix ID group-ID momentum N keyword values ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
momentum = style name of this fix command :l
N = adjust the momentum every this many timesteps
one or more keyword/value pairs may be appended :l
keyword = {linear} or {angular} or {rescale} :l
{linear} values = xflag yflag zflag
xflag,yflag,zflag = 0/1 to exclude/include each dimension
{angular} values = none :pre
{rescale} values = none :pre
:ule
[Examples:]
fix 1 all momentum 1 linear 1 1 0
fix 1 all momentum 1 linear 1 1 1 rescale
fix 1 all momentum 100 linear 1 1 1 angular :pre
[Description:]
Zero the linear and/or angular momentum of the group of atoms every N
timesteps by adjusting the velocities of the atoms. One (or both) of
the {linear} or {angular} keywords must be specified.
If the {linear} keyword is used, the linear momentum is zeroed by
subtracting the center-of-mass velocity of the group from each atom.
This does not change the relative velocity of any pair of atoms. One
or more dimensions can be excluded from this operation by setting the
corresponding flag to 0.
If the {angular} keyword is used, the angular momentum is zeroed by
subtracting a rotational component from each atom.
This command can be used to insure the entire collection of atoms (or
a subset of them) does not drift or rotate during the simulation due
to random perturbations (e.g. "fix langevin"_fix_langevin.html
thermostatting).
The {rescale} keyword enables conserving the kinetic energy of the group
of atoms by rescaling the velocities after the momentum was removed.
Note that the "velocity"_velocity.html command can be used to create
initial velocities with zero aggregate linear and/or angular momentum.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:] none
[Related commands:]
"fix recenter"_fix_recenter.html, "velocity"_velocity.html
[Default:] none
diff --git a/doc/src/fix_msst.txt b/doc/src/fix_msst.txt
index 43f35d688..025c73389 100644
--- a/doc/src/fix_msst.txt
+++ b/doc/src/fix_msst.txt
@@ -1,185 +1,193 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix msst command :h3
[Syntax:]
fix ID group-ID msst dir shockvel keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
msst = style name of this fix :l
dir = {x} or {y} or {z} :l
shockvel = shock velocity (strictly positive, distance/time units) :l
zero or more keyword value pairs may be appended :l
keyword = {q} or {mu} or {p0} or {v0} or {e0} or {tscale} or {beta} or {dftb} :l
{q} value = cell mass-like parameter (mass^2/distance^4 units)
{mu} value = artificial viscosity (mass/length/time units)
{p0} value = initial pressure in the shock equations (pressure units)
{v0} value = initial simulation cell volume in the shock equations (distance^3 units)
{e0} value = initial total energy (energy units)
{tscale} value = reduction in initial temperature (unitless fraction between 0.0 and 1.0)
{dftb} value = {yes} or {no} for whether using MSST in conjunction with DFTB+
- {beta} value = scale factor on energy contribution of DFTB+ :pre
+ {beta} value = scale factor for improved energy conservation :pre
:ule
[Examples:]
fix 1 all msst y 100.0 q 1.0e5 mu 1.0e5
fix 2 all msst z 50.0 q 1.0e4 mu 1.0e4 v0 4.3419e+03 p0 3.7797e+03 e0 -9.72360e+02 tscale 0.01
fix 1 all msst y 100.0 q 1.0e5 mu 1.0e5 dftb yes beta 0.5 :pre
[Description:]
This command performs the Multi-Scale Shock Technique (MSST)
integration to update positions and velocities each timestep to mimic
a compressive shock wave passing over the system. See "(Reed)"_#Reed
for a detailed description of this method. The MSST varies the cell
volume and temperature in such a way as to restrain the system to the
shock Hugoniot and the Rayleigh line. These restraints correspond to
the macroscopic conservation laws dictated by a shock
front. {shockvel} determines the steady shock velocity that will be
simulated.
To perform a simulation, choose a value of {q} that provides volume
compression on the timescale of 100 fs to 1 ps. If the volume is not
compressing, either the shock speed is chosen to be below the material
sound speed or {p0} has been chosen inaccurately. Volume compression
at the start can be sped up by using a non-zero value of {tscale}. Use
the smallest value of {tscale} that results in compression.
Under some special high-symmetry conditions, the pressure (volume)
and/or temperature of the system may oscillate for many cycles even
with an appropriate choice of mass-like parameter {q}. Such
oscillations have physical significance in some cases. The optional
{mu} keyword adds an artificial viscosity that helps break the system
symmetry to equilibrate to the shock Hugoniot and Rayleigh line more
rapidly in such cases.
The keyword {tscale} is a factor between 0 and 1 that determines what
fraction of thermal kinetic energy is converted to compressive strain
kinetic energy at the start of the simulation. Setting this parameter
to a non-zero value may assist in compression at the start of
simulations where it is slow to occur.
If keywords {e0}, {p0},or {v0} are not supplied, these quantities will
be calculated on the first step, after the energy specified by
{tscale} is removed. The value of {e0} is not used in the dynamical
equations, but is used in calculating the deviation from the Hugoniot.
+The keyword {beta} is a scaling term that can be added to the MSST
+ionic equations of motion to account for drift in the conserved
+quantity during long timescale simulations, similar to a Berendson
+thermostat. See "(Reed)"_#Reed and "(Goldman)"_#Goldman for more
+details. The value of {beta} must be between 0.0 and 1.0 inclusive.
+A value of 0.0 means no contribution, a value of 1.0 means a full
+contribution.
+
Values of shockvel less than a critical value determined by the
material response will not have compressive solutions. This will be
reflected in lack of significant change of the volume in the MSST.
For all pressure styles, the simulation box stays orthogonal in shape.
Parrinello-Rahman boundary conditions (tilted box) are supported by
LAMMPS, but are not implemented for MSST.
This fix computes a temperature and pressure and potential energy each
timestep. To do this, the fix creates its own computes of style "temp"
"pressure", and "pe", as if these commands had been issued:
compute fix-ID_MSST_temp all temp
compute fix-ID_MSST_press all pressure fix-ID_MSST_temp :pre
compute fix-ID_MSST_pe all pe :pre
See the "compute temp"_compute_temp.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + "_MSST_temp" or "_MSST_press"
or "_MSST_pe". The group for the new computes is "all".
:line
-The {dftb} and {beta} keywords are to allow this fix to be used when
-LAMMPS is being driven by DFTB+, a density-functional tight-binding
-code.
-
-If the keyword {dftb} is used with a value of {yes}, then the MSST
-equations are altered to account for an energy contribution compute by
-DFTB+. In this case, you must define a "fix
-external"_fix_external.html command in your input script, which is
-used to callback to DFTB+ during the LAMMPS timestepping. DFTB+ will
-communicate its info to LAMMPS via that fix.
-
-The keyword {beta} is a scale factor on the DFTB+ energy contribution.
-The value of {beta} must be between 0.0 and 1.0 inclusive. A value of
-0.0 means no contribution, a value of 1.0 means a full contribution.
-
-(July 2017) More information about these keywords and the use of
-LAMMPS with DFTB+ will be added to the LAMMMPS documention soon.
+The {dftb} keyword is to allow this fix to be used when LAMMPS is
+being driven by DFTB+, a density-functional tight-binding code. If the
+keyword {dftb} is used with a value of {yes}, then the MSST equations
+are altered to account for the electron entropy contribution to the
+Hugonio relations and total energy. See "(Reed2)"_#Reed2 and
+"(Goldman)"_#Goldman for details on this contribution. In this case,
+you must define a "fix external"_fix_external.html command in your
+input script, which is used to callback to DFTB+ during the LAMMPS
+timestepping. DFTB+ will communicate its info to LAMMPS via that fix.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of all internal variables to "binary restart
files"_restart.html. See the "read_restart"_read_restart.html command
for info on how to re-specify a fix in an input script that reads a
restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The progress of the MSST can be monitored by printing the global
scalar and global vector quantities computed by the fix.
The scalar is the cumulative energy change due to the fix. This is
also the energy added to the potential energy by the
"fix_modify"_fix_modify.html {energy} command. With this command, the
thermo keyword {etotal} prints the conserved quantity of the MSST
dynamic equations. This can be used to test if the MD timestep is
sufficiently small for accurate integration of the dynamic
equations. See also "thermo_style"_thermo_style.html command.
The global vector contains four values in this order:
\[{dhugoniot}, {drayleigh}, {lagrangian_speed}, {lagrangian_position}\]
{dhugoniot} is the departure from the Hugoniot (temperature units).
{drayleigh} is the departure from the Rayleigh line (pressure units).
{lagrangian_speed} is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units).
{lagrangian_position} is the computational cell position in the reference frame moving at the shock speed. This is usually a good estimate of distance of the computational cell behind the shock front. :ol
To print these quantities to the log file with descriptive column
headers, the following LAMMPS commands are suggested:
fix msst all msst z
fix_modify msst energy yes
variable dhug equal f_msst\[1\]
variable dray equal f_msst\[2\]
variable lgr_vel equal f_msst\[3\]
variable lgr_pos equal f_msst\[4\]
thermo_style custom step temp ke pe lz pzz etotal v_dhug v_dray v_lgr_vel v_lgr_pos f_msst :pre
These fixes compute a global scalar and a global vector of 4
quantities, which can be accessed by various "output
commands"_Section_howto.html#howto_15. The scalar values calculated
by this fix are "extensive"; the vector values are "intensive".
[Restrictions:]
This fix style is part of the SHOCK package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
All cell dimensions must be periodic. This fix can not be used with a
triclinic cell. The MSST fix has been tested only for the group-ID
all.
[Related commands:]
"fix nphug"_fix_nphug.html, "fix deform"_fix_deform.html
[Default:]
The keyword defaults are q = 10, mu = 0, tscale = 0.01, dftb = no,
beta = 0.0. Note that p0, v0, and e0 are calculated on the first
timestep.
:line
:link(Reed)
-[(Reed)] Reed, Fried, and Joannopoulos, Phys. Rev. Lett., 90, 235503 (2003).
+[(Reed)] Reed, Fried, and Joannopoulos, Phys. Rev. Lett., 90, 235503
+(2003).
+
+:link(Reed2)
+[(Reed2)] Reed, J. Phys. Chem. C, 116, 2205 (2012).
+
+:link(Goldman)
+[(Goldman)] Goldman, Srinivasan, Hamel, Fried, Gaus, and Elstner,
+J. Phys. Chem. C, 117, 7885 (2013).
diff --git a/doc/src/fix_nh.txt b/doc/src/fix_nh.txt
index c1cc3e560..8fa30ac22 100644
--- a/doc/src/fix_nh.txt
+++ b/doc/src/fix_nh.txt
@@ -1,642 +1,642 @@
<"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nvt command :h3
fix nvt/intel command :h3
fix nvt/kk command :h3
fix nvt/omp command :h3
fix npt command :h3
fix npt/intel command :h3
fix npt/kk command :h3
fix npt/omp command :h3
fix nph command :h3
fix nph/kk command :h3
fix nph/omp command :h3
[Syntax:]
fix ID group-ID style_name keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
style_name = {nvt} or {npt} or {nph} :l
one or more keyword/value pairs may be appended :l
keyword = {temp} or {iso} or {aniso} or {tri} or {x} or {y} or {z} or {xy} or {yz} or {xz} or {couple} or {tchain} or {pchain} or {mtk} or {tloop} or {ploop} or {nreset} or {drag} or {dilate} or {scalexy} or {scaleyz} or {scalexz} or {flip} or {fixedpoint} or {update}
{temp} values = Tstart Tstop Tdamp
Tstart,Tstop = external temperature at start/end of run
Tdamp = temperature damping parameter (time units)
{iso} or {aniso} or {tri} values = Pstart Pstop Pdamp
Pstart,Pstop = scalar external pressure at start/end of run (pressure units)
Pdamp = pressure damping parameter (time units)
{x} or {y} or {z} or {xy} or {yz} or {xz} values = Pstart Pstop Pdamp
Pstart,Pstop = external stress tensor component at start/end of run (pressure units)
Pdamp = stress damping parameter (time units)
{couple} = {none} or {xyz} or {xy} or {yz} or {xz}
{tchain} value = N
N = length of thermostat chain (1 = single thermostat)
{pchain} values = N
N length of thermostat chain on barostat (0 = no thermostat)
{mtk} value = {yes} or {no} = add in MTK adjustment term or not
{tloop} value = M
M = number of sub-cycles to perform on thermostat
{ploop} value = M
M = number of sub-cycles to perform on barostat thermostat
{nreset} value = reset reference cell every this many timesteps
{drag} value = Df
Df = drag factor added to barostat/thermostat (0.0 = no drag)
{dilate} value = dilate-group-ID
dilate-group-ID = only dilate atoms in this group due to barostat volume changes
{scalexy} value = {yes} or {no} = scale xy with ly
{scaleyz} value = {yes} or {no} = scale yz with lz
{scalexz} value = {yes} or {no} = scale xz with lz
{flip} value = {yes} or {no} = allow or disallow box flips when it becomes highly skewed
{fixedpoint} values = x y z
x,y,z = perform barostat dilation/contraction around this point (distance units)
{update} value = {dipole} or {dipole/dlm}
dipole = update dipole orientation (only for sphere variants)
dipole/dlm = use DLM integrator to update dipole orientation (only for sphere variants) :pre
:ule
[Examples:]
fix 1 all nvt temp 300.0 300.0 100.0
fix 1 water npt temp 300.0 300.0 100.0 iso 0.0 0.0 1000.0
fix 2 jello npt temp 300.0 300.0 100.0 tri 5.0 5.0 1000.0
fix 2 ice nph x 1.0 1.0 0.5 y 2.0 2.0 0.5 z 3.0 3.0 0.5 yz 0.1 0.1 0.5 xz 0.2 0.2 0.5 xy 0.3 0.3 0.5 nreset 1000 :pre
[Description:]
These commands perform time integration on Nose-Hoover style
non-Hamiltonian equations of motion which are designed to generate
positions and velocities sampled from the canonical (nvt),
isothermal-isobaric (npt), and isenthalpic (nph) ensembles. This
updates the position and velocity for atoms in the group each
timestep.
The thermostatting and barostatting is achieved by adding some dynamic
variables which are coupled to the particle velocities
(thermostatting) and simulation domain dimensions (barostatting). In
addition to basic thermostatting and barostatting, these fixes can
also create a chain of thermostats coupled to the particle thermostat,
and another chain of thermostats coupled to the barostat
variables. The barostat can be coupled to the overall box volume, or
to individual dimensions, including the {xy}, {xz} and {yz} tilt
dimensions. The external pressure of the barostat can be specified as
either a scalar pressure (isobaric ensemble) or as components of a
symmetric stress tensor (constant stress ensemble). When used
correctly, the time-averaged temperature and stress tensor of the
particles will match the target values specified by Tstart/Tstop and
Pstart/Pstop.
The equations of motion used are those of Shinoda et al in
"(Shinoda)"_#nh-Shinoda, which combine the hydrostatic equations of
Martyna, Tobias and Klein in "(Martyna)"_#nh-Martyna with the strain
energy proposed by Parrinello and Rahman in
"(Parrinello)"_#nh-Parrinello. The time integration schemes closely
follow the time-reversible measure-preserving Verlet and rRESPA
integrators derived by Tuckerman et al in "(Tuckerman)"_#nh-Tuckerman.
:line
The thermostat parameters for fix styles {nvt} and {npt} is specified
using the {temp} keyword. Other thermostat-related keywords are
{tchain}, {tloop} and {drag}, which are discussed below.
The thermostat is applied to only the translational degrees of freedom
for the particles. The translational degrees of freedom can also have
a bias velocity removed before thermostatting takes place; see the
description below. The desired temperature at each timestep is a
ramped value during the run from {Tstart} to {Tstop}. The {Tdamp}
parameter is specified in time units and determines how rapidly the
temperature is relaxed. For example, a value of 10.0 means to relax
the temperature in a timespan of (roughly) 10 time units (e.g. tau or
fmsec or psec - see the "units"_units.html command). The atoms in the
fix group are the only ones whose velocities and positions are updated
by the velocity/position update portion of the integration.
NOTE: A Nose-Hoover thermostat will not work well for arbitrary values
of {Tdamp}. If {Tdamp} is too small, the temperature can fluctuate
wildly; if it is too large, the temperature will take a very long time
to equilibrate. A good choice for many models is a {Tdamp} of around
100 timesteps. Note that this is NOT the same as 100 time units for
most "units"_units.html settings.
:line
The barostat parameters for fix styles {npt} and {nph} is specified
using one or more of the {iso}, {aniso}, {tri}, {x}, {y}, {z}, {xy},
{xz}, {yz}, and {couple} keywords. These keywords give you the
ability to specify all 6 components of an external stress tensor, and
to couple various of these components together so that the dimensions
they represent are varied together during a constant-pressure
simulation.
Other barostat-related keywords are {pchain}, {mtk}, {ploop},
{nreset}, {drag}, and {dilate}, which are discussed below.
Orthogonal simulation boxes have 3 adjustable dimensions (x,y,z).
Triclinic (non-orthogonal) simulation boxes have 6 adjustable
dimensions (x,y,z,xy,xz,yz). The "create_box"_create_box.html, "read
data"_read_data.html, and "read_restart"_read_restart.html commands
specify whether the simulation box is orthogonal or non-orthogonal
(triclinic) and explain the meaning of the xy,xz,yz tilt factors.
The target pressures for each of the 6 components of the stress tensor
can be specified independently via the {x}, {y}, {z}, {xy}, {xz}, {yz}
keywords, which correspond to the 6 simulation box dimensions. For
each component, the external pressure or tensor component at each
timestep is a ramped value during the run from {Pstart} to {Pstop}.
If a target pressure is specified for a component, then the
corresponding box dimension will change during a simulation. For
example, if the {y} keyword is used, the y-box length will change. If
the {xy} keyword is used, the xy tilt factor will change. A box
dimension will not change if that component is not specified, although
you have the option to change that dimension via the "fix
deform"_fix_deform.html command.
Note that in order to use the {xy}, {xz}, or {yz} keywords, the
simulation box must be triclinic, even if its initial tilt factors are
0.0.
For all barostat keywords, the {Pdamp} parameter operates like the
{Tdamp} parameter, determining the time scale on which pressure is
relaxed. For example, a value of 10.0 means to relax the pressure in
a timespan of (roughly) 10 time units (e.g. tau or fmsec or psec - see
the "units"_units.html command).
NOTE: A Nose-Hoover barostat will not work well for arbitrary values
of {Pdamp}. If {Pdamp} is too small, the pressure and volume can
fluctuate wildly; if it is too large, the pressure will take a very
long time to equilibrate. A good choice for many models is a {Pdamp}
of around 1000 timesteps. However, note that {Pdamp} is specified in
time units, and that timesteps are NOT the same as time units for most
"units"_units.html settings.
Regardless of what atoms are in the fix group (the only atoms which
are time integrated), a global pressure or stress tensor is computed
for all atoms. Similarly, when the size of the simulation box is
changed, all atoms are re-scaled to new positions, unless the keyword
{dilate} is specified with a {dilate-group-ID} for a group that
represents a subset of the atoms. This can be useful, for example, to
leave the coordinates of atoms in a solid substrate unchanged and
controlling the pressure of a surrounding fluid. This option should
be used with care, since it can be unphysical to dilate some atoms and
not others, because it can introduce large, instantaneous
displacements between a pair of atoms (one dilated, one not) that are
far from the dilation origin. Also note that for atoms not in the fix
group, a separate time integration fix like "fix nve"_fix_nve.html or
"fix nvt"_fix_nh.html can be used on them, independent of whether they
are dilated or not.
:line
The {couple} keyword allows two or three of the diagonal components of
the pressure tensor to be "coupled" together. The value specified
with the keyword determines which are coupled. For example, {xz}
means the {Pxx} and {Pzz} components of the stress tensor are coupled.
{Xyz} means all 3 diagonal components are coupled. Coupling means two
things: the instantaneous stress will be computed as an average of the
corresponding diagonal components, and the coupled box dimensions will
be changed together in lockstep, meaning coupled dimensions will be
dilated or contracted by the same percentage every timestep. The
{Pstart}, {Pstop}, {Pdamp} parameters for any coupled dimensions must
be identical. {Couple xyz} can be used for a 2d simulation; the {z}
dimension is simply ignored.
:line
The {iso}, {aniso}, and {tri} keywords are simply shortcuts that are
equivalent to specifying several other keywords together.
The keyword {iso} means couple all 3 diagonal components together when
pressure is computed (hydrostatic pressure), and dilate/contract the
dimensions together. Using "iso Pstart Pstop Pdamp" is the same as
specifying these 4 keywords:
x Pstart Pstop Pdamp
y Pstart Pstop Pdamp
z Pstart Pstop Pdamp
couple xyz :pre
The keyword {aniso} means {x}, {y}, and {z} dimensions are controlled
independently using the {Pxx}, {Pyy}, and {Pzz} components of the
stress tensor as the driving forces, and the specified scalar external
pressure. Using "aniso Pstart Pstop Pdamp" is the same as specifying
these 4 keywords:
x Pstart Pstop Pdamp
y Pstart Pstop Pdamp
z Pstart Pstop Pdamp
couple none :pre
The keyword {tri} means {x}, {y}, {z}, {xy}, {xz}, and {yz} dimensions
are controlled independently using their individual stress components
as the driving forces, and the specified scalar pressure as the
external normal stress. Using "tri Pstart Pstop Pdamp" is the same as
specifying these 7 keywords:
x Pstart Pstop Pdamp
y Pstart Pstop Pdamp
z Pstart Pstop Pdamp
xy 0.0 0.0 Pdamp
yz 0.0 0.0 Pdamp
xz 0.0 0.0 Pdamp
couple none :pre
:line
In some cases (e.g. for solids) the pressure (volume) and/or
temperature of the system can oscillate undesirably when a Nose/Hoover
barostat and thermostat is applied. The optional {drag} keyword will
damp these oscillations, although it alters the Nose/Hoover equations.
A value of 0.0 (no drag) leaves the Nose/Hoover formalism unchanged.
A non-zero value adds a drag term; the larger the value specified, the
greater the damping effect. Performing a short run and monitoring the
pressure and temperature is the best way to determine if the drag term
is working. Typically a value between 0.2 to 2.0 is sufficient to
damp oscillations after a few periods. Note that use of the drag
keyword will interfere with energy conservation and will also change
the distribution of positions and velocities so that they do not
correspond to the nominal NVT, NPT, or NPH ensembles.
An alternative way to control initial oscillations is to use chain
thermostats. The keyword {tchain} determines the number of thermostats
in the particle thermostat. A value of 1 corresponds to the original
Nose-Hoover thermostat. The keyword {pchain} specifies the number of
thermostats in the chain thermostatting the barostat degrees of
freedom. A value of 0 corresponds to no thermostatting of the
barostat variables.
The {mtk} keyword controls whether or not the correction terms due to
Martyna, Tuckerman, and Klein are included in the equations of motion
"(Martyna)"_#nh-Martyna. Specifying {no} reproduces the original
Hoover barostat, whose volume probability distribution function
differs from the true NPT and NPH ensembles by a factor of 1/V. Hence
using {yes} is more correct, but in many cases the difference is
negligible.
The keyword {tloop} can be used to improve the accuracy of integration
scheme at little extra cost. The initial and final updates of the
thermostat variables are broken up into {tloop} substeps, each of
length {dt}/{tloop}. This corresponds to using a first-order
Suzuki-Yoshida scheme "(Tuckerman)"_#nh-Tuckerman. The keyword {ploop}
does the same thing for the barostat thermostat.
The keyword {nreset} controls how often the reference dimensions used
to define the strain energy are reset. If this keyword is not used,
or is given a value of zero, then the reference dimensions are set to
those of the initial simulation domain and are never changed. If the
simulation domain changes significantly during the simulation, then
the final average pressure tensor will differ significantly from the
specified values of the external stress tensor. A value of {nstep}
means that every {nstep} timesteps, the reference dimensions are set
to those of the current simulation domain.
The {scaleyz}, {scalexz}, and {scalexy} keywords control whether or
not the corresponding tilt factors are scaled with the associated box
dimensions when barostatting triclinic periodic cells. The default
values {yes} will turn on scaling, which corresponds to adjusting the
linear dimensions of the cell while preserving its shape. Choosing
{no} ensures that the tilt factors are not scaled with the box
dimensions. See below for restrictions and default values in different
situations. In older versions of LAMMPS, scaling of tilt factors was
not performed. The old behavior can be recovered by setting all three
scale keywords to {no}.
The {flip} keyword allows the tilt factors for a triclinic box to
exceed half the distance of the parallel box length, as discussed
below. If the {flip} value is set to {yes}, the bound is enforced by
flipping the box when it is exceeded. If the {flip} value is set to
{no}, the tilt will continue to change without flipping. Note that if
applied stress induces large deformations (e.g. in a liquid), this
means the box shape can tilt dramatically and LAMMPS will run less
efficiently, due to the large volume of communication needed to
acquire ghost atoms around a processor's irregular-shaped sub-domain.
For extreme values of tilt, LAMMPS may also lose atoms and generate an
error.
The {fixedpoint} keyword specifies the fixed point for barostat volume
changes. By default, it is the center of the box. Whatever point is
chosen will not move during the simulation. For example, if the lower
periodic boundaries pass through (0,0,0), and this point is provided
to {fixedpoint}, then the lower periodic boundaries will remain at
(0,0,0), while the upper periodic boundaries will move twice as
far. In all cases, the particle trajectories are unaffected by the
chosen value, except for a time-dependent constant translation of
positions.
If the {update} keyword is used with the {dipole} value, then the
orientation of the dipole moment of each particle is also updated
during the time integration. This option should be used for models
where a dipole moment is assigned to finite-size particles,
e.g. spheroids via use of the "atom_style hybrid sphere
dipole"_atom_style.html command.
The default dipole orientation integrator can be changed to the
Dullweber-Leimkuhler-McLachlan integration scheme
"(Dullweber)"_#nh-Dullweber when using {update} with the value
{dipole/dlm}. This integrator is symplectic and time-reversible,
giving better energy conservation and allows slightly longer timesteps
at only a small additional computational cost.
:line
NOTE: Using a barostat coupled to tilt dimensions {xy}, {xz}, {yz} can
sometimes result in arbitrarily large values of the tilt dimensions,
i.e. a dramatically deformed simulation box. LAMMPS allows the tilt
factors to grow a small amount beyond the normal limit of half the box
length (0.6 times the box length), and then performs a box "flip" to
an equivalent periodic cell. See the discussion of the {flip} keyword
above, to allow this bound to be exceeded, if desired.
The flip operation is described in more detail in the doc page for
"fix deform"_fix_deform.html. Both the barostat dynamics and the atom
trajectories are unaffected by this operation. However, if a tilt
factor is incremented by a large amount (1.5 times the box length) on
a single timestep, LAMMPS can not accomodate this event and will
terminate the simulation with an error. This error typically indicates
that there is something badly wrong with how the simulation was
constructed, such as specifying values of {Pstart} that are too far
from the current stress value, or specifying a timestep that is too
large. Triclinic barostatting should be used with care. This also is
true for other barostat styles, although they tend to be more
forgiving of insults. In particular, it is important to recognize that
equilibrium liquids can not support a shear stress and that
equilibrium solids can not support shear stresses that exceed the
yield stress.
One exception to this rule is if the 1st dimension in the tilt factor
(x for xy) is non-periodic. In that case, the limits on the tilt
factor are not enforced, since flipping the box in that dimension does
not change the atom positions due to non-periodicity. In this mode,
if you tilt the system to extreme angles, the simulation will simply
become inefficient due to the highly skewed simulation box.
NOTE: Unlike the "fix temp/berendsen"_fix_temp_berendsen.html command
which performs thermostatting but NO time integration, these fixes
perform thermostatting/barostatting AND time integration. Thus you
should not use any other time integration fix, such as "fix
nve"_fix_nve.html on atoms to which this fix is applied. Likewise,
fix nvt and fix npt should not normally be used on atoms that also
have their temperature controlled by another fix - e.g. by "fix
langevin"_fix_nh.html or "fix temp/rescale"_fix_temp_rescale.html
commands.
See "this howto section"_Section_howto.html#howto_16 of the manual for
a discussion of different ways to compute temperature and perform
thermostatting and barostatting.
:line
These fixes compute a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp" and "pressure",
as if one of these two sets of commands had been issued:
compute fix-ID_temp group-ID temp
compute fix-ID_press group-ID pressure fix-ID_temp :pre
compute fix-ID_temp all temp
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp"_compute_temp.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press". For fix nvt, the group for the new computes
is the same as the fix group. For fix nph and fix npt, the group for
the new computes is "all" since pressure is computed for the entire
system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
Like other fixes that perform thermostatting, fix nvt and fix npt can
be used with "compute commands"_compute.html that calculate a
temperature after removing a "bias" from the atom velocities.
E.g. removing the center-of-mass velocity from a group of atoms or
only calculating temperature on the x-component of velocity or only
calculating temperature for atoms in a geometric region. This is not
done by default, but only if the "fix_modify"_fix_modify.html command
is used to assign a temperature compute to this fix that includes such
a bias term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
These fixes can be used with either the {verlet} or {respa}
"integrators"_run_style.html. When using one of the barostat fixes
with {respa}, LAMMPS uses an integrator constructed
according to the following factorization of the Liouville propagator
(for two rRESPA levels):
:c,image(Eqs/fix_nh1.jpg)
This factorization differs somewhat from that of Tuckerman et al, in
that the barostat is only updated at the outermost rRESPA level,
whereas Tuckerman's factorization requires splitting the pressure into
pieces corresponding to the forces computed at each rRESPA level. In
theory, the latter method will exhibit better numerical stability. In
practice, because Pdamp is normally chosen to be a large multiple of
the outermost rRESPA timestep, the barostat dynamics are not the
limiting factor for numerical stability. Both factorizations are
time-reversible and can be shown to preserve the phase space measure
of the underlying non-Hamiltonian equations of motion.
NOTE: This implementation has been shown to conserve linear momentum
up to machine precision under NVT dynamics. Under NPT dynamics,
for a system with zero initial total linear momentum, the total
momentum fluctuates close to zero. It may occasionally undergo brief
excursions to non-negligible values, before returning close to zero.
Over long simulations, this has the effect of causing the center-of-mass
to undergo a slow random walk. This can be mitigated by resetting
the momentum at infrequent intervals using the
"fix momentum"_fix_momentum.html command.
:line
The fix npt and fix nph commands can be used with rigid bodies or
mixtures of rigid bodies and non-rigid particles (e.g. solvent). But
there are also "fix rigid/npt"_fix_rigid.html and "fix
rigid/nph"_fix_rigid.html commands, which are typically a more natural
choice. See the doc page for those commands for more discussion of
the various ways to do this.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
These fixes writes the state of all the thermostat and barostat
variables to "binary restart files"_restart.html. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by these fixes. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure, as described above.
If you do this, note that the kinetic energy derived from the compute
temperature should be consistent with the virial term computed using
all atoms for the pressure. LAMMPS will warn you if you choose to
compute temperature on a subset of atoms.
NOTE: If both the {temp} and {press} keywords are used in a single
thermo_modify command (or in two separate commands), then the order in
which the keywords are specified is important. Note that a "pressure
compute"_compute_pressure.html defines its own temperature compute as
an argument when it is specified. The {temp} keyword will override
this (for the pressure compute being used by fix npt), but only if the
{temp} keyword comes after the {press} keyword. If the {temp} keyword
comes before the {press} keyword, then the new pressure compute
specified by the {press} keyword will be unaffected by the {temp}
setting.
The "fix_modify"_fix_modify.html {energy} option is supported by these
fixes to add the energy change induced by Nose/Hoover thermostatting
and barostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html.
These fixes compute a global scalar and a global vector of quantities,
which can be accessed by various "output
commands"_Section_howto.html#howto_15. The scalar value calculated by
these fixes is "extensive"; the vector values are "intensive".
The scalar is the cumulative energy change due to the fix.
The vector stores internal Nose/Hoover thermostat and barostat
variables. The number and meaning of the vector values depends on
which fix is used and the settings for keywords {tchain} and {pchain},
which specify the number of Nose/Hoover chains for the thermostat and
barostat. If no thermostatting is done, then {tchain} is 0. If no
barostatting is done, then {pchain} is 0. In the following list,
"ndof" is 0, 1, 3, or 6, and is the number of degrees of freedom in
the barostat. Its value is 0 if no barostat is used, else its value
is 6 if any off-diagonal stress tensor component is barostatted, else
its value is 1 if {couple xyz} is used or {couple xy} for a 2d
simulation, otherwise its value is 3.
The order of values in the global vector and their meaning is as
follows. The notation means there are tchain values for eta, followed
by tchain for eta_dot, followed by ndof for omega, etc:
eta\[tchain\] = particle thermostat displacements (unitless)
eta_dot\[tchain\] = particle thermostat velocities (1/time units)
omega\[ndof\] = barostat displacements (unitless)
omega_dot\[ndof\] = barostat velocities (1/time units)
etap\[pchain\] = barostat thermostat displacements (unitless)
etap_dot\[pchain\] = barostat thermostat velocities (1/time units)
PE_eta\[tchain\] = potential energy of each particle thermostat displacement (energy units)
KE_eta_dot\[tchain\] = kinetic energy of each particle thermostat velocity (energy units)
PE_omega\[ndof\] = potential energy of each barostat displacement (energy units)
KE_omega_dot\[ndof\] = kinetic energy of each barostat velocity (energy units)
PE_etap\[pchain\] = potential energy of each barostat thermostat displacement (energy units)
KE_etap_dot\[pchain\] = kinetic energy of each barostat thermostat velocity (energy units)
PE_strain\[1\] = scalar strain energy (energy units) :ul
These fixes can ramp their external temperature and pressure over
multiple runs, using the {start} and {stop} keywords of the
"run"_run.html command. See the "run"_run.html command for details of
how to do this.
These fixes are not invoked during "energy
minimization"_minimize.html.
:line
[Restrictions:]
{X}, {y}, {z} cannot be barostatted if the associated dimension is not
periodic. {Xy}, {xz}, and {yz} can only be barostatted if the
simulation domain is triclinic and the 2nd dimension in the keyword
({y} dimension in {xy}) is periodic. {Z}, {xz}, and {yz}, cannot be
barostatted for 2D simulations. The "create_box"_create_box.html,
"read data"_read_data.html, and "read_restart"_read_restart.html
commands specify whether the simulation box is orthogonal or
non-orthogonal (triclinic) and explain the meaning of the xy,xz,yz
tilt factors.
For the {temp} keyword, the final Tstop cannot be 0.0 since it would
make the external T = 0.0 at some timestep during the simulation which
is not allowed in the Nose/Hoover formulation.
The {scaleyz yes} and {scalexz yes} keyword/value pairs can not be used
for 2D simulations. {scaleyz yes}, {scalexz yes}, and {scalexy yes} options
can only be used if the 2nd dimension in the keyword is periodic,
and if the tilt factor is not coupled to the barostat via keywords
{tri}, {yz}, {xz}, and {xy}.
These fixes can be used with dynamic groups as defined by the
"group"_group.html command. Likewise they can be used with groups to
which atoms are added or deleted over time, e.g. a deposition
simulation. However, the conservation properties of the thermostat
and barostat are defined for systems with a static set of atoms. You
may observe odd behavior if the atoms in a group vary dramatically
over time or the atom count becomes very small.
[Related commands:]
"fix nve"_fix_nve.html, "fix_modify"_fix_modify.html,
"run_style"_run_style.html
[Default:]
The keyword defaults are tchain = 3, pchain = 3, mtk = yes, tloop =
ploop = 1, nreset = 0, drag = 0.0, dilate = all, couple = none,
scaleyz = scalexz = scalexy = yes if periodic in 2nd dimension and
not coupled to barostat, otherwise no.
:line
:link(nh-Martyna)
[(Martyna)] Martyna, Tobias and Klein, J Chem Phys, 101, 4177 (1994).
:link(nh-Parrinello)
[(Parrinello)] Parrinello and Rahman, J Appl Phys, 52, 7182 (1981).
:link(nh-Tuckerman)
[(Tuckerman)] Tuckerman, Alejandre, Lopez-Rendon, Jochim, and
Martyna, J Phys A: Math Gen, 39, 5629 (2006).
:link(nh-Shinoda)
[(Shinoda)] Shinoda, Shiga, and Mikami, Phys Rev B, 69, 134103 (2004).
:link(nh-Dullweber)
[(Dullweber)] Dullweber, Leimkuhler and McLachlan, J Chem Phys, 107,
5840 (1997).
diff --git a/doc/src/fix_nph_asphere.txt b/doc/src/fix_nph_asphere.txt
index 3d151a724..8c35b6a1a 100644
--- a/doc/src/fix_nph_asphere.txt
+++ b/doc/src/fix_nph_asphere.txt
@@ -1,153 +1,153 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nph/asphere command :h3
fix nph/asphere/omp command :h3
[Syntax:]
fix ID group-ID nph/asphere args keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
nph/asphere = style name of this fix command
additional barostat related keyword/value pairs from the "fix nph"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all nph/asphere iso 0.0 0.0 1000.0
fix 2 all nph/asphere x 5.0 5.0 1000.0
fix 2 all nph/asphere x 5.0 5.0 1000.0 drag 0.2
fix 2 water nph/asphere aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPH integration to update position, velocity,
orientation, and angular velocity each timestep for aspherical or
ellipsoidal particles in the group using a Nose/Hoover pressure
barostat. P is pressure; H is enthalpy. This creates a system
trajectory consistent with the isenthalpic ensemble.
This fix differs from the "fix nph"_fix_nh.html command, which assumes
point particles and only updates their position and velocity.
Additional parameters affecting the barostat are specified by keywords
and values documented with the "fix nph"_fix_nh.html command. See,
for example, discussion of the {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPH integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/asphere" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/asphere
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/asphere"_compute_temp_asphere.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover barostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover barostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nph"_fix_nh.html command.
This fix can ramp its target pressure over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the ASPHERE package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style ellipsoid"_atom_style.html
command.
All particles in the group must be finite-size. They cannot be point
particles, but they can be aspherical or spherical as defined by their
shape attribute.
[Related commands:]
"fix nph"_fix_nh.html, "fix nve_asphere"_fix_nve_asphere.html, "fix
nvt_asphere"_fix_nvt_asphere.html, "fix
npt_asphere"_fix_npt_asphere.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nph_body.txt b/doc/src/fix_nph_body.txt
index 3a273be59..1e590f1cb 100644
--- a/doc/src/fix_nph_body.txt
+++ b/doc/src/fix_nph_body.txt
@@ -1,148 +1,148 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nph/body command :h3
[Syntax:]
fix ID group-ID nph/body args keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
nph/body = style name of this fix command
additional barostat related keyword/value pairs from the "fix nph"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all nph/body iso 0.0 0.0 1000.0
fix 2 all nph/body x 5.0 5.0 1000.0
fix 2 all nph/body x 5.0 5.0 1000.0 drag 0.2
fix 2 water nph/body aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPH integration to update position, velocity,
orientation, and angular velocity each timestep for body
particles in the group using a Nose/Hoover pressure
barostat. P is pressure; H is enthalpy. This creates a system
trajectory consistent with the isenthalpic ensemble.
This fix differs from the "fix nph"_fix_nh.html command, which assumes
point particles and only updates their position and velocity.
Additional parameters affecting the barostat are specified by keywords
and values documented with the "fix nph"_fix_nh.html command. See,
for example, discussion of the {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPH integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/body" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/body
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/body"_compute_temp_body.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover barostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover barostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nph"_fix_nh.html command.
This fix can ramp its target pressure over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the BODY package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style body"_atom_style.html
command.
[Related commands:]
"fix nph"_fix_nh.html, "fix nve_body"_fix_nve_body.html, "fix
nvt_body"_fix_nvt_body.html, "fix
npt_body"_fix_npt_body.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nph_sphere.txt b/doc/src/fix_nph_sphere.txt
index 9258f40c7..62b45edfd 100644
--- a/doc/src/fix_nph_sphere.txt
+++ b/doc/src/fix_nph_sphere.txt
@@ -1,160 +1,160 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nph/sphere command :h3
fix nph/sphere/omp command :h3
[Syntax:]
fix ID group-ID nph/sphere args keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
nph/sphere = style name of this fix command :l
keyword = {disc} :l
{disc} value = none = treat particles as 2d discs, not spheres :pre
additional barostat related keyword/value pairs from the "fix nph"_fix_nh.html command can be appended :l,ule
[Examples:]
fix 1 all nph/sphere iso 0.0 0.0 1000.0
fix 2 all nph/sphere x 5.0 5.0 1000.0
fix 2 all nph/sphere x 5.0 5.0 1000.0 disc
fix 2 all nph/sphere x 5.0 5.0 1000.0 drag 0.2
fix 2 water nph/sphere aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPH integration to update position, velocity, and
angular velocity each timestep for finite-size spherical particles in
the group using a Nose/Hoover pressure barostat. P is pressure; H is
enthalpy. This creates a system trajectory consistent with the
isenthalpic ensemble.
This fix differs from the "fix nph"_fix_nh.html command, which assumes
point particles and only updates their position and velocity.
If the {disc} keyword is used, then each particle is treated as a 2d
disc (circle) instead of as a sphere. This is only possible for 2d
simulations, as defined by the "dimension"_dimension.html keyword.
The only difference between discs and spheres in this context is their
moment of inertia, as used in the time integration.
Additional parameters affecting the barostat are specified by keywords
and values documented with the "fix nph"_fix_nh.html command. See,
for example, discussion of the {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPH integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/sphere" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/sphere
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/sphere"_compute_temp_sphere.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover barostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover barostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nph"_fix_nh.html command.
This fix can ramp its target pressure over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix requires that atoms store torque and angular velocity (omega)
and a radius as defined by the "atom_style sphere"_atom_style.html
command.
All particles in the group must be finite-size spheres. They cannot
be point particles.
Use of the {disc} keyword is only allowed for 2d simulations, as
defined by the "dimension"_dimension.html keyword.
[Related commands:]
"fix nph"_fix_nh.html, "fix nve_sphere"_fix_nve_sphere.html, "fix
nvt_sphere"_fix_nvt_sphere.html, "fix npt_sphere"_fix_npt_sphere.html,
"fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nphug.txt b/doc/src/fix_nphug.txt
index ef3ffc495..292e46f94 100644
--- a/doc/src/fix_nphug.txt
+++ b/doc/src/fix_nphug.txt
@@ -1,229 +1,229 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nphug command :h3
fix nphug/omp command :h3
[Syntax:]
fix ID group-ID nphug keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
one or more keyword value pairs may be appended
keyword = {temp} or {iso} or {aniso} or {tri} or {x} or {y} or {z} or {couple} or {tchain} or {pchain} or {mtk} or {tloop} or {ploop} or {nreset} or {drag} or {dilate} or {scaleyz} or {scalexz} or {scalexy}
{temp} values = Value1 Value2 Tdamp
Value1, Value2 = Nose-Hoover target temperatures, ignored by Hugoniostat
Tdamp = temperature damping parameter (time units)
{iso} or {aniso} or {tri} values = Pstart Pstop Pdamp
Pstart,Pstop = scalar external pressures, must be equal (pressure units)
Pdamp = pressure damping parameter (time units)
{x} or {y} or {z} or {xy} or {yz} or {xz} values = Pstart Pstop Pdamp
Pstart,Pstop = external stress tensor components, must be equal (pressure units)
Pdamp = stress damping parameter (time units)
{couple} = {none} or {xyz} or {xy} or {yz} or {xz}
{tchain} value = length of thermostat chain (1 = single thermostat)
{pchain} values = length of thermostat chain on barostat (0 = no thermostat)
{mtk} value = {yes} or {no} = add in MTK adjustment term or not
{tloop} value = number of sub-cycles to perform on thermostat
{ploop} value = number of sub-cycles to perform on barostat thermostat
{nreset} value = reset reference cell every this many timesteps
{drag} value = drag factor added to barostat/thermostat (0.0 = no drag)
{dilate} value = {all} or {partial}
{scaleyz} value = {yes} or {no} = scale yz with lz
{scalexz} value = {yes} or {no} = scale xz with lz
{scalexy} value = {yes} or {no} = scale xy with ly :pre
:ule
[Examples:]
fix myhug all nphug temp 1.0 1.0 10.0 z 40.0 40.0 70.0
fix myhug all nphug temp 1.0 1.0 10.0 iso 40.0 40.0 70.0 drag 200.0 tchain 1 pchain 0 :pre
[Description:]
This command is a variant of the Nose-Hoover
"fix npt"_fix_nh.html fix style.
It performs time integration of the Hugoniostat equations
of motion developed by Ravelo et al. "(Ravelo)"_#Ravelo1.
These equations compress the system to a state with average
axial stress or pressure equal to the specified target value
and that satisfies the Rankine-Hugoniot (RH)
jump conditions for steady shocks.
The compression can be performed
either
hydrostatically (using keyword {iso}, {aniso}, or {tri}) or uniaxially
(using keywords {x}, {y}, or {z}). In the hydrostatic case,
the cell dimensions change dynamically so that the average axial stress
in all three directions converges towards the specified target value.
In the uniaxial case, the chosen cell dimension changes dynamically
so that the average
axial stress in that direction converges towards the target value. The
other two cell dimensions are kept fixed (zero lateral strain).
This leads to the following additional restrictions on the keywords:
One and only one of the following keywords should be used: {iso}, {aniso}, {tri}, {x}, {y}, {z}
The specified initial and final target pressures must be the same.
The keywords {xy}, {xz}, {yz} may not be used.
The only admissible value for the couple keyword is {xyz}, which has the same effect as keyword {iso}
The {temp} keyword must be used to specify the time constant for kinetic energy relaxation, but initial and final target temperature values are ignored. :ul
Essentially, a Hugoniostat simulation is an NPT simulation in which the
user-specified target temperature is replaced with a time-dependent
target temperature Tt obtained from the following equation:
:c,image(Eqs/fix_nphug.jpg)
where T and Tt are the instantaneous and target temperatures,
P and P0 are the instantaneous and reference pressures or axial stresses,
depending on whether hydrostatic or uniaxial compression is being
performed, V and V0 are the instantaneous and reference volumes,
E and E0 are the instantaneous and reference internal energy (potential
plus kinetic), Ndof is the number of degrees of freedom used in the
definition of temperature, and kB is the Boltzmann constant. Delta is the
negative deviation of the instantaneous temperature from the target temperature.
When the system reaches a stable equilibrium, the value of Delta should
fluctuate about zero.
The values of E0, V0, and P0 are the instantaneous values at the start of
the simulation. These can be overridden using the fix_modify keywords {e0},
{v0}, and {p0} described below.
:line
NOTE: Unlike the "fix temp/berendsen"_fix_temp_berendsen.html command
which performs thermostatting but NO time integration, this fix
performs thermostatting/barostatting AND time integration. Thus you
should not use any other time integration fix, such as "fix
nve"_fix_nve.html on atoms to which this fix is applied. Likewise,
this fix should not be used on atoms that have their temperature
controlled by another fix - e.g. by "fix langevin"_fix_nh.html or "fix
temp/rescale"_fix_temp_rescale.html commands.
:line
This fix computes a temperature and pressure at each timestep. To do
this, the fix creates its own computes of style "temp" and "pressure",
as if one of these two sets of commands had been issued:
compute fix-ID_temp group-ID temp
compute fix-ID_press group-ID pressure fix-ID_temp :pre
compute fix-ID_temp all temp
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp"_compute_temp.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press". The group for
the new computes is "all" since pressure is computed for the entire
system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the values of E0, V0, and P0, as well as the
state of all the thermostat and barostat
variables to "binary restart files"_restart.html. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {e0}, {v0} and {p0} keywords
can be used to define the values of E0, V0, and P0. Note the
the values for {e0} and {v0} are extensive, and so must correspond
to the total energy and volume of the entire system, not energy and
volume per atom. If any of these quantities are not specified, then the
instantaneous value in the system at the start of the simulation is used.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by these fixes. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure, as described above.
If you do this, note that the kinetic energy derived from the compute
temperature should be consistent with the virial term computed using
all atoms for the pressure. LAMMPS will warn you if you choose to
compute temperature on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by these
fixes to add the energy change induced by Nose/Hoover thermostatting
and barostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html. Either way, this energy is *not*
included in the definition of internal energy E when calculating the value
of Delta in the above equation.
These fixes compute a global scalar and a global vector of quantities,
which can be accessed by various "output
commands"_Section_howto.html#howto_15. The scalar value calculated by
these fixes is "extensive"; the vector values are "intensive".
The scalar is the cumulative energy change due to the fix.
The vector stores three quantities unique to this fix (Delta, Us, and up),
followed by all the internal Nose/Hoover thermostat and barostat
variables defined for "fix npt"_fix_nh.html. Delta is the deviation
of the temperature from the target temperature, given by the above equation.
Us and up are the shock and particle velocity corresponding to a steady
shock calculated from the RH conditions. They have units of distance/time.
[Restrictions:]
This fix style is part of the SHOCK package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
All the usual restrictions for "fix npt"_fix_nh.html apply,
plus the additional ones mentioned above.
[Related commands:]
"fix msst"_fix_msst.html, "fix npt"_fix_nh.html, "fix_modify"_fix_modify.html
[Default:]
The keyword defaults are the same as those for "fix npt"_fix_nh.html
:line
:link(Ravelo1)
[(Ravelo)] Ravelo, Holian, Germann and Lomdahl, Phys Rev B, 70, 014103 (2004).
diff --git a/doc/src/fix_npt_asphere.txt b/doc/src/fix_npt_asphere.txt
index 8fe98f181..5f3979e36 100644
--- a/doc/src/fix_npt_asphere.txt
+++ b/doc/src/fix_npt_asphere.txt
@@ -1,177 +1,177 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix npt/asphere command :h3
fix npt/asphere/omp command :h3
[Syntax:]
fix ID group-ID npt/asphere keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
npt/asphere = style name of this fix command
additional thermostat and barostat related keyword/value pairs from the "fix npt"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all npt/asphere temp 300.0 300.0 100.0 iso 0.0 0.0 1000.0
fix 2 all npt/asphere temp 300.0 300.0 100.0 x 5.0 5.0 1000.0
fix 2 all npt/asphere temp 300.0 300.0 100.0 x 5.0 5.0 1000.0 drag 0.2
fix 2 water npt/asphere temp 300.0 300.0 100.0 aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPT integration to update position, velocity,
orientation, and angular velocity each timestep for aspherical or
ellipsoidal particles in the group using a Nose/Hoover temperature
thermostat and Nose/Hoover pressure barostat. P is pressure; T is
temperature. This creates a system trajectory consistent with the
isothermal-isobaric ensemble.
This fix differs from the "fix npt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the aspherical particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
Additional parameters affecting the thermostat and barostat are
specified by keywords and values documented with the "fix
npt"_fix_nh.html command. See, for example, discussion of the {temp},
{iso}, {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPT integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/asphere" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/asphere
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/asphere"_compute_temp_asphere.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat and barostat
to "binary restart files"_restart.html. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting and
barostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix npt"_fix_nh.html command.
This fix can ramp its target temperature and pressure over multiple
runs, using the {start} and {stop} keywords of the "run"_run.html
command. See the "run"_run.html command for details of how to do
this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the ASPHERE package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style ellipsoid"_atom_style.html
command.
All particles in the group must be finite-size. They cannot be point
particles, but they can be aspherical or spherical as defined by their
shape attribute.
[Related commands:]
"fix npt"_fix_nh.html, "fix nve_asphere"_fix_nve_asphere.html, "fix
nvt_asphere"_fix_nvt_asphere.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_npt_body.txt b/doc/src/fix_npt_body.txt
index 772920df6..d89bf19db 100644
--- a/doc/src/fix_npt_body.txt
+++ b/doc/src/fix_npt_body.txt
@@ -1,172 +1,172 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix npt/body command :h3
[Syntax:]
fix ID group-ID npt/body keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
npt/body = style name of this fix command
additional thermostat and barostat related keyword/value pairs from the "fix npt"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all npt/body temp 300.0 300.0 100.0 iso 0.0 0.0 1000.0
fix 2 all npt/body temp 300.0 300.0 100.0 x 5.0 5.0 1000.0
fix 2 all npt/body temp 300.0 300.0 100.0 x 5.0 5.0 1000.0 drag 0.2
fix 2 water npt/body temp 300.0 300.0 100.0 aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPT integration to update position, velocity,
orientation, and angular velocity each timestep for body
particles in the group using a Nose/Hoover temperature
thermostat and Nose/Hoover pressure barostat. P is pressure; T is
temperature. This creates a system trajectory consistent with the
isothermal-isobaric ensemble.
This fix differs from the "fix npt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the body particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
Additional parameters affecting the thermostat and barostat are
specified by keywords and values documented with the "fix
npt"_fix_nh.html command. See, for example, discussion of the {temp},
{iso}, {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPT integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/body" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/body
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/body"_compute_temp_body.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat and barostat
to "binary restart files"_restart.html. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting and
barostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix npt"_fix_nh.html command.
This fix can ramp its target temperature and pressure over multiple
runs, using the {start} and {stop} keywords of the "run"_run.html
command. See the "run"_run.html command for details of how to do
this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the BODY package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style body"_atom_style.html
command.
[Related commands:]
"fix npt"_fix_nh.html, "fix nve_body"_fix_nve_body.html, "fix
nvt_body"_fix_nvt_body.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_npt_sphere.txt b/doc/src/fix_npt_sphere.txt
index 24a8fede5..c4cf2cb08 100644
--- a/doc/src/fix_npt_sphere.txt
+++ b/doc/src/fix_npt_sphere.txt
@@ -1,186 +1,186 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix npt/sphere command :h3
fix npt/sphere/omp command :h3
[Syntax:]
fix ID group-ID npt/sphere keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
npt/sphere = style name of this fix command
zero or more keyword/value pairs may be appended :l
keyword = {disc} :l
{disc} value = none = treat particles as 2d discs, not spheres :pre
additional thermostat and barostat related keyword/value pairs from the "fix npt"_fix_nh.html command can be appended :l,ule
[Examples:]
fix 1 all npt/sphere temp 300.0 300.0 100.0 iso 0.0 0.0 1000.0
fix 2 all npt/sphere temp 300.0 300.0 100.0 x 5.0 5.0 1000.0
fix 2 all npt/sphere temp 300.0 300.0 100.0 x 5.0 5.0 1000.0 disc
fix 2 all npt/sphere temp 300.0 300.0 100.0 x 5.0 5.0 1000.0 drag 0.2
fix 2 water npt/sphere temp 300.0 300.0 100.0 aniso 0.0 0.0 1000.0 dilate partial :pre
[Description:]
Perform constant NPT integration to update position, velocity, and
angular velocity each timestep for finite-sizex spherical particles in
the group using a Nose/Hoover temperature thermostat and Nose/Hoover
pressure barostat. P is pressure; T is temperature. This creates a
system trajectory consistent with the isothermal-isobaric ensemble.
This fix differs from the "fix npt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the spherical particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
If the {disc} keyword is used, then each particle is treated as a 2d
disc (circle) instead of as a sphere. This is only possible for 2d
simulations, as defined by the "dimension"_dimension.html keyword.
The only difference between discs and spheres in this context is their
moment of inertia, as used in the time integration.
Additional parameters affecting the thermostat and barostat are
specified by keywords and values documented with the "fix
npt"_fix_nh.html command. See, for example, discussion of the {temp},
{iso}, {aniso}, and {dilate} keywords.
The particles in the fix group are the only ones whose velocities and
positions are updated by the velocity/position update portion of the
NPT integration.
Regardless of what particles are in the fix group, a global pressure is
computed for all particles. Similarly, when the size of the simulation
box is changed, all particles are re-scaled to new positions, unless the
keyword {dilate} is specified with a value of {partial}, in which case
only the particles in the fix group are re-scaled. The latter can be
useful for leaving the coordinates of particles in a solid substrate
unchanged and controlling the pressure of a surrounding fluid.
:line
This fix computes a temperature and pressure each timestep. To do
this, the fix creates its own computes of style "temp/sphere" and
"pressure", as if these commands had been issued:
compute fix-ID_temp all temp/sphere
compute fix-ID_press all pressure fix-ID_temp :pre
See the "compute temp/sphere"_compute_temp_sphere.html and "compute
pressure"_compute_pressure.html commands for details. Note that the
IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID
+ underscore + "press", and the group for the new computes is "all"
since pressure is computed for the entire system.
Note that these are NOT the computes used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}
and {thermo_press}. This means you can change the attributes of this
fix's temperature or pressure via the
"compute_modify"_compute_modify.html command or print this temperature
or pressure during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} or
{thermo_press} will have no effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat and barostat
to "binary restart files"_restart.html. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by this fix. You can use them to assign a
"compute"_compute.html you have defined to this fix which will be used
in its thermostatting or barostatting procedure. If you do this, note
that the kinetic energy derived from the compute temperature should be
consistent with the virial term computed using all atoms for the
pressure. LAMMPS will warn you if you choose to compute temperature
on a subset of atoms.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting and
barostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix npt"_fix_nh.html command.
This fix can ramp its target temperature and pressure over multiple
runs, using the {start} and {stop} keywords of the "run"_run.html
command. See the "run"_run.html command for details of how to do
this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix requires that atoms store torque and angular velocity (omega)
and a radius as defined by the "atom_style sphere"_atom_style.html
command.
All particles in the group must be finite-size spheres. They cannot
be point particles.
Use of the {disc} keyword is only allowed for 2d simulations, as
defined by the "dimension"_dimension.html keyword.
[Related commands:]
"fix npt"_fix_nh.html, "fix nve_sphere"_fix_nve_sphere.html, "fix
nvt_sphere"_fix_nvt_sphere.html, "fix
npt_asphere"_fix_npt_asphere.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nve.txt b/doc/src/fix_nve.txt
index 7ad830187..c04c17858 100644
--- a/doc/src/fix_nve.txt
+++ b/doc/src/fix_nve.txt
@@ -1,73 +1,73 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nve command :h3
fix nve/intel command :h3
fix nve/kk command :h3
fix nve/omp command :h3
[Syntax:]
fix ID group-ID nve :pre
ID, group-ID are documented in "fix"_fix.html command
nve = style name of this fix command :ul
[Examples:]
fix 1 all nve :pre
[Description:]
Perform constant NVE integration to update position and velocity for
atoms in the group each timestep. V is volume; E is energy. This
creates a system trajectory consistent with the microcanonical
ensemble.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:] none
[Related commands:]
"fix nvt"_fix_nh.html, "fix npt"_fix_nh.html
[Default:] none
diff --git a/doc/src/fix_nve_asphere.txt b/doc/src/fix_nve_asphere.txt
index 03846a255..1f31fb967 100644
--- a/doc/src/fix_nve_asphere.txt
+++ b/doc/src/fix_nve_asphere.txt
@@ -1,86 +1,86 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nve/asphere command :h3
fix nve/asphere/intel command :h3
[Syntax:]
fix ID group-ID nve/asphere :pre
ID, group-ID are documented in "fix"_fix.html command
nve/asphere = style name of this fix command :ul
[Examples:]
fix 1 all nve/asphere :pre
[Description:]
Perform constant NVE integration to update position, velocity,
orientation, and angular velocity for aspherical particles in the
group each timestep. V is volume; E is energy. This creates a system
trajectory consistent with the microcanonical ensemble.
This fix differs from the "fix nve"_fix_nve.html command, which
assumes point particles and only updates their position and velocity.
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This fix is part of the ASPHERE package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style ellipsoid"_atom_style.html
command.
All particles in the group must be finite-size. They cannot be point
particles, but they can be aspherical or spherical as defined by their
shape attribute.
[Related commands:]
"fix nve"_fix_nve.html, "fix nve/sphere"_fix_nve_sphere.html
[Default:] none
diff --git a/doc/src/fix_nve_sphere.txt b/doc/src/fix_nve_sphere.txt
index f91a41f51..21dc6cba8 100644
--- a/doc/src/fix_nve_sphere.txt
+++ b/doc/src/fix_nve_sphere.txt
@@ -1,122 +1,122 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nve/sphere command :h3
fix nve/sphere/omp command :h3
[Syntax:]
fix ID group-ID nve/sphere :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
nve/sphere = style name of this fix command :l
zero or more keyword/value pairs may be appended :l
keyword = {update} or {disc} :l
{update} value = {dipole} or {dipole/dlm}
dipole = update orientation of dipole moment during integration
dipole/dlm = use DLM integrator to update dipole orientation
{disc} value = none = treat particles as 2d discs, not spheres :pre
:ule
[Examples:]
fix 1 all nve/sphere
fix 1 all nve/sphere update dipole
fix 1 all nve/sphere disc
fix 1 all nve/sphere update dipole/dlm :pre
[Description:]
Perform constant NVE integration to update position, velocity, and
angular velocity for finite-size spherical particles in the group each
timestep. V is volume; E is energy. This creates a system trajectory
consistent with the microcanonical ensemble.
This fix differs from the "fix nve"_fix_nve.html command, which
assumes point particles and only updates their position and velocity.
If the {update} keyword is used with the {dipole} value, then the
orientation of the dipole moment of each particle is also updated
during the time integration. This option should be used for models
where a dipole moment is assigned to finite-size particles,
e.g. spheroids via use of the "atom_style hybrid sphere
dipole"_atom_style.html command.
The default dipole orientation integrator can be changed to the
Dullweber-Leimkuhler-McLachlan integration scheme
"(Dullweber)"_#nh-Dullweber when using {update} with the value
{dipole/dlm}. This integrator is symplectic and time-reversible,
giving better energy conservation and allows slightly longer timesteps
at only a small additional computational cost.
If the {disc} keyword is used, then each particle is treated as a 2d
disc (circle) instead of as a sphere. This is only possible for 2d
simulations, as defined by the "dimension"_dimension.html keyword.
The only difference between discs and spheres in this context is their
moment of inertia, as used in the time integration.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix requires that atoms store torque and angular velocity (omega)
and a radius as defined by the "atom_style sphere"_atom_style.html
command. If the {dipole} keyword is used, then they must also store a
dipole moment as defined by the "atom_style dipole"_atom_style.html
command.
All particles in the group must be finite-size spheres. They cannot
be point particles.
Use of the {disc} keyword is only allowed for 2d simulations, as
defined by the "dimension"_dimension.html keyword.
[Related commands:]
"fix nve"_fix_nve.html, "fix nve/asphere"_fix_nve_asphere.html
[Default:] none
:line
:link(nve-Dullweber)
[(Dullweber)] Dullweber, Leimkuhler and McLachlan, J Chem Phys, 107,
5840 (1997).
diff --git a/doc/src/fix_nvt_asphere.txt b/doc/src/fix_nvt_asphere.txt
index 77de1dea4..21b900f16 100644
--- a/doc/src/fix_nvt_asphere.txt
+++ b/doc/src/fix_nvt_asphere.txt
@@ -1,153 +1,153 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nvt/asphere command :h3
fix nvt/asphere/omp command :h3
[Syntax:]
fix ID group-ID nvt/asphere keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
nvt/asphere = style name of this fix command
additional thermostat related keyword/value pairs from the "fix nvt"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all nvt/asphere temp 300.0 300.0 100.0
fix 1 all nvt/asphere temp 300.0 300.0 100.0 drag 0.2 :pre
[Description:]
Perform constant NVT integration to update position, velocity,
orientation, and angular velocity each timestep for aspherical or
ellipsoidal particles in the group using a Nose/Hoover temperature
thermostat. V is volume; T is temperature. This creates a system
trajectory consistent with the canonical ensemble.
This fix differs from the "fix nvt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the aspherical particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
Additional parameters affecting the thermostat are specified by
keywords and values documented with the "fix nvt"_fix_nh.html
command. See, for example, discussion of the {temp} and {drag}
keywords.
This fix computes a temperature each timestep. To do this, the fix
creates its own compute of style "temp/asphere", as if this command
had been issued:
compute fix-ID_temp group-ID temp/asphere :pre
See the "compute temp/asphere"_compute_temp_asphere.html command for
details. Note that the ID of the new compute is the fix-ID +
underscore + "temp", and the group for the new compute is the same as
the fix group.
Note that this is NOT the compute used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}.
This means you can change the attributes of this fix's temperature
(e.g. its degrees-of-freedom) via the
"compute_modify"_compute_modify.html command or print this temperature
during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} will have no
effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} option is supported by this
fix. You can use it to assign a "compute"_compute.html you have
defined to this fix which will be used in its thermostatting
procedure.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nvt"_fix_nh.html command.
This fix can ramp its target temperature over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the ASPHERE package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style ellipsoid"_atom_style.html
command.
All particles in the group must be finite-size. They cannot be point
particles, but they can be aspherical or spherical as defined by their
shape attribute.
[Related commands:]
"fix nvt"_fix_nh.html, "fix nve_asphere"_fix_nve_asphere.html, "fix
npt_asphere"_fix_npt_asphere.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nvt_body.txt b/doc/src/fix_nvt_body.txt
index 1f04b85c8..6a5e09ba7 100644
--- a/doc/src/fix_nvt_body.txt
+++ b/doc/src/fix_nvt_body.txt
@@ -1,148 +1,148 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nvt/body command :h3
[Syntax:]
fix ID group-ID nvt/body keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
nvt/body = style name of this fix command
additional thermostat related keyword/value pairs from the "fix nvt"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all nvt/body temp 300.0 300.0 100.0
fix 1 all nvt/body temp 300.0 300.0 100.0 drag 0.2 :pre
[Description:]
Perform constant NVT integration to update position, velocity,
orientation, and angular velocity each timestep for body
particles in the group using a Nose/Hoover temperature
thermostat. V is volume; T is temperature. This creates a system
trajectory consistent with the canonical ensemble.
This fix differs from the "fix nvt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the body particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
Additional parameters affecting the thermostat are specified by
keywords and values documented with the "fix nvt"_fix_nh.html
command. See, for example, discussion of the {temp} and {drag}
keywords.
This fix computes a temperature each timestep. To do this, the fix
creates its own compute of style "temp/body", as if this command
had been issued:
compute fix-ID_temp group-ID temp/body :pre
See the "compute temp/body"_compute_temp_body.html command for
details. Note that the ID of the new compute is the fix-ID +
underscore + "temp", and the group for the new compute is the same as
the fix group.
Note that this is NOT the compute used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}.
This means you can change the attributes of this fix's temperature
(e.g. its degrees-of-freedom) via the
"compute_modify"_compute_modify.html command or print this temperature
during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} will have no
effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} option is supported by this
fix. You can use it to assign a "compute"_compute.html you have
defined to this fix which will be used in its thermostatting
procedure.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nvt"_fix_nh.html command.
This fix can ramp its target temperature over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix is part of the BODY package. It is only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix requires that atoms store torque and angular momentum and a
quaternion as defined by the "atom_style body"_atom_style.html
command.
[Related commands:]
"fix nvt"_fix_nh.html, "fix nve_body"_fix_nve_body.html, "fix
npt_body"_fix_npt_body.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_nvt_sllod.txt b/doc/src/fix_nvt_sllod.txt
index 82631f22e..392dbc281 100644
--- a/doc/src/fix_nvt_sllod.txt
+++ b/doc/src/fix_nvt_sllod.txt
@@ -1,180 +1,180 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nvt/sllod command :h3
fix nvt/sllod/intel command :h3
fix nvt/sllod/omp command :h3
[Syntax:]
fix ID group-ID nvt/sllod keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command
nvt/sllod = style name of this fix command
additional thermostat related keyword/value pairs from the "fix nvt"_fix_nh.html command can be appended :ul
[Examples:]
fix 1 all nvt/sllod temp 300.0 300.0 100.0
fix 1 all nvt/sllod temp 300.0 300.0 100.0 drag 0.2 :pre
[Description:]
Perform constant NVT integration to update positions and velocities
each timestep for atoms in the group using a Nose/Hoover temperature
thermostat. V is volume; T is temperature. This creates a system
trajectory consistent with the canonical ensemble.
This thermostat is used for a simulation box that is changing size
and/or shape, for example in a non-equilibrium MD (NEMD) simulation.
The size/shape change is induced by use of the "fix
deform"_fix_deform.html command, so each point in the simulation box
can be thought of as having a "streaming" velocity. This
position-dependent streaming velocity is subtracted from each atom's
actual velocity to yield a thermal velocity which is used for
temperature computation and thermostatting. For example, if the box
is being sheared in x, relative to y, then points at the bottom of the
box (low y) have a small x velocity, while points at the top of the
box (hi y) have a large x velocity. These velocities do not
contribute to the thermal "temperature" of the atom.
NOTE: "Fix deform"_fix_deform.html has an option for remapping either
atom coordinates or velocities to the changing simulation box. To use
fix nvt/sllod, fix deform should NOT remap atom positions, because fix
nvt/sllod adjusts the atom positions and velocities to create a
velocity profile that matches the changing box size/shape. Fix deform
SHOULD remap atom velocities when atoms cross periodic boundaries
since that is consistent with maintaining the velocity profile created
by fix nvt/sllod. LAMMPS will give an error if this setting is not
consistent.
The SLLOD equations of motion, originally proposed by Hoover and Ladd
(see "(Evans and Morriss)"_#Evans3), were proven to be equivalent to
Newton's equations of motion for shear flow by "(Evans and
Morriss)"_#Evans3. They were later shown to generate the desired
velocity gradient and the correct production of work by stresses for
all forms of homogeneous flow by "(Daivis and Todd)"_#Daivis. As
implemented in LAMMPS, they are coupled to a Nose/Hoover chain
thermostat in a velocity Verlet formulation, closely following the
implementation used for the "fix nvt"_fix_nh.html command.
Additional parameters affecting the thermostat are specified by
keywords and values documented with the "fix nvt"_fix_nh.html
command. See, for example, discussion of the {temp} and {drag}
keywords.
This fix computes a temperature each timestep. To do this, the fix
creates its own compute of style "temp/deform", as if this command had
been issued:
compute fix-ID_temp group-ID temp/deform :pre
See the "compute temp/deform"_compute_temp_deform.html command for
details. Note that the ID of the new compute is the fix-ID +
underscore + "temp", and the group for the new compute is the same as
the fix group.
Note that this is NOT the compute used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}.
This means you can change the attributes of this fix's temperature
(e.g. its degrees-of-freedom) via the
"compute_modify"_compute_modify.html command or print this temperature
during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} will have no
effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} option is supported by this
fix. You can use it to assign a "compute"_compute.html you have
defined to this fix which will be used in its thermostatting
procedure.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nvt"_fix_nh.html command.
This fix can ramp its target temperature over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix works best without Nose-Hoover chain thermostats, i.e. using
tchain = 1. Setting tchain to larger values can result in poor
equilibration.
[Related commands:]
"fix nve"_fix_nve.html, "fix nvt"_fix_nh.html, "fix
temp/rescale"_fix_temp_rescale.html, "fix langevin"_fix_langevin.html,
"fix_modify"_fix_modify.html, "compute
temp/deform"_compute_temp_deform.html
[Default:]
Same as "fix nvt"_fix_nh.html, except tchain = 1.
:line
:link(Evans3)
[(Evans and Morriss)] Evans and Morriss, Phys Rev A, 30, 1528 (1984).
:link(Daivis)
[(Daivis and Todd)] Daivis and Todd, J Chem Phys, 124, 194103 (2006).
diff --git a/doc/src/fix_nvt_sphere.txt b/doc/src/fix_nvt_sphere.txt
index fa1c97bcc..ecf0922b7 100644
--- a/doc/src/fix_nvt_sphere.txt
+++ b/doc/src/fix_nvt_sphere.txt
@@ -1,162 +1,162 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix nvt/sphere command :h3
fix nvt/sphere/omp command :h3
[Syntax:]
fix ID group-ID nvt/sphere keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
nvt/sphere = style name of this fix command :l
zero or more keyword/value pairs may be appended :l
keyword = {disc} :l
{disc} value = none = treat particles as 2d discs, not spheres :pre
additional thermostat related keyword/value pairs from the "fix nvt"_fix_nh.html command can be appended :l,ule
[Examples:]
fix 1 all nvt/sphere temp 300.0 300.0 100.0
fix 1 all nvt/sphere temp 300.0 300.0 100.0 disc
fix 1 all nvt/sphere temp 300.0 300.0 100.0 drag 0.2 :pre
[Description:]
Perform constant NVT integration to update position, velocity, and
angular velocity each timestep for finite-size spherical particles in
the group using a Nose/Hoover temperature thermostat. V is volume; T
is temperature. This creates a system trajectory consistent with the
canonical ensemble.
This fix differs from the "fix nvt"_fix_nh.html command, which
assumes point particles and only updates their position and velocity.
The thermostat is applied to both the translational and rotational
degrees of freedom for the spherical particles, assuming a compute is
used which calculates a temperature that includes the rotational
degrees of freedom (see below). The translational degrees of freedom
can also have a bias velocity removed from them before thermostatting
takes place; see the description below.
If the {disc} keyword is used, then each particle is treated as a 2d
disc (circle) instead of as a sphere. This is only possible for 2d
simulations, as defined by the "dimension"_dimension.html keyword.
The only difference between discs and spheres in this context is their
moment of inertia, as used in the time integration.
Additional parameters affecting the thermostat are specified by
keywords and values documented with the "fix nvt"_fix_nh.html
command. See, for example, discussion of the {temp} and {drag}
keywords.
This fix computes a temperature each timestep. To do this, the fix
creates its own compute of style "temp/sphere", as if this command
had been issued:
compute fix-ID_temp group-ID temp/sphere :pre
See the "compute temp/sphere"_compute_temp_sphere.html command for
details. Note that the ID of the new compute is the fix-ID +
underscore + "temp", and the group for the new compute is the same as
the fix group.
Note that this is NOT the compute used by thermodynamic output (see
the "thermo_style"_thermo_style.html command) with ID = {thermo_temp}.
This means you can change the attributes of this fix's temperature
(e.g. its degrees-of-freedom) via the
"compute_modify"_compute_modify.html command or print this temperature
during thermodynamic output via the "thermo_style
custom"_thermo_style.html command using the appropriate compute-ID.
It also means that changing attributes of {thermo_temp} will have no
effect on this fix.
Like other fixes that perform thermostatting, this fix can be used
with "compute commands"_compute.html that calculate a temperature
after removing a "bias" from the atom velocities. E.g. removing the
center-of-mass velocity from a group of atoms or only calculating
temperature on the x-component of velocity or only calculating
temperature for atoms in a geometric region. This is not done by
default, but only if the "fix_modify"_fix_modify.html command is used
to assign a temperature compute to this fix that includes such a bias
term. See the doc pages for individual "compute
commands"_compute.html to determine which ones include a bias. In
this case, the thermostat works in the following manner: the current
temperature is calculated taking the bias into account, bias is
removed from each atom, thermostatting is performed on the remaining
thermal degrees of freedom, and the bias is added back in.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restart, fix_modify, output, run start/stop, minimize info:]
This fix writes the state of the Nose/Hoover thermostat to "binary
restart files"_restart.html. See the "read_restart"_read_restart.html
command for info on how to re-specify a fix in an input script that
reads a restart file, so that the operation of the fix continues in an
uninterrupted fashion.
The "fix_modify"_fix_modify.html {temp} option is supported by this
fix. You can use it to assign a "compute"_compute.html you have
defined to this fix which will be used in its thermostatting
procedure.
The "fix_modify"_fix_modify.html {energy} option is supported by this
fix to add the energy change induced by Nose/Hoover thermostatting to
the system's potential energy as part of "thermodynamic
output"_thermo_style.html.
This fix computes the same global scalar and global vector of
quantities as does the "fix nvt"_fix_nh.html command.
This fix can ramp its target temperature over multiple runs, using the
{start} and {stop} keywords of the "run"_run.html command. See the
"run"_run.html command for details of how to do this.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix requires that atoms store torque and angular velocity (omega)
and a radius as defined by the "atom_style sphere"_atom_style.html
command.
All particles in the group must be finite-size spheres. They cannot
be point particles.
Use of the {disc} keyword is only allowed for 2d simulations, as
defined by the "dimension"_dimension.html keyword.
[Related commands:]
"fix nvt"_fix_nh.html, "fix nve_sphere"_fix_nve_sphere.html, "fix
nvt_asphere"_fix_nvt_asphere.html, "fix
npt_sphere"_fix_npt_sphere.html, "fix_modify"_fix_modify.html
[Default:] none
diff --git a/doc/src/fix_qeq_comb.txt b/doc/src/fix_qeq_comb.txt
index 30c5003e7..7f8240412 100644
--- a/doc/src/fix_qeq_comb.txt
+++ b/doc/src/fix_qeq_comb.txt
@@ -1,132 +1,132 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix qeq/comb command :h3
fix qeq/comb/omp command :h3
[Syntax:]
fix ID group-ID qeq/comb Nevery precision keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
qeq/comb = style name of this fix command :l
Nevery = perform charge equilibration every this many steps :l
precision = convergence criterion for charge equilibration :l
zero or more keyword/value pairs may be appended :l
keyword = {file} :l
{file} value = filename
filename = name of file to write QEQ equilibration info to :pre
:ule
[Examples:]
fix 1 surface qeq/comb 10 0.0001 :pre
[Description:]
Perform charge equilibration (QeQ) in conjunction with the COMB
(Charge-Optimized Many-Body) potential as described in
"(COMB_1)"_#COMB_1 and "(COMB_2)"_#COMB_2. It performs the charge
equilibration portion of the calculation using the so-called QEq
method, whereby the charge on each atom is adjusted to minimize the
energy of the system. This fix can only be used with the COMB
potential; see the "fix qeq/reax"_fix_qeq_reax.html command for a QeQ
calculation that can be used with any potential.
Only charges on the atoms in the specified group are equilibrated.
The fix relies on the pair style (COMB in this case) to calculate the
per-atom electronegativity (effective force on the charges). An
electronegativity equalization calculation (or QEq) is performed in an
iterative fashion, which in parallel requires communication at each
iteration for processors to exchange charge information about nearby
atoms with each other. See "Rappe_and_Goddard"_#Rappe_and_Goddard and
"Rick_and_Stuart"_#Rick_and_Stuart for details.
During a run, charge equilibration is performed every {Nevery} time
steps. Charge equilibration is also always enforced on the first step
of each run. The {precision} argument controls the tolerance for the
difference in electronegativity for all atoms during charge
equilibration. {Precision} is a trade-off between the cost of
performing charge equilibration (more iterations) and accuracy.
If the {file} keyword is used, then information about each
equilibration calculation is written to the specified file.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html.
The "fix_modify"_fix_modify.html {respa} option is supported by this
fix. This allows to set at which level of the "r-RESPA"_run_style.html
integrator the fix is performing charge equilibration. Default is
the outermost level.
This fix produces a per-atom vector which can be accessed by various
"output commands"_Section_howto.html#howto_15. The vector stores the
gradient of the charge on each atom. The per-atom values be accessed
on any timestep.
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command.
This fix can be invoked during "energy minimization"_minimize.html.
[Restrictions:]
This fix command currently only supports "pair style {comb}"_pair_comb.html.
[Related commands:]
"pair_style comb"_pair_comb.html
[Default:]
No file output is performed.
:line
:link(COMB_1)
[(COMB_1)] J. Yu, S. B. Sinnott, S. R. Phillpot, Phys Rev B, 75, 085311 (2007),
:link(COMB_2)
[(COMB_2)] T.-R. Shan, B. D. Devine, T. W. Kemper, S. B. Sinnott, S. R.
Phillpot, Phys Rev B, 81, 125328 (2010).
:link(Rappe_and_Goddard)
[(Rappe_and_Goddard)] A. K. Rappe, W. A. Goddard, J Phys Chem 95, 3358
(1991).
:link(Rick_and_Stuart)
[(Rick_and_Stuart)] S. W. Rick, S. J. Stuart, B. J. Berne, J Chem Phys
101, 16141 (1994).
diff --git a/doc/src/fix_qeq_reax.txt b/doc/src/fix_qeq_reax.txt
index a1a19b736..18450c7cd 100644
--- a/doc/src/fix_qeq_reax.txt
+++ b/doc/src/fix_qeq_reax.txt
@@ -1,130 +1,130 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix qeq/reax command :h3
fix qeq/reax/kk command :h3
fix qeq/reax/omp command :h3
[Syntax:]
fix ID group-ID qeq/reax Nevery cutlo cuthi tolerance params args :pre
ID, group-ID are documented in "fix"_fix.html command
qeq/reax = style name of this fix command
Nevery = perform QEq every this many steps
cutlo,cuthi = lo and hi cutoff for Taper radius
tolerance = precision to which charges will be equilibrated
params = reax/c or a filename
args = {dual} (optional) :ul
[Examples:]
fix 1 all qeq/reax 1 0.0 10.0 1.0e-6 reax/c
fix 1 all qeq/reax 1 0.0 10.0 1.0e-6 param.qeq :pre
[Description:]
Perform the charge equilibration (QEq) method as described in "(Rappe
and Goddard)"_#Rappe2 and formulated in "(Nakano)"_#Nakano2. It is
typically used in conjunction with the ReaxFF force field model as
implemented in the "pair_style reax/c"_pair_reaxc.html command, but
it can be used with any potential in LAMMPS, so long as it defines and
uses charges on each atom. The "fix qeq/comb"_fix_qeq_comb.html
command should be used to perform charge equilibration with the "COMB
potential"_pair_comb.html. For more technical details about the
charge equilibration performed by fix qeq/reax, see the
"(Aktulga)"_#qeq-Aktulga paper.
The QEq method minimizes the electrostatic energy of the system by
adjusting the partial charge on individual atoms based on interactions
with their neighbors. It requires some parameters for each atom type.
If the {params} setting above is the word "reax/c", then these are
extracted from the "pair_style reax/c"_pair_reaxc.html command and
the ReaxFF force field file it reads in. If a file name is specified
for {params}, then the parameters are taken from the specified file
and the file must contain one line for each atom type. The latter
form must be used when performing QeQ with a non-ReaxFF potential.
Each line should be formatted as follows:
itype chi eta gamma :pre
where {itype} is the atom type from 1 to Ntypes, {chi} denotes the
electronegativity in eV, {eta} denotes the self-Coulomb
potential in eV, and {gamma} denotes the valence orbital
exponent. Note that these 3 quantities are also in the ReaxFF
potential file, except that eta is defined here as twice the eta value
in the ReaxFF file. Note that unlike the rest of LAMMPS, the units
of this fix are hard-coded to be A, eV, and electronic charge.
The optional {dual} keyword allows to perform the optimization
of the S and T matrices in parallel. This is only supported for
the {qeq/reax/omp} style. Otherwise they are processed separately.
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. No global scalar or vector or per-atom
quantities are stored by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is invoked during "energy minimization"_minimize.html.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This fix is part of the USER-REAXC package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This fix does not correctly handle interactions
involving multiple periodic images of the same atom. Hence, it should not
be used for periodic cell dimensions less than 10 angstroms.
[Related commands:]
"pair_style reax/c"_pair_reaxc.html
[Default:] none
:line
:link(Rappe2)
[(Rappe)] Rappe and Goddard III, Journal of Physical Chemistry, 95,
3358-3363 (1991).
:link(Nakano2)
[(Nakano)] Nakano, Computer Physics Communications, 104, 59-69 (1997).
:link(qeq-Aktulga)
[(Aktulga)] Aktulga, Fogarty, Pandit, Grama, Parallel Computing, 38,
245-259 (2012).
diff --git a/doc/src/fix_reax_bonds.txt b/doc/src/fix_reax_bonds.txt
index aadb0a9cb..54aa7faef 100644
--- a/doc/src/fix_reax_bonds.txt
+++ b/doc/src/fix_reax_bonds.txt
@@ -1,113 +1,113 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix reax/bonds command :h3
fix reax/c/bonds command :h3
fix reax/c/bonds/kk command :h3
[Syntax:]
fix ID group-ID reax/bonds Nevery filename :pre
ID, group-ID are documented in "fix"_fix.html command
reax/bonds = style name of this fix command
Nevery = output interval in timesteps
filename = name of output file :ul
[Examples:]
fix 1 all reax/bonds 100 bonds.tatb
fix 1 all reax/c/bonds 100 bonds.reaxc :pre
[Description:]
Write out the bond information computed by the ReaxFF potential
specified by "pair_style reax"_pair_reax.html or "pair_style
reax/c"_pair_reaxc.html in the exact same format as the original
stand-alone ReaxFF code of Adri van Duin. The bond information is
written to {filename} on timesteps that are multiples of {Nevery},
including timestep 0. For time-averaged chemical species analysis,
please see the "fix reaxc/c/species"_fix_reaxc_species.html command.
The format of the output file should be reasonably self-explanatory.
The meaning of the column header abbreviations is as follows:
id = atom id
type = atom type
nb = number of bonds
id_1 = atom id of first bond
id_nb = atom id of Nth bond
mol = molecule id
bo_1 = bond order of first bond
bo_nb = bond order of Nth bond
abo = atom bond order (sum of all bonds)
nlp = number of lone pairs
q = atomic charge :ul
If the filename ends with ".gz", the output file is written in gzipped
format. A gzipped dump file will be about 3x smaller than the text
version, but will also take longer to write.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section_accelerate"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section_accelerate"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
The fix reax/bonds command requires that the "pair_style
reax"_pair_reax.html be invoked. This fix is part of the REAX
package. It is only enabled if LAMMPS was built with that package,
which also requires the REAX library be built and linked with LAMMPS.
The fix reax/c/bonds command requires that the "pair_style
reax/c"_pair_reaxc.html be invoked. This fix is part of the
USER-REAXC package. It is only enabled if LAMMPS was built with that
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info.
To write gzipped bond files, you must compile LAMMPS with the
-DLAMMPS_GZIP option.
[Related commands:]
"pair_style reax"_pair_reax.html, "pair_style
reax/c"_pair_reaxc.html, "fix reax/c/species"_fix_reaxc_species.html
[Default:] none
diff --git a/doc/src/fix_reaxc_species.txt b/doc/src/fix_reaxc_species.txt
index 9a588356e..7c920791f 100644
--- a/doc/src/fix_reaxc_species.txt
+++ b/doc/src/fix_reaxc_species.txt
@@ -1,187 +1,187 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix reax/c/species command :h3
fix reax/c/species/kk command :h3
[Syntax:]
fix ID group-ID reax/c/species Nevery Nrepeat Nfreq filename keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
reax/c/species = style name of this command :l
Nevery = sample bond-order every this many timesteps :l
Nrepeat = # of bond-order samples used for calculating averages :l
Nfreq = calculate average bond-order every this many timesteps :l
filename = name of output file :l
zero or more keyword/value pairs may be appended :l
keyword = {cutoff} or {element} or {position} :l
{cutoff} value = I J Cutoff
I, J = atom types
Cutoff = Bond-order cutoff value for this pair of atom types
{element} value = Element1, Element2, ...
{position} value = posfreq filepos
posfreq = write position files every this many timestep
filepos = name of position output file :pre
:ule
[Examples:]
fix 1 all reax/c/species 10 10 100 species.out
fix 1 all reax/c/species 1 2 20 species.out cutoff 1 1 0.40 cutoff 1 2 0.55
fix 1 all reax/c/species 1 100 100 species.out element Au O H position 1000 AuOH.pos :pre
[Description:]
Write out the chemical species information computed by the ReaxFF
potential specified by "pair_style reax/c"_pair_reaxc.html.
Bond-order values (either averaged or instantaneous, depending on
value of {Nrepeat}) are used to determine chemical bonds. Every
{Nfreq} timesteps, chemical species information is written to
{filename} as a two line output. The first line is a header
containing labels. The second line consists of the following:
timestep, total number of molecules, total number of distinct species,
number of molecules of each species. In this context, "species" means
a unique molecule. The chemical formula of each species is given in
the first line.
If the filename ends with ".gz", the output file is written in gzipped
format. A gzipped dump file will be about 3x smaller than the text version,
but will also take longer to write.
Optional keyword {cutoff} can be assigned to change the minimum
bond-order values used in identifying chemical bonds between pairs of
atoms. Bond-order cutoffs should be carefully chosen, as bond-order
cutoffs that are too small may include too many bonds (which will
result in an error), while cutoffs that are too large will result in
fragmented molecules. The default cutoff of 0.3 usually gives good
results.
The optional keyword {element} can be used to specify the chemical
symbol printed for each LAMMPS atom type. The number of symbols must
match the number of LAMMPS atom types and each symbol must consist of
1 or 2 alphanumeric characters. Normally, these symbols should be
chosen to match the chemical identity of each LAMMPS atom type, as
specified using the "reax/c pair_coeff"_pair_reaxc.html command and
the ReaxFF force field file.
The optional keyword {position} writes center-of-mass positions of
each identified molecules to file {filepos} every {posfreq} timesteps.
The first line contains information on timestep, total number of
molecules, total number of distinct species, and box dimensions. The
second line is a header containing labels. From the third line
downward, each molecule writes a line of output containing the
following information: molecule ID, number of atoms in this molecule,
chemical formula, total charge, and center-of-mass xyz positions of
this molecule. The xyz positions are in fractional coordinates
relative to the box dimensions.
For the keyword {position}, the {filepos} is the name of the output
file. It can contain the wildcard character "*". If the "*"
character appears in {filepos}, then one file per snapshot is written
at {posfreq} and the "*" character is replaced with the timestep
value. For example, AuO.pos.* becomes AuO.pos.0, AuO.pos.1000, etc.
:line
The {Nevery}, {Nrepeat}, and {Nfreq} arguments specify on what
timesteps the bond-order values are sampled to get the average bond
order. The species analysis is performed using the average bond-order
on timesteps that are a multiple of {Nfreq}. The average is over
{Nrepeat} bond-order samples, computed in the preceding portion of the
simulation every {Nevery} timesteps. {Nfreq} must be a multiple of
{Nevery} and {Nevery} must be non-zero even if {Nrepeat} is 1.
Also, the timesteps
contributing to the average bond-order cannot overlap,
i.e. Nrepeat*Nevery can not exceed Nfreq.
For example, if Nevery=2, Nrepeat=6, and Nfreq=100, then bond-order
values on timesteps 90,92,94,96,98,100 will be used to compute the
average bond-order for the species analysis output on timestep 100.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix.
This fix computes both a global vector of length 2 and a per-atom
vector, either of which can be accessed by various "output
commands"_Section_howto.html#howto_15. The values in the global
vector are "intensive".
The 2 values in the global vector are as follows:
1 = total number of molecules
2 = total number of distinct species :ul
The per-atom vector stores the molecule ID for each atom as identified
by the fix. If an atom is not in a molecule, its ID will be 0.
For atoms in the same molecule, the molecule ID for all of them
will be the same and will be equal to the smallest atom ID of
any atom in the molecule.
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command. This fix is not invoked during "energy
minimization"_minimize.html.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section_accelerate"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section_accelerate"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
The fix species currently only works with
"pair_style reax/c"_pair_reaxc.html and it requires that the "pair_style
reax/c"_pair_reaxc.html be invoked. This fix is part of the
USER-REAXC package. It is only enabled if LAMMPS was built with that
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info.
To write gzipped species files, you must compile LAMMPS with the
-DLAMMPS_GZIP option.
It should be possible to extend it to other reactive pair_styles (such as
"rebo"_pair_airebo.html, "airebo"_pair_airebo.html,
"comb"_pair_comb.html, and "bop"_pair_bop.html), but this has not yet been done.
[Related commands:]
"pair_style reax/c"_pair_reaxc.html, "fix
reax/bonds"_fix_reax_bonds.html
[Default:]
The default values for bond-order cutoffs are 0.3 for all I-J pairs. The
default element symbols are C, H, O, N. Position files are not written
by default.
diff --git a/doc/src/fix_rigid.txt b/doc/src/fix_rigid.txt
index 87021b855..62969112f 100644
--- a/doc/src/fix_rigid.txt
+++ b/doc/src/fix_rigid.txt
@@ -1,822 +1,822 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix rigid command :h3
fix rigid/nve command :h3
fix rigid/nvt command :h3
fix rigid/npt command :h3
fix rigid/nph command :h3
fix rigid/small command :h3
fix rigid/nve/small command :h3
fix rigid/nvt/small command :h3
fix rigid/npt/small command :h3
fix rigid/nph/small command :h3
[Syntax:]
fix ID group-ID style bodystyle args keyword values ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
style = {rigid} or {rigid/nve} or {rigid/nvt} or {rigid/npt} or {rigid/nph} or {rigid/small} or {rigid/nve/small} or {rigid/nvt/small} or {rigid/npt/small} or {rigid/nph/small} :l
bodystyle = {single} or {molecule} or {group} :l
{single} args = none
{molecule} args = none
{group} args = N groupID1 groupID2 ...
N = # of groups
groupID1, groupID2, ... = list of N group IDs :pre
zero or more keyword/value pairs may be appended :l
keyword = {langevin} or {reinit} or {temp} or {iso} or {aniso} or {x} or {y} or {z} or {couple} or {tparam} or {pchain} or {dilate} or {force} or {torque} or {infile} :l
{langevin} values = Tstart Tstop Tperiod seed
Tstart,Tstop = desired temperature at start/stop of run (temperature units)
Tdamp = temperature damping parameter (time units)
seed = random number seed to use for white noise (positive integer)
{reinit} = {yes} or {no}
{temp} values = Tstart Tstop Tdamp
Tstart,Tstop = desired temperature at start/stop of run (temperature units)
Tdamp = temperature damping parameter (time units)
{iso} or {aniso} values = Pstart Pstop Pdamp
Pstart,Pstop = scalar external pressure at start/end of run (pressure units)
Pdamp = pressure damping parameter (time units)
{x} or {y} or {z} values = Pstart Pstop Pdamp
Pstart,Pstop = external stress tensor component at start/end of run (pressure units)
Pdamp = stress damping parameter (time units)
{couple} = {none} or {xyz} or {xy} or {yz} or {xz}
{tparam} values = Tchain Titer Torder
Tchain = length of Nose/Hoover thermostat chain
Titer = number of thermostat iterations performed
Torder = 3 or 5 = Yoshida-Suzuki integration parameters
{pchain} values = Pchain
Pchain = length of the Nose/Hoover thermostat chain coupled with the barostat
{dilate} value = dilate-group-ID
dilate-group-ID = only dilate atoms in this group due to barostat volume changes
{force} values = M xflag yflag zflag
M = which rigid body from 1-Nbody (see asterisk form below)
xflag,yflag,zflag = off/on if component of center-of-mass force is active
{torque} values = M xflag yflag zflag
M = which rigid body from 1-Nbody (see asterisk form below)
xflag,yflag,zflag = off/on if component of center-of-mass torque is active
{infile} filename
filename = file with per-body values of mass, center-of-mass, moments of inertia
{mol} value = template-ID
template-ID = ID of molecule template specified in a separate "molecule"_molecule.html command :pre
:ule
[Examples:]
fix 1 clump rigid single reinit yes
fix 1 clump rigid/small molecule
fix 1 clump rigid single force 1 off off on langevin 1.0 1.0 1.0 428984
fix 1 polychains rigid/nvt molecule temp 1.0 1.0 5.0 reinit no
fix 1 polychains rigid molecule force 1*5 off off off force 6*10 off off on
fix 1 polychains rigid/small molecule langevin 1.0 1.0 1.0 428984
fix 2 fluid rigid group 3 clump1 clump2 clump3 torque * off off off
fix 1 rods rigid/npt molecule temp 300.0 300.0 100.0 iso 0.5 0.5 10.0
fix 1 particles rigid/npt molecule temp 1.0 1.0 5.0 x 0.5 0.5 1.0 z 0.5 0.5 1.0 couple xz
fix 1 water rigid/nph molecule iso 0.5 0.5 1.0
fix 1 particles rigid/npt/small molecule temp 1.0 1.0 1.0 iso 0.5 0.5 1.0 :pre
[Description:]
Treat one or more sets of atoms as independent rigid bodies. This
means that each timestep the total force and torque on each rigid body
is computed as the sum of the forces and torques on its constituent
particles. The coordinates, velocities, and orientations of the atoms
in each body are then updated so that the body moves and rotates as a
single entity. This is implemented by creating internal data structures
for each rigid body and performing time integration on these data
structures. Positions, velocities, and orientations of the constituent
particles are regenerated from the rigid body data structures in every
time step. This restricts which operations and fixes can be applied to
rigid bodies. See below for a detailed discussion.
Examples of large rigid bodies are a colloidal particle, or portions
of a biomolecule such as a protein.
Example of small rigid bodies are patchy nanoparticles, such as those
modeled in "this paper"_#Zhang1 by Sharon Glotzer's group, clumps of
granular particles, lipid molecules consiting of one or more point
dipoles connected to other spheroids or ellipsoids, irregular
particles built from line segments (2d) or triangles (3d), and
coarse-grain models of nano or colloidal particles consisting of a
small number of constituent particles. Note that the "fix
shake"_fix_shake.html command can also be used to rigidify small
molecules of 2, 3, or 4 atoms, e.g. water molecules. That fix treats
the constituent atoms as point masses.
These fixes also update the positions and velocities of the atoms in
each rigid body via time integration, in the NVE, NVT, NPT, or NPH
ensemble, as described below.
There are two main variants of this fix, fix rigid and fix
rigid/small. The NVE/NVT/NPT/NHT versions belong to one of the two
variants, as their style names indicate.
NOTE: Not all of the {bodystyle} options and keyword/value options are
available for both the {rigid} and {rigid/small} variants. See
details below.
The {rigid} styles are typically the best choice for a system with a
small number of large rigid bodies, each of which can extend across
the domain of many processors. It operates by creating a single
global list of rigid bodies, which all processors contribute to.
MPI_Allreduce operations are performed each timestep to sum the
contributions from each processor to the force and torque on all the
bodies. This operation will not scale well in parallel if large
numbers of rigid bodies are simulated.
The {rigid/small} styles are typically best for a system with a large
number of small rigid bodies. Each body is assigned to the atom
closest to the geometrical center of the body. The fix operates using
local lists of rigid bodies owned by each processor and information is
exchanged and summed via local communication between neighboring
processors when ghost atom info is accumulated.
NOTE: To use the {rigid/small} styles the ghost atom cutoff must be
large enough to span the distance between the atom that owns the body
and every other atom in the body. This distance value is printed out
when the rigid bodies are defined. If the
"pair_style"_pair_style.html cutoff plus neighbor skin does not span
this distance, then you should use the "comm_modify
cutoff"_comm_modify.html command with a setting epsilon larger than
the distance.
Which of the two variants is faster for a particular problem is hard
to predict. The best way to decide is to perform a short test run.
Both variants should give identical numerical answers for short runs.
Long runs should give statistically similar results, but round-off
differences may accumulate to produce divergent trajectories.
NOTE: You should not update the atoms in rigid bodies via other
time-integration fixes (e.g. "fix nve"_fix_nve.html, "fix
nvt"_fix_nh.html, "fix npt"_fix_nh.html, "fix move"_fix_move.html),
or you will have conflicting updates to positions and velocities
resulting in unphysical behavior in most cases. When performing a hybrid
simulation with some atoms in rigid bodies, and some not, a separate
time integration fix like "fix nve"_fix_nve.html or "fix
nvt"_fix_nh.html should be used for the non-rigid particles.
NOTE: These fixes are overkill if you simply want to hold a collection
of atoms stationary or have them move with a constant velocity. A
simpler way to hold atoms stationary is to not include those atoms in
your time integration fix. E.g. use "fix 1 mobile nve" instead of
"fix 1 all nve", where "mobile" is the group of atoms that you want to
move. You can move atoms with a constant velocity by assigning them
an initial velocity (via the "velocity"_velocity.html command),
setting the force on them to 0.0 (via the "fix
setforce"_fix_setforce.html command), and integrating them as usual
(e.g. via the "fix nve"_fix_nve.html command).
IMPORTANT NOTE: The aggregate properties of each rigid body are
calculated at the start of a simulation run and are maintained in
internal data structures. The properties include the position and
velocity of the center-of-mass of the body, its moments of inertia, and
its angular momentum. This is done using the properties of the
constituent atoms of the body at that point in time (or see the {infile}
keyword option). Thereafter, changing these properties of individual
atoms in the body will have no effect on a rigid body's dynamics, unless
they effect any computation of per-atom forces or torques. If the
keyword {reinit} is set to {yes} (the default), the rigid body data
structures will be recreated at the beginning of each {run} command;
if the keyword {reinit} is set to {no}, the rigid body data structures
will be built only at the very first {run} command and maintained for
as long as the rigid fix is defined. For example, you might think you
could displace the atoms in a body or add a large velocity to each atom
in a body to make it move in a desired direction before a 2nd run is
performed, using the "set"_set.html or
"displace_atoms"_displace_atoms.html or "velocity"_velocity.html
commands. But these commands will not affect the internal attributes
of the body unless {reinit} is set to {yes}. With {reinit} set to {no}
(or using the {infile} option, which implies {reinit} {no}) the position
and velocity of individual atoms in the body will be reset when time
integration starts again.
:line
Each rigid body must have two or more atoms. An atom can belong to at
most one rigid body. Which atoms are in which bodies can be defined
via several options.
NOTE: With the {rigid/small} styles, which require that {bodystyle} be
specified as {molecule}, you can define a system that has no rigid
bodies initially. This is useful when you are using the {mol} keyword
in conjunction with another fix that is adding rigid bodies on-the-fly
as molecules, such as "fix deposit"_fix_deposit.html or "fix
pour"_fix_pour.html.
For bodystyle {single} the entire fix group of atoms is treated as one
rigid body. This option is only allowed for the {rigid} styles.
For bodystyle {molecule}, atoms are grouped into rigid bodies by their
respective molecule IDs: each set of atoms in the fix group with the
same molecule ID is treated as a different rigid body. This option is
allowed for both the {rigid} and {rigid/small} styles. Note that
atoms with a molecule ID = 0 will be treated as a single rigid body.
For a system with atomic solvent (typically this is atoms with
molecule ID = 0) surrounding rigid bodies, this may not be what you
want. Thus you should be careful to use a fix group that only
includes atoms you want to be part of rigid bodies.
For bodystyle {group}, each of the listed groups is treated as a
separate rigid body. Only atoms that are also in the fix group are
included in each rigid body. This option is only allowed for the
{rigid} styles.
NOTE: To compute the initial center-of-mass position and other
properties of each rigid body, the image flags for each atom in the
body are used to "unwrap" the atom coordinates. Thus you must insure
that these image flags are consistent so that the unwrapping creates a
valid rigid body (one where the atoms are close together),
particularly if the atoms in a single rigid body straddle a periodic
boundary. This means the input data file or restart file must define
the image flags for each atom consistently or that you have used the
"set"_set.html command to specify them correctly. If a dimension is
non-periodic then the image flag of each atom must be 0 in that
dimension, else an error is generated.
The {force} and {torque} keywords discussed next are only allowed for
the {rigid} styles.
By default, each rigid body is acted on by other atoms which induce an
external force and torque on its center of mass, causing it to
translate and rotate. Components of the external center-of-mass force
and torque can be turned off by the {force} and {torque} keywords.
This may be useful if you wish a body to rotate but not translate, or
vice versa, or if you wish it to rotate or translate continuously
unaffected by interactions with other particles. Note that if you
expect a rigid body not to move or rotate by using these keywords, you
must insure its initial center-of-mass translational or angular
velocity is 0.0. Otherwise the initial translational or angular
momentum the body has will persist.
An xflag, yflag, or zflag set to {off} means turn off the component of
force of torque in that dimension. A setting of {on} means turn on
the component, which is the default. Which rigid body(s) the settings
apply to is determined by the first argument of the {force} and
{torque} keywords. It can be an integer M from 1 to Nbody, where
Nbody is the number of rigid bodies defined. A wild-card asterisk can
be used in place of, or in conjunction with, the M argument to set the
flags for multiple rigid bodies. This takes the form "*" or "*n" or
"n*" or "m*n". If N = the number of rigid bodies, then an asterisk
with no numeric values means all bodies from 1 to N. A leading
asterisk means all bodies from 1 to n (inclusive). A trailing
asterisk means all bodies from n to N (inclusive). A middle asterisk
means all types from m to n (inclusive). Note that you can use the
{force} or {torque} keywords as many times as you like. If a
particular rigid body has its component flags set multiple times, the
settings from the final keyword are used.
NOTE: For computational efficiency, you may wish to turn off pairwise
and bond interactions within each rigid body, as they no longer
contribute to the motion. The "neigh_modify
exclude"_neigh_modify.html and "delete_bonds"_delete_bonds.html
commands are used to do this. If the rigid bodies have strongly
overlapping atoms, you may need to turn off these interactions to
avoid numerical problems due to large equal/opposite intra-body forces
swamping the contribution of small inter-body forces.
For computational efficiency, you should typically define one fix
rigid or fix rigid/small command which includes all the desired rigid
bodies. LAMMPS will allow multiple rigid fixes to be defined, but it
is more expensive.
:line
The constituent particles within a rigid body can be point particles
(the default in LAMMPS) or finite-size particles, such as spheres or
ellipsoids or line segments or triangles. See the "atom_style sphere
and ellipsoid and line and tri"_atom_style.html commands for more
details on these kinds of particles. Finite-size particles contribute
differently to the moment of inertia of a rigid body than do point
particles. Finite-size particles can also experience torque (e.g. due
to "frictional granular interactions"_pair_gran.html) and have an
orientation. These contributions are accounted for by these fixes.
Forces between particles within a body do not contribute to the
external force or torque on the body. Thus for computational
efficiency, you may wish to turn off pairwise and bond interactions
between particles within each rigid body. The "neigh_modify
exclude"_neigh_modify.html and "delete_bonds"_delete_bonds.html
commands are used to do this. For finite-size particles this also
means the particles can be highly overlapped when creating the rigid
body.
:line
The {rigid}, {rigid/nve}, {rigid/small}, and {rigid/small/nve} styles
perform constant NVE time integration. They are referred to below as
the 4 NVE rigid styles. The only difference is that the {rigid} and
{rigid/small} styles use an integration technique based on Richardson
iterations. The {rigid/nve} and {rigid/small/nve} styles uses the
methods described in the paper by "Miller"_#Miller3, which are thought
to provide better energy conservation than an iterative approach.
The {rigid/nvt} and {rigid/nvt/small} styles performs constant NVT
integration using a Nose/Hoover thermostat with chains as described
originally in "(Hoover)"_#Hoover and "(Martyna)"_#Martyna2, which
thermostats both the translational and rotational degrees of freedom
of the rigid bodies. They are referred to below as the 2 NVT rigid
styles. The rigid-body algorithm used by {rigid/nvt} is described in
the paper by "Kamberaj"_#Kamberaj.
The {rigid/npt}, {rigid/nph}, {rigid/npt/small}, and {rigid/nph/small}
styles perform constant NPT or NPH integration using a Nose/Hoover
barostat with chains. They are referred to below as the 4 NPT and NPH
rigid styles. For the NPT case, the same Nose/Hoover thermostat is
also used as with {rigid/nvt} and {rigid/nvt/small}.
The barostat parameters are specified using one or more of the {iso},
{aniso}, {x}, {y}, {z} and {couple} keywords. These keywords give you
the ability to specify 3 diagonal components of the external stress
tensor, and to couple these components together so that the dimensions
they represent are varied together during a constant-pressure
simulation. The effects of these keywords are similar to those
defined in "fix npt/nph"_fix_nh.html
NOTE: Currently the {rigid/npt}, {rigid/nph}, {rigid/npt/small}, and
{rigid/nph/small} styles do not support triclinic (non-orthogonal)
boxes.
The target pressures for each of the 6 components of the stress tensor
can be specified independently via the {x}, {y}, {z} keywords, which
correspond to the 3 simulation box dimensions. For each component,
the external pressure or tensor component at each timestep is a ramped
value during the run from {Pstart} to {Pstop}. If a target pressure is
specified for a component, then the corresponding box dimension will
change during a simulation. For example, if the {y} keyword is used,
the y-box length will change. A box dimension will not change if that
component is not specified, although you have the option to change
that dimension via the "fix deform"_fix_deform.html command.
For all barostat keywords, the {Pdamp} parameter operates like the
{Tdamp} parameter, determining the time scale on which pressure is
relaxed. For example, a value of 10.0 means to relax the pressure in
a timespan of (roughly) 10 time units (e.g. tau or fmsec or psec - see
the "units"_units.html command).
Regardless of what atoms are in the fix group (the only atoms which
are time integrated), a global pressure or stress tensor is computed
for all atoms. Similarly, when the size of the simulation box is
changed, all atoms are re-scaled to new positions, unless the keyword
{dilate} is specified with a {dilate-group-ID} for a group that
represents a subset of the atoms. This can be useful, for example, to
leave the coordinates of atoms in a solid substrate unchanged and
controlling the pressure of a surrounding fluid. Another example is a
system consisting of rigid bodies and point particles where the
barostat is only coupled with the rigid bodies. This option should be
used with care, since it can be unphysical to dilate some atoms and
not others, because it can introduce large, instantaneous
displacements between a pair of atoms (one dilated, one not) that are
far from the dilation origin.
The {couple} keyword allows two or three of the diagonal components of
the pressure tensor to be "coupled" together. The value specified
with the keyword determines which are coupled. For example, {xz}
means the {Pxx} and {Pzz} components of the stress tensor are coupled.
{Xyz} means all 3 diagonal components are coupled. Coupling means two
things: the instantaneous stress will be computed as an average of the
corresponding diagonal components, and the coupled box dimensions will
be changed together in lockstep, meaning coupled dimensions will be
dilated or contracted by the same percentage every timestep. The
{Pstart}, {Pstop}, {Pdamp} parameters for any coupled dimensions must
be identical. {Couple xyz} can be used for a 2d simulation; the {z}
dimension is simply ignored.
The {iso} and {aniso} keywords are simply shortcuts that are
equivalent to specifying several other keywords together.
The keyword {iso} means couple all 3 diagonal components together when
pressure is computed (hydrostatic pressure), and dilate/contract the
dimensions together. Using "iso Pstart Pstop Pdamp" is the same as
specifying these 4 keywords:
x Pstart Pstop Pdamp
y Pstart Pstop Pdamp
z Pstart Pstop Pdamp
couple xyz :pre
The keyword {aniso} means {x}, {y}, and {z} dimensions are controlled
independently using the {Pxx}, {Pyy}, and {Pzz} components of the
stress tensor as the driving forces, and the specified scalar external
pressure. Using "aniso Pstart Pstop Pdamp" is the same as specifying
these 4 keywords:
x Pstart Pstop Pdamp
y Pstart Pstop Pdamp
z Pstart Pstop Pdamp
couple none :pre
:line
The keyword/value option pairs are used in the following ways.
The {reinit} keyword determines, whether the rigid body properties
are reinitialized between run commands. With the option {yes} (the
default) this is done, with the option {no} this is not done. Turning
off the reinitialization can be helpful to protect rigid bodies against
unphysical manipulations between runs or when properties cannot be
easily recomputed (e.g. when read from a file). When using the {infile}
keyword, the {reinit} option is automatically set to {no}.
The {langevin} and {temp} and {tparam} keywords perform thermostatting
of the rigid bodies, altering both their translational and rotational
degrees of freedom. What is meant by "temperature" of a collection of
rigid bodies and how it can be monitored via the fix output is
discussed below.
The {langevin} keyword applies a Langevin thermostat to the constant
NVE time integration performed by any of the 4 NVE rigid styles:
{rigid}, {rigid/nve}, {rigid/small}, {rigid/small/nve}. It cannot be
used with the 2 NVT rigid styles: {rigid/nvt}, {rigid/small/nvt}. The
desired temperature at each timestep is a ramped value during the run
from {Tstart} to {Tstop}. The {Tdamp} parameter is specified in time
units and determines how rapidly the temperature is relaxed. For
example, a value of 100.0 means to relax the temperature in a timespan
of (roughly) 100 time units (tau or fmsec or psec - see the
"units"_units.html command). The random # {seed} must be a positive
integer.
The way that Langevin thermostatting operates is explained on the "fix
langevin"_fix_langevin.html doc page. If you wish to simply viscously
damp the rotational motion without thermostatting, you can set
{Tstart} and {Tstop} to 0.0, which means only the viscous drag term in
the Langevin thermostat will be applied. See the discussion on the
"fix viscous"_fix_viscous.html doc page for details.
NOTE: When the {langevin} keyword is used with fix rigid versus fix
rigid/small, different dynamics will result for parallel runs. This
is because of the way random numbers are used in the two cases. The
dynamics for the two cases should be statistically similar, but will
not be identical, even for a single timestep.
The {temp} and {tparam} keywords apply a Nose/Hoover thermostat to the
NVT time integration performed by the 2 NVT rigid styles. They cannot
be used with the 4 NVE rigid styles. The desired temperature at each
timestep is a ramped value during the run from {Tstart} to {Tstop}.
The {Tdamp} parameter is specified in time units and determines how
rapidly the temperature is relaxed. For example, a value of 100.0
means to relax the temperature in a timespan of (roughly) 100 time
units (tau or fmsec or psec - see the "units"_units.html command).
Nose/Hoover chains are used in conjunction with this thermostat. The
{tparam} keyword can optionally be used to change the chain settings
used. {Tchain} is the number of thermostats in the Nose Hoover chain.
This value, along with {Tdamp} can be varied to dampen undesirable
oscillations in temperature that can occur in a simulation. As a rule
of thumb, increasing the chain length should lead to smaller
oscillations. The keyword {pchain} specifies the number of
thermostats in the chain thermostatting the barostat degrees of
freedom.
NOTE: There are alternate ways to thermostat a system of rigid bodies.
You can use "fix langevin"_fix_langevin.html to treat the individual
particles in the rigid bodies as effectively immersed in an implicit
solvent, e.g. a Brownian dynamics model. For hybrid systems with both
rigid bodies and solvent particles, you can thermostat only the
solvent particles that surround one or more rigid bodies by
appropriate choice of groups in the compute and fix commands for
temperature and thermostatting. The solvent interactions with the
rigid bodies should then effectively thermostat the rigid body
temperature as well without use of the Langevin or Nose/Hoover options
associated with the fix rigid commands.
:line
The {mol} keyword can only be used with the {rigid/small} styles. It
must be used when other commands, such as "fix
deposit"_fix_deposit.html or "fix pour"_fix_pour.html, add rigid
bodies on-the-fly during a simulation. You specify a {template-ID}
previously defined using the "molecule"_molecule.html command, which
reads a file that defines the molecule. You must use the same
{template-ID} that the other fix which is adding rigid bodies uses.
The coordinates, atom types, atom diameters, center-of-mass, and
moments of inertia can be specified in the molecule file. See the
"molecule"_molecule.html command for details. The only settings
required to be in this file are the coordinates and types of atoms in
the molecule, in which case the molecule command calculates the other
quantities itself.
Note that these other fixes create new rigid bodies, in addition to
those defined initially by this fix via the {bodystyle} setting.
Also note that when using the {mol} keyword, extra restart information
about all rigid bodies is written out whenever a restart file is
written out. See the NOTE in the next section for details.
:line
The {infile} keyword allows a file of rigid body attributes to be read
in from a file, rather then having LAMMPS compute them. There are 5
such attributes: the total mass of the rigid body, its center-of-mass
position, its 6 moments of inertia, its center-of-mass velocity, and
the 3 image flags of the center-of-mass position. For rigid bodies
consisting of point particles or non-overlapping finite-size
particles, LAMMPS can compute these values accurately. However, for
rigid bodies consisting of finite-size particles which overlap each
other, LAMMPS will ignore the overlaps when computing these 4
attributes. The amount of error this induces depends on the amount of
overlap. To avoid this issue, the values can be pre-computed
(e.g. using Monte Carlo integration).
The format of the file is as follows. Note that the file does not
have to list attributes for every rigid body integrated by fix rigid.
Only bodies which the file specifies will have their computed
attributes overridden. The file can contain initial blank lines or
comment lines starting with "#" which are ignored. The first
non-blank, non-comment line should list N = the number of lines to
follow. The N successive lines contain the following information:
ID1 masstotal xcm ycm zcm ixx iyy izz ixy ixz iyz vxcm vycm vzcm lx ly lz ixcm iycm izcm
ID2 masstotal xcm ycm zcm ixx iyy izz ixy ixz iyz vxcm vycm vzcm lx ly lz ixcm iycm izcm
...
IDN masstotal xcm ycm zcm ixx iyy izz ixy ixz iyz vxcm vycm vzcm lx ly lz ixcm iycm izcm :pre
The rigid body IDs are all positive integers. For the {single}
bodystyle, only an ID of 1 can be used. For the {group} bodystyle,
IDs from 1 to Ng can be used where Ng is the number of specified
groups. For the {molecule} bodystyle, use the molecule ID for the
atoms in a specific rigid body as the rigid body ID.
The masstotal and center-of-mass coordinates (xcm,ycm,zcm) are
self-explanatory. The center-of-mass should be consistent with what
is calculated for the position of the rigid body with all its atoms
unwrapped by their respective image flags. If this produces a
center-of-mass that is outside the simulation box, LAMMPS wraps it
back into the box.
The 6 moments of inertia (ixx,iyy,izz,ixy,ixz,iyz) should be the
values consistent with the current orientation of the rigid body
around its center of mass. The values are with respect to the
simulation box XYZ axes, not with respect to the principal axes of the
rigid body itself. LAMMPS performs the latter calculation internally.
The (vxcm,vycm,vzcm) values are the velocity of the center of mass.
The (lx,ly,lz) values are the angular momentum of the body. The
(vxcm,vycm,vzcm) and (lx,ly,lz) values can simply be set to 0 if you
wish the body to have no initial motion.
The (ixcm,iycm,izcm) values are the image flags of the center of mass
of the body. For periodic dimensions, they specify which image of the
simulation box the body is considered to be in. An image of 0 means
it is inside the box as defined. A value of 2 means add 2 box lengths
to get the true value. A value of -1 means subtract 1 box length to
get the true value. LAMMPS updates these flags as the rigid bodies
cross periodic boundaries during the simulation.
NOTE: If you use the {infile} or {mol} keywords and write restart
files during a simulation, then each time a restart file is written,
the fix also write an auxiliary restart file with the name
rfile.rigid, where "rfile" is the name of the restart file,
e.g. tmp.restart.10000 and tmp.restart.10000.rigid. This auxiliary
file is in the same format described above. Thus it can be used in a
new input script that restarts the run and re-specifies a rigid fix
using an {infile} keyword and the appropriate filename. Note that the
auxiliary file will contain one line for every rigid body, even if the
original file only listed a subset of the rigid bodies.
:line
If you use a "temperature compute"_compute.html with a group that
includes particles in rigid bodies, the degrees-of-freedom removed by
each rigid body are accounted for in the temperature (and pressure)
computation, but only if the temperature group includes all the
particles in a particular rigid body.
A 3d rigid body has 6 degrees of freedom (3 translational, 3
rotational), except for a collection of point particles lying on a
straight line, which has only 5, e.g a dimer. A 2d rigid body has 3
degrees of freedom (2 translational, 1 rotational).
NOTE: You may wish to explicitly subtract additional
degrees-of-freedom if you use the {force} and {torque} keywords to
eliminate certain motions of one or more rigid bodies. LAMMPS does
not do this automatically.
The rigid body contribution to the pressure of the system (virial) is
also accounted for by this fix.
:line
If your simulation is a hybrid model with a mixture of rigid bodies
and non-rigid particles (e.g. solvent) there are several ways these
rigid fixes can be used in tandem with "fix nve"_fix_nve.html, "fix
nvt"_fix_nh.html, "fix npt"_fix_nh.html, and "fix nph"_fix_nh.html.
If you wish to perform NVE dynamics (no thermostatting or
barostatting), use one of 4 NVE rigid styles to integrate the rigid
bodies, and "fix nve"_fix_nve.html to integrate the non-rigid
particles.
If you wish to perform NVT dynamics (thermostatting, but no
barostatting), you can use one of the 2 NVT rigid styles for the rigid
bodies, and any thermostatting fix for the non-rigid particles ("fix
nvt"_fix_nh.html, "fix langevin"_fix_langevin.html, "fix
temp/berendsen"_fix_temp_berendsen.html). You can also use one of the
4 NVE rigid styles for the rigid bodies and thermostat them using "fix
langevin"_fix_langevin.html on the group that contains all the
particles in the rigid bodies. The net force added by "fix
langevin"_fix_langevin.html to each rigid body effectively thermostats
its translational center-of-mass motion. Not sure how well it does at
thermostatting its rotational motion.
If you with to perform NPT or NPH dynamics (barostatting), you cannot
use both "fix npt"_fix_nh.html and the NPT or NPH rigid styles. This
is because there can only be one fix which monitors the global
pressure and changes the simulation box dimensions. So you have 3
choices:
Use one of the 4 NPT or NPH styles for the rigid bodies. Use the
{dilate} all option so that it will dilate the positions of the
non-rigid particles as well. Use "fix nvt"_fix_nh.html (or any other
thermostat) for the non-rigid particles. :ulb,l
Use "fix npt"_fix_nh.html for the group of non-rigid particles. Use
the {dilate} all option so that it will dilate the center-of-mass
positions of the rigid bodies as well. Use one of the 4 NVE or 2 NVT
rigid styles for the rigid bodies. :l
Use "fix press/berendsen"_fix_press_berendsen.html to compute the
pressure and change the box dimensions. Use one of the 4 NVE or 2 NVT
rigid styles for the rigid bodies. Use "fix nvt"_fix_nh.html (or any
other thermostat) for the non-rigid particles. :l
:ule
In all case, the rigid bodies and non-rigid particles both contribute
to the global pressure and the box is scaled the same by any of the
barostatting fixes.
You could even use the 2nd and 3rd options for a non-hybrid simulation
consisting of only rigid bodies, assuming you give "fix
npt"_fix_nh.html an empty group, though it's an odd thing to do. The
barostatting fixes ("fix npt"_fix_nh.html and "fix
press/berensen"_fix_press_berendsen.html) will monitor the pressure
and change the box dimensions, but not time integrate any particles.
The integration of the rigid bodies will be performed by fix
rigid/nvt.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about the 4 NVE rigid styles is written to "binary
restart files"_restart.html. The exception is if the {infile} or
{mol} keyword is used, in which case an auxiliary file is written out
with rigid body information each time a restart file is written, as
explained above for the {infile} keyword. For the 2 NVT rigid styles,
the state of the Nose/Hoover thermostat is written to "binary restart
files"_restart.html. Ditto for the 4 NPT and NPH rigid styles, and
the state of the Nose/Hoover barostat. See the
"read_restart"_read_restart.html command for info on how to re-specify
a fix in an input script that reads a restart file, so that the
operation of the fix continues in an uninterrupted fashion.
The "fix_modify"_fix_modify.html {energy} option is supported by the 6
NVT, NPT, NPH rigid styles to add the energy change induced by the
thermostatting to the system's potential energy as part of
"thermodynamic output"_thermo_style.html.
The "fix_modify"_fix_modify.html {temp} and {press} options are
supported by the 4 NPT and NPH rigid styles to change the computes
used to calculate the instantaneous pressure tensor. Note that the 2
NVT rigid fixes do not use any external compute to compute
instantaneous temperature.
The 2 NVE rigid fixes compute a global scalar which can be accessed by
various "output commands"_Section_howto.html#howto_15. The scalar
value calculated by these fixes is "intensive". The scalar is the
current temperature of the collection of rigid bodies. This is
averaged over all rigid bodies and their translational and rotational
degrees of freedom. The translational energy of a rigid body is 1/2 m
v^2, where m = total mass of the body and v = the velocity of its
center of mass. The rotational energy of a rigid body is 1/2 I w^2,
where I = the moment of inertia tensor of the body and w = its angular
velocity. Degrees of freedom constrained by the {force} and {torque}
keywords are removed from this calculation, but only for the {rigid}
and {rigid/nve} fixes.
The 6 NVT, NPT, NPH rigid fixes compute a global scalar which can be
accessed by various "output commands"_Section_howto.html#howto_15.
The scalar value calculated by these fixes is "extensive". The scalar
is the cumulative energy change due to the thermostatting and
barostatting the fix performs.
All of the {rigid} styles (not the {rigid/small} styles) compute a
global array of values which can be accessed by various "output
commands"_Section_howto.html#howto_15. Similar information about the
bodies defined by the {rigid/small} styles can be accessed via the
"compute rigid/local"_compute_rigid_local.html command.
The number of rows in the array is equal to the number of rigid
bodies. The number of columns is 15. Thus for each rigid body, 15
values are stored: the xyz coords of the center of mass (COM), the xyz
components of the COM velocity, the xyz components of the force acting
on the COM, the xyz components of the torque acting on the COM, and
the xyz image flags of the COM.
The center of mass (COM) for each body is similar to unwrapped
coordinates written to a dump file. It will always be inside (or
slightly outside) the simulation box. The image flags have the same
meaning as image flags for atom positions (see the "dump" command).
This means you can calculate the unwrapped COM by applying the image
flags to the COM, the same as when unwrapped coordinates are written
to a dump file.
The force and torque values in the array are not affected by the
{force} and {torque} keywords in the fix rigid command; they reflect
values before any changes are made by those keywords.
The ordering of the rigid bodies (by row in the array) is as follows.
For the {single} keyword there is just one rigid body. For the
{molecule} keyword, the bodies are ordered by ascending molecule ID.
For the {group} keyword, the list of group IDs determines the ordering
of bodies.
The array values calculated by these fixes are "intensive", meaning
they are independent of the number of atoms in the simulation.
No parameter of these fixes can be used with the {start/stop} keywords
of the "run"_run.html command. These fixes are not invoked during
"energy minimization"_minimize.html.
:line
[Restrictions:]
These fixes are all part of the RIGID package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
Assigning a temperature via the "velocity create"_velocity.html
command to a system with "rigid bodies"_fix_rigid.html may not have
the desired outcome for two reasons. First, the velocity command can
be invoked before the rigid-body fix is invoked or initialized and the
number of adjusted degrees of freedom (DOFs) is known. Thus it is not
possible to compute the target temperature correctly. Second, the
assigned velocities may be partially canceled when constraints are
first enforced, leading to a different temperature than desired. A
workaround for this is to perform a "run 0"_run.html command, which
insures all DOFs are accounted for properly, and then rescale the
temperature to the desired value before performing a simulation. For
example:
velocity all create 300.0 12345
run 0 # temperature may not be 300K
velocity all scale 300.0 # now it should be :pre
[Related commands:]
"delete_bonds"_delete_bonds.html, "neigh_modify"_neigh_modify.html
exclude, "fix shake"_fix_shake.html
[Default:]
The option defaults are force * on on on and torque * on on on,
meaning all rigid bodies are acted on by center-of-mass force and
torque. Also Tchain = Pchain = 10, Titer = 1, Torder = 3, reinit = yes.
:line
:link(Hoover)
[(Hoover)] Hoover, Phys Rev A, 31, 1695 (1985).
:link(Kamberaj)
[(Kamberaj)] Kamberaj, Low, Neal, J Chem Phys, 122, 224114 (2005).
:link(Martyna2)
[(Martyna)] Martyna, Klein, Tuckerman, J Chem Phys, 97, 2635 (1992);
Martyna, Tuckerman, Tobias, Klein, Mol Phys, 87, 1117.
:link(Miller3)
[(Miller)] Miller, Eleftheriou, Pattnaik, Ndirango, and Newns,
J Chem Phys, 116, 8649 (2002).
:link(Zhang1)
[(Zhang)] Zhang, Glotzer, Nanoletters, 4, 1407-1413 (2004).
diff --git a/doc/src/fix_setforce.txt b/doc/src/fix_setforce.txt
index 90766fc5b..f5be0f93a 100644
--- a/doc/src/fix_setforce.txt
+++ b/doc/src/fix_setforce.txt
@@ -1,126 +1,126 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix setforce command :h3
fix setforce/kk command :h3
[Syntax:]
fix ID group-ID setforce fx fy fz keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
setforce = style name of this fix command :l
fx,fy,fz = force component values :l
any of fx,fy,fz can be a variable (see below) :l
zero or more keyword/value pairs may be appended to args :l
keyword = {region} :l
{region} value = region-ID
region-ID = ID of region atoms must be in to have added force :pre
:ule
[Examples:]
fix freeze indenter setforce 0.0 0.0 0.0
fix 2 edge setforce NULL 0.0 0.0
fix 2 edge setforce NULL 0.0 v_oscillate :pre
[Description:]
Set each component of force on each atom in the group to the specified
values fx,fy,fz. This erases all previously computed forces on the
atom, though additional fixes could add new forces. This command can
be used to freeze certain atoms in the simulation by zeroing their
force, either for running dynamics or performing an energy
minimization. For dynamics, this assumes their initial velocity is
also zero.
Any of the fx,fy,fz values can be specified as NULL which means do not
alter the force component in that dimension.
Any of the 3 quantities defining the force components can be specified
as an equal-style or atom-style "variable"_variable.html, namely {fx},
{fy}, {fz}. If the value is a variable, it should be specified as
v_name, where name is the variable name. In this case, the variable
will be evaluated each timestep, and its value used to determine the
force component.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent force field.
Atom-style variables can specify the same formulas as equal-style
variables but can also include per-atom values, such as atom
coordinates. Thus it is easy to specify a spatially-dependent force
field with optional time-dependence as well.
If the {region} keyword is used, the atom must also be in the
specified geometric "region"_region.html in order to have force added
to it.
:line
Styles with a r {kk} suffix are functionally the same as the
corresponding style without the suffix. They have been optimized to
run faster, depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
The region keyword is also supported by Kokkos, but a Kokkos-enabled
region must be used. See the region "region"_region.html command for
more information.
These accelerated styles are part of the r Kokkos package. They are
only enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html.
The "fix_modify"_fix_modify.html {respa} option is supported by
this fix. This allows to set at which level of the "r-RESPA"_run_style.html
integrator the fix is setting the forces to the desired values; on all
other levels, the force is set to 0.0 for the atoms in the fix group,
so that setforce values are not counted multiple times. Default is to
to override forces at the outermost level.
This fix computes a global 3-vector of forces, which can be accessed
by various "output commands"_Section_howto.html#howto_15. This is the
total force on the group of atoms before the forces on individual
atoms are changed by the fix. The vector values calculated by this
fix are "extensive".
No parameter of this fix can be used with the {start/stop} keywords of
the "run"_run.html command.
The forces due to this fix are imposed during an energy minimization,
invoked by the "minimize"_minimize.html command, but you cannot set
forces to any value besides zero when performing a minimization. Use
the "fix addforce"_fix_addforce.html command if you want to apply a
non-zero force to atoms during a minimization.
[Restrictions:] none
[Related commands:]
"fix addforce"_fix_addforce.html, "fix aveforce"_fix_aveforce.html
[Default:] none
diff --git a/doc/src/fix_shake.txt b/doc/src/fix_shake.txt
index 8b26aaa87..c187b17c6 100644
--- a/doc/src/fix_shake.txt
+++ b/doc/src/fix_shake.txt
@@ -1,227 +1,227 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix shake command :h3
fix rattle command :h3
[Syntax:]
fix ID group-ID style tol iter N constraint values ... keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
style = shake or rattle = style name of this fix command :l
tol = accuracy tolerance of SHAKE solution :l
iter = max # of iterations in each SHAKE solution :l
N = print SHAKE statistics every this many timesteps (0 = never) :l
one or more constraint/value pairs are appended :l
constraint = {b} or {a} or {t} or {m} :l
{b} values = one or more bond types
{a} values = one or more angle types
{t} values = one or more atom types
{m} value = one or more mass values :pre
zero or more keyword/value pairs may be appended :l
keyword = {mol} :l
{mol} value = template-ID
template-ID = ID of molecule template specified in a separate "molecule"_molecule.html command :pre
:ule
[Examples:]
fix 1 sub shake 0.0001 20 10 b 4 19 a 3 5 2
fix 1 sub shake 0.0001 20 10 t 5 6 m 1.0 a 31
fix 1 sub shake 0.0001 20 10 t 5 6 m 1.0 a 31 mol myMol
fix 1 sub rattle 0.0001 20 10 t 5 6 m 1.0 a 31
fix 1 sub rattle 0.0001 20 10 t 5 6 m 1.0 a 31 mol myMol :pre
[Description:]
Apply bond and angle constraints to specified bonds and angles in the
simulation by either the SHAKE or RATTLE algorithms. This typically
enables a longer timestep.
[SHAKE vs RATTLE:]
The SHAKE algorithm was invented for schemes such as standard Verlet
timestepping, where only the coordinates are integrated and the
velocities are approximated as finite differences to the trajectories
("Ryckaert et al. (1977)"_#Ryckaert). If the velocities are
integrated explicitly, as with velocity Verlet which is what LAMMPS
uses as an integration method, a second set of constraining forces is
required in order to eliminate velocity components along the bonds
("Andersen (1983)"_#Andersen3).
In order to formulate individual constraints for SHAKE and RATTLE,
focus on a single molecule whose bonds are constrained. Let Ri and Vi
be the position and velocity of atom {i} at time {n}, for
{i}=1,...,{N}, where {N} is the number of sites of our reference
molecule. The distance vector between sites {i} and {j} is given by
:c,image(Eqs/fix_rattle_rij.jpg)
The constraints can then be formulated as
:c,image(Eqs/fix_rattle_constraints.jpg)
The SHAKE algorithm satisfies the first condition, i.e. the sites at
time {n+1} will have the desired separations Dij immediately after the
coordinates are integrated. If we also enforce the second condition,
the velocity components along the bonds will vanish. RATTLE satisfies
both conditions. As implemented in LAMMPS, fix rattle uses fix shake
for satisfying the coordinate constraints. Therefore the settings and
optional keywords are the same for both fixes, and all the information
below about SHAKE is also relevant for RATTLE.
[SHAKE:]
Each timestep the specified bonds and angles are reset to their
equilibrium lengths and angular values via the SHAKE algorithm
("Ryckaert et al. (1977)"_#Ryckaert). This is done by applying an
additional constraint force so that the new positions preserve the
desired atom separations. The equations for the additional force are
solved via an iterative method that typically converges to an accurate
solution in a few iterations. The desired tolerance (e.g. 1.0e-4 = 1
part in 10000) and maximum # of iterations are specified as arguments.
Setting the N argument will print statistics to the screen and log
file about regarding the lengths of bonds and angles that are being
constrained. Small delta values mean SHAKE is doing a good job.
In LAMMPS, only small clusters of atoms can be constrained. This is
so the constraint calculation for a cluster can be performed by a
single processor, to enable good parallel performance. A cluster is
defined as a central atom connected to others in the cluster by
constrained bonds. LAMMPS allows for the following kinds of clusters
to be constrained: one central atom bonded to 1 or 2 or 3 atoms, or
one central atom bonded to 2 others and the angle between the 3 atoms
also constrained. This means water molecules or CH2 or CH3 groups may
be constrained, but not all the C-C backbone bonds of a long polymer
chain.
The {b} constraint lists bond types that will be constrained. The {t}
constraint lists atom types. All bonds connected to an atom of the
specified type will be constrained. The {m} constraint lists atom
masses. All bonds connected to atoms of the specified masses will be
constrained (within a fudge factor of MASSDELTA specified in
fix_shake.cpp). The {a} constraint lists angle types. If both bonds
in the angle are constrained then the angle will also be constrained
if its type is in the list.
For all constraints, a particular bond is only constrained if both
atoms in the bond are in the group specified with the SHAKE fix.
The degrees-of-freedom removed by SHAKE bonds and angles are accounted
for in temperature and pressure computations. Similarly, the SHAKE
contribution to the pressure of the system (virial) is also accounted
for.
NOTE: This command works by using the current forces on atoms to
calculate an additional constraint force which when added will leave
the atoms in positions that satisfy the SHAKE constraints (e.g. bond
length) after the next time integration step. If you define fixes
(e.g. "fix efield"_fix_efield.html) that add additional force to the
atoms after fix shake operates, then this fix will not take them into
account and the time integration will typically not satisfy the SHAKE
constraints. The solution for this is to make sure that fix shake is
defined in your input script after any other fixes which add or change
forces (to atoms that fix shake operates on).
:line
The {mol} keyword should be used when other commands, such as "fix
deposit"_fix_deposit.html or "fix pour"_fix_pour.html, add molecules
on-the-fly during a simulation, and you wish to constrain the new
molecules via SHAKE. You specify a {template-ID} previously defined
using the "molecule"_molecule.html command, which reads a file that
defines the molecule. You must use the same {template-ID} that the
command adding molecules uses. The coordinates, atom types, special
bond restrictions, and SHAKE info can be specified in the molecule
file. See the "molecule"_molecule.html command for details. The only
settings required to be in this file (by this command) are the SHAKE
info of atoms in the molecule.
:line
Styles with a suffix are functionally the same as the corresponding
style without the suffix. They have been optimized to run faster,
depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[RATTLE:]
The velocity constraints lead to a linear system of equations which
can be solved analytically. The implementation of the algorithm in
LAMMPS closely follows ("Andersen (1983)"_#Andersen3).
NOTE: The fix rattle command modifies forces and velocities and thus
should be defined after all other integration fixes in your input
script. If you define other fixes that modify velocities or forces
after fix rattle operates, then fix rattle will not take them into
account and the overall time integration will typically not satisfy
the RATTLE constraints. You can check whether the constraints work
correctly by setting the value of RATTLE_DEBUG in src/fix_rattle.cpp
to 1 and recompiling LAMMPS.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about these fixes is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to these fixes. No global or per-atom quantities are
stored by these fixes for access by various "output
commands"_Section_howto.html#howto_15. No parameter of these fixes
can be used with the {start/stop} keywords of the "run"_run.html
command. These fixes are not invoked during "energy
minimization"_minimize.html.
[Restrictions:]
These fixes are part of the RIGID package. They are only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
For computational efficiency, there can only be one shake or rattle
fix defined in a simulation.
If you use a tolerance that is too large or a max-iteration count that
is too small, the constraints will not be enforced very strongly,
which can lead to poor energy conservation. You can test for this in
your system by running a constant NVE simulation with a particular set
of SHAKE parameters and monitoring the energy versus time.
SHAKE or RATTLE should not be used to constrain an angle at 180 degrees
(e.g. linear CO2 molecule). This causes numeric difficulties.
[Related commands:] none
[Default:] none
:line
:link(Ryckaert)
[(Ryckaert)] J.-P. Ryckaert, G. Ciccotti and H. J. C. Berendsen,
J of Comp Phys, 23, 327-341 (1977).
:link(Andersen3)
[(Andersen)] H. Andersen, J of Comp Phys, 52, 24-34 (1983).
diff --git a/doc/src/fix_wall_reflect.txt b/doc/src/fix_wall_reflect.txt
index 5b425316e..954ec65bf 100644
--- a/doc/src/fix_wall_reflect.txt
+++ b/doc/src/fix_wall_reflect.txt
@@ -1,184 +1,184 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
fix wall/reflect command :h3
fix wall/reflect/kk command :h3
[Syntax:]
fix ID group-ID wall/reflect face arg ... keyword value ... :pre
ID, group-ID are documented in "fix"_fix.html command :ulb,l
wall/reflect = style name of this fix command :l
one or more face/arg pairs may be appended :l
face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} :l
{xlo},{ylo},{zlo} arg = EDGE or constant or variable
EDGE = current lo edge of simulation box
constant = number like 0.0 or -30.0 (distance units)
variable = "equal-style variable"_variable.html like v_x or v_wiggle
{xhi},{yhi},{zhi} arg = EDGE or constant or variable
EDGE = current hi edge of simulation box
constant = number like 50.0 or 100.3 (distance units)
variable = "equal-style variable"_variable.html like v_x or v_wiggle :pre
zero or more keyword/value pairs may be appended :l
keyword = {units} :l
{units} value = {lattice} or {box}
{lattice} = the wall position is defined in lattice units
{box} = the wall position is defined in simulation box units :pre
:ule
[Examples:]
fix xwalls all wall/reflect xlo EDGE xhi EDGE
fix walls all wall/reflect xlo 0.0 ylo 10.0 units box
fix top all wall/reflect zhi v_pressdown :pre
[Description:]
Bound the simulation with one or more walls which reflect particles
in the specified group when they attempt to move thru them.
Reflection means that if an atom moves outside the wall on a timestep
by a distance delta (e.g. due to "fix nve"_fix_nve.html), then it is
put back inside the face by the same delta, and the sign of the
corresponding component of its velocity is flipped.
When used in conjunction with "fix nve"_fix_nve.html and "run_style
verlet"_run_style.html, the resultant time-integration algorithm is
equivalent to the primitive splitting algorithm (PSA) described by
"Bond"_#Bond. Because each reflection event divides
the corresponding timestep asymmetrically, energy conservation is only
satisfied to O(dt), rather than to O(dt^2) as it would be for
velocity-Verlet integration without reflective walls.
Up to 6 walls or faces can be specified in a single command: {xlo},
{xhi}, {ylo}, {yhi}, {zlo}, {zhi}. A {lo} face reflects particles
that move to a coordinate less than the wall position, back in the
{hi} direction. A {hi} face reflects particles that move to a
coordinate higher than the wall position, back in the {lo} direction.
The position of each wall can be specified in one of 3 ways: as the
EDGE of the simulation box, as a constant value, or as a variable. If
EDGE is used, then the corresponding boundary of the current
simulation box is used. If a numeric constant is specified then the
wall is placed at that position in the appropriate dimension (x, y, or
z). In both the EDGE and constant cases, the wall will never move.
If the wall position is a variable, it should be specified as v_name,
where name is an "equal-style variable"_variable.html name. In this
case the variable is evaluated each timestep and the result becomes
the current position of the reflecting wall. Equal-style variables
can specify formulas with various mathematical functions, and include
"thermo_style"_thermo_style.html command keywords for the simulation
box parameters and timestep and elapsed time. Thus it is easy to
specify a time-dependent wall position.
The {units} keyword determines the meaning of the distance units used
to define a wall position, but only when a numeric constant or
variable is used. It is not relevant when EDGE is used to specify a
face position. In the variable case, the variable is assumed to
produce a value compatible with the {units} setting you specify.
A {box} value selects standard distance units as defined by the
"units"_units.html command, e.g. Angstroms for units = real or metal.
A {lattice} value means the distance units are in lattice spacings.
The "lattice"_lattice.html command must have been previously used to
define the lattice spacings.
:line
Here are examples of variable definitions that move the wall position
in a time-dependent fashion using equal-style
"variables"_variable.html.
variable ramp equal ramp(0,10)
fix 1 all wall/reflect xlo v_ramp :pre
variable linear equal vdisplace(0,20)
fix 1 all wall/reflect xlo v_linear :pre
variable wiggle equal swiggle(0.0,5.0,3.0)
fix 1 all wall/reflect xlo v_wiggle :pre
variable wiggle equal cwiggle(0.0,5.0,3.0)
fix 1 all wall/reflect xlo v_wiggle :pre
The ramp(lo,hi) function adjusts the wall position linearly from lo to
hi over the course of a run. The vdisplace(c0,velocity) function does
something similar using the equation position = c0 + velocity*delta,
where delta is the elapsed time.
The swiggle(c0,A,period) function causes the wall position to
oscillate sinusoidally according to this equation, where omega = 2 PI
/ period:
position = c0 + A sin(omega*delta) :pre
The cwiggle(c0,A,period) function causes the wall position to
oscillate sinusoidally according to this equation, which will have an
initial wall velocity of 0.0, and thus may impose a gentler
perturbation on the particles:
position = c0 + A (1 - cos(omega*delta)) :pre
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restart, fix_modify, output, run start/stop, minimize info:]
No information about this fix is written to "binary restart
files"_restart.html. None of the "fix_modify"_fix_modify.html options
are relevant to this fix. No global or per-atom quantities are stored
by this fix for access by various "output
commands"_Section_howto.html#howto_15. No parameter of this fix can
be used with the {start/stop} keywords of the "run"_run.html command.
This fix is not invoked during "energy minimization"_minimize.html.
[Restrictions:]
Any dimension (xyz) that has a reflecting wall must be non-periodic.
A reflecting wall should not be used with rigid bodies such as those
defined by a "fix rigid" command. This is because the wall/reflect
displaces atoms directly rather than exerts a force on them. For
rigid bodies, use a soft wall instead, such as "fix
wall/lj93"_fix_wall.html. LAMMPS will flag the use of a rigid
fix with fix wall/reflect with a warning, but will not generate an
error.
[Related commands:]
"fix wall/lj93"_fix_wall.html, "fix oneway"_fix_oneway.html
[Default:] none
:line
:link(Bond)
[(Bond)] Bond and Leimkuhler, SIAM J Sci Comput, 30, p 134 (2007).
diff --git a/doc/src/improper_class2.txt b/doc/src/improper_class2.txt
index 0b41afe2d..14ec6258d 100644
--- a/doc/src/improper_class2.txt
+++ b/doc/src/improper_class2.txt
@@ -1,125 +1,125 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style class2 command :h3
improper_style class2/omp command :h3
improper_style class2/kk command :h3
[Syntax:]
improper_style class2 :pre
[Examples:]
improper_style class2
improper_coeff 1 100.0 0
improper_coeff * aa 0.0 0.0 0.0 115.06 130.01 115.06 :pre
[Description:]
The {class2} improper style uses the potential
:c,image(Eqs/improper_class2.jpg)
where Ei is the improper term and Eaa is an angle-angle term. The 3 X
terms in Ei are an average over 3 out-of-plane angles.
The 4 atoms in an improper quadruplet (listed in the data file read by
the "read_data"_read_data.html command) are ordered I,J,K,L. X_IJKL
refers to the angle between the plane of I,J,K and the plane of J,K,L,
and the bond JK lies in both planes. Similarly for X_KJLI and X_LJIK.
Note that atom J appears in the common bonds (JI, JK, JL) of all 3 X
terms. Thus J (the 2nd atom in the quadruplet) is the atom of
symmetry in the 3 X angles.
The subscripts on the various theta's refer to different combinations
of 3 atoms (I,J,K,L) used to form a particular angle. E.g. Theta_IJL
is the angle formed by atoms I,J,L with J in the middle. Theta1,
theta2, theta3 are the equilibrium positions of those angles. Again,
atom J (the 2nd atom in the quadruplet) is the atom of symmetry in the
theta angles, since it is always the center atom.
Since atom J is the atom of symmetry, normally the bonds J-I, J-K, J-L
would exist for an improper to be defined between the 4 atoms, but
this is not required.
See "(Sun)"_#improper-Sun for a description of the COMPASS class2 force field.
Coefficients for the Ei and Eaa formulas must be defined for each
improper type via the "improper_coeff"_improper_coeff.html command as
in the example above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands.
These are the 2 coefficients for the Ei formula:
K (energy/radian^2)
X0 (degrees) :ul
X0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of K are in energy/radian^2.
For the Eaa formula, each line in a
"improper_coeff"_improper_coeff.html command in the input script lists
7 coefficients, the first of which is "aa" to indicate they are
AngleAngle coefficients. In a data file, these coefficients should be
listed under a "AngleAngle Coeffs" heading and you must leave out the
"aa", i.e. only list 6 coefficients after the improper type.
aa
M1 (energy/distance)
M2 (energy/distance)
M3 (energy/distance)
theta1 (degrees)
theta2 (degrees)
theta3 (degrees) :ul
The theta values are specified in degrees, but LAMMPS converts them to
radians internally; hence the units of M are in energy/radian^2.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
CLASS2 package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
:line
:link(improper-Sun)
[(Sun)] Sun, J Phys Chem B 102, 7338-7364 (1998).
diff --git a/doc/src/improper_cossq.txt b/doc/src/improper_cossq.txt
index e238063a8..138a6a165 100644
--- a/doc/src/improper_cossq.txt
+++ b/doc/src/improper_cossq.txt
@@ -1,86 +1,86 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style cossq command :h3
improper_style cossq/omp command :h3
[Syntax:]
improper_style cossq :pre
[Examples:]
improper_style cossq
improper_coeff 1 4.0 0.0 :pre
[Description:]
The {cossq} improper style uses the potential
:c,image(Eqs/improper_cossq.jpg)
where x is the improper angle, x0 is its equilibrium value, and K is a
prefactor.
If the 4 atoms in an improper quadruplet (listed in the data file read
by the "read_data"_read_data.html command) are ordered I,J,K,L then X
is the angle between the plane of I,J,K and the plane of J,K,L.
Alternatively, you can think of atoms J,K,L as being in a plane, and
atom I above the plane, and X as a measure of how far out-of-plane I
is with respect to the other 3 atoms.
Note that defining 4 atoms to interact in this way, does not mean that
bonds necessarily exist between I-J, J-K, or K-L, as they would in a
linear dihedral. Normally, the bonds I-J, I-K, I-L would exist for an
improper to be defined between the 4 atoms.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy)
X0 (degrees) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
diff --git a/doc/src/improper_cvff.txt b/doc/src/improper_cvff.txt
index 72f346ba0..5f69eccc6 100644
--- a/doc/src/improper_cvff.txt
+++ b/doc/src/improper_cvff.txt
@@ -1,87 +1,87 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style cvff command :h3
improper_style cvff/intel command :h3
improper_style cvff/omp command :h3
[Syntax:]
improper_style cvff :pre
[Examples:]
improper_style cvff
improper_coeff 1 80.0 -1 4 :pre
[Description:]
The {cvff} improper style uses the potential
:c,image(Eqs/improper_cvff.jpg)
where phi is the improper dihedral angle.
If the 4 atoms in an improper quadruplet (listed in the data file read
by the "read_data"_read_data.html command) are ordered I,J,K,L then
the improper dihedral angle is between the plane of I,J,K and the
plane of J,K,L. Note that because this is effectively a dihedral
angle, the formula for this improper style is the same as for
"dihedral_style harmonic"_dihedral_harmonic.html.
Note that defining 4 atoms to interact in this way, does not mean that
bonds necessarily exist between I-J, J-K, or K-L, as they would in a
linear dihedral. Normally, the bonds I-J, I-K, I-L would exist for an
improper to be defined between the 4 atoms.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy)
d (+1 or -1)
n (0,1,2,3,4,6) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
diff --git a/doc/src/improper_fourier.txt b/doc/src/improper_fourier.txt
index 3a5354b1f..f9062da20 100644
--- a/doc/src/improper_fourier.txt
+++ b/doc/src/improper_fourier.txt
@@ -1,82 +1,82 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style fourier command :h3
improper_style fourier/omp command :h3
[Syntax:]
improper_style fourier :pre
[Examples:]
improper_style fourier
improper_coeff 1 100.0 180.0 :pre
[Description:]
The {fourier} improper style uses the following potential:
:c,image(Eqs/improper_fourier.jpg)
where K is the force constant and omega is the angle between the IL
axis and the IJK plane:
:c,image(Eqs/umbrella.jpg)
If all parameter (see bellow) is not zero, the all the three possible angles will taken in account.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy)
C0 (real)
C1 (real)
C2 (real)
all (integer >= 0) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This angle style can only be used if LAMMPS was built with the
USER_MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
diff --git a/doc/src/improper_harmonic.txt b/doc/src/improper_harmonic.txt
index b47b0ca41..bb17e5a64 100644
--- a/doc/src/improper_harmonic.txt
+++ b/doc/src/improper_harmonic.txt
@@ -1,91 +1,91 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style harmonic command :h3
improper_style harmonic/intel command :h3
improper_style harmonic/kk command :h3
improper_style harmonic/omp command :h3
[Syntax:]
improper_style harmonic :pre
[Examples:]
improper_style harmonic
improper_coeff 1 100.0 0 :pre
[Description:]
The {harmonic} improper style uses the potential
:c,image(Eqs/improper_harmonic.jpg)
where X is the improper angle, X0 is its equilibrium value, and K is a
prefactor. Note that the usual 1/2 factor is included in K.
If the 4 atoms in an improper quadruplet (listed in the data file read
by the "read_data"_read_data.html command) are ordered I,J,K,L then X
is the angle between the plane of I,J,K and the plane of J,K,L.
Alternatively, you can think of atoms J,K,L as being in a plane, and
atom I above the plane, and X as a measure of how far out-of-plane I
is with respect to the other 3 atoms.
Note that defining 4 atoms to interact in this way, does not mean that
bonds necessarily exist between I-J, J-K, or K-L, as they would in a
linear dihedral. Normally, the bonds I-J, I-K, I-L would exist for an
improper to be defined between the 4 atoms.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy/radian^2)
X0 (degrees) :ul
X0 is specified in degrees, but LAMMPS converts it to radians
internally; hence the units of K are in energy/radian^2.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
diff --git a/doc/src/improper_ring.txt b/doc/src/improper_ring.txt
index cba59399e..c02d39247 100644
--- a/doc/src/improper_ring.txt
+++ b/doc/src/improper_ring.txt
@@ -1,93 +1,93 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style ring command :h3
improper_style ring/omp command :h3
[Syntax:]
improper_style ring :pre
[Examples:]
improper_style ring
improper_coeff 1 8000 70.5 :pre
[Description:]
The {ring} improper style uses the potential
:c,image(Eqs/improper_ring.jpg)
where K is a prefactor, theta is the angle formed by the atoms
specified by (i,j,k,l) indices and theta0 its equilibrium value.
If the 4 atoms in an improper quadruplet (listed in the data file read
by the "read_data"_read_data.html command) are ordered i,j,k,l then
theta_{ijl} is the angle between atoms i,j and l, theta_{ijk} is the
angle between atoms i,j and k, theta_{kjl} is the angle between atoms
j,k, and l.
The "ring" improper style implements the improper potential introduced
by Destree et al., in Equation (9) of "(Destree)"_#Destree. This
potential does not affect small amplitude vibrations but is used in an
ad-hoc way to prevent the onset of accidentally large amplitude
fluctuations leading to the occurrence of a planar conformation of the
three bonds i-j, j-k and j-l, an intermediate conformation toward the
chiral inversion of a methine carbon. In the "Impropers" section of
data file four atoms: i, j, k and l are specified with i,j and l lying
on the backbone of the chain and k specifying the chirality of j.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy)
theta0 (degrees) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
:link(Destree)
[(Destree)] M. Destree, F. Laupretre, A. Lyulin, and J.-P. Ryckaert,
J Chem Phys, 112, 9632 (2000).
diff --git a/doc/src/improper_umbrella.txt b/doc/src/improper_umbrella.txt
index fafa2e7e4..d6df9ee6c 100644
--- a/doc/src/improper_umbrella.txt
+++ b/doc/src/improper_umbrella.txt
@@ -1,90 +1,90 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
improper_style umbrella command :h3
improper_style umbrella/omp command :h3
[Syntax:]
improper_style umbrella :pre
[Examples:]
improper_style umbrella
improper_coeff 1 100.0 180.0 :pre
[Description:]
The {umbrella} improper style uses the following potential, which is
commonly referred to as a classic inversion and used in the
"DREIDING"_Section_howto.html#howto_4 force field:
:c,image(Eqs/improper_umbrella.jpg)
where K is the force constant and omega is the angle between the IL
axis and the IJK plane:
:c,image(Eqs/umbrella.jpg)
If omega0 = 0 the potential term has a minimum for the planar
structure. Otherwise it has two minima at +/- omega0, with a barrier
in between.
See "(Mayo)"_#umbrella-Mayo for a description of the DREIDING force field.
The following coefficients must be defined for each improper type via
the "improper_coeff"_improper_coeff.html command as in the example
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
K (energy)
omega0 (degrees) :ul
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This improper style can only be used if LAMMPS was built with the
MOLECULE package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"improper_coeff"_improper_coeff.html
[Default:] none
:line
:link(umbrella-Mayo)
[(Mayo)] Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909
(1990),
diff --git a/doc/src/jump.txt b/doc/src/jump.txt
index 1b1a20951..4e3799f7b 100644
--- a/doc/src/jump.txt
+++ b/doc/src/jump.txt
@@ -1,130 +1,130 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
jump command :h3
[Syntax:]
jump file label :pre
file = filename of new input script to switch to
label = optional label within file to jump to :ul
[Examples:]
jump newfile
jump in.run2 runloop
jump SELF runloop :pre
[Description:]
This command closes the current input script file, opens the file with
the specified name, and begins reading LAMMPS commands from that file.
Unlike the "include"_include.html command, the original file is not
returned to, although by using multiple jump commands it is possible
to chain from file to file or back to the original file.
If the word "SELF" is used for the filename, then the current input
script is re-opened and read again.
NOTE: The SELF option is not guaranteed to work when the current input
script is being read through stdin (standard input), e.g.
lmp_g++ < in.script :pre
since the SELF option invokes the C-library rewind() call, which may
not be supported for stdin on some systems or by some MPI
implementations. This can be worked around by using the "-in
-command-line argument"_Section_start.html#start_7, e.g.
+command-line argument"_Section_start.html#start_6, e.g.
lmp_g++ -in in.script :pre
or by using the "-var command-line
-argument"_Section_start.html#start_7 to pass the script name as a
+argument"_Section_start.html#start_6 to pass the script name as a
variable to the input script. In the latter case, a
"variable"_variable.html called "fname" could be used in place of
SELF, e.g.
lmp_g++ -var fname in.script < in.script :pre
The 2nd argument to the jump command is optional. If specified, it is
treated as a label and the new file is scanned (without executing
commands) until the label is found, and commands are executed from
that point forward. This can be used to loop over a portion of the
input script, as in this example. These commands perform 10 runs,
each of 10000 steps, and create 10 dump files named file.1, file.2,
etc. The "next"_next.html command is used to exit the loop after 10
iterations. When the "a" variable has been incremented for the tenth
time, it will cause the next jump command to be skipped.
variable a loop 10
label loop
dump 1 all atom 100 file.$a
run 10000
undump 1
next a
jump in.lj loop :pre
If the jump {file} argument is a variable, the jump command can be
used to cause different processor partitions to run different input
scripts. In this example, LAMMPS is run on 40 processors, with 4
partitions of 10 procs each. An in.file containing the example
variable and jump command will cause each partition to run a different
simulation.
mpirun -np 40 lmp_ibm -partition 4x10 -in in.file :pre
variable f world script.1 script.2 script.3 script.4
jump $f :pre
Here is an example of a loop which checks every 1000 steps if the
system temperature has reached a certain value, and if so, breaks out
of the loop to finish the run. Note that any variable could be
checked, so long as it is current on the timestep when the run
completes. As explained on the "variable"_variable.html doc page,
this can be insured by including the variable in thermodynamic output.
variable myTemp equal temp
label loop
variable a loop 1000
run 1000
if "$\{myTemp\} < 300.0" then "jump SELF break"
next a
jump SELF loop
label break
print "ALL DONE" :pre
Here is an example of a double loop which uses the if and
"jump"_jump.html commands to break out of the inner loop when a
condition is met, then continues iterating thru the outer loop.
label loopa
variable a loop 5
label loopb
variable b loop 5
print "A,B = $a,$b"
run 10000
if "$b > 2" then "jump SELF break"
next b
jump in.script loopb
label break
variable b delete
next a
jump SELF loopa :pre
[Restrictions:]
If you jump to a file and it does not contain the specified label,
LAMMPS will come to the end of the file and exit.
[Related commands:]
"variable"_variable.html, "include"_include.html, "label"_label.html,
"next"_next.html
[Default:] none
diff --git a/doc/src/log.txt b/doc/src/log.txt
index 460482ea1..92bb12e6d 100644
--- a/doc/src/log.txt
+++ b/doc/src/log.txt
@@ -1,46 +1,46 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
log command :h3
[Syntax:]
log file keyword :pre
file = name of new logfile
keyword = {append} if output should be appended to logfile (optional) :ul
[Examples:]
log log.equil
log log.equil append :pre
[Description:]
This command closes the current LAMMPS log file, opens a new file with
the specified name, and begins logging information to it. If the
specified file name is {none}, then no new log file is opened. If the
optional keyword {append} is specified, then output will be appended
to an existing log file, instead of overwriting it.
If multiple processor partitions are being used, the file name should
be a variable, so that different processors do not attempt to write to
the same log file.
The file "log.lammps" is the default log file for a LAMMPS run. The
name of the initial log file can also be set by the command-line
-switch -log. See "Section 2.7"_Section_start.html#start_7 for
+switch -log. See "Section 2.6"_Section_start.html#start_6 for
details.
[Restrictions:] none
[Related commands:] none
[Default:]
The default LAMMPS log file is named log.lammps
diff --git a/doc/src/neb.txt b/doc/src/neb.txt
index d2e8be3f0..144fe8bde 100644
--- a/doc/src/neb.txt
+++ b/doc/src/neb.txt
@@ -1,427 +1,427 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
neb command :h3
[Syntax:]
neb etol ftol N1 N2 Nevery file-style arg keyword :pre
etol = stopping tolerance for energy (energy units) :ulb,l
ftol = stopping tolerance for force (force units) :l
N1 = max # of iterations (timesteps) to run initial NEB :l
N2 = max # of iterations (timesteps) to run barrier-climbing NEB :l
Nevery = print replica energies and reaction coordinates every this many timesteps :l
file-style = {final} or {each} or {none} :l
{final} arg = filename
filename = file with initial coords for final replica
coords for intermediate replicas are linearly interpolated
between first and last replica
{each} arg = filename
filename = unique filename for each replica (except first)
with its initial coords
{none} arg = no argument all replicas assumed to already have
their initial coords :pre
keyword = {verbose}
:ule
[Examples:]
neb 0.1 0.0 1000 500 50 final coords.final
neb 0.0 0.001 1000 500 50 each coords.initial.$i
neb 0.0 0.001 1000 500 50 none verbose :pre
[Description:]
Perform a nudged elastic band (NEB) calculation using multiple
replicas of a system. Two or more replicas must be used; the first
and last are the end points of the transition path.
NEB is a method for finding both the atomic configurations and height
of the energy barrier associated with a transition state, e.g. for an
atom to perform a diffusive hop from one energy basin to another in a
coordinated fashion with its neighbors. The implementation in LAMMPS
follows the discussion in these 4 papers: "(HenkelmanA)"_#HenkelmanA,
"(HenkelmanB)"_#HenkelmanB, "(Nakano)"_#Nakano3 and "(Maras)"_#Maras2.
Each replica runs on a partition of one or more processors. Processor
partitions are defined at run-time using the -partition command-line
-switch; see "Section 2.7"_Section_start.html#start_7 of the manual.
+switch; see "Section 2.6"_Section_start.html#start_6 of the manual.
Note that if you have MPI installed, you can run a multi-replica
simulation with more replicas (partitions) than you have physical
processors, e.g you can run a 10-replica simulation on just one or two
processors. You will simply not get the performance speed-up you
would see with one or more physical processors per replica. See
"Section 6.5"_Section_howto.html#howto_5 of the manual for further
discussion.
NOTE: As explained below, a NEB calculation perfoms a damped dynamics
minimization across all the replicas. The minimizer uses whatever
timestep you have defined in your input script, via the
"timestep"_timestep.html command. Often NEB will converge more
quickly if you use a timestep about 10x larger than you would normally
use for dynamics simulations.
When a NEB calculation is performed, it is assumed that each replica
is running the same system, though LAMMPS does not check for this.
I.e. the simulation domain, the number of atoms, the interaction
potentials, and the starting configuration when the neb command is
issued should be the same for every replica.
In a NEB calculation each replica is connected to other replicas by
inter-replica nudging forces. These forces are imposed by the "fix
neb"_fix_neb.html command, which must be used in conjunction with the
neb command. The group used to define the fix neb command defines the
NEB atoms which are the only ones that inter-replica springs are
applied to. If the group does not include all atoms, then non-NEB
atoms have no inter-replica springs and the forces they feel and their
motion is computed in the usual way due only to other atoms within
their replica. Conceptually, the non-NEB atoms provide a background
force field for the NEB atoms. They can be allowed to move during the
NEB minimization procedure (which will typically induce different
coordinates for non-NEB atoms in different replicas), or held fixed
using other LAMMPS commands such as "fix setforce"_fix_setforce.html.
Note that the "partition"_partition.html command can be used to invoke
a command on a subset of the replicas, e.g. if you wish to hold NEB or
non-NEB atoms fixed in only the end-point replicas.
The initial atomic configuration for each of the replicas can be
specified in different manners via the {file-style} setting, as
discussed below. Only atoms whose initial coordinates should differ
from the current configuration need be specified.
Conceptually, the initial and final configurations for the first
replica should be states on either side of an energy barrier.
As explained below, the initial configurations of intermediate
replicas can be atomic coordinates interpolated in a linear fashion
between the first and last replicas. This is often adequate for
simple transitions. For more complex transitions, it may lead to slow
convergence or even bad results if the minimum energy path (MEP, see
below) of states over the barrier cannot be correctly converged to
from such an initial path. In this case, you will want to generate
initial states for the intermediate replicas that are geometrically
closer to the MEP and read them in.
:line
For a {file-style} setting of {final}, a filename is specified which
contains atomic coordinates for zero or more atoms, in the format
described below. For each atom that appears in the file, the new
coordinates are assigned to that atom in the final replica. Each
intermediate replica also assigns a new position to that atom in an
interpolated manner. This is done by using the current position of
the atom as the starting point and the read-in position as the final
point. The distance between them is calculated, and the new position
is assigned to be a fraction of the distance. E.g. if there are 10
replicas, the 2nd replica will assign a position that is 10% of the
distance along a line between the starting and final point, and the
9th replica will assign a position that is 90% of the distance along
the line. Note that for this procedure to produce consistent
coordinates across all the replicas, the current coordinates need to
be the same in all replicas. LAMMPS does not check for this, but
invalid initial configurations will likely result if it is not the
case.
NOTE: The "distance" between the starting and final point is
calculated in a minimum-image sense for a periodic simulation box.
This means that if the two positions are on opposite sides of a box
(periodic in that dimension), the distance between them will be small,
because the periodic image of one of the atoms is close to the other.
Similarly, even if the assigned position resulting from the
interpolation is outside the periodic box, the atom will be wrapped
back into the box when the NEB calculation begins.
For a {file-style} setting of {each}, a filename is specified which is
assumed to be unique to each replica. This can be done by using a
variable in the filename, e.g.
variable i equal part
neb 0.0 0.001 1000 500 50 each coords.initial.$i :pre
which in this case will substitute the partition ID (0 to N-1) for the
variable I, which is also effectively the replica ID. See the
"variable"_variable.html command for other options, such as using
world-, universe-, or uloop-style variables.
Each replica (except the first replica) will read its file, formatted
as described below, and for any atom that appears in the file, assign
the specified coordinates to its atom. The various files do not need
to contain the same set of atoms.
For a {file-style} setting of {none}, no filename is specified. Each
replica is assumed to already be in its initial configuration at the
time the neb command is issued. This allows each replica to define
its own configuration by reading a replica-specific data or restart or
dump file, via the "read_data"_read_data.html,
"read_restart"_read_restart.html, or "read_dump"_read_dump.html
commands. The replica-specific names of these files can be specified
as in the discussion above for the {each} file-style. Also see the
section below for how a NEB calculation can produce restart files, so
that a long calculation can be restarted if needed.
NOTE: None of the {file-style} settings change the initial
configuration of any atom in the first replica. The first replica
must thus be in the correct initial configuration at the time the neb
command is issued.
:line
A NEB calculation proceeds in two stages, each of which is a
minimization procedure, performed via damped dynamics. To enable
this, you must first define a damped dynamics
"min_style"_min_style.html, such as {quickmin} or {fire}. The {cg},
{sd}, and {hftn} styles cannot be used, since they perform iterative
line searches in their inner loop, which cannot be easily synchronized
across multiple replicas.
The minimizer tolerances for energy and force are set by {etol} and
{ftol}, the same as for the "minimize"_minimize.html command.
A non-zero {etol} means that the NEB calculation will terminate if the
energy criterion is met by every replica. The energies being compared
to {etol} do not include any contribution from the inter-replica
nudging forces, since these are non-conservative. A non-zero {ftol}
means that the NEB calculation will terminate if the force criterion
is met by every replica. The forces being compared to {ftol} include
the inter-replica nudging forces.
The maximum number of iterations in each stage is set by {N1} and
{N2}. These are effectively timestep counts since each iteration of
damped dynamics is like a single timestep in a dynamics
"run"_run.html. During both stages, the potential energy of each
replica and its normalized distance along the reaction path (reaction
coordinate RD) will be printed to the screen and log file every
{Nevery} timesteps. The RD is 0 and 1 for the first and last replica.
For intermediate replicas, it is the cumulative distance (normalized
by the total cumulative distance) between adjacent replicas, where
"distance" is defined as the length of the 3N-vector of differences in
atomic coordinates, where N is the number of NEB atoms involved in the
transition. These outputs allow you to monitor NEB's progress in
finding a good energy barrier. {N1} and {N2} must both be multiples
of {Nevery}.
In the first stage of NEB, the set of replicas should converge toward
a minimum energy path (MEP) of conformational states that transition
over a barrier. The MEP for a transition is defined as a sequence of
3N-dimensional states, each of which has a potential energy gradient
parallel to the MEP itself. The configuration of highest energy along
a MEP corresponds to a saddle point. The replica states will also be
roughly equally spaced along the MEP due to the inter-replica nugding
force added by the "fix neb"_fix_neb.html command.
In the second stage of NEB, the replica with the highest energy is
selected and the inter-replica forces on it are converted to a force
that drives its atom coordinates to the top or saddle point of the
barrier, via the barrier-climbing calculation described in
"(HenkelmanB)"_#HenkelmanB. As before, the other replicas rearrange
themselves along the MEP so as to be roughly equally spaced.
When both stages are complete, if the NEB calculation was successful,
the configurations of the replicas should be along (close to) the MEP
and the replica with the highest energy should be an atomic
configuration at (close to) the saddle point of the transition. The
potential energies for the set of replicas represents the energy
profile of the transition along the MEP.
:line
A few other settings in your input script are required or advised to
perform a NEB calculation. See the NOTE about the choice of timestep
at the beginning of this doc page.
An atom map must be defined which it is not by default for "atom_style
atomic"_atom_style.html problems. The "atom_modify
map"_atom_modify.html command can be used to do this.
The minimizers in LAMMPS operate on all atoms in your system, even
non-NEB atoms, as defined above. To prevent non-NEB atoms from moving
during the minimization, you should use the "fix
setforce"_fix_setforce.html command to set the force on each of those
atoms to 0.0. This is not required, and may not even be desired in
some cases, but if those atoms move too far (e.g. because the initial
state of your system was not well-minimized), it can cause problems
for the NEB procedure.
The damped dynamics "minimizers"_min_style.html, such as {quickmin}
and {fire}), adjust the position and velocity of the atoms via an
Euler integration step. Thus you must define an appropriate
"timestep"_timestep.html to use with NEB. As mentioned above, NEB
will often converge more quickly if you use a timestep about 10x
larger than you would normally use for dynamics simulations.
:line
Each file read by the neb command containing atomic coordinates used
to initialize one or more replicas must be formatted as follows.
The file can be ASCII text or a gzipped text file (detected by a .gz
suffix). The file can contain initial blank lines or comment lines
starting with "#" which are ignored. The first non-blank, non-comment
line should list N = the number of lines to follow. The N successive
lines contain the following information:
ID1 x1 y1 z1
ID2 x2 y2 z2
...
IDN xN yN zN :pre
The fields are the atom ID, followed by the x,y,z coordinates. The
lines can be listed in any order. Additional trailing information on
the line is OK, such as a comment.
Note that for a typical NEB calculation you do not need to specify
initial coordinates for very many atoms to produce differing starting
and final replicas whose intermediate replicas will converge to the
energy barrier. Typically only new coordinates for atoms
geometrically near the barrier need be specified.
Also note there is no requirement that the atoms in the file
correspond to the NEB atoms in the group defined by the "fix
neb"_fix_neb.html command. Not every NEB atom need be in the file,
and non-NEB atoms can be listed in the file.
:line
Four kinds of output can be generated during a NEB calculation: energy
barrier statistics, thermodynamic output by each replica, dump files,
and restart files.
When running with multiple partitions (each of which is a replica in
this case), the print-out to the screen and master log.lammps file
contains a line of output, printed once every {Nevery} timesteps. It
contains the timestep, the maximum force per replica, the maximum
force per atom (in any replica), potential gradients in the initial,
final, and climbing replicas, the forward and backward energy
barriers, the total reaction coordinate (RDT), and the normalized
reaction coordinate and potential energy of each replica.
The "maximum force per replica" is the two-norm of the 3N-length force
vector for the atoms in each replica, maximized across replicas, which
is what the {ftol} setting is checking against. In this case, N is
all the atoms in each replica. The "maximum force per atom" is the
maximum force component of any atom in any replica. The potential
gradients are the two-norm of the 3N-length force vector solely due to
the interaction potential i.e. without adding in inter-replica
forces.
The "reaction coordinate" (RD) for each replica is the two-norm of the
3N-length vector of distances between its atoms and the preceding
replica's atoms, added to the RD of the preceding replica. The RD of
the first replica RD1 = 0.0; the RD of the final replica RDN = RDT,
the total reaction coordinate. The normalized RDs are divided by RDT,
so that they form a monotonically increasing sequence from zero to
one. When computing RD, N only includes the atoms being operated on by
the fix neb command.
The forward (reverse) energy barrier is the potential energy of the
highest replica minus the energy of the first (last) replica.
Supplementary informations for all replicas can be printed out to the
screen and master log.lammps file by adding the verbose keyword. These
informations include the following. The "path angle" (pathangle) for
the replica i which is the angle between the 3N-length vectors (Ri-1 -
Ri) and (Ri+1 - Ri) (where Ri is the atomic coordinates of replica
i). A "path angle" of 180 indicates that replicas i-1, i and i+1 are
aligned. "angletangrad" is the angle between the 3N-length tangent
vector and the 3N-length force vector at image i. The tangent vector
is calculated as in "(HenkelmanA)"_#HenkelmanA for all intermediate
replicas and at R2 - R1 and RM - RM-1 for the first and last replica,
respectively. "anglegrad" is the angle between the 3N-length energy
gradient vector of replica i and that of replica i+1. It is not
defined for the final replica and reads nan. gradV is the norm of the
energy gradient of image i. ReplicaForce is the two-norm of the
3N-length force vector (including nudging forces) for replica i.
MaxAtomForce is the maximum force component of any atom in replica i.
When a NEB calculation does not converge properly, these suplementary
informations can help understanding what is going wrong. For instance
when the path angle becomes accute the definition of tangent used in
the NEB calculation is questionable and the NEB cannot may diverge
"(Maras)"_#Maras2.
When running on multiple partitions, LAMMPS produces additional log
files for each partition, e.g. log.lammps.0, log.lammps.1, etc. For a
NEB calculation, these contain the thermodynamic output for each
replica.
If "dump"_dump.html commands in the input script define a filename
that includes a {universe} or {uloop} style "variable"_variable.html,
then one dump file (per dump command) will be created for each
replica. At the end of the NEB calculation, the final snapshot in
each file will contain the sequence of snapshots that transition the
system over the energy barrier. Earlier snapshots will show the
convergence of the replicas to the MEP.
Likewise, "restart"_restart.html filenames can be specified with a
{universe} or {uloop} style "variable"_variable.html, to generate
restart files for each replica. These may be useful if the NEB
calculation fails to converge properly to the MEP, and you wish to
restart the calculation from an intermediate point with altered
parameters.
There are 2 Python scripts provided in the tools/python directory,
neb_combine.py and neb_final.py, which are useful in analyzing output
from a NEB calculation. Assume a NEB simulation with M replicas, and
the NEB atoms labeled with a specific atom type.
The neb_combine.py script extracts atom coords for the NEB atoms from
all M dump files and creates a single dump file where each snapshot
contains the NEB atoms from all the replicas and one copy of non-NEB
atoms from the first replica (presumed to be identical in other
replicas). This can be visualized/animated to see how the NEB atoms
relax as the NEB calculation proceeds.
The neb_final.py script extracts the final snapshot from each of the M
dump files to create a single dump file with M snapshots. This can be
visualized to watch the system make its transition over the energy
barrier.
To illustrate, here are images from the final snapshot produced by the
neb_combine.py script run on the dump files produced by the two
example input scripts in examples/neb. Click on them to see a larger
image.
:image(JPG/hop1_small.jpg,JPG/hop1.jpg)
:image(JPG/hop2_small.jpg,JPG/hop2.jpg)
:line
[Restrictions:]
This command can only be used if LAMMPS was built with the REPLICA
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
:line
[Related commands:]
"prd"_prd.html, "temper"_temper.html, "fix langevin"_fix_langevin.html,
"fix viscous"_fix_viscous.html
[Default:]
none
:line
:link(HenkelmanA)
[(HenkelmanA)] Henkelman and Jonsson, J Chem Phys, 113, 9978-9985 (2000).
:link(HenkelmanB)
[(HenkelmanB)] Henkelman, Uberuaga, Jonsson, J Chem Phys, 113,
9901-9904 (2000).
:link(Nakano3)
[(Nakano)] Nakano, Comp Phys Comm, 178, 280-289 (2008).
:link(Maras2)
[(Maras)] Maras, Trushin, Stukowski, Ala-Nissila, Jonsson,
Comp Phys Comm, 205, 13-21 (2016)
diff --git a/doc/src/neighbor.txt b/doc/src/neighbor.txt
index 7b8f499ba..062f79a5b 100644
--- a/doc/src/neighbor.txt
+++ b/doc/src/neighbor.txt
@@ -1,83 +1,83 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
neighbor command :h3
[Syntax:]
neighbor skin style :pre
skin = extra distance beyond force cutoff (distance units)
style = {bin} or {nsq} or {multi} :ul
[Examples:]
neighbor 0.3 bin
neighbor 2.0 nsq :pre
[Description:]
This command sets parameters that affect the building of pairwise
neighbor lists. All atom pairs within a neighbor cutoff distance
equal to the their force cutoff plus the {skin} distance are stored in
the list. Typically, the larger the skin distance, the less often
neighbor lists need to be built, but more pairs must be checked for
possible force interactions every timestep. The default value for
{skin} depends on the choice of units for the simulation; see the
default values below.
The {skin} distance is also used to determine how often atoms migrate
to new processors if the {check} option of the
"neigh_modify"_neigh_modify.html command is set to {yes}. Atoms are
migrated (communicated) to new processors on the same timestep that
neighbor lists are re-built.
The {style} value selects what algorithm is used to build the list.
The {bin} style creates the list by binning which is an operation that
scales linearly with N/P, the number of atoms per processor where N =
total number of atoms and P = number of processors. It is almost
always faster than the {nsq} style which scales as (N/P)^2. For
unsolvated small molecules in a non-periodic box, the {nsq} choice can
sometimes be faster. Either style should give the same answers.
The {multi} style is a modified binning algorithm that is useful for
systems with a wide range of cutoff distances, e.g. due to different
size particles. For the {bin} style, the bin size is set to 1/2 of
the largest cutoff distance between any pair of atom types and a
single set of bins is defined to search over for all atom types. This
can be inefficient if one pair of types has a very long cutoff, but
other type pairs have a much shorter cutoff. For style {multi} the
bin size is set to 1/2 of the shortest cutoff distance and multiple
sets of bins are defined to search over for different atom types.
This imposes some extra setup overhead, but the searches themselves
may be much faster for the short-cutoff cases. See the "comm_modify
mode multi"_comm_modify.html command for a communication option option
that may also be beneficial for simulations of this kind.
The "neigh_modify"_neigh_modify.html command has additional options
that control how often neighbor lists are built and which pairs are
stored in the list.
When a run is finished, counts of the number of neighbors stored in
the pairwise list and the number of times neighbor lists were built
are printed to the screen and log file. See "this
-section"_Section_start.html#start_8 for details.
+section"_Section_start.html#start_7 for details.
[Restrictions:] none
[Related commands:]
"neigh_modify"_neigh_modify.html, "units"_units.html,
"comm_modify"_comm_modify.html
[Default:]
0.3 bin for units = lj, skin = 0.3 sigma
2.0 bin for units = real or metal, skin = 2.0 Angstroms
0.001 bin for units = si, skin = 0.001 meters = 1.0 mm
0.1 bin for units = cgs, skin = 0.1 cm = 1.0 mm :all(b)
diff --git a/doc/src/next.txt b/doc/src/next.txt
index fe9dc9754..08f73b896 100644
--- a/doc/src/next.txt
+++ b/doc/src/next.txt
@@ -1,142 +1,142 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
next command :h3
[Syntax:]
next variables :pre
variables = one or more variable names :ul
[Examples:]
next x
next a t x myTemp :pre
[Description:]
This command is used with variables defined by the
"variable"_variable.html command. It assigns the next value to the
variable from the list of values defined for that variable by the
"variable"_variable.html command. Thus when that variable is
subsequently substituted for in an input script command, the new value
is used.
See the "variable"_variable.html command for info on how to define and
use different kinds of variables in LAMMPS input scripts. If a
variable name is a single lower-case character from "a" to "z", it can
be used in an input script command as $a or $z. If it is multiple
letters, it can be used as $\{myTemp\}.
If multiple variables are used as arguments to the {next} command,
then all must be of the same variable style: {index}, {loop}, {file},
{universe}, or {uloop}. An exception is that {universe}- and
{uloop}-style variables can be mixed in the same {next} command.
All the variables specified with the next command are incremented by
one value from their respective list of values. A {file}-style
variable reads the next line from its associated file. An
{atomfile}-style variable reads the next set of lines (one per atom)
from its associated file. {String-} or {atom}- or {equal}- or
{world}-style variables cannot be used with the next command,
since they only store a single value.
When any of the variables in the next command has no more values, a
flag is set that causes the input script to skip the next
"jump"_jump.html command encountered. This enables a loop containing
a next command to exit. As explained in the "variable"_variable.html
command, the variable that has exhausted its values is also deleted.
This allows it to be used and re-defined later in the input script.
{File}-style and {atomfile}-style variables are exhausted when the
end-of-file is reached.
When the next command is used with {index}- or {loop}-style variables,
the next value is assigned to the variable for all processors. When
the next command is used with {file}-style variables, the next line is
read from its file and the string assigned to the variable. When the
next command is used with {atomfile}-style variables, the next set of
per-atom values is read from its file and assigned to the variable.
When the next command is used with {universe}- or {uloop}-style
variables, all {universe}- or {uloop}-style variables must be listed
in the next command. This is because of the manner in which the
incrementing is done, using a single lock file for all variables. The
next value (for each variable) is assigned to whichever processor
partition executes the command first. All processors in the partition
are assigned the same value(s). Running LAMMPS on multiple partitions
of processors via the "-partition" command-line switch is described in
-"this section"_Section_start.html#start_7 of the manual. {Universe}-
+"this section"_Section_start.html#start_6 of the manual. {Universe}-
and {uloop}-style variables are incremented using the files
"tmp.lammps.variable" and "tmp.lammps.variable.lock" which you will
see in your directory during and after such a LAMMPS run.
Here is an example of running a series of simulations using the next
command with an {index}-style variable. If this input script is named
in.polymer, 8 simulations would be run using data files from
directories run1 thru run8.
variable d index run1 run2 run3 run4 run5 run6 run7 run8
shell cd $d
read_data data.polymer
run 10000
shell cd ..
clear
next d
jump in.polymer :pre
If the variable "d" were of style {universe}, and the same in.polymer
input script were run on 3 partitions of processors, then the first 3
simulations would begin, one on each set of processors. Whichever
partition finished first, it would assign variable "d" the 4th value
and run another simulation, and so forth until all 8 simulations were
finished.
Jump and next commands can also be nested to enable multi-level loops.
For example, this script will run 15 simulations in a double loop.
variable i loop 3
variable j loop 5
clear
...
read_data data.polymer.$i$j
print Running simulation $i.$j
run 10000
next j
jump in.script
next i
jump in.script :pre
Here is an example of a double loop which uses the "if"_if.html and
"jump"_jump.html commands to break out of the inner loop when a
condition is met, then continues iterating thru the outer loop.
label loopa
variable a loop 5
label loopb
variable b loop 5
print "A,B = $a,$b"
run 10000
if $b > 2 then "jump in.script break"
next b
jump in.script loopb
label break
variable b delete :pre
next a
jump in.script loopa :pre
[Restrictions:]
As described above.
[Related commands:]
"jump"_jump.html, "include"_include.html, "shell"_shell.html,
"variable"_variable.html,
[Default:] none
diff --git a/doc/src/package.txt b/doc/src/package.txt
index 18a26bd55..1b9092644 100644
--- a/doc/src/package.txt
+++ b/doc/src/package.txt
@@ -1,589 +1,589 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
package command :h3
[Syntax:]
package style args :pre
style = {gpu} or {intel} or {kokkos} or {omp} :ulb,l
args = arguments specific to the style :l
{gpu} args = Ngpu keyword value ...
Ngpu = # of GPUs per node
zero or more keyword/value pairs may be appended
keywords = {neigh} or {newton} or {binsize} or {split} or {gpuID} or {tpa} or {device} or {blocksize}
{neigh} value = {yes} or {no}
yes = neighbor list build on GPU (default)
no = neighbor list build on CPU
{newton} = {off} or {on}
off = set Newton pairwise flag off (default and required)
on = set Newton pairwise flag on (currently not allowed)
{binsize} value = size
size = bin size for neighbor list construction (distance units)
{split} = fraction
fraction = fraction of atoms assigned to GPU (default = 1.0)
{gpuID} values = first last
first = ID of first GPU to be used on each node
last = ID of last GPU to be used on each node
{tpa} value = Nthreads
Nthreads = # of GPU threads used per atom
{device} value = device_type
device_type = {kepler} or {fermi} or {cypress} or {generic}
{blocksize} value = size
size = thread block size for pair force computation
{intel} args = NPhi keyword value ...
Nphi = # of coprocessors per node
zero or more keyword/value pairs may be appended
keywords = {mode} or {omp} or {lrt} or {balance} or {ghost} or {tpc} or {tptask} or {no_affinity}
{mode} value = {single} or {mixed} or {double}
single = perform force calculations in single precision
mixed = perform force calculations in mixed precision
double = perform force calculations in double precision
{omp} value = Nthreads
Nthreads = number of OpenMP threads to use on CPU (default = 0)
{lrt} value = {yes} or {no}
yes = use additional thread dedicated for some PPPM calculations
no = do not dedicate an extra thread for some PPPM calculations
{balance} value = split
split = fraction of work to offload to coprocessor, -1 for dynamic
{ghost} value = {yes} or {no}
yes = include ghost atoms for offload
no = do not include ghost atoms for offload
{tpc} value = Ntpc
Ntpc = max number of coprocessor threads per coprocessor core (default = 4)
{tptask} value = Ntptask
Ntptask = max number of coprocessor threads per MPI task (default = 240)
{no_affinity} values = none
{kokkos} args = keyword value ...
zero or more keyword/value pairs may be appended
keywords = {neigh} or {neigh/qeq} or {newton} or {binsize} or {comm} or {comm/exchange} or {comm/forward}
{neigh} value = {full} or {half}
full = full neighbor list
half = half neighbor list built in thread-safe manner
{neigh/qeq} value = {full} or {half}
full = full neighbor list
half = half neighbor list built in thread-safe manner
{newton} = {off} or {on}
off = set Newton pairwise and bonded flags off (default)
on = set Newton pairwise and bonded flags on
{binsize} value = size
size = bin size for neighbor list construction (distance units)
{comm} value = {no} or {host} or {device}
use value for both comm/exchange and comm/forward
{comm/exchange} value = {no} or {host} or {device}
{comm/forward} value = {no} or {host} or {device}
no = perform communication pack/unpack in non-KOKKOS mode
host = perform pack/unpack on host (e.g. with OpenMP threading)
device = perform pack/unpack on device (e.g. on GPU)
{omp} args = Nthreads keyword value ...
Nthread = # of OpenMP threads to associate with each MPI process
zero or more keyword/value pairs may be appended
keywords = {neigh}
{neigh} value = {yes} or {no}
yes = threaded neighbor list build (default)
no = non-threaded neighbor list build :pre
:ule
[Examples:]
package gpu 1
package gpu 1 split 0.75
package gpu 2 split -1.0
package kokkos neigh half comm device
package omp 0 neigh no
package omp 4
package intel 1
package intel 2 omp 4 mode mixed balance 0.5 :pre
[Description:]
This command invokes package-specific settings for the various
accelerator packages available in LAMMPS. Currently the following
packages use settings from this command: GPU, USER-INTEL, KOKKOS, and
USER-OMP.
If this command is specified in an input script, it must be near the
top of the script, before the simulation box has been defined. This
is because it specifies settings that the accelerator packages use in
their initialization, before a simulation is defined.
This command can also be specified from the command-line when
launching LAMMPS, using the "-pk" "command-line
-switch"_Section_start.html#start_7. The syntax is exactly the same as
+switch"_Section_start.html#start_6. The syntax is exactly the same as
when used in an input script.
Note that all of the accelerator packages require the package command
to be specified (except the OPT package), if the package is to be used
in a simulation (LAMMPS can be built with an accelerator package
without using it in a particular simulation). However, in all cases,
a default version of the command is typically invoked by other
accelerator settings.
The KOKKOS package requires a "-k on" "command-line
-switch"_Section_start.html#start_7 respectively, which invokes a
+switch"_Section_start.html#start_6 respectively, which invokes a
"package kokkos" command with default settings.
For the GPU, USER-INTEL, and USER-OMP packages, if a "-sf gpu" or "-sf
-intel" or "-sf omp" "command-line switch"_Section_start.html#start_7
+intel" or "-sf omp" "command-line switch"_Section_start.html#start_6
is used to auto-append accelerator suffixes to various styles in the
input script, then those switches also invoke a "package gpu",
"package intel", or "package omp" command with default settings.
NOTE: A package command for a particular style can be invoked multiple
times when a simulation is setup, e.g. by the "-c on", "-k on", "-sf",
-and "-pk" "command-line switches"_Section_start.html#start_7, and by
+and "-pk" "command-line switches"_Section_start.html#start_6, and by
using this command in an input script. Each time it is used all of
the style options are set, either to default values or to specified
settings. I.e. settings from previous invocations do not persist
across multiple invocations.
See the "Section 5.3"_Section_accelerate.html#acc_3 section of the
manual for more details about using the various accelerator packages
for speeding up LAMMPS simulations.
:line
The {gpu} style invokes settings associated with the use of the GPU
package.
The {Ngpu} argument sets the number of GPUs per node. There must be
at least as many MPI tasks per node as GPUs, as set by the mpirun or
mpiexec command. If there are more MPI tasks (per node)
than GPUs, multiple MPI tasks will share each GPU.
Optional keyword/value pairs can also be specified. Each has a
default value as listed below.
The {neigh} keyword specifies where neighbor lists for pair style
computation will be built. If {neigh} is {yes}, which is the default,
neighbor list building is performed on the GPU. If {neigh} is {no},
neighbor list building is performed on the CPU. GPU neighbor list
building currently cannot be used with a triclinic box. GPU neighbor
list calculation currently cannot be used with
"hybrid"_pair_hybrid.html pair styles. GPU neighbor lists are not
compatible with commands that are not GPU-enabled. When a non-GPU
enabled command requires a neighbor list, it will also be built on the
CPU. In these cases, it will typically be more efficient to only use
CPU neighbor list builds.
The {newton} keyword sets the Newton flags for pairwise (not bonded)
interactions to {off} or {on}, the same as the "newton"_newton.html
command allows. Currently, only an {off} value is allowed, since all
the GPU package pair styles require this setting. This means more
computation is done, but less communication. In the future a value of
{on} may be allowed, so the {newton} keyword is included as an option
for compatibility with the package command for other accelerator
styles. Note that the newton setting for bonded interactions is not
affected by this keyword.
The {binsize} keyword sets the size of bins used to bin atoms in
neighbor list builds performed on the GPU, if {neigh} = {yes} is set.
If {binsize} is set to 0.0 (the default), then bins = the size of the
pairwise cutoff + neighbor skin distance. This is 2x larger than the
LAMMPS default used for neighbor list building on the CPU. This will
be close to optimal for the GPU, so you do not normally need to use
this keyword. Note that if you use a longer-than-usual pairwise
cutoff, e.g. to allow for a smaller fraction of KSpace work with a
"long-range Coulombic solver"_kspace_style.html because the GPU is
faster at performing pairwise interactions, then it may be optimal to
make the {binsize} smaller than the default. For example, with a
cutoff of 20*sigma in LJ "units"_units.html and a neighbor skin
distance of sigma, a {binsize} = 5.25*sigma can be more efficient than
the default.
The {split} keyword can be used for load balancing force calculations
between CPU and GPU cores in GPU-enabled pair styles. If 0 < {split} <
1.0, a fixed fraction of particles is offloaded to the GPU while force
calculation for the other particles occurs simultaneously on the CPU.
If {split} < 0.0, the optimal fraction (based on CPU and GPU timings)
is calculated every 25 timesteps, i.e. dynamic load-balancing across
the CPU and GPU is performed. If {split} = 1.0, all force
calculations for GPU accelerated pair styles are performed on the GPU.
In this case, other "hybrid"_pair_hybrid.html pair interactions,
"bond"_bond_style.html, "angle"_angle_style.html,
"dihedral"_dihedral_style.html, "improper"_improper_style.html, and
"long-range"_kspace_style.html calculations can be performed on the
CPU while the GPU is performing force calculations for the GPU-enabled
pair style. If all CPU force computations complete before the GPU
completes, LAMMPS will block until the GPU has finished before
continuing the timestep.
As an example, if you have two GPUs per node and 8 CPU cores per node,
and would like to run on 4 nodes (32 cores) with dynamic balancing of
force calculation across CPU and GPU cores, you could specify
mpirun -np 32 -sf gpu -in in.script # launch command
package gpu 2 split -1 # input script command :pre
In this case, all CPU cores and GPU devices on the nodes would be
utilized. Each GPU device would be shared by 4 CPU cores. The CPU
cores would perform force calculations for some fraction of the
particles at the same time the GPUs performed force calculation for
the other particles.
The {gpuID} keyword allows selection of which GPUs on each node will
be used for a simulation. The {first} and {last} values specify the
GPU IDs to use (from 0 to Ngpu-1). By default, first = 0 and last =
Ngpu-1, so that all GPUs are used, assuming Ngpu is set to the number
of physical GPUs. If you only wish to use a subset, set Ngpu to a
smaller number and first/last to a sub-range of the available GPUs.
The {tpa} keyword sets the number of GPU thread per atom used to
perform force calculations. With a default value of 1, the number of
threads will be chosen based on the pair style, however, the value can
be set explicitly with this keyword to fine-tune performance. For
large cutoffs or with a small number of particles per GPU, increasing
the value can improve performance. The number of threads per atom must
be a power of 2 and currently cannot be greater than 32.
The {device} keyword can be used to tune parameters optimized for a
specific accelerator, when using OpenCL. For CUDA, the {device}
keyword is ignored. Currently, the device type is limited to NVIDIA
Kepler, NVIDIA Fermi, AMD Cypress, or a generic device. More devices
may be added later. The default device type can be specified when
building LAMMPS with the GPU library, via settings in the
lib/gpu/Makefile that is used.
The {blocksize} keyword allows you to tweak the number of threads used
per thread block. This number should be a multiple of 32 (for GPUs)
and its maximum depends on the specific GPU hardware. Typical choices
are 64, 128, or 256. A larger blocksize increases occupancy of
individual GPU cores, but reduces the total number of thread blocks,
thus may lead to load imbalance.
:line
The {intel} style invokes settings associated with the use of the
USER-INTEL package. All of its settings, except the {omp} and {mode}
keywords, are ignored if LAMMPS was not built with Xeon Phi
coprocessor support. All of its settings, including the {omp} and
{mode} keyword are applicable if LAMMPS was built with coprocessor
support.
The {Nphi} argument sets the number of coprocessors per node.
This can be set to any value, including 0, if LAMMPS was not
built with coprocessor support.
Optional keyword/value pairs can also be specified. Each has a
default value as listed below.
The {omp} keyword determines the number of OpenMP threads allocated
for each MPI task when any portion of the interactions computed by a
USER-INTEL pair style are run on the CPU. This can be the case even
if LAMMPS was built with coprocessor support; see the {balance}
keyword discussion below. If you are running with less MPI tasks/node
than there are CPUs, it can be advantageous to use OpenMP threading on
the CPUs.
NOTE: The {omp} keyword has nothing to do with coprocessor threads on
the Xeon Phi; see the {tpc} and {tptask} keywords below for a
discussion of coprocessor threads.
The {Nthread} value for the {omp} keyword sets the number of OpenMP
threads allocated for each MPI task. Setting {Nthread} = 0 (the
default) instructs LAMMPS to use whatever value is the default for the
given OpenMP environment. This is usually determined via the
{OMP_NUM_THREADS} environment variable or the compiler runtime, which
is usually a value of 1.
For more details, including examples of how to set the OMP_NUM_THREADS
environment variable, see the discussion of the {Nthreads} setting on
this doc page for the "package omp" command. Nthreads is a required
argument for the USER-OMP package. Its meaning is exactly the same
for the USER-INTEL package.
NOTE: If you build LAMMPS with both the USER-INTEL and USER-OMP
packages, be aware that both packages allow setting of the {Nthreads}
value via their package commands, but there is only a single global
{Nthreads} value used by OpenMP. Thus if both package commands are
invoked, you should insure the two values are consistent. If they are
not, the last one invoked will take precedence, for both packages.
Also note that if the "-sf hybrid intel omp" "command-line
-switch"_"_Section_start.html#start_7 is used, it invokes a "package
+switch"_"_Section_start.html#start_6 is used, it invokes a "package
intel" command, followed by a "package omp" command, both with a
setting of {Nthreads} = 0.
The {mode} keyword determines the precision mode to use for
computing pair style forces, either on the CPU or on the coprocessor,
when using a USER-INTEL supported "pair style"_pair_style.html. It
can take a value of {single}, {mixed} which is the default, or
{double}. {Single} means single precision is used for the entire
force calculation. {Mixed} means forces between a pair of atoms are
computed in single precision, but accumulated and stored in double
precision, including storage of forces, torques, energies, and virial
quantities. {Double} means double precision is used for the entire
force calculation.
The {lrt} keyword can be used to enable "Long Range Thread (LRT)"
mode. It can take a value of {yes} to enable and {no} to disable.
LRT mode generates an extra thread (in addition to any OpenMP threads
specified with the OMP_NUM_THREADS environment variable or the {omp}
keyword). The extra thread is dedicated for performing part of the
"PPPM solver"_kspace_style.html computations and communications. This
can improve parallel performance on processors supporting
Simultaneous Multithreading (SMT) such as Hyperthreading on Intel
processors. In this mode, one additional thread is generated per MPI
process. LAMMPS will generate a warning in the case that more threads
are used than available in SMT hardware on a node. If the PPPM solver
from the USER-INTEL package is not used, then the LRT setting is
ignored and no extra threads are generated. Enabling LRT will replace
the "run_style"_run_style.html with the {verlet/lrt/intel} style that
is identical to the default {verlet} style aside from supporting the
LRT feature.
The {balance} keyword sets the fraction of "pair
style"_pair_style.html work offloaded to the coprocessor for split
values between 0.0 and 1.0 inclusive. While this fraction of work is
running on the coprocessor, other calculations will run on the host,
including neighbor and pair calculations that are not offloaded, as
well as angle, bond, dihedral, kspace, and some MPI communications.
If {split} is set to -1, the fraction of work is dynamically adjusted
automatically throughout the run. This typically give performance
within 5 to 10 percent of the optimal fixed fraction.
The {ghost} keyword determines whether or not ghost atoms, i.e. atoms
at the boundaries of processor sub-domains, are offloaded for neighbor
and force calculations. When the value = "no", ghost atoms are not
offloaded. This option can reduce the amount of data transfer with
the coprocessor and can also overlap MPI communication of forces with
computation on the coprocessor when the "newton pair"_newton.html
setting is "on". When the value = "yes", ghost atoms are offloaded.
In some cases this can provide better performance, especially if the
{balance} fraction is high.
The {tpc} keyword sets the max # of coprocessor threads {Ntpc} that
will run on each core of the coprocessor. The default value = 4,
which is the number of hardware threads per core supported by the
current generation Xeon Phi chips.
The {tptask} keyword sets the max # of coprocessor threads (Ntptask}
assigned to each MPI task. The default value = 240, which is the
total # of threads an entire current generation Xeon Phi chip can run
(240 = 60 cores * 4 threads/core). This means each MPI task assigned
to the Phi will enough threads for the chip to run the max allowed,
even if only 1 MPI task is assigned. If 8 MPI tasks are assigned to
the Phi, each will run with 30 threads. If you wish to limit the
number of threads per MPI task, set {tptask} to a smaller value.
E.g. for {tptask} = 16, if 8 MPI tasks are assigned, each will run
with 16 threads, for a total of 128.
Note that the default settings for {tpc} and {tptask} are fine for
most problems, regardless of how many MPI tasks you assign to a Phi.
The {no_affinity} keyword will turn off automatic setting of core
affinity for MPI tasks and OpenMP threads on the host when using
offload to a coprocessor. Affinity settings are used when possible
to prevent MPI tasks and OpenMP threads from being on separate NUMA
domains and to prevent offload threads from interfering with other
processes/threads used for LAMMPS.
:line
The {kokkos} style invokes settings associated with the use of the
KOKKOS package.
All of the settings are optional keyword/value pairs. Each has a
default value as listed below.
The {neigh} keyword determines how neighbor lists are built. A value
of {half} uses a thread-safe variant of half-neighbor lists,
the same as used by most pair styles in LAMMPS.
A value of {full} uses a full neighbor lists and is the default. This
performs twice as much computation as the {half} option, however that
is often a win because it is thread-safe and doesn't require atomic
operations in the calculation of pair forces. For that reason, {full}
is the default setting. However, when running in MPI-only mode with 1
thread per MPI task, {half} neighbor lists will typically be faster,
just as it is for non-accelerated pair styles. Similarly, the {neigh/qeq}
keyword determines how neighbor lists are built for "fix qeq/reax/kk"_fix_qeq_reax.html.
If not explicitly set, the value of {neigh/qeq} will match {neigh}.
The {newton} keyword sets the Newton flags for pairwise and bonded
interactions to {off} or {on}, the same as the "newton"_newton.html
command allows. The default is {off} because this will almost always
give better performance for the KOKKOS package. This means more
computation is done, but less communication. However, when running in
MPI-only mode with 1 thread per MPI task, a value of {on} will
typically be faster, just as it is for non-accelerated pair styles.
The {binsize} keyword sets the size of bins used to bin atoms in
neighbor list builds. The same value can be set by the "neigh_modify
binsize"_neigh_modify.html command. Making it an option in the
package kokkos command allows it to be set from the command line. The
default value is 0.0, which means the LAMMPS default will be used,
which is bins = 1/2 the size of the pairwise cutoff + neighbor skin
distance. This is fine when neighbor lists are built on the CPU. For
GPU builds, a 2x larger binsize equal to the pairwise cutoff +
neighbor skin, is often faster, which can be set by this keyword.
Note that if you use a longer-than-usual pairwise cutoff, e.g. to
allow for a smaller fraction of KSpace work with a "long-range
Coulombic solver"_kspace_style.html because the GPU is faster at
performing pairwise interactions, then this rule of thumb may give too
large a binsize.
The {comm} and {comm/exchange} and {comm/forward} keywords determine
whether the host or device performs the packing and unpacking of data
when communicating per-atom data between processors. "Exchange"
communication happens only on timesteps that neighbor lists are
rebuilt. The data is only for atoms that migrate to new processors.
"Forward" communication happens every timestep. The data is for atom
coordinates and any other atom properties that needs to be updated for
ghost atoms owned by each processor.
The {comm} keyword is simply a short-cut to set the same value
for both the {comm/exchange} and {comm/forward} keywords.
The value options for all 3 keywords are {no} or {host} or {device}.
A value of {no} means to use the standard non-KOKKOS method of
packing/unpacking data for the communication. A value of {host} means
to use the host, typically a multi-core CPU, and perform the
packing/unpacking in parallel with threads. A value of {device} means
to use the device, typically a GPU, to perform the packing/unpacking
operation.
The optimal choice for these keywords depends on the input script and
the hardware used. The {no} value is useful for verifying that the
Kokkos-based {host} and {device} values are working correctly. It may
also be the fastest choice when using Kokkos styles in MPI-only mode
(i.e. with a thread count of 1).
When running on CPUs or Xeon Phi, the {host} and {device} values work
identically. When using GPUs, the {device} value will typically be
optimal if all of your styles used in your input script are supported
by the KOKKOS package. In this case data can stay on the GPU for many
timesteps without being moved between the host and GPU, if you use the
{device} value. This requires that your MPI is able to access GPU
memory directly. Currently that is true for OpenMPI 1.8 (or later
versions), Mvapich2 1.9 (or later), and CrayMPI. If your script uses
styles (e.g. fixes) which are not yet supported by the KOKKOS package,
then data has to be move between the host and device anyway, so it is
typically faster to let the host handle communication, by using the
{host} value. Using {host} instead of {no} will enable use of
multiple threads to pack/unpack communicated data.
:line
The {omp} style invokes settings associated with the use of the
USER-OMP package.
The {Nthread} argument sets the number of OpenMP threads allocated for
each MPI task. For example, if your system has nodes with dual
quad-core processors, it has a total of 8 cores per node. You could
use two MPI tasks per node (e.g. using the -ppn option of the mpirun
command in MPICH or -npernode in OpenMPI), and set {Nthreads} = 4.
This would use all 8 cores on each node. Note that the product of MPI
tasks * threads/task should not exceed the physical number of cores
(on a node), otherwise performance will suffer.
Setting {Nthread} = 0 instructs LAMMPS to use whatever value is the
default for the given OpenMP environment. This is usually determined
via the {OMP_NUM_THREADS} environment variable or the compiler
runtime. Note that in most cases the default for OpenMP capable
compilers is to use one thread for each available CPU core when
{OMP_NUM_THREADS} is not explicitly set, which can lead to poor
performance.
Here are examples of how to set the environment variable when
launching LAMMPS:
env OMP_NUM_THREADS=4 lmp_machine -sf omp -in in.script
env OMP_NUM_THREADS=2 mpirun -np 2 lmp_machine -sf omp -in in.script
mpirun -x OMP_NUM_THREADS=2 -np 2 lmp_machine -sf omp -in in.script :pre
or you can set it permanently in your shell's start-up script.
All three of these examples use a total of 4 CPU cores.
Note that different MPI implementations have different ways of passing
the OMP_NUM_THREADS environment variable to all MPI processes. The
2nd example line above is for MPICH; the 3rd example line with -x is
for OpenMPI. Check your MPI documentation for additional details.
What combination of threads and MPI tasks gives the best performance
is difficult to predict and can depend on many components of your
input. Not all features of LAMMPS support OpenMP threading via the
USER-OMP package and the parallel efficiency can be very different,
too.
Optional keyword/value pairs can also be specified. Each has a
default value as listed below.
The {neigh} keyword specifies whether neighbor list building will be
multi-threaded in addition to force calculations. If {neigh} is set
to {no} then neighbor list calculation is performed only by MPI tasks
with no OpenMP threading. If {mode} is {yes} (the default), a
multi-threaded neighbor list build is used. Using {neigh} = {yes} is
almost always faster and should produce identical neighbor lists at the
expense of using more memory. Specifically, neighbor list pages are
allocated for all threads at the same time and each thread works
within its own pages.
:line
[Restrictions:]
This command cannot be used after the simulation box is defined by a
"read_data"_read_data.html or "create_box"_create_box.html command.
The gpu style of this command can only be invoked if LAMMPS was built
with the GPU package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The intel style of this command can only be invoked if LAMMPS was
built with the USER-INTEL package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The kk style of this command can only be invoked if LAMMPS was built
with the KOKKOS package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The omp style of this command can only be invoked if LAMMPS was built
with the USER-OMP package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"suffix"_suffix.html, "-pk" "command-line
-setting"_Section_start.html#start_7
+setting"_Section_start.html#start_6
[Default:]
For the GPU package, the default is Ngpu = 1 and the option defaults
are neigh = yes, newton = off, binsize = 0.0, split = 1.0, gpuID = 0
to Ngpu-1, tpa = 1, and device = not used. These settings are made
automatically if the "-sf gpu" "command-line
-switch"_Section_start.html#start_7 is used. If it is not used, you
+switch"_Section_start.html#start_6 is used. If it is not used, you
must invoke the package gpu command in your input script or via the
-"-pk gpu" "command-line switch"_Section_start.html#start_7.
+"-pk gpu" "command-line switch"_Section_start.html#start_6.
For the USER-INTEL package, the default is Nphi = 1 and the option
defaults are omp = 0, mode = mixed, lrt = no, balance = -1, tpc = 4,
tptask = 240. The default ghost option is determined by the pair
style being used. This value is output to the screen in the offload
report at the end of each run. Note that all of these settings,
except "omp" and "mode", are ignored if LAMMPS was not built with
Xeon Phi coprocessor support. These settings are made automatically
-if the "-sf intel" "command-line switch"_Section_start.html#start_7
+if the "-sf intel" "command-line switch"_Section_start.html#start_6
is used. If it is not used, you must invoke the package intel
command in your input script or or via the "-pk intel" "command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
For the KOKKOS package, the option defaults neigh = full,
neigh/qeq = full, newton = off, binsize = 0.0, and comm = device.
These settings are made automatically by the required "-k on" "command-line
-switch"_Section_start.html#start_7. You can change them bu using the
+switch"_Section_start.html#start_6. You can change them bu using the
package kokkos command in your input script or via the "-pk kokkos"
-"command-line switch"_Section_start.html#start_7.
+"command-line switch"_Section_start.html#start_6.
For the OMP package, the default is Nthreads = 0 and the option
defaults are neigh = yes. These settings are made automatically if
-the "-sf omp" "command-line switch"_Section_start.html#start_7 is
+the "-sf omp" "command-line switch"_Section_start.html#start_6 is
used. If it is not used, you must invoke the package omp command in
your input script or via the "-pk omp" "command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
diff --git a/doc/src/pair_adp.txt b/doc/src/pair_adp.txt
index 457a797d9..9d2a48dcb 100644
--- a/doc/src/pair_adp.txt
+++ b/doc/src/pair_adp.txt
@@ -1,186 +1,186 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style adp command :h3
pair_style adp/omp command :h3
[Syntax:]
pair_style adp :pre
[Examples:]
pair_style adp
pair_coeff * * Ta.adp Ta
pair_coeff * * ../potentials/AlCu.adp Al Al Cu :pre
[Description:]
Style {adp} computes pairwise interactions for metals and metal alloys
using the angular dependent potential (ADP) of "(Mishin)"_#Mishin,
which is a generalization of the "embedded atom method (EAM)
potential"_pair_eam.html. The LAMMPS implementation is discussed in
"(Singh)"_#Singh. The total energy Ei of an atom I is given by
:c,image(Eqs/pair_adp.jpg)
where F is the embedding energy which is a function of the atomic
electron density rho, phi is a pair potential interaction, alpha and
beta are the element types of atoms I and J, and s and t = 1,2,3 and
refer to the cartesian coordinates. The mu and lambda terms represent
the dipole and quadruple distortions of the local atomic environment
which extend the original EAM framework by introducing angular forces.
Note that unlike for other potentials, cutoffs for ADP potentials are
not set in the pair_style or pair_coeff command; they are specified in
the ADP potential files themselves. Likewise, the ADP potential files
list atomic masses; thus you do not need to use the "mass"_mass.html
command to specify them.
The NIST WWW site distributes and documents ADP potentials:
http://www.ctcms.nist.gov/potentials :pre
Note that these must be converted into the extended DYNAMO {setfl}
format discussed below.
The NIST site is maintained by Chandler Becker (cbecker at nist.gov)
who is good resource for info on interatomic potentials and file
formats.
:line
Only a single pair_coeff command is used with the {adp} style which
specifies an extended DYNAMO {setfl} file, which contains information
for M elements. These are mapped to LAMMPS atom types by specifying N
additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of extended {setfl} elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways to
specify the path for the potential file.
As an example, the potentials/AlCu.adp file, included in the
potentials directory of the LAMMPS distribution, is an extended {setfl}
file which has tabulated ADP values for w elements and their alloy
interactions: Cu and Al. If your LAMMPS simulation has 4 atoms types
and you want the 1st 3 to be Al, and the 4th to be Cu, you would use
the following pair_coeff command:
pair_coeff * * AlCu.adp Al Al Al Cu :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Al arguments map LAMMPS atom types 1,2,3 to the Al
element in the extended {setfl} file. The final Cu argument maps
LAMMPS atom type 4 to the Al element in the extended {setfl} file.
Note that there is no requirement that your simulation use all the
elements specified by the extended {setfl} file.
If a mapping value is specified as NULL, the mapping is not performed.
This can be used when an {adp} potential is used as part of the
{hybrid} pair style. The NULL values are placeholders for atom types
that will be used with other potentials.
{Adp} files in the {potentials} directory of the LAMMPS distribution
have an ".adp" suffix. A DYNAMO {setfl} file extended for ADP is
formatted as follows. Basically it is the standard {setfl} format
with additional tabulated functions u and w added to the file after
the tabulated pair potentials. See the "pair_eam"_pair_eam.html
command for further details on the {setfl} format.
lines 1,2,3 = comments (ignored)
line 4: Nelements Element1 Element2 ... ElementN
line 5: Nrho, drho, Nr, dr, cutoff :ul
Following the 5 header lines are Nelements sections, one for each
element, each with the following format:
line 1 = atomic number, mass, lattice constant, lattice type (e.g. FCC)
embedding function F(rho) (Nrho values)
density function rho(r) (Nr values) :ul
Following the Nelements sections, Nr values for each pair potential
phi(r) array are listed for all i,j element pairs in the same format
as other arrays. Since these interactions are symmetric (i,j = j,i)
only phi arrays with i >= j are listed, in the following order: i,j =
(1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ..., (Nelements,
Nelements). The tabulated values for each phi function are listed as
r*phi (in units of eV-Angstroms), since they are for atom pairs, the
same as for "other EAM files"_pair_eam.html.
After the phi(r) arrays, each of the u(r) arrays are listed in the
same order with the same assumptions of symmetry. Directly following
the u(r), the w(r) arrays are listed. Note that phi(r) is the only
array tabulated with a scaling by r.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, no special mixing rules are needed, since
the ADP potential files specify alloy interactions explicitly.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in tabulated potential files.
Thus, you need to re-specify the pair_style and pair_coeff commands in
an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style is part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_eam"_pair_eam.html
[Default:] none
:line
:link(Mishin)
[(Mishin)] Mishin, Mehl, and Papaconstantopoulos, Acta Mater, 53, 4029
(2005).
:link(Singh)
[(Singh)] Singh and Warner, Acta Mater, 58, 5797-5805 (2010),
diff --git a/doc/src/pair_agni.txt b/doc/src/pair_agni.txt
index 06dcccb9d..402e537da 100644
--- a/doc/src/pair_agni.txt
+++ b/doc/src/pair_agni.txt
@@ -1,128 +1,128 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style agni command :h3
pair_style agni/omp command :h3
[Syntax:]
pair_style agni :pre
[Examples:]
pair_style agni
pair_coeff * * Al.agni Al
[Description:]
Style {agni} style computes the manybody vectorial force components for
an atom as
:c,image(Eqs/pair_agni.jpg)
{u} labels the individual components, i.e. x, y or z, and {V} is the
corresponding atomic fingerprint. {d} is the Euclidean distance between
any two atomic fingerprints. A total of N_t reference atomic
environments are considered to construct the force field file. {alpha_t}
and {l} are the weight coefficients and length scale parameter of the
non-linear regression model.
The method implements the recently proposed machine learning access to
atomic forces as discussed extensively in the following publications -
"(Botu1)"_#Botu2015adaptive and "(Botu2)"_#Botu2015learning. The premise
of the method is to map the atomic environment numerically into a
fingerprint, and use machine learning methods to create a mapping to the
vectorial atomic forces.
Only a single pair_coeff command is used with the {agni} style which
specifies an AGNI potential file containing the parameters of the
force field for the needed elements. These are mapped to LAMMPS atom
types by specifying N additional arguments after the filename in the
pair_coeff command, where N is the number of LAMMPS atom types:
filename
N element names = mapping of AGNI elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the force field file.
An AGNI force field is fully specified by the filename which contains the
parameters of the force field, i.e., the reference training environments
used to construct the machine learning force field. Example force field
and input files are provided in the examples/USER/misc/agni directory.
:line
Styles with {omp} suffix is functionally the same as the corresponding
style without the suffix. They have been optimized to run faster, depending
on your available hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated style takes the same arguments and
should produce the same results, except for round-off and precision
issues.
The accelerated style is part of the USER-OMP. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated style explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
Currently, only elemental systems are implemented. Also, the method only
provides access to the forces and not energies or stresses. However, one
can access the energy via thermodynamic integration of the forces as
discussed in "(Botu3)"_#Botu2016construct. This pair style is part
of the USER-MISC package. It is only enabled if LAMMPS was built with
that package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info.
The AGNI force field files provided with LAMMPS (see the
potentials directory) are parameterized for metal "units"_units.html.
You can use the AGNI potential with any LAMMPS units, but you would need
to create your own AGNI potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Botu2015adaptive)
[(Botu1)] V. Botu and R. Ramprasad, Int. J. Quant. Chem., 115(16), 1074 (2015).
:link(Botu2015learning)
[(Botu2)] V. Botu and R. Ramprasad, Phys. Rev. B, 92(9), 094306 (2015).
:link(Botu2016construct)
[(Botu3)] V. Botu, R. Batra, J. Chapman and R. Ramprasad, https://arxiv.org/abs/1610.02098 (2016).
diff --git a/doc/src/pair_airebo.txt b/doc/src/pair_airebo.txt
index 0c03eb326..e66ecb637 100644
--- a/doc/src/pair_airebo.txt
+++ b/doc/src/pair_airebo.txt
@@ -1,243 +1,243 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style airebo command :h3
pair_style airebo/omp command :h3
pair_style airebo/morse command :h3
pair_style airebo/morse/omp command :h3
pair_style rebo command :h3
pair_style rebo/omp command :h3
[Syntax:]
pair_style style cutoff LJ_flag TORSION_flag cutoff_min :pre
style = {airebo} or {airebo/morse} or {rebo}
cutoff = LJ or Morse cutoff (sigma scale factor) (AIREBO and AIREBO-M only)
LJ_flag = 0/1 to turn off/on the LJ or Morse term (AIREBO and AIREBO-M only, optional)
TORSION_flag = 0/1 to turn off/on the torsion term (AIREBO and AIREBO-M only, optional)
cutoff_min = Start of the transition region of cutoff (sigma scale factor) (AIREBO and AIREBO-M only, optional) :ul
[Examples:]
pair_style airebo 3.0
pair_style airebo 2.5 1 0
pair_coeff * * ../potentials/CH.airebo H C :pre
pair_style airebo/morse 3.0
pair_coeff * * ../potentials/CH.airebo-m H C :pre
pair_style rebo
pair_coeff * * ../potentials/CH.airebo H C :pre
[Description:]
The {airebo} pair style computes the Adaptive Intermolecular Reactive
Empirical Bond Order (AIREBO) Potential of "(Stuart)"_#Stuart for a
system of carbon and/or hydrogen atoms. Note that this is the initial
formulation of AIREBO from 2000, not the later formulation.
The {airebo/morse} pair style computes the AIREBO-M potential, which
is equivalent to AIREBO, but replaces the LJ term with a Morse potential.
The Morse potentials are parameterized by high-quality quantum chemistry
(MP2) calculations and do not diverge as quickly as particle density
increases. This allows AIREBO-M to retain accuracy to much higher pressures
than AIREBO (up to 40 GPa for Polyethylene). Details for this potential
and its parameterization are given in "(O'Conner)"_#OConnor.
The {rebo} pair style computes the Reactive Empirical Bond Order (REBO)
Potential of "(Brenner)"_#Brenner. Note that this is the so-called
2nd generation REBO from 2002, not the original REBO from 1990.
As discussed below, 2nd generation REBO is closely related to the
initial AIREBO; it is just a subset of the potential energy terms.
The AIREBO potential consists of three terms:
:c,image(Eqs/pair_airebo.jpg)
By default, all three terms are included. For the {airebo} style, if
the first two optional flag arguments to the pair_style command are
included, the LJ and torsional terms can be turned off. Note that
both or neither of the flags must be included. If both of the LJ an
torsional terms are turned off, it becomes the 2nd-generation REBO
potential, with a small caveat on the spline fitting procedure
mentioned below. This can be specified directly as pair_style {rebo}
with no additional arguments.
The detailed formulas for this potential are given in
"(Stuart)"_#Stuart; here we provide only a brief description.
The E_REBO term has the same functional form as the hydrocarbon REBO
potential developed in "(Brenner)"_#Brenner. The coefficients for
E_REBO in AIREBO are essentially the same as Brenner's potential, but
a few fitted spline values are slightly different. For most cases the
E_REBO term in AIREBO will produce the same energies, forces and
statistical averages as the original REBO potential from which it was
derived. The E_REBO term in the AIREBO potential gives the model its
reactive capabilities and only describes short-ranged C-C, C-H and H-H
interactions (r < 2 Angstroms). These interactions have strong
coordination-dependence through a bond order parameter, which adjusts
the attraction between the I,J atoms based on the position of other
nearby atoms and thus has 3- and 4-body dependence.
The E_LJ term adds longer-ranged interactions (2 < r < cutoff) using a
form similar to the standard "Lennard Jones potential"_pair_lj.html.
The E_LJ term in AIREBO contains a series of switching functions so
that the short-ranged LJ repulsion (1/r^12) does not interfere with
the energetics captured by the E_REBO term. The extent of the E_LJ
interactions is determined by the {cutoff} argument to the pair_style
command which is a scale factor. For each type pair (C-C, C-H, H-H)
the cutoff is obtained by multiplying the scale factor by the sigma
value defined in the potential file for that type pair. In the
standard AIREBO potential, sigma_CC = 3.4 Angstroms, so with a scale
factor of 3.0 (the argument in pair_style), the resulting E_LJ cutoff
would be 10.2 Angstroms.
By default, the longer-ranged interaction is smoothly switched off
between 2.16 and 3.0 sigma. By specifying {cutoff_min} in addition
to {cutoff}, the switching can be configured to take place between
{cutoff_min} and {cutoff}. {cutoff_min} can only be specified if all
optional arguments are given.
The E_TORSION term is an explicit 4-body potential that describes
various dihedral angle preferences in hydrocarbon configurations.
:line
Only a single pair_coeff command is used with the {airebo}, {airebo}
or {rebo} style which specifies an AIREBO or AIREBO-M potential file
with parameters for C and H. Note that the {rebo} style in LAMMPS
uses the same AIREBO-formatted potential file. These are mapped to
LAMMPS atom types by specifying N additional arguments after the
filename in the pair_coeff command, where N is the number of LAMMPS
atom types:
filename
N element names = mapping of AIREBO elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, if your LAMMPS simulation has 4 atom types and you want
the 1st 3 to be C, and the 4th to be H, you would use the following
pair_coeff command:
pair_coeff * * CH.airebo C C C H :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three C arguments map LAMMPS atom types 1,2,3 to the C
element in the AIREBO file. The final H argument maps LAMMPS atom
type 4 to the H element in the SW file. If a mapping value is
specified as NULL, the mapping is not performed. This can be used
when a {airebo} potential is used as part of the {hybrid} pair style.
The NULL values are placeholders for atom types that will be used with
other potentials.
The parameters/coefficients for the AIREBO potentials are listed in
the CH.airebo file to agree with the original "(Stuart)"_#Stuart
paper. Thus the parameters are specific to this potential and the way
it was fit, so modifying the file should be done cautiously.
Similarly the parameters/coefficients for the AIREBO-M potentials are
listed in the CH.airebo-m file to agree with the "(O'Connor)"_#OConnor
paper. Thus the parameters are specific to this potential and the way
it was fit, so modifying the file should be done cautiously. The
AIREBO-M Morse potentials were parameterized using a cutoff of
3.0 (sigma). Modifying this cutoff may impact simulation accuracy.
This pair style tallies a breakdown of the total AIREBO potential
energy into sub-categories, which can be accessed via the "compute
pair"_compute_pair.html command as a vector of values of length 3.
The 3 values correspond to the following sub-categories:
{E_REBO} = REBO energy
{E_LJ} = Lennard-Jones energy
{E_TORSION} = Torsion energy :ol
To print these quantities to the log file (with descriptive column
headings) the following commands could be included in an input script:
compute 0 all pair airebo
variable REBO equal c_0\[1\]
variable LJ equal c_0\[2\]
variable TORSION equal c_0\[3\]
thermo_style custom step temp epair v_REBO v_LJ v_TORSION :pre
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support the "pair_modify"_pair_modify.html
mix, shift, table, and tail options.
These pair styles do not write their information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
[Restrictions:]
These pair styles are part of the MANYBODY package. They are only
enabled if LAMMPS was built with that package. See the
"Making LAMMPS"_Section_start.html#start_3 section for more info.
These pair potentials require the "newton"_newton.html setting to be
"on" for pair interactions.
The CH.airebo and CH.airebo-m potential files provided with LAMMPS
(see the potentials directory) are parameterized for metal "units"_units.html.
You can use the AIREBO, AIREBO-M or REBO potential with any LAMMPS units,
but you would need to create your own AIREBO or AIREBO-M potential file
with coefficients listed in the appropriate units, if your simulation
doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Stuart)
[(Stuart)] Stuart, Tutein, Harrison, J Chem Phys, 112, 6472-6486
(2000).
:link(Brenner)
[(Brenner)] Brenner, Shenderova, Harrison, Stuart, Ni, Sinnott, J
Physics: Condensed Matter, 14, 783-802 (2002).
:link(OConnor)
[(O'Connor)] O'Connor et al., J. Chem. Phys. 142, 024903 (2015).
diff --git a/doc/src/pair_beck.txt b/doc/src/pair_beck.txt
index 4e792754b..e160f09b3 100644
--- a/doc/src/pair_beck.txt
+++ b/doc/src/pair_beck.txt
@@ -1,109 +1,109 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style beck command :h3
pair_style beck/gpu command :h3
pair_style beck/omp command :h3
[Syntax:]
pair_style beck Rc :pre
Rc = cutoff for interactions (distance units) :ul
[Examples:]
pair_style beck 8.0
pair_coeff * * 399.671876712 0.0000867636112694 0.675 4.390 0.0003746
pair_coeff 1 1 399.671876712 0.0000867636112694 0.675 4.390 0.0003746 6.0 :pre
[Description:]
Style {beck} computes interactions based on the potential by
"(Beck)"_#Beck, originally designed for simulation of Helium. It
includes truncation at a cutoff distance Rc.
:c,image(Eqs/pair_beck.jpg)
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands.
A (energy units)
B (energy-distance^6 units)
a (distance units)
alpha (1/distance units)
beta (1/distance^6 units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global cutoff
Rc is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, coefficients must be specified.
No default mixing rules are used.
This pair style does not support the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Beck)
[(Beck)] Beck, Molecular Physics, 14, 311 (1968).
diff --git a/doc/src/pair_born.txt b/doc/src/pair_born.txt
index d38d9e319..a3cc744a2 100644
--- a/doc/src/pair_born.txt
+++ b/doc/src/pair_born.txt
@@ -1,205 +1,205 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style born command :h3
pair_style born/omp command :h3
pair_style born/gpu command :h3
pair_style born/coul/long command :h3
pair_style born/coul/long/cs command :h3
pair_style born/coul/long/gpu command :h3
pair_style born/coul/long/omp command :h3
pair_style born/coul/msm command :h3
pair_style born/coul/msm/omp command :h3
pair_style born/coul/wolf command :h3
pair_style born/coul/wolf/gpu command :h3
pair_style born/coul/wolf/omp command :h3
pair_style born/coul/dsf command :h3
pair_style born/coul/dsf/cs command :h3
[Syntax:]
pair_style style args :pre
style = {born} or {born/coul/long} or {born/coul/long/cs} or {born/coul/msm} or {born/coul/wolf}
args = list of arguments for a particular style :ul
{born} args = cutoff
cutoff = global cutoff for non-Coulombic interactions (distance units)
{born/coul/long} or {born/coul/long/cs} args = cutoff (cutoff2)
cutoff = global cutoff for non-Coulombic (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{born/coul/msm} args = cutoff (cutoff2)
cutoff = global cutoff for non-Coulombic (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{born/coul/wolf} args = alpha cutoff (cutoff2)
alpha = damping parameter (inverse distance units)
cutoff = global cutoff for non-Coulombic (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{born/coul/dsf} or {born/coul/dsf/cs} args = alpha cutoff (cutoff2)
alpha = damping parameter (inverse distance units)
cutoff = global cutoff for non-Coulombic (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (distance units) :pre
[Examples:]
pair_style born 10.0
pair_coeff * * 6.08 0.317 2.340 24.18 11.51
pair_coeff 1 1 6.08 0.317 2.340 24.18 11.51 :pre
pair_style born/coul/long 10.0
pair_style born/coul/long/cs 10.0
pair_style born/coul/long 10.0 8.0
pair_style born/coul/long/cs 10.0 8.0
pair_coeff * * 6.08 0.317 2.340 24.18 11.51
pair_coeff 1 1 6.08 0.317 2.340 24.18 11.51 :pre
pair_style born/coul/msm 10.0
pair_style born/coul/msm 10.0 8.0
pair_coeff * * 6.08 0.317 2.340 24.18 11.51
pair_coeff 1 1 6.08 0.317 2.340 24.18 11.51 :pre
pair_style born/coul/wolf 0.25 10.0
pair_style born/coul/wolf 0.25 10.0 9.0
pair_coeff * * 6.08 0.317 2.340 24.18 11.51
pair_coeff 1 1 6.08 0.317 2.340 24.18 11.51 :pre
pair_style born/coul/dsf 0.1 10.0 12.0
pair_coeff * * 0.0 1.00 0.00 0.00 0.00
pair_coeff 1 1 480.0 0.25 0.00 1.05 0.50 :pre
[Description:]
The {born} style computes the Born-Mayer-Huggins or Tosi/Fumi
potential described in "(Fumi and Tosi)"_#FumiTosi, given by
:c,image(Eqs/pair_born.jpg)
where sigma is an interaction-dependent length parameter, rho is an
ionic-pair dependent length parameter, and Rc is the cutoff.
The styles with {coul/long} or {coul/msm} add a Coulombic term as
described for the "lj/cut"_pair_lj.html pair styles. An additional
damping factor is applied to the Coulombic term so it can be used in
conjunction with the "kspace_style"_kspace_style.html command and its
{ewald} or {pppm} of {msm} option. The Coulombic cutoff specified for
this style means that pairwise interactions within this distance are
computed directly; interactions outside that distance are computed in
reciprocal space.
If one cutoff is specified for the {born/coul/long} and
{born/coul/msm} style, it is used for both the A,C,D and Coulombic
terms. If two cutoffs are specified, the first is used as the cutoff
for the A,C,D terms, and the second is the cutoff for the Coulombic
term.
The {born/coul/wolf} style adds a Coulombic term as described for the
Wolf potential in the "coul/wolf"_pair_coul.html pair style.
The {born/coul/dsf} style computes the Coulomb contribution with the
damped shifted force model as in the "coul/dsf"_pair_coul.html style.
Style {born/coul/long/cs} is identical to {born/coul/long} except that
a term is added for the "core/shell model"_Section_howto.html#howto_25
to allow charges on core and shell particles to be separated by r =
0.0. The same correction is introduced for {born/coul/dsf/cs} style
which is identical to {born/coul/dsf}.
Note that these potentials are related to the "Buckingham
potential"_pair_buck.html.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
A (energy units)
rho (distance units)
sigma (distance units)
C (energy units * distance units^6)
D (energy units * distance units^8)
cutoff (distance units) :ul
The second coefficient, rho, must be greater than zero.
The last coefficient is optional. If not specified, the global A,C,D
cutoff specified in the pair_style command is used.
For {born/coul/long}, {born/coul/wolf} and {born/coul/dsf} no
Coulombic cutoff can be specified for an individual I,J type pair.
All type pairs use the same global Coulombic cutoff specified in the
pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
These styles support the "pair_modify"_pair_modify.html shift option
for the energy of the exp(), 1/r^6, and 1/r^8 portion of the pair
interaction.
The {born/coul/long} pair style supports the
"pair_modify"_pair_modify.html table option ti tabulate the
short-range portion of the long-range Coulombic interaction.
These styles support the pair_modify tail option for adding long-range
tail corrections to energy and pressure.
Thess styles writes thei information to binary "restart"_restart.html
files, so pair_style and pair_coeff commands do not need to be
specified in an input script that reads a restart file.
These styles can only be used via the {pair} keyword of the "run_style
respa"_run_style.html command. They do not support the {inner},
{middle}, {outer} keywords.
:line
[Restrictions:]
The {born/coul/long} style is part of the KSPACE package. It is only
enabled if LAMMPS was built with that package. See the
"Making LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style buck"_pair_buck.html
[Default:] none
:line
:link(FumiTosi)
Fumi and Tosi, J Phys Chem Solids, 25, 31 (1964),
Fumi and Tosi, J Phys Chem Solids, 25, 45 (1964).
diff --git a/doc/src/pair_brownian.txt b/doc/src/pair_brownian.txt
index 33eed7762..79b71e91c 100644
--- a/doc/src/pair_brownian.txt
+++ b/doc/src/pair_brownian.txt
@@ -1,143 +1,143 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style brownian command :h3
pair_style brownian/omp command :h3
pair_style brownian/poly command :h3
pair_style brownian/poly/omp command :h3
[Syntax:]
pair_style style mu flaglog flagfld cutinner cutoff t_target seed flagHI flagVF :pre
style = {brownian} or {brownian/poly}
mu = dynamic viscosity (dynamic viscosity units)
flaglog = 0/1 log terms in the lubrication approximation on/off
flagfld = 0/1 to include/exclude Fast Lubrication Dynamics effects
cutinner = inner cutoff distance (distance units)
cutoff = outer cutoff for interactions (distance units)
t_target = target temp of the system (temperature units)
seed = seed for the random number generator (positive integer)
flagHI (optional) = 0/1 to include/exclude 1/r hydrodynamic interactions
flagVF (optional) = 0/1 to include/exclude volume fraction corrections in the long-range isotropic terms :ul
[Examples:]
pair_style brownian 1.5 1 1 2.01 2.5 2.0 5878567 (assuming radius = 1)
pair_coeff 1 1 2.05 2.8
pair_coeff * * :pre
[Description:]
Styles {brownian} and {brownian/poly} compute Brownian forces and
torques on finite-size spherical particles. The former requires
monodisperse spherical particles; the latter allows for polydisperse
spherical particles.
These pair styles are designed to be used with either the "pair_style
lubricate"_pair_lubricate.html or "pair_style
lubricateU"_pair_lubricateU.html commands to provide thermostatting
when dissipative lubrication forces are acting. Thus the parameters
{mu}, {flaglog}, {flagfld}, {cutinner}, and {cutoff} should be
specified consistent with the settings in the lubrication pair styles.
For details, refer to either of the lubrication pair styles.
The {t_target} setting is used to specify the target temperature of
the system. The random number {seed} is used to generate random
numbers for the thermostatting procedure.
The {flagHI} and {flagVF} settings are optional. Neither should be
used, or both must be defined.
:line
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
cutinner (distance units)
cutoff (distance units) :ul
The two coefficients are optional. If neither is specified, the two
cutoffs specified in the pair_style command are used. Otherwise both
must be specified.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "this section"_Section_accelerate.html of
the manual. The accelerated styles take the same arguments and should
produce the same results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "this section"_Section_accelerate.html of the manual for more
instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the two cutoff distances for this
pair style can be mixed. The default mix value is {geometric}. See
the "pair_modify" command for details.
This pair style does not support the "pair_modify"_pair_modify.html
shift option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
These styles are part of the COLLOID package. They are only enabled
if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
Only spherical monodisperse particles are allowed for pair_style
brownian.
Only spherical particles are allowed for pair_style brownian/poly.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style
lubricate"_pair_lubricate.html, "pair_style
lubricateU"_pair_lubricateU.html
[Default:]
The default settings for the optional args are flagHI = 1 and flagVF =
1.
diff --git a/doc/src/pair_buck.txt b/doc/src/pair_buck.txt
index e705e735f..d18b39d5d 100644
--- a/doc/src/pair_buck.txt
+++ b/doc/src/pair_buck.txt
@@ -1,201 +1,201 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style buck command :h3
pair_style buck/gpu command :h3
pair_style buck/intel command :h3
pair_style buck/kk command :h3
pair_style buck/omp command :h3
pair_style buck/coul/cut command :h3
pair_style buck/coul/cut/gpu command :h3
pair_style buck/coul/cut/intel command :h3
pair_style buck/coul/cut/kk command :h3
pair_style buck/coul/cut/omp command :h3
pair_style buck/coul/long command :h3
pair_style buck/coul/long/cs command :h3
pair_style buck/coul/long/gpu command :h3
pair_style buck/coul/long/intel command :h3
pair_style buck/coul/long/kk command :h3
pair_style buck/coul/long/omp command :h3
pair_style buck/coul/msm command :h3
pair_style buck/coul/msm/omp command :h3
[Syntax:]
pair_style style args :pre
style = {buck} or {buck/coul/cut} or {buck/coul/long} or {buck/coul/long/cs} or {buck/coul/msm}
args = list of arguments for a particular style :ul
{buck} args = cutoff
cutoff = global cutoff for Buckingham interactions (distance units)
{buck/coul/cut} args = cutoff (cutoff2)
cutoff = global cutoff for Buckingham (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{buck/coul/long} or {buck/coul/long/cs} args = cutoff (cutoff2)
cutoff = global cutoff for Buckingham (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{buck/coul/msm} args = cutoff (cutoff2)
cutoff = global cutoff for Buckingham (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
[Examples:]
pair_style buck 2.5
pair_coeff * * 100.0 1.5 200.0
pair_coeff * * 100.0 1.5 200.0 3.0 :pre
pair_style buck/coul/cut 10.0
pair_style buck/coul/cut 10.0 8.0
pair_coeff * * 100.0 1.5 200.0
pair_coeff 1 1 100.0 1.5 200.0 9.0
pair_coeff 1 1 100.0 1.5 200.0 9.0 8.0 :pre
pair_style buck/coul/long 10.0
pair_style buck/coul/long/cs 10.0
pair_style buck/coul/long 10.0 8.0
pair_style buck/coul/long/cs 10.0 8.0
pair_coeff * * 100.0 1.5 200.0
pair_coeff 1 1 100.0 1.5 200.0 9.0 :pre
pair_style buck/coul/msm 10.0
pair_style buck/coul/msm 10.0 8.0
pair_coeff * * 100.0 1.5 200.0
pair_coeff 1 1 100.0 1.5 200.0 9.0 :pre
[Description:]
The {buck} style computes a Buckingham potential (exp/6 instead of
Lennard-Jones 12/6) given by
:c,image(Eqs/pair_buck.jpg)
where rho is an ionic-pair dependent length parameter, and Rc is the
cutoff on both terms.
The styles with {coul/cut} or {coul/long} or {coul/msm} add a
Coulombic term as described for the "lj/cut"_pair_lj.html pair styles.
For {buck/coul/long} and {buc/coul/msm}, an additional damping factor
is applied to the Coulombic term so it can be used in conjunction with
the "kspace_style"_kspace_style.html command and its {ewald} or {pppm}
or {msm} option. The Coulombic cutoff specified for this style means
that pairwise interactions within this distance are computed directly;
interactions outside that distance are computed in reciprocal space.
If one cutoff is specified for the {born/coul/cut} and
{born/coul/long} and {born/coul/msm} styles, it is used for both the
A,C and Coulombic terms. If two cutoffs are specified, the first is
used as the cutoff for the A,C terms, and the second is the cutoff for
the Coulombic term.
Style {buck/coul/long/cs} is identical to {buck/coul/long} except that
a term is added for the "core/shell model"_Section_howto.html#howto_25
to allow charges on core and shell particles to be separated by r =
0.0.
Note that these potentials are related to the "Born-Mayer-Huggins
potential"_pair_born.html.
NOTE: For all these pair styles, the terms with A and C are always
cutoff. The additional Coulombic term can be cutoff or long-range (no
cutoff) depending on whether the style name includes coul/cut or
coul/long or coul/msm. If you wish the C/r^6 term to be long-range
(no cutoff), then see the "pair_style
buck/long/coul/long"_pair_buck_long.html command.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
A (energy units)
rho (distance units)
C (energy-distance^6 units)
cutoff (distance units)
cutoff2 (distance units) :ul
The second coefficient, rho, must be greater than zero.
The coefficients A, rho, and C can be written as analytical expressions
of epsilon and sigma, in analogy to the Lennard-Jones potential
"(Khrapak)"_#Khrapak.
The latter 2 coefficients are optional. If not specified, the global
A,C and Coulombic cutoffs are used. If only one cutoff is specified,
it is used as the cutoff for both A,C and Coulombic interactions for
this type pair. If both coefficients are specified, they are used as
the A,C and Coulombic cutoffs for this type pair. You cannot specify
2 cutoffs for style {buck}, since it has no Coulombic terms.
For {buck/coul/long} only the LJ cutoff can be specified since a
Coulombic cutoff cannot be specified for an individual I,J type pair.
All type pairs use the same global Coulombic cutoff specified in the
pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
These styles support the "pair_modify"_pair_modify.html shift option
for the energy of the exp() and 1/r^6 portion of the pair interaction.
The {buck/coul/long} pair style supports the
"pair_modify"_pair_modify.html table option to tabulate the
short-range portion of the long-range Coulombic interaction.
These styles support the pair_modify tail option for adding long-range
tail corrections to energy and pressure for the A,C terms in the
pair interaction.
These styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
These styles can only be used via the {pair} keyword of the "run_style
respa"_run_style.html command. They do not support the {inner},
{middle}, {outer} keywords.
[Restrictions:]
The {buck/coul/long} style is part of the KSPACE package. The
{buck/coul/long/cs} style is part of the CORESHELL package. They are
only enabled if LAMMPS was built with that package. See the
"Making LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style born"_pair_born.html
[Default:] none
:link(Khrapak)
[(Khrapak)] Khrapak, Chaudhuri, and Morfill, J Chem Phys, 134, 054120 (2011).
diff --git a/doc/src/pair_buck_long.txt b/doc/src/pair_buck_long.txt
index ba18738e4..05e760e1b 100644
--- a/doc/src/pair_buck_long.txt
+++ b/doc/src/pair_buck_long.txt
@@ -1,171 +1,171 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style buck/long/coul/long command :h3
pair_style buck/long/coul/long/omp command :h3
[Syntax:]
pair_style buck/long/coul/long flag_buck flag_coul cutoff (cutoff2) :pre
flag_buck = {long} or {cut} :ulb,l
{long} = use Kspace long-range summation for the dispersion term 1/r^6
{cut} = use a cutoff :pre
flag_coul = {long} or {off} :l
{long} = use Kspace long-range summation for the Coulombic term 1/r
{off} = omit the Coulombic term :pre
cutoff = global cutoff for Buckingham (and Coulombic if only 1 cutoff) (distance units) :l
cutoff2 = global cutoff for Coulombic (optional) (distance units) :l
:ule
[Examples:]
pair_style buck/long/coul/long cut off 2.5
pair_style buck/long/coul/long cut long 2.5 4.0
pair_style buck/long/coul/long long long 4.0
pair_coeff * * 1 1
pair_coeff 1 1 1 3 4 :pre
[Description:]
The {buck/long/coul/long} style computes a Buckingham potential (exp/6
instead of Lennard-Jones 12/6) and Coulombic potential, given by
:c,image(Eqs/pair_buck.jpg)
:c,image(Eqs/pair_coulomb.jpg)
Rc is the cutoff. If one cutoff is specified in the pair_style
command, it is used for both the Buckingham and Coulombic terms. If
two cutoffs are specified, they are used as cutoffs for the Buckingham
and Coulombic terms respectively.
The purpose of this pair style is to capture long-range interactions
resulting from both attractive 1/r^6 Buckingham and Coulombic 1/r
interactions. This is done by use of the {flag_buck} and {flag_coul}
settings. The "Ismail"_#Ismail paper has more details on when it is
appropriate to include long-range 1/r^6 interactions, using this
potential.
If {flag_buck} is set to {long}, no cutoff is used on the Buckingham
1/r^6 dispersion term. The long-range portion can be calculated by
using the "kspace_style ewald/disp or pppm/disp"_kspace_style.html
commands. The specified Buckingham cutoff then determines which
portion of the Buckingham interactions are computed directly by the
pair potential versus which part is computed in reciprocal space via
the Kspace style. If {flag_buck} is set to {cut}, the Buckingham
interactions are simply cutoff, as with "pair_style
buck"_pair_buck.html.
If {flag_coul} is set to {long}, no cutoff is used on the Coulombic
interactions. The long-range portion can calculated by using any of
several "kspace_style"_kspace_style.html command options such as
{pppm} or {ewald}. Note that if {flag_buck} is also set to long, then
the {ewald/disp} or {pppm/disp} Kspace style needs to be used to
perform the long-range calculations for both the Buckingham and
Coulombic interactions. If {flag_coul} is set to {off}, Coulombic
interactions are not computed.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
A (energy units)
rho (distance units)
C (energy-distance^6 units)
cutoff (distance units)
cutoff2 (distance units) :ul
The second coefficient, rho, must be greater than zero.
The latter 2 coefficients are optional. If not specified, the global
Buckingham and Coulombic cutoffs specified in the pair_style command
are used. If only one cutoff is specified, it is used as the cutoff
for both Buckingham and Coulombic interactions for this type pair. If
both coefficients are specified, they are used as the Buckingham and
Coulombic cutoffs for this type pair. Note that if you are using
{flag_buck} set to {long}, you cannot specify a Buckingham cutoff for
an atom type pair, since only one global Buckingham cutoff is allowed.
Similarly, if you are using {flag_coul} set to {long}, you cannot
specify a Coulombic cutoff for an atom type pair, since only one
global Coulombic cutoff is allowed.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair styles does not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the exp() and 1/r^6 portion of the pair
interaction, assuming {flag_buck} is {cut}.
This pair style does not support the "pair_modify"_pair_modify.html
shift option for the energy of the Buckingham portion of the pair
interaction.
This pair style supports the "pair_modify"_pair_modify.html table and
table/disp options since they can tabulate the short-range portion of
the long-range Coulombic and dispersion interactions.
This pair style write its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style supports the use of the {inner}, {middle}, and {outer}
keywords of the "run_style respa"_run_style.html command, meaning the
pairwise forces can be partitioned by distance at different levels of
the rRESPA hierarchy. See the "run_style"_run_style.html command for
details.
:line
[Restrictions:]
This style is part of the KSPACE package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info. Note that
the KSPACE package is installed by default.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Ismail)
[(Ismail)] Ismail, Tsige, In 't Veld, Grest, Molecular Physics
(accepted) (2007).
diff --git a/doc/src/pair_charmm.txt b/doc/src/pair_charmm.txt
index 1e78607c0..ef4ef41c9 100644
--- a/doc/src/pair_charmm.txt
+++ b/doc/src/pair_charmm.txt
@@ -1,269 +1,269 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/charmm/coul/charmm command :h3
pair_style lj/charmm/coul/charmm/omp command :h3
pair_style lj/charmm/coul/charmm/implicit command :h3
pair_style lj/charmm/coul/charmm/implicit/omp command :h3
pair_style lj/charmm/coul/long command :h3
pair_style lj/charmm/coul/long/gpu command :h3
pair_style lj/charmm/coul/long/intel command :h3
pair_style lj/charmm/coul/long/opt command :h3
pair_style lj/charmm/coul/long/omp command :h3
pair_style lj/charmm/coul/msm command :h3
pair_style lj/charmm/coul/msm/omp command :h3
pair_style lj/charmmfsw/coul/charmmfsh command :h3
pair_style lj/charmmfsw/coul/long command :h3
[Syntax:]
pair_style style args :pre
style = {lj/charmm/coul/charmm} or {lj/charmm/coul/charmm/implicit} or {lj/charmm/coul/long} or {lj/charmm/coul/msm} or {lj/charmmfsw/coul/charmmfsh} or {lj/charmmfsw/coul/long}
args = list of arguments for a particular style :ul
{lj/charmm/coul/charmm} args = inner outer (inner2) (outer2)
inner, outer = global switching cutoffs for Lennard Jones (and Coulombic if only 2 args)
inner2, outer2 = global switching cutoffs for Coulombic (optional)
{lj/charmm/coul/charmm/implicit} args = inner outer (inner2) (outer2)
inner, outer = global switching cutoffs for LJ (and Coulombic if only 2 args)
inner2, outer2 = global switching cutoffs for Coulombic (optional)
{lj/charmm/coul/long} args = inner outer (cutoff)
inner, outer = global switching cutoffs for LJ (and Coulombic if only 2 args)
cutoff = global cutoff for Coulombic (optional, outer is Coulombic cutoff if only 2 args)
{lj/charmm/coul/msm} args = inner outer (cutoff)
inner, outer = global switching cutoffs for LJ (and Coulombic if only 2 args)
cutoff = global cutoff for Coulombic (optional, outer is Coulombic cutoff if only 2 args)
{lj/charmmfsw/coul/charmmfsh} args = inner outer (cutoff)
inner, outer = global cutoffs for LJ (and Coulombic if only 2 args)
cutoff = global cutoff for Coulombic (optional, outer is Coulombic cutoff if only 2 args)
{lj/charmmfsw/coul/long} args = inner outer (cutoff)
inner, outer = global cutoffs for LJ (and Coulombic if only 2 args)
cutoff = global cutoff for Coulombic (optional, outer is Coulombic cutoff if only 2 args) :pre
[Examples:]
pair_style lj/charmm/coul/charmm 8.0 10.0
pair_style lj/charmm/coul/charmm 8.0 10.0 7.0 9.0
pair_style lj/charmmfsw/coul/charmmfsh 10.0 12.0
pair_style lj/charmmfsw/coul/charmmfsh 10.0 12.0 9.0
pair_coeff * * 100.0 2.0
pair_coeff 1 1 100.0 2.0 150.0 3.5 :pre
pair_style lj/charmm/coul/charmm/implicit 8.0 10.0
pair_style lj/charmm/coul/charmm/implicit 8.0 10.0 7.0 9.0
pair_coeff * * 100.0 2.0
pair_coeff 1 1 100.0 2.0 150.0 3.5 :pre
pair_style lj/charmm/coul/long 8.0 10.0
pair_style lj/charmm/coul/long 8.0 10.0 9.0
pair_style lj/charmmfsw/coul/long 8.0 10.0
pair_style lj/charmmfsw/coul/long 8.0 10.0 9.0
pair_coeff * * 100.0 2.0
pair_coeff 1 1 100.0 2.0 150.0 3.5 :pre
pair_style lj/charmm/coul/msm 8.0 10.0
pair_style lj/charmm/coul/msm 8.0 10.0 9.0
pair_coeff * * 100.0 2.0
pair_coeff 1 1 100.0 2.0 150.0 3.5 :pre
[Description:]
These pair styles compute Lennard Jones (LJ) and Coulombic
interactions with additional switching or shifting functions that ramp
the energy and/or force smoothly to zero between an inner and outer
cutoff. They are implementations of the widely used CHARMM force
field used in the "CHARMM"_http://www.scripps.edu/brooks MD code (and
others). See "(MacKerell)"_#pair-MacKerell for a description of the
CHARMM force field.
The styles with {charmm} (not {charmmfsw} or {charmmfsh}) in their
name are the older, original LAMMPS implementations. They compute the
LJ and Coulombic interactions with an energy switching function (esw,
shown in the formula below as S(r)), which ramps the energy smoothly
to zero between the inner and outer cutoff. This can cause
irregularities in pair-wise forces (due to the discontinuous 2nd
derivative of energy at the boundaries of the switching region), which
in some cases can result in detectable artifacts in an MD simulation.
The newer styles with {charmmfsw} or {charmmfsh} in their name replace
the energy switching with force switching (fsw) and force shifting
(fsh) functions, for LJ and Coulombic interactions respectively.
These follow the formulas and description given in
"(Steinbach)"_#Steinbach and "(Brooks)"_#Brooks1 to minimize these
artifacts.
NOTE: The newer {charmmfsw} or {charmmfsh} styles were released in
March 2017. We recommend they be used instead of the older {charmm}
styles. This includes the newer "dihedral_style
charmmfsw"_dihedral_charmm.html command. Eventually code from the new
styles will propagate into the related pair styles (e.g. implicit,
accelerator, free energy variants).
NOTE: The newest CHARMM pair styles reset the Coulombic energy
conversion factor used internally in the code, from the LAMMPS value
to the CHARMM value, as if it were effectively a parameter of the
force field. This is because the CHARMM code uses a slightly
different value for the this conversion factor in "real
units"_units.html (Kcal/mole), namely CHARMM = 332.0716, LAMMPS =
332.06371. This is to enable more precise agreement by LAMMPS with
the CHARMM force field energies and forces, when using one of these
two CHARMM pair styles.
:c,image(Eqs/pair_charmm.jpg)
where S(r) is the energy switching function mentioned above for the
{charmm} styles. See the "(Steinbach)"_#Steinbach paper for the
functional forms of the force switching and force shifting functions
used in the {charmmfsw} and {charmmfsh} styles.
When using the {lj/charmm/coul/charmm styles}, both the LJ and
Coulombic terms require an inner and outer cutoff. They can be the
same for both formulas or different depending on whether 2 or 4
arguments are used in the pair_style command. For the
{lj/charmmfsw/coul/charmmfsh} style, the LJ term requires both an
inner and outer cutoff, while the Coulombic term requires only one
cutoff. If the Coulomb cutoff is not specified (2 instead of 3
arguments), the LJ outer cutoff is used for the Coulombic cutoff. In
all cases where an inner and outer cutoff are specified, the inner
cutoff distance must be less than the outer cutoff. It is typical to
make the difference between the inner and outer cutoffs about 2.0
Angstroms.
Style {lj/charmm/coul/charmm/implicit} computes the same formulas as
style {lj/charmm/coul/charmm} except that an additional 1/r term is
included in the Coulombic formula. The Coulombic energy thus varies
as 1/r^2. This is effectively a distance-dependent dielectric term
which is a simple model for an implicit solvent with additional
screening. It is designed for use in a simulation of an unsolvated
biomolecule (no explicit water molecules).
Styles {lj/charmm/coul/long} and {lj/charmm/coul/msm} compute the same
formulas as style {lj/charmm/coul/charmm} and style
{lj/charmmfsw/coul/long} computes the same formulas as style
{lj/charmmfsw/coul/charmmfsh}, except that an additional damping
factor is applied to the Coulombic term, so it can be used in
conjunction with the "kspace_style"_kspace_style.html command and its
{ewald} or {pppm} or {msm} option. Only one Coulombic cutoff is
specified for these styles; if only 2 arguments are used in the
pair_style command, then the outer LJ cutoff is used as the single
Coulombic cutoff. The Coulombic cutoff specified for these styles
means that pairwise interactions within this distance are computed
directly; interactions outside that distance are computed in
reciprocal space.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
epsilon_14 (energy units)
sigma_14 (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum at 2^(1/6)
sigma.
The latter 2 coefficients are optional. If they are specified, they
are used in the LJ formula between 2 atoms of these types which are
also first and fourth atoms in any dihedral. No cutoffs are specified
because the CHARMM force field does not allow varying cutoffs for
individual atom pairs; all pairs use the global cutoff(s) specified in
the pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon, sigma, epsilon_14,
and sigma_14 coefficients for all of the lj/charmm pair styles can be
mixed. The default mix value is {arithmetic} to coincide with the
usual settings for the CHARMM force field. See the "pair_modify"
command for details.
None of the {lj/charmm} or {lj/charmmfsw} pair styles support the
"pair_modify"_pair_modify.html shift option, since the Lennard-Jones
portion of the pair interaction is smoothed to 0.0 at the cutoff.
The {lj/charmm/coul/long} and {lj/charmmfsw/coul/long} styles support
the "pair_modify"_pair_modify.html table option since they can
tabulate the short-range portion of the long-range Coulombic
interaction.
None of the {lj/charmm} or {lj/charmmfsw} pair styles support the
"pair_modify"_pair_modify.html tail option for adding long-range tail
corrections to energy and pressure, since the Lennard-Jones portion of
the pair interaction is smoothed to 0.0 at the cutoff.
All of the {lj/charmm} and {lj/charmmfsw} pair styles write their
information to "binary restart files"_restart.html, so pair_style and
pair_coeff commands do not need to be specified in an input script
that reads a restart file.
The {lj/charmm/coul/long} and {lj/charmmfsw/coul/long} pair styles
support the use of the {inner}, {middle}, and {outer} keywords of the
"run_style respa"_run_style.html command, meaning the pairwise forces
can be partitioned by distance at different levels of the rRESPA
hierarchy. The other styles only support the {pair} keyword of
run_style respa. See the "run_style"_run_style.html command for
details.
:line
[Restrictions:]
All the styles with {coul/charmm} or {coul/charmmfsh} styles are part
of the MOLECULE package. All the styles with {coul/long} style are
part of the KSPACE package. They are only enabled if LAMMPS was built
with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info. Note that
the MOLECULE and KSPACE packages are installed by default.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Brooks1)
[(Brooks)] Brooks, et al, J Comput Chem, 30, 1545 (2009).
:link(pair-MacKerell)
[(MacKerell)] MacKerell, Bashford, Bellott, Dunbrack, Evanseck, Field,
Fischer, Gao, Guo, Ha, et al, J Phys Chem, 102, 3586 (1998).
:link(Steinbach)
[(Steinbach)] Steinbach, Brooks, J Comput Chem, 15, 667 (1994).
diff --git a/doc/src/pair_class2.txt b/doc/src/pair_class2.txt
index 23b90aae2..36fae5068 100644
--- a/doc/src/pair_class2.txt
+++ b/doc/src/pair_class2.txt
@@ -1,170 +1,170 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/class2 command :h3
pair_style lj/class2/gpu command :h3
pair_style lj/class2/kk command :h3
pair_style lj/class2/omp command :h3
pair_style lj/class2/coul/cut command :h3
pair_style lj/class2/coul/cut/kk command :h3
pair_style lj/class2/coul/cut/omp command :h3
pair_style lj/class2/coul/long command :h3
pair_style lj/class2/coul/long/gpu command :h3
pair_style lj/class2/coul/long/kk command :h3
pair_style lj/class2/coul/long/omp command :h3
[Syntax:]
pair_style style args :pre
style = {lj/class2} or {lj/class2/coul/cut} or {lj/class2/coul/long}
args = list of arguments for a particular style :ul
{lj/class2} args = cutoff
cutoff = global cutoff for class 2 interactions (distance units)
{lj/class2/coul/cut} args = cutoff (cutoff2)
cutoff = global cutoff for class 2 (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/class2/coul/long} args = cutoff (cutoff2)
cutoff = global cutoff for class 2 (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
[Examples:]
pair_style lj/class2 10.0
pair_coeff * * 100.0 2.5
pair_coeff 1 2* 100.0 2.5 9.0 :pre
pair_style lj/class2/coul/cut 10.0
pair_style lj/class2/coul/cut 10.0 8.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0
pair_coeff 1 1 100.0 3.5 9.0 9.0 :pre
pair_style lj/class2/coul/long 10.0
pair_style lj/class2/coul/long 10.0 8.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
[Description:]
The {lj/class2} styles compute a 6/9 Lennard-Jones potential given by
:c,image(Eqs/pair_class2.jpg)
Rc is the cutoff.
The {lj/class2/coul/cut} and {lj/class2/coul/long} styles add a
Coulombic term as described for the "lj/cut"_pair_lj.html pair styles.
See "(Sun)"_#pair-Sun for a description of the COMPASS class2 force field.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
cutoff1 (distance units)
cutoff2 (distance units) :ul
The latter 2 coefficients are optional. If not specified, the global
class 2 and Coulombic cutoffs are used. If only one cutoff is
specified, it is used as the cutoff for both class 2 and Coulombic
interactions for this type pair. If both coefficients are specified,
they are used as the class 2 and Coulombic cutoffs for this type pair.
You cannot specify 2 cutoffs for style {lj/class2}, since it has no
Coulombic terms.
For {lj/class2/coul/long} only the class 2 cutoff can be specified
since a Coulombic cutoff cannot be specified for an individual I,J
type pair. All type pairs use the same global Coulombic cutoff
specified in the pair_style command.
:line
If the pair_coeff command is not used to define coefficients for a
particular I != J type pair, the mixing rule for epsilon and sigma for
all class2 potentials is to use the {sixthpower} formulas documented
by the "pair_modify"_pair_modify.html command. The "pair_modify
mix"_pair_modify.html setting is thus ignored for class2 potentials
for epsilon and sigma. However it is still followed for mixing the
cutoff distance.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/class2 pair styles can be mixed.
Epsilon and sigma are always mixed with the value {sixthpower}. The
cutoff distance is mixed by whatever option is set by the pair_modify
command (default = geometric). See the "pair_modify" command for
details.
All of the lj/class2 pair styles support the
"pair_modify"_pair_modify.html shift option for the energy of the
Lennard-Jones portion of the pair interaction.
The {lj/class2/coul/long} pair style does not support the
"pair_modify"_pair_modify.html table option since a tabulation
capability has not yet been added to this potential.
All of the lj/class2 pair styles support the
"pair_modify"_pair_modify.html tail option for adding a long-range
tail correction to the energy and pressure of the Lennard-Jones
portion of the pair interaction.
All of the lj/class2 pair styles write their information to "binary
restart files"_restart.html, so pair_style and pair_coeff commands do
not need to be specified in an input script that reads a restart file.
All of the lj/class2 pair styles can only be used via the {pair}
keyword of the "run_style respa"_run_style.html command. They do not
support the {inner}, {middle}, {outer} keywords.
[Restrictions:]
These styles are part of the CLASS2 package. They are only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(pair-Sun)
[(Sun)] Sun, J Phys Chem B 102, 7338-7364 (1998).
diff --git a/doc/src/pair_colloid.txt b/doc/src/pair_colloid.txt
index a0df1d464..83b15b358 100644
--- a/doc/src/pair_colloid.txt
+++ b/doc/src/pair_colloid.txt
@@ -1,205 +1,205 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style colloid command :h3
pair_style colloid/gpu command :h3
pair_style colloid/omp command :h3
[Syntax:]
pair_style colloid cutoff :pre
cutoff = global cutoff for colloidal interactions (distance units) :ul
[Examples:]
pair_style colloid 10.0
pair_coeff * * 25 1.0 10.0 10.0
pair_coeff 1 1 144 1.0 0.0 0.0 3.0
pair_coeff 1 2 75.398 1.0 0.0 10.0 9.0
pair_coeff 2 2 39.478 1.0 10.0 10.0 25.0 :pre
[Description:]
Style {colloid} computes pairwise interactions between large colloidal
particles and small solvent particles using 3 formulas. A colloidal
particle has a size > sigma; a solvent particle is the usual
Lennard-Jones particle of size sigma.
The colloid-colloid interaction energy is given by
:c,image(Eqs/pair_colloid_cc.jpg)
where A_cc is the Hamaker constant, a1 and a2 are the radii of the two
colloidal particles, and Rc is the cutoff. This equation results from
describing each colloidal particle as an integrated collection of
Lennard-Jones particles of size sigma and is derived in
"(Everaers)"_#Everaers1.
The colloid-solvent interaction energy is given by
:c,image(Eqs/pair_colloid_cs.jpg)
where A_cs is the Hamaker constant, a is the radius of the colloidal
particle, and Rc is the cutoff. This formula is derived from the
colloid-colloid interaction, letting one of the particle sizes go to
zero.
The solvent-solvent interaction energy is given by the usual
Lennard-Jones formula
:c,image(Eqs/pair_colloid_ss.jpg)
with A_ss set appropriately, which results from letting both particle
sizes go to zero.
When used in combination with "pair_style
yukawa/colloid"_pair_colloid.html, the two terms become the so-called
DLVO potential, which combines electrostatic repulsion and van der
Waals attraction.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
A (energy units)
sigma (distance units)
d1 (distance units)
d2 (distance units)
cutoff (distance units) :ul
A is the Hamaker energy prefactor and should typically be set as
follows:
A_cc = colloid/colloid = 4 pi^2 = 39.5
A_cs = colloid/solvent = sqrt(A_cc*A_ss)
A_ss = solvent/solvent = 144 (assuming epsilon = 1, so that 144/36 = 4) :ul
Sigma is the size of the solvent particle or the constituent particles
integrated over in the colloidal particle and should typically be set
as follows:
Sigma_cc = colloid/colloid = 1.0
Sigma_cs = colloid/solvent = arithmetic mixing between colloid sigma and solvent sigma
Sigma_ss = solvent/solvent = 1.0 or whatever size the solvent particle is :ul
Thus typically Sigma_cs = 1.0, unless the solvent particle's size !=
1.0.
D1 and d2 are particle diameters, so that d1 = 2*a1 and d2 = 2*a2 in
the formulas above. Both d1 and d2 must be values >= 0. If d1 > 0
and d2 > 0, then the pair interacts via the colloid-colloid formula
above. If d1 = 0 and d2 = 0, then the pair interacts via the
solvent-solvent formula. I.e. a d value of 0 is a Lennard-Jones
particle of size sigma. If either d1 = 0 or d2 = 0 and the other is
larger, then the pair interacts via the colloid-solvent formula.
Note that the diameter of a particular particle type may appear in
multiple pair_coeff commands, as it interacts with other particle
types. You should insure the particle diameter is specified
consistently each time it appears.
The last coefficient is optional. If not specified, the global cutoff
specified in the pair_style command is used. However, you typically
want different cutoffs for interactions between different particle
sizes. E.g. if colloidal particles of diameter 10 are used with
solvent particles of diameter 1, then a solvent-solvent cutoff of 2.5
would correspond to a colloid-colloid cutoff of 25. A good
rule-of-thumb is to use a colloid-solvent cutoff that is half the big
diameter + 4 times the small diameter. I.e. 9 = 5 + 4 for the
colloid-solvent cutoff in this case.
NOTE: When using pair_style colloid for a mixture with 2 (or more)
widely different particles sizes (e.g. sigma=10 colloids in a
background sigma=1 LJ fluid), you will likely want to use these
commands for efficiency: "neighbor multi"_neighbor.html and
"comm_modify multi"_comm_modify.html.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the A, sigma, d1, and d2
coefficients and cutoff distance for this pair style can be mixed. A
is an energy value mixed like a LJ epsilon. D1 and d2 are distance
values and are mixed like sigma. The default mix value is
{geometric}. See the "pair_modify" command for details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This style is part of the COLLOID package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
Normally, this pair style should be used with finite-size particles
which have a diameter, e.g. see the "atom_style
sphere"_atom_style.html command. However, this is not a requirement,
since the only definition of particle size is via the pair_coeff
parameters for each type. In other words, the physical radius of the
particle is ignored. Thus you should insure that the d1,d2 parameters
you specify are consistent with the physical size of the particles of
that type.
Per-particle polydispersity is not yet supported by this pair style;
only per-type polydispersity is enabled via the pair_coeff parameters.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Everaers1)
[(Everaers)] Everaers, Ejtehadi, Phys Rev E, 67, 041710 (2003).
diff --git a/doc/src/pair_comb.txt b/doc/src/pair_comb.txt
index 3a2f380bf..f5461b1cb 100644
--- a/doc/src/pair_comb.txt
+++ b/doc/src/pair_comb.txt
@@ -1,192 +1,192 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style comb command :h3
pair_style comb/omp command :h3
pair_style comb3 command :h3
[Syntax:]
pair_style comb
pair_style comb3 keyword :pre
keyword = {polar}
{polar} value = {polar_on} or {polar_off} = whether or not to include atomic polarization :pre
:ule
[Examples:]
pair_style comb
pair_coeff * * ../potentials/ffield.comb Si
pair_coeff * * ../potentials/ffield.comb Hf Si O :pre
pair_style comb3 polar_off
pair_coeff * * ../potentials/ffield.comb3 O Cu N C O :pre
[Description:]
Style {comb} computes the second-generation variable charge COMB
(Charge-Optimized Many-Body) potential. Style {comb3} computes the
third-generation COMB potential. These COMB potentials are described
in "(COMB)"_#COMB and "(COMB3)"_#COMB3. Briefly, the total energy
{E<sub>T</sub>} of a system of atoms is given by
:c,image(Eqs/pair_comb1.jpg)
where {E<sub>i</sub><sup>self</sup>} is the self-energy of atom {i}
(including atomic ionization energies and electron affinities),
{E<sub>ij</sub><sup>short</sup>} is the bond-order potential between
atoms {i} and {j},
{E<sub>ij</sub><sup>Coul</sup>} is the Coulomb interactions,
{E<sup>polar</sup>} is the polarization term for organic systems
(style {comb3} only),
{E<sup>vdW</sup>} is the van der Waals energy (style {comb3} only),
{E<sup>barr</sup>} is a charge barrier function, and
{E<sup>corr</sup>} are angular correction terms.
The COMB potentials (styles {comb} and {comb3}) are variable charge
potentials. The equilibrium charge on each atom is calculated by the
electronegativity equalization (QEq) method. See "Rick"_#Rick2 for
further details. This is implemented by the "fix
qeq/comb"_fix_qeq_comb.html command, which should normally be
specified in the input script when running a model with the COMB
potential. The "fix qeq/comb"_fix_qeq_comb.html command has options
that determine how often charge equilibration is performed, its
convergence criterion, and which atoms are included in the
calculation.
Only a single pair_coeff command is used with the {comb} and {comb3}
styles which specifies the COMB potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the potential file in the pair_coeff
command, where N is the number of LAMMPS atom types.
For example, if your LAMMPS simulation of a Si/SiO<sub>2</sub>/
HfO<sub>2</sub> interface has 4 atom types, and you want the 1st and
last to be Si, the 2nd to be Hf, and the 3rd to be O, and you would
use the following pair_coeff command:
pair_coeff * * ../potentials/ffield.comb Si Hf O Si :pre
The first two arguments must be * * so as to span all LAMMPS atom
types. The first and last Si arguments map LAMMPS atom types 1 and 4
to the Si element in the {ffield.comb} file. The second Hf argument
maps LAMMPS atom type 2 to the Hf element, and the third O argument
maps LAMMPS atom type 3 to the O element in the potential file. If a
mapping value is specified as NULL, the mapping is not performed.
This can be used when a {comb} potential is used as part of the
{hybrid} pair style. The NULL values are placeholders for atom types
that will be used with other potentials.
For style {comb}, the provided potential file {ffield.comb} contains
all currently-available 2nd generation COMB parameterizations: for Si,
Cu, Hf, Ti, O, their oxides and Zr, Zn and U metals. For style
{comb3}, the potential file {ffield.comb3} contains all
currently-available 3rd generation COMB parameterizations: O, Cu, N, C,
H, Ti, Zn and Zr. The status of the optimization of the compounds, for
example Cu<sub>2</sub>O, TiN and hydrocarbons, are given in the
following table:
:c,image(Eqs/pair_comb2.jpg)
For style {comb3}, in addition to ffield.comb3, a special parameter
file, {lib.comb3}, that is exclusively used for C/O/H systems, will be
automatically loaded if carbon atom is detected in LAMMPS input
structure. This file must be in your working directory or in the
directory pointed to by the environment variable LAMMPS_POTENTIALS, as
described on the "pair_coeff"_pair_coeff.html command doc page.
Keyword {polar} indicates whether the force field includes
the atomic polarization. Since the equilibration of the polarization
has not yet been implemented, it can only set polar_off at present.
NOTE: You can not use potential file {ffield.comb} with style {comb3},
nor file {ffield.comb3} with style {comb}.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above from values in the potential file.
These pair styles does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
These pair styles do not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style, pair_coeff, and "fix
qeq/comb"_fix_qeq_comb.html commands in an input script that reads a
restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
These pair styles are part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
These pair styles requires the "newton"_newton.html setting to be "on"
for pair interactions.
The COMB potentials in the {ffield.comb} and {ffield.comb3} files provided
with LAMMPS (see the potentials directory) are parameterized for metal
"units"_units.html. You can use the COMB potential with any LAMMPS
units, but you would need to create your own COMB potential file with
coefficients listed in the appropriate units if your simulation
doesn't use "metal" units.
[Related commands:]
"pair_style"_pair_style.html, "pair_coeff"_pair_coeff.html,
"fix qeq/comb"_fix_qeq_comb.html
[Default:] none
:line
:link(COMB)
[(COMB)] T.-R. Shan, B. D. Devine, T. W. Kemper, S. B. Sinnott, and
S. R. Phillpot, Phys. Rev. B 81, 125328 (2010)
:link(COMB3)
[(COMB3)] T. Liang, T.-R. Shan, Y.-T. Cheng, B. D. Devine, M. Noordhoek,
Y. Li, Z. Lu, S. R. Phillpot, and S. B. Sinnott, Mat. Sci. & Eng: R 74,
255-279 (2013).
:link(Rick2)
[(Rick)] S. W. Rick, S. J. Stuart, B. J. Berne, J Chem Phys 101, 6141
(1994).
diff --git a/doc/src/pair_coul.txt b/doc/src/pair_coul.txt
index 4a601e90c..29e5beed3 100644
--- a/doc/src/pair_coul.txt
+++ b/doc/src/pair_coul.txt
@@ -1,342 +1,342 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style coul/cut command :h3
pair_style coul/cut/gpu command :h3
pair_style coul/cut/kk command :h3
pair_style coul/cut/omp command :h3
pair_style coul/debye command :h3
pair_style coul/debye/gpu command :h3
pair_style coul/debye/kk command :h3
pair_style coul/debye/omp command :h3
pair_style coul/dsf command :h3
pair_style coul/dsf/gpu command :h3
pair_style coul/dsf/kk command :h3
pair_style coul/dsf/omp command :h3
pair_style coul/long command :h3
pair_style coul/long/cs command :h3
pair_style coul/long/omp command :h3
pair_style coul/long/gpu command :h3
pair_style coul/long/kk command :h3
pair_style coul/msm command :h3
pair_style coul/msm/omp command :h3
pair_style coul/streitz command :h3
pair_style coul/wolf command :h3
pair_style coul/wolf/kk command :h3
pair_style coul/wolf/omp command :h3
pair_style tip4p/cut command :h3
pair_style tip4p/long command :h3
pair_style tip4p/cut/omp command :h3
pair_style tip4p/long/omp command :h3
[Syntax:]
pair_style coul/cut cutoff
pair_style coul/debye kappa cutoff
pair_style coul/dsf alpha cutoff
pair_style coul/long cutoff
pair_style coul/long/cs cutoff
pair_style coul/long/gpu cutoff
pair_style coul/wolf alpha cutoff
pair_style coul/streitz cutoff keyword alpha
pair_style tip4p/cut otype htype btype atype qdist cutoff
pair_style tip4p/long otype htype btype atype qdist cutoff :pre
cutoff = global cutoff for Coulombic interactions
kappa = Debye length (inverse distance units)
alpha = damping parameter (inverse distance units) :ul
[Examples:]
pair_style coul/cut 2.5
pair_coeff * *
pair_coeff 2 2 3.5 :pre
pair_style coul/debye 1.4 3.0
pair_coeff * *
pair_coeff 2 2 3.5 :pre
pair_style coul/dsf 0.05 10.0
pair_coeff * * :pre
pair_style coul/long 10.0
pair_style coul/long/cs 10.0
pair_coeff * * :pre
pair_style coul/msm 10.0
pair_coeff * * :pre
pair_style coul/wolf 0.2 9.0
pair_coeff * * :pre
pair_style coul/streitz 12.0 ewald
pair_style coul/streitz 12.0 wolf 0.30
pair_coeff * * AlO.streitz Al O :pre
pair_style tip4p/cut 1 2 7 8 0.15 12.0
pair_coeff * * :pre
pair_style tip4p/long 1 2 7 8 0.15 10.0
pair_coeff * * :pre
[Description:]
The {coul/cut} style computes the standard Coulombic interaction
potential given by
:c,image(Eqs/pair_coulomb.jpg)
where C is an energy-conversion constant, Qi and Qj are the charges on
the 2 atoms, and epsilon is the dielectric constant which can be set
by the "dielectric"_dielectric.html command. The cutoff Rc truncates
the interaction distance.
:line
Style {coul/debye} adds an additional exp() damping factor to the
Coulombic term, given by
:c,image(Eqs/pair_debye.jpg)
where kappa is the Debye length. This potential is another way to
mimic the screening effect of a polar solvent.
:line
Style {coul/dsf} computes Coulombic interactions via the damped
shifted force model described in "Fennell"_#Fennell1, given by:
:c,image(Eqs/pair_coul_dsf.jpg)
where {alpha} is the damping parameter and erfc() is the
complementary error-function. The potential corrects issues in the
Wolf model (described below) to provide consistent forces and energies
(the Wolf potential is not differentiable at the cutoff) and smooth
decay to zero.
:line
Style {coul/wolf} computes Coulombic interactions via the Wolf
summation method, described in "Wolf"_#Wolf1, given by:
:c,image(Eqs/pair_coul_wolf.jpg)
where {alpha} is the damping parameter, and erc() and erfc() are
error-function and complementary error-function terms. This potential
is essentially a short-range, spherically-truncated,
charge-neutralized, shifted, pairwise {1/r} summation. With a
manipulation of adding and subtracting a self term (for i = j) to the
first and second term on the right-hand-side, respectively, and a
small enough {alpha} damping parameter, the second term shrinks and
the potential becomes a rapidly-converging real-space summation. With
a long enough cutoff and small enough alpha parameter, the energy and
forces calculated by the Wolf summation method approach those of the
Ewald sum. So it is a means of getting effective long-range
interactions with a short-range potential.
:line
Style {coul/streitz} is the Coulomb pair interaction defined as part
of the Streitz-Mintmire potential, as described in "this
paper"_#Streitz2, in which charge distribution about an atom is modeled
as a Slater 1{s} orbital. More details can be found in the referenced
paper. To fully reproduce the published Streitz-Mintmire potential,
which is a variable charge potential, style {coul/streitz} must be
used with "pair_style eam/alloy"_pair_eam.html (or some other
short-range potential that has been parameterized appropriately) via
the "pair_style hybrid/overlay"_pair_hybrid.html command. Likewise,
charge equilibration must be performed via the "fix
qeq/slater"_fix_qeq.html command. For example:
pair_style hybrid/overlay coul/streitz 12.0 wolf 0.31 eam/alloy
pair_coeff * * coul/streitz AlO.streitz Al O
pair_coeff * * eam/alloy AlO.eam.alloy Al O
fix 1 all qeq/slater 1 12.0 1.0e-6 100 coul/streitz :pre
The keyword {wolf} in the coul/streitz command denotes computing
Coulombic interactions via Wolf summation. An additional damping
parameter is required for the Wolf summation, as described for the
coul/wolf potential above. Alternatively, Coulombic interactions can
be computed via an Ewald summation. For example:
pair_style hybrid/overlay coul/streitz 12.0 ewald eam/alloy
kspace_style ewald 1e-6 :pre
Keyword {ewald} does not need a damping parameter, but a
"kspace_style"_kspace_style.html must be defined, which can be style
{ewald} or {pppm}. The Ewald method was used in Streitz and
Mintmire's original paper, but a Wolf summation offers a speed-up in
some cases.
For the fix qeq/slater command, the {qfile} can be a filename that
contains QEq parameters as discussed on the "fix qeq"_fix_qeq.html
command doc page. Alternatively {qfile} can be replaced by
"coul/streitz", in which case the fix will extract QEq parameters from
the coul/streitz pair style itself.
See the examples/strietz directory for an example input script that
uses the Streitz-Mintmire potential. The potentials directory has the
AlO.eam.alloy and AlO.streitz potential files used by the example.
Note that the Streiz-Mintmire potential is generally used for oxides,
but there is no conceptual problem with extending it to nitrides and
carbides (such as SiC, TiN). Pair coul/strietz used by itself or with
any other pair style such as EAM, MEAM, Tersoff, or LJ in
hybrid/overlay mode. To do this, you would need to provide a
Streitz-Mintmire parameterization for the material being modeled.
:line
Styles {coul/long} and {coul/msm} compute the same Coulombic
interactions as style {coul/cut} except that an additional damping
factor is applied so it can be used in conjunction with the
"kspace_style"_kspace_style.html command and its {ewald} or {pppm}
option. The Coulombic cutoff specified for this style means that
pairwise interactions within this distance are computed directly;
interactions outside that distance are computed in reciprocal space.
Style {coul/long/cs} is identical to {coul/long} except that a term is
added for the "core/shell model"_Section_howto.html#howto_25 to allow
charges on core and shell particles to be separated by r = 0.0.
Styles {tip4p/cut} and {tip4p/long} implement the coulomb part of
the TIP4P water model of "(Jorgensen)"_#Jorgensen3, which introduces
a massless site located a short distance away from the oxygen atom
along the bisector of the HOH angle. The atomic types of the oxygen and
hydrogen atoms, the bond and angle types for OH and HOH interactions,
and the distance to the massless charge site are specified as
pair_style arguments. Style {tip4p/cut} uses a global cutoff for
Coulomb interactions; style {tip4p/long} is for use with a long-range
Coulombic solver (Ewald or PPPM).
NOTE: For each TIP4P water molecule in your system, the atom IDs for
the O and 2 H atoms must be consecutive, with the O atom first. This
is to enable LAMMPS to "find" the 2 H atoms associated with each O
atom. For example, if the atom ID of an O atom in a TIP4P water
molecule is 500, then its 2 H atoms must have IDs 501 and 502.
See the "howto section"_Section_howto.html#howto_8 for more
information on how to use the TIP4P pair styles and lists of
parameters to set. Note that the neighbor list cutoff for Coulomb
interactions is effectively extended by a distance 2*qdist when using
the TIP4P pair style, to account for the offset distance of the
fictitious charges on O atoms in water molecules. Thus it is
typically best in an efficiency sense to use a LJ cutoff >= Coulomb
cutoff + 2*qdist, to shrink the size of the neighbor list. This leads
to slightly larger cost for the long-range calculation, so you can
test the trade-off for your model.
:line
Note that these potentials are designed to be combined with other pair
potentials via the "pair_style hybrid/overlay"_pair_hybrid.html
command. This is because they have no repulsive core. Hence if they
are used by themselves, there will be no repulsion to keep two
oppositely charged particles from moving arbitrarily close to each
other.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
cutoff (distance units) :ul
For {coul/cut} and {coul/debye}, the cutoff coefficient is optional.
If it is not used (as in some of the examples above), the default
global value specified in the pair_style command is used.
For {coul/long} and {coul/msm} no cutoff can be specified for an
individual I,J type pair via the pair_coeff command. All type pairs
use the same global Coulombic cutoff specified in the pair_style
command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the cutoff distance for the
{coul/cut} style can be mixed. The default mix value is {geometric}.
See the "pair_modify" command for details.
The "pair_modify"_pair_modify.html shift option is not relevant
for these pair styles.
The {coul/long} style supports the "pair_modify"_pair_modify.html
table option for tabulation of the short-range portion of the
long-range Coulombic interaction.
These pair styles do not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
These pair styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
The {coul/long}, {coul/msm} and {tip4p/long} styles are part of the
KSPACE package. The {coul/long/cs} style is part of the CORESHELL
package. They are only enabled if LAMMPS was built with that package.
See the "Making LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style,
hybrid/overlay"_pair_hybrid.html, "kspace_style"_kspace_style.html
[Default:] none
:line
:link(Wolf1)
[(Wolf)] D. Wolf, P. Keblinski, S. R. Phillpot, J. Eggebrecht, J Chem
Phys, 110, 8254 (1999).
:link(Fennell1)
[(Fennell)] C. J. Fennell, J. D. Gezelter, J Chem Phys, 124,
234104 (2006).
:link(Streitz2)
[(Streitz)] F. H. Streitz, J. W. Mintmire, Phys Rev B, 50, 11996-12003
(1994).
:link(Jorgensen3)
[(Jorgensen)] Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem
Phys, 79, 926 (1983).
diff --git a/doc/src/pair_dipole.txt b/doc/src/pair_dipole.txt
index 985581cac..2516e5eae 100644
--- a/doc/src/pair_dipole.txt
+++ b/doc/src/pair_dipole.txt
@@ -1,275 +1,275 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/cut/dipole/cut command :h3
pair_style lj/cut/dipole/cut/gpu command :h3
pair_style lj/cut/dipole/cut/omp command :h3
pair_style lj/sf/dipole/sf command :h3
pair_style lj/sf/dipole/sf/gpu command :h3
pair_style lj/sf/dipole/sf/omp command :h3
pair_style lj/cut/dipole/long command :h3
pair_style lj/long/dipole/long command :h3
[Syntax:]
pair_style lj/cut/dipole/cut cutoff (cutoff2)
pair_style lj/sf/dipole/sf cutoff (cutoff2)
pair_style lj/cut/dipole/long cutoff (cutoff2)
pair_style lj/long/dipole/long flag_lj flag_coul cutoff (cutoff2) :pre
cutoff = global cutoff LJ (and Coulombic if only 1 arg) (distance units) :ulb,l
cutoff2 = global cutoff for Coulombic and dipole (optional) (distance units) :l
flag_lj = {long} or {cut} or {off} :l
{long} = use long-range damping on dispersion 1/r^6 term
{cut} = use a cutoff on dispersion 1/r^6 term
{off} = omit disperion 1/r^6 term entirely :pre
flag_coul = {long} or {off} :l
{long} = use long-range damping on Coulombic 1/r and point-dipole terms
{off} = omit Coulombic and point-dipole terms entirely :pre
:ule
[Examples:]
pair_style lj/cut/dipole/cut 10.0
pair_coeff * * 1.0 1.0
pair_coeff 2 3 1.0 1.0 2.5 4.0 :pre
pair_style lj/sf/dipole/sf 9.0
pair_coeff * * 1.0 1.0
pair_coeff 2 3 1.0 1.0 2.5 4.0 scale 0.5
pair_coeff 2 3 1.0 1.0 2.5 4.0 :pre
pair_style lj/cut/dipole/long 10.0
pair_coeff * * 1.0 1.0
pair_coeff 2 3 1.0 1.0 2.5 4.0 :pre
pair_style lj/long/dipole/long long long 3.5 10.0
pair_coeff * * 1.0 1.0
pair_coeff 2 3 1.0 1.0 2.5 4.0 :pre
[Description:]
Style {lj/cut/dipole/cut} computes interactions between pairs of particles
that each have a charge and/or a point dipole moment. In addition to
the usual Lennard-Jones interaction between the particles (Elj) the
charge-charge (Eqq), charge-dipole (Eqp), and dipole-dipole (Epp)
interactions are computed by these formulas for the energy (E), force
(F), and torque (T) between particles I and J.
:c,image(Eqs/pair_dipole.jpg)
where qi and qj are the charges on the two particles, pi and pj are
the dipole moment vectors of the two particles, r is their separation
distance, and the vector r = Ri - Rj is the separation vector between
the two particles. Note that Eqq and Fqq are simply Coulombic energy
and force, Fij = -Fji as symmetric forces, and Tij != -Tji since the
torques do not act symmetrically. These formulas are discussed in
"(Allen)"_#Allen2 and in "(Toukmaji)"_#Toukmaji2.
Also note, that in the code, all of these terms (except Elj) have a
C/epsilon prefactor, the same as the Coulombic term in the LJ +
Coulombic pair styles discussed "here"_pair_lj.html. C is an
energy-conversion constant and epsilon is the dielectric constant
which can be set by the "dielectric"_dielectric.html command. The
same is true of the equations that follow for other dipole pair
styles.
Style {lj/sf/dipole/sf} computes "shifted-force" interactions between
pairs of particles that each have a charge and/or a point dipole
moment. In general, a shifted-force potential is a (sligthly) modified
potential containing extra terms that make both the energy and its
derivative go to zero at the cutoff distance; this removes
(cutoff-related) problems in energy conservation and any numerical
instability in the equations of motion "(Allen)"_#Allen2. Shifted-force
interactions for the Lennard-Jones (E_LJ), charge-charge (Eqq),
charge-dipole (Eqp), dipole-charge (Epq) and dipole-dipole (Epp)
potentials are computed by these formulas for the energy (E), force
(F), and torque (T) between particles I and J:
:c,image(Eqs/pair_dipole_sf.jpg)
:c,image(Eqs/pair_dipole_sf2.jpg)
where epsilon and sigma are the standard LJ parameters, r_c is the
cutoff, qi and qj are the charges on the two particles, pi and pj are
the dipole moment vectors of the two particles, r is their separation
distance, and the vector r = Ri - Rj is the separation vector between
the two particles. Note that Eqq and Fqq are simply Coulombic energy
and force, Fij = -Fji as symmetric forces, and Tij != -Tji since the
torques do not act symmetrically. The shifted-force formula for the
Lennard-Jones potential is reported in "(Stoddard)"_#Stoddard. The
original (unshifted) formulas for the electrostatic potentials, forces
and torques can be found in "(Price)"_#Price2. The shifted-force
electrostatic potentials have been obtained by applying equation 5.13
of "(Allen)"_#Allen2. The formulas for the corresponding forces and
torques have been obtained by applying the 'chain rule' as in appendix
C.3 of "(Allen)"_#Allen2.
If one cutoff is specified in the pair_style command, it is used for
both the LJ and Coulombic (q,p) terms. If two cutoffs are specified,
they are used as cutoffs for the LJ and Coulombic (q,p) terms
respectively. This pair style also supports an optional {scale} keyword
as part of a pair_coeff statement, where the interactions can be
scaled according to this factor. This scale factor is also made available
for use with fix adapt.
Style {lj/cut/dipole/long} computes long-range point-dipole
interactions as discussed in "(Toukmaji)"_#Toukmaji2. Dipole-dipole,
dipole-charge, and charge-charge interactions are all supported, along
with the standard 12/6 Lennard-Jones interactions, which are computed
with a cutoff. A "kspace_style"_kspace_style.html must be defined to
use this pair style. Currently, only "kspace_style
ewald/disp"_kspace_style.html support long-range point-dipole
interactions.
Style {lj/long/dipole/long} also computes point-dipole interactions as
discussed in "(Toukmaji)"_#Toukmaji2. Long-range dipole-dipole,
dipole-charge, and charge-charge interactions are all supported, along
with the standard 12/6 Lennard-Jones interactions. LJ interactions
can be cutoff or long-ranged.
For style {lj/long/dipole/long}, if {flag_lj} is set to {long}, no
cutoff is used on the LJ 1/r^6 dispersion term. The long-range
portion is calculated by using the "kspace_style
ewald_disp"_kspace_style.html command. The specified LJ cutoff then
determines which portion of the LJ interactions are computed directly
by the pair potential versus which part is computed in reciprocal
space via the Kspace style. If {flag_lj} is set to {cut}, the LJ
interactions are simply cutoff, as with "pair_style
lj/cut"_pair_lj.html. If {flag_lj} is set to {off}, LJ interactions
are not computed at all.
If {flag_coul} is set to {long}, no cutoff is used on the Coulombic or
dipole interactions. The long-range portion is calculated by using
{ewald_disp} of the "kspace_style"_kspace_style.html command. If
{flag_coul} is set to {off}, Coulombic and dipole interactions are not
computed at all.
Atoms with dipole moments should be integrated using the "fix
nve/sphere update dipole"_fix_nve_sphere.html or the "fix
nvt/sphere update dipole"_fix_nvt_sphere.html command to rotate the
dipole moments. The {omega} option on the "fix
langevin"_fix_langevin.html command can be used to thermostat the
rotational motion. The "compute temp/sphere"_compute_temp_sphere.html
command can be used to monitor the temperature, since it includes
rotational degrees of freedom. The "atom_style
hybrid dipole sphere"_atom_style.html command should be used since
it defines the point dipoles and their rotational state.
The magnitude and orientation of the dipole moment for each particle
can be defined by the "set"_set.html command or in the "Atoms" section
of the data file read in by the "read_data"_read_data.html command.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
cutoff1 (distance units)
cutoff2 (distance units) :ul
The latter 2 coefficients are optional. If not specified, the global
LJ and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both LJ
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the LJ and Coulombic cutoffs for this
type pair.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distances for this pair style can be mixed. The default
mix value is {geometric}. See the "pair_modify" command for details.
For atom type pairs I,J and I != J, the A, sigma, d1, and d2
coefficients and cutoff distance for this pair style can be mixed. A
is an energy value mixed like a LJ epsilon. D1 and d2 are distance
values and are mixed like sigma. The default mix value is
{geometric}. See the "pair_modify" command for details.
This pair style does not support the "pair_modify"_pair_modify.html
shift option for the energy of the Lennard-Jones portion of the pair
interaction; such energy goes to zero at the cutoff by construction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
[Restrictions:]
The {lj/cut/dipole/cut}, {lj/cut/dipole/long}, and
{lj/long/dipole/long} styles are part of the DIPOLE package. They are
only enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The {lj/sf/dipole/sf} style is part of the USER-MISC package. It is
only enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
Using dipole pair styles with {electron} "units"_units.html is not
currently supported.
[Related commands:]
"pair_coeff"_pair_coeff.html, "set"_set.html, "read_data"_read_data.html,
"fix nve/sphere"_fix_nve_sphere.html, "fix nvt/sphere"_fix_nvt_sphere.html
[Default:] none
:line
:link(Allen2)
[(Allen)] Allen and Tildesley, Computer Simulation of Liquids,
Clarendon Press, Oxford, 1987.
:link(Toukmaji2)
[(Toukmaji)] Toukmaji, Sagui, Board, and Darden, J Chem Phys, 113,
10913 (2000).
:link(Stoddard)
[(Stoddard)] Stoddard and Ford, Phys Rev A, 8, 1504 (1973).
:link(Price2)
[(Price)] Price, Stone and Alderton, Mol Phys, 52, 987 (1984).
diff --git a/doc/src/pair_dpd.txt b/doc/src/pair_dpd.txt
index 62a5faffe..9dd204ad2 100644
--- a/doc/src/pair_dpd.txt
+++ b/doc/src/pair_dpd.txt
@@ -1,209 +1,209 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style dpd command :h3
pair_style dpd/gpu command :h3
pair_style dpd/omp command :h3
pair_style dpd/tstat command :h3
pair_style dpd/tstat/gpu command :h3
pair_style dpd/tstat/omp command :h3
[Syntax:]
pair_style dpd T cutoff seed
pair_style dpd/tstat Tstart Tstop cutoff seed :pre
T = temperature (temperature units)
Tstart,Tstop = desired temperature at start/end of run (temperature units)
cutoff = global cutoff for DPD interactions (distance units)
seed = random # seed (positive integer) :ul
[Examples:]
pair_style dpd 1.0 2.5 34387
pair_coeff * * 3.0 1.0
pair_coeff 1 1 3.0 1.0 1.0 :pre
pair_style dpd/tstat 1.0 1.0 2.5 34387
pair_coeff * * 1.0
pair_coeff 1 1 1.0 1.0 :pre
[Description:]
Style {dpd} computes a force field for dissipative particle dynamics
(DPD) following the exposition in "(Groot)"_#Groot.
Style {dpd/tstat} invokes a DPD thermostat on pairwise interactions,
which is equivalent to the non-conservative portion of the DPD force
field. This pair-wise thermostat can be used in conjunction with any
"pair style"_pair_style.html, and in leiu of per-particle thermostats
like "fix langevin"_fix_langevin.html or ensemble thermostats like
Nose Hoover as implemented by "fix nvt"_fix_nh.html. To use
{dpd/tstat} as a thermostat for another pair style, use the "pair_style
hybrid/overlay"_pair_hybrid.html command to compute both the desired
pair interaction and the thermostat for each pair of particles.
For style {dpd}, the force on atom I due to atom J is given as a sum
of 3 terms
:c,image(Eqs/pair_dpd.jpg)
where Fc is a conservative force, Fd is a dissipative force, and Fr is
a random force. Rij is a unit vector in the direction Ri - Rj, Vij is
the vector difference in velocities of the two atoms = Vi - Vj, alpha
is a Gaussian random number with zero mean and unit variance, dt is
the timestep size, and w(r) is a weighting factor that varies between
0 and 1. Rc is the cutoff. Sigma is set equal to sqrt(2 Kb T gamma),
where Kb is the Boltzmann constant and T is the temperature parameter
in the pair_style command.
For style {dpd/tstat}, the force on atom I due to atom J is the same
as the above equation, except that the conservative Fc term is
dropped. Also, during the run, T is set each timestep to a ramped
value from Tstart to Tstop.
For style {dpd}, the pairwise energy associated with style {dpd} is
only due to the conservative force term Fc, and is shifted to be zero
at the cutoff distance Rc. The pairwise virial is calculated using
all 3 terms. For style {dpd/tstat} there is no pairwise energy, but
the last two terms of the formula make a contribution to the virial.
For style {dpd}, the following coefficients must be defined for each
pair of atoms types via the "pair_coeff"_pair_coeff.html command as in
the examples above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
A (force units)
gamma (force/velocity units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global DPD
cutoff is used. Note that sigma is set equal to sqrt(2 T gamma),
where T is the temperature set by the "pair_style"_pair_style.html
command so it does not need to be specified.
For style {dpd/tstat}, the coefficients defined for each pair of
atoms types via the "pair_coeff"_pair_coeff.html command is the same,
except that A is not included.
The GPU-accelerated versions of these styles are implemented based on
the work of "(Afshar)"_#Afshar and "(Phillips)"_#Phillips.
NOTE: If you are modeling DPD polymer chains, you may want to use the
"pair_style srp"_pair_srp.html command in conjuction with these pair
styles. It is a soft segmental repulsive potential (SRP) that can
prevent DPD polymer chains from crossing each other.
NOTE: The virial calculation for pressure when using this pair style
includes all the components of force listed above, including the
random force.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
These pair styles do not support the "pair_modify"_pair_modify.html
shift option for the energy of the pair interaction. Note that as
discussed above, the energy due to the conservative Fc term is already
shifted to be 0.0 at the cutoff distance Rc.
The "pair_modify"_pair_modify.html table option is not relevant
for these pair styles.
These pair style do not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
These pair styles writes their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file. Note
that the user-specified random number seed is stored in the restart
file, so when a simulation is restarted, each processor will
re-initialize its random number generator the same way it did
initially. This means the random forces will be random, but will not
be the same as they would have been if the original simulation had
continued past the restart time.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
The {dpd/tstat} style can ramp its target temperature over multiple
runs, using the {start} and {stop} keywords of the "run"_run.html
command. See the "run"_run.html command for details of how to do
this.
:line
[Restrictions:]
The default frequency for rebuilding neighbor lists is every 10 steps
(see the "neigh_modify"_neigh_modify.html command). This may be too
infrequent for style {dpd} simulations since particles move rapidly
and can overlap by large amounts. If this setting yields a non-zero
number of "dangerous" reneighborings (printed at the end of a
simulation), you should experiment with forcing reneighboring more
often and see if system energies/trajectories change.
These pair styles requires you to use the "comm_modify vel
yes"_comm_modify.html command so that velocites are stored by ghost
atoms.
These pair styles will not restart exactly when using the
"read_restart"_read_restart.html command, though they should provide
statistically similar results. This is because the forces they
compute depend on atom velocities. See the
"read_restart"_read_restart.html command for more details.
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix nvt"_fix_nh.html, "fix
langevin"_fix_langevin.html, "pair_style srp"_pair_srp.html
[Default:] none
:line
:link(Groot)
[(Groot)] Groot and Warren, J Chem Phys, 107, 4423-35 (1997).
:link(Afshar)
[(Afshar)] Afshar, F. Schmid, A. Pishevar, S. Worley, Comput Phys
Comm, 184, 1119-1128 (2013).
:link(Phillips)
[(Phillips)] C. L. Phillips, J. A. Anderson, S. C. Glotzer, Comput
Phys Comm, 230, 7191-7201 (2011).
diff --git a/doc/src/pair_eam.txt b/doc/src/pair_eam.txt
index 4d3c2b2de..ce8495aff 100644
--- a/doc/src/pair_eam.txt
+++ b/doc/src/pair_eam.txt
@@ -1,448 +1,448 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style eam command :h3
pair_style eam/gpu command :h3
pair_style eam/intel command :h3
pair_style eam/kk command :h3
pair_style eam/omp command :h3
pair_style eam/opt command :h3
pair_style eam/alloy command :h3
pair_style eam/alloy/gpu command :h3
pair_style eam/alloy/kk command :h3
pair_style eam/alloy/omp command :h3
pair_style eam/alloy/opt command :h3
pair_style eam/cd command :h3
pair_style eam/cd/omp command :h3
pair_style eam/fs command :h3
pair_style eam/fs/gpu command :h3
pair_style eam/fs/kk command :h3
pair_style eam/fs/omp command :h3
pair_style eam/fs/opt command :h3
[Syntax:]
pair_style style :pre
style = {eam} or {eam/alloy} or {eam/cd} or {eam/fs} :ul
[Examples:]
pair_style eam
pair_coeff * * cuu3
pair_coeff 1*3 1*3 niu3.eam :pre
pair_style eam/alloy
pair_coeff * * ../potentials/NiAlH_jea.eam.alloy Ni Al Ni Ni :pre
pair_style eam/cd
pair_coeff * * ../potentials/FeCr.cdeam Fe Cr :pre
pair_style eam/fs
pair_coeff * * NiAlH_jea.eam.fs Ni Al Ni Ni :pre
[Description:]
Style {eam} computes pairwise interactions for metals and metal alloys
using embedded-atom method (EAM) potentials "(Daw)"_#Daw. The total
energy Ei of an atom I is given by
:c,image(Eqs/pair_eam.jpg)
where F is the embedding energy which is a function of the atomic
electron density rho, phi is a pair potential interaction, and alpha
and beta are the element types of atoms I and J. The multi-body
nature of the EAM potential is a result of the embedding energy term.
Both summations in the formula are over all neighbors J of atom I
within the cutoff distance.
The cutoff distance and the tabulated values of the functionals F,
rho, and phi are listed in one or more files which are specified by
the "pair_coeff"_pair_coeff.html command. These are ASCII text files
in a DYNAMO-style format which is described below. DYNAMO was the
original serial EAM MD code, written by the EAM originators. Several
DYNAMO potential files for different metals are included in the
"potentials" directory of the LAMMPS distribution. All of these files
are parameterized in terms of LAMMPS "metal units"_units.html.
NOTE: The {eam} style reads single-element EAM potentials in the
DYNAMO {funcfl} format. Either single element or alloy systems can be
modeled using multiple {funcfl} files and style {eam}. For the alloy
case LAMMPS mixes the single-element potentials to produce alloy
potentials, the same way that DYNAMO does. Alternatively, a single
DYNAMO {setfl} file or Finnis/Sinclair EAM file can be used by LAMMPS
to model alloy systems by invoking the {eam/alloy} or {eam/cd} or
{eam/fs} styles as described below. These files require no mixing
since they specify alloy interactions explicitly.
NOTE: Note that unlike for other potentials, cutoffs for EAM
potentials are not set in the pair_style or pair_coeff command; they
are specified in the EAM potential files themselves. Likewise, the
EAM potential files list atomic masses; thus you do not need to use
the "mass"_mass.html command to specify them.
There are several WWW sites that distribute and document EAM
potentials stored in DYNAMO or other formats:
http://www.ctcms.nist.gov/potentials
http://cst-www.nrl.navy.mil/ccm6/ap
http://enpub.fulton.asu.edu/cms/potentials/main/main.htm :pre
These potentials should be usable with LAMMPS, though the alternate
formats would need to be converted to the DYNAMO format used by LAMMPS
and described on this page. The NIST site is maintained by Chandler
Becker (cbecker at nist.gov) who is good resource for info on
interatomic potentials and file formats.
:line
For style {eam}, potential values are read from a file that is in the
DYNAMO single-element {funcfl} format. If the DYNAMO file was created
by a Fortran program, it cannot have "D" values in it for exponents.
C only recognizes "e" or "E" for scientific notation.
Note that unlike for other potentials, cutoffs for EAM potentials are
not set in the pair_style or pair_coeff command; they are specified in
the EAM potential files themselves.
For style {eam} a potential file must be assigned to each I,I pair of
atom types by using one or more pair_coeff commands, each with a
single argument:
filename :ul
Thus the following command
pair_coeff *2 1*2 cuu3.eam :pre
will read the cuu3 potential file and use the tabulated Cu values for
F, phi, rho that it contains for type pairs 1,1 and 2,2 (type pairs
1,2 and 2,1 are ignored). See the "pair_coeff"_pair_coeff.html doc
page for alternate ways to specify the path for the potential file.
In effect, this makes atom types 1 and 2 in LAMMPS be Cu atoms.
Different single-element files can be assigned to different atom types
to model an alloy system. The mixing to create alloy potentials for
type pairs with I != J is done automatically the same way that the
serial DYNAMO code originally did it; you do not need to specify
coefficients for these type pairs.
{Funcfl} files in the {potentials} directory of the LAMMPS
distribution have an ".eam" suffix. A DYNAMO single-element {funcfl}
file is formatted as follows:
line 1: comment (ignored)
line 2: atomic number, mass, lattice constant, lattice type (e.g. FCC)
line 3: Nrho, drho, Nr, dr, cutoff :ul
On line 2, all values but the mass are ignored by LAMMPS. The mass is
in mass "units"_units.html, e.g. mass number or grams/mole for metal
units. The cubic lattice constant is in Angstroms. On line 3, Nrho
and Nr are the number of tabulated values in the subsequent arrays,
drho and dr are the spacing in density and distance space for the
values in those arrays, and the specified cutoff becomes the pairwise
cutoff used by LAMMPS for the potential. The units of dr are
Angstroms; I'm not sure of the units for drho - some measure of
electron density.
Following the three header lines are three arrays of tabulated values:
embedding function F(rho) (Nrho values)
effective charge function Z(r) (Nr values)
density function rho(r) (Nr values) :ul
The values for each array can be listed as multiple values per line,
so long as each array starts on a new line. For example, the
individual Z(r) values are for r = 0,dr,2*dr, ... (Nr-1)*dr.
The units for the embedding function F are eV. The units for the
density function rho are the same as for drho (see above, electron
density). The units for the effective charge Z are "atomic charge" or
sqrt(Hartree * Bohr-radii). For two interacting atoms i,j this is used
by LAMMPS to compute the pair potential term in the EAM energy
expression as r*phi, in units of eV-Angstroms, via the formula
r*phi = 27.2 * 0.529 * Zi * Zj :pre
where 1 Hartree = 27.2 eV and 1 Bohr = 0.529 Angstroms.
:line
Style {eam/alloy} computes pairwise interactions using the same
formula as style {eam}. However the associated
"pair_coeff"_pair_coeff.html command reads a DYNAMO {setfl} file
instead of a {funcfl} file. {Setfl} files can be used to model a
single-element or alloy system. In the alloy case, as explained
above, {setfl} files contain explicit tabulated values for alloy
interactions. Thus they allow more generality than {funcfl} files for
modeling alloys.
For style {eam/alloy}, potential values are read from a file that is
in the DYNAMO multi-element {setfl} format, except that element names
(Ni, Cu, etc) are added to one of the lines in the file. If the
DYNAMO file was created by a Fortran program, it cannot have "D"
values in it for exponents. C only recognizes "e" or "E" for
scientific notation.
Only a single pair_coeff command is used with the {eam/alloy} style
which specifies a DYNAMO {setfl} file, which contains information for
M elements. These are mapped to LAMMPS atom types by specifying N
additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of {setfl} elements to atom types :ul
As an example, the potentials/NiAlH_jea.eam.alloy file is a {setfl}
file which has tabulated EAM values for 3 elements and their alloy
interactions: Ni, Al, and H. See the "pair_coeff"_pair_coeff.html doc
page for alternate ways to specify the path for the potential file.
If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to
be Ni, and the 4th to be Al, you would use the following pair_coeff
command:
pair_coeff * * NiAlH_jea.eam.alloy Ni Ni Ni Al :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Ni arguments map LAMMPS atom types 1,2,3 to the Ni
element in the {setfl} file. The final Al argument maps LAMMPS atom
type 4 to the Al element in the {setfl} file. Note that there is no
requirement that your simulation use all the elements specified by the
{setfl} file.
If a mapping value is specified as NULL, the mapping is not performed.
This can be used when an {eam/alloy} potential is used as part of the
{hybrid} pair style. The NULL values are placeholders for atom types
that will be used with other potentials.
{Setfl} files in the {potentials} directory of the LAMMPS distribution
have an ".eam.alloy" suffix. A DYNAMO multi-element {setfl} file is
formatted as follows:
lines 1,2,3 = comments (ignored)
line 4: Nelements Element1 Element2 ... ElementN
line 5: Nrho, drho, Nr, dr, cutoff :ul
In a DYNAMO {setfl} file, line 4 only lists Nelements = the # of
elements in the {setfl} file. For LAMMPS, the element name (Ni, Cu,
etc) of each element must be added to the line, in the order the
elements appear in the file.
The meaning and units of the values in line 5 is the same as for the
{funcfl} file described above. Note that the cutoff (in Angstroms) is
a global value, valid for all pairwise interactions for all element
pairings.
Following the 5 header lines are Nelements sections, one for each
element, each with the following format:
line 1 = atomic number, mass, lattice constant, lattice type (e.g. FCC)
embedding function F(rho) (Nrho values)
density function rho(r) (Nr values) :ul
As with the {funcfl} files, only the mass (in mass "units"_units.html,
e.g. mass number or grams/mole for metal units) is used by LAMMPS from
the 1st line. The cubic lattice constant is in Angstroms. The F and
rho arrays are unique to a single element and have the same format and
units as in a {funcfl} file.
Following the Nelements sections, Nr values for each pair potential
phi(r) array are listed for all i,j element pairs in the same format
as other arrays. Since these interactions are symmetric (i,j = j,i)
only phi arrays with i >= j are listed, in the following order: i,j =
(1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ..., (Nelements,
Nelements). Unlike the effective charge array Z(r) in {funcfl} files,
the tabulated values for each phi function are listed in {setfl} files
directly as r*phi (in units of eV-Angstroms), since they are for atom
pairs.
:line
Style {eam/cd} is similar to the {eam/alloy} style, except that it
computes alloy pairwise interactions using the concentration-dependent
embedded-atom method (CD-EAM). This model can reproduce the enthalpy
of mixing of alloys over the full composition range, as described in
"(Stukowski)"_#Stukowski.
The pair_coeff command is specified the same as for the {eam/alloy}
style. However the DYNAMO {setfl} file must has two
lines added to it, at the end of the file:
line 1: Comment line (ignored)
line 2: N Coefficient0 Coefficient1 ... CoefficientN :ul
The last line begins with the degree {N} of the polynomial function
{h(x)} that modifies the cross interaction between A and B elements.
Then {N+1} coefficients for the terms of the polynomial are then
listed.
Modified EAM {setfl} files used with the {eam/cd} style must contain
exactly two elements, i.e. in the current implementation the {eam/cd}
style only supports binary alloys. The first and second elements in
the input EAM file are always taken as the {A} and {B} species.
{CD-EAM} files in the {potentials} directory of the LAMMPS
distribution have a ".cdeam" suffix.
:line
Style {eam/fs} computes pairwise interactions for metals and metal
alloys using a generalized form of EAM potentials due to Finnis and
Sinclair "(Finnis)"_#Finnis. The total energy Ei of an atom I is
given by
:c,image(Eqs/pair_eam_fs.jpg)
This has the same form as the EAM formula above, except that rho is
now a functional specific to the atomic types of both atoms I and J,
so that different elements can contribute differently to the total
electron density at an atomic site depending on the identity of the
element at that atomic site.
The associated "pair_coeff"_pair_coeff.html command for style {eam/fs}
reads a DYNAMO {setfl} file that has been extended to include
additional rho_alpha_beta arrays of tabulated values. A discussion of
how FS EAM differs from conventional EAM alloy potentials is given in
"(Ackland1)"_#Ackland1. An example of such a potential is the same
author's Fe-P FS potential "(Ackland2)"_#Ackland2. Note that while FS
potentials always specify the embedding energy with a square root
dependence on the total density, the implementation in LAMMPS does not
require that; the user can tabulate any functional form desired in the
FS potential files.
For style {eam/fs}, the form of the pair_coeff command is exactly the
same as for style {eam/alloy}, e.g.
pair_coeff * * NiAlH_jea.eam.fs Ni Ni Ni Al :pre
where there are N additional arguments after the filename, where N is
the number of LAMMPS atom types. See the "pair_coeff"_pair_coeff.html
doc page for alternate ways to specify the path for the potential
file. The N values determine the mapping of LAMMPS atom types to EAM
elements in the file, as described above for style {eam/alloy}. As
with {eam/alloy}, if a mapping value is NULL, the mapping is not
performed. This can be used when an {eam/fs} potential is used as
part of the {hybrid} pair style. The NULL values are used as
placeholders for atom types that will be used with other potentials.
FS EAM files include more information than the DYNAMO {setfl} format
files read by {eam/alloy}, in that i,j density functionals for all
pairs of elements are included as needed by the Finnis/Sinclair
formulation of the EAM.
FS EAM files in the {potentials} directory of the LAMMPS distribution
have an ".eam.fs" suffix. They are formatted as follows:
lines 1,2,3 = comments (ignored)
line 4: Nelements Element1 Element2 ... ElementN
line 5: Nrho, drho, Nr, dr, cutoff :ul
The 5-line header section is identical to an EAM {setfl} file.
Following the header are Nelements sections, one for each element I,
each with the following format:
line 1 = atomic number, mass, lattice constant, lattice type (e.g. FCC)
embedding function F(rho) (Nrho values)
density function rho(r) for element I at element 1 (Nr values)
density function rho(r) for element I at element 2
...
density function rho(r) for element I at element Nelement :ul
The units of these quantities in line 1 are the same as for {setfl}
files. Note that the rho(r) arrays in Finnis/Sinclair can be
asymmetric (i,j != j,i) so there are Nelements^2 of them listed in the
file.
Following the Nelements sections, Nr values for each pair potential
phi(r) array are listed in the same manner (r*phi, units of
eV-Angstroms) as in EAM {setfl} files. Note that in Finnis/Sinclair,
the phi(r) arrays are still symmetric, so only phi arrays for i >= j
are listed.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for more
instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above with the individual styles. You never need to specify
a pair_coeff command with I != J arguments for the eam styles.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
The eam pair styles do not write their information to "binary restart
files"_restart.html, since it is stored in tabulated potential files.
Thus, you need to re-specify the pair_style and pair_coeff commands in
an input script that reads a restart file.
The eam pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
All of these styles except the {eam/cd} style are part of the MANYBODY
package. They are only enabled if LAMMPS was built with that package.
See the "Making LAMMPS"_Section_start.html#start_3 section for more info.
The {eam/cd} style is part of the USER-MISC package and also requires
the MANYBODY package. It is only enabled if LAMMPS was built with
those packages. See the "Making LAMMPS"_Section_start.html#start_3
section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Ackland1)
[(Ackland1)] Ackland, Condensed Matter (2005).
:link(Ackland2)
[(Ackland2)] Ackland, Mendelev, Srolovitz, Han and Barashev, Journal
of Physics: Condensed Matter, 16, S2629 (2004).
:link(Daw)
[(Daw)] Daw, Baskes, Phys Rev Lett, 50, 1285 (1983).
Daw, Baskes, Phys Rev B, 29, 6443 (1984).
:link(Finnis)
[(Finnis)] Finnis, Sinclair, Philosophical Magazine A, 50, 45 (1984).
:link(Stukowski)
[(Stukowski)] Stukowski, Sadigh, Erhart, Caro; Modeling Simulation
Materials Science & Engineering, 7, 075005 (2009).
diff --git a/doc/src/pair_edip.txt b/doc/src/pair_edip.txt
index 86453859d..e5b1420b5 100644
--- a/doc/src/pair_edip.txt
+++ b/doc/src/pair_edip.txt
@@ -1,172 +1,172 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style edip command :h3
pair_style edip/multi command :h3
[Syntax:]
pair_style style :pre
style = {edip} or {edip/multi} :ul
[Examples:]
pair_style edip
pair_coeff * * Si.edip Si
[Description:]
The {edip} and {edip/multi} styles compute a 3-body "EDIP"_#EDIP
potential which is popular for modeling silicon materials where
it can have advantages over other models such as the
"Stillinger-Weber"_pair_sw.html or "Tersoff"_pair_tersoff.html
potentials. The {edip} style has been programmed for single element
potentials, while {edip/multi} supports multi-element EDIP runs.
In EDIP, the energy E of a system of atoms is
:c,image(Eqs/pair_edip.jpg)
where phi2 is a two-body term and phi3 is a three-body term. The
summations in the formula are over all neighbors J and K of atom I
within a cutoff distance = a.
Both terms depend on the local environment of atom I through its
effective coordination number defined by Z, which is unity for a
cutoff distance < c and gently goes to 0 at distance = a.
Only a single pair_coeff command is used with the {edip} style which
specifies a EDIP potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of EDIP elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine a file Si.edip has EDIP values for Si.
EDIP files in the {potentials} directory of the LAMMPS
distribution have a ".edip" suffix. Lines that are not blank or
comments (starting with #) define parameters for a triplet of
elements. The parameters in a single entry correspond to the two-body
and three-body coefficients in the formula above:
element 1 (the center atom in a 3-body interaction)
element 2
element 3
A (energy units)
B (distance units)
cutoffA (distance units)
cutoffC (distance units)
alpha
beta
eta
gamma (distance units)
lambda (energy units)
mu
tho
sigma (distance units)
Q0
u1
u2
u3
u4 :ul
The A, B, beta, sigma parameters are used only for two-body interactions.
The eta, gamma, lambda, mu, Q0 and all u1 to u4 parameters are used only
for three-body interactions. The alpha and cutoffC parameters are used
for the coordination environment function only.
The EDIP potential file must contain entries for all the
elements listed in the pair_coeff command. It can also contain
entries for additional elements not being used in a particular
simulation; LAMMPS ignores those entries.
For a single-element simulation, only a single entry is required
(e.g. SiSiSi). For a two-element simulation, the file must contain 8
entries (for SiSiSi, SiSiC, SiCSi, SiCC, CSiSi, CSiC, CCSi, CCC), that
specify EDIP parameters for all permutations of the two elements
interacting in three-body configurations. Thus for 3 elements, 27
entries would be required, etc.
At the moment, only a single element parametrization is
implemented. However, the author is not aware of other
multi-element EDIP parameterization. If you know any and
you are interest in that, please contact the author of
the EDIP package.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style can only be used if LAMMPS was built with the
USER-MISC package. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
The EDIP potential files provided with LAMMPS (see the potentials directory)
are parameterized for metal "units"_units.html.
You can use the EDIP potential with any LAMMPS units, but you would need
to create your own EDIP potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(EDIP)
[(EDIP)] J F Justo et al, Phys Rev B 58, 2539 (1998).
diff --git a/doc/src/pair_eim.txt b/doc/src/pair_eim.txt
index 3f068d404..75ad2d468 100644
--- a/doc/src/pair_eim.txt
+++ b/doc/src/pair_eim.txt
@@ -1,174 +1,174 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style eim command :h3
pair_style eim/omp command :h3
[Syntax:]
pair_style style :pre
style = {eim} :ul
[Examples:]
pair_style eim
pair_coeff * * Na Cl ../potentials/ffield.eim Na Cl
pair_coeff * * Na Cl ffield.eim Na Na Na Cl
pair_coeff * * Na Cl ../potentials/ffield.eim Cl NULL Na :pre
[Description:]
Style {eim} computes pairwise interactions for ionic compounds
using embedded-ion method (EIM) potentials "(Zhou)"_#Zhou2. The
energy of the system E is given by
:c,image(Eqs/pair_eim1.jpg)
The first term is a double pairwise sum over the J neighbors of all I
atoms, where phi_ij is a pair potential. The second term sums over
the embedding energy E_i of atom I, which is a function of its charge
q_i and the electrical potential sigma_i at its location. E_i, q_i,
and sigma_i are calculated as
:c,image(Eqs/pair_eim2.jpg)
where eta_ji is a pairwise function describing electron flow from atom
I to atom J, and psi_ij is another pairwise function. The multi-body
nature of the EIM potential is a result of the embedding energy term.
A complete list of all the pair functions used in EIM is summarized
below
:c,image(Eqs/pair_eim3.jpg)
Here E_b, r_e, r_(c,phi), alpha, beta, A_(psi), zeta, r_(s,psi),
r_(c,psi), A_(eta), r_(s,eta), r_(c,eta), chi, and pair function type
p are parameters, with subscripts ij indicating the two species of
atoms in the atomic pair.
NOTE: Even though the EIM potential is treating atoms as charged ions,
you should not use a LAMMPS "atom_style"_atom_style.html that stores a
charge on each atom and thus requires you to assign a charge to each
atom, e.g. the {charge} or {full} atom styles. This is because the
EIM potential infers the charge on an atom from the equation above for
q_i; you do not assign charges explicitly.
:line
All the EIM parameters are listed in a potential file which is
specified by the "pair_coeff"_pair_coeff.html command. This is an
ASCII text file in a format described below. The "ffield.eim" file
included in the "potentials" directory of the LAMMPS distribution
currently includes nine elements Li, Na, K, Rb, Cs, F, Cl, Br, and I.
A system with any combination of these elements can be modeled. This
file is parameterized in terms of LAMMPS "metal units"_units.html.
Note that unlike other potentials, cutoffs for EIM potentials are not
set in the pair_style or pair_coeff command; they are specified in the
EIM potential file itself. Likewise, the EIM potential file lists
atomic masses; thus you do not need to use the "mass"_mass.html
command to specify them.
Only a single pair_coeff command is used with the {eim} style which
specifies an EIM potential file and the element(s) to extract
information for. The EIM elements are mapped to LAMMPS atom types by
specifying N additional arguments after the filename in the pair_coeff
command, where N is the number of LAMMPS atom types:
Elem1, Elem2, ...
EIM potential file
N element names = mapping of EIM elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example like one of those above, suppose you want to model a
system with Na and Cl atoms. If your LAMMPS simulation has 4 atoms
types and you want the 1st 3 to be Na, and the 4th to be Cl, you would
use the following pair_coeff command:
pair_coeff * * Na Cl ffield.eim Na Na Na Cl :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The filename is the EIM potential file. The Na and Cl arguments
(before the file name) are the two elements for which info will be
extracted from the potential file. The first three trailing Na
arguments map LAMMPS atom types 1,2,3 to the EIM Na element. The
final Cl argument maps LAMMPS atom type 4 to the EIM Cl element.
If a mapping value is specified as NULL, the mapping is not performed.
This can be used when an {eim} potential is used as part of the
{hybrid} pair style. The NULL values are placeholders for atom types
that will be used with other potentials.
The ffield.eim file in the {potentials} directory of the LAMMPS
distribution is formatted as follows:
Lines starting with # are comments and are ignored by LAMMPS. Lines
starting with "global:" include three global values. The first value
divides the cations from anions, i.e., any elements with
electronegativity above this value are viewed as anions, and any
elements with electronegativity below this value are viewed as
cations. The second and third values are related to the cutoff
function - i.e. the 0.510204, 1.64498, and 0.010204 shown in the above
equation can be derived from these values.
Lines starting with "element:" are formatted as follows: name of
element, atomic number, atomic mass, electronic negativity, atomic
radius (LAMMPS ignores it), ionic radius (LAMMPS ignores it), cohesive
energy (LAMMPS ignores it), and q0 (must be 0).
Lines starting with "pair:" are entered as: element 1, element 2,
r_(c,phi), r_(c,phi) (redundant for historical reasons), E_b, r_e,
alpha, beta, r_(c,eta), A_(eta), r_(s,eta), r_(c,psi), A_(psi), zeta,
r_(s,psi), and p.
The lines in the file can be in any order; LAMMPS extracts the info it
needs.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This style is part of the MANYBODY package. It is only enabled if
LAMMPS was built with that package.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Zhou2)
[(Zhou)] Zhou, submitted for publication (2010). Please contact
Xiaowang Zhou (Sandia) for details via email at xzhou at sandia.gov.
diff --git a/doc/src/pair_gayberne.txt b/doc/src/pair_gayberne.txt
index 8639f220a..c92357858 100644
--- a/doc/src/pair_gayberne.txt
+++ b/doc/src/pair_gayberne.txt
@@ -1,231 +1,231 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style gayberne command :h3
pair_style gayberne/gpu command :h3
pair_style gayberne/intel command :h3
pair_style gayberne/omp command :h3
[Syntax:]
pair_style gayberne gamma upsilon mu cutoff :pre
gamma = shift for potential minimum (typically 1)
upsilon = exponent for eta orientation-dependent energy function
mu = exponent for chi orientation-dependent energy function
cutoff = global cutoff for interactions (distance units) :ul
[Examples:]
pair_style gayberne 1.0 1.0 1.0 10.0
pair_coeff * * 1.0 1.7 1.7 3.4 3.4 1.0 1.0 1.0 :pre
[Description:]
The {gayberne} styles compute a Gay-Berne anisotropic LJ interaction
"(Berardi)"_#Berardi between pairs of ellipsoidal particles or an
ellipsoidal and spherical particle via the formulas
:c,image(Eqs/pair_gayberne.jpg)
where A1 and A2 are the transformation matrices from the simulation
box frame to the body frame and r12 is the center to center vector
between the particles. Ur controls the shifted distance dependent
interaction based on the distance of closest approach of the two
particles (h12) and the user-specified shift parameter gamma. When
both particles are spherical, the formula reduces to the usual
Lennard-Jones interaction (see details below for when Gay-Berne treats
a particle as "spherical").
For large uniform molecules it has been shown that the energy
parameters are approximately representable in terms of local contact
curvatures "(Everaers)"_#Everaers2:
:c,image(Eqs/pair_gayberne2.jpg)
The variable names utilized as potential parameters are for the most
part taken from "(Everaers)"_#Everaers2 in order to be consistent with
the "RE-squared pair potential"_pair_resquared.html. Details on the
upsilon and mu parameters are given
"here"_PDF/pair_resquared_extra.pdf.
More details of the Gay-Berne formulation are given in the references
listed below and in "this supplementary
document"_PDF/pair_gayberne_extra.pdf.
Use of this pair style requires the NVE, NVT, or NPT fixes with the
{asphere} extension (e.g. "fix nve/asphere"_fix_nve_asphere.html) in
order to integrate particle rotation. Additionally, "atom_style
ellipsoid"_atom_style.html should be used since it defines the
rotational state and the size and shape of each ellipsoidal particle.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon = well depth (energy units)
sigma = minimum effective particle radii (distance units)
epsilon_i_a = relative well depth of type I for side-to-side interactions
epsilon_i_b = relative well depth of type I for face-to-face interactions
epsilon_i_c = relative well depth of type I for end-to-end interactions
epsilon_j_a = relative well depth of type J for side-to-side interactions
epsilon_j_b = relative well depth of type J for face-to-face interactions
epsilon_j_c = relative well depth of type J for end-to-end interactions
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global
cutoff specified in the pair_style command is used.
It is typical with the Gay-Berne potential to define {sigma} as the
minimum of the 3 shape diameters of the particles involved in an I,I
interaction, though this is not required. Note that this is a
different meaning for {sigma} than the "pair_style
resquared"_pair_resquared.html potential uses.
The epsilon_i and epsilon_j coefficients are actually defined for atom
types, not for pairs of atom types. Thus, in a series of pair_coeff
commands, they only need to be specified once for each atom type.
Specifically, if any of epsilon_i_a, epsilon_i_b, epsilon_i_c are
non-zero, the three values are assigned to atom type I. If all the
epsilon_i values are zero, they are ignored. If any of epsilon_j_a,
epsilon_j_b, epsilon_j_c are non-zero, the three values are assigned
to atom type J. If all three epsilon_j values are zero, they are
ignored. Thus the typical way to define the epsilon_i and epsilon_j
coefficients is to list their values in "pair_coeff I J" commands when
I = J, but set them to 0.0 when I != J. If you do list them when I !=
J, you should insure they are consistent with their values in other
pair_coeff commands, since only the last setting will be in effect.
Note that if this potential is being used as a sub-style of
"pair_style hybrid"_pair_hybrid.html, and there is no "pair_coeff I I"
setting made for Gay-Berne for a particular type I (because I-I
interactions are computed by another hybrid pair potential), then you
still need to insure the epsilon a,b,c coefficients are assigned to
that type. e.g. in a "pair_coeff I J" command.
NOTE: If the epsilon a = b = c for an atom type, and if the shape of
the particle itself is spherical, meaning its 3 shape parameters are
all the same, then the particle is treated as an LJ sphere by the
Gay-Berne potential. This is significant because if two LJ spheres
interact, then the simple Lennard-Jones formula is used to compute
their interaction energy/force using the specified epsilon and sigma
as the standard LJ parameters. This is much cheaper to compute than
the full Gay-Berne formula. To treat the particle as a LJ sphere with
sigma = D, you should normally set epsilon a = b = c = 1.0, set the
pair_coeff sigma = D, and also set the 3 shape parameters for the
particle to D. The one exception is that if the 3 shape parameters
are set to 0.0, which is a valid way in LAMMPS to specify a point
particle, then the Gay-Berne potential will treat that as shape
parameters of 1.0 (i.e. a LJ particle with sigma = 1), since it
requires finite-size particles. In this case you should still set the
pair_coeff sigma to 1.0 as well.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for this pair style can be mixed. The default mix
value is {geometric}. See the "pair_modify" command for details.
This pair styles supports the "pair_modify"_pair_modify.html shift
option for the energy of the Lennard-Jones portion of the pair
interaction, but only for sphere-sphere interactions. There is no
shifting performed for ellipsoidal interactions due to the anisotropic
dependence of the interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
The {gayberne} style is part of the ASPHERE package. It is only
enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
These pair style require that atoms store torque and a quaternion to
represent their orientation, as defined by the
"atom_style"_atom_style.html. It also require they store a per-type
"shape"_set.html. The particles cannot store a per-particle
diameter.
This pair style requires that atoms be ellipsoids as defined by the
"atom_style ellipsoid"_atom_style.html command.
Particles acted on by the potential can be finite-size aspherical or
spherical particles, or point particles. Spherical particles have all
3 of their shape parameters equal to each other. Point particles have
all 3 of their shape parameters equal to 0.0.
The Gay-Berne potential does not become isotropic as r increases
"(Everaers)"_#Everaers2. The distance-of-closest-approach
approximation used by LAMMPS becomes less accurate when high-aspect
ratio ellipsoids are used.
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix nve/asphere"_fix_nve_asphere.html,
"compute temp/asphere"_compute_temp_asphere.html, "pair_style
resquared"_pair_resquared.html
[Default:] none
:line
:link(Everaers2)
[(Everaers)] Everaers and Ejtehadi, Phys Rev E, 67, 041710 (2003).
:link(Berardi)
[(Berardi)] Berardi, Fava, Zannoni, Chem Phys Lett, 297, 8-14 (1998).
Berardi, Muccioli, Zannoni, J Chem Phys, 128, 024905 (2008).
:link(Perram)
[(Perram)] Perram and Rasmussen, Phys Rev E, 54, 6565-6572 (1996).
:link(Allen3)
[(Allen)] Allen and Germano, Mol Phys 104, 3225-3235 (2006).
diff --git a/doc/src/pair_gran.txt b/doc/src/pair_gran.txt
index 62a58b350..d7e87af01 100644
--- a/doc/src/pair_gran.txt
+++ b/doc/src/pair_gran.txt
@@ -1,271 +1,271 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style gran/hooke command :h3
pair_style gran/omp command :h3
pair_style gran/hooke/history command :h3
pair_style gran/hooke/history/omp command :h3
pair_style gran/hertz/history command :h3
pair_style gran/hertz/history/omp command :h3
[Syntax:]
pair_style style Kn Kt gamma_n gamma_t xmu dampflag :pre
style = {gran/hooke} or {gran/hooke/history} or {gran/hertz/history} :ulb,l
Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) :l
Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) :l
gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) :l
gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) :l
xmu = static yield criterion (unitless value between 0.0 and 1.0e4) :l
dampflag = 0 or 1 if tangential damping force is excluded or included :l
:ule
NOTE: Versions of LAMMPS before 9Jan09 had different style names for
granular force fields. This is to emphasize the fact that the
Hertzian equation has changed to model polydispersity more accurately.
A side effect of the change is that the Kn, Kt, gamma_n, and gamma_t
coefficients in the pair_style command must be specified with
different values in order to reproduce calculations made with earlier
versions of LAMMPS, even for monodisperse systems. See the NOTE below
for details.
[Examples:]
pair_style gran/hooke/history 200000.0 NULL 50.0 NULL 0.5 1
pair_style gran/hooke 200000.0 70000.0 50.0 30.0 0.5 0 :pre
[Description:]
The {gran} styles use the following formulas for the frictional force
between two granular particles, as described in
"(Brilliantov)"_#Brilliantov, "(Silbert)"_#Silbert, and
"(Zhang)"_#Zhang3, when the distance r between two particles of radii
Ri and Rj is less than their contact distance d = Ri + Rj. There is
no force between the particles when r > d.
The two Hookean styles use this formula:
:c,image(Eqs/pair_gran_hooke.jpg)
The Hertzian style uses this formula:
:c,image(Eqs/pair_gran_hertz.jpg)
In both equations the first parenthesized term is the normal force
between the two particles and the second parenthesized term is the
tangential force. The normal force has 2 terms, a contact force and a
damping force. The tangential force also has 2 terms: a shear force
and a damping force. The shear force is a "history" effect that
accounts for the tangential displacement between the particles for the
duration of the time they are in contact. This term is included in
pair styles {hooke/history} and {hertz/history}, but is not included
in pair style {hooke}. The tangential damping force term is included
in all three pair styles if {dampflag} is set to 1; it is not included
if {dampflag} is set to 0.
The other quantities in the equations are as follows:
delta = d - r = overlap distance of 2 particles
Kn = elastic constant for normal contact
Kt = elastic constant for tangential contact
gamma_n = viscoelastic damping constant for normal contact
gamma_t = viscoelastic damping constant for tangential contact
m_eff = Mi Mj / (Mi + Mj) = effective mass of 2 particles of mass Mi and Mj
Delta St = tangential displacement vector between 2 particles \
which is truncated to satisfy a frictional yield criterion
n_ij = unit vector along the line connecting the centers of the 2 particles
Vn = normal component of the relative velocity of the 2 particles
Vt = tangential component of the relative velocity of the 2 particles :ul
The Kn, Kt, gamma_n, and gamma_t coefficients are specified as
parameters to the pair_style command. If a NULL is used for Kt, then
a default value is used where Kt = 2/7 Kn. If a NULL is used for
gamma_t, then a default value is used where gamma_t = 1/2 gamma_n.
The interpretation and units for these 4 coefficients are different in
the Hookean versus Hertzian equations.
The Hookean model is one where the normal push-back force for two
overlapping particles is a linear function of the overlap distance.
Thus the specified Kn is in units of (force/distance). Note that this
push-back force is independent of absolute particle size (in the
monodisperse case) and of the relative sizes of the two particles (in
the polydisperse case). This model also applies to the other terms in
the force equation so that the specified gamma_n is in units of
(1/time), Kt is in units of (force/distance), and gamma_t is in units
of (1/time).
The Hertzian model is one where the normal push-back force for two
overlapping particles is proportional to the area of overlap of the
two particles, and is thus a non-linear function of overlap distance.
Thus Kn has units of force per area and is thus specified in units of
(pressure). The effects of absolute particle size (monodispersity)
and relative size (polydispersity) are captured in the radii-dependent
pre-factors. When these pre-factors are carried through to the other
terms in the force equation it means that the specified gamma_n is in
units of (1/(time*distance)), Kt is in units of (pressure), and
gamma_t is in units of (1/(time*distance)).
Note that in the Hookean case, Kn can be thought of as a linear spring
constant with units of force/distance. In the Hertzian case, Kn is
like a non-linear spring constant with units of force/area or
pressure, and as shown in the "(Zhang)"_#Zhang3 paper, Kn = 4G /
(3(1-nu)) where nu = the Poisson ratio, G = shear modulus = E /
(2(1+nu)), and E = Young's modulus. Similarly, Kt = 4G / (2-nu).
(NOTE: in an earlier version of the manual, we incorrectly stated that
Kt = 8G / (2-nu).)
Thus in the Hertzian case Kn and Kt can be set to values that
corresponds to properties of the material being modeled. This is also
true in the Hookean case, except that a spring constant must be chosen
that is appropriate for the absolute size of particles in the model.
Since relative particle sizes are not accounted for, the Hookean
styles may not be a suitable model for polydisperse systems.
NOTE: In versions of LAMMPS before 9Jan09, the equation for Hertzian
interactions did not include the sqrt(RiRj/Ri+Rj) term and thus was
not as accurate for polydisperse systems. For monodisperse systems,
sqrt(RiRj/Ri+Rj) is a constant factor that effectively scales all 4
coefficients: Kn, Kt, gamma_n, gamma_t. Thus you can set the values
of these 4 coefficients appropriately in the current code to reproduce
the results of a previous Hertzian monodisperse calculation. For
example, for the common case of a monodisperse system with particles
of diameter 1, all 4 of these coefficients should now be set 2x larger
than they were previously.
Xmu is also specified in the pair_style command and is the upper limit
of the tangential force through the Coulomb criterion Ft = xmu*Fn,
where Ft and Fn are the total tangential and normal force components
in the formulas above. Thus in the Hookean case, the tangential force
between 2 particles grows according to a tangential spring and
dash-pot model until Ft/Fn = xmu and is then held at Ft = Fn*xmu until
the particles lose contact. In the Hertzian case, a similar analogy
holds, though the spring is no longer linear.
NOTE: Normally, xmu should be specified as a fractional value between
0.0 and 1.0, however LAMMPS allows large values (up to 1.0e4) to allow
for modeling of systems which can sustain very large tangential
forces.
The effective mass {m_eff} is given by the formula above for two
isolated particles. If either particle is part of a rigid body, its
mass is replaced by the mass of the rigid body in the formula above.
This is determined by searching for a "fix rigid"_fix_rigid.html
command (or its variants).
For granular styles there are no additional coefficients to set for
each pair of atom types via the "pair_coeff"_pair_coeff.html command.
All settings are global and are made via the pair_style command.
However you must still use the "pair_coeff"_pair_coeff.html for all
pairs of granular atom types. For example the command
pair_coeff * * :pre
should be used if all atoms in the simulation interact via a granular
potential (i.e. one of the pair styles above is used). If a granular
potential is used as a sub-style of "pair_style
hybrid"_pair_hybrid.html, then specific atom types can be used in the
pair_coeff command to determine which atoms interact via a granular
potential.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
The "pair_modify"_pair_modify.html mix, shift, table, and tail options
are not relevant for granular pair styles.
These pair styles write their information to "binary restart
files"_restart.html, so a pair_style command does not need to be
specified in an input script that reads a restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
The single() function of these pair styles returns 0.0 for the energy
of a pairwise interaction, since energy is not conserved in these
dissipative potentials. It also returns only the normal component of
the pairwise interaction force. However, the single() function also
calculates 10 extra pairwise quantities. The first 3 are the
components of the tangential force between particles I and J, acting
on particle I. The 4th is the magnitude of this tangential force.
The next 3 (5-7) are the components of the relative velocity in the
normal direction (along the line joining the 2 sphere centers). The
last 3 (8-10) the components of the relative velocity in the
tangential direction.
These extra quantities can be accessed by the "compute
pair/local"_compute_pair_local.html command, as {p1}, {p2}, ...,
{p10}.
:line
[Restrictions:]
All the granular pair styles are part of the GRANULAR package. It is
only enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
These pair styles require that atoms store torque and angular velocity
(omega) as defined by the "atom_style"_atom_style.html. They also
require a per-particle radius is stored. The {sphere} atom style does
all of this.
This pair style requires you to use the "comm_modify vel
yes"_comm_modify.html command so that velocites are stored by ghost
atoms.
These pair styles will not restart exactly when using the
"read_restart"_read_restart.html command, though they should provide
statistically similar results. This is because the forces they
compute depend on atom velocities. See the
"read_restart"_read_restart.html command for more details.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Brilliantov)
[(Brilliantov)] Brilliantov, Spahn, Hertzsch, Poschel, Phys Rev E, 53,
p 5382-5392 (1996).
:link(Silbert)
[(Silbert)] Silbert, Ertas, Grest, Halsey, Levine, Plimpton, Phys Rev
E, 64, p 051302 (2001).
:link(Zhang3)
[(Zhang)] Zhang and Makse, Phys Rev E, 72, p 011301 (2005).
diff --git a/doc/src/pair_gromacs.txt b/doc/src/pair_gromacs.txt
index 3aca8c3cd..ec84a2d57 100644
--- a/doc/src/pair_gromacs.txt
+++ b/doc/src/pair_gromacs.txt
@@ -1,155 +1,155 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/gromacs command :h3
pair_style lj/gromacs/gpu command :h3
pair_style lj/gromacs/omp command :h3
pair_style lj/gromacs/coul/gromacs command :h3
pair_style lj/gromacs/coul/gromacs/omp command :h3
[Syntax:]
pair_style style args :pre
style = {lj/gromacs} or {lj/gromacs/coul/gromacs}
args = list of arguments for a particular style :ul
{lj/gromacs} args = inner outer
inner, outer = global switching cutoffs for Lennard Jones
{lj/gromacs/coul/gromacs} args = inner outer (inner2) (outer2)
inner, outer = global switching cutoffs for Lennard Jones (and Coulombic if only 2 args)
inner2, outer2 = global switching cutoffs for Coulombic (optional) :pre
[Examples:]
pair_style lj/gromacs 9.0 12.0
pair_coeff * * 100.0 2.0
pair_coeff 2 2 100.0 2.0 8.0 10.0 :pre
pair_style lj/gromacs/coul/gromacs 9.0 12.0
pair_style lj/gromacs/coul/gromacs 8.0 10.0 7.0 9.0
pair_coeff * * 100.0 2.0 :pre
[Description:]
The {lj/gromacs} styles compute shifted LJ and Coulombic interactions
with an additional switching function S(r) that ramps the energy and force
smoothly to zero between an inner and outer cutoff. It is a commonly
used potential in the "GROMACS"_http://www.gromacs.org MD code and for
the coarse-grained models of "(Marrink)"_#Marrink.
:c,image(Eqs/pair_gromacs.jpg)
r1 is the inner cutoff; rc is the outer cutoff. The coefficients A, B,
and C are computed by LAMMPS to perform the shifting and smoothing.
The function
S(r) is actually applied once to each term of the LJ formula and once
to the Coulombic formula, so there are 2 or 3 sets of A,B,C coefficients
depending on which pair_style is used. The boundary conditions
applied to the smoothing function are as follows: S'(r1) = S''(r1) = 0,
S(rc) = -E(rc), S'(rc) = -E'(rc), and S''(rc) = -E''(rc),
where E(r) is the corresponding term
in the LJ or Coulombic potential energy function.
Single and double primes denote first and second
derivatives with respect to r, respectively.
The inner and outer cutoff for the LJ and Coulombic terms can be the
same or different depending on whether 2 or 4 arguments are used in
the pair_style command. The inner LJ cutoff must be > 0, but the
inner Coulombic cutoff can be >= 0.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
inner (distance units)
outer (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum at 2^(1/6)
sigma.
The last 2 coefficients are optional inner and outer cutoffs for style
{lj/gromacs}. If not specified, the global {inner} and {outer} values
are used.
The last 2 coefficients cannot be used with style
{lj/gromacs/coul/gromacs} because this force field does not allow
varying cutoffs for individual atom pairs; all pairs use the global
cutoff(s) specified in the pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/cut pair styles can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
None of the GROMACS pair styles support the
"pair_modify"_pair_modify.html shift option, since the Lennard-Jones
portion of the pair interaction is already smoothed to 0.0 at the
cutoff.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
None of the GROMACS pair styles support the
"pair_modify"_pair_modify.html tail option for adding long-range tail
corrections to energy and pressure, since there are no corrections for
a potential that goes to 0.0 at the cutoff.
All of the GROMACS pair styles write their information to "binary
restart files"_restart.html, so pair_style and pair_coeff commands do
not need to be specified in an input script that reads a restart file.
All of the GROMACS pair styles can only be used via the {pair}
keyword of the "run_style respa"_run_style.html command. They do not
support the {inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Marrink)
[(Marrink)] Marrink, de Vries, Mark, J Phys Chem B, 108, 750-760 (2004).
diff --git a/doc/src/pair_hbond_dreiding.txt b/doc/src/pair_hbond_dreiding.txt
index 9641e294f..d3cf90ec1 100644
--- a/doc/src/pair_hbond_dreiding.txt
+++ b/doc/src/pair_hbond_dreiding.txt
@@ -1,243 +1,243 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style hbond/dreiding/lj command :h3
pair_style hbond/dreiding/lj/omp command :h3
pair_style hbond/dreiding/morse command :h3
pair_style hbond/dreiding/morse/omp command :h3
[Syntax:]
pair_style style N inner_distance_cutoff outer_distance_cutoff angle_cutof :pre
style = {hbond/dreiding/lj} or {hbond/dreiding/morse}
n = cosine angle periodicity
inner_distance_cutoff = global inner cutoff for Donor-Acceptor interactions (distance units)
outer_distance_cutoff = global cutoff for Donor-Acceptor interactions (distance units)
angle_cutoff = global angle cutoff for Acceptor-Hydrogen-Donor
interactions (degrees) :ul
[Examples:]
pair_style hybrid/overlay lj/cut 10.0 hbond/dreiding/lj 4 9.0 11.0 90
pair_coeff 1 2 hbond/dreiding/lj 3 i 9.5 2.75 4 9.0 11.0 90.0 :pre
pair_style hybrid/overlay lj/cut 10.0 hbond/dreiding/morse 2 9.0 11.0 90
pair_coeff 1 2 hbond/dreiding/morse 3 i 3.88 1.7241379 2.9 2 9 11 90 :pre
[Description:]
The {hbond/dreiding} styles compute the Acceptor-Hydrogen-Donor (AHD)
3-body hydrogen bond interaction for the
"DREIDING"_Section_howto.html#howto_4 force field, given by:
:c,image(Eqs/pair_hbond_dreiding.jpg)
where Rin is the inner spline distance cutoff, Rout is the outer
distance cutoff, theta_c is the angle cutoff, and n is the cosine
periodicity.
Here, {r} is the radial distance between the donor (D) and acceptor
(A) atoms and {theta} is the bond angle between the acceptor, the
hydrogen (H) and the donor atoms:
:c,image(Eqs/dreiding_hbond.jpg)
These 3-body interactions can be defined for pairs of acceptor and
donor atoms, based on atom types. For each donor/acceptor atom pair,
the 3rd atom in the interaction is a hydrogen permanently bonded to
the donor atom, e.g. in a bond list read in from a data file via the
"read_data"_read_data.html command. The atom types of possible
hydrogen atoms for each donor/acceptor type pair are specified by the
"pair_coeff"_pair_coeff.html command (see below).
Style {hbond/dreiding/lj} is the original DREIDING potential of
"(Mayo)"_#pair-Mayo. It uses a LJ 12/10 functional for the Donor-Acceptor
interactions. To match the results in the original paper, use n = 4.
Style {hbond/dreiding/morse} is an improved version using a Morse
potential for the Donor-Acceptor interactions. "(Liu)"_#Liu showed
that the Morse form gives improved results for Dendrimer simulations,
when n = 2.
See this "howto section"_Section_howto.html#howto_4 of the manual for
more information on the DREIDING forcefield.
NOTE: Because the Dreiding hydrogen bond potential is only one portion
of an overall force field which typically includes other pairwise
interactions, it is common to use it as a sub-style in a "pair_style
hybrid/overlay"_pair_hybrid.html command, where another pair style
provides the repulsive core interaction between pairs of atoms, e.g. a
1/r^12 Lennard-Jones repulsion.
NOTE: When using the hbond/dreiding pair styles with "pair_style
hybrid/overlay"_pair_hybrid.html, you should explicitly define pair
interactions between the donor atom and acceptor atoms, (as well as
between these atoms and ALL other atoms in your system). Whenever
"pair_style hybrid/overlay"_pair_hybrid.html is used, ordinary mixing
rules are not applied to atoms like the donor and acceptor atoms
because they are typically referenced in multiple pair styles.
Neglecting to do this can cause difficult-to-detect physics problems.
NOTE: In the original Dreiding force field paper 1-4 non-bonded
interactions ARE allowed. If this is desired for your model, use the
special_bonds command (e.g. "special_bonds lj 0.0 0.0 1.0") to turn
these interactions on.
:line
The following coefficients must be defined for pairs of eligible
donor/acceptor types via the "pair_coeff"_pair_coeff.html command as
in the examples above.
NOTE: Unlike other pair styles and their associated
"pair_coeff"_pair_coeff.html commands, you do not need to specify
pair_coeff settings for all possible I,J type pairs. Only I,J type
pairs for atoms which act as joint donors/acceptors need to be
specified; all other type pairs are assumed to be inactive.
NOTE: A "pair_coeff"_pair_coeff.html command can be specified multiple
times for the same donor/acceptor type pair. This enables multiple
hydrogen types to be assigned to the same donor/acceptor type pair.
For other pair_styles, if the pair_coeff command is re-used for the
same I.J type pair, the settings for that type pair are overwritten.
For the hydrogen bond potentials this is not the case; the settings
are cumulative. This means the only way to turn off a previous
setting, is to re-use the pair_style command and start over.
For the {hbond/dreiding/lj} style the list of coefficients is as
follows:
K = hydrogen atom type = 1 to Ntypes
donor flag = {i} or {j}
epsilon (energy units)
sigma (distance units)
n = exponent in formula above
distance cutoff Rin (distance units)
distance cutoff Rout (distance units)
angle cutoff (degrees) :ul
For the {hbond/dreiding/morse} style the list of coefficients is as
follows:
K = hydrogen atom type = 1 to Ntypes
donor flag = {i} or {j}
D0 (energy units)
alpha (1/distance units)
r0 (distance units)
n = exponent in formula above
distance cutoff Rin (distance units)
distance cutoff Rout (distance units)
angle cutoff (degrees) :ul
A single hydrogen atom type K can be specified, or a wild-card
asterisk can be used in place of or in conjunction with the K
arguments to select multiple types as hydrogens. This takes the form
"*" or "*n" or "n*" or "m*n". See the "pair_coeff"_pair_coeff.html
command doc page for details.
If the donor flag is {i}, then the atom of type I in the pair_coeff
command is treated as the donor, and J is the acceptor. If the donor
flag is {j}, then the atom of type J in the pair_coeff command is
treated as the donor and I is the donor. This option is required
because the "pair_coeff"_pair_coeff.html command requires that I <= J.
Epsilon and sigma are settings for the hydrogen bond potential based
on a Lennard-Jones functional form. Note that sigma is defined as the
zero-crossing distance for the potential, not as the energy minimum at
2^(1/6) sigma.
D0 and alpha and r0 are settings for the hydrogen bond potential based
on a Morse functional form.
The last 3 coefficients for both styles are optional. If not
specified, the global n, distance cutoff, and angle cutoff specified
in the pair_style command are used. If you wish to only override the
2nd or 3rd optional parameter, you must also specify the preceding
optional parameters.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. You must explicitly identify
each donor/acceptor type pair.
These styles do not support the "pair_modify"_pair_modify.html shift
option for the energy of the interactions.
The "pair_modify"_pair_modify.html table option is not relevant for
these pair styles.
These pair styles do not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
These pair styles do not write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands need to be
re-specified in an input script that reads a restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
These pair styles tally a count of how many hydrogen bonding
interactions they calculate each timestep and the hbond energy. These
quantities can be accessed via the "compute pair"_compute_pair.html
command as a vector of values of length 2.
To print these quantities to the log file (with a descriptive column
heading) the following commands could be included in an input script:
compute hb all pair hbond/dreiding/lj
variable n_hbond equal c_hb\[1\] #number hbonds
variable E_hbond equal c_hb\[2\] #hbond energy
thermo_style custom step temp epair v_E_hbond :pre
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(pair-Mayo)
[(Mayo)] Mayo, Olfason, Goddard III, J Phys Chem, 94, 8897-8909
(1990).
:link(Liu)
[(Liu)] Liu, Bryantsev, Diallo, Goddard III, J. Am. Chem. Soc 131 (8)
2798 (2009)
diff --git a/doc/src/pair_hybrid.txt b/doc/src/pair_hybrid.txt
index 5166fe1f8..fc1824cf6 100644
--- a/doc/src/pair_hybrid.txt
+++ b/doc/src/pair_hybrid.txt
@@ -1,388 +1,388 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style hybrid command :h3
pair_style hybrid/omp command :h3
pair_style hybrid/overlay command :h3
pair_style hybrid/overlay/omp command :h3
[Syntax:]
pair_style hybrid style1 args style2 args ...
pair_style hybrid/overlay style1 args style2 args ... :pre
style1,style2 = list of one or more pair styles and their arguments :ul
[Examples:]
pair_style hybrid lj/cut/coul/cut 10.0 eam lj/cut 5.0
pair_coeff 1*2 1*2 eam niu3
pair_coeff 3 3 lj/cut/coul/cut 1.0 1.0
pair_coeff 1*2 3 lj/cut 0.5 1.2 :pre
pair_style hybrid/overlay lj/cut 2.5 coul/long 2.0
pair_coeff * * lj/cut 1.0 1.0
pair_coeff * * coul/long :pre
[Description:]
The {hybrid} and {hybrid/overlay} styles enable the use of multiple
pair styles in one simulation. With the {hybrid} style, exactly one
pair style is assigned to each pair of atom types. With the
{hybrid/overlay} style, one or more pair styles can be assigned to
each pair of atom types. The assignment of pair styles to type pairs
is made via the "pair_coeff"_pair_coeff.html command.
Here are two examples of hybrid simulations. The {hybrid} style could
be used for a simulation of a metal droplet on a LJ surface. The
metal atoms interact with each other via an {eam} potential, the
surface atoms interact with each other via a {lj/cut} potential, and
the metal/surface interaction is also computed via a {lj/cut}
potential. The {hybrid/overlay} style could be used as in the 2nd
example above, where multiple potentials are superposed in an additive
fashion to compute the interaction between atoms. In this example,
using {lj/cut} and {coul/long} together gives the same result as if
the {lj/cut/coul/long} potential were used by itself. In this case,
it would be more efficient to use the single combined potential, but
in general any combination of pair potentials can be used together in
to produce an interaction that is not encoded in any single pair_style
file, e.g. adding Coulombic forces between granular particles.
All pair styles that will be used are listed as "sub-styles" following
the {hybrid} or {hybrid/overlay} keyword, in any order. Each
sub-style's name is followed by its usual arguments, as illustrated in
the example above. See the doc pages of individual pair styles for a
listing and explanation of the appropriate arguments.
Note that an individual pair style can be used multiple times as a
sub-style. For efficiency this should only be done if your model
requires it. E.g. if you have different regions of Si and C atoms and
wish to use a Tersoff potential for pure Si for one set of atoms, and
a Tersoff potential for pure C for the other set (presumably with some
3rd potential for Si-C interactions), then the sub-style {tersoff}
could be listed twice. But if you just want to use a Lennard-Jones or
other pairwise potential for several different atom type pairs in your
model, then you should just list the sub-style once and use the
pair_coeff command to assign parameters for the different type pairs.
NOTE: There are two exceptions to this option to list an individual
pair style multiple times. The first is for pair styles implemented
as Fortran libraries: "pair_style meam"_pair_meam.html and "pair_style
reax"_pair_reax.html ("pair_style reax/c"_pair_reaxc.html is OK).
This is because unlike a C++ class, they can not be instantiated
multiple times, due to the manner in which they were coded in Fortran.
The second is for GPU-enabled pair styles in the GPU package. This is
b/c the GPU package also currently assumes that only one instance of a
pair style is being used.
In the pair_coeff commands, the name of a pair style must be added
after the I,J type specification, with the remaining coefficients
being those appropriate to that style. If the pair style is used
multiple times in the pair_style command, then an additional numeric
argument must also be specified which is a number from 1 to M where M
is the number of times the sub-style was listed in the pair style
command. The extra number indicates which instance of the sub-style
these coefficients apply to.
For example, consider a simulation with 3 atom types: types 1 and 2
are Ni atoms, type 3 are LJ atoms with charges. The following
commands would set up a hybrid simulation:
pair_style hybrid eam/alloy lj/cut/coul/cut 10.0 lj/cut 8.0
pair_coeff * * eam/alloy nialhjea Ni Ni NULL
pair_coeff 3 3 lj/cut/coul/cut 1.0 1.0
pair_coeff 1*2 3 lj/cut 0.8 1.3 :pre
As an example of using the same pair style multiple times, consider a
simulation with 2 atom types. Type 1 is Si, type 2 is C. The
following commands would model the Si atoms with Tersoff, the C atoms
with Tersoff, and the cross-interactions with Lennard-Jones:
pair_style hybrid lj/cut 2.5 tersoff tersoff
pair_coeff * * tersoff 1 Si.tersoff Si NULL
pair_coeff * * tersoff 2 C.tersoff NULL C
pair_coeff 1 2 lj/cut 1.0 1.5 :pre
If pair coefficients are specified in the data file read via the
"read_data"_read_data.html command, then the same rule applies.
E.g. "eam/alloy" or "lj/cut" must be added after the atom type, for
each line in the "Pair Coeffs" section, e.g.
Pair Coeffs :pre
1 lj/cut/coul/cut 1.0 1.0
... :pre
Note that the pair_coeff command for some potentials such as
"pair_style eam/alloy"_pair_eam.html includes a mapping specification
of elements to all atom types, which in the hybrid case, can include
atom types not assigned to the {eam/alloy} potential. The NULL
keyword is used by many such potentials (eam/alloy, Tersoff, AIREBO,
etc), to denote an atom type that will be assigned to a different
sub-style.
For the {hybrid} style, each atom type pair I,J is assigned to exactly
one sub-style. Just as with a simulation using a single pair style,
if you specify the same atom type pair in a second pair_coeff command,
the previous assignment will be overwritten.
For the {hybrid/overlay} style, each atom type pair I,J can be
assigned to one or more sub-styles. If you specify the same atom type
pair in a second pair_coeff command with a new sub-style, then the
second sub-style is added to the list of potentials that will be
calculated for two interacting atoms of those types. If you specify
the same atom type pair in a second pair_coeff command with a
sub-style that has already been defined for that pair of atoms, then
the new pair coefficients simply override the previous ones, as in the
normal usage of the pair_coeff command. E.g. these two sets of
commands are the same:
pair_style lj/cut 2.5
pair_coeff * * 1.0 1.0
pair_coeff 2 2 1.5 0.8 :pre
pair_style hybrid/overlay lj/cut 2.5
pair_coeff * * lj/cut 1.0 1.0
pair_coeff 2 2 lj/cut 1.5 0.8 :pre
Coefficients must be defined for each pair of atoms types via the
"pair_coeff"_pair_coeff.html command as described above, or in the
data file or restart files read by the "read_data"_read_data.html or
"read_restart"_read_restart.html commands, or by mixing as described
below.
For both the {hybrid} and {hybrid/overlay} styles, every atom type
pair I,J (where I <= J) must be assigned to at least one sub-style via
the "pair_coeff"_pair_coeff.html command as in the examples above, or
in the data file read by the "read_data"_read_data.html, or by mixing
as described below.
If you want there to be no interactions between a particular pair of
atom types, you have 3 choices. You can assign the type pair to some
sub-style and use the "neigh_modify exclude type"_neigh_modify.html
command. You can assign it to some sub-style and set the coefficients
so that there is effectively no interaction (e.g. epsilon = 0.0 in a
LJ potential). Or, for {hybrid} and {hybrid/overlay} simulations, you
can use this form of the pair_coeff command in your input script:
pair_coeff 2 3 none :pre
or this form in the "Pair Coeffs" section of the data file:
3 none :pre
If an assignment to {none} is made in a simulation with the
{hybrid/overlay} pair style, it wipes out all previous assignments of
that atom type pair to sub-styles.
Note that you may need to use an "atom_style"_atom_style.html hybrid
command in your input script, if atoms in the simulation will need
attributes from several atom styles, due to using multiple pair
potentials.
:line
Different force fields (e.g. CHARMM vs AMBER) may have different rules
for applying weightings that change the strength of pairwise
interactions between pairs of atoms that are also 1-2, 1-3, and 1-4
neighbors in the molecular bond topology, as normally set by the
"special_bonds"_special_bonds.html command. Different weights can be
assigned to different pair hybrid sub-styles via the "pair_modify
special"_pair_modify.html command. This allows multiple force fields
to be used in a model of a hybrid system, however, there is no consistent
approach to determine parameters automatically for the interactions
between the two force fields, this is only recommended when particles
described by the different force fields do not mix.
Here is an example for mixing CHARMM and AMBER: The global {amber}
setting sets the 1-4 interactions to non-zero scaling factors and
then overrides them with 0.0 only for CHARMM:
special_bonds amber
pair_hybrid lj/charmm/coul/long 8.0 10.0 lj/cut/coul/long 10.0
pair_modify pair lj/charmm/coul/long special lj/coul 0.0 0.0 0.0 :pre
The this input achieves the same effect:
special_bonds 0.0 0.0 0.1
pair_hybrid lj/charmm/coul/long 8.0 10.0 lj/cut/coul/long 10.0
pair_modify pair lj/cut/coul/long special lj 0.0 0.0 0.5
pair_modify pair lj/cut/coul/long special coul 0.0 0.0 0.83333333
pair_modify pair lj/charmm/coul/long special lj/coul 0.0 0.0 0.0 :pre
Here is an example for mixing Tersoff with OPLS/AA based on
a data file that defines bonds for all atoms where for the
Tersoff part of the system the force constants for the bonded
interactions have been set to 0. Note the global settings are
effectively {lj/coul 0.0 0.0 0.5} as required for OPLS/AA:
special_bonds lj/coul 1e-20 1e-20 0.5
pair_hybrid tersoff lj/cut/coul/long 12.0
pair_modify pair tersoff special lj/coul 1.0 1.0 1.0 :pre
For use with the various "compute */tally"_compute_tally.html
computes, the "pair_modify compute/tally"_pair_modify.html
command can be used to selectively turn off processing of
the compute tally styles, for example, if those pair styles
(e.g. manybody styles) do not support this feature.
See the "pair_modify"_pair_modify.html doc page for details on
the specific syntax, requirements and restrictions.
:line
The potential energy contribution to the overall system due to an
individual sub-style can be accessed and output via the "compute
pair"_compute_pair.html command.
:line
NOTE: Several of the potentials defined via the pair_style command in
LAMMPS are really many-body potentials, such as Tersoff, AIREBO, MEAM,
ReaxFF, etc. The way to think about using these potentials in a
hybrid setting is as follows.
A subset of atom types is assigned to the many-body potential with a
single "pair_coeff"_pair_coeff.html command, using "* *" to include
all types and the NULL keywords described above to exclude specific
types not assigned to that potential. If types 1,3,4 were assigned in
that way (but not type 2), this means that all many-body interactions
between all atoms of types 1,3,4 will be computed by that potential.
Pair_style hybrid allows interactions between type pairs 2-2, 1-2,
2-3, 2-4 to be specified for computation by other pair styles. You
could even add a second interaction for 1-1 to be computed by another
pair style, assuming pair_style hybrid/overlay is used.
But you should not, as a general rule, attempt to exclude the
many-body interactions for some subset of the type pairs within the
set of 1,3,4 interactions, e.g. exclude 1-1 or 1-3 interactions. That
is not conceptually well-defined for many-body interactions, since the
potential will typically calculate energies and foces for small groups
of atoms, e.g. 3 or 4 atoms, using the neighbor lists of the atoms to
find the additional atoms in the group. It is typically non-physical
to think of excluding an interaction between a particular pair of
atoms when the potential computes 3-body or 4-body interactions.
However, you can still use the pair_coeff none setting or the
"neigh_modify exclude"_neigh_modify.html command to exclude certain
type pairs from the neighbor list that will be passed to a manybody
sub-style. This will alter the calculations made by a many-body
potential, since it builds its list of 3-body, 4-body, etc
interactions from the pair list. You will need to think carefully as
to whether it produces a physically meaningful result for your model.
For example, imagine you have two atom types in your model, type 1 for
atoms in one surface, and type 2 for atoms in the other, and you wish
to use a Tersoff potential to compute interactions within each
surface, but not between surfaces. Then either of these two command
sequences would implement that model:
pair_style hybrid tersoff
pair_coeff * * tersoff SiC.tersoff C C
pair_coeff 1 2 none :pre
pair_style tersoff
pair_coeff * * SiC.tersoff C C
neigh_modify exclude type 1 2 :pre
Either way, only neighbor lists with 1-1 or 2-2 interactions would be
passed to the Tersoff potential, which means it would compute no
3-body interactions containing both type 1 and 2 atoms.
Here is another example, using hybrid/overlay, to use 2 many-body
potentials together, in an overlapping manner. Imagine you have CNT
(C atoms) on a Si surface. You want to use Tersoff for Si/Si and Si/C
interactions, and AIREBO for C/C interactions. Si atoms are type 1; C
atoms are type 2. Something like this will work:
pair_style hybrid/overlay tersoff airebo 3.0
pair_coeff * * tersoff SiC.tersoff.custom Si C
pair_coeff * * airebo CH.airebo NULL C :pre
Note that to prevent the Tersoff potential from computing C/C
interactions, you would need to modify the SiC.tersoff file to turn
off C/C interaction, i.e. by setting the appropriate coefficients to
0.0.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual.
Since the {hybrid} and {hybrid/overlay} styles delegate computation to
the individual sub-styles, the suffix versions of the {hybrid} and
{hybrid/overlay} styles are used to propagate the corresponding suffix
to all sub-styles, if those versions exist. Otherwise the
non-accelerated version will be used.
The individual accelerated sub-styles are part of the GPU,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the
"Making LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
Any pair potential settings made via the
"pair_modify"_pair_modify.html command are passed along to all
sub-styles of the hybrid potential.
For atom type pairs I,J and I != J, if the sub-style assigned to I,I
and J,J is the same, and if the sub-style allows for mixing, then the
coefficients for I,J can be mixed. This means you do not have to
specify a pair_coeff command for I,J since the I,J type pair will be
assigned automatically to the sub-style defined for both I,I and J,J
and its coefficients generated by the mixing rule used by that
sub-style. For the {hybrid/overlay} style, there is an additional
requirement that both the I,I and J,J pairs are assigned to a single
sub-style. See the "pair_modify" command for details of mixing rules.
See the See the doc page for the sub-style to see if allows for
mixing.
The hybrid pair styles supports the "pair_modify"_pair_modify.html
shift, table, and tail options for an I,J pair interaction, if the
associated sub-style supports it.
For the hybrid pair styles, the list of sub-styles and their
respective settings are written to "binary restart
files"_restart.html, so a "pair_style"_pair_style.html command does
not need to specified in an input script that reads a restart file.
However, the coefficient information is not stored in the restart
file. Thus, pair_coeff commands need to be re-specified in the
restart input script.
These pair styles support the use of the {inner}, {middle}, and
{outer} keywords of the "run_style respa"_run_style.html command, if
their sub-styles do.
[Restrictions:]
When using a long-range Coulombic solver (via the
"kspace_style"_kspace_style.html command) with a hybrid pair_style,
one or more sub-styles will be of the "long" variety,
e.g. {lj/cut/coul/long} or {buck/coul/long}. You must insure that the
short-range Coulombic cutoff used by each of these long pair styles is
the same or else LAMMPS will generate an error.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_lj.txt b/doc/src/pair_lj.txt
index 5c8e31ac4..058d54fb5 100644
--- a/doc/src/pair_lj.txt
+++ b/doc/src/pair_lj.txt
@@ -1,320 +1,320 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/cut command :h3
pair_style lj/cut/gpu command :h3
pair_style lj/cut/intel command :h3
pair_style lj/cut/kk command :h3
pair_style lj/cut/opt command :h3
pair_style lj/cut/omp command :h3
pair_style lj/cut/coul/cut command :h3
pair_style lj/cut/coul/cut/gpu command :h3
pair_style lj/cut/coul/cut/omp command :h3
pair_style lj/cut/coul/debye command :h3
pair_style lj/cut/coul/debye/gpu command :h3
pair_style lj/cut/coul/debye/kk command :h3
pair_style lj/cut/coul/debye/omp command :h3
pair_style lj/cut/coul/dsf command :h3
pair_style lj/cut/coul/dsf/gpu command :h3
pair_style lj/cut/coul/dsf/kk command :h3
pair_style lj/cut/coul/dsf/omp command :h3
pair_style lj/cut/coul/long command :h3
pair_style lj/cut/coul/long/cs command :h3
pair_style lj/cut/coul/long/gpu command :h3
pair_style lj/cut/coul/long/intel command :h3
pair_style lj/cut/coul/long/opt command :h3
pair_style lj/cut/coul/long/omp command :h3
pair_style lj/cut/coul/msm command :h3
pair_style lj/cut/coul/msm/gpu command :h3
pair_style lj/cut/coul/msm/omp command :h3
pair_style lj/cut/tip4p/cut command :h3
pair_style lj/cut/tip4p/cut/omp command :h3
pair_style lj/cut/tip4p/long command :h3
pair_style lj/cut/tip4p/long/omp command :h3
pair_style lj/cut/tip4p/long/opt command :h3
[Syntax:]
pair_style style args :pre
style = {lj/cut} or {lj/cut/coul/cut} or {lj/cut/coul/debye} or {lj/cut/coul/dsf} or {lj/cut/coul/long} or {lj/cut/coul/long/cs} or {lj/cut/coul/msm} or {lj/cut/tip4p/long}
args = list of arguments for a particular style :ul
{lj/cut} args = cutoff
cutoff = global cutoff for Lennard Jones interactions (distance units)
{lj/cut/coul/cut} args = cutoff (cutoff2)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/coul/debye} args = kappa cutoff (cutoff2)
kappa = inverse of the Debye length (inverse distance units)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/coul/dsf} args = alpha cutoff (cutoff2)
alpha = damping parameter (inverse distance units)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (distance units)
{lj/cut/coul/long} args = cutoff (cutoff2)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/coul/msm} args = cutoff (cutoff2)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/tip4p/cut} args = otype htype btype atype qdist cutoff (cutoff2)
otype,htype = atom types for TIP4P O and H
btype,atype = bond and angle types for TIP4P waters
qdist = distance from O atom to massless charge (distance units)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/tip4p/long} args = otype htype btype atype qdist cutoff (cutoff2)
otype,htype = atom types for TIP4P O and H
btype,atype = bond and angle types for TIP4P waters
qdist = distance from O atom to massless charge (distance units)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
[Examples:]
pair_style lj/cut 2.5
pair_coeff * * 1 1
pair_coeff 1 1 1 1.1 2.8 :pre
pair_style lj/cut/coul/cut 10.0
pair_style lj/cut/coul/cut 10.0 8.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0
pair_coeff 1 1 100.0 3.5 9.0 9.0 :pre
pair_style lj/cut/coul/debye 1.5 3.0
pair_style lj/cut/coul/debye 1.5 2.5 5.0
pair_coeff * * 1.0 1.0
pair_coeff 1 1 1.0 1.5 2.5
pair_coeff 1 1 1.0 1.5 2.5 5.0 :pre
pair_style lj/cut/coul/dsf 0.05 2.5 10.0
pair_coeff * * 1.0 1.0
pair_coeff 1 1 1.0 1.0 2.5 :pre
pair_style lj/cut/coul/long 10.0
pair_style lj/cut/coul/long/cs 10.0
pair_style lj/cut/coul/long 10.0 8.0
pair_style lj/cut/coul/long/cs 10.0 8.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
pair_style lj/cut/coul/msm 10.0
pair_style lj/cut/coul/msm 10.0 8.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
pair_style lj/cut/tip4p/cut 1 2 7 8 0.15 12.0
pair_style lj/cut/tip4p/cut 1 2 7 8 0.15 12.0 10.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
pair_style lj/cut/tip4p/long 1 2 7 8 0.15 12.0
pair_style lj/cut/tip4p/long 1 2 7 8 0.15 12.0 10.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
[Description:]
The {lj/cut} styles compute the standard 12/6 Lennard-Jones potential,
given by
:c,image(Eqs/pair_lj.jpg)
Rc is the cutoff.
Style {lj/cut/coul/cut} adds a Coulombic pairwise interaction given by
:c,image(Eqs/pair_coulomb.jpg)
where C is an energy-conversion constant, Qi and Qj are the charges on
the 2 atoms, and epsilon is the dielectric constant which can be set
by the "dielectric"_dielectric.html command. If one cutoff is
specified in the pair_style command, it is used for both the LJ and
Coulombic terms. If two cutoffs are specified, they are used as
cutoffs for the LJ and Coulombic terms respectively.
Style {lj/cut/coul/debye} adds an additional exp() damping factor
to the Coulombic term, given by
:c,image(Eqs/pair_debye.jpg)
where kappa is the inverse of the Debye length. This potential is
another way to mimic the screening effect of a polar solvent.
Style {lj/cut/coul/dsf} computes the Coulombic term via the damped
shifted force model described in "Fennell"_#Fennell2, given by:
:c,image(Eqs/pair_coul_dsf.jpg)
where {alpha} is the damping parameter and erfc() is the complementary
error-function. This potential is essentially a short-range,
spherically-truncated, charge-neutralized, shifted, pairwise {1/r}
summation. The potential is based on Wolf summation, proposed as an
alternative to Ewald summation for condensed phase systems where
charge screening causes electrostatic interactions to become
effectively short-ranged. In order for the electrostatic sum to be
absolutely convergent, charge neutralization within the cutoff radius
is enforced by shifting the potential through placement of image
charges on the cutoff sphere. Convergence can often be improved by
setting {alpha} to a small non-zero value.
Styles {lj/cut/coul/long} and {lj/cut/coul/msm} compute the same
Coulombic interactions as style {lj/cut/coul/cut} except that an
additional damping factor is applied to the Coulombic term so it can
be used in conjunction with the "kspace_style"_kspace_style.html
command and its {ewald} or {pppm} option. The Coulombic cutoff
specified for this style means that pairwise interactions within this
distance are computed directly; interactions outside that distance are
computed in reciprocal space.
Style {lj/cut/coul/long/cs} is identical to {lj/cut/coul/long} except
that a term is added for the "core/shell
model"_Section_howto.html#howto_25 to allow charges on core and shell
particles to be separated by r = 0.0.
Styles {lj/cut/tip4p/cut} and {lj/cut/tip4p/long} implement the TIP4P
water model of "(Jorgensen)"_#Jorgensen2, which introduces a massless
site located a short distance away from the oxygen atom along the
bisector of the HOH angle. The atomic types of the oxygen and
hydrogen atoms, the bond and angle types for OH and HOH interactions,
and the distance to the massless charge site are specified as
pair_style arguments. Style {lj/cut/tip4p/cut} uses a cutoff for
Coulomb interactions; style {lj/cut/tip4p/long} is for use with a
long-range Coulombic solver (Ewald or PPPM).
NOTE: For each TIP4P water molecule in your system, the atom IDs for
the O and 2 H atoms must be consecutive, with the O atom first. This
is to enable LAMMPS to "find" the 2 H atoms associated with each O
atom. For example, if the atom ID of an O atom in a TIP4P water
molecule is 500, then its 2 H atoms must have IDs 501 and 502.
See the "howto section"_Section_howto.html#howto_8 for more
information on how to use the TIP4P pair styles and lists of
parameters to set. Note that the neighbor list cutoff for Coulomb
interactions is effectively extended by a distance 2*qdist when using
the TIP4P pair style, to account for the offset distance of the
fictitious charges on O atoms in water molecules. Thus it is
typically best in an efficiency sense to use a LJ cutoff >= Coulomb
cutoff + 2*qdist, to shrink the size of the neighbor list. This leads
to slightly larger cost for the long-range calculation, so you can
test the trade-off for your model.
For all of the {lj/cut} pair styles, the following coefficients must
be defined for each pair of atoms types via the
"pair_coeff"_pair_coeff.html command as in the examples above, or in
the data file or restart files read by the "read_data"_read_data.html
or "read_restart"_read_restart.html commands, or by mixing as
described below:
epsilon (energy units)
sigma (distance units)
cutoff1 (distance units)
cutoff2 (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum at 2^(1/6)
sigma.
The latter 2 coefficients are optional. If not specified, the global
LJ and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both LJ
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the LJ and Coulombic cutoffs for this
type pair. You cannot specify 2 cutoffs for style {lj/cut}, since it
has no Coulombic terms.
For {lj/cut/coul/long} and {lj/cut/coul/msm} and {lj/cut/tip4p/cut}
and {lj/cut/tip4p/long} only the LJ cutoff can be specified since a
Coulombic cutoff cannot be specified for an individual I,J type pair.
All type pairs use the same global Coulombic cutoff specified in the
pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/cut pair styles can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
All of the {lj/cut} pair styles support the
"pair_modify"_pair_modify.html shift option for the energy of the
Lennard-Jones portion of the pair interaction.
The {lj/cut/coul/long} and {lj/cut/tip4p/long} pair styles support the
"pair_modify"_pair_modify.html table option since they can tabulate
the short-range portion of the long-range Coulombic interaction.
All of the {lj/cut} pair styles support the
"pair_modify"_pair_modify.html tail option for adding a long-range
tail correction to the energy and pressure for the Lennard-Jones
portion of the pair interaction.
All of the {lj/cut} pair styles write their information to "binary
restart files"_restart.html, so pair_style and pair_coeff commands do
not need to be specified in an input script that reads a restart file.
The {lj/cut} and {lj/cut/coul/long} pair styles support the use of the
{inner}, {middle}, and {outer} keywords of the "run_style
respa"_run_style.html command, meaning the pairwise forces can be
partitioned by distance at different levels of the rRESPA hierarchy.
The other styles only support the {pair} keyword of run_style respa.
See the "run_style"_run_style.html command for details.
:line
[Restrictions:]
The {lj/cut/coul/long} and {lj/cut/tip4p/long} styles are part of the
KSPACE package. The {lj/cut/tip4p/cut} style is part of the MOLECULE
package. These styles are only enabled if LAMMPS was built with those
packages. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info. Note that the KSPACE and MOLECULE packages are
installed by default.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Jorgensen2)
[(Jorgensen)] Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem
Phys, 79, 926 (1983).
:link(Fennell2)
[(Fennell)] C. J. Fennell, J. D. Gezelter, J Chem Phys, 124,
234104 (2006).
diff --git a/doc/src/pair_lj96.txt b/doc/src/pair_lj96.txt
index 6e7c3cbae..83f6ec063 100644
--- a/doc/src/pair_lj96.txt
+++ b/doc/src/pair_lj96.txt
@@ -1,107 +1,107 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj96/cut command :h3
pair_style lj96/cut/gpu command :h3
pair_style lj96/cut/omp command :h3
[Syntax:]
pair_style lj96/cut cutoff :pre
cutoff = global cutoff for lj96/cut interactions (distance units) :ul
[Examples:]
pair_style lj96/cut 2.5
pair_coeff * * 1.0 1.0 4.0
pair_coeff 1 1 1.0 1.0 :pre
[Description:]
The {lj96/cut} style compute a 9/6 Lennard-Jones potential, instead
of the standard 12/6 potential, given by
:c,image(Eqs/pair_lj96.jpg)
Rc is the cutoff.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global LJ
cutoff specified in the pair_style command is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/cut pair styles can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style supports the "pair_modify"_pair_modify.html tail
option for adding a long-range tail correction to the energy and
pressure of the pair interaction.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style supports the use of the {inner}, {middle}, and {outer}
keywords of the "run_style respa"_run_style.html command, meaning the
pairwise forces can be partitioned by distance at different levels of
the rRESPA hierarchy. See the "run_style"_run_style.html command for
details.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_lj_cubic.txt b/doc/src/pair_lj_cubic.txt
index d33e3ec09..4ca8c3c14 100644
--- a/doc/src/pair_lj_cubic.txt
+++ b/doc/src/pair_lj_cubic.txt
@@ -1,129 +1,129 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/cubic command :h3
pair_style lj/cubic/gpu command :h3
pair_style lj/cubic/omp command :h3
[Syntax:]
pair_style lj/cubic :pre
[Examples:]
pair_style lj/cubic
pair_coeff * * 1.0 0.8908987 :pre
[Description:]
The {lj/cubic} style computes a truncated LJ interaction potential
whose energy and force are continuous everywhere. Inside the
inflection point the interaction is identical to the standard 12/6
"Lennard-Jones"_pair_lj.html potential. The LJ function outside the
inflection point is replaced with a cubic function of distance. The
energy, force, and second derivative are continuous at the inflection
point. The cubic coefficient A3 is chosen so that both energy and
force go to zero at the cutoff distance. Outside the cutoff distance
the energy and force are zero.
:c,image(Eqs/pair_lj_cubic.jpg)
The location of the inflection point rs is defined
by the LJ diameter, rs/sigma = (26/7)^1/6. The cutoff distance
is defined by rc/rs = 67/48 or rc/sigma = 1.737....
The analytic expression for the
the cubic coefficient
A3*rmin^3/epsilon = 27.93... is given in the paper by
Holian and Ravelo "(Holian)"_#Holian.
This potential is commonly used to study the shock mechanics of FCC
solids, as in Ravelo et al. "(Ravelo)"_#Ravelo2.
The following coefficients must be defined for each pair of atom types
via the "pair_coeff"_pair_coeff.html command as in the example above,
or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum, which is
located at rmin = 2^(1/6)*sigma. In the above example, sigma =
0.8908987, so rmin = 1.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/cut pair styles can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
The lj/cubic pair style does not support the
"pair_modify"_pair_modify.html shift option,
since pair interaction is already smoothed to 0.0 at the
cutoff.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
The lj/cubic pair style does not support the
"pair_modify"_pair_modify.html tail option for adding long-range tail
corrections to energy and pressure, since there are no corrections for
a potential that goes to 0.0 at the cutoff.
The lj/cubic pair style writes its information to "binary
restart files"_restart.html, so pair_style and pair_coeff commands do
not need to be specified in an input script that reads a restart file.
The lj/cubic pair style can only be used via the {pair}
keyword of the "run_style respa"_run_style.html command. It does not
support the {inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Holian)
[(Holian)] Holian and Ravelo, Phys Rev B, 51, 11275 (1995).
:link(Ravelo2)
[(Ravelo)] Ravelo, Holian, Germann and Lomdahl, Phys Rev B, 70, 014103 (2004).
diff --git a/doc/src/pair_lj_expand.txt b/doc/src/pair_lj_expand.txt
index c5f0c88a7..e0838426f 100644
--- a/doc/src/pair_lj_expand.txt
+++ b/doc/src/pair_lj_expand.txt
@@ -1,111 +1,111 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/expand command :h3
pair_style lj/expand/gpu command :h3
pair_style lj/expand/omp command :h3
[Syntax:]
pair_style lj/expand cutoff :pre
cutoff = global cutoff for lj/expand interactions (distance units) :ul
[Examples:]
pair_style lj/expand 2.5
pair_coeff * * 1.0 1.0 0.5
pair_coeff 1 1 1.0 1.0 -0.2 2.0 :pre
[Description:]
Style {lj/expand} computes a LJ interaction with a distance shifted by
delta which can be useful when particles are of different sizes, since
it is different that using different sigma values in a standard LJ
formula:
:c,image(Eqs/pair_lj_expand.jpg)
Rc is the cutoff which does not include the delta distance. I.e. the
actual force cutoff is the sum of cutoff + delta.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
delta (distance units)
cutoff (distance units) :ul
The delta values can be positive or negative. The last coefficient is
optional. If not specified, the global LJ cutoff is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon, sigma, and shift
coefficients and cutoff distance for this pair style can be mixed.
Shift is always mixed via an {arithmetic} rule. The other
coefficients are mixed according to the pair_modify mix value. The
default mix value is {geometric}. See the "pair_modify" command for
details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style supports the "pair_modify"_pair_modify.html tail
option for adding a long-range tail correction to the energy and
pressure of the pair interaction.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_lj_long.txt b/doc/src/pair_lj_long.txt
index da9f37b9c..6be4562d1 100644
--- a/doc/src/pair_lj_long.txt
+++ b/doc/src/pair_lj_long.txt
@@ -1,230 +1,230 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/long/coul/long command :h3
pair_style lj/long/coul/long/intel command :h3
pair_style lj/long/coul/long/omp command :h3
pair_style lj/long/coul/long/opt command :h3
pair_style lj/long/tip4p/long command :h3
[Syntax:]
pair_style style args :pre
style = {lj/long/coul/long} or {lj/long/tip4p/long}
args = list of arguments for a particular style :ul
{lj/long/coul/long} args = flag_lj flag_coul cutoff (cutoff2)
flag_lj = {long} or {cut} or {off}
{long} = use Kspace long-range summation for dispersion 1/r^6 term
{cut} = use a cutoff on dispersion 1/r^6 term
{off} = omit disperion 1/r^6 term entirely
flag_coul = {long} or {off}
{long} = use Kspace long-range summation for Coulombic 1/r term
{off} = omit Coulombic term
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/long/tip4p/long} args = flag_lj flag_coul otype htype btype atype qdist cutoff (cutoff2)
flag_lj = {long} or {cut}
{long} = use Kspace long-range summation for dispersion 1/r^6 term
{cut} = use a cutoff
flag_coul = {long} or {off}
{long} = use Kspace long-range summation for Coulombic 1/r term
{off} = omit Coulombic term
otype,htype = atom types for TIP4P O and H
btype,atype = bond and angle types for TIP4P waters
qdist = distance from O atom to massless charge (distance units)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
[Examples:]
pair_style lj/long/coul/long cut off 2.5
pair_style lj/long/coul/long cut long 2.5 4.0
pair_style lj/long/coul/long long long 2.5 4.0
pair_coeff * * 1 1
pair_coeff 1 1 1 3 4 :pre
pair_style lj/long/tip4p/long long long 1 2 7 8 0.15 12.0
pair_style lj/long/tip4p/long long long 1 2 7 8 0.15 12.0 10.0
pair_coeff * * 100.0 3.0
pair_coeff 1 1 100.0 3.5 9.0 :pre
[Description:]
Style {lj/long/coul/long} computes the standard 12/6 Lennard-Jones and
Coulombic potentials, given by
:c,image(Eqs/pair_lj.jpg)
:c,image(Eqs/pair_coulomb.jpg)
where C is an energy-conversion constant, Qi and Qj are the charges on
the 2 atoms, epsilon is the dielectric constant which can be set by
the "dielectric"_dielectric.html command, and Rc is the cutoff. If
one cutoff is specified in the pair_style command, it is used for both
the LJ and Coulombic terms. If two cutoffs are specified, they are
used as cutoffs for the LJ and Coulombic terms respectively.
The purpose of this pair style is to capture long-range interactions
resulting from both attractive 1/r^6 Lennard-Jones and Coulombic 1/r
interactions. This is done by use of the {flag_lj} and {flag_coul}
settings. The "In 't Veld"_#Veld2 paper has more details on when it is
appropriate to include long-range 1/r^6 interactions, using this
potential.
Style {lj/long/tip4p/long} implements the TIP4P water model of
"(Jorgensen)"_#Jorgensen4, which introduces a massless site located a
short distance away from the oxygen atom along the bisector of the HOH
angle. The atomic types of the oxygen and hydrogen atoms, the bond
and angle types for OH and HOH interactions, and the distance to the
massless charge site are specified as pair_style arguments.
NOTE: For each TIP4P water molecule in your system, the atom IDs for
the O and 2 H atoms must be consecutive, with the O atom first. This
is to enable LAMMPS to "find" the 2 H atoms associated with each O
atom. For example, if the atom ID of an O atom in a TIP4P water
molecule is 500, then its 2 H atoms must have IDs 501 and 502.
See the "howto section"_Section_howto.html#howto_8 for more
information on how to use the TIP4P pair style. Note that the
neighbor list cutoff for Coulomb interactions is effectively extended
by a distance 2*qdist when using the TIP4P pair style, to account for
the offset distance of the fictitious charges on O atoms in water
molecules. Thus it is typically best in an efficiency sense to use a
LJ cutoff >= Coulomb cutoff + 2*qdist, to shrink the size of the
neighbor list. This leads to slightly larger cost for the long-range
calculation, so you can test the trade-off for your model.
If {flag_lj} is set to {long}, no cutoff is used on the LJ 1/r^6
dispersion term. The long-range portion can be calculated by using
the "kspace_style ewald/disp or pppm/disp"_kspace_style.html commands.
The specified LJ cutoff then determines which portion of the LJ
interactions are computed directly by the pair potential versus which
part is computed in reciprocal space via the Kspace style. If
{flag_lj} is set to {cut}, the LJ interactions are simply cutoff, as
with "pair_style lj/cut"_pair_lj.html.
If {flag_coul} is set to {long}, no cutoff is used on the Coulombic
interactions. The long-range portion can calculated by using any of
several "kspace_style"_kspace_style.html command options such as
{pppm} or {ewald}. Note that if {flag_lj} is also set to long, then
the {ewald/disp} or {pppm/disp} Kspace style needs to be used to
perform the long-range calculations for both the LJ and Coulombic
interactions. If {flag_coul} is set to {off}, Coulombic interactions
are not computed.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
cutoff1 (distance units)
cutoff2 (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum at 2^(1/6)
sigma.
The latter 2 coefficients are optional. If not specified, the global
LJ and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both LJ
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the LJ and Coulombic cutoffs for this
type pair.
Note that if you are using {flag_lj} set to {long}, you
cannot specify a LJ cutoff for an atom type pair, since only one
global LJ cutoff is allowed. Similarly, if you are using {flag_coul}
set to {long}, you cannot specify a Coulombic cutoff for an atom type
pair, since only one global Coulombic cutoff is allowed.
For {lj/long/tip4p/long} only the LJ cutoff can be specified
since a Coulombic cutoff cannot be specified for an individual I,J
type pair. All type pairs use the same global Coulombic cutoff
specified in the pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/long pair styles can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
These pair styles support the "pair_modify"_pair_modify.html shift
option for the energy of the Lennard-Jones portion of the pair
interaction, assuming {flag_lj} is {cut}.
These pair styles support the "pair_modify"_pair_modify.html table and
table/disp options since they can tabulate the short-range portion of
the long-range Coulombic and dispersion interactions.
Thes pair styles do not support the "pair_modify"_pair_modify.html
tail option for adding a long-range tail correction to the
Lennard-Jones portion of the energy and pressure.
These pair styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
The pair lj/long/coul/long styles support the use of the {inner},
{middle}, and {outer} keywords of the "run_style respa"_run_style.html
command, meaning the pairwise forces can be partitioned by distance at
different levels of the rRESPA hierarchy. See the
"run_style"_run_style.html command for details.
:line
[Restrictions:]
These styles are part of the KSPACE package. They are only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info. Note that
the KSPACE package is installed by default.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Veld2)
[(In 't Veld)] In 't Veld, Ismail, Grest, J Chem Phys (accepted) (2007).
:link(Jorgensen4)
[(Jorgensen)] Jorgensen, Chandrasekhar, Madura, Impey, Klein, J Chem
Phys, 79, 926 (1983).
diff --git a/doc/src/pair_lj_smooth.txt b/doc/src/pair_lj_smooth.txt
index 133773abd..b1678cad5 100644
--- a/doc/src/pair_lj_smooth.txt
+++ b/doc/src/pair_lj_smooth.txt
@@ -1,122 +1,122 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/smooth command :h3
pair_style lj/smooth/omp command :h3
[Syntax:]
pair_style lj/smooth Rin Rc :pre
Rin = inner cutoff beyond which force smoothing will be applied (distance units)
Rc = outer cutoff for lj/smooth interactions (distance units) :ul
[Examples:]
pair_style lj/smooth 8.0 10.0
pair_coeff * * 10.0 1.5
pair_coeff 1 1 20.0 1.3 7.0 9.0 :pre
[Description:]
Style {lj/smooth} computes a LJ interaction with a force smoothing
applied between the inner and outer cutoff.
:c,image(Eqs/pair_lj_smooth.jpg)
The polynomial coefficients C1, C2, C3, C4 are computed by LAMMPS to
cause the force to vary smoothly from the inner cutoff Rin to the
outer cutoff Rc.
At the inner cutoff the force and its 1st derivative
will match the unsmoothed LJ formula. At the outer cutoff the force
and its 1st derivative will be 0.0. The inner cutoff cannot be 0.0.
NOTE: this force smoothing causes the energy to be discontinuous both
in its values and 1st derivative. This can lead to poor energy
conservation and may require the use of a thermostat. Plot the energy
and force resulting from this formula via the
"pair_write"_pair_write.html command to see the effect.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
inner (distance units)
outer (distance units) :ul
The last 2 coefficients are optional inner and outer cutoffs. If not
specified, the global values for Rin and Rc are used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon, sigma, Rin
coefficients and the cutoff distance for this pair style can be mixed.
Rin is a cutoff value and is mixed like the cutoff. The other
coefficients are mixed according to the pair_modify mix option. The
default mix value is {geometric}. See the "pair_modify" command for
details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure, since the energy of the pair interaction is smoothed to 0.0
at the cutoff.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair
lj/smooth/linear"_pair_lj_smooth_linear.html
[Default:] none
diff --git a/doc/src/pair_lj_smooth_linear.txt b/doc/src/pair_lj_smooth_linear.txt
index a48c441f5..5f7c226ce 100644
--- a/doc/src/pair_lj_smooth_linear.txt
+++ b/doc/src/pair_lj_smooth_linear.txt
@@ -1,111 +1,111 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/smooth/linear command :h3
pair_style lj/smooth/linear/omp command :h3
[Syntax:]
pair_style lj/smooth/linear cutoff :pre
cutoff = global cutoff for Lennard-Jones interactions (distance units) :ul
[Examples:]
pair_style lj/smooth/linear 2.5
pair_coeff * * 1.0 1.0
pair_coeff 1 1 0.3 3.0 9.0 :pre
[Description:]
Style {lj/smooth/linear} computes a truncated and force-shifted LJ
interaction (aka Shifted Force Lennard-Jones) that combines the
standard 12/6 Lennard-Jones function and subtracts a linear term based
on the cutoff distance, so that both, the potential and the force, go
continuously to zero at the cutoff Rc "(Toxvaerd)"_#Toxvaerd:
:c,image(Eqs/pair_lj_smooth_linear.jpg)
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global
LJ cutoff specified in the pair_style command is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance can be mixed. The default mix value is geometric.
See the "pair_modify" command for details.
This pair style does not support the "pair_modify"_pair_modify.html
shift option for the energy of the pair interaction, since it goes
to 0.0 at the cutoff by construction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure, since the energy of the pair interaction is smoothed to 0.0
at the cutoff.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair lj/smooth"_pair_lj_smooth.html
[Default:] none
:line
:link(Toxvaerd)
[(Toxvaerd)] Toxvaerd, Dyre, J Chem Phys, 134, 081102 (2011).
diff --git a/doc/src/pair_lj_soft.txt b/doc/src/pair_lj_soft.txt
index e372092cf..2ef133da5 100644
--- a/doc/src/pair_lj_soft.txt
+++ b/doc/src/pair_lj_soft.txt
@@ -1,278 +1,278 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/cut/soft command :h3
pair_style lj/cut/soft/omp command :h3
pair_style lj/cut/coul/cut/soft command :h3
pair_style lj/cut/coul/cut/soft/omp command :h3
pair_style lj/cut/coul/long/soft command :h3
pair_style lj/cut/coul/long/soft/omp command :h3
pair_style lj/cut/tip4p/long/soft command :h3
pair_style lj/cut/tip4p/long/soft/omp command :h3
pair_style lj/charmm/coul/long/soft command :h3
pair_style lj/charmm/coul/long/soft/omp command :h3
pair_style coul/cut/soft command :h3
pair_style coul/cut/soft/omp command :h3
pair_style coul/long/soft command :h3
pair_style coul/long/soft/omp command :h3
pair_style tip4p/long/soft command :h3
pair_style tip4p/long/soft/omp command :h3
[Syntax:]
pair_style style args :pre
style = {lj/cut/soft} or {lj/cut/coul/cut/soft} or {lj/cut/coul/long/soft} or {lj/cut/tip4p/long/soft} or {lj/charmm/coul/long/soft} or {coul/cut/soft} or {coul/long/soft} or {tip4p/long/soft}
args = list of arguments for a particular style :ul
{lj/cut/soft} args = n alpha_lj cutoff
n, alpha_LJ = parameters of soft-core potential
cutoff = global cutoff for Lennard-Jones interactions (distance units)
{lj/cut/coul/cut/soft} args = n alpha_LJ alpha_C cutoff (cutoff2)
n, alpha_LJ, alpha_C = parameters of soft-core potential
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/coul/long/soft} args = n alpha_LJ alpha_C cutoff
n, alpha_LJ, alpha_C = parameters of the soft-core potential
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/cut/tip4p/long/soft} args = otype htype btype atype qdist n alpha_LJ alpha_C cutoff (cutoff2)
otype,htype = atom types for TIP4P O and H
btype,atype = bond and angle types for TIP4P waters
qdist = distance from O atom to massless charge (distance units)
n, alpha_LJ, alpha_C = parameters of the soft-core potential
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{lj/charmm/coul/long/soft} args = n alpha_LJ alpha_C inner outer (cutoff)
n, alpha_LJ, alpha_C = parameters of the soft-core potential
inner, outer = global switching cutoffs for LJ (and Coulombic if only 5 args)
cutoff = global cutoff for Coulombic (optional, outer is Coulombic cutoff if only 5 args)
{coul/cut/soft} args = n alpha_C cutoff
n, alpha_C = parameters of the soft-core potential
cutoff = global cutoff for Coulomb interactions (distance units)
{coul/long/soft} args = n alpha_C cutoff
n, alpha_C = parameters of the soft-core potential
cutoff = global cutoff for Coulomb interactions (distance units)
{tip4p/long/soft} args = otype htype btype atype qdist n alpha_C cutoff
otype,htype = atom types for TIP4P O and H
btype,atype = bond and angle types for TIP4P waters
qdist = distance from O atom to massless charge (distance units)
n, alpha_C = parameters of the soft-core potential
cutoff = global cutoff for Coulomb interactions (distance units)
:pre
[Examples:]
pair_style lj/cut/soft 2.0 0.5 9.5
pair_coeff * * 0.28 3.1 1.0
pair_coeff 1 1 0.28 3.1 1.0 9.5 :pre
pair_style lj/cut/coul/cut/soft 2.0 0.5 10.0 9.5
pair_style lj/cut/coul/cut/soft 2.0 0.5 10.0 9.5 9.5
pair_coeff * * 0.28 3.1 1.0
pair_coeff 1 1 0.28 3.1 0.5 10.0
pair_coeff 1 1 0.28 3.1 0.5 10.0 9.5 :pre
pair_style lj/cut/coul/long/soft 2.0 0.5 10.0 9.5
pair_style lj/cut/coul/long/soft 2.0 0.5 10.0 9.5 9.5
pair_coeff * * 0.28 3.1 1.0
pair_coeff 1 1 0.28 3.1 0.0 10.0
pair_coeff 1 1 0.28 3.1 0.0 10.0 9.5 :pre
pair_style lj/cut/tip4p/long/soft 1 2 7 8 0.15 2.0 0.5 10.0 9.8
pair_style lj/cut/tip4p/long/soft 1 2 7 8 0.15 2.0 0.5 10.0 9.8 9.5
pair_coeff * * 0.155 3.1536 1.0
pair_coeff 1 1 0.155 3.1536 1.0 9.5 :pre
pair_style lj/charmm/coul/long 2.0 0.5 10.0 8.0 10.0
pair_style lj/charmm/coul/long 2.0 0.5 10.0 8.0 10.0 9.0
pair_coeff * * 0.28 3.1 1.0
pair_coeff 1 1 0.28 3.1 1.0 0.14 3.1 :pre
pair_style coul/long/soft 1.0 10.0 9.5
pair_coeff * * 1.0
pair_coeff 1 1 1.0 9.5 :pre
pair_style tip4p/long/soft 1 2 7 8 0.15 2.0 0.5 10.0 9.8
pair_coeff * * 1.0
pair_coeff 1 1 1.0 9.5 :pre
[Description:]
The {lj/cut/soft} style and substyles compute the 12/6 Lennard-Jones
and Coulomb potential modified by a soft core, in order to avoid
singularities during free energy calculations when sites are created
or annihilated "(Beutler)"_#Beutler,
:c,image(Eqs/pair_lj_soft.jpg)
Coulomb interactions are also damped with a soft core at short
distance,
:c,image(Eqs/pair_coul_soft.jpg)
In the Coulomb part C is an energy-conversion constant, q_i and q_j
are the charges on the 2 atoms, and epsilon is the dielectric constant
which can be set by the "dielectric"_dielectric.html command.
The coefficient lambda is an activation parameter. When lambda = 1 the
pair potential is identical to a Lennard-Jones term or a Coulomb term
or a combination of both. When lambda = 0 the interactions are
deactivated. The transition between these two extrema is smoothed by a
soft repulsive core in order to avoid singularities in potential
energy and forces when sites are created or annihilated and can overlap
"(Beutler)"_#Beutler.
The parameters n, alpha_LJ and alpha_C are set in the
"pair_style"_pair_style.html command, before the cutoffs. Usual
choices for the exponent are n = 2 or n = 1. For the remaining
coefficients alpha_LJ = 0.5 and alpha_C = 10 Angstrom^2 are
appropriate choices. Plots of the LJ and Coulomb terms are shown
below, for lambda ranging from 1 to 0 every 0.1.
:image(JPG/lj_soft.jpg),image(JPG/coul_soft.jpg)
:c
For the {lj/cut/coul/cut/soft} or {lj/cut/coul/long/soft} pair styles,
the following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
epsilon (energy units)
sigma (distance units)
lambda (activation parameter between 0 and 1)
cutoff1 (distance units)
cutoff2 (distance units) :ul
The latter two coefficients are optional. If not specified, the global
LJ and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both LJ
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the LJ and Coulombic cutoffs for this
type pair. You cannot specify 2 cutoffs for style {lj/cut/soft},
since it has no Coulombic terms. For the {coul/cut/soft} and
{coul/long/soft} only lambda and the optional cutoff2 are to be
specified.
Style {lj/cut/tip4p/long/soft} implements a soft-core version of the
TIP4P water model. The usage of this pair style is documented in the
"pair_lj"_pair_lj.html styles. The soft-core version introduces the
lambda parameter to the list of arguments, after epsilon and sigma in
the "pair_coeff"_pair_coeff.html command. The parameters n, alpha_LJ
and alpha_C are set in the "pair_style"_pair_style.html command,
before the cutoffs.
Style {lj/charmm/coul/long/soft} implements a soft-core version of the
CHARMM version of LJ interactions with an additional switching
function S(r) that ramps the energy and force smoothly to zero between
an inner and outer cutoff. The usage of this pair style is documented
in the "pair_charmm"_pair_charmm.html styles. The soft-core version
introduces the lambda parameter to the list of arguments, after
epsilon and sigma in the "pair_coeff"_pair_coeff.html command (and
before the optional eps14 and sigma14). The parameters n,
alpha_LJ and alpha_C are set in the "pair_style"_pair_style.html
command, before the cutoffs.
The {coul/cut/soft}, {coul/long/soft} and {tip4p/long/soft} substyles
are designed to be combined with other pair potentials via the
"pair_style hybrid/overlay"_pair_hybrid.html command. This is because
they have no repulsive core. Hence, if used by themselves, there will
be no repulsion to keep two oppositely charged particles from
overlapping each other. In this case, if lambda = 1, a singularity may
occur. These substyles are suitable to represent charges embedded in
the Lennard-Jones radius of another site (for example hydrogen atoms
in several water models).
NOTES: When using the core-softed Coulomb potentials with long-range
solvers ({coul/long/soft}, {lj/cut/coul/long/soft}, etc.) in a free
energy calculation in which sites holding electrostatic charges are
being created or annihilated (using "fix adapt/fep"_fix_adapt_fep.html
and "compute fep"_compute_fep.html) it is important to adapt both the
lambda activation parameter (from 0 to 1, or the reverse) and the
value of the charge (from 0 to its final value, or the reverse). This
ensures that long-range electrostatic terms (kspace) are correct. It
is not necessary to use core-softed Coulomb potentials if the van der
Waals site is present during the free-energy route, thus avoiding
overlap of the charges. Examples are provided in the LAMMPS source
directory tree, under examples/USER/fep.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, tail correction, restart info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for this pair style can be mixed.
The default mix value is {geometric}. See the "pair_modify" command
for details.
These pair styles support the "pair_modify"_pair_modify.html shift
option for the energy of the Lennard-Jones portion of the pair
interaction.
These pair styles support the "pair_modify"_pair_modify.html tail
option for adding a long-range tail correction to the energy and
pressure for the Lennard-Jones portion of the pair interaction.
These pair styles write information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
:line
[Restrictions:]
To avoid division by zero do not set sigma = 0; use the lambda
parameter instead to activate/deactivate interactions, or use
epsilon = 0 and sigma = 1. Alternatively, when sites do not
interact though the Lennard-Jones term the {coul/long/soft} or
similar substyle can be used via the
"pair_style hybrid/overlay"_pair_hybrid.html command.
:line
All of the plain {soft} pair styles are part of the USER-FEP package.
The {long} styles also requires the KSPACE package to be installed.
They are only enabled if LAMMPS was built with those packages. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix adapt"_fix_adapt.html,
"fix adapt/fep"_fix_adapt_fep.html, "compute fep"_compute_fep.html
[Default:] none
:line
:link(Beutler)
[(Beutler)] Beutler, Mark, van Schaik, Gerber, van Gunsteren, Chem
Phys Lett, 222, 529 (1994).
diff --git a/doc/src/pair_lubricate.txt b/doc/src/pair_lubricate.txt
index 501a04380..b39c7545c 100644
--- a/doc/src/pair_lubricate.txt
+++ b/doc/src/pair_lubricate.txt
@@ -1,228 +1,228 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lubricate command :h3
pair_style lubricate/omp command :h3
pair_style lubricate/poly command :h3
pair_style lubricate/poly/omp command :h3
[Syntax:]
pair_style style mu flaglog flagfld cutinner cutoff flagHI flagVF :pre
style = {lubricate} or {lubricate/poly}
mu = dynamic viscosity (dynamic viscosity units)
flaglog = 0/1 to exclude/include log terms in the lubrication approximation
flagfld = 0/1 to exclude/include Fast Lubrication Dynamics (FLD) effects
cutinner = inner cutoff distance (distance units)
cutoff = outer cutoff for interactions (distance units)
flagHI (optional) = 0/1 to exclude/include 1/r hydrodynamic interactions
flagVF (optional) = 0/1 to exclude/include volume fraction corrections in the long-range isotropic terms :ul
[Examples:] (all assume radius = 1)
pair_style lubricate 1.5 1 1 2.01 2.5
pair_coeff 1 1 2.05 2.8
pair_coeff * * :pre
pair_style lubricate 1.5 1 1 2.01 2.5
pair_coeff * *
variable mu equal ramp(1,2)
fix 1 all adapt 1 pair lubricate mu * * v_mu :pre
[Description:]
Styles {lubricate} and {lubricate/poly} compute hydrodynamic
interactions between mono-disperse finite-size spherical particles in
a pairwise fashion. The interactions have 2 components. The first is
Ball-Melrose lubrication terms via the formulas in "(Ball and
Melrose)"_#Ball1
:c,image(Eqs/pair_lubricate.jpg)
which represents the dissipation W between two nearby particles due to
their relative velocities in the presence of a background solvent with
viscosity {mu}. Note that this is dynamic viscosity which has units of
mass/distance/time, not kinematic viscosity.
The Asq (squeeze) term is the strongest and is included if {flagHI} is
set to 1 (default). It scales as 1/gap where gap is the separation
between the surfaces of the 2 particles. The Ash (shear) and Apu
(pump) terms are only included if {flaglog} is set to 1. They are the
next strongest interactions, and the only other singular interaction,
and scale as log(gap). Note that {flaglog} = 1 and {flagHI} = 0 is
invalid, and will result in a warning message, after which {flagHI} will
be set to 1. The Atw (twist) term is currently not included. It is
typically a very small contribution to the lubrication forces.
The {flagHI} and {flagVF} settings are optional. Neither should be
used, or both must be defined.
{Cutinner} sets the minimum center-to-center separation that will be
used in calculations irrespective of the actual separation. {Cutoff}
is the maximum center-to-center separation at which an interaction is
computed. Using a {cutoff} less than 3 radii is recommended if
{flaglog} is set to 1.
The other component is due to the Fast Lubrication Dynamics (FLD)
approximation, described in "(Kumar)"_#Kumar1, which can be
represented by the following equation
:c,image(Eqs/fld.jpg)
where U represents the velocities and angular velocities of the
particles, U^{infty} represents the velocity and the angular velocity
of the undisturbed fluid, and E^{infty} represents the rate of strain
tensor of the undisturbed fluid with viscosity {mu}. Again, note that
this is dynamic viscosity which has units of mass/distance/time, not
kinematic viscosity. Volume fraction corrections to R_FU are included
as long as {flagVF} is set to 1 (default).
NOTE: When using the FLD terms, these pair styles are designed to be
used with explicit time integration and a correspondingly small
timestep. Thus either "fix nve/sphere"_fix_nve_sphere.html or "fix
nve/asphere"_fix_nve_asphere.html should be used for time integration.
To perform implicit FLD, see the "pair_style
lubricateU"_pair_lubricateU.html command.
Style {lubricate} requires monodisperse spherical particles; style
{lubricate/poly} allows for polydisperse spherical particles.
The viscosity {mu} can be varied in a time-dependent manner over the
course of a simulation, in which case in which case the pair_style
setting for {mu} will be overridden. See the "fix adapt"_fix_adapt.html
command for details.
If the suspension is sheared via the "fix deform"_fix_deform.html
command then the pair style uses the shear rate to adjust the
hydrodynamic interactions accordingly. Volume changes due to fix
deform are accounted for when computing the volume fraction
corrections to R_FU.
When computing the volume fraction corrections to R_FU, the presence
of walls (whether moving or stationary) will affect the volume
fraction available to colloidal particles. This is currently accounted
for with the following types of walls: "wall/lj93"_fix_wall.html,
"wall/lj126"_fix_wall.html, "wall/colloid"_fix_wall.html, and
"wall/harmonic"_fix_wall.html. For these wall styles, the correct
volume fraction will be used when walls do not coincide with the box
boundary, as well as when walls move and thereby cause a change in the
volume fraction. Other wall styles will still work, but they will
result in the volume fraction being computed based on the box
boundaries.
Since lubrication forces are dissipative, it is usually desirable to
thermostat the system at a constant temperature. If Brownian motion
(at a constant temperature) is desired, it can be set using the
"pair_style brownian"_pair_brownian.html command. These pair styles
and the brownian style should use consistent parameters for {mu},
{flaglog}, {flagfld}, {cutinner}, {cutoff}, {flagHI} and {flagVF}.
:line
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
cutinner (distance units)
cutoff (distance units) :ul
The two coefficients are optional. If neither is specified, the two
cutoffs specified in the pair_style command are used. Otherwise both
must be specified.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "this section"_Section_accelerate.html of
the manual. The accelerated styles take the same arguments and should
produce the same results, except for round-off and precision issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "this section"_Section_accelerate.html of the manual for more
instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the two cutoff distances for this
pair style can be mixed. The default mix value is {geometric}. See
the "pair_modify" command for details.
This pair style does not support the "pair_modify"_pair_modify.html
shift option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
These styles are part of the COLLOID package. They are only enabled
if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_2_3 section for more info.
Only spherical monodisperse particles are allowed for pair_style
lubricate.
Only spherical particles are allowed for pair_style lubricate/poly.
These pair styles will not restart exactly when using the
"read_restart"_read_restart.html command, though they should provide
statistically similar results. This is because the forces they
compute depend on atom velocities. See the
"read_restart"_read_restart.html command for more details.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style
lubricateU"_pair_lubricateU.html
[Default:]
The default settings for the optional args are flagHI = 1 and flagVF =
1.
:line
:link(Ball1)
[(Ball)] Ball and Melrose, Physica A, 247, 444-472 (1997).
:link(Kumar1)
[(Kumar)] Kumar and Higdon, Phys Rev E, 82, 051401 (2010). See also
his thesis for more details: A. Kumar, "Microscale Dynamics in
Suspensions of Non-spherical Particles", Thesis, University of
Illinois Urbana-Champaign,
(2010). ("https://www.ideals.illinois.edu/handle/2142/16032"_https://www.ideals.illinois.edu/handle/2142/16032)
diff --git a/doc/src/pair_meam_spline.txt b/doc/src/pair_meam_spline.txt
index 2295a6640..6653b397a 100644
--- a/doc/src/pair_meam_spline.txt
+++ b/doc/src/pair_meam_spline.txt
@@ -1,168 +1,168 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style meam/spline :h3
pair_style meam/spline/omp :h3
[Syntax:]
pair_style meam/spline :pre
[Examples:]
pair_style meam/spline
pair_coeff * * Ti.meam.spline Ti
pair_coeff * * Ti.meam.spline Ti Ti Ti :pre
[Description:]
The {meam/spline} style computes pairwise interactions for metals
using a variant of modified embedded-atom method (MEAM) potentials
"(Lenosky)"_#Lenosky1. For a single species ("old-style") MEAM,
the total energy E is given by
:c,image(Eqs/pair_meam_spline.jpg)
where rho_i is the density at atom I, theta_jik is the angle between
atoms J, I, and K centered on atom I. The five functions Phi, U, rho,
f, and g are represented by cubic splines.
The {meam/spline} style also supports a new style multicomponent
modified embedded-atom method (MEAM) potential "(Zhang)"_#Zhang4, where
the total energy E is given by
:c,image(Eqs/pair_meam_spline_multicomponent.jpg)
where the five functions Phi, U, rho, f, and g depend on the chemistry
of the atoms in the interaction. In particular, if there are N different
chemistries, there are N different U, rho, and f functions, while there
are N(N+1)/2 different Phi and g functions. The new style multicomponent
MEAM potential files are indicated by the second line in the file starts
with "meam/spline" followed by the number of elements and the name of each
element.
The cutoffs and the coefficients for these spline functions are listed
in a parameter file which is specified by the
"pair_coeff"_pair_coeff.html command. Parameter files for different
elements are included in the "potentials" directory of the LAMMPS
distribution and have a ".meam.spline" file suffix. All of these
files are parameterized in terms of LAMMPS "metal units"_units.html.
Note that unlike for other potentials, cutoffs for spline-based MEAM
potentials are not set in the pair_style or pair_coeff command; they
are specified in the potential files themselves.
Unlike the EAM pair style, which retrieves the atomic mass from the
potential file, the spline-based MEAM potentials do not include mass
information; thus you need to use the "mass"_mass.html command to
specify it.
Only a single pair_coeff command is used with the {meam/spline} style
which specifies a potential file with parameters for all needed
elements. These are mapped to LAMMPS atom types by specifying N
additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of spline-based MEAM elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine the Ti.meam.spline file has values for Ti (old style). If
your LAMMPS simulation has 3 atoms types and they are all to be
treated with this potentials, you would use the following pair_coeff
command:
pair_coeff * * Ti.meam.spline Ti Ti Ti :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The three Ti arguments map LAMMPS atom types 1,2,3 to the Ti element
in the potential file. If a mapping value is specified as NULL, the
mapping is not performed. This can be used when a {meam/spline}
potential is used as part of the {hybrid} pair style. The NULL values
are placeholders for atom types that will be used with other
potentials. The old-style potential maps any non-NULL species named
on the command line to that single type.
An example with a two component spline (new style) is TiO.meam.spline, where
the command
pair_coeff * * TiO.meam.spline Ti O :pre
will map the 1st atom type to Ti and the second atom type to O. Note
in this case that the species names need to match exactly with the
names of the elements in the TiO.meam.spline file; otherwise an
error will be raised. This behavior is different than the old style
MEAM files.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
The {meam/spline} pair style does not write its information to "binary
restart files"_restart.html, since it is stored in an external
potential parameter file. Thus, you need to re-specify the pair_style
and pair_coeff commands in an input script that reads a restart file.
The {meam/spline} pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
This pair style is only enabled if LAMMPS was built with the USER-MISC
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_style meam"_pair_meam.html
[Default:] none
:line
:link(Lenosky1)
[(Lenosky)] Lenosky, Sadigh, Alonso, Bulatov, de la Rubia, Kim, Voter,
Kress, Modelling Simulation Materials Science Engineering, 8, 825
(2000).
:link(Zhang4)
[(Zhang)] Zhang and Trinkle, Computational Materials Science, 124, 204-210 (2016).
diff --git a/doc/src/pair_morse.txt b/doc/src/pair_morse.txt
index 5fbb6d5c0..3eb5ac5af 100644
--- a/doc/src/pair_morse.txt
+++ b/doc/src/pair_morse.txt
@@ -1,163 +1,163 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style morse command :h3
pair_style morse/gpu command :h3
pair_style morse/omp command :h3
pair_style morse/opt command :h3
pair_style morse/smooth/linear command :h3
pair_style morse/smooth/linear/omp command :h3
pair_style morse/soft command :h3
pair_style morse/kk command :h3
[Syntax:]
pair_style style args :pre
style = {morse} or {morse/smooth/linear} or {morse/soft}
args = list of arguments for a particular style :ul
{morse} args = cutoff
cutoff = global cutoff for Morse interactions (distance units)
{morse/smooth/linear} args = cutoff
cutoff = global cutoff for Morse interactions (distance units)
{morse/soft} args = n lf cutoff
n = soft-core parameter
lf = transformation range is lf < lambda < 1
cutoff = global cutoff for Morse interactions (distance units)
:pre
[Examples:]
pair_style morse 2.5
pair_style morse/smooth/linear 2.5
pair_coeff * * 100.0 2.0 1.5
pair_coeff 1 1 100.0 2.0 1.5 3.0 :pre
pair_style morse/soft 4 0.9 10.0
pair_coeff * * 100.0 2.0 1.5 1.0
pair_coeff 1 1 100.0 2.0 1.5 1.0 3.0 :pre
[Description:]
Style {morse} computes pairwise interactions with the formula
:c,image(Eqs/pair_morse.jpg)
Rc is the cutoff.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
D0 (energy units)
alpha (1/distance units)
r0 (distance units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global morse
cutoff is used.
:line
The {morse/smooth/linear} variant is similar to the lj/smooth/linear
variant in that it adds to the potential a shift and a linear term
so that both, potential energy and force, go to zero at the cut-off:
:c,image(Eqs/pair_morse_smooth_linear.jpg)
The syntax of the pair_style and pair_coeff commands are the same for
the {morse} and {morse/smooth/linear} styles.
:line
The {morse/soft} variant is similar to the {lj/cut/soft} pair style
in that it modifies the potential at short range to have a soft core.
This helps to avoid singularities during free energy calculation in
which sites are created or annihilated. The formula differs from that
of {lj/cut/soft}, and is instead given by:
:c,image(Eqs/pair_morse_soft.jpg)
The {morse/soft} style requires the following pair coefficients:
D0 (energy units)
alpha (1/distance units)
r0 (distance units)
lamda (unitless, between 0.0 and 1.0)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global morse
cutoff is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
None of these pair styles support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
All of these pair styles support the "pair_modify"_pair_modify.html
shift option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table options is not relevant for
the Morse pair styles.
None of these pair styles support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
All of these pair styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
The {morse/smooth/linear} pair style is only enabled if LAMMPS was
built with the USER-MISC package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The {morse/soft} pair style is only enabled if LAMMPS was built with
the USER-FEP package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_nb3b_harmonic.txt b/doc/src/pair_nb3b_harmonic.txt
index 3f7066c82..2395707fb 100644
--- a/doc/src/pair_nb3b_harmonic.txt
+++ b/doc/src/pair_nb3b_harmonic.txt
@@ -1,125 +1,125 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style nb3b/harmonic command :h3
pair_style nb3b/harmonic/omp command :h3
[Syntax:]
pair_style nb3b/harmonic :pre
[Examples:]
pair_style nb3b/harmonic
pair_coeff * * MgOH.nb3bharmonic Mg O H :pre
[Description:]
This pair style computes a nonbonded 3-body harmonic potential for the
energy E of a system of atoms as
:c,image(Eqs/pair_nb3b_harmonic.jpg)
where {theta_0} is the equilibrium value of the angle and {K} is a
prefactor. Note that the usual 1/2 factor is included in {K}. The form
of the potential is identical to that used in angle_style {harmonic},
but in this case, the atoms do not need to be explicitly bonded.
Only a single pair_coeff command is used with this style which
specifies a potential file with parameters for specified elements.
These are mapped to LAMMPS atom types by specifying N additional
arguments after the filename in the pair_coeff command, where N is the
number of LAMMPS atom types:
filename
N element names = mapping of elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine a file SiC.nb3b.harmonic has potential values
for Si and C. If your LAMMPS simulation has 4 atoms types and you
want the 1st 3 to be Si, and the 4th to be C, you would use the
following pair_coeff command:
pair_coeff * * SiC.nb3b.harmonic Si Si Si C :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Si arguments map LAMMPS atom types 1,2,3 to the Si
element in the potential file. The final C argument maps LAMMPS atom
type 4 to the C element in the potential file. If a mapping value is
specified as NULL, the mapping is not performed. This can be used
when the potential is used as part of the {hybrid} pair style. The
NULL values are placeholders for atom types that will be used with
other potentials. An example of a pair_coeff command for use with the
{hybrid} pair style is:
pair_coeff * * nb3b/harmonic MgOH.nb3b.harmonic Mg O H
Three-body nonbonded harmonic files in the {potentials} directory of
the LAMMPS distribution have a ".nb3b.harmonic" suffix. Lines that
are not blank or comments (starting with #) define parameters for a
triplet of elements.
Each entry has six arguments. The first three are atom types as
referenced in the LAMMPS input file. The first argument specifies the
central atom. The fourth argument indicates the {K} parameter. The
fifth argument indicates {theta_0}. The sixth argument indicates a
separation cutoff in Angstroms.
For a given entry, if the second and third arguments are identical,
then the entry is for a cutoff for the distance between types 1 and 2
(values for {K} and {theta_0} are irrelevant in this case).
For a given entry, if the first three arguments are all different,
then the entry is for the {K} and {theta_0} parameters (the cutoff in
this case is irrelevant).
It is required that the potential file contains entries for {all}
permutations of the elements listed in the pair_coeff command.
If certain combinations are not parameterized the corresponding
parameters should be set to zero. The potential file can also
contain entries for additional elements which are not used in
a particular simulation; LAMMPS ignores those entries.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This pair style can only be used if LAMMPS was built with the MANYBODY
package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info on packages.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_nm.txt b/doc/src/pair_nm.txt
index 9096bdc52..81cea1a38 100644
--- a/doc/src/pair_nm.txt
+++ b/doc/src/pair_nm.txt
@@ -1,169 +1,169 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style nm/cut command :h3
pair_style nm/cut/coul/cut command :h3
pair_style nm/cut/coul/long command :h3
pair_style nm/cut/omp command :h3
pair_style nm/cut/coul/cut/omp command :h3
pair_style nm/cut/coul/long/omp command :h3
[Syntax:]
pair_style style args :pre
style = {nm/cut} or {nm/cut/coul/cut} or {nm/cut/coul/long} :ulb,l
args = list of arguments for a particular style :l
{nm/cut} args = cutoff
cutoff = global cutoff for Pair interactions (distance units)
{nm/cut/coul/cut} args = cutoff (cutoff2)
cutoff = global cutoff for Pair (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units)
{nm/cut/coul/long} args = cutoff (cutoff2)
cutoff = global cutoff for Pair (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
:ule
[Examples:]
pair_style nm/cut 12.0
pair_coeff * * 0.01 5.4 8.0 7.0
pair_coeff 1 1 0.01 4.4 7.0 6.0 :pre
pair_style nm/cut/coul/cut 12.0 15.0
pair_coeff * * 0.01 5.4 8.0 7.0
pair_coeff 1 1 0.01 4.4 7.0 6.0 :pre
pair_style nm/cut/coul/long 12.0 15.0
pair_coeff * * 0.01 5.4 8.0 7.0
pair_coeff 1 1 0.01 4.4 7.0 6.0 :pre
[Description:]
Style {nm} computes site-site interactions based on the N-M potential
by "Clarke"_#Clarke, mainly used for ionic liquids. A site can
represent a single atom or a united-atom site. The energy of an
interaction has the following form:
:c,image(Eqs/pair_nm.jpg)
Rc is the cutoff.
Style {nm/cut/coul/cut} adds a Coulombic pairwise interaction given by
:c,image(Eqs/pair_coulomb.jpg)
where C is an energy-conversion constant, Qi and Qj are the charges on
the 2 atoms, and epsilon is the dielectric constant which can be set
by the "dielectric"_dielectric.html command. If one cutoff is
specified in the pair_style command, it is used for both the NM and
Coulombic terms. If two cutoffs are specified, they are used as
cutoffs for the NM and Coulombic terms respectively.
Styles {nm/cut/coul/long} compute the same
Coulombic interactions as style {nm/cut/coul/cut} except that an
additional damping factor is applied to the Coulombic term so it can
be used in conjunction with the "kspace_style"_kspace_style.html
command and its {ewald} or {pppm} option. The Coulombic cutoff
specified for this style means that pairwise interactions within this
distance are computed directly; interactions outside that distance are
computed in reciprocal space.
For all of the {nm} pair styles, the following coefficients must
be defined for each pair of atoms types
via the "pair_coeff"_pair_coeff.html command as in the
examples above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands.
E0 (energy units)
r0 (distance units)
n (unitless)
m (unitless)
cutoff1 (distance units)
cutoff2 (distance units) :ul
The latter 2 coefficients are optional. If not specified, the global
NM and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both NM
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the NM and Coulombic cutoffs for this
type pair. You cannot specify 2 cutoffs for style {nm}, since it
has no Coulombic terms.
For {nm/cut/coul/long} only the NM cutoff can be specified since a
Coulombic cutoff cannot be specified for an individual I,J type pair.
All type pairs use the same global Coulombic cutoff specified in the
pair_style command.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
All of the {nm} pair styles supports the
"pair_modify"_pair_modify.html shift option for the energy of the pair
interaction.
The {nm/cut/coul/long} pair styles support the
"pair_modify"_pair_modify.html table option since they can tabulate
the short-range portion of the long-range Coulombic interaction.
All of the {nm} pair styles support the "pair_modify"_pair_modify.html
tail option for adding a long-range tail correction to the energy and
pressure for the NM portion of the pair interaction.
All of the {nm} pair styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
All of the {nm} pair styles can only be used via the {pair} keyword of
the "run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Restrictions:]
These pair styles are part of the MISC package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Clarke)
[(Clarke)] Clarke and Smith, J Chem Phys, 84, 2290 (1986).
diff --git a/doc/src/pair_peri.txt b/doc/src/pair_peri.txt
index 6ffd8122a..deca093e3 100644
--- a/doc/src/pair_peri.txt
+++ b/doc/src/pair_peri.txt
@@ -1,216 +1,216 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style peri/pmb command :h3
pair_style peri/pmb/omp command :h3
pair_style peri/lps command :h3
pair_style peri/lps/omp command :h3
pair_style peri/ves command :h3
pair_style peri/eps command :h3
[Syntax:]
pair_style style :pre
style = {peri/pmb} or {peri/lps} or {peri/ves} or {peri/eps} :ul
[Examples:]
pair_style peri/pmb
pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25 :pre
pair_style peri/lps
pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 :pre
pair_style peri/ves
pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001 :pre
pair_style peri/eps
pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 118.43 :pre
[Description:]
The peridynamic pair styles implement material models that can be used
at the mescscopic and macroscopic scales. See "this
document"_PDF/PDLammps_overview.pdf for an overview of LAMMPS commands
for Peridynamics modeling.
Style {peri/pmb} implements the Peridynamic bond-based prototype
microelastic brittle (PMB) model.
Style {peri/lps} implements the Peridynamic state-based linear
peridynamic solid (LPS) model.
Style {peri/ves} implements the Peridynamic state-based linear
peridynamic viscoelastic solid (VES) model.
Style {peri/eps} implements the Peridynamic state-based elastic-plastic
solid (EPS) model.
The canonical papers on Peridynamics are "(Silling 2000)"_#Silling2000
and "(Silling 2007)"_#Silling2007. The implementation of Peridynamics
in LAMMPS is described in "(Parks)"_#Parks. Also see the "PDLAMMPS
user guide"_http://www.sandia.gov/~mlparks/papers/PDLAMMPS.pdf for
more details about its implementation.
The peridynamic VES and EPS models in PDLAMMPS were implemented by
R. Rahman and J. T. Foster at University of Texas at San Antonio. The
original VES formulation is described in "(Mitchell2011)" and the
original EPS formulation is in "(Mitchell2011a)". Additional PDF docs
that describe the VES and EPS implementations are include in the
LAMMPS distro in "doc/PDF/PDLammps_VES.pdf"_PDF/PDLammps_VES.pdf and
"doc/PDF/PDLammps_EPS.pdf"_PDF/PDLammps_EPS.pdf. For questions
regarding the VES and EPS models in LAMMPS you can contact R. Rahman
(rezwanur.rahman at utsa.edu).
The following coefficients must be defined for each pair of atom types
via the "pair_coeff"_pair_coeff.html command as in the examples above,
or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below.
For the {peri/pmb} style:
c (energy/distance/volume^2 units)
horizon (distance units)
s00 (unitless)
alpha (unitless) :ul
C is the effectively a spring constant for Peridynamic bonds, the
horizon is a cutoff distance for truncating interactions, and s00 and
alpha are used as a bond breaking criteria. The units of c are such
that c/distance = stiffness/volume^2, where stiffness is
energy/distance^2 and volume is distance^3. See the users guide for
more details.
For the {peri/lps} style:
K (force/area units)
G (force/area units)
horizon (distance units)
s00 (unitless)
alpha (unitless) :ul
K is the bulk modulus and G is the shear modulus. The horizon is a
cutoff distance for truncating interactions, and s00 and alpha are
used as a bond breaking criteria. See the users guide for more
details.
For the {peri/ves} style:
K (force/area units)
G (force/area units)
horizon (distance units)
s00 (unitless)
alpha (unitless)
m_lambdai (unitless)
m_taubi (unitless) :ul
K is the bulk modulus and G is the shear modulus. The horizon is a
cutoff distance for truncating interactions, and s00 and alpha are
used as a bond breaking criteria. m_lambdai and m_taubi are the
viscoelastic relaxation parameter and time constant,
respectively. m_lambdai varies within zero to one. For very small
values of m_lambdai the viscoelastic model responds very similar to a
linear elastic model. For details please see the description in
"(Mtchell2011)".
For the {peri/eps} style:
K (force/area units)
G (force/area units)
horizon (distance units)
s00 (unitless)
alpha (unitless)
-m_yield_stress (force/area units)
+m_yield_stress (force/area units) :ul
K is the bulk modulus and G is the shear modulus. The horizon is a
cutoff distance and s00 and alpha are used as a bond breaking
criteria. m_yield_stress is the yield stress of the material. For
details please see the description in "(Mtchell2011a)".
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
These pair styles do not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
These pair styles do not support the "pair_modify"_pair_modify.html
shift option.
The "pair_modify"_pair_modify.html table and tail options are not
relevant for these pair styles.
These pair styles write their information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
These pair styles can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. They do not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
All of these styles are part of the PERI package. They are only
enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Parks)
[(Parks)] Parks, Lehoucq, Plimpton, Silling, Comp Phys Comm, 179(11),
777-783 (2008).
:link(Silling2000)
[(Silling 2000)] Silling, J Mech Phys Solids, 48, 175-209 (2000).
:link(Silling2007)
[(Silling 2007)] Silling, Epton, Weckner, Xu, Askari, J Elasticity,
88, 151-184 (2007).
:link(Mitchell2011)
[(Mitchell2011)] Mitchell. A non-local, ordinary-state-based
viscoelasticity model for peridynamics. Sandia National Lab Report,
8064:1-28 (2011).
:link(Mitchell2011a)
[(Mitchell2011a)] Mitchell. A Nonlocal, Ordinary, State-Based
Plasticity Model for Peridynamics. Sandia National Lab Report,
3166:1-34 (2011).
diff --git a/doc/src/pair_quip.txt b/doc/src/pair_quip.txt
index 12dcd244e..9436b0c4e 100644
--- a/doc/src/pair_quip.txt
+++ b/doc/src/pair_quip.txt
@@ -1,96 +1,112 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style quip command :h3
[Syntax:]
pair_style quip :pre
[Examples:]
pair_style quip
pair_coeff * * gap_example.xml "Potential xml_label=GAP_2014_5_8_60_17_10_38_466" 14
pair_coeff * * sw_example.xml "IP SW" 14 :pre
[Description:]
Style {quip} provides an interface for calling potential routines from
the QUIP package. QUIP is built separately, and then linked to
LAMMPS. The most recent version of the QUIP package can be downloaded
from GitHub:
"https://github.com/libAtoms/QUIP"_https://github.com/libAtoms/QUIP. The
interface is chiefly intended to be used to run Gaussian Approximation
Potentials (GAP), which are described in the following publications:
"(Bartok et al)"_#Bartok_2010 and "(PhD thesis of
Bartok)"_#Bartok_PhD.
Only a single pair_coeff command is used with the {quip} style that
specifies a QUIP potential file containing the parameters of the
potential for all needed elements in XML format. This is followed by a
QUIP initialization string. Finally, the QUIP elements are mapped to
LAMMPS atom types by specifying N atomic numbers, where N is the
number of LAMMPS atom types:
QUIP filename
QUIP initialization string
N atomic numbers = mapping of QUIP elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
A QUIP potential is fully specified by the filename which contains the
parameters of the potential in XML format, the initialization string,
and the map of atomic numbers.
GAP potentials can be obtained from the Data repository section of
"http://www.libatoms.org"_http://www.libatoms.org, where the
appropriate initialization strings are also advised. The list of
atomic numbers must be matched to the LAMMPS atom types specified in
the LAMMPS data file or elsewhere.
Two examples input scripts are provided in the examples/USER/quip
directory.
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
mix, shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
[Restrictions:]
This pair style is part of the USER-QUIP package. It is only enabled
if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
QUIP potentials are parametrized in electron-volts and Angstroms and
therefore should be used with LAMMPS metal "units"_units.html.
+QUIP potentials are generally not designed to work with the scaling
+factors set by the "special_bonds"_special_bonds.html command. The
+recommended setting in molecular systems is to include all
+interactions, i.e. to use {special_bonds lj/coul 1.0 1.0 1.0}. Scaling
+factors > 0.0 will be ignored and treated as 1.0. The only exception
+to this rule is if you know that your QUIP potential needs to exclude
+bonded, 1-3, or 1-4 interactions and does not already do this exclusion
+within QUIP. Then a factor 0.0 needs to be used which will remove such
+pairs from the neighbor list. This needs to be very carefully tested,
+because it may remove pairs from the neighbor list that are still
+required.
+
+Pair style {quip} cannot be used with pair style {hybrid}, only
+with {hybrid/overlay} and only the {quip} substyle is applied to
+all atom types.
+
[Related commands:]
"pair_coeff"_pair_coeff.html
:line
:link(Bartok_2010)
[(Bartok_2010)] AP Bartok, MC Payne, R Kondor, and G Csanyi, Physical
Review Letters 104, 136403 (2010).
:link(Bartok_PhD)
[(Bartok_PhD)] A Bartok-Partay, PhD Thesis, University of Cambridge,
(2010).
diff --git a/doc/src/pair_reaxc.txt b/doc/src/pair_reaxc.txt
index cfa88673d..b9dc6e0ed 100644
--- a/doc/src/pair_reaxc.txt
+++ b/doc/src/pair_reaxc.txt
@@ -1,358 +1,358 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style reax/c command :h3
pair_style reax/c/kk command :h3
pair_style reax/c/omp command :h3
[Syntax:]
pair_style reax/c cfile keyword value :pre
cfile = NULL or name of a control file :ulb,l
zero or more keyword/value pairs may be appended :l
keyword = {checkqeq} or {lgvdw} or {safezone} or {mincap}
{checkqeq} value = {yes} or {no} = whether or not to require qeq/reax fix
{enobonds} value = {yes} or {no} = whether or not to tally energy of atoms with no bonds
{lgvdw} value = {yes} or {no} = whether or not to use a low gradient vdW correction
{safezone} = factor used for array allocation
{mincap} = minimum size for array allocation :pre
:ule
[Examples:]
pair_style reax/c NULL
pair_style reax/c controlfile checkqeq no
pair_style reax/c NULL lgvdw yes
pair_style reax/c NULL safezone 1.6 mincap 100
pair_coeff * * ffield.reax C H O N :pre
[Description:]
Style {reax/c} computes the ReaxFF potential of van Duin, Goddard and
co-workers. ReaxFF uses distance-dependent bond-order functions to
represent the contributions of chemical bonding to the potential
energy. There is more than one version of ReaxFF. The version
implemented in LAMMPS uses the functional forms documented in the
supplemental information of the following paper: "(Chenoweth et al.,
2008)"_#Chenoweth_20082. The version integrated into LAMMPS matches
the most up-to-date version of ReaxFF as of summer 2010. For more
technical details about the pair reax/c implementation of ReaxFF, see
the "(Aktulga)"_#Aktulga paper. The {reax/c} style was initially
implemented as a stand-alone C code and is now integrated into LAMMPS
as a package.
The {reax/c/kk} style is a Kokkos version of the ReaxFF potential that is
derived from the {reax/c} style. The Kokkos version can run on GPUs and
can also use OpenMP multithreading. For more information about the Kokkos package,
see "Section 4"_Section_packages.html#kokkos and "Section 5.3.3"_accelerate_kokkos.html.
One important consideration when using the {reax/c/kk} style is the choice of either
half or full neighbor lists. This setting can be changed using the Kokkos "package"_package.html
command.
The {reax/c} style differs from the "pair_style reax"_pair_reax.html
command in the lo-level implementation details. The {reax} style is a
Fortran library, linked to LAMMPS. The {reax/c} style was initially
implemented as stand-alone C code and is now integrated into LAMMPS as
a package.
LAMMPS provides several different versions of ffield.reax in its
potentials dir, each called potentials/ffield.reax.label. These are
documented in potentials/README.reax. The default ffield.reax
contains parameterizations for the following elements: C, H, O, N.
The format of these files is identical to that used originally by van
Duin. We have tested the accuracy of {pair_style reax/c} potential
against the original ReaxFF code for the systems mentioned above. You
can use other ffield files for specific chemical systems that may be
available elsewhere (but note that their accuracy may not have been
tested).
NOTE: We do not distribute a wide variety of ReaxFF force field files
with LAMMPS. Adri van Duin's group at PSU is the central repository
for this kind of data as they are continuously deriving and updating
parameterizations for different classes of materials. You can submit
a contact request at the Materials Computation Center (MCC) website
"https://www.mri.psu.edu/materials-computation-center/connect-mcc"_https://www.mri.psu.edu/materials-computation-center/connect-mcc,
describing the material(s) you are interested in modeling with ReaxFF.
They can tell
you what is currently available or what it would take to create a
suitable ReaxFF parameterization.
The {cfile} setting can be specified as NULL, in which case default
settings are used. A control file can be specified which defines
values of control variables. Some control variables are
global parameters for the ReaxFF potential. Others define certain
performance and output settings.
Each line in the control file specifies the value for
a control variable. The format of the control file is described
below.
NOTE: The LAMMPS default values for the ReaxFF global parameters
correspond to those used by Adri van Duin's stand-alone serial
code. If these are changed by setting control variables in the control
file, the results from LAMMPS and the serial code will not agree.
Two examples using {pair_style reax/c} are provided in the examples/reax
sub-directory, along with corresponding examples for
"pair_style reax"_pair_reax.html.
Use of this pair style requires that a charge be defined for every
atom. See the "atom_style"_atom_style.html and
"read_data"_read_data.html commands for details on how to specify
charges.
The ReaxFF parameter files provided were created using a charge
equilibration (QEq) model for handling the electrostatic interactions.
Therefore, by default, LAMMPS requires that the "fix
qeq/reax"_fix_qeq_reax.html command be used with {pair_style reax/c}
when simulating a ReaxFF model, to equilibrate charge each timestep.
Using the keyword {checkqeq} with the value {no}
turns off the check for {fix qeq/reax},
allowing a simulation to be run without charge equilibration.
In this case, the static charges you
assign to each atom will be used for computing the electrostatic
interactions in the system.
See the "fix qeq/reax"_fix_qeq_reax.html command for details.
Using the optional keyword {lgvdw} with the value {yes} turns on
the low-gradient correction of the ReaxFF/C for long-range
London Dispersion, as described in the "(Liu)"_#Liu_2011 paper. Force field
file {ffield.reax.lg} is designed for this correction, and is trained
for several energetic materials (see "Liu"). When using lg-correction,
recommended value for parameter {thb} is 0.01, which can be set in the
control file. Note: Force field files are different for the original
or lg corrected pair styles, using wrong ffield file generates an error message.
Using the optional keyword {enobonds} with the value {yes}, the energy
of atoms with no bonds (i.e. isolated atoms) is included in the total
potential energy and the per-atom energy of that atom. If the value
{no} is specified then the energy of atoms with no bonds is set to zero.
The latter behavior is usual not desired, as it causes discontinuities
in the potential energy when the bonding of an atom drops to zero.
Optional keywords {safezone} and {mincap} are used for allocating
reax/c arrays. Increasing these values can avoid memory problems, such
as segmentation faults and bondchk failed errors, that could occur under
certain conditions. These keywords aren't used by the Kokkos version, which
instead uses a more robust memory allocation scheme that checks if the sizes of
the arrays have been exceeded and automatically allocates more memory.
The thermo variable {evdwl} stores the sum of all the ReaxFF potential
energy contributions, with the exception of the Coulombic and charge
equilibration contributions which are stored in the thermo variable
{ecoul}. The output of these quantities is controlled by the
"thermo"_thermo.html command.
This pair style tallies a breakdown of the total ReaxFF potential
energy into sub-categories, which can be accessed via the "compute
pair"_compute_pair.html command as a vector of values of length 14.
The 14 values correspond to the following sub-categories (the variable
names in italics match those used in the original FORTRAN ReaxFF code):
{eb} = bond energy
{ea} = atom energy
{elp} = lone-pair energy
{emol} = molecule energy (always 0.0)
{ev} = valence angle energy
{epen} = double-bond valence angle penalty
{ecoa} = valence angle conjugation energy
{ehb} = hydrogen bond energy
{et} = torsion energy
{eco} = conjugation energy
{ew} = van der Waals energy
{ep} = Coulomb energy
{efi} = electric field energy (always 0.0)
{eqeq} = charge equilibration energy :ol
To print these quantities to the log file (with descriptive column
headings) the following commands could be included in an input script:
compute reax all pair reax/c
variable eb equal c_reax\[1\]
variable ea equal c_reax\[2\]
\[...\]
variable eqeq equal c_reax\[14\]
thermo_style custom step temp epair v_eb v_ea \[...\] v_eqeq :pre
Only a single pair_coeff command is used with the {reax/c} style which
specifies a ReaxFF potential file with parameters for all needed
elements. These are mapped to LAMMPS atom types by specifying N
additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N indices = ReaxFF elements :ul
The filename is the ReaxFF potential file. Unlike for the {reax}
pair style, any filename can be used.
In the ReaxFF potential file, near the top, after the general
parameters, is the atomic parameters section that contains element
names, each with a couple dozen numeric parameters. If there are M
elements specified in the {ffield} file, think of these as numbered 1
to M. Each of the N indices you specify for the N atom types of LAMMPS
atoms must be an integer from 1 to M. Atoms with LAMMPS type 1 will
be mapped to whatever element you specify as the first index value,
etc. If a mapping value is specified as NULL, the mapping is not
performed. This can be used when the {reax/c} style is used as part
of the {hybrid} pair style. The NULL values are placeholders for atom
types that will be used with other potentials.
As an example, say your LAMMPS simulation has 4 atom types and the
elements are ordered as C, H, O, N in the {ffield} file. If you want
the LAMMPS atom type 1 and 2 to be C, type 3 to be N, and type 4 to be
H, you would use the following pair_coeff command:
pair_coeff * * ffield.reax C C N H :pre
:line
The format of a line in the control file is as follows:
variable_name value :pre
and it may be followed by an "!" character and a trailing comment.
If the value of a control variable is not specified, then default
values are used. What follows is the list of variables along with a
brief description of their use and default values.
simulation_name: Output files produced by {pair_style reax/c} carry
this name + extensions specific to their contents. Partial energies
are reported with a ".pot" extension, while the trajectory file has
".trj" extension.
tabulate_long_range: To improve performance, long range interactions
can optionally be tabulated (0 means no tabulation). Value of this
variable denotes the size of the long range interaction table. The
range from 0 to long range cutoff (defined in the {ffield} file) is
divided into {tabulate_long_range} points. Then at the start of
simulation, we fill in the entries of the long range interaction table
by computing the energies and forces resulting from van der Waals and
Coulomb interactions between every possible atom type pairs present in
the input system. During the simulation we consult to the long range
interaction table to estimate the energy and forces between a pair of
atoms. Linear interpolation is used for estimation. (default value =
0)
energy_update_freq: Denotes the frequency (in number of steps) of
writes into the partial energies file. (default value = 0)
nbrhood_cutoff: Denotes the near neighbors cutoff (in Angstroms)
regarding the bonded interactions. (default value = 5.0)
hbond_cutoff: Denotes the cutoff distance (in Angstroms) for hydrogen
bond interactions.(default value = 7.5. A value of 0.0 turns off
hydrogen bonds)
bond_graph_cutoff: is the threshold used in determining what is a
physical bond, what is not. Bonds and angles reported in the
trajectory file rely on this cutoff. (default value = 0.3)
thb_cutoff: cutoff value for the strength of bonds to be considered in
three body interactions. (default value = 0.001)
thb_cutoff_sq: cutoff value for the strength of bond order products
to be considered in three body interactions. (default value = 0.00001)
write_freq: Frequency of writes into the trajectory file. (default
value = 0)
traj_title: Title of the trajectory - not the name of the trajectory
file.
atom_info: 1 means print only atomic positions + charge (default = 0)
atom_forces: 1 adds net forces to atom lines in the trajectory file
(default = 0)
atom_velocities: 1 adds atomic velocities to atoms line (default = 0)
bond_info: 1 prints bonds in the trajectory file (default = 0)
angle_info: 1 prints angles in the trajectory file (default = 0)
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
mix, shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
This pair style is part of the USER-REAXC package. It is only enabled
if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
The ReaxFF potential files provided with LAMMPS in the potentials
directory are parameterized for real "units"_units.html. You can use
the ReaxFF potential with any LAMMPS units, but you would need to
create your own potential file with coefficients listed in the
appropriate units if your simulation doesn't use "real" units.
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix qeq/reax"_fix_qeq_reax.html, "fix
reax/c/bonds"_fix_reax_bonds.html, "fix
reax/c/species"_fix_reaxc_species.html, "pair_style
reax"_pair_reax.html
[Default:]
The keyword defaults are checkqeq = yes, enobonds = yes, lgvdw = no, safezone = 1.2,
mincap = 50.
:line
:link(Chenoweth_20082)
[(Chenoweth_2008)] Chenoweth, van Duin and Goddard,
Journal of Physical Chemistry A, 112, 1040-1053 (2008).
:link(Aktulga)
(Aktulga) Aktulga, Fogarty, Pandit, Grama, Parallel Computing, 38,
245-259 (2012).
:link(Liu_2011)
[(Liu)] L. Liu, Y. Liu, S. V. Zybin, H. Sun and W. A. Goddard, Journal
of Physical Chemistry A, 115, 11016-11022 (2011).
diff --git a/doc/src/pair_resquared.txt b/doc/src/pair_resquared.txt
index 2e0034ed3..9ad95eb5f 100644
--- a/doc/src/pair_resquared.txt
+++ b/doc/src/pair_resquared.txt
@@ -1,235 +1,235 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style resquared command :h3
pair_style resquared/gpu command :h3
pair_style resquared/omp command :h3
[Syntax:]
pair_style resquared cutoff :pre
cutoff = global cutoff for interactions (distance units) :ul
[Examples:]
pair_style resquared 10.0
pair_coeff * * 1.0 1.0 1.7 3.4 3.4 1.0 1.0 1.0 :pre
[Description:]
Style {resquared} computes the RE-squared anisotropic interaction
"(Everaers)"_#Everaers3, "(Babadi)"_#Babadi between pairs of
ellipsoidal and/or spherical Lennard-Jones particles. For ellipsoidal
interactions, the potential considers the ellipsoid as being comprised
of small spheres of size sigma. LJ particles are a single sphere of
size sigma. The distinction is made to allow the pair style to make
efficient calculations of ellipsoid/solvent interactions.
Details for the equations used are given in the references below and
in "this supplementary document"_PDF/pair_resquared_extra.pdf.
Use of this pair style requires the NVE, NVT, or NPT fixes with the
{asphere} extension (e.g. "fix nve/asphere"_fix_nve_asphere.html) in
order to integrate particle rotation. Additionally, "atom_style
ellipsoid"_atom_style.html should be used since it defines the
rotational state and the size and shape of each ellipsoidal particle.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands:
A12 = Energy Prefactor/Hamaker constant (energy units)
sigma = atomic interaction diameter (distance units)
epsilon_i_a = relative well depth of type I for side-to-side interactions
epsilon_i_b = relative well depth of type I for face-to-face interactions
epsilon_i_c = relative well depth of type I for end-to-end interactions
epsilon_j_a = relative well depth of type J for side-to-side interactions
epsilon_j_b = relative well depth of type J for face-to-face interactions
epsilon_j_c = relative well depth of type J for end-to-end interactions
cutoff (distance units) :ul
The parameters used depend on the type of the interacting particles,
i.e. ellipsoids or LJ spheres. The type of a particle is determined
by the diameters specified for its 3 shape parameters. If all 3 shape
parameters = 0.0, then the particle is treated as an LJ sphere. The
epsilon_i_* or epsilon_j_* parameters are ignored for LJ spheres. If
the 3 shape parameters are > 0.0, then the particle is treated as an
ellipsoid (even if the 3 parameters are equal to each other).
A12 specifies the energy prefactor which depends on the types of the
two interacting particles.
For ellipsoid/ellipsoid interactions, the interaction is computed by
the formulas in the supplementary document referenced above. A12 is
the Hamaker constant as described in "(Everaers)"_#Everaers3. In LJ
units:
:c,image(Eqs/pair_resquared.jpg)
where rho gives the number density of the spherical particles
composing the ellipsoids and epsilon_LJ determines the interaction
strength of the spherical particles.
For ellipsoid/LJ sphere interactions, the interaction is also computed
by the formulas in the supplementary document referenced above. A12
has a modified form (see "here"_PDF/pair_resquared_extra.pdf for
details):
:c,image(Eqs/pair_resquared2.jpg)
For ellipsoid/LJ sphere interactions, a correction to the distance-
of-closest approach equation has been implemented to reduce the error
from two particles of disparate sizes; see "this supplementary
document"_PDF/pair_resquared_extra.pdf.
For LJ sphere/LJ sphere interactions, the interaction is computed
using the standard Lennard-Jones formula, which is much cheaper to
compute than the ellipsoidal formulas. A12 is used as epsilon in the
standard LJ formula:
:c,image(Eqs/pair_resquared3.jpg)
and the specified {sigma} is used as the sigma in the standard LJ
formula.
When one of both of the interacting particles are ellipsoids, then
{sigma} specifies the diameter of the continuous distribution of
constituent particles within each ellipsoid used to model the
RE-squared potential. Note that this is a different meaning for
{sigma} than the "pair_style gayberne"_pair_gayberne.html potential
uses.
The epsilon_i and epsilon_j coefficients are defined for atom types,
not for pairs of atom types. Thus, in a series of pair_coeff
commands, they only need to be specified once for each atom type.
Specifically, if any of epsilon_i_a, epsilon_i_b, epsilon_i_c are
non-zero, the three values are assigned to atom type I. If all the
epsilon_i values are zero, they are ignored. If any of epsilon_j_a,
epsilon_j_b, epsilon_j_c are non-zero, the three values are assigned
to atom type J. If all three epsilon_i values are zero, they are
ignored. Thus the typical way to define the epsilon_i and epsilon_j
coefficients is to list their values in "pair_coeff I J" commands when
I = J, but set them to 0.0 when I != J. If you do list them when I !=
J, you should insure they are consistent with their values in other
pair_coeff commands.
Note that if this potential is being used as a sub-style of
"pair_style hybrid"_pair_hybrid.html, and there is no "pair_coeff I I"
setting made for RE-squared for a particular type I (because I-I
interactions are computed by another hybrid pair potential), then you
still need to insure the epsilon a,b,c coefficients are assigned to
that type in a "pair_coeff I J" command.
For large uniform molecules it has been shown that the epsilon_*_*
energy parameters are approximately representable in terms of local
contact curvatures "(Everaers)"_#Everaers3:
:c,image(Eqs/pair_resquared4.jpg)
where a, b, and c give the particle diameters.
The last coefficient is optional. If not specified, the global cutoff
specified in the pair_style command is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance can be mixed, but only for sphere pairs. The
default mix value is {geometric}. See the "pair_modify" command for
details. Other type pairs cannot be mixed, due to the different
meanings of the energy prefactors used to calculate the interactions
and the implicit dependence of the ellipsoid-sphere interaction on the
equation for the Hamaker constant presented here. Mixing of sigma and
epsilon followed by calculation of the energy prefactors using the
equations above is recommended.
This pair styles supports the "pair_modify"_pair_modify.html shift
option for the energy of the Lennard-Jones portion of the pair
interaction, but only for sphere-sphere interactions. There is no
shifting performed for ellipsoidal interactions due to the anisotropic
dependence of the interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords of the "run_style
command"_run_style.html.
:line
[Restrictions:]
This style is part of the ASPHERE package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires that atoms be ellipsoids as defined by the
"atom_style ellipsoid"_atom_style.html command.
Particles acted on by the potential can be finite-size aspherical or
spherical particles, or point particles. Spherical particles have all
3 of their shape parameters equal to each other. Point particles have
all 3 of their shape parameters equal to 0.0.
The distance-of-closest-approach approximation used by LAMMPS becomes
less accurate when high-aspect ratio ellipsoids are used.
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix nve/asphere"_fix_nve_asphere.html,
"compute temp/asphere"_compute_temp_asphere.html, "pair_style
gayberne"_pair_gayberne.html
[Default:] none
:line
:link(Everaers3)
[(Everaers)] Everaers and Ejtehadi, Phys Rev E, 67, 041710 (2003).
:link(Babadi)
[(Berardi)] Babadi, Ejtehadi, Everaers, J Comp Phys, 219, 770-779 (2006).
diff --git a/doc/src/pair_sdk.txt b/doc/src/pair_sdk.txt
index 1c348eaaf..360136a4e 100644
--- a/doc/src/pair_sdk.txt
+++ b/doc/src/pair_sdk.txt
@@ -1,156 +1,156 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style lj/sdk command :h3
pair_style lj/sdk/gpu command :h3
pair_style lj/sdk/kk command :h3
pair_style lj/sdk/omp command :h3
pair_style lj/sdk/coul/long command :h3
pair_style lj/sdk/coul/long/gpu command :h3
pair_style lj/sdk/coul/long/omp command :h3
[Syntax:]
pair_style style args :pre
style = {lj/sdk} or {lj/sdk/coul/long}
args = list of arguments for a particular style :ul
{lj/sdk} args = cutoff
cutoff = global cutoff for Lennard Jones interactions (distance units)
{lj/sdk/coul/long} args = cutoff (cutoff2)
cutoff = global cutoff for LJ (and Coulombic if only 1 arg) (distance units)
cutoff2 = global cutoff for Coulombic (optional) (distance units) :pre
[Examples:]
pair_style lj/sdk 2.5
pair_coeff 1 1 lj12_6 1 1.1 2.8 :pre
pair_style lj/sdk/coul/long 10.0
pair_style lj/sdk/coul/long 10.0 12.0
pair_coeff 1 1 lj9_6 100.0 3.5 12.0 :pre
[Description:]
The {lj/sdk} styles compute a 9/6, 12/4, or 12/6 Lennard-Jones potential,
given by
:c,image(Eqs/pair_cmm.jpg)
as required for the SDK Coarse-grained MD parametrization discussed in
"(Shinoda)"_#Shinoda3 and "(DeVane)"_#DeVane. Rc is the cutoff.
Style {lj/sdk/coul/long} computes the adds Coulombic interactions
with an additional damping factor applied so it can be used in
conjunction with the "kspace_style"_kspace_style.html command and
its {ewald} or {pppm} or {pppm/cg} option. The Coulombic cutoff
specified for this style means that pairwise interactions within
this distance are computed directly; interactions outside that
distance are computed in reciprocal space.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
cg_type (lj9_6, lj12_4, or lj12_6)
epsilon (energy units)
sigma (distance units)
cutoff1 (distance units) :ul
Note that sigma is defined in the LJ formula as the zero-crossing
distance for the potential, not as the energy minimum. The prefactors
are chosen so that the potential minimum is at -epsilon.
The latter 2 coefficients are optional. If not specified, the global
LJ and Coulombic cutoffs specified in the pair_style command are used.
If only one cutoff is specified, it is used as the cutoff for both LJ
and Coulombic interactions for this type pair. If both coefficients
are specified, they are used as the LJ and Coulombic cutoffs for this
type pair.
For {lj/sdk/coul/long} only the LJ cutoff can be specified since a
Coulombic cutoff cannot be specified for an individual I,J type pair.
All type pairs use the same global Coulombic cutoff specified in the
pair_style command.
:line
Styles with a {gpu}, {intel}, {kk}, {omp} or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP, and OPT packages respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, and rRESPA info]:
For atom type pairs I,J and I != J, the epsilon and sigma coefficients
and cutoff distance for all of the lj/sdk pair styles {cannot} be mixed,
since different pairs may have different exponents. So all parameters
for all pairs have to be specified explicitly through the "pair_coeff"
command. Defining then in a data file is also not supported, due to
limitations of that file format.
All of the lj/sdk pair styles support the
"pair_modify"_pair_modify.html shift option for the energy of the
Lennard-Jones portion of the pair interaction.
The {lj/sdk/coul/long} pair styles support the
"pair_modify"_pair_modify.html table option since they can tabulate
the short-range portion of the long-range Coulombic interaction.
All of the lj/sdk pair styles write their information to "binary
restart files"_restart.html, so pair_style and pair_coeff commands do
not need to be specified in an input script that reads a restart file.
The lj/sdk and lj/cut/coul/long pair styles do not support
the use of the {inner}, {middle}, and {outer} keywords of the "run_style
respa"_run_style.html command.
:line
[Restrictions:]
All of the lj/sdk pair styles are part of the USER-CGSDK package.
The {lj/sdk/coul/long} style also requires the KSPACE package to be
built (which is enabled by default). They are only enabled if LAMMPS
was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
[Related commands:]
"pair_coeff"_pair_coeff.html, "angle_style sdk"_angle_sdk.html
[Default:] none
:line
:link(Shinoda3)
[(Shinoda)] Shinoda, DeVane, Klein, Mol Sim, 33, 27 (2007).
:link(DeVane)
[(DeVane)] Shinoda, DeVane, Klein, Soft Matter, 4, 2453-2462 (2008).
diff --git a/doc/src/pair_soft.txt b/doc/src/pair_soft.txt
index ec1c06729..08fa88c47 100644
--- a/doc/src/pair_soft.txt
+++ b/doc/src/pair_soft.txt
@@ -1,136 +1,136 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style soft command :h3
pair_style soft/gpu command :h3
pair_style soft/omp command :h3
[Syntax:]
pair_style soft cutoff :pre
cutoff = global cutoff for soft interactions (distance units) :ul
[Examples:]
pair_style soft 1.0
pair_coeff * * 10.0
pair_coeff 1 1 10.0 3.0 :pre
pair_style soft 1.0
pair_coeff * * 0.0
variable prefactor equal ramp(0,30)
fix 1 all adapt 1 pair soft a * * v_prefactor :pre
[Description:]
Style {soft} computes pairwise interactions with the formula
:c,image(Eqs/pair_soft.jpg)
It is useful for pushing apart overlapping atoms, since it does not
blow up as r goes to 0. A is a pre-factor that can be made to vary in
time from the start to the end of the run (see discussion below),
e.g. to start with a very soft potential and slowly harden the
interactions over time. Rc is the cutoff. See the "fix
nve/limit"_fix_nve_limit.html command for another way to push apart
overlapping atoms.
The following coefficients must be defined for each pair of atom types
via the "pair_coeff"_pair_coeff.html command as in the examples above,
or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
A (energy units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global soft
cutoff is used.
NOTE: The syntax for "pair_coeff"_pair_coeff.html with a single A
coeff is different in the current version of LAMMPS than in older
versions which took two values, Astart and Astop, to ramp between
them. This functionality is now available in a more general form
through the "fix adapt"_fix_adapt.html command, as explained below.
Note that if you use an old input script and specify Astart and Astop
without a cutoff, then LAMMPS will interpret that as A and a cutoff,
which is probably not what you want.
The "fix adapt"_fix_adapt.html command can be used to vary A for one
or more pair types over the course of a simulation, in which case
pair_coeff settings for A must still be specified, but will be
overridden. For example these commands will vary the prefactor A for
all pairwise interactions from 0.0 at the beginning to 30.0 at the end
of a run:
variable prefactor equal ramp(0,30)
fix 1 all adapt 1 pair soft a * * v_prefactor :pre
Note that a formula defined by an "equal-style variable"_variable.html
can use the current timestep, elapsed time in the current run, elapsed
time since the beginning of a series of runs, as well as access other
variables.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the A coefficient and cutoff
distance for this pair style can be mixed. A is always mixed via a
{geometric} rule. The cutoff is mixed according to the pair_modify
mix value. The default mix value is {geometric}. See the
"pair_modify" command for details.
This pair style does not support the "pair_modify"_pair_modify.html
shift option, since the pair interaction goes to 0.0 at the cutoff.
The "pair_modify"_pair_modify.html table and tail options are not
relevant for this pair style.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html, "fix nve/limit"_fix_nve_limit.html, "fix
adapt"_fix_adapt.html
[Default:] none
diff --git a/doc/src/pair_sw.txt b/doc/src/pair_sw.txt
index 6025b9b11..6ed8f0023 100644
--- a/doc/src/pair_sw.txt
+++ b/doc/src/pair_sw.txt
@@ -1,216 +1,216 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style sw command :h3
pair_style sw/gpu command :h3
pair_style sw/intel command :h3
pair_style sw/kk command :h3
pair_style sw/omp command :h3
[Syntax:]
pair_style sw :pre
[Examples:]
pair_style sw
pair_coeff * * si.sw Si
pair_coeff * * GaN.sw Ga N Ga :pre
[Description:]
The {sw} style computes a 3-body "Stillinger-Weber"_#Stillinger2
potential for the energy E of a system of atoms as
:c,image(Eqs/pair_sw.jpg)
where phi2 is a two-body term and phi3 is a three-body term. The
summations in the formula are over all neighbors J and K of atom I
within a cutoff distance = a*sigma.
Only a single pair_coeff command is used with the {sw} style which
specifies a Stillinger-Weber potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of SW elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine a file SiC.sw has Stillinger-Weber values for
Si and C. If your LAMMPS simulation has 4 atoms types and you want
the 1st 3 to be Si, and the 4th to be C, you would use the following
pair_coeff command:
pair_coeff * * SiC.sw Si Si Si C :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Si arguments map LAMMPS atom types 1,2,3 to the Si
element in the SW file. The final C argument maps LAMMPS atom type 4
to the C element in the SW file. If a mapping value is specified as
NULL, the mapping is not performed. This can be used when a {sw}
potential is used as part of the {hybrid} pair style. The NULL values
are placeholders for atom types that will be used with other
potentials.
Stillinger-Weber files in the {potentials} directory of the LAMMPS
distribution have a ".sw" suffix. Lines that are not blank or
comments (starting with #) define parameters for a triplet of
elements. The parameters in a single entry correspond to the two-body
and three-body coefficients in the formula above:
element 1 (the center atom in a 3-body interaction)
element 2
element 3
epsilon (energy units)
sigma (distance units)
a
lambda
gamma
costheta0
A
B
p
q
tol :ul
The A, B, p, and q parameters are used only for two-body
interactions. The lambda and costheta0 parameters are used only for
three-body interactions. The epsilon, sigma and a parameters are used
for both two-body and three-body interactions. gamma is used only in the
three-body interactions, but is defined for pairs of atoms.
The non-annotated parameters are unitless.
LAMMPS introduces an additional performance-optimization parameter tol
that is used for both two-body and three-body interactions. In the
Stillinger-Weber potential, the interaction energies become negligibly
small at atomic separations substantially less than the theoretical
cutoff distances. LAMMPS therefore defines a virtual cutoff distance
based on a user defined tolerance tol. The use of the virtual cutoff
distance in constructing atom neighbor lists can significantly reduce
the neighbor list sizes and therefore the computational cost. LAMMPS
provides a {tol} value for each of the three-body entries so that they
can be separately controlled. If tol = 0.0, then the standard
Stillinger-Weber cutoff is used.
The Stillinger-Weber potential file must contain entries for all the
elements listed in the pair_coeff command. It can also contain
entries for additional elements not being used in a particular
simulation; LAMMPS ignores those entries.
For a single-element simulation, only a single entry is required
(e.g. SiSiSi). For a two-element simulation, the file must contain 8
entries (for SiSiSi, SiSiC, SiCSi, SiCC, CSiSi, CSiC, CCSi, CCC), that
specify SW parameters for all permutations of the two elements
interacting in three-body configurations. Thus for 3 elements, 27
entries would be required, etc.
As annotated above, the first element in the entry is the center atom
in a three-body interaction. Thus an entry for SiCC means a Si atom
with 2 C atoms as neighbors. The parameter values used for the
two-body interaction come from the entry where the 2nd and 3rd
elements are the same. Thus the two-body parameters for Si
interacting with C, comes from the SiCC entry. The three-body
parameters can in principle be specific to the three elements of the
configuration. In the literature, however, the three-body parameters
are usually defined by simple formulas involving two sets of pair-wise
parameters, corresponding to the ij and ik pairs, where i is the
center atom. The user must ensure that the correct combining rule is
used to calculate the values of the threebody parameters for
alloys. Note also that the function phi3 contains two exponential
screening factors with parameter values from the ij pair and ik
pairs. So phi3 for a C atom bonded to a Si atom and a second C atom
will depend on the three-body parameters for the CSiC entry, and also
on the two-body parameters for the CCC and CSiSi entries. Since the
order of the two neighbors is arbitrary, the threebody parameters for
entries CSiC and CCSi should be the same. Similarly, the two-body
parameters for entries SiCC and CSiSi should also be the same. The
parameters used only for two-body interactions (A, B, p, and q) in
entries whose 2nd and 3rd element are different (e.g. SiCSi) are not
used for anything and can be set to 0.0 if desired.
This is also true for the parameters in phi3 that are
taken from the ij and ik pairs (sigma, a, gamma)
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
When using the USER-INTEL package with this style, there is an
additional 5 to 10 percent performance improvement when the
Stillinger-Weber parameters p and q are set to 4 and 0 respectively.
These parameters are common for modeling silicon and water.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above from values in the potential file.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style is part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
The Stillinger-Weber potential files provided with LAMMPS (see the
potentials directory) are parameterized for metal "units"_units.html.
You can use the SW potential with any LAMMPS units, but you would need
to create your own SW potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Stillinger2)
[(Stillinger)] Stillinger and Weber, Phys Rev B, 31, 5262 (1985).
diff --git a/doc/src/pair_table.txt b/doc/src/pair_table.txt
index 01c577cd9..b99491b47 100644
--- a/doc/src/pair_table.txt
+++ b/doc/src/pair_table.txt
@@ -1,272 +1,272 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style table command :h3
pair_style table/gpu command :h3
pair_style table/kk command :h3
pair_style table/omp command :h3
[Syntax:]
pair_style table style N keyword ... :pre
style = {lookup} or {linear} or {spline} or {bitmap} = method of interpolation
N = use N values in {lookup}, {linear}, {spline} tables
N = use 2^N values in {bitmap} tables
zero or more keywords may be appended
keyword = {ewald} or {pppm} or {msm} or {dispersion} or {tip4p} :ul
[Examples:]
pair_style table linear 1000
pair_style table linear 1000 pppm
pair_style table bitmap 12
pair_coeff * 3 morse.table ENTRY1
pair_coeff * 3 morse.table ENTRY1 7.0 :pre
[Description:]
Style {table} creates interpolation tables from potential energy and
force values listed in a file(s) as a function of distance. When
performing dynamics or minimization, the interpolation tables are used
to evaluate energy and forces for pairwise interactions between
particles, similar to how analytic formulas are used for other pair
styles.
The interpolation tables are created as a pre-computation by fitting
cubic splines to the file values and interpolating energy and force
values at each of {N} distances. During a simulation, the tables are
used to interpolate energy and force values as needed for each pair of
particles separated by a distance {R}. The interpolation is done in
one of 4 styles: {lookup}, {linear}, {spline}, or {bitmap}.
For the {lookup} style, the distance {R} is used to find the nearest
table entry, which is the energy or force.
For the {linear} style, the distance {R} is used to find the 2
surrounding table values from which an energy or force is computed by
linear interpolation.
For the {spline} style, a cubic spline coefficients are computed and
stored for each of the {N} values in the table, one set of splines for
energy, another for force. Note that these splines are different than
the ones used to pre-compute the {N} values. Those splines were fit
to the {Nfile} values in the tabulated file, where often {Nfile} <
{N}. The distance {R} is used to find the appropriate set of spline
coefficients which are used to evaluate a cubic polynomial which
computes the energy or force.
For the {bitmap} style, the specified {N} is used to create
interpolation tables that are 2^N in length. The distance {R} is used
to index into the table via a fast bit-mapping technique due to
"(Wolff)"_#Wolff2, and a linear interpolation is performed between
adjacent table values.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above.
filename
keyword
cutoff (distance units) :ul
The filename specifies a file containing tabulated energy and force
values. The keyword specifies a section of the file. The cutoff is
an optional coefficient. If not specified, the outer cutoff in the
table itself (see below) will be used to build an interpolation table
that extend to the largest tabulated distance. If specified, only
file values up to the cutoff are used to create the interpolation
table. The format of this file is described below.
If your tabulated potential(s) are designed to be used as the
short-range part of one of the long-range solvers specified by the
"kspace_style"_kspace_style.html command, then you must use one or
more of the optional keywords listed above for the pair_style command.
These are {ewald} or {pppm} or {msm} or {dispersion} or {tip4p}. This
is so LAMMPS can insure the short-range potential and long-range
solver are compatible with each other, as it does for other
short-range pair styles, such as "pair_style
lj/cut/coul/long"_pair_lj.html. Note that it is up to you to insure
the tabulated values for each pair of atom types has the correct
functional form to be compatible with the matching long-range solver.
:line
Here are some guidelines for using the pair_style table command to
best effect:
Vary the number of table points; you may need to use more than you think
to get good resolution. :ulb,l
Always use the "pair_write"_pair_write.html command to produce a plot
of what the final interpolated potential looks like. This can show up
interpolation "features" you may not like. :l
Start with the linear style; it's the style least likely to have problems. :l
Use {N} in the pair_style command equal to the "N" in the tabulation
file, and use the "RSQ" or "BITMAP" parameter, so additional interpolation
is not needed. See discussion below. :l
Make sure that your tabulated forces and tabulated energies are
consistent (dE/dr = -F) over the entire range of r values. LAMMPS
will warn if this is not the case. :l
Use as large an inner cutoff as possible. This avoids fitting splines
to very steep parts of the potential. :l
:ule
:line
The format of a tabulated file is a series of one or more sections,
defined as follows (without the parenthesized comments):
# Morse potential for Fe (one or more comment or blank lines) :pre
MORSE_FE (keyword is first text on line)
N 500 R 1.0 10.0 (N, R, RSQ, BITMAP, FPRIME parameters)
(blank)
1 1.0 25.5 102.34 (index, r, energy, force)
2 1.02 23.4 98.5
...
500 10.0 0.001 0.003 :pre
A section begins with a non-blank line whose 1st character is not a
"#"; blank lines or lines starting with "#" can be used as comments
between sections. The first line begins with a keyword which
identifies the section. The line can contain additional text, but the
initial text must match the argument specified in the pair_coeff
command. The next line lists (in any order) one or more parameters
for the table. Each parameter is a keyword followed by one or more
numeric values.
The parameter "N" is required and its value is the number of table
entries that follow. Note that this may be different than the {N}
specified in the "pair_style table"_pair_style.html command. Let
Ntable = {N} in the pair_style command, and Nfile = "N" in the
tabulated file. What LAMMPS does is a preliminary interpolation by
creating splines using the Nfile tabulated values as nodal points. It
uses these to interpolate energy and force values at Ntable different
points. The resulting tables of length Ntable are then used as
described above, when computing energy and force for individual pair
distances. This means that if you want the interpolation tables of
length Ntable to match exactly what is in the tabulated file (with
effectively no preliminary interpolation), you should set Ntable =
Nfile, and use the "RSQ" or "BITMAP" parameter. This is because the
internal table abscissa is always RSQ (separation distance squared),
for efficient lookup.
All other parameters are optional. If "R" or "RSQ" or "BITMAP" does
not appear, then the distances in each line of the table are used
as-is to perform spline interpolation. In this case, the table values
can be spaced in {r} uniformly or however you wish to position table
values in regions of large gradients.
If used, the parameters "R" or "RSQ" are followed by 2 values {rlo}
and {rhi}. If specified, the distance associated with each energy and
force value is computed from these 2 values (at high accuracy), rather
than using the (low-accuracy) value listed in each line of the table.
The distance values in the table file are ignored in this case.
For "R", distances uniformly spaced between {rlo} and {rhi} are
computed; for "RSQ", squared distances uniformly spaced between
{rlo*rlo} and {rhi*rhi} are computed.
NOTE: If you use "R" or "RSQ", the tabulated distance values in the
file are effectively ignored, and replaced by new values as described
in the previous paragraph. If the distance value in the table is not
very close to the new value (i.e. round-off difference), then you will
be assigning energy/force values to a different distance, which is
probably not what you want. LAMMPS will warn if this is occurring.
If used, the parameter "BITMAP" is also followed by 2 values {rlo} and
{rhi}. These values, along with the "N" value determine the ordering
of the N lines that follow and what distance is associated with each.
This ordering is complex, so it is not documented here, since this
file is typically produced by the "pair_write"_pair_write.html command
with its {bitmap} option. When the table is in BITMAP format, the "N"
parameter in the file must be equal to 2^M where M is the value
specified in the pair_style command. Also, a cutoff parameter cannot
be used as an optional 3rd argument in the pair_coeff command; the
entire table extent as specified in the file must be used.
If used, the parameter "FPRIME" is followed by 2 values {fplo} and
{fphi} which are the derivative of the force at the innermost and
outermost distances listed in the table. These values are needed by
the spline construction routines. If not specified by the "FPRIME"
parameter, they are estimated (less accurately) by the first 2 and
last 2 force values in the table. This parameter is not used by
BITMAP tables.
Following a blank line, the next N lines list the tabulated values.
On each line, the 1st value is the index from 1 to N, the 2nd value is
r (in distance units), the 3rd value is the energy (in energy units),
and the 4th is the force (in force units). The r values must increase
from one line to the next (unless the BITMAP parameter is specified).
Note that one file can contain many sections, each with a tabulated
potential. LAMMPS reads the file section by section until it finds
one that matches the specified keyword.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support mixing. Thus, coefficients for all
I,J pairs must be specified explicitly.
The "pair_modify"_pair_modify.html shift, table, and tail options are
not relevant for this pair style.
This pair style writes the settings for the "pair_style table" command
to "binary restart files"_restart.html, so a pair_style command does
not need to specified in an input script that reads a restart file.
However, the coefficient information is not stored in the restart
file, since it is tabulated in the potential files. Thus, pair_coeff
commands do need to be specified in the restart input script.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html, "pair_write"_pair_write.html
[Default:] none
:line
:link(Wolff2)
[(Wolff)] Wolff and Rudd, Comp Phys Comm, 120, 200-32 (1999).
diff --git a/doc/src/pair_tersoff.txt b/doc/src/pair_tersoff.txt
index 23a20ad0f..918e88992 100644
--- a/doc/src/pair_tersoff.txt
+++ b/doc/src/pair_tersoff.txt
@@ -1,253 +1,253 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style tersoff command :h3
pair_style tersoff/table command :h3
pair_style tersoff/gpu :h3
pair_style tersoff/intel :h3
pair_style tersoff/kk :h3
pair_style tersoff/omp :h3
pair_style tersoff/table/omp command :h3
[Syntax:]
pair_style style :pre
style = {tersoff} or {tersoff/table} or {tersoff/gpu} or {tersoff/omp} or {tersoff/table/omp} :ul
[Examples:]
pair_style tersoff
pair_coeff * * Si.tersoff Si
pair_coeff * * SiC.tersoff Si C Si :pre
pair_style tersoff/table
pair_coeff * * SiCGe.tersoff Si(D) :pre
[Description:]
The {tersoff} style computes a 3-body Tersoff potential
"(Tersoff_1)"_#Tersoff_11 for the energy E of a system of atoms as
:c,image(Eqs/pair_tersoff_1.jpg)
where f_R is a two-body term and f_A includes three-body interactions.
The summations in the formula are over all neighbors J and K of atom I
within a cutoff distance = R + D.
The {tersoff/table} style uses tabulated forms for the two-body,
environment and angular functions. Linear interpolation is performed
between adjacent table entries. The table length is chosen to be
accurate within 10^-6 with respect to the {tersoff} style energy.
The {tersoff/table} should give better performance in terms of speed.
Only a single pair_coeff command is used with the {tersoff} style
which specifies a Tersoff potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of Tersoff elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine the SiC.tersoff file has Tersoff values for Si
and C. If your LAMMPS simulation has 4 atoms types and you want the
1st 3 to be Si, and the 4th to be C, you would use the following
pair_coeff command:
pair_coeff * * SiC.tersoff Si Si Si C :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Si arguments map LAMMPS atom types 1,2,3 to the Si
element in the Tersoff file. The final C argument maps LAMMPS atom
type 4 to the C element in the Tersoff file. If a mapping value is
specified as NULL, the mapping is not performed. This can be used
when a {tersoff} potential is used as part of the {hybrid} pair style.
The NULL values are placeholders for atom types that will be used with
other potentials.
Tersoff files in the {potentials} directory of the LAMMPS distribution
have a ".tersoff" suffix. Lines that are not blank or comments
(starting with #) define parameters for a triplet of elements. The
parameters in a single entry correspond to coefficients in the formula
above:
element 1 (the center atom in a 3-body interaction)
element 2 (the atom bonded to the center atom)
element 3 (the atom influencing the 1-2 bond in a bond-order sense)
m
gamma
lambda3 (1/distance units)
c
d
costheta0 (can be a value < -1 or > 1)
n
beta
lambda2 (1/distance units)
B (energy units)
R (distance units)
D (distance units)
lambda1 (1/distance units)
A (energy units) :ul
The n, beta, lambda2, B, lambda1, and A parameters are only used for
two-body interactions. The m, gamma, lambda3, c, d, and costheta0
parameters are only used for three-body interactions. The R and D
parameters are used for both two-body and three-body interactions. The
non-annotated parameters are unitless. The value of m must be 3 or 1.
The Tersoff potential file must contain entries for all the elements
listed in the pair_coeff command. It can also contain entries for
additional elements not being used in a particular simulation; LAMMPS
ignores those entries.
For a single-element simulation, only a single entry is required
(e.g. SiSiSi). For a two-element simulation, the file must contain 8
entries (for SiSiSi, SiSiC, SiCSi, SiCC, CSiSi, CSiC, CCSi, CCC), that
specify Tersoff parameters for all permutations of the two elements
interacting in three-body configurations. Thus for 3 elements, 27
entries would be required, etc.
As annotated above, the first element in the entry is the center atom
in a three-body interaction and it is bonded to the 2nd atom and the
bond is influenced by the 3rd atom. Thus an entry for SiCC means Si
bonded to a C with another C atom influencing the bond. Thus
three-body parameters for SiCSi and SiSiC entries will not, in
general, be the same. The parameters used for the two-body
interaction come from the entry where the 2nd element is repeated.
Thus the two-body parameters for Si interacting with C, comes from the
SiCC entry.
The parameters used for a particular
three-body interaction come from the entry with the corresponding
three elements. The parameters used only for two-body interactions
(n, beta, lambda2, B, lambda1, and A) in entries whose 2nd and 3rd
element are different (e.g. SiCSi) are not used for anything and can
be set to 0.0 if desired.
Note that the twobody parameters in entries such as SiCC and CSiSi
are often the same, due to the common use of symmetric mixing rules,
but this is not always the case. For example, the beta and n parameters in
Tersoff_2 "(Tersoff_2)"_#Tersoff_21 are not symmetric.
We chose the above form so as to enable users to define all commonly
used variants of the Tersoff potential. In particular, our form
reduces to the original Tersoff form when m = 3 and gamma = 1, while
it reduces to the form of "Albe et al."_#Albe when beta = 1 and m = 1.
Note that in the current Tersoff implementation in LAMMPS, m must be
specified as either 3 or 1. Tersoff used a slightly different but
equivalent form for alloys, which we will refer to as Tersoff_2
potential "(Tersoff_2)"_#Tersoff_21. The {tersoff/table} style implements
Tersoff_2 parameterization only.
LAMMPS parameter values for Tersoff_2 can be obtained as follows:
gamma_ijk = omega_ik, lambda3 = 0 and the value of
m has no effect. The parameters for species i and j can be calculated
using the Tersoff_2 mixing rules:
:c,image(Eqs/pair_tersoff_2.jpg)
Tersoff_2 parameters R and S must be converted to the LAMMPS
parameters R and D (R is different in both forms), using the following
relations: R=(R'+S')/2 and D=(S'-R')/2, where the primes indicate the
Tersoff_2 parameters.
In the potentials directory, the file SiCGe.tersoff provides the
LAMMPS parameters for Tersoff's various versions of Si, as well as his
alloy parameters for Si, C, and Ge. This file can be used for pure Si,
(three different versions), pure C, pure Ge, binary SiC, and binary
SiGe. LAMMPS will generate an error if this file is used with any
combination involving C and Ge, since there are no entries for the GeC
interactions (Tersoff did not publish parameters for this
cross-interaction.) Tersoff files are also provided for the SiC alloy
(SiC.tersoff) and the GaN (GaN.tersoff) alloys.
Many thanks to Rutuparna Narulkar, David Farrell, and Xiaowang Zhou
for helping clarify how Tersoff parameters for alloys have been
defined in various papers.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above from values in the potential file.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style is part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
The Tersoff potential files provided with LAMMPS (see the potentials
directory) are parameterized for metal "units"_units.html. You can
use the Tersoff potential with any LAMMPS units, but you would need to
create your own Tersoff potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Tersoff_11)
[(Tersoff_1)] J. Tersoff, Phys Rev B, 37, 6991 (1988).
:link(Albe)
[(Albe)] J. Nord, K. Albe, P. Erhart, and K. Nordlund, J. Phys.:
Condens. Matter, 15, 5649(2003).
:link(Tersoff_21)
[(Tersoff_2)] J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248)
diff --git a/doc/src/pair_tersoff_mod.txt b/doc/src/pair_tersoff_mod.txt
index ff703063b..e0c2b5a5c 100644
--- a/doc/src/pair_tersoff_mod.txt
+++ b/doc/src/pair_tersoff_mod.txt
@@ -1,207 +1,207 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style tersoff/mod command :h3
pair_style tersoff/mod/c command :h3
pair_style tersoff/mod/gpu command :h3
pair_style tersoff/mod/kk command :h3
pair_style tersoff/mod/omp command :h3
pair_style tersoff/mod/c/omp command :h3
[Syntax:]
pair_style tersoff/mod :pre
pair_style tersoff/mod/c :pre
[Examples:]
pair_style tersoff/mod
pair_coeff * * Si.tersoff.mod Si Si :pre
pair_style tersoff/mod/c
pair_coeff * * Si.tersoff.modc Si Si :pre
[Description:]
The {tersoff/mod} and {tersoff/mod/c} styles computes a bond-order type
interatomic potential "(Kumagai)"_#Kumagai based on a 3-body Tersoff
potential "(Tersoff_1)"_#Tersoff_12, "(Tersoff_2)"_#Tersoff_22 with
modified cutoff function and angular-dependent term, giving the energy
E of a system of atoms as
:c,image(Eqs/pair_tersoff_mod.jpg)
where f_R is a two-body term and f_A includes three-body interactions.
The summations in the formula are over all neighbors J and K of atom I
within a cutoff distance = R + D.
The {tersoff/mod/c} style differs from {tersoff/mod} only in the
formulation of the V_ij term, where it contains an additional c0 term.
:c,image(Eqs/pair_tersoff_mod_c.jpg)
The modified cutoff function f_C proposed by "(Murty)"_#Murty and
having a continuous second-order differential is employed. The
angular-dependent term g(theta) was modified to increase the
flexibility of the potential.
The {tersoff/mod} potential is fitted to both the elastic constants
and melting point by employing the modified Tersoff potential function
form in which the angular-dependent term is improved. The model
performs extremely well in describing the crystalline, liquid, and
amorphous phases "(Schelling)"_#Schelling.
Only a single pair_coeff command is used with the {tersoff/mod} style
which specifies a Tersoff/MOD potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of Tersoff/MOD elements to atom types :ul
As an example, imagine the Si.tersoff_mod file has Tersoff values for Si.
If your LAMMPS simulation has 3 Si atoms types, you would use the following
pair_coeff command:
pair_coeff * * Si.tersoff_mod Si Si Si :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The three Si arguments map LAMMPS atom types 1,2,3 to the Si element
in the Tersoff/MOD file. If a mapping value is specified as NULL, the
mapping is not performed. This can be used when a {tersoff/mod}
potential is used as part of the {hybrid} pair style. The NULL values
are placeholders for atom types that will be used with other
potentials.
Tersoff/MOD file in the {potentials} directory of the LAMMPS
distribution have a ".tersoff.mod" suffix. Potential files for the
{tersoff/mod/c} style have the suffix ".tersoff.modc". Lines that are
not blank or comments (starting with #) define parameters for a triplet
of elements. The parameters in a single entry correspond to
coefficients in the formulae above:
element 1 (the center atom in a 3-body interaction)
element 2 (the atom bonded to the center atom)
element 3 (the atom influencing the 1-2 bond in a bond-order sense)
beta
alpha
h
eta
beta_ters = 1 (dummy parameter)
lambda2 (1/distance units)
B (energy units)
R (distance units)
D (distance units)
lambda1 (1/distance units)
A (energy units)
n
c1
c2
c3
c4
c5
c0 (energy units, tersoff/mod/c only):ul
The n, eta, lambda2, B, lambda1, and A parameters are only used for
two-body interactions. The beta, alpha, c1, c2, c3, c4, c5, h
parameters are only used for three-body interactions. The R and D
parameters are used for both two-body and three-body interactions.
The c0 term applies to {tersoff/mod/c} only. The non-annotated
parameters are unitless.
The Tersoff/MOD potential file must contain entries for all the elements
listed in the pair_coeff command. It can also contain entries for
additional elements not being used in a particular simulation; LAMMPS
ignores those entries.
For a single-element simulation, only a single entry is required
(e.g. SiSiSi). As annotated above, the first element in the entry is
the center atom in a three-body interaction and it is bonded to the
2nd atom and the bond is influenced by the 3rd atom. Thus an entry
for SiSiSi means Si bonded to a Si with another Si atom influencing the bond.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style is part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
The Tersoff/MOD potential files provided with LAMMPS (see the potentials
directory) are parameterized for metal "units"_units.html. You can
use the Tersoff/MOD potential with any LAMMPS units, but you would need to
create your own Tersoff/MOD potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Kumagai)
[(Kumagai)] T. Kumagai, S. Izumi, S. Hara, S. Sakai,
Comp. Mat. Science, 39, 457 (2007).
:link(Tersoff_12)
[(Tersoff_1)] J. Tersoff, Phys Rev B, 37, 6991 (1988).
:link(Tersoff_22)
[(Tersoff_2)] J. Tersoff, Phys Rev B, 38, 9902 (1988).
:link(Murty)
[(Murty)] M.V.R. Murty, H.A. Atwater, Phys Rev B, 51, 4889 (1995).
:link(Schelling)
[(Schelling)] Patrick K. Schelling, Comp. Mat. Science, 44, 274 (2008).
diff --git a/doc/src/pair_tersoff_zbl.txt b/doc/src/pair_tersoff_zbl.txt
index 18e54749a..21d57e4e8 100644
--- a/doc/src/pair_tersoff_zbl.txt
+++ b/doc/src/pair_tersoff_zbl.txt
@@ -1,268 +1,268 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style tersoff/zbl command :h3
pair_style tersoff/zbl/gpu command :h3
pair_style tersoff/zbl/kk command :h3
pair_style tersoff/zbl/omp command :h3
[Syntax:]
pair_style tersoff/zbl :pre
[Examples:]
pair_style tersoff/zbl
pair_coeff * * SiC.tersoff.zbl Si C Si :pre
[Description:]
The {tersoff/zbl} style computes a 3-body Tersoff potential
"(Tersoff_1)"_#zbl-Tersoff_1 with a close-separation pairwise modification
based on a Coulomb potential and the Ziegler-Biersack-Littmark
universal screening function "(ZBL)"_#zbl-ZBL, giving the energy E of a
system of atoms as
:c,image(Eqs/pair_tersoff_zbl.jpg)
The f_F term is a fermi-like function used to smoothly connect the ZBL
repulsive potential with the Tersoff potential. There are 2
parameters used to adjust it: A_F and r_C. A_F controls how "sharp"
the transition is between the two, and r_C is essentially the cutoff
for the ZBL potential.
For the ZBL portion, there are two terms. The first is the Coulomb
repulsive term, with Z1, Z2 as the number of protons in each nucleus,
e as the electron charge (1 for metal and real units) and epsilon0 as
the permittivity of vacuum. The second part is the ZBL universal
screening function, with a0 being the Bohr radius (typically 0.529
Angstroms), and the remainder of the coefficients provided by the
original paper. This screening function should be applicable to most
systems. However, it is only accurate for small separations
(i.e. less than 1 Angstrom).
For the Tersoff portion, f_R is a two-body term and f_A includes
three-body interactions. The summations in the formula are over all
neighbors J and K of atom I within a cutoff distance = R + D.
Only a single pair_coeff command is used with the {tersoff/zbl} style
which specifies a Tersoff/ZBL potential file with parameters for all
needed elements. These are mapped to LAMMPS atom types by specifying
N additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of Tersoff/ZBL elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine the SiC.tersoff.zbl file has Tersoff/ZBL values
for Si and C. If your LAMMPS simulation has 4 atoms types and you
want the 1st 3 to be Si, and the 4th to be C, you would use the
following pair_coeff command:
pair_coeff * * SiC.tersoff Si Si Si C :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Si arguments map LAMMPS atom types 1,2,3 to the Si
element in the Tersoff/ZBL file. The final C argument maps LAMMPS
atom type 4 to the C element in the Tersoff/ZBL file. If a mapping
value is specified as NULL, the mapping is not performed. This can be
used when a {tersoff/zbl} potential is used as part of the {hybrid}
pair style. The NULL values are placeholders for atom types that will
be used with other potentials.
Tersoff/ZBL files in the {potentials} directory of the LAMMPS
distribution have a ".tersoff.zbl" suffix. Lines that are not blank
or comments (starting with #) define parameters for a triplet of
elements. The parameters in a single entry correspond to coefficients
in the formula above:
element 1 (the center atom in a 3-body interaction)
element 2 (the atom bonded to the center atom)
element 3 (the atom influencing the 1-2 bond in a bond-order sense)
m
gamma
lambda3 (1/distance units)
c
d
costheta0 (can be a value < -1 or > 1)
n
beta
lambda2 (1/distance units)
B (energy units)
R (distance units)
D (distance units)
lambda1 (1/distance units)
A (energy units)
Z_i
Z_j
ZBLcut (distance units)
ZBLexpscale (1/distance units) :ul
The n, beta, lambda2, B, lambda1, and A parameters are only used for
two-body interactions. The m, gamma, lambda3, c, d, and costheta0
parameters are only used for three-body interactions. The R and D
parameters are used for both two-body and three-body interactions. The
Z_i,Z_j, ZBLcut, ZBLexpscale parameters are used in the ZBL repulsive
portion of the potential and in the Fermi-like function. The
non-annotated parameters are unitless. The value of m must be 3 or 1.
The Tersoff/ZBL potential file must contain entries for all the
elements listed in the pair_coeff command. It can also contain
entries for additional elements not being used in a particular
simulation; LAMMPS ignores those entries.
For a single-element simulation, only a single entry is required
(e.g. SiSiSi). For a two-element simulation, the file must contain 8
entries (for SiSiSi, SiSiC, SiCSi, SiCC, CSiSi, CSiC, CCSi, CCC), that
specify Tersoff parameters for all permutations of the two elements
interacting in three-body configurations. Thus for 3 elements, 27
entries would be required, etc.
As annotated above, the first element in the entry is the center atom
in a three-body interaction and it is bonded to the 2nd atom and the
bond is influenced by the 3rd atom. Thus an entry for SiCC means Si
bonded to a C with another C atom influencing the bond. Thus
three-body parameters for SiCSi and SiSiC entries will not, in
general, be the same. The parameters used for the two-body
interaction come from the entry where the 2nd element is repeated.
Thus the two-body parameters for Si interacting with C, comes from the
SiCC entry.
The parameters used for a particular
three-body interaction come from the entry with the corresponding
three elements. The parameters used only for two-body interactions
(n, beta, lambda2, B, lambda1, and A) in entries whose 2nd and 3rd
element are different (e.g. SiCSi) are not used for anything and can
be set to 0.0 if desired.
Note that the twobody parameters in entries such as SiCC and CSiSi
are often the same, due to the common use of symmetric mixing rules,
but this is not always the case. For example, the beta and n parameters in
Tersoff_2 "(Tersoff_2)"_#zbl-Tersoff_2 are not symmetric.
We chose the above form so as to enable users to define all commonly
used variants of the Tersoff portion of the potential. In particular,
our form reduces to the original Tersoff form when m = 3 and gamma =
1, while it reduces to the form of "Albe et al."_#zbl-Albe when beta = 1
and m = 1. Note that in the current Tersoff implementation in LAMMPS,
m must be specified as either 3 or 1. Tersoff used a slightly
different but equivalent form for alloys, which we will refer to as
Tersoff_2 potential "(Tersoff_2)"_#zbl-Tersoff_2.
LAMMPS parameter values for Tersoff_2 can be obtained as follows:
gamma = omega_ijk, lambda3 = 0 and the value of
m has no effect. The parameters for species i and j can be calculated
using the Tersoff_2 mixing rules:
:c,image(Eqs/pair_tersoff_2.jpg)
Tersoff_2 parameters R and S must be converted to the LAMMPS
parameters R and D (R is different in both forms), using the following
relations: R=(R'+S')/2 and D=(S'-R')/2, where the primes indicate the
Tersoff_2 parameters.
In the potentials directory, the file SiCGe.tersoff provides the
LAMMPS parameters for Tersoff's various versions of Si, as well as his
alloy parameters for Si, C, and Ge. This file can be used for pure Si,
(three different versions), pure C, pure Ge, binary SiC, and binary
SiGe. LAMMPS will generate an error if this file is used with any
combination involving C and Ge, since there are no entries for the GeC
interactions (Tersoff did not publish parameters for this
cross-interaction.) Tersoff files are also provided for the SiC alloy
(SiC.tersoff) and the GaN (GaN.tersoff) alloys.
Many thanks to Rutuparna Narulkar, David Farrell, and Xiaowang Zhou
for helping clarify how Tersoff parameters for alloys have been
defined in various papers. Also thanks to Ram Devanathan for
providing the base ZBL implementation.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above from values in the potential file.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This pair style is part of the MANYBODY package. It is only enabled
if LAMMPS was built with that package. See
the "Making LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires the "newton"_newton.html setting to be "on"
for pair interactions.
The Tersoff/ZBL potential files provided with LAMMPS (see the
potentials directory) are parameterized for metal "units"_units.html.
You can use the Tersoff potential with any LAMMPS units, but you would
need to create your own Tersoff potential file with coefficients
listed in the appropriate units if your simulation doesn't use "metal"
units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(zbl-Tersoff_1)
[(Tersoff_1)] J. Tersoff, Phys Rev B, 37, 6991 (1988).
:link(zbl-ZBL)
[(ZBL)] J.F. Ziegler, J.P. Biersack, U. Littmark, 'Stopping and Ranges
of Ions in Matter' Vol 1, 1985, Pergamon Press.
:link(zbl-Albe)
[(Albe)] J. Nord, K. Albe, P. Erhart and K. Nordlund, J. Phys.:
Condens. Matter, 15, 5649(2003).
:link(zbl-Tersoff_2)
[(Tersoff_2)] J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248)
diff --git a/doc/src/pair_thole.txt b/doc/src/pair_thole.txt
index 61ca0b5c3..41a4059ce 100644
--- a/doc/src/pair_thole.txt
+++ b/doc/src/pair_thole.txt
@@ -1,193 +1,193 @@
<script type="text/javascript"
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({ TeX: { equationNumbers: {autoNumber: "AMS"} } });
</script>
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style thole command :h3
pair_style lj/cut/thole/long command :h3
pair_style lj/cut/thole/long/omp command :h3
[Syntax:]
pair_style style args :pre
style = {thole} or {lj/cut/thole/long} or {lj/cut/thole/long/omp}
args = list of arguments for a particular style :ul
{thole} args = damp cutoff
damp = global damping parameter
cutoff = global cutoff (distance units)
{lj/cut/thole/long} or {lj/cut/thole/long/omp} args = damp cutoff (cutoff2)
damp = global damping parameter
cutoff = global cutoff for LJ (and Thole if only 1 arg) (distance units)
cutoff2 = global cutoff for Thole (optional) (distance units) :pre
[Examples:]
pair_style hybrid/overlay ... thole 2.6 12.0
pair_coeff 1 1 thole 1.0
pair_coeff 1 2 thole 1.0 2.6 10.0
pair_coeff * 2 thole 1.0 2.6 :pre
pair_style lj/cut/thole/long 2.6 12.0 :pre
[Description:]
The {thole} pair styles are meant to be used with force fields that
include explicit polarization through Drude dipoles. This link
describes how to use the "thermalized Drude oscillator
model"_tutorial_drude.html in LAMMPS and polarizable models in LAMMPS
are discussed in "this Section"_Section_howto.html#howto_25.
The {thole} pair style should be used as a sub-style within in the
"pair_hybrid/overlay"_pair_hybrid.html command, in conjunction with a
main pair style including Coulomb interactions, i.e. any pair style
containing {coul/cut} or {coul/long} in its style name.
The {lj/cut/thole/long} pair style is equivalent to, but more convenient that
the frequent combination {hybrid/overlay lj/cut/coul/long cutoff thole damp
cutoff2}. It is not only a shorthand for this pair_style combination, but
it also allows for mixing pair coefficients instead of listing them all.
The {lj/cut/thole/long} pair style is also a bit faster because it avoids an
overlay and can benefit from OMP acceleration. Moreover, it uses a more
precise approximation of the direct Coulomb interaction at short range similar
to "coul/long/cs"_pair_cs.html, which stabilizes the temperature of
Drude particles.
The {thole} pair styles compute the Coulomb interaction damped at
short distances by a function
\begin\{equation\} T_\{ij\}(r_\{ij\}) = 1 - \left( 1 +
\frac\{s_\{ij\} r_\{ij\} \}\{2\} \right)
\exp \left( - s_\{ij\} r_\{ij\} \right) \end\{equation\}
This function results from an adaptation to point charges
"(Noskov)"_#Noskov1 of the dipole screening scheme originally proposed
by "Thole"_#Thole1. The scaling coefficient \(s_\{ij\} \) is determined
by the polarizability of the atoms, \( \alpha_i \), and by a Thole
damping parameter \( a \). This Thole damping parameter usually takes
a value of 2.6, but in certain force fields the value can depend upon
the atom types. The mixing rule for Thole damping parameters is the
arithmetic average, and for polarizabilities the geometric average
between the atom-specific values.
\begin\{equation\} s_\{ij\} = \frac\{ a_\{ij\} \}\{
(\alpha_\{ij\})^\{1/3\} \} = \frac\{ (a_i + a_j)/2 \}\{
\[(\alpha_i\alpha_j)^\{1/2\}\]^\{1/3\} \} \end\{equation\}
The damping function is only applied to the interactions between the
point charges representing the induced dipoles on polarizable sites,
that is, charges on Drude particles, \( q_\{D,i\} \), and opposite
charges, \( -q_\{D,i\} \), located on the respective core particles
(to which each Drude particle is bonded). Therefore, Thole screening
is not applied to the full charge of the core particle \( q_i \), but
only to the \( -q_\{D,i\} \) part of it.
The interactions between core charges are subject to the weighting
factors set by the "special_bonds"_special_bonds.html command. The
interactions between Drude particles and core charges or
non-polarizable atoms are also subject to these weighting factors. The
Drude particles inherit the 1-2, 1-3 and 1-4 neighbor relations from
their respective cores.
For pair_style {thole}, the following coefficients must be defined for
each pair of atoms types via the "pair_coeff"_pair_coeff.html command
as in the example above.
alpha (distance units^3)
damp
cutoff (distance units) :ul
The last two coefficients are optional. If not specified the global
Thole damping parameter or global cutoff specified in the pair_style
command are used. In order to specify a cutoff (third argument) a damp
parameter (second argument) must also be specified.
For pair style {lj/cut/thole/long}, the following coefficients must be
defined for each pair of atoms types via the "pair_coeff"_pair_coeff.html
command.
epsilon (energy units)
sigma (length units)
alpha (distance units^3)
damps
LJ cutoff (distance units) :ul
The last two coefficients are optional and default to the global values from
the {pair_style} command line.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
[Mixing]:
The {thole} pair style does not support mixing. Thus, coefficients
for all I,J pairs must be specified explicitly.
The {lj/cut/thole/long} pair style does support mixing. Mixed coefficients
are defined using
\begin\{equation\} \alpha_\{ij\} = \sqrt\{\alpha_i\alpha_j\}\end\{equation\}
\begin\{equation\} a_\{ij\} = \frac 1 2 (a_i + a_j)\end\{equation\}
[Restrictions:]
These pair styles are part of the USER-DRUDE package. They are only
enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This pair_style should currently not be used with the "charmm dihedral
style"_dihedral_charmm.html if the latter has non-zero 1-4 weighting
factors. This is because the {thole} pair style does not know which
pairs are 1-4 partners of which dihedrals.
The {lj/cut/thole/long} pair style should be used with a "Kspace solver"_kspace_style.html
like PPPM or Ewald, which is only enabled if LAMMPS was built with the kspace
package.
[Related commands:]
"fix drude"_fix_drude.html, "fix
langevin/drude"_fix_langevin_drude.html, "fix
drude/transform"_fix_drude_transform.html, "compute
temp/drude"_compute_temp_drude.html
"pair_style lj/cut/coul/long"_pair_lj.html
[Default:] none
:line
:link(Noskov1)
[(Noskov)] Noskov, Lamoureux and Roux, J Phys Chem B, 109, 6705 (2005).
:link(Thole1)
[(Thole)] Chem Phys, 59, 341 (1981).
diff --git a/doc/src/pair_vashishta.txt b/doc/src/pair_vashishta.txt
index 9c275a61d..d9c66d45c 100644
--- a/doc/src/pair_vashishta.txt
+++ b/doc/src/pair_vashishta.txt
@@ -1,247 +1,247 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style vashishta command :h3
pair_style vashishta/gpu command :h3
pair_style vashishta/omp command :h3
pair_style vashishta/kk command :h3
pair_style vashishta/table command :h3
pair_style vashishta/table/omp command :h3
[Syntax:]
pair_style style args :pre
style = {vashishta} or {vashishta/table} or {vashishta/omp} or {vashishta/table/omp}
args = list of arguments for a particular style :ul
{vashishta} or {vashishta/omp} args = none
{vashishta/table} or {vashishta/table/omp} args = Ntable cutinner
Ntable = # of tabulation points
cutinner = tablulate from cutinner to cutoff :pre
[Examples:]
pair_style vashishta
pair_coeff * * SiC.vashishta Si C :pre
pair_style vashishta/table 100000 0.2
pair_coeff * * SiC.vashishta Si C :pre
[Description:]
The {vashishta} and {vashishta/table} styles compute the combined
2-body and 3-body family of potentials developed in the group of Priya
Vashishta and collaborators. By combining repulsive, screened
Coulombic, screened charge-dipole, and dispersion interactions with a
bond-angle energy based on the Stillinger-Weber potential, this
potential has been used to describe a variety of inorganic compounds,
including SiO2 "Vashishta1990"_#Vashishta1990, SiC
"Vashishta2007"_#Vashishta2007, and InP "Branicio2009"_#Branicio2009.
The potential for the energy U of a system of atoms is
:c,image(Eqs/pair_vashishta.jpg)
where we follow the notation used in "Branicio2009"_#Branicio2009.
U2 is a two-body term and U3 is a three-body term. The
summation over two-body terms is over all neighbors J within
a cutoff distance = {rc}. The twobody terms are shifted and
tilted by a linear function so that the energy and force are
both zero at {rc}. The summation over three-body terms
is over all neighbors J and K within a cut-off distance = {r0},
where the exponential screening function becomes zero.
The {vashishta} style computes these formulas analytically. The
{vashishta/table} style tabulates the analytic values for {Ntable}
points from cutinner to the cutoff of the potential. The points are
equally spaced in R^2 space from cutinner^2 to cutoff^2. For the
two-body term in the above equation, a linear interpolation for each
pairwise distance between adjacent points in the table. In practice
the tabulated version can run 3-5x faster than the analytic version
with with moderate to little loss of accuracy for Ntable values
between 10000 and 1000000. It is not recommended to use less than
5000 tabulation points.
Only a single pair_coeff command is used with either style which
specifies a Vashishta potential file with parameters for all needed
elements. These are mapped to LAMMPS atom types by specifying N
additional arguments after the filename in the pair_coeff command,
where N is the number of LAMMPS atom types:
filename
N element names = mapping of Vashishta elements to atom types :ul
See the "pair_coeff"_pair_coeff.html doc page for alternate ways
to specify the path for the potential file.
As an example, imagine a file SiC.vashishta has parameters for
Si and C. If your LAMMPS simulation has 4 atoms types and you want
the 1st 3 to be Si, and the 4th to be C, you would use the following
pair_coeff command:
pair_coeff * * SiC.vashishta Si Si Si C :pre
The 1st 2 arguments must be * * so as to span all LAMMPS atom types.
The first three Si arguments map LAMMPS atom types 1,2,3 to the Si
element in the file. The final C argument maps LAMMPS atom type 4
to the C element in the file. If a mapping value is specified as
NULL, the mapping is not performed. This can be used when a {vashishta}
potential is used as part of the {hybrid} pair style. The NULL values
are placeholders for atom types that will be used with other
potentials.
Vashishta files in the {potentials} directory of the LAMMPS
distribution have a ".vashishta" suffix. Lines that are not blank or
comments (starting with #) define parameters for a triplet of
elements. The parameters in a single entry correspond to the two-body
and three-body coefficients in the formulae above:
element 1 (the center atom in a 3-body interaction)
element 2
element 3
H (energy units)
eta
Zi (electron charge units)
Zj (electron charge units)
lambda1 (distance units)
D (energy units)
lambda4 (distance units)
W (energy units)
rc (distance units)
B (energy units)
gamma
r0 (distance units)
C
costheta0 :ul
The non-annotated parameters are unitless. The Vashishta potential
file must contain entries for all the elements listed in the
pair_coeff command. It can also contain entries for additional
elements not being used in a particular simulation; LAMMPS ignores
those entries. For a single-element simulation, only a single entry
is required (e.g. SiSiSi). For a two-element simulation, the file
must contain 8 entries (for SiSiSi, SiSiC, SiCSi, SiCC, CSiSi, CSiC,
CCSi, CCC), that specify parameters for all permutations of the two
elements interacting in three-body configurations. Thus for 3
elements, 27 entries would be required, etc.
Depending on the particular version of the Vashishta potential, the
values of these parameters may be keyed to the identities of zero,
one, two, or three elements. In order to make the input file format
unambiguous, general, and simple to code, LAMMPS uses a slightly
confusing method for specifying parameters. All parameters are
divided into two classes: two-body and three-body. Two-body and
three-body parameters are handled differently, as described below.
The two-body parameters are H, eta, lambda1, D, lambda4, W, rc, gamma,
and r0. They appear in the above formulae with two subscripts. The
parameters Zi and Zj are also classified as two-body parameters, even
though they only have 1 subscript. The three-body parameters are B,
C, costheta0. They appear in the above formulae with three
subscripts. Two-body and three-body parameters are handled
differently, as described below.
The first element in each entry is the center atom in a three-body
interaction, while the second and third elements are two neighbor
atoms. Three-body parameters for a central atom I and two neighbors J
and K are taken from the IJK entry. Note that even though three-body
parameters do not depend on the order of J and K, LAMMPS stores
three-body parameters for both IJK and IKJ. The user must ensure that
these values are equal. Two-body parameters for an atom I interacting
with atom J are taken from the IJJ entry, where the 2nd and 3rd
elements are the same. Thus the two-body parameters for Si interacting
with C come from the SiCC entry. Note that even though two-body
parameters (except possibly gamma and r0 in U3) do not depend on the
order of the two elements, LAMMPS will get the Si-C value from the
SiCC entry and the C-Si value from the CSiSi entry. The user must
ensure that these values are equal. Two-body parameters appearing in
entries where the 2nd and 3rd elements are different are stored but
never used. It is good practice to enter zero for these values. Note
that the three-body function U3 above contains the two-body parameters
gamma and r0. So U3 for a central C atom bonded to an Si atom and a
second C atom will take three-body parameters from the CSiC entry, but
two-body parameters from the CCC and CSiSi entries.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, where types I and J correspond to
two different element types, mixing is performed by LAMMPS as
described above from values in the potential file.
This pair style does not support the "pair_modify"_pair_modify.html
shift, table, and tail options.
This pair style does not write its information to "binary restart
files"_restart.html, since it is stored in potential files. Thus, you
need to re-specify the pair_style and pair_coeff commands in an input
script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
These pair style are part of the MANYBODY package. They is only
enabled if LAMMPS was built with that package. See the
"Making LAMMPS"_Section_start.html#start_3 section for more info.
These pair styles requires the "newton"_newton.html setting to be "on"
for pair interactions.
The Vashishta potential files provided with LAMMPS (see the potentials
directory) are parameterized for metal "units"_units.html. You can
use the Vashishta potential with any LAMMPS units, but you would need
to create your own potential file with coefficients listed in the
appropriate units if your simulation doesn't use "metal" units.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Vashishta1990)
[(Vashishta1990)] P. Vashishta, R. K. Kalia, J. P. Rino, Phys. Rev. B
41, 12197 (1990).
:link(Vashishta2007)
[(Vashishta2007)] P. Vashishta, R. K. Kalia, A. Nakano,
J. P. Rino. J. Appl. Phys. 101, 103515 (2007).
:link(Branicio2009)
[(Branicio2009)] Branicio, Rino, Gan and Tsuzuki, J. Phys Condensed
Matter 21 (2009) 095002
diff --git a/doc/src/pair_yukawa.txt b/doc/src/pair_yukawa.txt
index 26acdb2cc..61d6bde6a 100644
--- a/doc/src/pair_yukawa.txt
+++ b/doc/src/pair_yukawa.txt
@@ -1,104 +1,104 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style yukawa command :h3
pair_style yukawa/gpu command :h3
pair_style yukawa/omp command :h3
[Syntax:]
pair_style yukawa kappa cutoff :pre
kappa = screening length (inverse distance units)
cutoff = global cutoff for Yukawa interactions (distance units) :ul
[Examples:]
pair_style yukawa 2.0 2.5
pair_coeff 1 1 100.0 2.3
pair_coeff * * 100.0 :pre
[Description:]
Style {yukawa} computes pairwise interactions with the formula
:c,image(Eqs/pair_yukawa.jpg)
Rc is the cutoff.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
A (energy*distance units)
cutoff (distance units) :ul
The last coefficient is optional. If not specified, the global yukawa
cutoff is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the A coefficient and cutoff
distance for this pair style can be mixed. A is an energy value mixed
like a LJ epsilon. The default mix value is {geometric}. See the
"pair_modify" command for details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
diff --git a/doc/src/pair_yukawa_colloid.txt b/doc/src/pair_yukawa_colloid.txt
index ecdc1496a..2037a9451 100644
--- a/doc/src/pair_yukawa_colloid.txt
+++ b/doc/src/pair_yukawa_colloid.txt
@@ -1,155 +1,155 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style yukawa/colloid command :h3
pair_style yukawa/colloid/gpu command :h3
pair_style yukawa/colloid/omp command :h3
[Syntax:]
pair_style yukawa/colloid kappa cutoff :pre
kappa = screening length (inverse distance units)
cutoff = global cutoff for colloidal Yukawa interactions (distance units) :ul
[Examples:]
pair_style yukawa/colloid 2.0 2.5
pair_coeff 1 1 100.0 2.3
pair_coeff * * 100.0 :pre
[Description:]
Style {yukawa/colloid} computes pairwise interactions with the formula
:c,image(Eqs/pair_yukawa_colloid.jpg)
where Ri and Rj are the radii of the two particles and Rc is the
cutoff.
In contrast to "pair_style yukawa"_pair_yukawa.html, this functional
form arises from the Coulombic interaction between two colloid
particles, screened due to the presence of an electrolyte, see the
book by "Safran"_#Safran for a derivation in the context of DLVO
theory. "Pair_style yukawa"_pair_yukawa.html is a screened Coulombic
potential between two point-charges and uses no such approximation.
This potential applies to nearby particle pairs for which the Derjagin
approximation holds, meaning h << Ri + Rj, where h is the
surface-to-surface separation of the two particles.
When used in combination with "pair_style colloid"_pair_colloid.html,
the two terms become the so-called DLVO potential, which combines
electrostatic repulsion and van der Waals attraction.
The following coefficients must be defined for each pair of atoms
types via the "pair_coeff"_pair_coeff.html command as in the examples
above, or in the data file or restart files read by the
"read_data"_read_data.html or "read_restart"_read_restart.html
commands, or by mixing as described below:
A (energy/distance units)
cutoff (distance units) :ul
The prefactor A is determined from the relationship between surface
charge and surface potential due to the presence of electrolyte. Note
that the A for this potential style has different units than the A
used in "pair_style yukawa"_pair_yukawa.html. For low surface
potentials, i.e. less than about 25 mV, A can be written as:
A = 2 * PI * R*eps*eps0 * kappa * psi^2 :pre
where
R = colloid radius (distance units)
eps0 = permittivity of free space (charge^2/energy/distance units)
eps = relative permittivity of fluid medium (dimensionless)
kappa = inverse screening length (1/distance units)
psi = surface potential (energy/charge units) :ul
The last coefficient is optional. If not specified, the global
yukawa/colloid cutoff is used.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the A coefficient and cutoff
distance for this pair style can be mixed. A is an energy value mixed
like a LJ epsilon. The default mix value is {geometric}. See the
"pair_modify" command for details.
This pair style supports the "pair_modify"_pair_modify.html shift
option for the energy of the pair interaction.
The "pair_modify"_pair_modify.html table option is not relevant
for this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure.
This pair style writes its information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands do not need
to be specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:]
This style is part of the COLLOID package. It is only enabled if
LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
This pair style requires that atoms be finite-size spheres with a
diameter, as defined by the "atom_style sphere"_atom_style.html
command.
Per-particle polydispersity is not yet supported by this pair style;
per-type polydispersity is allowed. This means all particles of the
same type must have the same diameter. Each type can have a different
diameter.
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Safran)
[(Safran)] Safran, Statistical Thermodynamics of Surfaces, Interfaces,
And Membranes, Westview Press, ISBN: 978-0813340791 (2003).
diff --git a/doc/src/pair_zbl.txt b/doc/src/pair_zbl.txt
index 154fdc1c1..5ab672171 100644
--- a/doc/src/pair_zbl.txt
+++ b/doc/src/pair_zbl.txt
@@ -1,139 +1,139 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
pair_style zbl command :h3
pair_style zbl/gpu command :h3
pair_style zbl/omp command :h3
[Syntax:]
pair_style zbl inner outer :pre
inner = distance where switching function begins
outer = global cutoff for ZBL interaction :ul
[Examples:]
pair_style zbl 3.0 4.0
pair_coeff * * 73.0 73.0
pair_coeff 1 1 14.0 14.0 :pre
[Description:]
Style {zbl} computes the Ziegler-Biersack-Littmark (ZBL) screened nuclear
repulsion for describing high-energy collisions between atoms.
"(Ziegler)"_#Ziegler. It includes an additional switching function
that ramps the energy, force, and curvature smoothly to zero
between an inner and outer cutoff. The potential
energy due to a pair of atoms at a distance r_ij is given by:
:c,image(Eqs/pair_zbl.jpg)
where e is the electron charge, epsilon_0 is the electrical
permittivity of vacuum, and Z_i and Z_j are the nuclear charges of the
two atoms. The switching function S(r) is identical to that used by
"pair_style lj/gromacs"_pair_gromacs.html. Here, the inner and outer
cutoff are the same for all pairs of atom types.
The following coefficients must be defined for each pair of atom types
via the "pair_coeff"_pair_coeff.html command as in the examples above,
or in the LAMMPS data file.
Z_i (atomic number for first atom type, e.g. 13.0 for aluminum) :ul
Z_j (ditto for second atom type) :ul
The values of Z_i and Z_j are normally equal to the atomic
numbers of the two atom types. Thus, the user may optionally
specify only the coefficients for each I==I pair, and rely
on the obvious mixing rule for cross interactions (see below).
Note that when I==I it is required that Z_i == Z_j. When used
with "hybrid/overlay"_pair_hybrid.html and pairs are assigned
to more than one sub-style, the mixing rule is not used and
each pair of types interacting with the ZBL sub-style must
be included in a pair_coeff command.
NOTE: The numerical values of the exponential decay constants in the
screening function depend on the unit of distance. In the above
equation they are given for units of angstroms. LAMMPS will
automatically convert these values to the distance unit of the
specified LAMMPS "units"_units.html setting. The values of Z should
always be given as multiples of a proton's charge, e.g. 29.0 for
copper.
:line
Styles with a {gpu}, {intel}, {kk}, {omp}, or {opt} suffix are
functionally the same as the corresponding style without the suffix.
They have been optimized to run faster, depending on your available
hardware, as discussed in "Section 5"_Section_accelerate.html
of the manual. The accelerated styles take the same arguments and
should produce the same results, except for round-off and precision
issues.
These accelerated styles are part of the GPU, USER-INTEL, KOKKOS,
USER-OMP and OPT packages, respectively. They are only enabled if
LAMMPS was built with those packages. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Mixing, shift, table, tail correction, restart, rRESPA info]:
For atom type pairs I,J and I != J, the Z_i and Z_j coefficients
can be mixed by taking Z_i and Z_j from the values specified for
I == I and J == J cases. When used
with "hybrid/overlay"_pair_hybrid.html and pairs are assigned
to more than one sub-style, the mixing rule is not used and
each pair of types interacting with the ZBL sub-style
must be included in a pair_coeff command.
The "pair_modify"_pair_modify.html mix option has no effect on
the mixing behavior
The ZBL pair style does not support the "pair_modify"_pair_modify.html
shift option, since the ZBL interaction is already smoothed to 0.0 at
the cutoff.
The "pair_modify"_pair_modify.html table option is not relevant for
this pair style.
This pair style does not support the "pair_modify"_pair_modify.html
tail option for adding long-range tail corrections to energy and
pressure, since there are no corrections for a potential that goes to
0.0 at the cutoff.
This pair style does not write information to "binary restart
files"_restart.html, so pair_style and pair_coeff commands must be
specified in an input script that reads a restart file.
This pair style can only be used via the {pair} keyword of the
"run_style respa"_run_style.html command. It does not support the
{inner}, {middle}, {outer} keywords.
:line
[Restrictions:] none
[Related commands:]
"pair_coeff"_pair_coeff.html
[Default:] none
:line
:link(Ziegler)
[(Ziegler)] J.F. Ziegler, J. P. Biersack and U. Littmark, "The
Stopping and Range of Ions in Matter," Volume 1, Pergamon, 1985.
diff --git a/doc/src/partition.txt b/doc/src/partition.txt
index 9c1d560c8..610eee99b 100644
--- a/doc/src/partition.txt
+++ b/doc/src/partition.txt
@@ -1,73 +1,73 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
partition command :h3
[Syntax:]
partition style N command ... :pre
style = {yes} or {no}
N = partition number (see asterisk form below)
command = any LAMMPS command :ul
[Examples:]
partition yes 1 processors 4 10 6
partition no 5 print "Active partition"
partition yes *5 fix all nve
partition yes 6* fix all nvt temp 1.0 1.0 0.1 :pre
[Description:]
This command invokes the specified command on a subset of the
partitions of processors you have defined via the -partition
-command-line switch. See "Section 2.6"_Section_start.html#start_7
+command-line switch. See "Section 2.6"_Section_start.html#start_6
for an explanation of the switch.
Normally, every input script command in your script is invoked by
every partition. This behavior can be modified by defining world- or
universe-style "variables"_variable.html that have different values
for each partition. This mechanism can be used to cause your script
to jump to different input script files on different partitions, if
such a variable is used in a "jump"_jump.html command.
The "partition" command is another mechanism for having as input
script operate differently on different partitions. It is basically a
prefix on any LAMMPS command. The command will only be invoked on
the partition(s) specified by the {style} and {N} arguments.
If the {style} is {yes}, the command will be invoked on any partition
which matches the {N} argument. If the {style} is {no} the command
will be invoked on all the partitions which do not match the Np
argument.
Partitions are numbered from 1 to Np, where Np is the number of
partitions specified by the "-partition command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
{N} can be specified in one of two ways. An explicit numeric value
can be used, as in the 1st example above. Or a wild-card asterisk can
be used to span a range of partition numbers. This takes the form "*"
or "*n" or "n*" or "m*n". An asterisk with no numeric values means
all partitions from 1 to Np. A leading asterisk means all partitions
from 1 to n (inclusive). A trailing asterisk means all partitions
from n to Np (inclusive). A middle asterisk means all partitions from
m to n (inclusive).
This command can be useful for the "run_style verlet/split" command
which imposed requirements on how the "processors"_processors.html
command lays out a 3d grid of processors in each of 2 partitions.
[Restrictions:] none
[Related commands:]
"run_style verlet/split"_run_style.html
[Default:] none
diff --git a/doc/src/prd.txt b/doc/src/prd.txt
index 247d422b1..3c0305e31 100644
--- a/doc/src/prd.txt
+++ b/doc/src/prd.txt
@@ -1,324 +1,324 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
prd command :h3
[Syntax:]
prd N t_event n_dephase t_dephase t_correlate compute-ID seed keyword value ... :pre
N = # of timesteps to run (not including dephasing/quenching) :ulb,l
t_event = timestep interval between event checks :l
n_dephase = number of velocity randomizations to perform in each dephase run :l
t_dephase = number of timesteps to run dynamics after each velocity randomization during dephase :l
t_correlate = number of timesteps within which 2 consecutive events are considered to be correlated :l
compute-ID = ID of the compute used for event detection :l
random_seed = random # seed (positive integer) :l
zero or more keyword/value pairs may be appended :l
keyword = {min} or {temp} or {vel} :l
{min} values = etol ftol maxiter maxeval
etol = stopping tolerance for energy, used in quenching
ftol = stopping tolerance for force, used in quenching
maxiter = max iterations of minimize, used in quenching
maxeval = max number of force/energy evaluations, used in quenching
{temp} value = Tdephase
Tdephase = target temperature for velocity randomization, used in dephasing
{vel} values = loop dist
loop = {all} or {local} or {geom}, used in dephasing
dist = {uniform} or {gaussian}, used in dephasing
{time} value = {steps} or {clock}
{steps} = simulation runs for N timesteps on each replica (default)
{clock} = simulation runs for N timesteps across all replicas :pre
:ule
[Examples:]
prd 5000 100 10 10 100 1 54982
prd 5000 100 10 10 100 1 54982 min 0.1 0.1 100 200 :pre
[Description:]
Run a parallel replica dynamics (PRD) simulation using multiple
replicas of a system. One or more replicas can be used. The total
number of steps {N} to run can be interpreted in one of two ways; see
discussion of the {time} keyword below.
PRD is described in "this paper"_#Voter1998 by Art Voter. It is a method
for performing accelerated dynamics that is suitable for
infrequent-event systems that obey first-order kinetics. A good
overview of accelerated dynamics methods for such systems in given in
"this review paper"_#Voter2002prd from the same group. To quote from the
paper: "The dynamical evolution is characterized by vibrational
excursions within a potential basin, punctuated by occasional
transitions between basins." The transition probability is
characterized by p(t) = k*exp(-kt) where k is the rate constant.
Running multiple replicas gives an effective enhancement in the
timescale spanned by the multiple simulations, while waiting for an
event to occur.
Each replica runs on a partition of one or more processors. Processor
partitions are defined at run-time using the -partition command-line
-switch; see "Section 2.7"_Section_start.html#start_7 of the manual.
+switch; see "Section 2.6"_Section_start.html#start_6 of the manual.
Note that if you have MPI installed, you can run a multi-replica
simulation with more replicas (partitions) than you have physical
processors, e.g you can run a 10-replica simulation on one or two
processors. However for PRD, this makes little sense, since running a
replica on virtual instead of physical processors,offers no effective
parallel speed-up in searching for infrequent events. See "Section
6.5"_Section_howto.html#howto_5 of the manual for further discussion.
When a PRD simulation is performed, it is assumed that each replica is
running the same model, though LAMMPS does not check for this.
I.e. the simulation domain, the number of atoms, the interaction
potentials, etc should be the same for every replica.
A PRD run has several stages, which are repeated each time an "event"
occurs in one of the replicas, as defined below. The logic for a PRD
run is as follows:
while (time remains):
dephase for n_dephase*t_dephase steps
until (event occurs on some replica):
run dynamics for t_event steps
quench
check for uncorrelated event on any replica
until (no correlated event occurs):
run dynamics for t_correlate steps
quench
check for correlated event on this replica
event replica shares state with all replicas :pre
Before this loop begins, the state of the system on replica 0 is
shared with all replicas, so that all replicas begin from the same
initial state. The first potential energy basin is identified by
quenching (an energy minimization, see below) the initial state and
storing the resulting coordinates for reference.
In the first stage, dephasing is performed by each replica
independently to eliminate correlations between replicas. This is
done by choosing a random set of velocities, based on the
{random_seed} that is specified, and running {t_dephase} timesteps of
dynamics. This is repeated {n_dephase} times. At each of the
{n_dephase} stages, if an event occurs during the {t_dephase} steps of
dynamics for a particular replica, the replica repeats the stage until
no event occurs.
If the {temp} keyword is not specified, the target temperature for
velocity randomization for each replica is the current temperature of
that replica. Otherwise, it is the specified {Tdephase} temperature.
The style of velocity randomization is controlled using the keyword
{vel} with arguments that have the same meaning as their counterparts
in the "velocity"_velocity.html command.
In the second stage, each replica runs dynamics continuously, stopping
every {t_event} steps to check if a transition event has occurred.
This check is performed by quenching the system and comparing the
resulting atom coordinates to the coordinates from the previous basin.
The first time through the PRD loop, the "previous basin" is the set
of quenched coordinates from the initial state of the system.
A quench is an energy minimization and is performed by whichever
algorithm has been defined by the "min_style"_min_style.html command.
Minimization parameters may be set via the
"min_modify"_min_modify.html command and by the {min} keyword of the
PRD command. The latter are the settings that would be used with the
"minimize"_minimize.html command. Note that typically, you do not
need to perform a highly-converged minimization to detect a transition
event.
The event check is performed by a compute with the specified
{compute-ID}. Currently there is only one compute that works with the
PRD command, which is the "compute
event/displace"_compute_event_displace.html command. Other
event-checking computes may be added. "Compute
event/displace"_compute_event_displace.html checks whether any atom in
the compute group has moved further than a specified threshold
distance. If so, an "event" has occurred.
In the third stage, the replica on which the event occurred (event
replica) continues to run dynamics to search for correlated events.
This is done by running dynamics for {t_correlate} steps, quenching
every {t_event} steps, and checking if another event has occurred.
The first time no correlated event occurs, the final state of the
event replica is shared with all replicas, the new basin reference
coordinates are updated with the quenched state, and the outer loop
begins again. While the replica event is searching for correlated
events, all the other replicas also run dynamics and event checking
with the same schedule, but the final states are always overwritten by
the state of the event replica.
The outer loop of the pseudo-code above continues until {N} steps of
dynamics have been performed. Note that {N} only includes the
dynamics of stages 2 and 3, not the steps taken during dephasing or
the minimization iterations of quenching. The specified {N} is
interpreted in one of two ways, depending on the {time} keyword. If
the {time} value is {steps}, which is the default, then each replica
runs for {N} timesteps. If the {time} value is {clock}, then the
simulation runs until {N} aggregate timesteps across all replicas have
elapsed. This aggregate time is the "clock" time defined below, which
typically advances nearly M times faster than the timestepping on a
single replica, where M is the number of replicas.
:line
Four kinds of output can be generated during a PRD run: event
statistics, thermodynamic output by each replica, dump files, and
restart files.
When running with multiple partitions (each of which is a replica in
this case), the print-out to the screen and master log.lammps file is
limited to event statistics. Note that if a PRD run is performed on
only a single replica then the event statistics will be intermixed
with the usual thermodynamic output discussed below.
The quantities printed each time an event occurs are the timestep, CPU
time, clock, event number, a correlation flag, the number of
coincident events, and the replica number of the chosen event.
The timestep is the usual LAMMPS timestep, except that time does not
advance during dephasing or quenches, but only during dynamics. Note
that are two kinds of dynamics in the PRD loop listed above that
contribute to this timestepping. The first is when all replicas are
performing independent dynamics, waiting for an event to occur. The
second is when correlated events are being searched for, but only one
replica is running dynamics.
The CPU time is the total elapsed time on each processor, since the
start of the PRD run.
The clock is the same as the timestep except that it advances by M
steps per timestep during the first kind of dynamics when the M
replicas are running independently. The clock advances by only 1 step
per timestep during the second kind of dynamics, when only a single
replica is checking for a correlated event. Thus "clock" time
represents the aggregate time (in steps) that has effectively elapsed
during a PRD simulation on M replicas. If most of the PRD run is
spent in the second stage of the loop above, searching for infrequent
events, then the clock will advance nearly M times faster than it
would if a single replica was running. Note the clock time between
successive events should be drawn from p(t).
The event number is a counter that increments with each event, whether
it is uncorrelated or correlated.
The correlation flag will be 0 when an uncorrelated event occurs
during the second stage of the loop listed above, i.e. when all
replicas are running independently. The correlation flag will be 1
when a correlated event occurs during the third stage of the loop
listed above, i.e. when only one replica is running dynamics.
When more than one replica detects an event at the end of the same
event check (every {t_event} steps) during the second stage, then
one of them is chosen at random. The number of coincident events is
the number of replicas that detected an event. Normally, this value
should be 1. If it is often greater than 1, then either the number of
replicas is too large, or {t_event} is too large.
The replica number is the ID of the replica (from 0 to M-1) in which
the event occurred.
:line
When running on multiple partitions, LAMMPS produces additional log
files for each partition, e.g. log.lammps.0, log.lammps.1, etc. For
the PRD command, these contain the thermodynamic output for each
replica. You will see short runs and minimizations corresponding to
the dynamics and quench operations of the loop listed above. The
timestep will be reset appropriately depending on whether the
operation advances time or not.
After the PRD command completes, timing statistics for the PRD run are
printed in each replica's log file, giving a breakdown of how much CPU
time was spent in each stage (dephasing, dynamics, quenching, etc).
:line
Any "dump files"_dump.html defined in the input script, will be
written to during a PRD run at timesteps corresponding to both
uncorrelated and correlated events. This means the requested dump
frequency in the "dump"_dump.html command is ignored. There will be
one dump file (per dump command) created for all partitions.
The atom coordinates of the dump snapshot are those of the minimum
energy configuration resulting from quenching following a transition
event. The timesteps written into the dump files correspond to the
timestep at which the event occurred and NOT the clock. A dump
snapshot corresponding to the initial minimum state used for event
detection is written to the dump file at the beginning of each PRD
run.
:line
If the "restart"_restart.html command is used, a single restart file
for all the partitions is generated, which allows a PRD run to be
continued by a new input script in the usual manner.
The restart file is generated at the end of the loop listed above. If
no correlated events are found, this means it contains a snapshot of
the system at time T + {t_correlate}, where T is the time at which the
uncorrelated event occurred. If correlated events were found, then it
contains a snapshot of the system at time T + {t_correlate}, where T
is the time of the last correlated event.
The restart frequency specified in the "restart"_restart.html command
is interpreted differently when performing a PRD run. It does not
mean the timestep interval between restart files. Instead it means an
event interval for uncorrelated events. Thus a frequency of 1 means
write a restart file every time an uncorrelated event occurs. A
frequency of 10 means write a restart file every 10th uncorrelated
event.
When an input script reads a restart file from a previous PRD run, the
new script can be run on a different number of replicas or processors.
However, it is assumed that {t_correlate} in the new PRD command is
the same as it was previously. If not, the calculation of the "clock"
value for the first event in the new run will be slightly off.
:line
[Restrictions:]
This command can only be used if LAMMPS was built with the REPLICA
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
The {N} and {t_correlate} settings must be integer multiples of
{t_event}.
Runs restarted from restart file written during a PRD run will not
produce identical results due to changes in the random numbers used
for dephasing.
This command cannot be used when any fixes are defined that keep track
of elapsed time to perform time-dependent operations. Examples
include the "ave" fixes such as "fix ave/chunk"_fix_ave_chunk.html.
Also "fix dt/reset"_fix_dt_reset.html and "fix
deposit"_fix_deposit.html.
[Related commands:]
"compute event/displace"_compute_event_displace.html,
"min_modify"_min_modify.html, "min_style"_min_style.html,
"run_style"_run_style.html, "minimize"_minimize.html,
"velocity"_velocity.html, "temper"_temper.html, "neb"_neb.html,
"tad"_tad.html
[Default:]
The option defaults are min = 0.1 0.1 40 50, no temp setting, vel =
geom gaussian, and time = steps.
:line
:link(Voter1998)
[(Voter1998)] Voter, Phys Rev B, 57, 13985 (1998).
:link(Voter2002prd)
[(Voter2002)] Voter, Montalenti, Germann, Annual Review of Materials
Research 32, 321 (2002).
diff --git a/doc/src/processors.txt b/doc/src/processors.txt
index 781049af9..e54b2cede 100644
--- a/doc/src/processors.txt
+++ b/doc/src/processors.txt
@@ -1,340 +1,340 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
processors command :h3
[Syntax:]
processors Px Py Pz keyword args ... :pre
Px,Py,Pz = # of processors in each dimension of 3d grid overlaying the simulation domain :ulb,l
zero or more keyword/arg pairs may be appended :l
keyword = {grid} or {map} or {part} or {file} :l
{grid} arg = gstyle params ...
gstyle = {onelevel} or {twolevel} or {numa} or {custom}
onelevel params = none
twolevel params = Nc Cx Cy Cz
Nc = number of cores per node
Cx,Cy,Cz = # of cores in each dimension of 3d sub-grid assigned to each node
numa params = none
custom params = infile
infile = file containing grid layout
{map} arg = {cart} or {cart/reorder} or {xyz} or {xzy} or {yxz} or {yzx} or {zxy} or {zyx}
cart = use MPI_Cart() methods to map processors to 3d grid with reorder = 0
cart/reorder = use MPI_Cart() methods to map processors to 3d grid with reorder = 1
xyz,xzy,yxz,yzx,zxy,zyx = map processors to 3d grid in IJK ordering
{numa} arg = none
{part} args = Psend Precv cstyle
Psend = partition # (1 to Np) which will send its processor layout
Precv = partition # (1 to Np) which will recv the processor layout
cstyle = {multiple}
{multiple} = Psend grid will be multiple of Precv grid in each dimension
{file} arg = outfile
outfile = name of file to write 3d grid of processors to :pre
:ule
[Examples:]
processors * * 5
processors 2 4 4
processors * * 8 map xyz
processors * * * grid numa
processors * * * grid twolevel 4 * * 1
processors 4 8 16 grid custom myfile
processors * * * part 1 2 multiple :pre
[Description:]
Specify how processors are mapped as a regular 3d grid to the global
simulation box. The mapping involves 2 steps. First if there are P
processors it means choosing a factorization P = Px by Py by Pz so
that there are Px processors in the x dimension, and similarly for the
y and z dimensions. Second, the P processors are mapped to the
regular 3d grid. The arguments to this command control each of these
2 steps.
The Px, Py, Pz parameters affect the factorization. Any of the 3
parameters can be specified with an asterisk "*", which means LAMMPS
will choose the number of processors in that dimension of the grid.
It will do this based on the size and shape of the global simulation
box so as to minimize the surface-to-volume ratio of each processor's
sub-domain.
Choosing explicit values for Px or Py or Pz can be used to override
the default manner in which LAMMPS will create the regular 3d grid of
processors, if it is known to be sub-optimal for a particular problem.
E.g. a problem where the extent of atoms will change dramatically in a
particular dimension over the course of the simulation.
The product of Px, Py, Pz must equal P, the total # of processors
LAMMPS is running on. For a "2d simulation"_dimension.html, Pz must
equal 1.
Note that if you run on a prime number of processors P, then a grid
such as 1 x P x 1 will be required, which may incur extra
communication costs due to the high surface area of each processor's
sub-domain.
Also note that if multiple partitions are being used then P is the
number of processors in this partition; see "this
-section"_Section_start.html#start_7 for an explanation of the
+section"_Section_start.html#start_6 for an explanation of the
-partition command-line switch. Also note that you can prefix the
processors command with the "partition"_partition.html command to
easily specify different Px,Py,Pz values for different partitions.
You can use the "partition"_partition.html command to specify
different processor grids for different partitions, e.g.
partition yes 1 processors 4 4 4
partition yes 2 processors 2 3 2 :pre
NOTE: This command only affects the initial regular 3d grid created
when the simulation box is first specified via a
"create_box"_create_box.html or "read_data"_read_data.html or
"read_restart"_read_restart.html command. Or if the simulation box is
re-created via the "replicate"_replicate.html command. The same
regular grid is initially created, regardless of which
"comm_style"_comm_style.html command is in effect.
If load-balancing is never invoked via the "balance"_balance.html or
"fix balance"_fix_balance.html commands, then the initial regular grid
will persist for all simulations. If balancing is performed, some of
the methods invoked by those commands retain the logical topology of
the initial 3d grid, and the mapping of processors to the grid
specified by the processors command. However the grid spacings in
different dimensions may change, so that processors own sub-domains of
different sizes. If the "comm_style tiled"_comm_style.html command is
used, methods invoked by the balancing commands may discard the 3d
grid of processors and tile the simulation domain with sub-domains of
different sizes and shapes which no longer have a logical 3d
connectivity. If that occurs, all the information specified by the
processors command is ignored.
:line
The {grid} keyword affects the factorization of P into Px,Py,Pz and it
can also affect how the P processor IDs are mapped to the 3d grid of
processors.
The {onelevel} style creates a 3d grid that is compatible with the
Px,Py,Pz settings, and which minimizes the surface-to-volume ratio of
each processor's sub-domain, as described above. The mapping of
processors to the grid is determined by the {map} keyword setting.
The {twolevel} style can be used on machines with multicore nodes to
minimize off-node communication. It insures that contiguous
sub-sections of the 3d grid are assigned to all the cores of a node.
For example if {Nc} is 4, then 2x2x1 or 2x1x2 or 1x2x2 sub-sections of
the 3d grid will correspond to the cores of each node. This affects
both the factorization and mapping steps.
The {Cx}, {Cy}, {Cz} settings are similar to the {Px}, {Py}, {Pz}
settings, only their product should equal {Nc}. Any of the 3
parameters can be specified with an asterisk "*", which means LAMMPS
will choose the number of cores in that dimension of the node's
sub-grid. As with Px,Py,Pz, it will do this based on the size and
shape of the global simulation box so as to minimize the
surface-to-volume ratio of each processor's sub-domain.
NOTE: For the {twolevel} style to work correctly, it assumes the MPI
ranks of processors LAMMPS is running on are ordered by core and then
by node. E.g. if you are running on 2 quad-core nodes, for a total of
8 processors, then it assumes processors 0,1,2,3 are on node 1, and
processors 4,5,6,7 are on node 2. This is the default rank ordering
for most MPI implementations, but some MPIs provide options for this
ordering, e.g. via environment variable settings.
The {numa} style operates similar to the {twolevel} keyword except
that it auto-detects which cores are running on which nodes.
Currently, it does this in only 2 levels, but it may be extended in
the future to account for socket topology and other non-uniform memory
access (NUMA) costs. It also uses a different algorithm than the
{twolevel} keyword for doing the two-level factorization of the
simulation box into a 3d processor grid to minimize off-node
communication, and it does its own MPI-based mapping of nodes and
cores to the regular 3d grid. Thus it may produce a different layout
of the processors than the {twolevel} options.
The {numa} style will give an error if the number of MPI processes is
not divisible by the number of cores used per node, or any of the Px
or Py of Pz values is greater than 1.
NOTE: Unlike the {twolevel} style, the {numa} style does not require
any particular ordering of MPI ranks i norder to work correctly. This
is because it auto-detects which processes are running on which nodes.
The {custom} style uses the file {infile} to define both the 3d
factorization and the mapping of processors to the grid.
The file should have the following format. Any number of initial
blank or comment lines (starting with a "#" character) can be present.
The first non-blank, non-comment line should have
3 values:
Px Py Py :pre
These must be compatible with the total number of processors
and the Px, Py, Pz settings of the processors command.
This line should be immediately followed by
P = Px*Py*Pz lines of the form:
ID I J K :pre
where ID is a processor ID (from 0 to P-1) and I,J,K are the
processors location in the 3d grid. I must be a number from 1 to Px
(inclusive) and similarly for J and K. The P lines can be listed in
any order, but no processor ID should appear more than once.
:line
The {map} keyword affects how the P processor IDs (from 0 to P-1) are
mapped to the 3d grid of processors. It is only used by the
{onelevel} and {twolevel} grid settings.
The {cart} style uses the family of MPI Cartesian functions to perform
the mapping, namely MPI_Cart_create(), MPI_Cart_get(),
MPI_Cart_shift(), and MPI_Cart_rank(). It invokes the
MPI_Cart_create() function with its reorder flag = 0, so that MPI is
not free to reorder the processors.
The {cart/reorder} style does the same thing as the {cart} style
except it sets the reorder flag to 1, so that MPI can reorder
processors if it desires.
The {xyz}, {xzy}, {yxz}, {yzx}, {zxy}, and {zyx} styles are all
similar. If the style is IJK, then it maps the P processors to the
grid so that the processor ID in the I direction varies fastest, the
processor ID in the J direction varies next fastest, and the processor
ID in the K direction varies slowest. For example, if you select
style {xyz} and you have a 2x2x2 grid of 8 processors, the assignments
of the 8 octants of the simulation domain will be:
proc 0 = lo x, lo y, lo z octant
proc 1 = hi x, lo y, lo z octant
proc 2 = lo x, hi y, lo z octant
proc 3 = hi x, hi y, lo z octant
proc 4 = lo x, lo y, hi z octant
proc 5 = hi x, lo y, hi z octant
proc 6 = lo x, hi y, hi z octant
proc 7 = hi x, hi y, hi z octant :pre
Note that, in principle, an MPI implementation on a particular machine
should be aware of both the machine's network topology and the
specific subset of processors and nodes that were assigned to your
simulation. Thus its MPI_Cart calls can optimize the assignment of
MPI processes to the 3d grid to minimize communication costs. In
practice, however, few if any MPI implementations actually do this.
So it is likely that the {cart} and {cart/reorder} styles simply give
the same result as one of the IJK styles.
Also note, that for the {twolevel} grid style, the {map} setting is
used to first map the nodes to the 3d grid, then again to the cores
within each node. For the latter step, the {cart} and {cart/reorder}
styles are not supported, so an {xyz} style is used in their place.
:line
The {part} keyword affects the factorization of P into Px,Py,Pz.
It can be useful when running in multi-partition mode, e.g. with the
"run_style verlet/split"_run_style.html command. It specifies a
dependency between a sending partition {Psend} and a receiving
partition {Precv} which is enforced when each is setting up their own
mapping of their processors to the simulation box. Each of {Psend}
and {Precv} must be integers from 1 to Np, where Np is the number of
partitions you have defined via the "-partition command-line
-switch"_Section_start.html#start_7.
+switch"_Section_start.html#start_6.
A "dependency" means that the sending partition will create its
regular 3d grid as Px by Py by Pz and after it has done this, it will
send the Px,Py,Pz values to the receiving partition. The receiving
partition will wait to receive these values before creating its own
regular 3d grid and will use the sender's Px,Py,Pz values as a
constraint. The nature of the constraint is determined by the
{cstyle} argument.
For a {cstyle} of {multiple}, each dimension of the sender's processor
grid is required to be an integer multiple of the corresponding
dimension in the receiver's processor grid. This is a requirement of
the "run_style verlet/split"_run_style.html command.
For example, assume the sending partition creates a 4x6x10 grid = 240
processor grid. If the receiving partition is running on 80
processors, it could create a 4x2x10 grid, but it will not create a
2x4x10 grid, since in the y-dimension, 6 is not an integer multiple of
4.
NOTE: If you use the "partition"_partition.html command to invoke
different "processors" commands on different partitions, and you also
use the {part} keyword, then you must insure that both the sending and
receiving partitions invoke the "processors" command that connects the
2 partitions via the {part} keyword. LAMMPS cannot easily check for
this, but your simulation will likely hang in its setup phase if this
error has been made.
:line
The {file} keyword writes the mapping of the factorization of P
processors and their mapping to the 3d grid to the specified file
{outfile}. This is useful to check that you assigned physical
processors in the manner you desired, which can be tricky to figure
out, especially when running on multiple partitions or on, a multicore
machine or when the processor ranks were reordered by use of the
-"-reorder command-line switch"_Section_start.html#start_7 or due to
+"-reorder command-line switch"_Section_start.html#start_6 or due to
use of MPI-specific launch options such as a config file.
If you have multiple partitions you should insure that each one writes
to a different file, e.g. using a "world-style variable"_variable.html
for the filename. The file has a self-explanatory header, followed by
one-line per processor in this format:
world-ID universe-ID original-ID: I J K: name
The IDs are the processor's rank in this simulation (the world), the
universe (of multiple simulations), and the original MPI communicator
used to instantiate LAMMPS, respectively. The world and universe IDs
will only be different if you are running on more than one partition;
-see the "-partition command-line switch"_Section_start.html#start_7.
+see the "-partition command-line switch"_Section_start.html#start_6.
The universe and original IDs will only be different if you used the
-"-reorder command-line switch"_Section_start.html#start_7 to reorder
+"-reorder command-line switch"_Section_start.html#start_6 to reorder
the processors differently than their rank in the original
communicator LAMMPS was instantiated with.
I,J,K are the indices of the processor in the regular 3d grid, each
from 1 to Nd, where Nd is the number of processors in that dimension
of the grid.
The {name} is what is returned by a call to MPI_Get_processor_name()
and should represent an identifier relevant to the physical processors
in your machine. Note that depending on the MPI implementation,
multiple cores can have the same {name}.
:line
[Restrictions:]
This command cannot be used after the simulation box is defined by a
"read_data"_read_data.html or "create_box"_create_box.html command.
It can be used before a restart file is read to change the 3d
processor grid from what is specified in the restart file.
The {grid numa} keyword only currently works with the {map cart}
option.
The {part} keyword (for the receiving partition) only works with the
{grid onelevel} or {grid twolevel} options.
[Related commands:]
-"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_7
+"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_6
[Default:]
The option defaults are Px Py Pz = * * *, grid = onelevel, and map =
cart.
diff --git a/doc/src/read_data.txt b/doc/src/read_data.txt
index 6785eb106..a8aca5369 100644
--- a/doc/src/read_data.txt
+++ b/doc/src/read_data.txt
@@ -1,1154 +1,1154 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
read_data command :h3
[Syntax:]
read_data file keyword args ... :pre
file = name of data file to read in :ulb,l
zero or more keyword/arg pairs may be appended :l
keyword = {add} or {offset} or {shift} or {extra/atom/types} or {extra/bond/types} or {extra/angle/types} or {extra/dihedral/types} or {extra/improper/types} or {extra/bond/per/atom} or {extra/angle/per/atom} or {extra/dihedral/per/atom} or {extra/improper/per/atom} or {group} or {nocoeff} or {fix} :l
{add} arg = {append} or {Nstart} or {merge}
append = add new atoms with IDs appended to current IDs
Nstart = add new atoms with IDs starting with Nstart
merge = add new atoms with their IDs unchanged
{offset} args = toff boff aoff doff ioff
toff = offset to add to atom types
boff = offset to add to bond types
aoff = offset to add to angle types
doff = offset to add to dihedral types
ioff = offset to add to improper types
{shift} args = Sx Sy Sz
Sx,Sy,Sz = distance to shift atoms when adding to system (distance units)
{extra/atom/types} arg = # of extra atom types
{extra/bond/types} arg = # of extra bond types
{extra/angle/types} arg = # of extra angle types
{extra/dihedral/types} arg = # of extra dihedral types
{extra/improper/types} arg = # of extra improper types
{extra/bond/per/atom} arg = leave space for this many new bonds per atom
{extra/angle/per/atom} arg = leave space for this many new angles per atom
{extra/dihedral/per/atom} arg = leave space for this many new dihedrals per atom
{extra/improper/per/atom} arg = leave space for this many new impropers per atom
{extra/special/per/atom} arg = leave space for extra 1-2,1-3,1-4 interactions per atom
{group} args = groupID
groupID = add atoms in data file to this group
{nocoeff} = ignore force field parameters
{fix} args = fix-ID header-string section-string
fix-ID = ID of fix to process header lines and sections of data file
header-string = header lines containing this string will be passed to fix
section-string = section names with this string will be passed to fix :pre
:ule
[Examples:]
read_data data.lj
read_data ../run7/data.polymer.gz
read_data data.protein fix mycmap crossterm CMAP
read_data data.water add append offset 3 1 1 1 1 shift 0.0 0.0 50.0
read_data data.water add merge 1 group solvent :pre
[Description:]
Read in a data file containing information LAMMPS needs to run a
simulation. The file can be ASCII text or a gzipped text file
(detected by a .gz suffix). This is one of 3 ways to specify initial
atom coordinates; see the "read_restart"_read_restart.html and
"create_atoms"_create_atoms.html commands for alternative methods.
Also see the explanation of the "-restart command-line
-switch"_Section_start.html#start_7 which can convert a restart file to
+switch"_Section_start.html#start_6 which can convert a restart file to
a data file.
This command can be used multiple times to add new atoms and their
properties to an existing system by using the {add}, {offset}, and
{shift} keywords. See more details below, which includes the use case
for the {extra} keywords.
The {group} keyword adds all the atoms in the data file to the
specified group-ID. The group will be created if it does not already
exist. This is useful if you are reading multiple data files and wish
to put sets of atoms into different groups so they can be operated on
later. E.g. a group of added atoms can be moved to new positions via
the "displace_atoms"_displace_atoms.html command. Note that atoms
read from the data file are also always added to the "all" group. The
"group"_group.html command discusses atom groups, as used in LAMMPS.
The {nocoeff} keyword tells read_data to ignore force field parameters.
The various Coeff sections are still read and have to have the correct
number of lines, but they are not applied. This also allows to read a
data file without having any pair, bond, angle, dihedral or improper
styles defined, or to read a data file for a different force field.
The use of the {fix} keyword is discussed below.
:line
[Reading multiple data files]
The read_data command can be used multiple times with the same or
different data files to build up a complex system from components
contained in individual data files. For example one data file could
contain fluid in a confined domain; a second could contain wall atoms,
and the second file could be read a third time to create a wall on the
other side of the fluid. The third set of atoms could be rotated to
an opposing direction using the "displace_atoms"_displace_atoms.html
command, after the third read_data command is used.
The {add}, {offset}, {shift}, {extra}, and {group} keywords are
useful in this context.
If a simulation box does not yet exist, the {add} keyword
cannot be used; the read_data command is being used for the first
time. If a simulation box does exist, due to using the
"create_box"_create_box.html command, or a previous read_data command,
then the {add} keyword must be used.
NOTE: The simulation box size (xlo to xhi, ylo to yhi, zlo to zhi) in
the new data file will be merged with the existing simulation box to
create a large enough box in each dimension to contain both the
existing and new atoms. Each box dimension never shrinks due to this
merge operation, it only stays the same or grows. Care must be used if
you are growing the existing simulation box in a periodic dimension.
If there are existing atoms with bonds that straddle that periodic
boundary, then the atoms may become far apart if the box size grows.
This will separate the atoms in the bond, which can lead to "lost"
bond atoms or bad dynamics.
The three choices for the {add} argument affect how the IDs of atoms
in the data file are treated. If {append} is specified, atoms in the
data file are added to the current system, with their atom IDs reset
so that an atomID = M in the data file becomes atomID = N+M, where N
is the largest atom ID in the current system. This rule is applied to
all occurrences of atom IDs in the data file, e.g. in the Velocity or
Bonds section. If {Nstart} is specified, then {Nstart} is a numeric
value is given, e.g. 1000, so that an atomID = M in the data file
becomes atomID = 1000+M. If {merge} is specified, the data file atoms
are added to the current system without changing their IDs. They are
assumed to merge (without duplication) with the currently defined
atoms. It is up to you to insure there are no multiply defined atom
IDs, as LAMMPS only performs an incomplete check that this is the case
by insuring the resulting max atomID >= the number of atoms.
The {offset} and {shift} keywords can only be used if the {add}
keyword is also specified.
The {offset} keyword adds the specified offset values to the atom
types, bond types, angle types, dihedral types, and improper types as
they are read from the data file. E.g. if {toff} = 2, and the file
uses atom types 1,2,3, then the added atoms will have atom types
3,4,5. These offsets apply to all occurrences of types in the data
file, e.g. for the Atoms or Masses or Pair Coeffs or Bond Coeffs
sections. This makes it easy to use atoms and molecules and their
attributes from a data file in different simulations, where you want
their types (atom, bond, angle, etc) to be different depending on what
other types already exist. All five offset values must be specified,
but individual values will be ignored if the data file does not use
that attribute (e.g. no bonds).
The {shift} keyword can be used to specify an (Sx, Sy, Sz)
displacement applied to the coordinates of each atom. Sz must be 0.0
for a 2d simulation. This is a mechanism for adding structured
collections of atoms at different locations within the simulation box,
to build up a complex geometry. It is up to you to insure atoms do
not end up overlapping unphysically which would lead to bad dynamics.
Note that the "displace_atoms"_displace_atoms.html command can be used
to move a subset of atoms after they have been read from a data file.
Likewise, the "delete_atoms"_delete_atoms.html command can be used to
remove overlapping atoms. Note that the shift values (Sx, Sy, Sz) are
also added to the simulation box information (xlo, xhi, ylo, yhi, zlo,
zhi) in the data file to shift its boundaries. E.g. xlo_new = xlo +
Sx, xhi_new = xhi + Sx.
The {extra} keywords can only be used the first time the read_data
command is used. They are useful if you intend to add new atom, bond,
angle, etc types later with additional read_data commands. This is
because the maximum number of allowed atom, bond, angle, etc types is
set by LAMMPS when the system is first initialized. If you do not use
the {extra} keywords, then the number of these types will be limited
to what appears in the first data file you read. For example, if the
first data file is a solid substrate of Si, it will likely specify a
single atom type. If you read a second data file with a different
material (water molecules) that sit on top of the substrate, you will
want to use different atom types for those atoms. You can only do
this if you set the {extra/atom/types} keyword to a sufficiently large
value when reading the substrate data file. Note that use of the
{extra} keywords also allows each data file to contain sections like
Masses or Pair Coeffs or Bond Coeffs which are sized appropriately for
the number of types in that data file. If the {offset} keyword is
used appropriately when each data file is read, the values in those
sections will be stored correctly in the larger data structures
allocated by the use of the {extra} keywords. E.g. the substrate file
can list mass and pair coefficients for type 1 silicon atoms. The
water file can list mass and pair coefficients for type 1 and type 2
hydrogen and oxygen atoms. Use of the {extra} and {offset} keywords
will store those mass and pair coefficient values appropriately in
data structures that allow for 3 atom types (Si, H, O). Of course,
you would still need to specify coefficients for H/Si and O/Si
interactions in your input script to have a complete pairwise
interaction model.
An alternative to using the {extra} keywords with the read_data
command, is to use the "create_box"_create_box.html command to
initialize the simulation box and all the various type limits you need
via its {extra} keywords. Then use the read_data command one or more
times to populate the system with atoms, bonds, angles, etc, using the
{offset} keyword if desired to alter types used in the various data
files you read.
:line
[Format of a data file]
The structure of the data file is important, though many settings and
sections are optional or can come in any order. See the examples
directory for sample data files for different problems.
A data file has a header and a body. The header appears first. The
first line of the header is always skipped; it typically contains a
description of the file. Then lines are read one at a time. Lines
can have a trailing comment starting with '#' that is ignored. If the
line is blank (only whitespace after comment is deleted), it is
skipped. If the line contains a header keyword, the corresponding
value(s) is read from the line. If it doesn't contain a header
keyword, the line begins the body of the file.
The body of the file contains zero or more sections. The first line
of a section has only a keyword. This line can have a trailing
comment starting with '#' that is either ignored or can be used to
check for a style match, as described below. The next line is
skipped. The remaining lines of the section contain values. The
number of lines depends on the section keyword as described below.
Zero or more blank lines can be used between sections. Sections can
appear in any order, with a few exceptions as noted below.
The keyword {fix} can be used one or more times. Each usage specifies
a fix that will be used to process a specific portion of the data
file. Any header line containing {header-string} and any section with
a name containing {section-string} will be passed to the specified
fix. See the "fix property/atom"_fix_property_atom.html command for
an example of a fix that operates in this manner. The doc page for
the fix defines the syntax of the header line(s) and section(s) that
it reads from the data file. Note that the {header-string} can be
specified as NULL, in which case no header lines are passed to the
fix. This means that it can infer the length of its Section from
standard header settings, such as the number of atoms.
The formatting of individual lines in the data file (indentation,
spacing between words and numbers) is not important except that header
and section keywords (e.g. atoms, xlo xhi, Masses, Bond Coeffs) must
be capitalized as shown and can't have extra white space between their
words - e.g. two spaces or a tab between the 2 words in "xlo xhi" or
the 2 words in "Bond Coeffs", is not valid.
:line
[Format of the header of a data file]
These are the recognized header keywords. Header lines can come in
any order. The value(s) are read from the beginning of the line.
Thus the keyword {atoms} should be in a line like "1000 atoms"; the
keyword {ylo yhi} should be in a line like "-10.0 10.0 ylo yhi"; the
keyword {xy xz yz} should be in a line like "0.0 5.0 6.0 xy xz yz".
All these settings have a default value of 0, except the lo/hi box
size defaults are -0.5 and 0.5. A line need only appear if the value
is different than the default.
{atoms} = # of atoms in system
{bonds} = # of bonds in system
{angles} = # of angles in system
{dihedrals} = # of dihedrals in system
{impropers} = # of impropers in system
{atom types} = # of atom types in system
{bond types} = # of bond types in system
{angle types} = # of angle types in system
{dihedral types} = # of dihedral types in system
{improper types} = # of improper types in system
{extra bond per atom} = leave space for this many new bonds per atom (deprecated, use extra/bond/per/atom keyword)
{extra angle per atom} = leave space for this many new angles per atom (deprecated, use extra/angle/per/atom keyword)
{extra dihedral per atom} = leave space for this many new dihedrals per atom (deprecated, use extra/dihedral/per/atom keyword)
{extra improper per atom} = leave space for this many new impropers per atom (deprecated, use extra/improper/per/atom keyword)
{extra special per atom} = leave space for this many new special bonds per atom (deprecated, use extra/special/per/atom keyword)
{ellipsoids} = # of ellipsoids in system
{lines} = # of line segments in system
{triangles} = # of triangles in system
{bodies} = # of bodies in system
{xlo xhi} = simulation box boundaries in x dimension
{ylo yhi} = simulation box boundaries in y dimension
{zlo zhi} = simulation box boundaries in z dimension
{xy xz yz} = simulation box tilt factors for triclinic system :ul
The initial simulation box size is determined by the lo/hi settings.
In any dimension, the system may be periodic or non-periodic; see the
"boundary"_boundary.html command. When the simulation box is created
it is also partitioned into a regular 3d grid of rectangular bricks,
one per processor, based on the number of processors being used and
the settings of the "processors"_processors.html command. The
partitioning can later be changed by the "balance"_balance.html or
"fix balance"_fix_balance.html commands.
If the {xy xz yz} line does not appear, LAMMPS will set up an
axis-aligned (orthogonal) simulation box. If the line does appear,
LAMMPS creates a non-orthogonal simulation domain shaped as a
parallelepiped with triclinic symmetry. The parallelepiped has its
"origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors starting
from the origin given by A = (xhi-xlo,0,0); B = (xy,yhi-ylo,0); C =
(xz,yz,zhi-zlo). {Xy,xz,yz} can be 0.0 or positive or negative values
and are called "tilt factors" because they are the amount of
displacement applied to faces of an originally orthogonal box to
transform it into the parallelepiped.
By default, the tilt factors (xy,xz,yz) can not skew the box more than
half the distance of the corresponding parallel box length. For
example, if xlo = 2 and xhi = 12, then the x box length is 10 and the
xy tilt factor must be between -5 and 5. Similarly, both xz and yz
must be between -(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is not
a limitation, since if the maximum tilt factor is 5 (as in this
example), then configurations with tilt = ..., -15, -5, 5, 15, 25,
... are all geometrically equivalent. If you wish to define a box
with tilt factors that exceed these limits, you can use the "box
tilt"_box.html command, with a setting of {large}; a setting of
{small} is the default.
See "Section 6.12"_Section_howto.html#howto_12 of the doc pages
for a geometric description of triclinic boxes, as defined by LAMMPS,
and how to transform these parameters to and from other commonly used
triclinic representations.
When a triclinic system is used, the simulation domain should normally
be periodic in the dimension that the tilt is applied to, which is
given by the second dimension of the tilt factor (e.g. y for xy tilt).
This is so that pairs of atoms interacting across that boundary will
have one of them shifted by the tilt factor. Periodicity is set by
the "boundary"_boundary.html command. For example, if the xy tilt
factor is non-zero, then the y dimension should be periodic.
Similarly, the z dimension should be periodic if xz or yz is non-zero.
LAMMPS does not require this periodicity, but you may lose atoms if
this is not the case.
Also note that if your simulation will tilt the box, e.g. via the "fix
deform"_fix_deform.html command, the simulation box must be setup to
be triclinic, even if the tilt factors are initially 0.0. You can
also change an orthogonal box to a triclinic box or vice versa by
using the "change box"_change_box.html command with its {ortho} and
{triclinic} options.
For 2d simulations, the {zlo zhi} values should be set to bound the z
coords for atoms that appear in the file; the default of -0.5 0.5 is
valid if all z coords are 0.0. For 2d triclinic simulations, the xz
and yz tilt factors must be 0.0.
If the system is periodic (in a dimension), then atom coordinates can
be outside the bounds (in that dimension); they will be remapped (in a
periodic sense) back inside the box. Note that if the {add} option is
being used to add atoms to a simulation box that already exists, this
periodic remapping will be performed using simulation box bounds that
are the union of the existing box and the box boundaries in the new
data file.
NOTE: If the system is non-periodic (in a dimension), then all atoms
in the data file must have coordinates (in that dimension) that are
"greater than or equal to" the lo value and "less than or equal to"
the hi value. If the non-periodic dimension is of style "fixed" (see
the "boundary"_boundary.html command), then the atom coords must be
strictly "less than" the hi value, due to the way LAMMPS assign atoms
to processors. Note that you should not make the lo/hi values
radically smaller/larger than the extent of the atoms. For example,
if your atoms extend from 0 to 50, you should not specify the box
bounds as -10000 and 10000. This is because LAMMPS uses the specified
box size to layout the 3d grid of processors. A huge (mostly empty)
box will be sub-optimal for performance when using "fixed" boundary
conditions (see the "boundary"_boundary.html command). When using
"shrink-wrap" boundary conditions (see the "boundary"_boundary.html
command), a huge (mostly empty) box may cause a parallel simulation to
lose atoms when LAMMPS shrink-wraps the box around the atoms. The
read_data command will generate an error in this case.
The "extra bond per atom" setting (angle, dihedral, improper) is only
needed if new bonds (angles, dihedrals, impropers) will be added to
the system when a simulation runs, e.g. by using the "fix
bond/create"_fix_bond_create.html command. Using this header flag
is deprecated; please use the {extra/bond/per/atom} keyword (and
correspondingly for angles, dihedrals and impropers) in the
read_data command instead. Either will pre-allocate space in LAMMPS
data structures for storing the new bonds (angles,
dihedrals, impropers).
The "extra special per atom" setting is typically only needed if new
bonds/angles/etc will be added to the system, e.g. by using the "fix
bond/create"_fix_bond_create.html command. Or if entire new molecules
will be added to the system, e.g. by using the
"fix deposit"_fix_deposit.html or "fix pour"_fix_pour.html commands,
which will have more special 1-2,1-3,1-4 neighbors than any other
molecules defined in the data file. Using this header flag is
deprecated; please use the {extra/special/per/atom} keyword instead.
Using this setting will pre-allocate space in the LAMMPS data
structures for storing these neighbors. See the
"special_bonds"_special_bonds.html and "molecule"_molecule.html doc
pages for more discussion of 1-2,1-3,1-4 neighbors.
NOTE: All of the "extra" settings are only applied in the first data
file read and when no simulation box has yet been created; as soon as
the simulation box is created (and read_data implies that), these
settings are {locked} and cannot be changed anymore. Please see the
description of the {add} keyword above for reading multiple data files.
If they appear in later data files, they are ignored.
The "ellipsoids" and "lines" and "triangles" and "bodies" settings are
only used with "atom_style ellipsoid or line or tri or
body"_atom_style.html and specify how many of the atoms are
finite-size ellipsoids or lines or triangles or bodies; the remainder
are point particles. See the discussion of ellipsoidflag and the
{Ellipsoids} section below. See the discussion of lineflag and the
{Lines} section below. See the discussion of triangleflag and the
{Triangles} section below. See the discussion of bodyflag and the
{Bodies} section below.
NOTE: For "atom_style template"_atom_style.html, the molecular
topology (bonds,angles,etc) is contained in the molecule templates
read-in by the "molecule"_molecule.html command. This means you
cannot set the {bonds}, {angles}, etc header keywords in the data
file, nor can you define {Bonds}, {Angles}, etc sections as discussed
below. You can set the {bond types}, {angle types}, etc header
keywords, though it is not necessary. If specified, they must match
the maximum values defined in any of the template molecules.
:line
[Format of the body of a data file]
These are the section keywords for the body of the file.
{Atoms, Velocities, Masses, Ellipsoids, Lines, Triangles, Bodies} = atom-property sections
{Bonds, Angles, Dihedrals, Impropers} = molecular topology sections
{Pair Coeffs, PairIJ Coeffs, Bond Coeffs, Angle Coeffs, Dihedral Coeffs, \
Improper Coeffs} = force field sections
{BondBond Coeffs, BondAngle Coeffs, MiddleBondTorsion Coeffs, \
EndBondTorsion Coeffs, AngleTorsion Coeffs, AngleAngleTorsion Coeffs, \
BondBond13 Coeffs, AngleAngle Coeffs} = class 2 force field sections :ul
These keywords will check an appended comment for a match with the
currently defined style:
{Atoms, Pair Coeffs, PairIJ Coeffs, Bond Coeffs, Angle Coeffs, Dihedral Coeffs, Improper Coeffs} :ul
For example, these lines:
Atoms # sphere
Pair Coeffs # lj/cut :pre
will check if the currently-defined "atom_style"_atom_style.html is
{sphere}, and the current "pair_style"_pair_style.html is {lj/cut}.
If not, LAMMPS will issue a warning to indicate that the data file
section likely does not contain the correct number or type of
parameters expected for the currently-defined style.
Each section is listed below in alphabetic order. The format of each
section is described including the number of lines it must contain and
rules (if any) for where it can appear in the data file.
Any individual line in the various sections can have a trailing
comment starting with "#" for annotation purposes. E.g. in the
Atoms section:
10 1 17 -1.0 10.0 5.0 6.0 # salt ion :pre
:line
{Angle Coeffs} section:
one line per angle type :ulb,l
line syntax: ID coeffs :l
ID = angle type (1-N)
coeffs = list of coeffs :pre
example: :l
6 70 108.5 0 0 :pre
:ule
The number and meaning of the coefficients are specific to the defined
angle style. See the "angle_style"_angle_style.html and
"angle_coeff"_angle_coeff.html commands for details. Coefficients can
also be set via the "angle_coeff"_angle_coeff.html command in the
input script.
:line
{AngleAngle Coeffs} section:
one line per improper type :ulb,l
line syntax: ID coeffs :l
ID = improper type (1-N)
coeffs = list of coeffs (see "improper_coeff"_improper_coeff.html) :pre
:ule
:line
{AngleAngleTorsion Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs (see "dihedral_coeff"_dihedral_coeff.html) :pre
:ule
:line
{Angles} section:
one line per angle :ulb,l
line syntax: ID type atom1 atom2 atom3 :l
ID = number of angle (1-Nangles)
type = angle type (1-Nangletype)
atom1,atom2,atom3 = IDs of 1st,2nd,3rd atoms in angle :pre
example: :b
2 2 17 29 430 :pre
:ule
The 3 atoms are ordered linearly within the angle. Thus the central
atom (around which the angle is computed) is the atom2 in the list.
E.g. H,O,H for a water molecule. The {Angles} section must appear
after the {Atoms} section. All values in this section must be
integers (1, not 1.0).
:line
{AngleTorsion Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs (see "dihedral_coeff"_dihedral_coeff.html) :pre
:ule
:line
{Atoms} section:
one line per atom
line syntax: depends on atom style :ul
An {Atoms} section must appear in the data file if natoms > 0 in the
header section. The atoms can be listed in any order. These are the
line formats for each "atom style"_atom_style.html in LAMMPS. As
discussed below, each line can optionally have 3 flags (nx,ny,nz)
appended to it, which indicate which image of a periodic simulation
box the atom is in. These may be important to include for some kinds
of analysis.
angle: atom-ID molecule-ID atom-type x y z
atomic: atom-ID atom-type x y z
body: atom-ID atom-type bodyflag mass x y z
bond: atom-ID molecule-ID atom-type x y z
charge: atom-ID atom-type q x y z
dipole: atom-ID atom-type q x y z mux muy muz
dpd: atom-ID atom-type theta x y z
electron: atom-ID atom-type q spin eradius x y z
ellipsoid: atom-ID atom-type ellipsoidflag density x y z
full: atom-ID molecule-ID atom-type q x y z
line: atom-ID molecule-ID atom-type lineflag density x y z
meso: atom-ID atom-type rho e cv x y z
molecular: atom-ID molecule-ID atom-type x y z
peri: atom-ID atom-type volume density x y z
smd: atom-ID atom-type molecule volume mass kernel-radius contact-radius x y z
sphere: atom-ID atom-type diameter density x y z
template: atom-ID molecule-ID template-index template-atom atom-type x y z
tri: atom-ID molecule-ID atom-type triangleflag density x y z
wavepacket: atom-ID atom-type charge spin eradius etag cs_re cs_im x y z
hybrid: atom-ID atom-type x y z sub-style1 sub-style2 ... :tb(s=:)
The per-atom values have these meanings and units, listed alphabetically:
atom-ID = integer ID of atom
atom-type = type of atom (1-Ntype)
bodyflag = 1 for body particles, 0 for point particles
contact-radius = ??? (distance units)
cs_re,cs_im = real/imaginary parts of wavepacket coefficients
cv = heat capacity (need units) for SPH particles
density = density of particle (mass/distance^3 or mass/distance^2 or mass/distance units, depending on dimensionality of particle)
diameter = diameter of spherical atom (distance units)
e = energy (need units) for SPH particles
ellipsoidflag = 1 for ellipsoidal particles, 0 for point particles
eradius = electron radius (or fixed-core radius)
etag = integer ID of electron that each wavepacket belongs to
kernel-radius = ??? (distance units)
lineflag = 1 for line segment particles, 0 for point or spherical particles
mass = mass of particle (mass units)
molecule-ID = integer ID of molecule the atom belongs to
mux,muy,muz = components of dipole moment of atom (dipole units)
q = charge on atom (charge units)
rho = density (need units) for SPH particles
spin = electron spin (+1/-1), 0 = nuclei, 2 = fixed-core, 3 = pseudo-cores (i.e. ECP)
template-atom = which atom within a template molecule the atom is
template-index = which molecule within the molecule template the atom is part of
theta = internal temperature of a DPD particle
triangleflag = 1 for triangular particles, 0 for point or spherical particles
volume = volume of Peridynamic particle (distance^3 units)
x,y,z = coordinates of atom (distance units) :ul
The units for these quantities depend on the unit style; see the
"units"_units.html command for details.
For 2d simulations specify z as 0.0, or a value within the {zlo zhi}
setting in the data file header.
The atom-ID is used to identify the atom throughout the simulation and
in dump files. Normally, it is a unique value from 1 to Natoms for
each atom. Unique values larger than Natoms can be used, but they
will cause extra memory to be allocated on each processor, if an atom
map array is used, but not if an atom map hash is used; see the
"atom_modify"_atom_modify.html command for details. If an atom map is
not used (e.g. an atomic system with no bonds), and you don't care if
unique atom IDs appear in dump files, then the atom-IDs can all be set
to 0.
The molecule ID is a 2nd identifier attached to an atom. Normally, it
is a number from 1 to N, identifying which molecule the atom belongs
to. It can be 0 if it is an unbonded atom or if you don't care to
keep track of molecule assignments.
The diameter specifies the size of a finite-size spherical particle.
It can be set to 0.0, which means that atom is a point particle.
The ellipsoidflag, lineflag, triangleflag, and bodyflag determine
whether the particle is a finite-size ellipsoid or line or triangle or
body of finite size, or whether the particle is a point particle.
Additional attributes must be defined for each ellipsoid, line,
triangle, or body in the corresponding {Ellipsoids}, {Lines},
{Triangles}, or {Bodies} section.
The {template-index} and {template-atom} are only defined used by
"atom_style template"_atom_style.html. In this case the
"molecule"_molecule.html command is used to define a molecule template
which contains one or more molecules. If an atom belongs to one of
those molecules, its {template-index} and {template-atom} are both set
to positive integers; if not the values are both 0. The
{template-index} is which molecule (1 to Nmols) the atom belongs to.
The {template-atom} is which atom (1 to Natoms) within the molecule
the atom is.
Some pair styles and fixes and computes that operate on finite-size
particles allow for a mixture of finite-size and point particles. See
the doc pages of individual commands for details.
For finite-size particles, the density is used in conjunction with the
particle volume to set the mass of each particle as mass = density *
volume. In this context, volume can be a 3d quantity (for spheres or
ellipsoids), a 2d quantity (for triangles), or a 1d quantity (for line
segments). If the volume is 0.0, meaning a point particle, then the
density value is used as the mass. One exception is for the body atom
style, in which case the mass of each particle (body or point
particle) is specified explicitly. This is because the volume of the
body is unknown.
Note that for 2d simulations of spheres, this command will treat them
as spheres when converting density to mass. However, they can also be
modeled as 2d discs (circles) if the "set density/disc"_set.html
command is used to reset their mass after the read_data command is
used. A {disc} keyword can also be used with time integration fixes,
such as "fix nve/sphere"_fix_nve_sphere.html and "fix
nvt/sphere"_fix_nve_sphere.html to time integrate their motion as 2d
discs (not 3d spheres), by changing their moment of inertia.
For atom_style hybrid, following the 5 initial values (ID,type,x,y,z),
specific values for each sub-style must be listed. The order of the
sub-styles is the same as they were listed in the
"atom_style"_atom_style.html command. The sub-style specific values
are those that are not the 5 standard ones (ID,type,x,y,z). For
example, for the "charge" sub-style, a "q" value would appear. For
the "full" sub-style, a "molecule-ID" and "q" would appear. These are
listed in the same order they appear as listed above. Thus if
atom_style hybrid charge sphere :pre
were used in the input script, each atom line would have these fields:
atom-ID atom-type x y z q diameter density :pre
Note that if a non-standard value is defined by multiple sub-styles,
it must appear mutliple times in the atom line. E.g. the atom line
for atom_style hybrid dipole full would list "q" twice:
atom-ID atom-type x y z q mux muy myz molecule-ID q :pre
Atom lines specify the (x,y,z) coordinates of atoms. These can be
inside or outside the simulation box. When the data file is read,
LAMMPS wraps coordinates outside the box back into the box for
dimensions that are periodic. As discussed above, if an atom is
outside the box in a non-periodic dimension, it will be lost.
LAMMPS always stores atom coordinates as values which are inside the
simulation box. It also stores 3 flags which indicate which image of
the simulation box (in each dimension) the atom would be in if its
coordinates were unwrapped across periodic boundaries. An image flag
of 0 means the atom is still inside the box when unwrapped. A value
of 2 means add 2 box lengths to get the unwrapped coordinate. A value
of -1 means subtract 1 box length to get the unwrapped coordinate.
LAMMPS updates these flags as atoms cross periodic boundaries during
the simulation. The "dump"_dump.html command can output atom atom
coordinates in wrapped or unwrapped form, as well as the 3 image
flags.
In the data file, atom lines (all lines or none of them) can
optionally list 3 trailing integer values (nx,ny,nz), which are used
to initialize the atom's image flags. If nx,ny,nz values are not
listed in the data file, LAMMPS initializes them to 0. Note that the
image flags are immediately updated if an atom's coordinates need to
wrapped back into the simulation box.
It is only important to set image flags correctly in a data file if a
simulation model relies on unwrapped coordinates for some calculation;
otherwise they can be left unspecified. Examples of LAMMPS commands
that use unwrapped coordinates internally are as follows:
Atoms in a rigid body (see "fix rigid"_fix_rigid.html, "fix
rigid/small"_fix_rigid.html) must have consistent image flags, so that
when the atoms are unwrapped, they are near each other, i.e. as a
single body. :ulb,l
If the "replicate"_replicate.html command is used to generate a larger
system, image flags must be consistent for bonded atoms when the bond
crosses a periodic boundary. I.e. the values of the image flags
should be different by 1 (in the appropriate dimension) for the two
atoms in such a bond. :l
If you plan to "dump"_dump.html image flags and perform post-analysis
that will unwrap atom coordinates, it may be important that a
continued run (restarted from a data file) begins with image flags
that are consistent with the previous run. :l
:ule
NOTE: If your system is an infinite periodic crystal with bonds then
it is impossible to have fully consistent image flags. This is because
some bonds will cross periodic boundaries and connect two atoms with the
same image flag.
Atom velocities and other atom quantities not defined above are set to
0.0 when the {Atoms} section is read. Velocities can be set later by
a {Velocities} section in the data file or by a
"velocity"_velocity.html or "set"_set.html command in the input
script.
:line
{Bodies} section:
one or more lines per body :ulb,l
first line syntax: atom-ID Ninteger Ndouble :l
Ninteger = # of integer quantities for this particle
Ndouble = # of floating-point quantities for this particle :pre
0 or more integer lines with total of Ninteger values :l
0 or more double lines with total of Ndouble values :l
example: :l
12 3 6
2 3 2
1.0 2.0 3.0 1.0 2.0 4.0 :pre
example: :l
12 0 14
1.0 2.0 3.0 1.0 2.0 4.0 1.0
2.0 3.0 1.0 2.0 4.0 4.0 2.0 :pre
:ule
The {Bodies} section must appear if "atom_style body"_atom_style.html
is used and any atoms listed in the {Atoms} section have a bodyflag =
1. The number of bodies should be specified in the header section via
the "bodies" keyword.
Each body can have a variable number of integer and/or floating-point
values. The number and meaning of the values is defined by the body
style, as described in the "body"_body.html doc page. The body style
is given as an argument to the "atom_style body"_atom_style.html
command.
The Ninteger and Ndouble values determine how many integer and
floating-point values are specified for this particle. Ninteger and
Ndouble can be as large as needed and can be different for every body.
Integer values are then listed next on subsequent lines. Lines are
read one at a time until Ninteger values are read. Floating-point
values follow on subsequent lines, Again lines are read one at a time
until Ndouble values are read. Note that if there are no values of a
particular type, no lines appear for that type.
The {Bodies} section must appear after the {Atoms} section.
:line
{Bond Coeffs} section:
one line per bond type :ulb,l
line syntax: ID coeffs :l
ID = bond type (1-N)
coeffs = list of coeffs :pre
example: :l
4 250 1.49 :pre
:ule
The number and meaning of the coefficients are specific to the defined
bond style. See the "bond_style"_bond_style.html and
"bond_coeff"_bond_coeff.html commands for details. Coefficients can
also be set via the "bond_coeff"_bond_coeff.html command in the input
script.
:line
{BondAngle Coeffs} section:
one line per angle type :ulb,l
line syntax: ID coeffs :l
ID = angle type (1-N)
coeffs = list of coeffs (see class 2 section of "angle_coeff"_angle_coeff.html) :pre
:ule
:line
{BondBond Coeffs} section:
one line per angle type :ulb,l
line syntax: ID coeffs :l
ID = angle type (1-N)
coeffs = list of coeffs (see class 2 section of "angle_coeff"_angle_coeff.html) :pre
:ule
:line
{BondBond13 Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs (see class 2 section of "dihedral_coeff"_dihedral_coeff.html) :pre
:ule
:line
{Bonds} section:
one line per bond :ulb,l
line syntax: ID type atom1 atom2 :l
ID = bond number (1-Nbonds)
type = bond type (1-Nbondtype)
atom1,atom2 = IDs of 1st,2nd atoms in bond :pre
example: :l
12 3 17 29 :pre
:ule
The {Bonds} section must appear after the {Atoms} section. All values
in this section must be integers (1, not 1.0).
:line
{Dihedral Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs :pre
example: :l
3 0.6 1 0 1 :pre
:ule
The number and meaning of the coefficients are specific to the defined
dihedral style. See the "dihedral_style"_dihedral_style.html and
"dihedral_coeff"_dihedral_coeff.html commands for details.
Coefficients can also be set via the
"dihedral_coeff"_dihedral_coeff.html command in the input script.
:line
{Dihedrals} section:
one line per dihedral :ulb,l
line syntax: ID type atom1 atom2 atom3 atom4 :l
ID = number of dihedral (1-Ndihedrals)
type = dihedral type (1-Ndihedraltype)
atom1,atom2,atom3,atom4 = IDs of 1st,2nd,3rd,4th atoms in dihedral :pre
example: :l
12 4 17 29 30 21 :pre
:ule
The 4 atoms are ordered linearly within the dihedral. The {Dihedrals}
section must appear after the {Atoms} section. All values in this
section must be integers (1, not 1.0).
:line
{Ellipsoids} section:
one line per ellipsoid :ulb,l
line syntax: atom-ID shapex shapey shapez quatw quati quatj quatk :l
atom-ID = ID of atom which is an ellipsoid
shapex,shapey,shapez = 3 diameters of ellipsoid (distance units)
quatw,quati,quatj,quatk = quaternion components for orientation of atom :pre
example: :l
12 1 2 1 1 0 0 0 :pre
:ule
The {Ellipsoids} section must appear if "atom_style
ellipsoid"_atom_style.html is used and any atoms are listed in the
{Atoms} section with an ellipsoidflag = 1. The number of ellipsoids
should be specified in the header section via the "ellipsoids"
keyword.
The 3 shape values specify the 3 diameters or aspect ratios of a
finite-size ellipsoidal particle, when it is oriented along the 3
coordinate axes. They must all be non-zero values.
The values {quatw}, {quati}, {quatj}, and {quatk} set the orientation
of the atom as a quaternion (4-vector). Note that the shape
attributes specify the aspect ratios of an ellipsoidal particle, which
is oriented by default with its x-axis along the simulation box's
x-axis, and similarly for y and z. If this body is rotated (via the
right-hand rule) by an angle theta around a unit vector (a,b,c), then
the quaternion that represents its new orientation is given by
(cos(theta/2), a*sin(theta/2), b*sin(theta/2), c*sin(theta/2)). These
4 components are quatw, quati, quatj, and quatk as specified above.
LAMMPS normalizes each atom's quaternion in case (a,b,c) is not
specified as a unit vector.
The {Ellipsoids} section must appear after the {Atoms} section.
:line
{EndBondTorsion Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs (see class 2 section of "dihedral_coeff"_dihedral_coeff.html) :pre
:ule
:line
{Improper Coeffs} section:
one line per improper type :ulb,l
line syntax: ID coeffs :l
ID = improper type (1-N)
coeffs = list of coeffs :pre
example: :l
2 20 0.0548311 :pre
:ule
The number and meaning of the coefficients are specific to the defined
improper style. See the "improper_style"_improper_style.html and
"improper_coeff"_improper_coeff.html commands for details.
Coefficients can also be set via the
"improper_coeff"_improper_coeff.html command in the input script.
:line
{Impropers} section:
one line per improper :ulb,l
line syntax: ID type atom1 atom2 atom3 atom4 :l
ID = number of improper (1-Nimpropers)
type = improper type (1-Nimpropertype)
atom1,atom2,atom3,atom4 = IDs of 1st,2nd,3rd,4th atoms in improper :pre
example: :l
12 3 17 29 13 100 :pre
:ule
The ordering of the 4 atoms determines the definition of the improper
angle used in the formula for each "improper
style"_improper_style.html. See the doc pages for individual styles
for details.
The {Impropers} section must appear after the {Atoms} section. All
values in this section must be integers (1, not 1.0).
:line
{Lines} section:
one line per line segment :ulb,l
line syntax: atom-ID x1 y1 x2 y2 :l
atom-ID = ID of atom which is a line segment
x1,y1 = 1st end point
x2,y2 = 2nd end point :pre
example: :l
12 1.0 0.0 2.0 0.0 :pre
:ule
The {Lines} section must appear if "atom_style line"_atom_style.html
is used and any atoms are listed in the {Atoms} section with a
lineflag = 1. The number of lines should be specified in the header
section via the "lines" keyword.
The 2 end points are the end points of the line segment. The ordering
of the 2 points should be such that using a right-hand rule to cross
the line segment with a unit vector in the +z direction, gives an
"outward" normal vector perpendicular to the line segment.
I.e. normal = (c2-c1) x (0,0,1). This orientation may be important
for defining some interactions.
The {Lines} section must appear after the {Atoms} section.
:line
{Masses} section:
one line per atom type :ulb,l
line syntax: ID mass :l
ID = atom type (1-N)
mass = mass value :pre
example: :l
3 1.01 :pre
:ule
This defines the mass of each atom type. This can also be set via the
"mass"_mass.html command in the input script. This section cannot be
used for atom styles that define a mass for individual atoms -
e.g. "atom_style sphere"_atom_style.html.
:line
{MiddleBondTorsion Coeffs} section:
one line per dihedral type :ulb,l
line syntax: ID coeffs :l
ID = dihedral type (1-N)
coeffs = list of coeffs (see class 2 section of "dihedral_coeff"_dihedral_coeff.html) :pre
:ule
:line
{Pair Coeffs} section:
one line per atom type :ulb,l
line syntax: ID coeffs :l
ID = atom type (1-N)
coeffs = list of coeffs :pre
example: :l
3 0.022 2.35197 0.022 2.35197 :pre
:ule
The number and meaning of the coefficients are specific to the defined
pair style. See the "pair_style"_pair_style.html and
"pair_coeff"_pair_coeff.html commands for details. Since pair
coefficients for types I != J are not specified, these will be
generated automatically by the pair style's mixing rule. See the
individual pair_style doc pages and the "pair_modify
mix"_pair_modify.html command for details. Pair coefficients can also
be set via the "pair_coeff"_pair_coeff.html command in the input
script.
:line
{PairIJ Coeffs} section:
one line per pair of atom types for all I,J with I <= J :ulb,l
line syntax: ID1 ID2 coeffs :l
ID1 = atom type I = 1-N
ID2 = atom type J = I-N, with I <= J
coeffs = list of coeffs :pre
examples: :l
3 3 0.022 2.35197 0.022 2.35197
3 5 0.022 2.35197 0.022 2.35197 :pre
:ule
This section must have N*(N+1)/2 lines where N = # of atom types. The
number and meaning of the coefficients are specific to the defined
pair style. See the "pair_style"_pair_style.html and
"pair_coeff"_pair_coeff.html commands for details. Since pair
coefficients for types I != J are all specified, these values will
turn off the default mixing rule defined by the pair style. See the
individual pair_style doc pages and the "pair_modify
mix"_pair_modify.html command for details. Pair coefficients can also
be set via the "pair_coeff"_pair_coeff.html command in the input
script.
:line
{Triangles} section:
one line per triangle :ulb,l
line syntax: atom-ID x1 y1 z1 x2 y2 z2 x3 y3 z3 :l
atom-ID = ID of atom which is a line segment
x1,y1,z1 = 1st corner point
x2,y2,z2 = 2nd corner point
x3,y3,z3 = 3rd corner point :pre
example: :l
12 0.0 0.0 0.0 2.0 0.0 1.0 0.0 2.0 1.0 :pre
:ule
The {Triangles} section must appear if "atom_style
tri"_atom_style.html is used and any atoms are listed in the {Atoms}
section with a triangleflag = 1. The number of lines should be
specified in the header section via the "triangles" keyword.
The 3 corner points are the corner points of the triangle. The
ordering of the 3 points should be such that using a right-hand rule
to go from point1 to point2 to point3 gives an "outward" normal vector
to the face of the triangle. I.e. normal = (c2-c1) x (c3-c1). This
orientation may be important for defining some interactions.
The {Triangles} section must appear after the {Atoms} section.
:line
{Velocities} section:
one line per atom
line syntax: depends on atom style :ul
all styles except those listed: atom-ID vx vy vz
electron: atom-ID vx vy vz ervel
ellipsoid: atom-ID vx vy vz lx ly lz
sphere: atom-ID vx vy vz wx wy wz
hybrid: atom-ID vx vy vz sub-style1 sub-style2 ... :tb(s=:)
where the keywords have these meanings:
vx,vy,vz = translational velocity of atom
lx,ly,lz = angular momentum of aspherical atom
wx,wy,wz = angular velocity of spherical atom
ervel = electron radial velocity (0 for fixed-core):ul
The velocity lines can appear in any order. This section can only be
used after an {Atoms} section. This is because the {Atoms} section
must have assigned a unique atom ID to each atom so that velocities
can be assigned to them.
Vx, vy, vz, and ervel are in "units"_units.html of velocity. Lx, ly,
lz are in units of angular momentum (distance-velocity-mass). Wx, Wy,
Wz are in units of angular velocity (radians/time).
For atom_style hybrid, following the 4 initial values (ID,vx,vy,vz),
specific values for each sub-style must be listed. The order of the
sub-styles is the same as they were listed in the
"atom_style"_atom_style.html command. The sub-style specific values
are those that are not the 5 standard ones (ID,vx,vy,vz). For
example, for the "sphere" sub-style, "wx", "wy", "wz" values would
appear. These are listed in the same order they appear as listed
above. Thus if
atom_style hybrid electron sphere :pre
were used in the input script, each velocity line would have these
fields:
atom-ID vx vy vz ervel wx wy wz :pre
Translational velocities can also be set by the
"velocity"_velocity.html command in the input script.
:line
[Restrictions:]
To read gzipped data files, you must compile LAMMPS with the
-DLAMMPS_GZIP option - see the "Making
LAMMPS"_Section_start.html#start_2 section of the documentation.
[Related commands:]
"read_dump"_read_dump.html, "read_restart"_read_restart.html,
"create_atoms"_create_atoms.html, "write_data"_write_data.html
[Default:]
The default for all the {extra} keywords is 0.
diff --git a/doc/src/read_restart.txt b/doc/src/read_restart.txt
index d0f4b1617..d1091542b 100644
--- a/doc/src/read_restart.txt
+++ b/doc/src/read_restart.txt
@@ -1,272 +1,272 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
read_restart command :h3
[Syntax:]
read_restart file flag :pre
file = name of binary restart file to read in
flag = remap (optional) :ul
[Examples:]
read_restart save.10000
read_restart save.10000 remap
read_restart restart.*
read_restart restart.*.mpiio
read_restart poly.*.% remap :pre
[Description:]
Read in a previously saved system configuration from a restart file.
This allows continuation of a previous run. Details about what
information is stored (and not stored) in a restart file is given
below. Basically this operation will re-create the simulation box
with all its atoms and their attributes as well as some related global
settings, at the point in time it was written to the restart file by a
previous simulation. The simulation box will be partitioned into a
regular 3d grid of rectangular bricks, one per processor, based on the
number of processors in the current simulation and the settings of the
"processors"_processors.html command. The partitioning can later be
changed by the "balance"_balance.html or "fix
balance"_fix_balance.html commands.
NOTE: Normally, restart files are written by the
"restart"_restart.html or "write_restart"_write_restart.html commands
so that all atoms in the restart file are inside the simulation box.
If this is not the case, the read_restart command will print an error
that atoms were "lost" when the file is read. This error should be
reported to the LAMMPS developers so the invalid writing of the
restart file can be fixed. If you still wish to use the restart file,
the optional {remap} flag can be appended to the read_restart command.
This should avoid the error, by explicitly remapping each atom back
into the simulation box, updating image flags for the atom
appropriately.
Restart files are saved in binary format to enable exact restarts,
meaning that the trajectories of a restarted run will precisely match
those produced by the original run had it continued on.
Several things can prevent exact restarts due to round-off effects, in
which case the trajectories in the 2 runs will slowly diverge. These
include running on a different number of processors or changing
certain settings such as those set by the "newton"_newton.html or
"processors"_processors.html commands. LAMMPS will issue a warning in
these cases.
Certain fixes will not restart exactly, though they should provide
statistically similar results. These include "fix
shake"_fix_shake.html and "fix langevin"_fix_langevin.html.
Certain pair styles will not restart exactly, though they should
provide statistically similar results. This is because the forces
they compute depend on atom velocities, which are used at half-step
values every timestep when forces are computed. When a run restarts,
forces are initially evaluated with a full-step velocity, which is
different than if the run had continued. These pair styles include
"granular pair styles"_pair_gran.html, "pair dpd"_pair_dpd.html, and
"pair lubricate"_pair_lubricate.html.
If a restarted run is immediately different than the run which
produced the restart file, it could be a LAMMPS bug, so consider
"reporting it"_Section_errors.html#err_2 if you think the behavior is
wrong.
Because restart files are binary, they may not be portable to other
machines. In this case, you can use the "-restart command-line
-switch"_Section_start.html#start_7 to convert a restart file to a data
+switch"_Section_start.html#start_6 to convert a restart file to a data
file.
Similar to how restart files are written (see the
"write_restart"_write_restart.html and "restart"_restart.html
commands), the restart filename can contain two wild-card characters.
If a "*" appears in the filename, the directory is searched for all
filenames that match the pattern where "*" is replaced with a timestep
value. The file with the largest timestep value is read in. Thus,
this effectively means, read the latest restart file. It's useful if
you want your script to continue a run from where it left off. See
the "run"_run.html command and its "upto" option for how to specify
the run command so it doesn't need to be changed either.
If a "%" character appears in the restart filename, LAMMPS expects a
set of multiple files to exist. The "restart"_restart.html and
"write_restart"_write_restart.html commands explain how such sets are
created. Read_restart will first read a filename where "%" is
replaced by "base". This file tells LAMMPS how many processors
created the set and how many files are in it. Read_restart then reads
the additional files. For example, if the restart file was specified
as save.% when it was written, then read_restart reads the files
save.base, save.0, save.1, ... save.P-1, where P is the number of
processors that created the restart file.
Note that P could be the total number of processors in the previous
simulation, or some subset of those processors, if the {fileper} or
{nfile} options were used when the restart file was written; see the
"restart"_restart.html and "write_restart"_write_restart.html commands
for details. The processors in the current LAMMPS simulation share
the work of reading these files; each reads a roughly equal subset of
the files. The number of processors which created the set can be
different the number of processors in the current LAMMPS simulation.
This can be a fast mode of input on parallel machines that support
parallel I/O.
A restart file can also be read in parallel as one large binary file
via the MPI-IO library, assuming it was also written with MPI-IO.
MPI-IO is part of the MPI standard for versions 2.0 and above. Using
MPI-IO requires two steps. First, build LAMMPS with its MPIIO package
installed, e.g.
make yes-mpiio # installs the MPIIO package
make mpi # build LAMMPS for your platform :pre
Second, use a restart filename which contains ".mpiio". Note that it
does not have to end in ".mpiio", just contain those characters.
Unlike MPI-IO dump files, a particular restart file must be both
written and read using MPI-IO.
:line
Here is the list of information included in a restart file, which
means these quantities do not need to be re-specified in the input
script that reads the restart file, though you can redefine many of
these settings after the restart file is read.
"units"_units.html
"newton bond"_newton.html (see discussion of newton command below)
"atom style"_atom_style.html and "atom_modify"_atom_modify.html settings id, map, sort
"comm style"_comm_style.html and "comm_modify"_comm_modify.html settings mode, cutoff, vel
"timestep"_timestep.html
simulation box size and shape and "boundary"_boundary.html settings
atom "group"_group.html definitions
per-type atom settings such as "mass"_mass.html
per-atom attributes including their group assignments and molecular topology attributes (bonds, angles, etc)
force field styles ("pair"_pair_style.html, "bond"_bond_style.html, "angle"_angle_style.html, etc)
force field coefficients ("pair"_pair_coeff.html, "bond"_bond_coeff.html, "angle"_angle_coeff.html, etc) in some cases (see below)
"pair_modify"_pair_modify.html settings, except the compute option
"special_bonds"_special_bonds.html settings :ul
Here is a list of information not stored in a restart file, which
means you must re-issue these commands in your input script, after
reading the restart file.
"newton pair"_newton.html (see discussion of newton command below)
"fix"_fix.html commands (see below)
"compute"_compute.html commands (see below)
"variable"_variable.html commands
"region"_region.html commands
"neighbor list"_neighbor.html criteria including "neigh_modify"_neigh_modify.html settings
"kspace_style"_kspace_style.html and "kspace_modify"_kspace_modify.html settings
info for "thermodynamic"_thermo_style.html, "dump"_dump.html, or "restart"_restart.html output :ul
The "newton"_newton.html command has two settings, one for pairwise
interactions, the other for bonded. Both settings are stored in the
restart file. For the bond setting, the value in the file will
overwrite the current value (at the time the read_restart command is
issued) and warn if the two values are not the same and the current
value is not the default. For the pair setting, the value in the file
will not overwrite the current value (so that you can override the
previous run's value), but a warning is issued if the two values are
not the same and the current value is not the default.
Note that some force field styles (pair, bond, angle, etc) do not
store their coefficient info in restart files. Typically these are
many-body or tabulated potentials which read their parameters from
separate files. In these cases you will need to re-specify the "pair
"pair_coeff"_pair_coeff.html, "bond_coeff"_bond_coeff.html, etc
commands in your restart input script. The doc pages for individual
force field styles mention if this is the case. This is also true of
"pair_style hybrid"_pair_hybrid.html (bond hybrid, angle hybrid, etc)
commands; they do not store coefficient info.
As indicated in the above list, the "fixes"_fix.html used for a
simulation are not stored in the restart file. This means the new
input script should specify all fixes it will use. However, note that
some fixes store an internal "state" which is written to the restart
file. This allows the fix to continue on with its calculations in a
restarted simulation. To re-enable such a fix, the fix command in the
new input script must be of the same style and use the same fix-ID as
was used in the input script that wrote the restart file.
If a match is found, LAMMPS prints a message indicating that the fix
is being re-enabled. If no match is found before the first run or
minimization is performed by the new script, the "state" information
for the saved fix is discarded. At the time the discard occurs,
LAMMPS will also print a list of fixes for which the information is
being discarded. See the doc pages for individual fixes for info on
which ones can be restarted in this manner. Note that fixes which are
created internally by other LAMMPS commands (computes, fixes, etc)
will have style names which are all-capitalized, and IDs which are
generated internally.
Likewise, the "computes"_fix.html used for a simulation are not stored
in the restart file. This means the new input script should specify
all computes it will use. However, some computes create a fix
internally to store "state" information that persists from timestep to
timestep. An example is the "compute msd"_compute_msd.html command
which uses a fix to store a reference coordinate for each atom, so
that a displacement can be calculated at any later time. If the
compute command in the new input script uses the same compute-ID and
group-ID as was used in the input script that wrote the restart file,
then it will create the same fix in the restarted run. This means the
re-created fix will be re-enabled with the stored state information as
described in the previous paragraph, so that the compute can continue
its calculations in a consistent manner.
NOTE: There are a handful of commands which can be used before or
between runs which may require a system initialization. Examples
include the "balance", "displace_atoms", "delete_atoms", "set" (some
options), and "velocity" (some options) commands. This is because
they can migrate atoms to new processors. Thus they will also discard
unused "state" information from fixes. You will know the discard has
occurred because a list of discarded fixes will be printed to the
screen and log file, as explained above. This means that if you wish
to retain that info in a restarted run, you must re-specify the
relevant fixes and computes (which create fixes) before those commands
are used.
Some pair styles, like the "granular pair styles"_pair_gran.html, also
use a fix to store "state" information that persists from timestep to
timestep. In the case of granular potentials, it is contact
information between pairs of touching particles. This info will also
be re-enabled in the restart script, assuming you re-use the same
granular pair style.
LAMMPS allows bond interactions (angle, etc) to be turned off or
deleted in various ways, which can affect how their info is stored in
a restart file.
If bonds (angles, etc) have been turned off by the "fix
shake"_fix_shake.html or "delete_bonds"_delete_bonds.html command,
their info will be written to a restart file as if they are turned on.
This means they will need to be turned off again in a new run after
the restart file is read.
Bonds that are broken (e.g. by a bond-breaking potential) are written
to the restart file as broken bonds with a type of 0. Thus these
bonds will still be broken when the restart file is read.
Bonds that have been broken by the "fix
bond/break"_fix_bond_break.html command have disappeared from the
system. No information about these bonds is written to the restart
file.
:line
[Restrictions:]
To write and read restart files in parallel with MPI-IO, the MPIIO
package must be installed.
[Related commands:]
"read_data"_read_data.html, "read_dump"_read_dump.html,
"write_restart"_write_restart.html, "restart"_restart.html
[Default:] none
diff --git a/doc/src/region.txt b/doc/src/region.txt
index 885e5e45f..5039e4a51 100644
--- a/doc/src/region.txt
+++ b/doc/src/region.txt
@@ -1,400 +1,400 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
region command :h3
[Syntax:]
region ID style args keyword arg ... :pre
ID = user-assigned name for the region :ulb,l
style = {delete} or {block} or {cone} or {cylinder} or {plane} or {prism} or {sphere} or {union} or {intersect} :l
{delete} = no args
{block} args = xlo xhi ylo yhi zlo zhi
xlo,xhi,ylo,yhi,zlo,zhi = bounds of block in all dimensions (distance units)
{cone} args = dim c1 c2 radlo radhi lo hi
dim = {x} or {y} or {z} = axis of cone
c1,c2 = coords of cone axis in other 2 dimensions (distance units)
radlo,radhi = cone radii at lo and hi end (distance units)
lo,hi = bounds of cone in dim (distance units)
{cylinder} args = dim c1 c2 radius lo hi
dim = {x} or {y} or {z} = axis of cylinder
c1,c2 = coords of cylinder axis in other 2 dimensions (distance units)
radius = cylinder radius (distance units)
radius can be a variable (see below)
lo,hi = bounds of cylinder in dim (distance units)
{plane} args = px py pz nx ny nz
px,py,pz = point on the plane (distance units)
nx,ny,nz = direction normal to plane (distance units)
{prism} args = xlo xhi ylo yhi zlo zhi xy xz yz
xlo,xhi,ylo,yhi,zlo,zhi = bounds of untilted prism (distance units)
xy = distance to tilt y in x direction (distance units)
xz = distance to tilt z in x direction (distance units)
yz = distance to tilt z in y direction (distance units)
{sphere} args = x y z radius
x,y,z = center of sphere (distance units)
radius = radius of sphere (distance units)
radius can be a variable (see below)
{union} args = N reg-ID1 reg-ID2 ...
N = # of regions to follow, must be 2 or greater
reg-ID1,reg-ID2, ... = IDs of regions to join together
{intersect} args = N reg-ID1 reg-ID2 ...
N = # of regions to follow, must be 2 or greater
reg-ID1,reg-ID2, ... = IDs of regions to intersect :pre
zero or more keyword/arg pairs may be appended :l
keyword = {side} or {units} or {move} or {rotate} or {open} :l
{side} value = {in} or {out}
{in} = the region is inside the specified geometry
{out} = the region is outside the specified geometry
{units} value = {lattice} or {box}
{lattice} = the geometry is defined in lattice units
{box} = the geometry is defined in simulation box units
{move} args = v_x v_y v_z
v_x,v_y,v_z = equal-style variables for x,y,z displacement of region over time
{rotate} args = v_theta Px Py Pz Rx Ry Rz
v_theta = equal-style variable for rotaton of region over time (in radians)
Px,Py,Pz = origin for axis of rotation (distance units)
Rx,Ry,Rz = axis of rotation vector
{open} value = integer from 1-6 corresponding to face index (see below)
:pre
accelerated styles (with same args) = {block/kk} :l
:ule
[Examples:]
region 1 block -3.0 5.0 INF 10.0 INF INF
region 2 sphere 0.0 0.0 0.0 5 side out
region void cylinder y 2 3 5 -5.0 EDGE units box
region 1 prism 0 10 0 10 0 10 2 0 0
region outside union 4 side1 side2 side3 side4
region 2 sphere 0.0 0.0 0.0 5 side out move v_left v_up NULL
region openbox block 0 10 0 10 0 10 open 5 open 6 units box
region funnel cone z 10 10 2 5 0 10 open 1 units box :pre
[Description:]
This command defines a geometric region of space. Various other
commands use regions. For example, the region can be filled with
atoms via the "create_atoms"_create_atoms.html command. Or a bounding
box around the region, can be used to define the simulation box via
the "create_box"_create_box.html command. Or the atoms in the region
can be identified as a group via the "group"_group.html command, or
deleted via the "delete_atoms"_delete_atoms.html command. Or the
surface of the region can be used as a boundary wall via the "fix
wall/region"_fix_wall_region.html command.
Commands which use regions typically test whether an atom's position
is contained in the region or not. For this purpose, coordinates
exactly on the region boundary are considered to be interior to the
region. This means, for example, for a spherical region, an atom on
the sphere surface would be part of the region if the sphere were
defined with the {side in} keyword, but would not be part of the
region if it were defined using the {side out} keyword. See more
details on the {side} keyword below.
Normally, regions in LAMMPS are "static", meaning their geometric
extent does not change with time. If the {move} or {rotate} keyword
is used, as described below, the region becomes "dynamic", meaning
it's location or orientation changes with time. This may be useful,
for example, when thermostatting a region, via the compute temp/region
command, or when the fix wall/region command uses a region surface as
a bounding wall on particle motion, i.e. a rotating container.
The {delete} style removes the named region. Since there is little
overhead to defining extra regions, there is normally no need to do
this, unless you are defining and discarding large numbers of regions
in your input script.
The lo/hi values for {block} or {cone} or {cylinder} or {prism} styles
can be specified as EDGE or INF. EDGE means they extend all the way
to the global simulation box boundary. Note that this is the current
box boundary; if the box changes size during a simulation, the region
does not. INF means a large negative or positive number (1.0e20), so
it should encompass the simulation box even if it changes size. If a
region is defined before the simulation box has been created (via
"create_box"_create_box.html or "read_data"_read_data.html or
"read_restart"_read_restart.html commands), then an EDGE or INF
parameter cannot be used. For a {prism} region, a non-zero tilt
factor in any pair of dimensions cannot be used if both the lo/hi
values in either of those dimensions are INF. E.g. if the xy tilt is
non-zero, then xlo and xhi cannot both be INF, nor can ylo and yhi.
NOTE: Regions in LAMMPS do not get wrapped across periodic boundaries,
as specified by the "boundary"_boundary.html command. For example, a
spherical region that is defined so that it overlaps a periodic
boundary is not treated as 2 half-spheres, one on either side of the
simulation box.
NOTE: Regions in LAMMPS are always 3d geometric objects, regardless of
whether the "dimension"_dimension.html of a simulation is 2d or 3d.
Thus when using regions in a 2d simulation, you should be careful to
define the region so that its intersection with the 2d x-y plane of
the simulation has the 2d geometric extent you want.
For style {cone}, an axis-aligned cone is defined which is like a
{cylinder} except that two different radii (one at each end) can be
defined. Either of the radii (but not both) can be 0.0.
For style {cone} and {cylinder}, the c1,c2 params are coordinates in
the 2 other dimensions besides the cylinder axis dimension. For dim =
x, c1/c2 = y/z; for dim = y, c1/c2 = x/z; for dim = z, c1/c2 = x/y.
Thus the third example above specifies a cylinder with its axis in the
y-direction located at x = 2.0 and z = 3.0, with a radius of 5.0, and
extending in the y-direction from -5.0 to the upper box boundary.
For style {plane}, a plane is defined which contain the point
(px,py,pz) and has a normal vector (nx,ny,nz). The normal vector does
not have to be of unit length. The "inside" of the plane is the
half-space in the direction of the normal vector; see the discussion
of the {side} option below.
For style {prism}, a parallelepiped is defined (it's too hard to spell
parallelepiped in an input script!). The parallelepiped has its
"origin" at (xlo,ylo,zlo) and is defined by 3 edge vectors starting
from the origin given by A = (xhi-xlo,0,0); B = (xy,yhi-ylo,0); C =
(xz,yz,zhi-zlo). {Xy,xz,yz} can be 0.0 or positive or negative values
and are called "tilt factors" because they are the amount of
displacement applied to faces of an originally orthogonal box to
transform it into the parallelepiped.
A prism region that will be used with the "create_box"_create_box.html
command to define a triclinic simulation box must have tilt factors
(xy,xz,yz) that do not skew the box more than half the distance of
corresponding the parallel box length. For example, if xlo = 2 and
xhi = 12, then the x box length is 10 and the xy tilt factor must be
between -5 and 5. Similarly, both xz and yz must be between
-(xhi-xlo)/2 and +(yhi-ylo)/2. Note that this is not a limitation,
since if the maximum tilt factor is 5 (as in this example), then
configurations with tilt = ..., -15, -5, 5, 15, 25, ... are all
geometrically equivalent.
The {radius} value for style {sphere} and {cylinder} can be specified
as an equal-style "variable"_variable.html. If the value is a
variable, it should be specified as v_name, where name is the variable
name. In this case, the variable will be evaluated each timestep, and
its value used to determine the radius of the region.
Equal-style variables can specify formulas with various mathematical
functions, and include "thermo_style"_thermo_style.html command
keywords for the simulation box parameters and timestep and elapsed
time. Thus it is easy to specify a time-dependent radius.
See "Section 6.12"_Section_howto.html#howto_12 of the doc pages
for a geometric description of triclinic boxes, as defined by LAMMPS,
and how to transform these parameters to and from other commonly used
triclinic representations.
The {union} style creates a region consisting of the volume of all the
listed regions combined. The {intersect} style creates a region
consisting of the volume that is common to all the listed regions.
NOTE: The {union} and {intersect} regions operate by invoking methods
from their list of sub-regions. Thus you cannot delete the
sub-regions after defining a {union} or {intersection} region.
:line
The {side} keyword determines whether the region is considered to be
inside or outside of the specified geometry. Using this keyword in
conjunction with {union} and {intersect} regions, complex geometries
can be built up. For example, if the interior of two spheres were
each defined as regions, and a {union} style with {side} = out was
constructed listing the region-IDs of the 2 spheres, the resulting
region would be all the volume in the simulation box that was outside
both of the spheres.
The {units} keyword determines the meaning of the distance units used
to define the region for any argument above listed as having distance
units. It also affects the scaling of the velocity vector specified
with the {vel} keyword, the amplitude vector specified with the
{wiggle} keyword, and the rotation point specified with the {rotate}
keyword, since they each involve a distance metric.
A {box} value selects standard distance units as defined by the
"units"_units.html command, e.g. Angstroms for units = real or metal.
A {lattice} value means the distance units are in lattice spacings.
The "lattice"_lattice.html command must have been previously used to
define the lattice spacings which are used as follows:
For style {block}, the lattice spacing in dimension x is applied to
xlo and xhi, similarly the spacings in dimensions y,z are applied to
ylo/yhi and zlo/zhi. :ulb,l
For style {cone}, the lattice spacing in argument {dim} is applied to
lo and hi. The spacings in the two radial dimensions are applied to
c1 and c2. The two cone radii are scaled by the lattice
spacing in the dimension corresponding to c1. :l
For style {cylinder}, the lattice spacing in argument {dim} is applied
to lo and hi. The spacings in the two radial dimensions are applied
to c1 and c2. The cylinder radius is scaled by the lattice
spacing in the dimension corresponding to c1. :l
For style {plane}, the lattice spacing in dimension x is applied to
px and nx, similarly the spacings in dimensions y,z are applied to
py/ny and pz/nz. :l
For style {prism}, the lattice spacing in dimension x is applied to
xlo and xhi, similarly for ylo/yhi and zlo/zhi. The lattice spacing
in dimension x is applied to xy and xz, and the spacing in dimension y
to yz. :l
For style {sphere}, the lattice spacing in dimensions x,y,z are
applied to the sphere center x,y,z. The spacing in dimension x is
applied to the sphere radius. :l,ule
:line
If the {move} or {rotate} keywords are used, the region is "dynamic",
meaning its location or orientation changes with time. These keywords
cannot be used with a {union} or {intersect} style region. Instead,
the keywords should be used to make the individual sub-regions of the
{union} or {intersect} region dynamic. Normally, each sub-region
should be "dynamic" in the same manner (e.g. rotate around the same
point), though this is not a requirement.
The {move} keyword allows one or more "equal-style
variables"_variable.html to be used to specify the x,y,z displacement
of the region, typically as a function of time. A variable is
specified as v_name, where name is the variable name. Any of the
three variables can be specified as NULL, in which case no
displacement is calculated in that dimension.
Note that equal-style variables can specify formulas with various
mathematical functions, and include "thermo_style"_thermo_style.html
command keywords for the simulation box parameters and timestep and
elapsed time. Thus it is easy to specify a region displacement that
change as a function of time or spans consecutive runs in a continuous
fashion. For the latter, see the {start} and {stop} keywords of the
"run"_run.html command and the {elaplong} keyword of "thermo_style
custom"_thermo_style.html for details.
For example, these commands would displace a region from its initial
position, in the positive x direction, effectively at a constant
velocity:
variable dx equal ramp(0,10)
region 2 sphere 10.0 10.0 0.0 5 move v_dx NULL NULL :pre
Note that the initial displacement is 0.0, though that is not required.
Either of these variables would "wiggle" the region back and forth in
the y direction:
variable dy equal swiggle(0,5,100)
variable dysame equal 5*sin(2*PI*elaplong*dt/100)
region 2 sphere 10.0 10.0 0.0 5 move NULL v_dy NULL :pre
The {rotate} keyword rotates the region around a rotation axis {R} =
(Rx,Ry,Rz) that goes thru a point {P} = (Px,Py,Pz). The rotation
angle is calculated, presumably as a function of time, by a variable
specified as v_theta, where theta is the variable name. The variable
should generate its result in radians. The direction of rotation for
the region around the rotation axis is consistent with the right-hand
rule: if your right-hand thumb points along {R}, then your fingers
wrap around the axis in the direction of rotation.
The {move} and {rotate} keywords can be used together. In this case,
the displacement specified by the {move} keyword is applied to the {P}
point of the {rotate} keyword.
:line
The {open} keyword can be used (multiple times) to indicate that one
or more faces of the region are ignored for purposes of particle/wall
interactions. This keyword is only relevant for regions used by the
{fix wall/region} and {fix wall/gran/region} commands. It can be used
to create "open" containers where only some of the region faces are
walls. For example, a funnel can be created with a {cone} style
region that has an open face at the smaller radius for particles to
flow out, or at the larger radius for pouring particles into the cone,
or both.
Note that using the {open} keyword partly overrides the {side}
keyword, since both exterior and interior surfaces of an open region
are tested for particle contacts. The exception to this is a {union}
or {intersect} region which includes an open sub-region. In that case
the {side} keyword is still used to define the union/intersect region
volume, and the {open} settings are only applied to the individual
sub-regions that use them.
The indices specified as part of the {open} keyword have the following
meanings:
For style {block}, indices 1-6 correspond to the xlo, xhi, ylo, yhi,
zlo, zhi surfaces of the block. I.e. 1 is the yz plane at x = xlo, 2
is the yz-plane at x = xhi, 3 is the xz plane at y = ylo, 4 is the xz
plane at y = yhi, 5 is the xy plane at z = zlo, 6 is the xy plane at z
= zhi). In the second-to-last example above, the region is a box open
at both xy planes.
For style {prism}, values 1-6 have the same mapping as for style
{block}. I.e. in an untilted {prism}, {open} indices correspond to
the xlo, xhi, ylo, yhi, zlo, zhi surfaces.
For style {cylinder}, index 1 corresponds to the flat end cap at the
low coordinate along the cylinder axis, index 2 corresponds to the
high-coordinate flat end cap along the cylinder axis, and index 3 is
the curved cylinder surface. For example, a {cylinder} region with
{open 1 open 2} keywords will be open at both ends (e.g. a section of
pipe), regardless of the cylinder orientation.
For style {cone}, the mapping is the same as for style {cylinder}.
Index 1 is the low-coordinate flat end cap, index 2 is the
high-coordinate flat end cap, and index 3 is the curved cone surface.
In the last example above, a {cone} region is defined along the z-axis
that is open at the zlo value (e.g. for use as a funnel).
For all other styles, the {open} keyword is ignored. As indicated
above, this includes the {intersect} and {union} regions, though their
sub-regions can be defined with the {open} keyword.
:line
Styles with a {kk} suffix are functionally the same as the
corresponding style without the suffix. They have been optimized to
run faster, depending on your available hardware, as discussed in
"Section 5"_Section_accelerate.html of the manual. The
accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
The code using the region (such as a fix or compute) must also be supported
by Kokkos or no acceleration will occur. Currently, only {block} style
regions are supported by Kokkos.
These accelerated styles are part of the Kokkos package. They are
only enabled if LAMMPS was built with that package. See the "Making
LAMMPS"_Section_start.html#start_3 section for more info.
You can specify the accelerated styles explicitly in your input script
by including their suffix, or you can use the "-suffix command-line
-switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can
+switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can
use the "suffix"_suffix.html command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
A prism cannot be of 0.0 thickness in any dimension; use a small z
thickness for 2d simulations. For 2d simulations, the xz and yz
parameters must be 0.0.
[Related commands:]
"lattice"_lattice.html, "create_atoms"_create_atoms.html,
"delete_atoms"_delete_atoms.html, "group"_group.html
[Default:]
The option defaults are side = in, units = lattice, and no move or
rotation.
diff --git a/doc/src/restart.txt b/doc/src/restart.txt
index 5e0c2a9ea..7c39ae140 100644
--- a/doc/src/restart.txt
+++ b/doc/src/restart.txt
@@ -1,174 +1,174 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
restart command :h3
[Syntax:]
restart 0
restart N root keyword value ...
restart N file1 file2 keyword value ... :pre
N = write a restart file every this many timesteps :ulb,l
N can be a variable (see below) :l
root = filename to which timestep # is appended :l
file1,file2 = two full filenames, toggle between them when writing file :l
zero or more keyword/value pairs may be appended :l
keyword = {fileper} or {nfile} :l
{fileper} arg = Np
Np = write one file for every this many processors
{nfile} arg = Nf
Nf = write this many files, one from each of Nf processors :pre
:ule
[Examples:]
restart 0
restart 1000 poly.restart
restart 1000 poly.restart.mpiio
restart 1000 restart.*.equil
restart 10000 poly.%.1 poly.%.2 nfile 10
restart v_mystep poly.restart :pre
[Description:]
Write out a binary restart file with the current state of the
simulation every so many timesteps, in either or both of two modes, as
a run proceeds. A value of 0 means do not write out any restart
files. The two modes are as follows. If one filename is specified, a
series of filenames will be created which include the timestep in the
filename. If two filenames are specified, only 2 restart files will
be created, with those names. LAMMPS will toggle between the 2 names
as it writes successive restart files.
Note that you can specify the restart command twice, once with a
single filename and once with two filenames. This would allow you,
for example, to write out archival restart files every 100000 steps
using a single filenname, and more frequent temporary restart files
every 1000 steps, using two filenames. Using restart 0 will turn off
both modes of output.
Similar to "dump"_dump.html files, the restart filename(s) can contain
two wild-card characters.
If a "*" appears in the single filename, it is replaced with the
current timestep value. This is only recognized when a single
filename is used (not when toggling back and forth). Thus, the 3rd
example above creates restart files as follows: restart.1000.equil,
restart.2000.equil, etc. If a single filename is used with no "*",
then the timestep value is appended. E.g. the 2nd example above
creates restart files as follows: poly.restart.1000,
poly.restart.2000, etc.
If a "%" character appears in the restart filename(s), then one file
is written for each processor and the "%" character is replaced with
the processor ID from 0 to P-1. An additional file with the "%"
replaced by "base" is also written, which contains global information.
For example, the files written on step 1000 for filename restart.%
would be restart.base.1000, restart.0.1000, restart.1.1000, ...,
restart.P-1.1000. This creates smaller files and can be a fast mode
of output and subsequent input on parallel machines that support
parallel I/O. The optional {fileper} and {nfile} keywords discussed
below can alter the number of files written.
The restart file can also be written in parallel as one large binary
file via the MPI-IO library, which is part of the MPI standard for
versions 2.0 and above. Using MPI-IO requires two steps. First,
build LAMMPS with its MPIIO package installed, e.g.
make yes-mpiio # installs the MPIIO package
make mpi # build LAMMPS for your platform :pre
Second, use a restart filename which contains ".mpiio". Note that it
does not have to end in ".mpiio", just contain those characters.
Unlike MPI-IO dump files, a particular restart file must be both
written and read using MPI-IO.
Restart files are written on timesteps that are a multiple of N but
not on the first timestep of a run or minimization. You can use the
"write_restart"_write_restart.html command to write a restart file
before a run begins. A restart file is not written on the last
timestep of a run unless it is a multiple of N. A restart file is
written on the last timestep of a minimization if N > 0 and the
minimization converges.
Instead of a numeric value, N can be specified as an "equal-style
variable"_variable.html, which should be specified as v_name, where
name is the variable name. In this case, the variable is evaluated at
the beginning of a run to determine the next timestep at which a
restart file will be written out. On that timestep, the variable will
be evaluated again to determine the next timestep, etc. Thus the
variable should return timestep values. See the stagger() and
logfreq() and stride() math functions for "equal-style
variables"_variable.html, as examples of useful functions to use in
this context. Other similar math functions could easily be added as
options for "equal-style variables"_variable.html.
For example, the following commands will write restart files
every step from 1100 to 1200, and could be useful for debugging
a simulation where something goes wrong at step 1163:
variable s equal stride(1100,1200,1)
restart v_s tmp.restart :pre
:line
See the "read_restart"_read_restart.html command for information about
what is stored in a restart file.
Restart files can be read by a "read_restart"_read_restart.html
command to restart a simulation from a particular state. Because the
file is binary (to enable exact restarts), it may not be readable on
another machine. In this case, you can use the "-r command-line
-switch"_Section_start.html#start_7 to convert a restart file to a data
+switch"_Section_start.html#start_6 to convert a restart file to a data
file.
NOTE: Although the purpose of restart files is to enable restarting a
simulation from where it left off, not all information about a
simulation is stored in the file. For example, the list of fixes that
were specified during the initial run is not stored, which means the
new input script must specify any fixes you want to use. Even when
restart information is stored in the file, as it is for some fixes,
commands may need to be re-specified in the new input script, in order
to re-use that information. See the "read_restart"_read_restart.html
command for information about what is stored in a restart file.
:line
The optional {nfile} or {fileper} keywords can be used in conjunction
with the "%" wildcard character in the specified restart file name(s).
As explained above, the "%" character causes the restart file to be
written in pieces, one piece for each of P processors. By default P =
the number of processors the simulation is running on. The {nfile} or
{fileper} keyword can be used to set P to a smaller value, which can
be more efficient when running on a large number of processors.
The {nfile} keyword sets P to the specified Nf value. For example, if
Nf = 4, and the simulation is running on 100 processors, 4 files will
be written, by processors 0,25,50,75. Each will collect information
from itself and the next 24 processors and write it to a restart file.
For the {fileper} keyword, the specified value of Np means write one
file for every Np processors. For example, if Np = 4, every 4th
processor (0,4,8,12,etc) will collect information from itself and the
next 3 processors and write it to a restart file.
:line
[Restrictions:]
To write and read restart files in parallel with MPI-IO, the MPIIO
package must be installed.
[Related commands:]
"write_restart"_write_restart.html, "read_restart"_read_restart.html
[Default:]
restart 0 :pre
diff --git a/doc/src/run_style.txt b/doc/src/run_style.txt
index a67899420..ba836a07d 100644
--- a/doc/src/run_style.txt
+++ b/doc/src/run_style.txt
@@ -1,294 +1,294 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
run_style command :h3
[Syntax:]
run_style style args :pre
style = {verlet} or {verlet/split} or {respa} or {respa/omp} :ulb,l
{verlet} args = none
{verlet/split} args = none
{respa} args = N n1 n2 ... keyword values ...
N = # of levels of rRESPA
n1, n2, ... = loop factors between rRESPA levels (N-1 values)
zero or more keyword/value pairings may be appended to the loop factors
keyword = {bond} or {angle} or {dihedral} or {improper} or
{pair} or {inner} or {middle} or {outer} or {hybrid} or {kspace}
{bond} value = M
M = which level (1-N) to compute bond forces in
{angle} value = M
M = which level (1-N) to compute angle forces in
{dihedral} value = M
M = which level (1-N) to compute dihedral forces in
{improper} value = M
M = which level (1-N) to compute improper forces in
{pair} value = M
M = which level (1-N) to compute pair forces in
{inner} values = M cut1 cut2
M = which level (1-N) to compute pair inner forces in
cut1 = inner cutoff between pair inner and
pair middle or outer (distance units)
cut2 = outer cutoff between pair inner and
pair middle or outer (distance units)
{middle} values = M cut1 cut2
M = which level (1-N) to compute pair middle forces in
cut1 = inner cutoff between pair middle and pair outer (distance units)
cut2 = outer cutoff between pair middle and pair outer (distance units)
{outer} value = M
M = which level (1-N) to compute pair outer forces in
{hybrid} values = M1 M2 ... (as many values as there are hybrid sub-styles
M1 = which level (1-N) to compute the first pair_style hybrid sub-style in
M2 = which level (1-N) to compute the second pair_style hybrid sub-style in
M3,etc
{kspace} value = M
M = which level (1-N) to compute kspace forces in :pre
:ule
[Examples:]
run_style verlet
run_style respa 4 2 2 2 bond 1 dihedral 2 pair 3 kspace 4
run_style respa 4 2 2 2 bond 1 dihedral 2 inner 3 5.0 6.0 outer 4 kspace 4
run_style respa 3 4 2 bond 1 hybrid 2 2 1 kspace 3 :pre
[Description:]
Choose the style of time integrator used for molecular dynamics
simulations performed by LAMMPS.
The {verlet} style is a standard velocity-Verlet integrator.
:line
The {verlet/split} style is also a velocity-Verlet integrator, but it
splits the force calculation within each timestep over 2 partitions of
-processors. See "Section 2.7"_Section_start.html#start_7 for an
+processors. See "Section 2.6"_Section_start.html#start_6 for an
explanation of the -partition command-line switch.
Specifically, this style performs all computation except the
"kspace_style"_kspace_style.html portion of the force field on the 1st
partition. This include the "pair style"_pair_style.html, "bond
style"_bond_style.html, "neighbor list building"_neighbor.html,
"fixes"_fix.html including time integration, and output. The
"kspace_style"_kspace_style.html portion of the calculation is
performed on the 2nd partition.
This is most useful for the PPPM kspace_style when its performance on
a large number of processors degrades due to the cost of communication
in its 3d FFTs. In this scenario, splitting your P total processors
into 2 subsets of processors, P1 in the 1st partition and P2 in the
2nd partition, can enable your simulation to run faster. This is
because the long-range forces in PPPM can be calculated at the same
time as pair-wise and bonded forces are being calculated, and the FFTs
can actually speed up when running on fewer processors.
To use this style, you must define 2 partitions where P1 is a multiple
of P2. Typically having P1 be 3x larger than P2 is a good choice.
The 3d processor layouts in each partition must overlay in the
following sense. If P1 is a Px1 by Py1 by Pz1 grid, and P2 = Px2 by
Py2 by Pz2, then Px1 must be an integer multiple of Px2, and similarly
for Py1 a multiple of Py2, and Pz1 a multiple of Pz2.
Typically the best way to do this is to let the 1st partition choose
its onn optimal layout, then require the 2nd partition's layout to
match the integer multiple constraint. See the
"processors"_processors.html command with its {part} keyword for a way
to control this, e.g.
procssors * * * part 1 2 multiple :pre
You can also use the "partition"_partition.html command to explicitly
specify the processor layout on each partition. E.g. for 2 partitions
of 60 and 15 processors each:
partition yes 1 processors 3 4 5
partition yes 2 processors 3 1 5 :pre
When you run in 2-partition mode with the {verlet/split} style, the
thermodynamic data for the entire simulation will be output to the log
and screen file of the 1st partition, which are log.lammps.0 and
screen.0 by default; see the "-plog and -pscreen command-line
-switches"_Section_start.html#start_7 to change this. The log and
+switches"_Section_start.html#start_6 to change this. The log and
screen file for the 2nd partition will not contain thermodynamic
output beyond the 1st timestep of the run.
See "Section 5"_Section_accelerate.html of the manual for
performance details of the speed-up offered by the {verlet/split}
style. One important performance consideration is the assignment of
logical processors in the 2 partitions to the physical cores of a
parallel machine. The "processors"_processors.html command has
options to support this, and strategies are discussed in
"Section 5"_Section_accelerate.html of the manual.
:line
The {respa} style implements the rRESPA multi-timescale integrator
"(Tuckerman)"_#Tuckerman3 with N hierarchical levels, where level 1 is
the innermost loop (shortest timestep) and level N is the outermost
loop (largest timestep). The loop factor arguments specify what the
looping factor is between levels. N1 specifies the number of
iterations of level 1 for a single iteration of level 2, N2 is the
iterations of level 2 per iteration of level 3, etc. N-1 looping
parameters must be specified.
The "timestep"_timestep.html command sets the timestep for the
outermost rRESPA level. Thus if the example command above for a
4-level rRESPA had an outer timestep of 4.0 fmsec, the inner timestep
would be 8x smaller or 0.5 fmsec. All other LAMMPS commands that
specify number of timesteps (e.g. "neigh_modify"_neigh_modify.html
parameters, "dump"_dump.html every N timesteps, etc) refer to the
outermost timesteps.
The rRESPA keywords enable you to specify at what level of the
hierarchy various forces will be computed. If not specified, the
defaults are that bond forces are computed at level 1 (innermost
loop), angle forces are computed where bond forces are, dihedral
forces are computed where angle forces are, improper forces are
computed where dihedral forces are, pair forces are computed at the
outermost level, and kspace forces are computed where pair forces are.
The inner, middle, outer forces have no defaults.
For fixes that support it, the rRESPA level at which a given fix is
active, can be selected through the "fix_modify"_fix_modify.html command.
The {inner} and {middle} keywords take additional arguments for
cutoffs that are used by the pairwise force computations. If the 2
cutoffs for {inner} are 5.0 and 6.0, this means that all pairs up to
6.0 apart are computed by the inner force. Those between 5.0 and 6.0
have their force go ramped to 0.0 so the overlap with the next regime
(middle or outer) is smooth. The next regime (middle or outer) will
compute forces for all pairs from 5.0 outward, with those from 5.0 to
6.0 having their value ramped in an inverse manner.
Only some pair potentials support the use of the {inner} and {middle}
and {outer} keywords. If not, only the {pair} keyword can be used
with that pair style, meaning all pairwise forces are computed at the
same rRESPA level. See the doc pages for individual pair styles for
details.i
Another option for using pair potentials with rRESPA is with the
{hybrid} keyword, which requires the use of the "pair_style hybrid or
hybrid/overlay"_pair_hybrid.html command. In this scenario, different
sub-styles of the hybrid pair style are evaluated at different rRESPA
levels. This can be useful, for example, to set different timesteps
for hybrid coarse-grained/all-atom models. The {hybrid} keyword
requires as many level assignments as there are hybrid substyles,
which assigns each sub-style to a rRESPA level, following their order
of definition in the pair_style command. Since the {hybrid} keyword
operates on pair style computations, it is mutually exclusive with
either the {pair} or the {inner}/{middle}/{outer} keywords.
When using rRESPA (or for any MD simulation) care must be taken to
choose a timestep size(s) that insures the Hamiltonian for the chosen
ensemble is conserved. For the constant NVE ensemble, total energy
must be conserved. Unfortunately, it is difficult to know {a priori}
how well energy will be conserved, and a fairly long test simulation
(~10 ps) is usually necessary in order to verify that no long-term
drift in energy occurs with the trial set of parameters.
With that caveat, a few rules-of-thumb may be useful in selecting
{respa} settings. The following applies mostly to biomolecular
simulations using the CHARMM or a similar all-atom force field, but
the concepts are adaptable to other problems. Without SHAKE, bonds
involving hydrogen atoms exhibit high-frequency vibrations and require
a timestep on the order of 0.5 fmsec in order to conserve energy. The
relatively inexpensive force computations for the bonds, angles,
impropers, and dihedrals can be computed on this innermost 0.5 fmsec
step. The outermost timestep cannot be greater than 4.0 fmsec without
risking energy drift. Smooth switching of forces between the levels
of the rRESPA hierarchy is also necessary to avoid drift, and a 1-2
angstrom "healing distance" (the distance between the outer and inner
cutoffs) works reasonably well. We thus recommend the following
settings for use of the {respa} style without SHAKE in biomolecular
simulations:
timestep 4.0
run_style respa 4 2 2 2 inner 2 4.5 6.0 middle 3 8.0 10.0 outer 4 :pre
With these settings, users can expect good energy conservation and
roughly a 2.5 fold speedup over the {verlet} style with a 0.5 fmsec
timestep.
If SHAKE is used with the {respa} style, time reversibility is lost,
but substantially longer time steps can be achieved. For biomolecular
simulations using the CHARMM or similar all-atom force field, bonds
involving hydrogen atoms exhibit high frequency vibrations and require
a time step on the order of 0.5 fmsec in order to conserve energy.
These high frequency modes also limit the outer time step sizes since
the modes are coupled. It is therefore desirable to use SHAKE with
respa in order to freeze out these high frequency motions and increase
the size of the time steps in the respa hierarchy. The following
settings can be used for biomolecular simulations with SHAKE and
rRESPA:
fix 2 all shake 0.000001 500 0 m 1.0 a 1
timestep 4.0
run_style respa 2 2 inner 1 4.0 5.0 outer 2 :pre
With these settings, users can expect good energy conservation and
roughly a 1.5 fold speedup over the {verlet} style with SHAKE and a
2.0 fmsec timestep.
For non-biomolecular simulations, the {respa} style can be
advantageous if there is a clear separation of time scales - fast and
slow modes in the simulation. Even a LJ system can benefit from
rRESPA if the interactions are divided by the inner, middle and outer
keywords. A 2-fold or more speedup can be obtained while maintaining
good energy conservation. In real units, for a pure LJ fluid at
liquid density, with a sigma of 3.0 angstroms, and epsilon of 0.1
Kcal/mol, the following settings seem to work well:
timestep 36.0
run_style respa 3 3 4 inner 1 3.0 4.0 middle 2 6.0 7.0 outer 3 :pre
:line
The {respa/omp} styles is a variant of {respa} adapted for use with
pair, bond, angle, dihedral, improper, or kspace styles with an {omp}
suffix. It is functionally equivalent to {respa} but performs additional
operations required for managing {omp} styles. For more on {omp} styles
see the "Section 5"_Section_accelerate.html of the manual.
Accelerated styles take the same arguments and should produce the same
results, except for round-off and precision issues.
You can specify {respa/omp} explicitly in your input script, or
-you can use the "-suffix command-line switch"_Section_start.html#start_7
+you can use the "-suffix command-line switch"_Section_start.html#start_6
when you invoke LAMMPS, or you can use the "suffix"_suffix.html
command in your input script.
See "Section 5"_Section_accelerate.html of the manual for
more instructions on how to use the accelerated styles effectively.
:line
[Restrictions:]
The {verlet/split} style can only be used if LAMMPS was built with the
REPLICA package. Correspondingly the {respa/omp} style is available only
if the USER-OMP package was included. See the "Making LAMMPS"_Section_start.html#start_3
section for more info on packages.
Whenever using rRESPA, the user should experiment with trade-offs in
speed and accuracy for their system, and verify that they are
conserving energy to adequate precision.
[Related commands:]
"timestep"_timestep.html, "run"_run.html
[Default:]
run_style verlet :pre
:line
:link(Tuckerman3)
[(Tuckerman)] Tuckerman, Berne and Martyna, J Chem Phys, 97, p 1990
(1992).
diff --git a/doc/src/suffix.txt b/doc/src/suffix.txt
index 127719cdb..7a4adb50b 100644
--- a/doc/src/suffix.txt
+++ b/doc/src/suffix.txt
@@ -1,110 +1,110 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
suffix command :h3
[Syntax:]
suffix style args :pre
style = {off} or {on} or {gpu} or {intel} or {kk} or {omp} or {opt} or {hybrid}
args = for hybrid style, default suffix to be used and alternative suffix :ul
[Examples:]
suffix off
suffix on
suffix gpu
suffix intel
suffix hybrid intel omp
suffix kk :pre
[Description:]
This command allows you to use variants of various styles if they
exist. In that respect it operates the same as the "-suffix
-command-line switch"_Section_start.html#start_7. It also has options
+command-line switch"_Section_start.html#start_6. It also has options
to turn off or back on any suffix setting made via the command line.
The specified style can be {gpu}, {intel}, {kk}, {omp}, {opt} or
{hybrid}. These refer to optional packages that LAMMPS can be built
with, as described in "this section of the
manual"_Section_start.html#start_3. The "gpu" style corresponds to
the GPU package, the "intel" style to the USER-INTEL package, the "kk"
style to the KOKKOS package, the "omp" style to the USER-OMP package,
and the "opt" style to the OPT package.
These are the variants these packages provide:
GPU = a handful of pair styles and the PPPM kspace_style, optimized to
run on one or more GPUs or multicore CPU/GPU nodes :ulb,l
USER-INTEL = a collection of pair styles and neighbor routines
optimized to run in single, mixed, or double precision on CPUs and
Intel(R) Xeon Phi(TM) coprocessors. :l
KOKKOS = a collection of atom, pair, and fix styles optimized to run
using the Kokkos library on various kinds of hardware, including GPUs
via Cuda and many-core chips via OpenMP or threading. :l
USER-OMP = a collection of pair, bond, angle, dihedral, improper,
kspace, compute, and fix styles with support for OpenMP
multi-threading :l
OPT = a handful of pair styles, cache-optimized for faster CPU
performance :l
HYBRID = a combination of two packages can be specified (see below) :l
:ule
As an example, all of the packages provide a "pair_style
lj/cut"_pair_lj.html variant, with style names lj/cut/opt, lj/cut/omp,
lj/cut/gpu, lj/cut/intel, or lj/cut/kk. A variant styles
can be specified explicitly in your input script, e.g. pair_style
lj/cut/gpu. If the suffix command is used with the appropriate style,
you do not need to modify your input script. The specified suffix
(opt,omp,gpu,intel,kk) is automatically appended whenever your
input script command creates a new "atom"_atom_style.html,
"pair"_pair_style.html, "bond"_bond_style.html,
"angle"_angle_style.html, "dihedral"_dihedral_style.html,
"improper"_improper_style.html, "kspace"_kspace_style.html,
"fix"_fix.html, "compute"_compute.html, or "run"_run_style.html style.
If the variant version does not exist, the standard version is
created.
For "hybrid", two packages are specified. The first is used whenever
available. If a style with the first suffix is not available, the style
with the suffix for the second package will be used if available. For
example, "hybrid intel omp" will use styles from the USER-INTEL package
as a first choice and styles from the USER-OMP package as a second choice
if no USER-INTEL variant is available.
If the specified style is {off}, then any previously specified suffix
is temporarily disabled, whether it was specified by a command-line
switch or a previous suffix command. If the specified style is {on},
a disabled suffix is turned back on. The use of these 2 commands lets
your input script use a standard LAMMPS style (i.e. a non-accelerated
variant), which can be useful for testing or benchmarking purposes.
Of course this is also possible by not using any suffix commands, and
explicitly appending or not appending the suffix to the relevant
commands in your input script.
NOTE: The default "run_style"_run_style.html verlet is invoked prior to
reading the input script and is therefore not affected by a suffix command
in the input script. The KOKKOS package requires "run_style verlet/kk",
so when using the KOKKOS package it is necessary to either use the command
line "-sf kk" command or add an explicit "run_style verlet" command to the
input script.
[Restrictions:] none
[Related commands:]
-"Command-line switch -suffix"_Section_start.html#start_7
+"Command-line switch -suffix"_Section_start.html#start_6
[Default:] none
diff --git a/doc/src/temper.txt b/doc/src/temper.txt
index be7edfba4..b1c47c807 100644
--- a/doc/src/temper.txt
+++ b/doc/src/temper.txt
@@ -1,149 +1,149 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
temper command :h3
[Syntax:]
temper N M temp fix-ID seed1 seed2 index :pre
N = total # of timesteps to run
M = attempt a tempering swap every this many steps
temp = initial temperature for this ensemble
fix-ID = ID of the fix that will control temperature during the run
seed1 = random # seed used to decide on adjacent temperature to partner with
seed2 = random # seed for Boltzmann factor in Metropolis swap
index = which temperature (0 to N-1) I am simulating (optional) :ul
[Examples:]
temper 100000 100 $t tempfix 0 58728
temper 40000 100 $t tempfix 0 32285 $w :pre
[Description:]
Run a parallel tempering or replica exchange simulation using multiple
replicas (ensembles) of a system. Two or more replicas must be used.
Each replica runs on a partition of one or more processors. Processor
partitions are defined at run-time using the -partition command-line
-switch; see "Section 2.7"_Section_start.html#start_7 of the
+switch; see "Section 2.6"_Section_start.html#start_6 of the
manual. Note that if you have MPI installed, you can run a
multi-replica simulation with more replicas (partitions) than you have
physical processors, e.g you can run a 10-replica simulation on one or
two processors. You will simply not get the performance speed-up you
would see with one or more physical processors per replica. See "this
section"_Section_howto.html#howto_5 of the manual for further
discussion.
Each replica's temperature is controlled at a different value by a fix
with {fix-ID} that controls temperature. Most thermostat fix styles
(with and without included time integration) are supported. The command
will print an error message and abort, if the chosen fix is unsupported.
The desired temperature is specified by {temp}, which is typically a
variable previously set in the input script, so that each partition is
assigned a different temperature. See the "variable"_variable.html
command for more details. For example:
variable t world 300.0 310.0 320.0 330.0
fix myfix all nvt temp $t $t 100.0
temper 100000 100 $t myfix 3847 58382 :pre
would define 4 temperatures, and assign one of them to the thermostat
used by each replica, and to the temper command.
As the tempering simulation runs for {N} timesteps, a temperature swap
between adjacent ensembles will be attempted every {M} timesteps. If
{seed1} is 0, then the swap attempts will alternate between odd and
even pairings. If {seed1} is non-zero then it is used as a seed in a
random number generator to randomly choose an odd or even pairing each
time. Each attempted swap of temperatures is either accepted or
rejected based on a Boltzmann-weighted Metropolis criterion which uses
{seed2} in the random number generator.
As a tempering run proceeds, multiple log files and screen output
files are created, one per replica. By default these files are named
log.lammps.M and screen.M where M is the replica number from 0 to N-1,
with N = # of replicas. See the "section on command-line
-switches"_Section_start.html#start_7 for info on how to change these
+switches"_Section_start.html#start_6 for info on how to change these
names.
The main screen and log file (log.lammps) will list information about
which temperature is assigned to each replica at each thermodynamic
output timestep. E.g. for a simulation with 16 replicas:
Running on 16 partitions of processors
Step T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15
0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
500 1 0 3 2 5 4 6 7 8 9 10 11 12 13 14 15
1000 2 0 4 1 5 3 6 7 8 9 10 11 12 14 13 15
1500 2 1 4 0 5 3 6 7 9 8 10 11 12 14 13 15
2000 2 1 3 0 6 4 5 7 10 8 9 11 12 14 13 15
2500 2 1 3 0 6 4 5 7 11 8 9 10 12 14 13 15
... :pre
The column headings T0 to TN-1 mean which temperature is currently
assigned to the replica 0 to N-1. Thus the columns represent replicas
and the value in each column is its temperature (also numbered 0 to
N-1). For example, a 0 in the 4th column (column T3, step 2500) means
that the 4th replica is assigned temperature 0, i.e. the lowest
temperature. You can verify this time sequence of temperature
assignments for the Nth replica by comparing the Nth column of screen
output to the thermodynamic data in the corresponding log.lammps.N or
screen.N files as time proceeds.
You can have each replica create its own dump file in the following
manner:
variable rep world 0 1 2 3 4 5 6 7
dump 1 all atom 1000 dump.temper.${rep} :pre
NOTE: Each replica's dump file will contain a continuous trajectory
for its atoms where the temperature varies over time as swaps take
place involving that replica. If you want a series of dump files,
each with snapshots (from all replicas) that are all at a single
temperature, then you will need to post-process the dump files using
the information from the log.lammps file. E.g. you could produce one
dump file with snapshots at 300K (from all replicas), another with
snapshots at 310K, etc. Note that these new dump files will not
contain "continuous trajectories" for individual atoms, because two
successive snapshots (in time) may be from different replicas.
The last argument {index} in the temper command is optional and is
used when restarting a tempering run from a set of restart files (one
for each replica) which had previously swapped to new temperatures.
The {index} value (from 0 to N-1, where N is the # of replicas)
identifies which temperature the replica was simulating on the
timestep the restart files were written. Obviously, this argument
must be a variable so that each partition has the correct value. Set
the variable to the {N} values listed in the log file for the previous
run for the replica temperatures at that timestep. For example if the
log file listed the following for a simulation with 5 replicas:
500000 2 4 0 1 3 :pre
then a setting of
variable w world 2 4 0 1 3 :pre
would be used to restart the run with a tempering command like the
example above with $w as the last argument.
:line
[Restrictions:]
This command can only be used if LAMMPS was built with the REPLICA
package. See the "Making LAMMPS"_Section_start.html#start_3 section
for more info on packages.
[Related commands:]
"variable"_variable.html, "prd"_prd.html, "neb"_neb.html
[Default:] none
diff --git a/doc/src/thermo_style.txt b/doc/src/thermo_style.txt
index 36ec7bf12..6102169ee 100644
--- a/doc/src/thermo_style.txt
+++ b/doc/src/thermo_style.txt
@@ -1,408 +1,408 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
thermo_style command :h3
[Syntax:]
thermo_style style args :pre
style = {one} or {multi} or {custom} :ulb,l
args = list of arguments for a particular style :l
{one} args = none
{multi} args = none
{custom} args = list of keywords
possible keywords = step, elapsed, elaplong, dt, time,
cpu, tpcpu, spcpu, cpuremain, part, timeremain,
atoms, temp, press, pe, ke, etotal, enthalpy,
evdwl, ecoul, epair, ebond, eangle, edihed, eimp,
emol, elong, etail,
vol, density, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi,
xy, xz, yz, xlat, ylat, zlat,
bonds, angles, dihedrals, impropers,
pxx, pyy, pzz, pxy, pxz, pyz,
fmax, fnorm, nbuild, ndanger,
cella, cellb, cellc, cellalpha, cellbeta, cellgamma,
c_ID, c_ID\[I\], c_ID\[I\]\[J\],
f_ID, f_ID\[I\], f_ID\[I\]\[J\],
v_name, v_name\[I\]
step = timestep
elapsed = timesteps since start of this run
elaplong = timesteps since start of initial run in a series of runs
dt = timestep size
time = simulation time
cpu = elapsed CPU time in seconds since start of this run
tpcpu = time per CPU second
spcpu = timesteps per CPU second
cpuremain = estimated CPU time remaining in run
part = which partition (0 to Npartition-1) this is
timeremain = remaining time in seconds on timer timeout.
atoms = # of atoms
temp = temperature
press = pressure
pe = total potential energy
ke = kinetic energy
etotal = total energy (pe + ke)
enthalpy = enthalpy (etotal + press*vol)
evdwl = VanderWaal pairwise energy (includes etail)
ecoul = Coulombic pairwise energy
epair = pairwise energy (evdwl + ecoul + elong)
ebond = bond energy
eangle = angle energy
edihed = dihedral energy
eimp = improper energy
emol = molecular energy (ebond + eangle + edihed + eimp)
elong = long-range kspace energy
etail = VanderWaal energy long-range tail correction
vol = volume
density = mass density of system
lx,ly,lz = box lengths in x,y,z
xlo,xhi,ylo,yhi,zlo,zhi = box boundaries
xy,xz,yz = box tilt for triclinic (non-orthogonal) simulation boxes
xlat,ylat,zlat = lattice spacings as calculated by "lattice"_lattice.html command
bonds,angles,dihedrals,impropers = # of these interactions defined
pxx,pyy,pzz,pxy,pxz,pyz = 6 components of pressure tensor
fmax = max component of force on any atom in any dimension
fnorm = length of force vector for all atoms
nbuild = # of neighbor list builds
ndanger = # of dangerous neighbor list builds
cella,cellb,cellc = periodic cell lattice constants a,b,c
cellalpha, cellbeta, cellgamma = periodic cell angles alpha,beta,gamma
c_ID = global scalar value calculated by a compute with ID
c_ID\[I\] = Ith component of global vector calculated by a compute with ID, I can include wildcard (see below)
c_ID\[I\]\[J\] = I,J component of global array calculated by a compute with ID
f_ID = global scalar value calculated by a fix with ID
f_ID\[I\] = Ith component of global vector calculated by a fix with ID, I can include wildcard (see below)
f_ID\[I\]\[J\] = I,J component of global array calculated by a fix with ID
v_name = value calculated by an equal-style variable with name
v_name\[I\] = value calculated by a vector-style variable with name :pre
:ule
[Examples:]
thermo_style multi
thermo_style custom step temp pe etotal press vol
thermo_style custom step temp etotal c_myTemp v_abc
thermo_style custom step temp etotal c_myTemp\[*\] v_abc :pre
[Description:]
Set the style and content for printing thermodynamic data to the
screen and log file.
Style {one} prints a one-line summary of thermodynamic info that is
the equivalent of "thermo_style custom step temp epair emol etotal
press". The line contains only numeric values.
Style {multi} prints a multiple-line listing of thermodynamic info
that is the equivalent of "thermo_style custom etotal ke temp pe ebond
eangle edihed eimp evdwl ecoul elong press". The listing contains
numeric values and a string ID for each quantity.
Style {custom} is the most general setting and allows you to specify
which of the keywords listed above you want printed on each
thermodynamic timestep. Note that the keywords c_ID, f_ID, v_name are
references to "computes"_compute.html, "fixes"_fix.html, and
equal-style "variables"_variable.html that have been defined
elsewhere in the input script or can even be new styles which users
have added to LAMMPS (see the "Section 10"_Section_modify.html
section of the documentation). Thus the {custom} style provides a
flexible means of outputting essentially any desired quantity as a
simulation proceeds.
All styles except {custom} have {vol} appended to their list of
outputs if the simulation box volume changes during the simulation.
The values printed by the various keywords are instantaneous values,
calculated on the current timestep. Time-averaged quantities, which
include values from previous timesteps, can be output by using the
f_ID keyword and accessing a fix that does time-averaging such as the
"fix ave/time"_fix_ave_time.html command.
Options invoked by the "thermo_modify"_thermo_modify.html command can
be used to set the one- or multi-line format of the print-out, the
normalization of thermodynamic output (total values versus per-atom
values for extensive quantities (ones which scale with the number of
atoms in the system), and the numeric precision of each printed value.
NOTE: When you use a "thermo_style" command, all thermodynamic
settings are restored to their default values, including those
previously set by a "thermo_modify"_thermo_modify.html command. Thus
if your input script specifies a thermo_style command, you should use
the thermo_modify command after it.
:line
Several of the thermodynamic quantities require a temperature to be
computed: "temp", "press", "ke", "etotal", "enthalpy", "pxx", etc. By
default this is done by using a {temperature} compute which is created
when LAMMPS starts up, as if this command had been issued:
compute thermo_temp all temp :pre
See the "compute temp"_compute_temp.html command for details. Note
that the ID of this compute is {thermo_temp} and the group is {all}.
You can change the attributes of this temperature (e.g. its
degrees-of-freedom) via the "compute_modify"_compute_modify.html
command. Alternatively, you can directly assign a new compute (that
calculates temperature) which you have defined, to be used for
calculating any thermodynamic quantity that requires a temperature.
This is done via the "thermo_modify"_thermo_modify.html command.
Several of the thermodynamic quantities require a pressure to be
computed: "press", "enthalpy", "pxx", etc. By default this is done by
using a {pressure} compute which is created when LAMMPS starts up, as
if this command had been issued:
compute thermo_press all pressure thermo_temp :pre
See the "compute pressure"_compute_pressure.html command for details.
Note that the ID of this compute is {thermo_press} and the group is
{all}. You can change the attributes of this pressure via the
"compute_modify"_compute_modify.html command. Alternatively, you can
directly assign a new compute (that calculates pressure) which you
have defined, to be used for calculating any thermodynamic quantity
that requires a pressure. This is done via the
"thermo_modify"_thermo_modify.html command.
Several of the thermodynamic quantities require a potential energy to
be computed: "pe", "etotal", "ebond", etc. This is done by using a
{pe} compute which is created when LAMMPS starts up, as if this
command had been issued:
compute thermo_pe all pe :pre
See the "compute pe"_compute_pe.html command for details. Note that
the ID of this compute is {thermo_pe} and the group is {all}. You can
change the attributes of this potential energy via the
"compute_modify"_compute_modify.html command.
:line
The kinetic energy of the system {ke} is inferred from the temperature
of the system with 1/2 Kb T of energy for each degree of freedom.
Thus, using different "compute commands"_compute.html for calculating
temperature, via the "thermo_modify temp"_thermo_modify.html command,
may yield different kinetic energies, since different computes that
calculate temperature can subtract out different non-thermal
components of velocity and/or include different degrees of freedom
(translational, rotational, etc).
The potential energy of the system {pe} will include contributions
from fixes if the "fix_modify thermo"_fix_modify.html option is set
for a fix that calculates such a contribution. For example, the "fix
wall/lj93"_fix_wall.html fix calculates the energy of atoms
interacting with the wall. See the doc pages for "individual fixes"
to see which ones contribute.
A long-range tail correction {etail} for the VanderWaal pairwise
energy will be non-zero only if the "pair_modify
tail"_pair_modify.html option is turned on. The {etail} contribution
is included in {evdwl}, {epair}, {pe}, and {etotal}, and the
corresponding tail correction to the pressure is included in {press}
and {pxx}, {pyy}, etc.
:line
The {step}, {elapsed}, and {elaplong} keywords refer to timestep
count. {Step} is the current timestep, or iteration count when a
"minimization"_minimize.html is being performed. {Elapsed} is the
number of timesteps elapsed since the beginning of this run.
{Elaplong} is the number of timesteps elapsed since the beginning of
an initial run in a series of runs. See the {start} and {stop}
keywords for the "run"_run.html for info on how to invoke a series of
runs that keep track of an initial starting time. If these keywords
are not used, then {elapsed} and {elaplong} are the same value.
The {dt} keyword is the current timestep size in time
"units"_units.html. The {time} keyword is the current elapsed
simulation time, also in time "units"_units.html, which is simply
(step*dt) if the timestep size has not changed and the timestep has
not been reset. If the timestep has changed (e.g. via "fix
dt/reset"_fix_dt_reset.html) or the timestep has been reset (e.g. via
the "reset_timestep" command), then the simulation time is effectively
a cumulative value up to the current point.
The {cpu} keyword is elapsed CPU seconds since the beginning of this
run. The {tpcpu} and {spcpu} keywords are measures of how fast your
simulation is currently running. The {tpcpu} keyword is simulation
time per CPU second, where simulation time is in time
"units"_units.html. E.g. for metal units, the {tpcpu} value would be
picoseconds per CPU second. The {spcpu} keyword is the number of
timesteps per CPU second. Both quantities are on-the-fly metrics,
measured relative to the last time they were invoked. Thus if you are
printing out thermodynamic output every 100 timesteps, the two keywords
will continually output the time and timestep rate for the last 100
steps. The {tpcpu} keyword does not attempt to track any changes in
timestep size, e.g. due to using the "fix dt/reset"_fix_dt_reset.html
command.
The {cpuremain} keyword estimates the CPU time remaining in the
current run, based on the time elapsed thus far. It will only be a
good estimate if the CPU time/timestep for the rest of the run is
similar to the preceding timesteps. On the initial timestep the value
will be 0.0 since there is no history to estimate from. For a
minimization run performed by the "minimize" command, the estimate is
based on the {maxiter} parameter, assuming the minimization will
proceed for the maximum number of allowed iterations.
The {part} keyword is useful for multi-replica or multi-partition
simulations to indicate which partition this output and this file
corresponds to, or for use in a "variable"_variable.html to append to
a filename for output specific to this partition. See "Section
-2.7"_Section_start.html#start_7 of the manual for details on running
+2.6"_Section_start.html#start_6 of the manual for details on running
in multi-partition mode.
The {timeremain} keyword returns the remaining seconds when a
timeout has been configured via the "timer timeout"_timer.html command.
If the timeout timer is inactive, the value of this keyword is 0.0 and
if the timer is expired, it is negative. This allows for example to exit
loops cleanly, if the timeout is expired with:
if "$(timeremain) < 0.0" then "quit 0" :pre
The {fmax} and {fnorm} keywords are useful for monitoring the progress
of an "energy minimization"_minimize.html. The {fmax} keyword
calculates the maximum force in any dimension on any atom in the
system, or the infinity-norm of the force vector for the system. The
{fnorm} keyword calculates the 2-norm or length of the force vector.
The {nbuild} and {ndanger} keywords are useful for monitoring neighbor
list builds during a run. Note that both these values are also
printed with the end-of-run statistics. The {nbuild} keyword is the
number of re-builds during the current run. The {ndanger} keyword is
the number of re-builds that LAMMPS considered potentially
"dangerous". If atom movement triggered neighbor list rebuilding (see
the "neigh_modify"_neigh_modify.html command), then dangerous
reneighborings are those that were triggered on the first timestep
atom movement was checked for. If this count is non-zero you may wish
to reduce the delay factor to insure no force interactions are missed
by atoms moving beyond the neighbor skin distance before a rebuild
takes place.
The keywords {cella}, {cellb}, {cellc}, {cellalpha}, {cellbeta},
{cellgamma}, correspond to the usual crystallographic quantities that
define the periodic unit cell of a crystal. See "this
section"_Section_howto.html#howto_12 of the doc pages for a geometric
description of triclinic periodic cells, including a precise definition
of these quantities in terms of the internal LAMMPS cell dimensions
{lx}, {ly}, {lz}, {yz}, {xz}, {xy}.
:line
For output values from a compute or fix, the bracketed index I used to
index a vector, as in {c_ID\[I\]} or {f_ID\[I\]}, can be specified
using a wildcard asterisk with the index to effectively specify
multiple values. This takes the form "*" or "*n" or "n*" or "m*n".
If N = the size of the vector (for {mode} = scalar) or the number of
columns in the array (for {mode} = vector), then an asterisk with no
numeric values means all indices from 1 to N. A leading asterisk
means all indices from 1 to n (inclusive). A trailing asterisk means
all indices from n to N (inclusive). A middle asterisk means all
indices from m to n (inclusive).
Using a wildcard is the same as if the individual elements of the
vector had been listed one by one. E.g. these 2 thermo_style commands
are equivalent, since the "compute temp"_compute_temp.html command
creates a global vector with 6 values.
compute myTemp all temp
thermo_style custom step temp etotal c_myTemp\[*\]
thermo_style custom step temp etotal &
c_myTemp\[1\] c_myTemp\[2\] c_myTemp\[3\] &
c_myTemp\[4\] c_myTemp\[5\] c_myTemp\[6\] :pre
:line
The {c_ID} and {c_ID\[I\]} and {c_ID\[I\]\[J\]} keywords allow global
values calculated by a compute to be output. As discussed on the
"compute"_compute.html doc page, computes can calculate global,
per-atom, or local values. Only global values can be referenced by
this command. However, per-atom compute values for an individual atom
can be referenced in a "variable"_variable.html and the variable
referenced by thermo_style custom, as discussed below. See the
discussion above for how the I in {c_ID\[I\]} can be specified with a
wildcard asterisk to effectively specify multiple values from a global
compute vector.
The ID in the keyword should be replaced by the actual ID of a compute
that has been defined elsewhere in the input script. See the
"compute"_compute.html command for details. If the compute calculates
a global scalar, vector, or array, then the keyword formats with 0, 1,
or 2 brackets will reference a scalar value from the compute.
Note that some computes calculate "intensive" global quantities like
temperature; others calculate "extensive" global quantities like
kinetic energy that are summed over all atoms in the compute group.
Intensive quantities are printed directly without normalization by
thermo_style custom. Extensive quantities may be normalized by the
total number of atoms in the simulation (NOT the number of atoms in
the compute group) when output, depending on the "thermo_modify
norm"_thermo_modify.html option being used.
The {f_ID} and {f_ID\[I\]} and {f_ID\[I\]\[J\]} keywords allow global
values calculated by a fix to be output. As discussed on the
"fix"_fix.html doc page, fixes can calculate global, per-atom, or
local values. Only global values can be referenced by this command.
However, per-atom fix values can be referenced for an individual atom
in a "variable"_variable.html and the variable referenced by
thermo_style custom, as discussed below. See the discussion above for
how the I in {f_ID\[I\]} can be specified with a wildcard asterisk to
effectively specify multiple values from a global fix vector.
The ID in the keyword should be replaced by the actual ID of a fix
that has been defined elsewhere in the input script. See the
"fix"_fix.html command for details. If the fix calculates a global
scalar, vector, or array, then the keyword formats with 0, 1, or 2
brackets will reference a scalar value from the fix.
Note that some fixes calculate "intensive" global quantities like
timestep size; others calculate "extensive" global quantities like
energy that are summed over all atoms in the fix group. Intensive
quantities are printed directly without normalization by thermo_style
custom. Extensive quantities may be normalized by the total number of
atoms in the simulation (NOT the number of atoms in the fix group)
when output, depending on the "thermo_modify norm"_thermo_modify.html
option being used.
The {v_name} keyword allow the current value of a variable to be
output. The name in the keyword should be replaced by the variable
name that has been defined elsewhere in the input script. Only
equal-style and vector-style variables can be referenced; the latter
requires a bracketed term to specify the Ith element of the vector
calculated by the variable. However, an atom-style variable can be
referenced for an individual atom by an equal-style variable and that
variable referenced. See the "variable"_variable.html command for
details. Variables of style {equal} and {vector} and {atom} define a
formula which can reference per-atom properties or thermodynamic
keywords, or they can invoke other computes, fixes, or variables when
evaluated, so this is a very general means of creating thermodynamic
output.
Note that equal-style and vector-style variables are assumed to
produce "intensive" global quantities, which are thus printed as-is,
without normalization by thermo_style custom. You can include a
division by "natoms" in the variable formula if this is not the case.
:line
[Restrictions:]
This command must come after the simulation box is defined by a
"read_data"_read_data.html, "read_restart"_read_restart.html, or
"create_box"_create_box.html command.
[Related commands:]
"thermo"_thermo.html, "thermo_modify"_thermo_modify.html,
"fix_modify"_fix_modify.html, "compute temp"_compute_temp.html,
"compute pressure"_compute_pressure.html
[Default:]
thermo_style one :pre
diff --git a/doc/src/timer.txt b/doc/src/timer.txt
index 39a6c542b..768c3e135 100644
--- a/doc/src/timer.txt
+++ b/doc/src/timer.txt
@@ -1,121 +1,121 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
timer command :h3
[Syntax:]
timer args :pre
{args} = one or more of {off} or {loop} or {normal} or {full} or {sync} or {nosync} or {timeout} or {every} :l
{off} = do not collect or print any timing information
{loop} = collect only the total time for the simulation loop
{normal} = collect timer information broken down by sections (default)
{full} = like {normal} but also include CPU and thread utilization
{sync} = explicitly synchronize MPI tasks between sections
{nosync} = do not synchronize MPI tasks between sections (default)
{timeout} elapse = set walltime limit to {elapse}
{every} Ncheck = perform timeout check every {Ncheck} steps :pre
[Examples:]
timer full sync
timer timeout 2:00:00 every 100
timer loop :pre
[Description:]
Select the level of detail at which LAMMPS performs its CPU timings.
Multiple keywords can be specified with the {timer} command. For
keywords that are mutually exclusive, the last one specified takes
precedence.
During a simulation run LAMMPS collects information about how much
time is spent in different sections of the code and thus can provide
information for determining performance and load imbalance problems.
This can be done at different levels of detail and accuracy. For more
information about the timing output, see this "discussion of screen
-output in Section 2.8"_Section_start.html#start_8.
+output in Section 2.7"_Section_start.html#start_7.
The {off} setting will turn all time measurements off. The {loop}
setting will only measure the total time for a run and not collect any
detailed per section information. With the {normal} setting, timing
information for portions of the timestep (pairwise calculations,
neighbor list construction, output, etc) are collected as well as
information about load imbalances for those sections across
processors. The {full} setting adds information about CPU
utilization and thread utilization, when multi-threading is enabled.
With the {sync} setting, all MPI tasks are synchronized at each timer
call which measures load imbalance for each section more accurately,
though it can also slow down the simulation by prohibiting overlapping
independent computations on different MPI ranks Using the {nosync}
setting (which is the default) turns this synchronization off.
With the {timeout} keyword a walltime limit can be imposed, that
affects the "run"_run.html and "minimize"_minimize.html commands.
This can be convenient when calculations have to comply with execution
time limits, e.g. when running under a batch system when you want to
maximize the utilization of the batch time slot, especially for runs
where the time per timestep varies much and thus it becomes difficult
to predict how many steps a simulation can perform for a given walltime
limit. This also applies for difficult to converge minimizations.
The timeout {elapse} value should be somewhat smaller than the maximum
wall time requested from the batch system, as there is usually
some overhead to launch jobs, and it is advisable to write
out a restart after terminating a run due to a timeout.
The timeout timer starts when the command is issued. When the time
limit is reached, the run or energy minimization will exit on the
next step or iteration that is a multiple of the {Ncheck} value
which can be set with the {every} keyword. Default is checking
every 10 steps. After the timer timeout has expired all subsequent
run or minimize commands in the input script will be skipped.
The remaining time or timer status can be accessed with the
"thermo"_thermo_style.html variable {timeremain}, which will be
zero, if the timeout is inactive (default setting), it will be
negative, if the timeout time is expired and positive if there
is time remaining and in this case the value of the variable are
the number of seconds remaining.
When the {timeout} key word is used a second time, the timer is
restarted with a new time limit. The timeout {elapse} value can
be specified as {off} or {unlimited} to impose a no timeout condition
(which is the default). The {elapse} setting can be specified as
a single number for seconds, two numbers separated by a colon (MM:SS)
for minutes and seconds, or as three numbers separated by colons for
hours, minutes, and seconds (H:MM:SS).
The {every} keyword sets how frequently during a run or energy
minimization the wall clock will be checked. This check count applies
to the outer iterations or time steps during minimizations or "r-RESPA
runs"_run_style.html, respectively. Checking for timeout too often,
can slow a calculation down. Checking too infrequently can make the
timeout measurement less accurate, with the run being stopped later
than desired.
NOTE: Using the {full} and {sync} options provides the most detailed
and accurate timing information, but can also have a negative
performance impact due to the overhead of the many required system
calls. It is thus recommended to use these settings only when testing
tests to identify performance bottlenecks. For calculations with few
atoms or a very large number of processors, even the {normal} setting
can have a measurable negative performance impact. In those cases you
can just use the {loop} or {off} setting.
[Restrictions:] none
[Related commands:]
"run post no"_run.html, "kspace_modify fftbench"_kspace_modify.html
[Default:]
timer normal nosync
timer timeout off
timer every 10 :pre
diff --git a/doc/src/variable.txt b/doc/src/variable.txt
index e32e82ef4..e3b7c5de0 100644
--- a/doc/src/variable.txt
+++ b/doc/src/variable.txt
@@ -1,1325 +1,1325 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
variable command :h3
[Syntax:]
variable name style args ... :pre
name = name of variable to define :ulb,l
style = {delete} or {index} or {loop} or {world} or {universe} or {uloop} or {string} or {format} or {getenv} or {file} or {atomfile} or {python} or {internal} or {equal} or {vector} or {atom} :l
{delete} = no args
{index} args = one or more strings
{loop} args = N
N = integer size of loop, loop from 1 to N inclusive
{loop} args = N pad
N = integer size of loop, loop from 1 to N inclusive
pad = all values will be same length, e.g. 001, 002, ..., 100
{loop} args = N1 N2
N1,N2 = loop from N1 to N2 inclusive
{loop} args = N1 N2 pad
N1,N2 = loop from N1 to N2 inclusive
pad = all values will be same length, e.g. 050, 051, ..., 100
{world} args = one string for each partition of processors
{universe} args = one or more strings
{uloop} args = N
N = integer size of loop
{uloop} args = N pad
N = integer size of loop
pad = all values will be same length, e.g. 001, 002, ..., 100
{string} arg = one string
{format} args = vname fstr
vname = name of equal-style variable to evaluate
fstr = C-style format string
{getenv} arg = one string
{file} arg = filename
{atomfile} arg = filename
{python} arg = function
{internal} arg = numeric value
{equal} or {vector} or {atom} args = one formula containing numbers, thermo keywords, math operations, group functions, atom values and vectors, compute/fix/variable references
numbers = 0.0, 100, -5.4, 2.8e-4, etc
constants = PI, version, on, off, true, false, yes, no
thermo keywords = vol, ke, press, etc from "thermo_style"_thermo_style.html
math operators = (), -x, x+y, x-y, x*y, x/y, x^y, x%y,
x == y, x != y, x < y, x <= y, x > y, x >= y, x && y, x || y, x |^ y, !x
math functions = sqrt(x), exp(x), ln(x), log(x), abs(x),
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x),
random(x,y,z), normal(x,y,z), ceil(x), floor(x), round(x)
ramp(x,y), stagger(x,y), logfreq(x,y,z), logfreq2(x,y,z),
stride(x,y,z), stride2(x,y,z,a,b,c),
vdisplace(x,y), swiggle(x,y,z), cwiggle(x,y,z)
group functions = count(group), mass(group), charge(group),
xcm(group,dim), vcm(group,dim), fcm(group,dim),
bound(group,dir), gyration(group), ke(group),
angmom(group,dim), torque(group,dim),
inertia(group,dimdim), omega(group,dim)
region functions = count(group,region), mass(group,region), charge(group,region),
xcm(group,dim,region), vcm(group,dim,region), fcm(group,dim,region),
bound(group,dir,region), gyration(group,region), ke(group,reigon),
angmom(group,dim,region), torque(group,dim,region),
inertia(group,dimdim,region), omega(group,dim,region)
special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), gmask(x), rmask(x), grmask(x,y), next(x)
feature functions = is_active(category,feature,exact), is_defined(category,id,exact)
atom value = id\[i\], mass\[i\], type\[i\], mol\[i\], x\[i\], y\[i\], z\[i\], vx\[i\], vy\[i\], vz\[i\], fx\[i\], fy\[i\], fz\[i\], q\[i\]
atom vector = id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q
compute references = c_ID, c_ID\[i\], c_ID\[i\]\[j\], C_ID, C_ID\[i\]
fix references = f_ID, f_ID\[i\], f_ID\[i\]\[j\], F_ID, F_ID\[i\]
variable references = v_name, v_name\[i\] :pre
:ule
[Examples:]
variable x index run1 run2 run3 run4 run5 run6 run7 run8
variable LoopVar loop $n
variable beta equal temp/3.0
variable b1 equal x\[234\]+0.5*vol
variable b1 equal "x\[234\] + 0.5*vol"
variable b equal xcm(mol1,x)/2.0
variable b equal c_myTemp
variable b atom x*y/vol
variable foo string myfile
variable foo internal 3.5
variable myPy python increase
variable f file values.txt
variable temp world 300.0 310.0 320.0 $\{Tfinal\}
variable x universe 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
variable x uloop 15 pad
variable str format x %.6g
variable x delete :pre
[Description:]
This command assigns one or more strings to a variable name for
evaluation later in the input script or during a simulation.
Variables can thus be useful in several contexts. A variable can be
defined and then referenced elsewhere in an input script to become
part of a new input command. For variable styles that store multiple
strings, the "next"_next.html command can be used to increment which
string is assigned to the variable. Variables of style {equal} store
a formula which when evaluated produces a single numeric value which
can be output either directly (see the "print"_print.html, "fix
print"_fix_print.html, and "run every"_run.html commands) or as part
of thermodynamic output (see the "thermo_style"_thermo_style.html
command), or used as input to an averaging fix (see the "fix
ave/time"_fix_ave_time.html command). Variables of style {vector}
store a formula which produces a vector of such values which can be
used as input to various averaging fixes, or elements of which can be
part of thermodynamic output. Variables of style {atom} store a
formula which when evaluated produces one numeric value per atom which
can be output to a dump file (see the "dump custom"_dump.html command)
or used as input to an averaging fix (see the "fix
ave/chunk"_fix_ave_chunk.html and "fix ave/atom"_fix_ave_atom.html
commands). Variables of style {atomfile} can be used anywhere in an
input script that atom-style variables are used; they get their
per-atom values from a file rather than from a formula. Variables of
style {python} can be hooked to Python functions using code you
provide, so that the variable gets its value from the evaluation of
the Python code. Variables of style {internal} are used by a few
commands which set their value directly.
NOTE: As discussed in "Section 3.2"_Section_commands.html#cmd_2 of the
manual, an input script can use "immediate" variables, specified as
$(formula) with parenthesis, where the formula has the same syntax as
equal-style variables described on this page. This is a convenient
way to evaluate a formula immediately without using the variable
command to define a named variable and then evaluate that
variable. See below for a more detailed discussion of this feature.
In the discussion that follows, the "name" of the variable is the
arbitrary string that is the 1st argument in the variable command.
This name can only contain alphanumeric characters and underscores.
The "string" is one or more of the subsequent arguments. The "string"
can be simple text as in the 1st example above, it can contain other
variables as in the 2nd example, or it can be a formula as in the 3rd
example. The "value" is the numeric quantity resulting from
evaluation of the string. Note that the same string can generate
different values when it is evaluated at different times during a
simulation.
NOTE: When an input script line is encountered that defines a variable
of style {equal} or {vector} or {atom} or {python} that contains a
formula or Python code, the formula is NOT immediately evaluated. It
will be evaluated every time when the variable is [used] instead. If
you simply want to evaluate a formula in place you can use as
so-called. See the section below about "Immediate Evaluation of
Variables" for more details on the topic. This is also true of a
{format} style variable since it evaluates another variable when it is
invoked.
Variables of style {equal} and {vector} and {atom} can be used as
inputs to various other commands which evaluate their formulas as
needed, e.g. at different timesteps during a "run"_run.html.
Variables of style {internal} can be used in place of an equal-style
variable, except by commands that set the value stored by the
internal-style variable. Thus any command that states it can use an
equal-style variable as an argument, can also use an internal-style
variable. This means that when the command evaluates the variable, it
will use the value set (internally) by another command.
Variables of style {python} can be used in place of an equal-style
variable so long as the associated Python function, as defined by the
"python"_python.html command, returns a numeric value. Thus any
command that states it can use an equal-style variable as an argument,
can also use such a python-style variable. This means that when the
LAMMPS command evaluates the variable, the Python function will be
executed.
NOTE: When a variable command is encountered in the input script and
the variable name has already been specified, the command is ignored.
This means variables can NOT be re-defined in an input script (with
two exceptions, read further). This is to allow an input script to be
processed multiple times without resetting the variables; see the
"jump"_jump.html or "include"_include.html commands. It also means
-that using the "command-line switch"_Section_start.html#start_7 -var
+that using the "command-line switch"_Section_start.html#start_6 -var
will override a corresponding index variable setting in the input
script.
There are two exceptions to this rule. First, variables of style
{string}, {getenv}, {internal}, {equal}, {vector}, {atom}, and
{python} ARE redefined each time the command is encountered. This
allows these style of variables to be redefined multiple times in an
input script. In a loop, this means the formula associated with an
{equal} or {atom} style variable can change if it contains a
substitution for another variable, e.g. $x or v_x.
Second, as described below, if a variable is iterated on to the end of
its list of strings via the "next"_next.html command, it is removed
from the list of active variables, and is thus available to be
re-defined in a subsequent variable command. The {delete} style does
the same thing.
:line
"This section"_Section_commands.html#cmd_2 of the manual explains how
occurrences of a variable name in an input script line are replaced by
the variable's string. The variable name can be referenced as $x if
the name "x" is a single character, or as $\{LoopVar\} if the name
"LoopVar" is one or more characters.
As described below, for variable styles {index}, {loop}, {file},
{universe}, and {uloop}, which string is assigned to a variable can be
incremented via the "next"_next.html command. When there are no more
strings to assign, the variable is exhausted and a flag is set that
causes the next "jump"_jump.html command encountered in the input
script to be skipped. This enables the construction of simple loops
in the input script that are iterated over and then exited from.
As explained above, an exhausted variable can be re-used in an input
script. The {delete} style also removes the variable, the same as if
it were exhausted, allowing it to be redefined later in the input
script or when the input script is looped over. This can be useful
when breaking out of a loop via the "if"_if.html and "jump"_jump.html
commands before the variable would become exhausted. For example,
label loop
variable a loop 5
print "A = $a"
if "$a > 2" then "jump in.script break"
next a
jump in.script loop
label break
variable a delete :pre
:line
This section describes how all the various variable styles are defined
and what they store. Except for the {equal} and {vector} and {atom}
styles, which are explained in the next section.
Many of the styles store one or more strings. Note that a single
string can contain spaces (multiple words), if it is enclosed in
quotes in the variable command. When the variable is substituted for
in another input script command, its returned string will then be
interpreted as multiple arguments in the expanded command.
For the {index} style, one or more strings are specified. Initially,
the 1st string is assigned to the variable. Each time a
"next"_next.html command is used with the variable name, the next
string is assigned. All processors assign the same string to the
variable.
{Index} style variables with a single string value can also be set by
using the command-line switch -var; see "this
-section"_Section_start.html#start_7 for details.
+section"_Section_start.html#start_6 for details.
The {loop} style is identical to the {index} style except that the
strings are the integers from 1 to N inclusive, if only one argument N
is specified. This allows generation of a long list of runs
(e.g. 1000) without having to list N strings in the input script.
Initially, the string "1" is assigned to the variable. Each time a
"next"_next.html command is used with the variable name, the next
string ("2", "3", etc) is assigned. All processors assign the same
string to the variable. The {loop} style can also be specified with
two arguments N1 and N2. In this case the loop runs from N1 to N2
inclusive, and the string N1 is initially assigned to the variable.
N1 <= N2 and N2 >= 0 is required.
For the {world} style, one or more strings are specified. There must
be one string for each processor partition or "world". See "this
-section"_Section_start.html#start_7 of the manual for information on
+section"_Section_start.html#start_6 of the manual for information on
running LAMMPS with multiple partitions via the "-partition"
command-line switch. This variable command assigns one string to each
world. All processors in the world are assigned the same string. The
next command cannot be used with {equal} style variables, since there
is only one value per world. This style of variable is useful when
you wish to run different simulations on different partitions, or when
performing a parallel tempering simulation (see the
"temper"_temper.html command), to assign different temperatures to
different partitions.
For the {universe} style, one or more strings are specified. There
must be at least as many strings as there are processor partitions or
-"worlds". See "this page"_Section_start.html#start_7 for information
+"worlds". See "this page"_Section_start.html#start_6 for information
on running LAMMPS with multiple partitions via the "-partition"
command-line switch. This variable command initially assigns one
string to each world. When a "next"_next.html command is encountered
using this variable, the first processor partition to encounter it, is
assigned the next available string. This continues until all the
variable strings are consumed. Thus, this command can be used to run
50 simulations on 8 processor partitions. The simulations will be run
one after the other on whatever partition becomes available, until
they are all finished. {Universe} style variables are incremented
using the files "tmp.lammps.variable" and "tmp.lammps.variable.lock"
which you will see in your directory during such a LAMMPS run.
The {uloop} style is identical to the {universe} style except that the
strings are the integers from 1 to N. This allows generation of long
list of runs (e.g. 1000) without having to list N strings in the input
script.
For the {string} style, a single string is assigned to the variable.
The only difference between this and using the {index} style with a
single string is that a variable with {string} style can be redefined.
E.g. by another command later in the input script, or if the script is
read again in a loop.
For the {format} style, an equal-style variable is specified along
with a C-style format string, e.g. "%f" or "%.10g", which must be
appropriate for formatting a double-precision floating-point value.
This allows an equal-style variable to be formatted specifically for
output as a string, e.g. by the "print"_print.html command, if the
default format "%.15g" has too much precision.
For the {getenv} style, a single string is assigned to the variable
which should be the name of an environment variable. When the
variable is evaluated, it returns the value of the environment
variable, or an empty string if it not defined. This style of
variable can be used to adapt the behavior of LAMMPS input scripts via
environment variable settings, or to retrieve information that has
been previously stored with the "shell putenv"_shell.html command.
Note that because environment variable settings are stored by the
operating systems, they persist beyond a "clear"_clear.html command.
For the {file} style, a filename is provided which contains a list of
strings to assign to the variable, one per line. The strings can be
numeric values if desired. See the discussion of the next() function
below for equal-style variables, which will convert the string of a
file-style variable into a numeric value in a formula.
When a file-style variable is defined, the file is opened and the
string on the first line is read and stored with the variable. This
means the variable can then be evaluated as many times as desired and
will return that string. There are two ways to cause the next string
from the file to be read: use the "next"_next.html command or the
next() function in an equal- or atom-style variable, as discussed
below.
The rules for formatting the file are as follows. A comment character
"#" can be used anywhere on a line; text starting with the comment
character is stripped. Blank lines are skipped. The first "word" of
a non-blank line, delimited by white space, is the "string" assigned
to the variable.
For the {atomfile} style, a filename is provided which contains one or
more sets of values, to assign on a per-atom basis to the variable.
The format of the file is described below.
When an atomfile-style variable is defined, the file is opened and the
first set of per-atom values are read and stored with the variable.
This means the variable can then be evaluated as many times as desired
and will return those values. There are two ways to cause the next
set of per-atom values from the file to be read: use the
"next"_next.html command or the next() function in an atom-style
variable, as discussed below.
The rules for formatting the file are as follows. Each time a set of
per-atom values is read, a non-blank line is searched for in the file.
A comment character "#" can be used anywhere on a line; text starting
with the comment character is stripped. Blank lines are skipped. The
first "word" of a non-blank line, delimited by white space, is read as
the count N of per-atom lines to immediately follow. N can be be the
total number of atoms in the system, or only a subset. The next N
lines have the following format
ID value :pre
where ID is an atom ID and value is the per-atom numeric value that
will be assigned to that atom. IDs can be listed in any order.
NOTE: Every time a set of per-atom lines is read, the value for all
atoms is first set to 0.0. Thus values for atoms whose ID does not
appear in the set, will remain 0.0.
For the {python} style a Python function name is provided. This needs
to match a function name specified in a "python"_python.html command
which returns a value to this variable as defined by its {return}
keyword. For example these two commands would be self-consistent:
variable foo python myMultiply
python myMultiply return v_foo format f file funcs.py :pre
The two commands can appear in either order so long as both are
specified before the Python function is invoked for the first time.
Each time the variable is evaluated, the associated Python function is
invoked, and the value it returns is also returned by the variable.
Since the Python function can use other LAMMPS variables as input, or
query interal LAMMPS quantities to perform its computation, this means
the variable can return a different value each time it is evaluated.
The type of value stored in the variable is determined by the {format}
keyword of the "python"_python.html command. It can be an integer
(i), floating point (f), or string (s) value. As mentioned above, if
it is a numeric value (integer or floating point), then the
python-style variable can be used in place of an equal-style variable
anywhere in an input script, e.g. as an argument to another command
that allows for equal-style variables.
For the {internal} style a numeric value is provided. This value will
be assigned to the variable until a LAMMPS command sets it to a new
value. There are currently only two LAMMPS commands that require
{internal} variables as inputs, because they reset them:
"create_atoms"_create_atoms.html and "fix
controller"_fix_controller.html. As mentioned above, an
internal-style variable can be used in place of an equal-style
variable anywhere else in an input script, e.g. as an argument to
another command that allows for equal-style variables.
:line
For the {equal} and {vector} and {atom} styles, a single string is
specified which represents a formula that will be evaluated afresh
each time the variable is used. If you want spaces in the string,
enclose it in double quotes so the parser will treat it as a single
argument. For {equal}-style variables the formula computes a scalar
quantity, which becomes the value of the variable whenever it is
evaluated. For {vector}-style variables the formula must compute a
vector of quantities, which becomes the value of the variable whenever
it is evaluated. The calculated vector can be on length one, but it
cannot be a simple scalar value like that produced by an equal-style
compute. I.e. the formula for a vector-style variable must have at
least one quantity in it that refers to a global vector produced by a
compute, fix, or other vector-style variable. For {atom}-style
variables the formula computes one quantity for each atom whenever it
is evaluated.
Note that {equal}, {vector}, and {atom} variables can produce
different values at different stages of the input script or at
different times during a run. For example, if an {equal} variable is
used in a "fix print"_fix_print.html command, different values could
be printed each timestep it was invoked. If you want a variable to be
evaluated immediately, so that the result is stored by the variable
instead of the string, see the section below on "Immediate Evaluation
of Variables".
The next command cannot be used with {equal} or {vector} or {atom}
style variables, since there is only one string.
The formula for an {equal}, {vector}, or {atom} variable can contain a
variety of quantities. The syntax for each kind of quantity is
simple, but multiple quantities can be nested and combined in various
ways to build up formulas of arbitrary complexity. For example, this
is a valid (though strange) variable formula:
variable x equal "pe + c_MyTemp / vol^(1/3)" :pre
Specifically, a formula can contain numbers, constants, thermo
keywords, math operators, math functions, group functions, region
functions, atom values, atom vectors, compute references, fix
references, and references to other variables.
Number: 0.2, 100, 1.0e20, -15.4, etc
Constant: PI, version, on, off, true, false, yes, no
Thermo keywords: vol, pe, ebond, etc
Math operators: (), -x, x+y, x-y, x*y, x/y, x^y, x%y, \
x == y, x != y, x < y, x <= y, x > y, x >= y, x && y, x || y, x |^ y, !x
Math functions: sqrt(x), exp(x), ln(x), log(x), abs(x), \
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x), \
random(x,y,z), normal(x,y,z), ceil(x), floor(x), round(x), \
ramp(x,y), stagger(x,y), logfreq(x,y,z), logfreq2(x,y,z), \
stride(x,y,z), stride2(x,y,z,a,b,c), vdisplace(x,y), \
swiggle(x,y,z), cwiggle(x,y,z)
Group functions: count(ID), mass(ID), charge(ID), xcm(ID,dim), \
vcm(ID,dim), fcm(ID,dim), bound(ID,dir), \
gyration(ID), ke(ID), angmom(ID,dim), torque(ID,dim), \
inertia(ID,dimdim), omega(ID,dim)
Region functions: count(ID,IDR), mass(ID,IDR), charge(ID,IDR), \
xcm(ID,dim,IDR), vcm(ID,dim,IDR), fcm(ID,dim,IDR), \
bound(ID,dir,IDR), gyration(ID,IDR), ke(ID,IDR), \
angmom(ID,dim,IDR), torque(ID,dim,IDR), \
inertia(ID,dimdim,IDR), omega(ID,dim,IDR)
Special functions: sum(x), min(x), max(x), ave(x), trap(x), \
slope(x), gmask(x), rmask(x), grmask(x,y), next(x)
Atom values: id\[i\], mass\[i\], type\[i\], mol\[i\], x\[i\], y\[i\], z\[i\], \
vx\[i\], vy\[i\], vz\[i\], fx\[i\], fy\[i\], fz\[i\], q\[i\]
Atom vectors: id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q
Compute references: c_ID, c_ID\[i\], c_ID\[i\]\[j\], C_ID, C_ID\[i\]
Fix references: f_ID, f_ID\[i\], f_ID\[i\]\[j\], F_ID, F_ID\[i\]
Other variables: v_name, v_name\[i\] :tb(s=:)
Most of the formula elements produce a scalar value. Some produce a
global or per-atom vector of values. Global vectors can be produced
by computes or fixes or by other vector-style variables. Per-atom
vectors are produced by atom vectors, compute references that
represent a per-atom vector, fix references that represent a per-atom
vector, and variables that are atom-style variables. Math functions
that operate on scalar values produce a scalar value; math function
that operate on global or per-atom vectors do so element-by-element
and produce a global or per-atom vector.
A formula for equal-style variables cannot use any formula element
that produces a global or per-atom vector. A formula for a
vector-style variable can use formula elements that produce either a
scalar value or a global vector value, but cannot use a formula
element that produces a per-atom vector. A formula for an atom-style
variable can use formula elements that produce either a scalar value
or a per-atom vector, but not one that produces a global vector.
Atom-style variables are evaluated by other commands that define a
"group"_group.html on which they operate, e.g. a "dump"_dump.html or
"compute"_compute.html or "fix"_fix.html command. When they invoke
the atom-style variable, only atoms in the group are included in the
formula evaluation. The variable evaluates to 0.0 for atoms not in
the group.
:line
Numbers, constants, and thermo keywords :h4
Numbers can contain digits, scientific notation
(3.0e20,3.0e-20,3.0E20,3.0E-20), and leading minus signs.
Constants are set at compile time and cannot be changed. {PI} will
return the number 3.14159265358979323846; {on}, {true} or {yes} will
return 1.0; {off}, {false} or {no} will return 0.0; {version} will
return a numeric version code of the current LAMMPS version (e.g.
version 2 Sep 2015 will return the number 20150902). The corresponding
value for newer versions of LAMMPS will be larger, for older versions
of LAMMPS will be smaller. This can be used to have input scripts
adapt automatically to LAMMPS versions, when non-backwards compatible
syntax changes are introduced. Here is an illustrative example (which
will not work, since the {version} has been introduced more recently):
if $(version<20140513) then "communicate vel yes" else "comm_modify vel yes" :pre
The thermo keywords allowed in a formula are those defined by the
"thermo_style custom"_thermo_style.html command. Thermo keywords that
require a "compute"_compute.html to calculate their values such as
"temp" or "press", use computes stored and invoked by the
"thermo_style"_thermo_style.html command. This means that you can
only use those keywords in a variable if the style you are using with
the thermo_style command (and the thermo keywords associated with that
style) also define and use the needed compute. Note that some thermo
keywords use a compute indirectly to calculate their value (e.g. the
enthalpy keyword uses temp, pe, and pressure). If a variable is
evaluated directly in an input script (not during a run), then the
values accessed by the thermo keyword must be current. See the
discussion below about "Variable Accuracy".
:line
Math Operators :h4
Math operators are written in the usual way, where the "x" and "y" in
the examples can themselves be arbitrarily complex formulas, as in the
examples above. In this syntax, "x" and "y" can be scalar values or
per-atom vectors. For example, "ke/natoms" is the division of two
scalars, where "vy+vz" is the element-by-element sum of two per-atom
vectors of y and z velocities.
Operators are evaluated left to right and have the usual C-style
precedence: unary minus and unary logical NOT operator "!" have the
highest precedence, exponentiation "^" is next; multiplication and
division and the modulo operator "%" are next; addition and
subtraction are next; the 4 relational operators "<", "<=", ">", and
">=" are next; the two remaining relational operators "==" and "!="
are next; then the logical AND operator "&&"; and finally the logical
OR operator "||" and logical XOR (exclusive or) operator "|^" have the
lowest precedence. Parenthesis can be used to group one or more
portions of a formula and/or enforce a different order of evaluation
than what would occur with the default precedence.
NOTE: Because a unary minus is higher precedence than exponentiation,
the formula "-2^2" will evaluate to 4, not -4. This convention is
compatible with some programming languages, but not others. As
mentioned, this behavior can be easily overridden with parenthesis;
the formula "-(2^2)" will evaluate to -4.
The 6 relational operators return either a 1.0 or 0.0 depending on
whether the relationship between x and y is TRUE or FALSE. For
example the expression x<10.0 in an atom-style variable formula will
return 1.0 for all atoms whose x-coordinate is less than 10.0, and 0.0
for the others. The logical AND operator will return 1.0 if both its
arguments are non-zero, else it returns 0.0. The logical OR operator
will return 1.0 if either of its arguments is non-zero, else it
returns 0.0. The logical XOR operator will return 1.0 if one of its
arguments is zero and the other non-zero, else it returns 0.0. The
logical NOT operator returns 1.0 if its argument is 0.0, else it
returns 0.0.
These relational and logical operators can be used as a masking or
selection operation in a formula. For example, the number of atoms
whose properties satisfy one or more criteria could be calculated by
taking the returned per-atom vector of ones and zeroes and passing it
to the "compute reduce"_compute_reduce.html command.
:line
Math Functions :h4
Math functions are specified as keywords followed by one or more
parenthesized arguments "x", "y", "z", each of which can themselves be
arbitrarily complex formulas. In this syntax, the arguments can
represent scalar values or global vectors or per-atom vectors. In the
latter case, the math operation is performed on each element of the
vector. For example, "sqrt(natoms)" is the sqrt() of a scalar, where
"sqrt(y*z)" yields a per-atom vector with each element being the
sqrt() of the product of one atom's y and z coordinates.
Most of the math functions perform obvious operations. The ln() is
the natural log; log() is the base 10 log.
The random(x,y,z) function takes 3 arguments: x = lo, y = hi, and z =
seed. It generates a uniform random number between lo and hi. The
normal(x,y,z) function also takes 3 arguments: x = mu, y = sigma, and
z = seed. It generates a Gaussian variate centered on mu with
variance sigma^2. In both cases the seed is used the first time the
internal random number generator is invoked, to initialize it. For
equal-style and vector-style variables, every processor uses the same
seed so that they each generate the same sequence of random numbers.
For atom-style variables, a unique seed is created for each processor,
based on the specified seed. This effectively generates a different
random number for each atom being looped over in the atom-style
variable.
NOTE: Internally, there is just one random number generator for all
equal-style and vector-style variables and another one for all
atom-style variables. If you define multiple variables (of each
style) which use the random() or normal() math functions, then the
internal random number generators will only be initialized once, which
means only one of the specified seeds will determine the sequence of
generated random numbers.
The ceil(), floor(), and round() functions are those in the C math
library. Ceil() is the smallest integer not less than its argument.
Floor() if the largest integer not greater than its argument. Round()
is the nearest integer to its argument.
The ramp(x,y) function uses the current timestep to generate a value
linearly interpolated between the specified x,y values over the course
of a run, according to this formula:
value = x + (y-x) * (timestep-startstep) / (stopstep-startstep) :pre
The run begins on startstep and ends on stopstep. Startstep and
stopstep can span multiple runs, using the {start} and {stop} keywords
of the "run"_run.html command. See the "run"_run.html command for
details of how to do this.
The stagger(x,y) function uses the current timestep to generate a new
timestep. X,y > 0 and x > y are required. The generated timesteps
increase in a staggered fashion, as the sequence
x,x+y,2x,2x+y,3x,3x+y,etc. For any current timestep, the next
timestep in the sequence is returned. Thus if stagger(1000,100) is
used in a variable by the "dump_modify every"_dump_modify.html
command, it will generate the sequence of output timesteps:
100,1000,1100,2000,2100,3000,etc :pre
The logfreq(x,y,z) function uses the current timestep to generate a
new timestep. X,y,z > 0 and y < z are required. The generated
timesteps are on a base-z logarithmic scale, starting with x, and the
y value is how many of the z-1 possible timesteps within one
logarithmic interval are generated. I.e. the timesteps follow the
sequence x,2x,3x,...y*x,x*z,2x*z,3x*z,...y*x*z,x*z^2,2x*z^2,etc. For
any current timestep, the next timestep in the sequence is returned.
Thus if logfreq(100,4,10) is used in a variable by the "dump_modify
every"_dump_modify.html command, it will generate this sequence of
output timesteps:
100,200,300,400,1000,2000,3000,4000,10000,20000,etc :pre
The logfreq2(x,y,z) function is similar to logfreq, except a single
logarithmic interval is divided into y equally-spaced timesteps and
all of them are output. Y < z is not required. Thus, if
logfreq2(100,18,10) is used in a variable by the "dump_modify
every"_dump_modify.html command, then the interval between 100 and
1000 is divided as 900/18 = 50 steps, and it will generate the
sequence of output timesteps:
100,150,200,...950,1000,1500,2000,...9500,10000,15000,etc :pre
The stride(x,y,z) function uses the current timestep to generate a new
timestep. X,y >= 0 and z > 0 and x <= y are required. The generated
timesteps increase in increments of z, from x to y, i.e. it generates
the sequence x,x+z,x+2z,...,y. If y-x is not a multiple of z, then
similar to the way a for loop operates, the last value will be one
that does not exceed y. For any current timestep, the next timestep
in the sequence is returned. Thus if stride(1000,2000,100) is used
in a variable by the "dump_modify every"_dump_modify.html command, it
will generate the sequence of output timesteps:
1000,1100,1200, ... ,1900,2000 :pre
The stride2(x,y,z,a,b,c) function is similar to the stride() function
except it generates two sets of strided timesteps, one at a coarser
level and one at a finer level. Thus it is useful for debugging,
e.g. to produce output every timestep at the point in simulation when
a problem occurs. X,y >= 0 and z > 0 and x <= y are required, as are
a,b >= 0 and c > 0 and a < b. Also, a >= x and b <= y are required so
that the second stride is inside the first. The generated timesteps
increase in increments of z, starting at x, until a is reached. At
that point the timestep increases in increments of c, from a to b,
then after b, increments by z are resumed until y is reached. For any
current timestep, the next timestep in the sequence is returned. Thus
if stride(1000,2000,100,1350,1360,1) is used in a variable by the
"dump_modify every"_dump_modify.html command, it will generate the
sequence of output timesteps:
1000,1100,1200,1300,1350,1351,1352, ... 1359,1360,1400,1500, ... ,2000 :pre
The vdisplace(x,y) function takes 2 arguments: x = value0 and y =
velocity, and uses the elapsed time to change the value by a linear
displacement due to the applied velocity over the course of a run,
according to this formula:
value = value0 + velocity*(timestep-startstep)*dt :pre
where dt = the timestep size.
The run begins on startstep. Startstep can span multiple runs, using
the {start} keyword of the "run"_run.html command. See the
"run"_run.html command for details of how to do this. Note that the
"thermo_style"_thermo_style.html keyword elaplong =
timestep-startstep.
The swiggle(x,y,z) and cwiggle(x,y,z) functions each take 3 arguments:
x = value0, y = amplitude, z = period. They use the elapsed time to
oscillate the value by a sin() or cos() function over the course of a
run, according to one of these formulas, where omega = 2 PI / period:
value = value0 + Amplitude * sin(omega*(timestep-startstep)*dt)
value = value0 + Amplitude * (1 - cos(omega*(timestep-startstep)*dt)) :pre
where dt = the timestep size.
The run begins on startstep. Startstep can span multiple runs, using
the {start} keyword of the "run"_run.html command. See the
"run"_run.html command for details of how to do this. Note that the
"thermo_style"_thermo_style.html keyword elaplong =
timestep-startstep.
:line
Group and Region Functions :h4
Group functions are specified as keywords followed by one or two
parenthesized arguments. The first argument {ID} is the group-ID.
The {dim} argument, if it exists, is {x} or {y} or {z}. The {dir}
argument, if it exists, is {xmin}, {xmax}, {ymin}, {ymax}, {zmin}, or
{zmax}. The {dimdim} argument, if it exists, is {xx} or {yy} or {zz}
or {xy} or {yz} or {xz}.
The group function count() is the number of atoms in the group. The
group functions mass() and charge() are the total mass and charge of
the group. Xcm() and vcm() return components of the position and
velocity of the center of mass of the group. Fcm() returns a
component of the total force on the group of atoms. Bound() returns
the min/max of a particular coordinate for all atoms in the group.
Gyration() computes the radius-of-gyration of the group of atoms. See
the "compute gyration"_compute_gyration.html command for a definition
of the formula. Angmom() returns components of the angular momentum
of the group of atoms around its center of mass. Torque() returns
components of the torque on the group of atoms around its center of
mass, based on current forces on the atoms. Inertia() returns one of
6 components of the symmetric inertia tensor of the group of atoms
around its center of mass, ordered as Ixx,Iyy,Izz,Ixy,Iyz,Ixz.
Omega() returns components of the angular velocity of the group of
atoms around its center of mass.
Region functions are specified exactly the same way as group functions
except they take an extra final argument {IDR} which is the region ID.
The function is computed for all atoms that are in both the group and
the region. If the group is "all", then the only criteria for atom
inclusion is that it be in the region.
:line
Special Functions :h4
Special functions take specific kinds of arguments, meaning their
arguments cannot be formulas themselves.
The sum(x), min(x), max(x), ave(x), trap(x), and slope(x) functions
each take 1 argument which is of the form "c_ID" or "c_ID\[N\]" or
"f_ID" or "f_ID\[N\]" or "v_name". The first two are computes and the
second two are fixes; the ID in the reference should be replaced by
the ID of a compute or fix defined elsewhere in the input script. The
compute or fix must produce either a global vector or array. If it
produces a global vector, then the notation without "\[N\]" should be
used. If it produces a global array, then the notation with "\[N\]"
should be used, when N is an integer, to specify which column of the
global array is being referenced. The last form of argument "v_name"
is for a vector-style variable where "name" is replaced by the name of
the variable.
These functions operate on a global vector of inputs and reduce it to
a single scalar value. This is analogous to the operation of the
"compute reduce"_compute_reduce.html command, which performs similar
operations on per-atom and local vectors.
The sum() function calculates the sum of all the vector elements. The
min() and max() functions find the minimum and maximum element
respectively. The ave() function is the same as sum() except that it
divides the result by the length of the vector.
The trap() function is the same as sum() except the first and last
elements are multiplied by a weighting factor of 1/2 when performing
the sum. This effectively implements an integration via the
trapezoidal rule on the global vector of data. I.e. consider a set of
points, equally spaced by 1 in their x coordinate: (1,V1), (2,V2),
..., (N,VN), where the Vi are the values in the global vector of
length N. The integral from 1 to N of these points is trap(). When
appropriately normalized by the timestep size, this function is useful
for calculating integrals of time-series data, like that generated by
the "fix ave/correlate"_fix_ave_correlate.html command.
The slope() function uses linear regression to fit a line to the set
of points, equally spaced by 1 in their x coordinate: (1,V1), (2,V2),
..., (N,VN), where the Vi are the values in the global vector of
length N. The returned value is the slope of the line. If the line
has a single point or is vertical, it returns 1.0e20.
The gmask(x) function takes 1 argument which is a group ID. It
can only be used in atom-style variables. It returns a 1 for
atoms that are in the group, and a 0 for atoms that are not.
The rmask(x) function takes 1 argument which is a region ID. It can
only be used in atom-style variables. It returns a 1 for atoms that
are in the geometric region, and a 0 for atoms that are not.
The grmask(x,y) function takes 2 arguments. The first is a group ID,
and the second is a region ID. It can only be used in atom-style
variables. It returns a 1 for atoms that are in both the group and
region, and a 0 for atoms that are not in both.
The next(x) function takes 1 argument which is a variable ID (not
"v_foo", just "foo"). It must be for a file-style or atomfile-style
variable. Each time the next() function is invoked (i.e. each time
the equal-style or atom-style variable is evaluated), the following
steps occur.
For file-style variables, the current string value stored by the
file-style variable is converted to a numeric value and returned by
the function. And the next string value in the file is read and
stored. Note that if the line previously read from the file was not a
numeric string, then it will typically evaluate to 0.0, which is
likely not what you want.
For atomfile-style variables, the current per-atom values stored by
the atomfile-style variable are returned by the function. And the
next set of per-atom values in the file is read and stored.
Since file-style and atomfile-style variables read and store the first
line of the file or first set of per-atoms values when they are
defined in the input script, these are the value(s) that will be
returned the first time the next() function is invoked. If next() is
invoked more times than there are lines or sets of lines in the file,
the variable is deleted, similar to how the "next"_next.html command
operates.
:line
Feature Functions :h4
Feature functions allow to probe the running LAMMPS executable for
whether specific features are either active, defined, or available.
The functions take two arguments, a {category} and a corresponding
{argument}. The arguments are strings thus cannot be formulas
themselves (only $-style immediate variable expansion is possible).
Return value is either 1.0 or 0.0 depending on whether the function
evaluates to true or false, respectively.
The {is_active()} function allows to query for active settings which
are grouped by categories. Currently supported categories and
arguments are:
{package} (argument = {cuda} or {gpu} or {intel} or {kokkos} or {omp})
{newton} (argument = {pair} or {bond} or {any})
{pair} (argument = {single} or {respa} or {manybody} or {tail} or {shift})
{comm_style} (argument = {brick} or {tiled})
{min_style} (argument = any of the compiled in minimizer styles)
{run_style} (argument = any of the compiled in run styles)
{atom_style} (argument = any of the compiled in atom styles)
{pair_style} (argument = any of the compiled in pair styles)
{bond_style} (argument = any of the compiled in bond styles)
{angle_style} (argument = any of the compiled in angle styles)
{dihedral_style} (argument = any of the compiled in dihedral styles)
{improper_style} (argument = any of the compiled in improper styles)
{kspace_style} (argument = any of the compiled in kspace styles) :ul
Most of the settings are self-explanatory, the {single} argument in the
{pair} category allows to check whether a pair style supports a
Pair::single() function as needed by compute group/group and others
features or LAMMPS, {respa} allows to check whether the inner/middle/outer
mode of r-RESPA is supported. In the various style categories,
the checking is also done using suffix flags, if available and enabled.
Example 1: disable use of suffix for pppm when using GPU package (i.e. run it on the CPU concurrently to running the pair style on the GPU), but do use the suffix otherwise (e.g. with USER-OMP).
pair_style lj/cut/coul/long 14.0
if $(is_active(package,gpu)) then "suffix off"
kspace_style pppm :pre
Example 2: use r-RESPA with inner/outer cutoff, if supported by pair style, otherwise fall back to using pair and reducing the outer time step
timestep $(2.0*(1.0+*is_active(pair,respa))
if $(is_active(pair,respa)) then "run_style respa 4 3 2 2 improper 1 inner 2 5.5 7.0 outer 3 kspace 4" else "run_style respa 3 3 2 improper 1 pair 2 kspace 3" :pre
The {is_defined()} function allows to query categories like {compute},
{dump}, {fix}, {group}, {region}, and {variable} whether an entry
with the provided name or id is defined.
The {is_available(category,name)} function allows to query whether
a specific optional feature is available, i.e. compiled in.
This currently works for the following categories: {command},
{compute}, {fix}, {pair_style} and {feature}. For all categories
except {command} and {feature} also appending active suffixes is
tried before reporting failure.
The {feature} category is used to check the availability of compiled in
features such as GZIP support, PNG support, JPEG support, FFMPEG support,
and C++ exceptions for error handling. Corresponding values for name are
{gzip}, {png}, {jpeg}, {ffmpeg} and {exceptions}.
This enables writing input scripts which only dump using a given format if
the compiled binary supports it.
if "$(is_available(feature,png))" then "print 'PNG supported'" else "print 'PNG not supported'" :pre
if "$(is_available(feature,ffmpeg)" then "dump 3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0" :pre
:line
Atom Values and Vectors :h4
Atom values take an integer argument I from 1 to N, where I is the
atom-ID, e.g. x\[243\], which means use the x coordinate of the atom
with ID = 243. Or they can take a variable name, specified as v_name,
where name is the name of the variable, like x\[v_myIndex\]. The
variable can be of any style except {vector} or {atom} or {atomfile}
variables. The variable is evaluated and the result is expected to be
numeric and is cast to an integer (i.e. 3.4 becomes 3), to use an an
index, which must be a value from 1 to N. Note that a "formula"
cannot be used as the argument between the brackets, e.g. x\[243+10\]
or x\[v_myIndex+1\] are not allowed. To do this a single variable can
be defined that contains the needed formula.
Note that the 0 < atom-ID <= N, where N is the largest atom ID
in the system. If an ID is specified for an atom that does not
currently exist, then the generated value is 0.0.
Atom vectors generate one value per atom, so that a reference like
"vx" means the x-component of each atom's velocity will be used when
evaluating the variable.
The meaning of the different atom values and vectors is mostly
self-explanatory. {Mol} refers to the molecule ID of an atom, and is
only defined if an "atom_style"_atom_style.html is being used that
defines molecule IDs.
Note that many other atom attributes can be used as inputs to a
variable by using the "compute
property/atom"_compute_property_atom.html command and then specifying
a quantity from that compute.
:line
Compute References :h4
Compute references access quantities calculated by a
"compute"_compute.html. The ID in the reference should be replaced by
the ID of a compute defined elsewhere in the input script. As
discussed in the doc page for the "compute"_compute.html command,
computes can produce global, per-atom, or local values. Only global
and per-atom values can be used in a variable. Computes can also
produce a scalar, vector, or array.
An equal-style variable can only use scalar values, which means a
global scalar, or an element of a global or per-atom vector or array.
A vector-style variable can use scalar values or a global vector of
values, or a column of a global array of values. Atom-style variables
can use global scalar values. They can also use per-atom vector
values, or a column of a per-atom array. See the doc pages for
individual computes to see what kind of values they produce.
Examples of different kinds of compute references are as follows.
There is typically no ambiguity (see exception below) as to what a
reference means, since computes only produce either global or per-atom
quantities, never both.
c_ID: global scalar, or per-atom vector
c_ID\[I\]: Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array
c_ID\[I\]\[J\]: I,J element of global array, or atom I's Jth value in per-atom array :tb(s=:)
For I and J indices, integers can be specified or a variable name,
specified as v_name, where name is the name of the variable. The
rules for this syntax are the same as for the "Atom Values and
Vectors" discussion above.
One source of ambiguity for compute references is when a vector-style
variable refers to a compute that produces both a global scalar and a
global vector. Consider a compute with ID "foo" that does this,
referenced as follows by variable "a", where "myVec" is another
vector-style variable:
variable a vector c_foo*v_myVec :pre
The reference "c_foo" could refer to either the global scalar or
global vector produced by compute "foo". In this case, "c_foo" will
always refer to the global scalar, and "C_foo" can be used to
reference the global vector. Similarly if the compute produces both a
global vector and global array, then "c_foo\[I\]" will always refer to
an element of the global vector, and "C_foo\[I\]" can be used to
reference the Ith column of the global array.
Note that if a variable containing a compute is evaluated directly in
an input script (not during a run), then the values accessed by the
compute must be current. See the discussion below about "Variable
Accuracy".
:line
Fix References :h4
Fix references access quantities calculated by a "fix"_compute.html.
The ID in the reference should be replaced by the ID of a fix defined
elsewhere in the input script. As discussed in the doc page for the
"fix"_fix.html command, fixes can produce global, per-atom, or local
values. Only global and per-atom values can be used in a variable.
Fixes can also produce a scalar, vector, or array. An equal-style
variable can only use scalar values, which means a global scalar, or
an element of a global or per-atom vector or array. Atom-style
variables can use the same scalar values. They can also use per-atom
vector values. A vector value can be a per-atom vector itself, or a
column of an per-atom array. See the doc pages for individual fixes
to see what kind of values they produce.
The different kinds of fix references are exactly the same as the
compute references listed in the above table, where "c_" is replaced
by "f_". Again, there is typically no ambiguity (see exception below)
as to what a reference means, since fixes only produce either global
or per-atom quantities, never both.
f_ID: global scalar, or per-atom vector
f_ID\[I\]: Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array
f_ID\[I\]\[J\]: I,J element of global array, or atom I's Jth value in per-atom array :tb(s=:)
For I and J indices, integers can be specified or a variable name,
specified as v_name, where name is the name of the variable. The
rules for this syntax are the same as for the "Atom Values and
Vectors" discussion above.
One source of ambiguity for fix references is the same ambiguity
discussed for compute references above. Namely when a vector-style
variable refers to a fix that produces both a global scalar and a
global vector. The solution is the same as for compute references.
For a fix with ID "foo", "f_foo" will always refer to the global
scalar, and "F_foo" can be used to reference the global vector. And
similarly for distinguishing between a fix's global vector versus
global array with "f_foo\[I\]" versus "F_foo\[I\]".
Note that if a variable containing a fix is evaluated directly in an
input script (not during a run), then the values accessed by the fix
should be current. See the discussion below about "Variable
Accuracy".
Note that some fixes only generate quantities on certain timesteps.
If a variable attempts to access the fix on non-allowed timesteps, an
error is generated. For example, the "fix ave/time"_fix_ave_time.html
command may only generate averaged quantities every 100 steps. See
the doc pages for individual fix commands for details.
:line
Variable References :h4
Variable references access quantities stored or calculated by other
variables, which will cause those variables to be evaluated. The name
in the reference should be replaced by the name of a variable defined
elsewhere in the input script.
As discussed on this doc page, equal-style variables generate a single
global numeric value, vector-style variables generate a vector of
global numeric values, and atom-style and atomfile-style variables
generate a per-atom vector of numeric values. All other variables
store one or more strings.
The formula for an equal-style variable can use any style of variable
including a vector_style or atom-style or atomfile-style. For these
3 styles, a subscript must be used to access a single value from
the vector-, atom-, or atomfile-style variable. If a string-storing
variable is used, the string is converted to a numeric value. Note
that this will typically produce a 0.0 if the string is not a numeric
string, which is likely not what you want.
The formula for a vector-style variable can use any style of variable,
including atom-style or atomfile-style variables. For these 2 styles,
a subscript must be used to access a single value from the atom-, or
atomfile-style variable.
The formula for an atom-style variable can use any style of variable,
including other atom-style or atomfile-style variables. If it uses a
vector-style variable, a subscript must be used to access a single
value from the vector-style variable.
Examples of different kinds of variable references are as follows.
There is no ambiguity as to what a reference means, since variables
produce only a global scalar or global vector or per-atom vector.
v_name: global scalar from equal-style variable
v_name: global vector from vector-style variable
v_name: per-atom vector from atom-style or atomfile-style variable
v_name\[I\]: Ith element of a global vector from vector-style variable
v_name\[I\]: value of atom with ID = I from atom-style or atomfile-style variable :tb(s=:)
For the I index, an integer can be specified or a variable name,
specified as v_name, where name is the name of the variable. The
rules for this syntax are the same as for the "Atom Values and
Vectors" discussion above.
:line
[Immediate Evaluation of Variables:]
If you want an equal-style variable to be evaluated immediately, it
may be the case that you do not need to define a variable at all. See
"Section 3.2"_Section_commands.html#cmd_2 of the manual, which
describes the use of "immediate" variables in an input script,
specified as $(formula) with parenthesis, where the formula has the
same syntax as equal-style variables described on this page. This
effectively evaluates a formula immediately without using the variable
command to define a named variable.
More generally, there is a difference between referencing a variable
with a leading $ sign (e.g. $x or $\{abc\}) versus with a leading "v_"
(e.g. v_x or v_abc). The former can be used in any input script
command, including a variable command. The input script parser
evaluates the reference variable immediately and substitutes its value
into the command. As explained in "Section
3.2"_Section_commands.html#cmd_2 for "Parsing rules", you can also use
un-named "immediate" variables for this purpose. For example, a
string like this $((xlo+xhi)/2+sqrt(v_area)) in an input script
command evaluates the string between the parenthesis as an equal-style
variable formula.
Referencing a variable with a leading "v_" is an optional or required
kind of argument for some commands (e.g. the "fix
ave/chunk"_fix_ave_chunk.html or "dump custom"_dump.html or
"thermo_style"_thermo_style.html commands) if you wish it to evaluate
a variable periodically during a run. It can also be used in a
variable formula if you wish to reference a second variable. The
second variable will be evaluated whenever the first variable is
evaluated.
As an example, suppose you use this command in your input script to
define the variable "v" as
variable v equal vol :pre
before a run where the simulation box size changes. You might think
this will assign the initial volume to the variable "v". That is not
the case. Rather it assigns a formula which evaluates the volume
(using the thermo_style keyword "vol") to the variable "v". If you
use the variable "v" in some other command like "fix
ave/time"_fix_ave_time.html then the current volume of the box will be
evaluated continuously during the run.
If you want to store the initial volume of the system, you can do it
this way:
variable v equal vol
variable v0 equal $v :pre
The second command will force "v" to be evaluated (yielding the
initial volume) and assign that value to the variable "v0". Thus the
command
thermo_style custom step v_v v_v0 :pre
would print out both the current and initial volume periodically
during the run.
Note that it is a mistake to enclose a variable formula in double
quotes if it contains variables preceded by $ signs. For example,
variable vratio equal "$\{vfinal\}/$\{v0\}" :pre
This is because the quotes prevent variable substitution (see "this
section"_Section_commands.html#cmd_2 on parsing input script
commands), and thus an error will occur when the formula for "vratio"
is evaluated later.
:line
[Variable Accuracy:]
Obviously, LAMMPS attempts to evaluate variables containing formulas
({equal} and {atom} style variables) accurately whenever the
evaluation is performed. Depending on what is included in the
formula, this may require invoking a "compute"_compute.html, either
directly or indirectly via a thermo keyword, or accessing a value
previously calculated by a compute, or accessing a value calculated
and stored by a "fix"_fix.html. If the compute is one that calculates
the pressure or energy of the system, then these quantities need to be
tallied during the evaluation of the interatomic potentials (pair,
bond, etc) on timesteps that the variable will need the values.
LAMMPS keeps track of all of this during a "run"_run.html or "energy
minimization"_minimize.html. An error will be generated if you
attempt to evaluate a variable on timesteps when it cannot produce
accurate values. For example, if a "thermo_style
custom"_thermo_style.html command prints a variable which accesses
values stored by a "fix ave/time"_fix_ave_time.html command and the
timesteps on which thermo output is generated are not multiples of the
averaging frequency used in the fix command, then an error will occur.
An input script can also request variables be evaluated before or
after or in between runs, e.g. by including them in a
"print"_print.html command. In this case, if a compute is needed to
evaluate a variable (either directly or indirectly), LAMMPS will not
invoke the compute, but it will use a value previously calculated by
the compute, and can do this only if it was invoked on the current
timestep. Fixes will always provide a quantity needed by a variable,
but the quantity may or may not be current. This leads to one of
three kinds of behavior:
(1) The variable may be evaluated accurately. If it contains
references to a compute or fix, and these values were calculated on
the last timestep of a preceding run, then they will be accessed and
used by the variable and the result will be accurate.
(2) LAMMPS may not be able to evaluate the variable and will generate
an error message stating so. For example, if the variable requires a
quantity from a "compute"_compute.html that has not been invoked on
the current timestep, LAMMPS will generate an error. This means, for
example, that such a variable cannot be evaluated before the first run
has occurred. Likewise, in between runs, a variable containing a
compute cannot be evaluated unless the compute was invoked on the last
timestep of the preceding run, e.g. by thermodynamic output.
One way to get around this problem is to perform a 0-timestep run
before using the variable. For example, these commands
variable t equal temp
print "Initial temperature = $t"
run 1000 :pre
will generate an error if the run is the first run specified in the
input script, because generating a value for the "t" variable requires
a compute for calculating the temperature to be invoked.
However, this sequence of commands would be fine:
run 0
variable t equal temp
print "Initial temperature = $t"
run 1000 :pre
The 0-timestep run initializes and invokes various computes, including
the one for temperature, so that the value it stores is current and
can be accessed by the variable "t" after the run has completed. Note
that a 0-timestep run does not alter the state of the system, so it
does not change the input state for the 1000-timestep run that
follows. Also note that the 0-timestep run must actually use and
invoke the compute in question (e.g. via "thermo"_thermo_style.html or
"dump"_dump.html output) in order for it to enable the compute to be
used in a variable after the run. Thus if you are trying to print a
variable that uses a compute you have defined, you can insure it is
invoked on the last timestep of the preceding run by including it in
thermodynamic output.
Unlike computes, "fixes"_fix.html will never generate an error if
their values are accessed by a variable in between runs. They always
return some value to the variable. However, the value may not be what
you expect if the fix has not yet calculated the quantity of interest
or it is not current. For example, the "fix indent"_fix_indent.html
command stores the force on the indenter. But this is not computed
until a run is performed. Thus if a variable attempts to print this
value before the first run, zeroes will be output. Again, performing
a 0-timestep run before printing the variable has the desired effect.
(3) The variable may be evaluated incorrectly and LAMMPS may have no
way to detect this has occurred. Consider the following sequence of
commands:
pair_coeff 1 1 1.0 1.0
run 1000
pair_coeff 1 1 1.5 1.0
variable e equal pe
print "Final potential energy = $e" :pre
The first run is performed using one setting for the pairwise
potential defined by the "pair_style"_pair_style.html and
"pair_coeff"_pair_coeff.html commands. The potential energy is
evaluated on the final timestep and stored by the "compute
pe"_compute_pe.html compute (this is done by the
"thermo_style"_thermo_style.html command). Then a pair coefficient is
changed, altering the potential energy of the system. When the
potential energy is printed via the "e" variable, LAMMPS will use the
potential energy value stored by the "compute pe"_compute_pe.html
compute, thinking it is current. There are many other commands which
could alter the state of the system between runs, causing a variable
to evaluate incorrectly.
The solution to this issue is the same as for case (2) above, namely
perform a 0-timestep run before the variable is evaluated to insure
the system is up-to-date. For example, this sequence of commands
would print a potential energy that reflected the changed pairwise
coefficient:
pair_coeff 1 1 1.0 1.0
run 1000
pair_coeff 1 1 1.5 1.0
run 0
variable e equal pe
print "Final potential energy = $e" :pre
:line
[Restrictions:]
Indexing any formula element by global atom ID, such as an atom value,
requires the "atom style"_atom_style.html to use a global mapping in
order to look up the vector indices. By default, only atom styles
with molecular information create global maps. The "atom_modify
map"_atom_modify.html command can override the default, e.g. for
atomic-style atom styles.
All {universe}- and {uloop}-style variables defined in an input script
must have the same number of values.
[Related commands:]
"next"_next.html, "jump"_jump.html, "include"_include.html,
"temper"_temper.html, "fix print"_fix_print.html, "print"_print.html
[Default:] none
diff --git a/doc/src/write_data.txt b/doc/src/write_data.txt
index 033199e98..39e5a7f81 100644
--- a/doc/src/write_data.txt
+++ b/doc/src/write_data.txt
@@ -1,123 +1,123 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
write_data command :h3
[Syntax:]
write_data file keyword value ... :pre
file = name of data file to write out :ulb,l
zero or more keyword/value pairs may be appended :l
keyword = {pair} or {nocoeff} :l
{nocoeff} = do not write out force field info
{pair} value = {ii} or {ij}
{ii} = write one line of pair coefficient info per atom type
{ij} = write one line of pair coefficient info per IJ atom type pair :pre
:ule
[Examples:]
write_data data.polymer
write_data data.* :pre
[Description:]
Write a data file in text format of the current state of the
simulation. Data files can be read by the "read data"_read_data.html
command to begin a simulation. The "read_data"_read_data.html command
also describes their format.
Similar to "dump"_dump.html files, the data filename can contain a "*"
wild-card character. The "*" is replaced with the current timestep
value.
NOTE: The write-data command is not yet fully implemented in two
respects. First, most pair styles do not yet write their coefficient
information into the data file. This means you will need to specify
that information in your input script that reads the data file, via
the "pair_coeff"_pair_coeff.html command. Second, a few of the "atom
styles"_atom_style.html (body, ellipsoid, line, tri) that store
auxiliary "bonus" information about aspherical particles, do not yet
write the bonus info into the data file. Both these functionalities
will be added to the write_data command later.
Because a data file is in text format, if you use a data file written
out by this command to restart a simulation, the initial state of the
new run will be slightly different than the final state of the old run
(when the file was written) which was represented internally by LAMMPS
in binary format. A new simulation which reads the data file will
thus typically diverge from a simulation that continued in the
original input script.
If you want to do more exact restarts, using binary files, see the
"restart"_restart.html, "write_restart"_write_restart.html, and
"read_restart"_read_restart.html commands. You can also convert
binary restart files to text data files, after a simulation has run,
-using the "-r command-line switch"_Section_start.html#start_7.
+using the "-r command-line switch"_Section_start.html#start_6.
NOTE: Only limited information about a simulation is stored in a data
file. For example, no information about atom "groups"_group.html and
"fixes"_fix.html are stored. "Binary restart files"_read_restart.html
store more information.
Bond interactions (angle, etc) that have been turned off by the "fix
shake"_fix_shake.html or "delete_bonds"_delete_bonds.html command will
be written to a data file as if they are turned on. This means they
will need to be turned off again in a new run after the data file is
read.
Bonds that are broken (e.g. by a bond-breaking potential) are not
written to the data file. Thus these bonds will not exist when the
data file is read.
:line
The {nocoeff} keyword requests that no force field parameters should
be written to the data file. This can be very helpful, if one wants
to make significant changes to the force field or if the parameters
are read in separately anyway, e.g. from an include file.
The {pair} keyword lets you specify in what format the pair
coefficient information is written into the data file. If the value
is specified as {ii}, then one line per atom type is written, to
specify the coefficients for each of the I=J interactions. This means
that no cross-interactions for I != J will be specified in the data
file and the pair style will apply its mixing rule, as documented on
individual "pair_style"_pair_style.html doc pages. Of course this
behavior can be overridden in the input script after reading the data
file, by specifying additional "pair_coeff"_pair_coeff.html commands
for any desired I,J pairs.
If the value is specified as {ij}, then one line of coefficients is
written for all I,J pairs where I <= J. These coefficients will
include any specific settings made in the input script up to that
point. The presence of these I != J coefficients in the data file
will effectively turn off the default mixing rule for the pair style.
Again, the coefficient values in the data file can can be overridden
in the input script after reading the data file, by specifying
additional "pair_coeff"_pair_coeff.html commands for any desired I,J
pairs.
:line
[Restrictions:]
This command requires inter-processor communication to migrate atoms
before the data file is written. This means that your system must be
ready to perform a simulation before using this command (force fields
setup, atom masses initialized, etc).
[Related commands:]
"read_data"_read_data.html, "write_restart"_write_restart.html
[Default:]
The option defaults are pair = ii.
diff --git a/doc/src/write_restart.txt b/doc/src/write_restart.txt
index 8160eec3d..ff3b652db 100644
--- a/doc/src/write_restart.txt
+++ b/doc/src/write_restart.txt
@@ -1,121 +1,121 @@
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
:link(lws,http://lammps.sandia.gov)
:link(ld,Manual.html)
:link(lc,Section_commands.html#comm)
:line
write_restart command :h3
[Syntax:]
write_restart file keyword value ... :pre
file = name of file to write restart information to :ulb,l
zero or more keyword/value pairs may be appended :l
keyword = {fileper} or {nfile} :l
{fileper} arg = Np
Np = write one file for every this many processors
{nfile} arg = Nf
Nf = write this many files, one from each of Nf processors :pre
:ule
[Examples:]
write_restart restart.equil
write_restart restart.equil.mpiio
write_restart poly.%.* nfile 10 :pre
[Description:]
Write a binary restart file of the current state of the simulation.
During a long simulation, the "restart"_restart.html command is
typically used to output restart files periodically. The
write_restart command is useful after a minimization or whenever you
wish to write out a single current restart file.
Similar to "dump"_dump.html files, the restart filename can contain
two wild-card characters. If a "*" appears in the filename, it is
replaced with the current timestep value. If a "%" character appears
in the filename, then one file is written by each processor and the
"%" character is replaced with the processor ID from 0 to P-1. An
additional file with the "%" replaced by "base" is also written, which
contains global information. For example, the files written for
filename restart.% would be restart.base, restart.0, restart.1, ...
restart.P-1. This creates smaller files and can be a fast mode of
output and subsequent input on parallel machines that support parallel
I/O. The optional {fileper} and {nfile} keywords discussed below can
alter the number of files written.
The restart file can also be written in parallel as one large binary
file via the MPI-IO library, which is part of the MPI standard for
versions 2.0 and above. Using MPI-IO requires two steps. First,
build LAMMPS with its MPIIO package installed, e.g.
make yes-mpiio # installs the MPIIO package
make mpi # build LAMMPS for your platform :pre
Second, use a restart filename which contains ".mpiio". Note that it
does not have to end in ".mpiio", just contain those characters.
Unlike MPI-IO dump files, a particular restart file must be both
written and read using MPI-IO.
Restart files can be read by a "read_restart"_read_restart.html
command to restart a simulation from a particular state. Because the
file is binary (to enable exact restarts), it may not be readable on
another machine. In this case, you can use the "-r command-line
-switch"_Section_start.html#start_7 to convert a restart file to a data
+switch"_Section_start.html#start_6 to convert a restart file to a data
file.
NOTE: Although the purpose of restart files is to enable restarting a
simulation from where it left off, not all information about a
simulation is stored in the file. For example, the list of fixes that
were specified during the initial run is not stored, which means the
new input script must specify any fixes you want to use. Even when
restart information is stored in the file, as it is for some fixes,
commands may need to be re-specified in the new input script, in order
to re-use that information. Details are usually given in the
documentation of the respective command. Also, see the
"read_restart"_read_restart.html command for general information about
what is stored in a restart file.
:line
The optional {nfile} or {fileper} keywords can be used in conjunction
with the "%" wildcard character in the specified restart file name.
As explained above, the "%" character causes the restart file to be
written in pieces, one piece for each of P processors. By default P =
the number of processors the simulation is running on. The {nfile} or
{fileper} keyword can be used to set P to a smaller value, which can
be more efficient when running on a large number of processors.
The {nfile} keyword sets P to the specified Nf value. For example, if
Nf = 4, and the simulation is running on 100 processors, 4 files will
be written, by processors 0,25,50,75. Each will collect information
from itself and the next 24 processors and write it to a restart file.
For the {fileper} keyword, the specified value of Np means write one
file for every Np processors. For example, if Np = 4, every 4th
processor (0,4,8,12,etc) will collect information from itself and the
next 3 processors and write it to a restart file.
:line
[Restrictions:]
This command requires inter-processor communication to migrate atoms
before the restart file is written. This means that your system must
be ready to perform a simulation before using this command (force
fields setup, atom masses initialized, etc).
To write and read restart files in parallel with MPI-IO, the MPIIO
package must be installed.
[Related commands:]
"restart"_restart.html, "read_restart"_read_restart.html,
"write_data"_write_data.html
[Default:] none
diff --git a/examples/COUPLE/README b/examples/COUPLE/README
index c8c9e0e31..83e746353 100644
--- a/examples/COUPLE/README
+++ b/examples/COUPLE/README
@@ -1,48 +1,48 @@
This directory has examples of how to use LAMMPS as a library, either
by itself or in tandem with another code or library.
These examples is meant to illustrate what is possible when coupling
codes or calling LAMMPS as a library. The examples are provided for
demonstration purposes. The physics they calculate is too simple to
model a realistic problem.
See these sections of the LAMMPS manaul for details:
2.5 Building LAMMPS as a library (doc/Section_start.html#start_5)
6.10 Coupling LAMMPS to other codes (doc/Section_howto.html#howto_10)
In all of the examples included here, LAMMPS must first be built as a
library. Basically, in the src dir you type one of
make mode=lib machine
make mode=shlib machine
to create the static library liblammps_machine.a or the shared library
liblammps_machine.so for your code to link against. A soft link
(liblammps.a or liblammps.so) is also created that points to the most
recently built static or shared library. Your code build can simply
use the soft link if you prefer.
The library interface to LAMMPS is in src/library.cpp. Routines can
be easily added to this file so an external program can perform the
LAMMPS tasks desired.
-------------------------------------------------------------------
These are the sub-directories included in this directory:
simple simple example of driver code calling LAMMPS as a lib
multiple example of driver code calling multiple instances of LAMMPS
lammps_quest MD with quantum forces, coupling to Quest DFT code
lammps_spparks grain-growth Monte Carlo with strain via MD,
coupling to SPPARKS kinetic MC code
library collection of useful inter-code communication routines
fortran a simple wrapper on the LAMMPS library API that
can be called from Fortran
fortran2 a more sophisticated wrapper on the LAMMPS library API that
can be called from Fortran
-fortran3 wrapper written by Nir Goldman (LLNL), as an
+fortran_dftb wrapper written by Nir Goldman (LLNL), as an
extension to fortran2, used for calling LAMMPS
- from Fortran DFTB+ code
+ from Fortran DFTB+ tight-binding code
Each sub-directory has its own README with more details.
diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper.cpp b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper.cpp
similarity index 100%
rename from examples/COUPLE/fortran3/LAMMPS-wrapper.cpp
rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper.cpp
diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper.h b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper.h
similarity index 100%
rename from examples/COUPLE/fortran3/LAMMPS-wrapper.h
rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper.h
diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp
similarity index 71%
rename from examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp
rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp
index f245c44d7..d16b49cc5 100644
--- a/examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp
+++ b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp
@@ -1,57 +1,81 @@
/* -----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
www.cs.sandia.gov/~sjplimp/lammps.html
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------
Contributing author: Karl D. Hammond <karlh@ugcs.caltech.edu>
University of Tennessee, Knoxville (USA), 2012
------------------------------------------------------------------------- */
/* This is set of "wrapper" functions to assist LAMMPS.F90, which itself
provides a (I hope) robust Fortran interface to library.cpp and
library.h. All functions herein COULD be added to library.cpp instead of
including this as a separate file. See the README for instructions. */
#include <mpi.h>
#include "LAMMPS-wrapper2.h"
#include <library.h>
#include <lammps.h>
#include <atom.h>
#include <input.h>
#include <modify.h>
#include <fix.h>
#include <fix_external.h>
#include <compute.h>
#include <modify.h>
#include <error.h>
#include <cstdlib>
using namespace LAMMPS_NS;
extern "C" void f_callback(void *, bigint, int, tagint *, double **, double **);
void lammps_set_callback (void *ptr) {
class LAMMPS *lmp = (class LAMMPS *) ptr;
int ifix = lmp->modify->find_fix_by_style("external");
FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
fix->set_callback(f_callback, ptr);
return;
}
+void lammps_set_external_vector_length (void *ptr, int n) {
+ class LAMMPS *lmp = (class LAMMPS *) ptr;
+ int ifix = lmp->modify->find_fix_by_style("external");
+ FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
+ fix->set_vector_length(n);
+ return;
+}
+
+void lammps_set_external_vector (void *ptr, int n, double val) {
+ class LAMMPS *lmp = (class LAMMPS *) ptr;
+ int ifix = lmp->modify->find_fix_by_style("external");
+ FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
+ fix->set_vector (n, val);
+ return;
+}
+
void lammps_set_user_energy (void *ptr, double energy) {
class LAMMPS *lmp = (class LAMMPS *) ptr;
int ifix = lmp->modify->find_fix_by_style("external");
FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
- fix->set_energy(energy);
+ fix->set_energy_global(energy);
+ return;
+}
+
+void lammps_set_user_virial (void *ptr, double *virial) {
+ class LAMMPS *lmp = (class LAMMPS *) ptr;
+ int ifix = lmp->modify->find_fix_by_style("external");
+ FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix];
+ fix->set_virial_global(virial);
return;
}
diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper2.h b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h
similarity index 89%
rename from examples/COUPLE/fortran3/LAMMPS-wrapper2.h
rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h
index 794006e3a..ed79015e7 100644
--- a/examples/COUPLE/fortran3/LAMMPS-wrapper2.h
+++ b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h
@@ -1,34 +1,37 @@
/* -----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
www.cs.sandia.gov/~sjplimp/lammps.html
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------
Contributing author: Nir Goldman, ngoldman@llnl.gov, Oct. 19th, 2016
------------------------------------------------------------------------- */
/* This is set of "wrapper" functions to assist LAMMPS.F90, which itself
provides a (I hope) robust Fortran interface to library.cpp and
library.h. All prototypes herein COULD be added to library.h instead of
including this as a separate file. See the README for instructions. */
#ifdef __cplusplus
extern "C" {
#endif
/* Prototypes for auxiliary functions */
void lammps_set_callback (void *);
void lammps_set_user_energy (void*, double);
+void lammps_set_user_virial (void*, double*);
+void lammps_set_external_vector_length (void*, int);
+void lammps_set_external_vector (void*, int, double);
#ifdef __cplusplus
}
#endif
/* vim: set ts=3 sts=3 expandtab: */
diff --git a/examples/COUPLE/fortran3/LAMMPS.F90 b/examples/COUPLE/fortran_dftb/LAMMPS.F90
similarity index 97%
rename from examples/COUPLE/fortran3/LAMMPS.F90
rename to examples/COUPLE/fortran_dftb/LAMMPS.F90
index eb5b7f825..9b18bbfa5 100644
--- a/examples/COUPLE/fortran3/LAMMPS.F90
+++ b/examples/COUPLE/fortran_dftb/LAMMPS.F90
@@ -1,956 +1,982 @@
!! -----------------------------------------------------------------------
! LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
! www.cs.sandia.gov/~sjplimp/lammps.html
! Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
!
! Copyright (2003) Sandia Corporation. Under the terms of Contract
! DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
! certain rights in this software. This software is distributed under
! the GNU General Public License.
!
! See the README file in the top-level LAMMPS directory.
!--------------------------------------------------------------------------
!! ------------------------------------------------------------------------
! Contributing author: Karl D. Hammond <karlh@ugcs.caltech.edu>
! University of Tennessee, Knoxville (USA), 2012
!--------------------------------------------------------------------------
!! LAMMPS, a Fortran 2003 module containing an interface between Fortran
!! programs and the C-style functions in library.cpp that ship with LAMMPS.
!! This file should be accompanied by LAMMPS-wrapper.cpp and LAMMPS-wrapper.h,
!! which define wrapper functions that ease portability and enforce array
!! dimensions.
!!
!! Everything in this module should be 100% portable by way of Fortran 2003's
!! ISO_C_BINDING intrinsic module. See the README for instructions for
!! compilation and use.
!!
!! Here are the PUBLIC functions and subroutines included in this module.
!! subroutine lammps_open (command_line, communicator, ptr)
!! subroutine lammps_open_no_mpi (command_line, ptr)
!! subroutine lammps_close (ptr)
!! subroutine lammps_file (ptr, str)
!! subroutine lammps_command (ptr, str)
!! subroutine lammps_free (ptr)
!! subroutine lammps_extract_global (global, ptr, name)
!! subroutine lammps_extract_atom (atom, ptr, name)
!! subroutine lammps_extract_fix (fix, ptr, id, style, type, i, j)
!! subroutine lammps_extract_compute (compute, ptr, id, style, type)
!! subroutine lammps_extract_variable (variable, ptr, name, group)
!! function lammps_get_natoms (ptr)
!! subroutine lammps_gather_atoms (ptr, name, count, data)
!! subroutine lammps_scatter_atoms (ptr, name, data)
#define FLERR __FILE__,__LINE__
! The above line allows for similar error checking as is done with standard
! LAMMPS files.
module LAMMPS
use, intrinsic :: ISO_C_binding, only : C_double, C_int, C_ptr, C_char, &
C_NULL_CHAR, C_loc, C_F_pointer, lammps_instance => C_ptr
implicit none
private
+ public :: lammps_set_user_virial
+ public :: lammps_set_external_vector_length
+ public :: lammps_set_external_vector
+ public :: lammps_set_user_energy
public :: lammps_open, lammps_open_no_mpi, lammps_close, lammps_file, &
lammps_command, lammps_free, lammps_extract_global, &
lammps_extract_atom, lammps_extract_compute, lammps_extract_fix, &
lammps_extract_variable, lammps_get_natoms, lammps_gather_atoms, &
- lammps_scatter_atoms, lammps_set_callback, lammps_set_user_energy
- public :: lammps_instance, C_ptr, C_double, C_int
+ lammps_set_callback
+ public :: lammps_scatter_atoms, lammps_instance, C_ptr, C_double, C_int
!! Functions supplemental to the prototypes in library.h. {{{1
!! The function definitions (in C++) are contained in LAMMPS-wrapper.cpp.
!! I would have written the first in Fortran, but the MPI libraries (which
!! were written in C) have C-based functions to convert from Fortran MPI
!! handles to C MPI handles, and there is no Fortran equivalent for those
!! functions.
interface
subroutine lammps_open_wrapper (argc, argv, communicator, ptr) &
bind (C, name='lammps_open_fortran_wrapper')
import :: C_int, C_ptr
integer (C_int), value :: argc
type (C_ptr), dimension(*) :: argv
integer, value :: communicator
type (C_ptr) :: ptr
end subroutine lammps_open_wrapper
subroutine lammps_actual_error_all (ptr, file, line, str) &
bind (C, name='lammps_error_all')
import :: C_int, C_char, C_ptr
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*), intent(in) :: file, str
integer (C_int), value :: line
end subroutine lammps_actual_error_all
function lammps_get_ntypes (ptr) result (ntypes) &
bind (C, name='lammps_get_ntypes')
import :: C_int, C_ptr
type (C_ptr), value :: ptr
integer (C_int) :: ntypes
end function lammps_get_ntypes
function lammps_actual_extract_compute_vectorsize (ptr, id, style) &
result (vectorsize) bind (C, name='lammps_extract_compute_vectorsize')
import :: C_int, C_char, C_ptr
integer (C_int) :: vectorsize
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style
end function lammps_actual_extract_compute_vectorsize
subroutine lammps_actual_extract_compute_arraysize (ptr, id, style, &
nrows, ncols) bind (C, name='lammps_extract_compute_arraysize')
import :: C_int, C_char, C_ptr
integer (C_int) :: arraysize
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style
integer (C_int) :: nrows, ncols
end subroutine lammps_actual_extract_compute_arraysize
function lammps_actual_extract_fix_vectorsize (ptr, id, style) &
result (vectorsize) bind (C, name='lammps_extract_fix_vectorsize')
import :: C_int, C_char, C_ptr
integer (C_int) :: vectorsize
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style
end function lammps_actual_extract_fix_vectorsize
subroutine lammps_actual_extract_fix_arraysize (ptr, id, style, &
nrows, ncols) bind (C, name='lammps_extract_fix_arraysize')
import :: C_int, C_char, C_ptr
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style
integer (C_int) :: nrows, ncols
end subroutine lammps_actual_extract_fix_arraysize
end interface
!! Functions/subroutines defined in library.h and library.cpp {{{1
interface
subroutine lammps_actual_open_no_mpi (argc, argv, ptr) &
bind (C, name='lammps_open_no_mpi')
import :: C_int, C_ptr
integer (C_int), value :: argc
type (C_ptr), dimension(*) :: argv
type (C_ptr) :: ptr
end subroutine lammps_actual_open_no_mpi
subroutine lammps_close (ptr) bind (C, name='lammps_close')
import :: C_ptr
type (C_ptr), value :: ptr
end subroutine lammps_close
subroutine lammps_actual_file (ptr, str) bind (C, name='lammps_file')
import :: C_ptr, C_char
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: str
end subroutine lammps_actual_file
function lammps_actual_command (ptr, str) result (command) &
bind (C, name='lammps_command')
import :: C_ptr, C_char
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: str
type (C_ptr) :: command
end function lammps_actual_command
subroutine lammps_free (ptr) bind (C, name='lammps_free')
import :: C_ptr
type (C_ptr), value :: ptr
end subroutine lammps_free
function lammps_actual_extract_global (ptr, name) &
bind (C, name='lammps_extract_global') result (global)
import :: C_ptr, C_char
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: name
type (C_ptr) :: global
end function lammps_actual_extract_global
function lammps_actual_extract_atom (ptr, name) &
bind (C, name='lammps_extract_atom') result (atom)
import :: C_ptr, C_char
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: name
type (C_ptr) :: atom
end function lammps_actual_extract_atom
function lammps_actual_extract_compute (ptr, id, style, type) &
result (compute) bind (C, name='lammps_extract_compute')
import :: C_ptr, C_char, C_int
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style, type
type (C_ptr) :: compute
end function lammps_actual_extract_compute
function lammps_actual_extract_fix (ptr, id, style, type, i, j) &
result (fix) bind (C, name='lammps_extract_fix')
import :: C_ptr, C_char, C_int
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: id
integer (C_int), value :: style, type, i, j
type (C_ptr) :: fix
end function lammps_actual_extract_fix
function lammps_actual_extract_variable (ptr, name, group) &
result (variable) bind (C, name='lammps_extract_variable')
import :: C_ptr, C_char
type (C_ptr), value :: ptr
character (kind=C_char), dimension(*) :: name, group
type (C_ptr) :: variable
end function lammps_actual_extract_variable
function lammps_get_natoms (ptr) result (natoms) &
bind (C, name='lammps_get_natoms')
import :: C_ptr, C_int
type (C_ptr), value :: ptr
integer (C_int) :: natoms
end function lammps_get_natoms
subroutine lammps_set_callback (ptr) &
bind (C, name='lammps_set_callback')
import :: C_ptr
type (C_ptr), value :: ptr
end subroutine lammps_set_callback
subroutine lammps_set_user_energy (ptr, energy) &
bind (C, name='lammps_set_user_energy')
import :: C_ptr, C_double
type (C_ptr), value :: ptr
real(C_double), value :: energy
end subroutine lammps_set_user_energy
+ subroutine lammps_set_user_virial (ptr, virial) &
+ bind (C, name='lammps_set_user_virial')
+ import :: C_ptr, C_double
+ type (C_ptr), value :: ptr
+ real(C_double) :: virial(6)
+ end subroutine lammps_set_user_virial
+
+ subroutine lammps_set_external_vector_length (ptr, n) &
+ bind (C, name='lammps_set_external_vector_length')
+ import :: C_ptr, C_double, C_int
+ type(C_ptr), value :: ptr
+ integer (C_int), value :: n
+ end subroutine lammps_set_external_vector_length
+
+ subroutine lammps_set_external_vector (ptr, n, val) &
+ bind (C, name='lammps_set_external_vector')
+ import :: C_ptr, C_int, C_double
+ type (C_ptr), value :: ptr
+ integer (C_int), value :: n
+ real(C_double), value :: val
+ end subroutine lammps_set_external_vector
+
subroutine lammps_actual_gather_atoms (ptr, name, type, count, data) &
bind (C, name='lammps_gather_atoms')
import :: C_ptr, C_int, C_char
type (C_ptr), value :: ptr, data
character (kind=C_char), dimension(*) :: name
integer (C_int), value :: type, count
end subroutine lammps_actual_gather_atoms
subroutine lammps_actual_scatter_atoms (ptr, name, type, count, data) &
bind (C, name='lammps_scatter_atoms')
import :: C_ptr, C_int, C_char
type (C_ptr), value :: ptr, data
character (kind=C_char), dimension(*) :: name
integer (C_int), value :: type, count
end subroutine lammps_actual_scatter_atoms
end interface
! Generic functions for the wrappers below {{{1
interface lammps_extract_global
module procedure lammps_extract_global_i, &
lammps_extract_global_dp
end interface lammps_extract_global
interface lammps_extract_atom
module procedure lammps_extract_atom_ia, &
lammps_extract_atom_dpa, &
lammps_extract_atom_dp2a
end interface lammps_extract_atom
interface lammps_extract_compute
module procedure lammps_extract_compute_dp, &
lammps_extract_compute_dpa, &
lammps_extract_compute_dp2a
end interface lammps_extract_compute
interface lammps_extract_fix
module procedure lammps_extract_fix_dp, &
lammps_extract_fix_dpa, &
lammps_extract_fix_dp2a
end interface lammps_extract_fix
interface lammps_extract_variable
module procedure lammps_extract_variable_dp, &
lammps_extract_variable_dpa
end interface lammps_extract_variable
interface lammps_gather_atoms
module procedure lammps_gather_atoms_ia, lammps_gather_atoms_dpa
end interface lammps_gather_atoms
interface lammps_scatter_atoms
module procedure lammps_scatter_atoms_ia, lammps_scatter_atoms_dpa
end interface lammps_scatter_atoms
contains !! Wrapper functions local to this module {{{1
subroutine lammps_open (command_line, communicator, ptr)
character (len=*), intent(in) :: command_line
integer, intent(in) :: communicator
type (C_ptr) :: ptr
integer (C_int) :: argc
type (C_ptr), dimension(:), allocatable :: argv
character (kind=C_char), dimension(len_trim(command_line)+1), target :: &
c_command_line
c_command_line = string2Cstring (command_line)
call Cstring2argcargv (c_command_line, argc, argv)
call lammps_open_wrapper (argc, argv, communicator, ptr)
deallocate (argv)
end subroutine lammps_open
!-----------------------------------------------------------------------------
subroutine lammps_open_no_mpi (command_line, ptr)
character (len=*), intent(in) :: command_line
type (C_ptr) :: ptr
integer (C_int) :: argc
type (C_ptr), dimension(:), allocatable :: argv
character (kind=C_char), dimension(len_trim(command_line)+1), target :: &
c_command_line
c_command_line = string2Cstring (command_line)
call Cstring2argcargv (c_command_line, argc, argv)
call lammps_actual_open_no_mpi (argc, argv, ptr)
deallocate (argv)
end subroutine lammps_open_no_mpi
!-----------------------------------------------------------------------------
subroutine lammps_file (ptr, str)
type (C_ptr) :: ptr
character (len=*) :: str
character (kind=C_char), dimension(len_trim(str)+1) :: Cstr
Cstr = string2Cstring (str)
call lammps_actual_file (ptr, Cstr)
end subroutine lammps_file
!-----------------------------------------------------------------------------
subroutine lammps_command (ptr, str)
type (C_ptr) :: ptr
character (len=*) :: str
character (kind=C_char), dimension(len_trim(str)+1) :: Cstr
type (C_ptr) :: dummy
Cstr = string2Cstring (str)
dummy = lammps_actual_command (ptr, Cstr)
end subroutine lammps_command
!-----------------------------------------------------------------------------
! lammps_extract_global {{{2
function lammps_extract_global_Cptr (ptr, name) result (global)
type (C_ptr) :: global
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
Cname = string2Cstring (name)
global = lammps_actual_extract_global (ptr, Cname)
end function lammps_extract_global_Cptr
subroutine lammps_extract_global_i (global, ptr, name)
integer (C_int), pointer, intent(out) :: global
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
type (C_ptr) :: Cptr
Cptr = lammps_extract_global_Cptr (ptr, name)
call C_F_pointer (Cptr, global)
end subroutine lammps_extract_global_i
subroutine lammps_extract_global_dp (global, ptr, name)
real (C_double), pointer, intent(out) :: global
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
type (C_ptr) :: Cptr
Cptr = lammps_extract_global_Cptr (ptr, name)
call C_F_pointer (Cptr, global)
end subroutine lammps_extract_global_dp
!-----------------------------------------------------------------------------
! lammps_extract_atom {{{2
function lammps_extract_atom_Cptr (ptr, name) result (atom)
type (C_ptr) :: atom
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
Cname = string2Cstring (name)
atom = lammps_actual_extract_atom (ptr, Cname)
end function lammps_extract_atom_Cptr
subroutine lammps_extract_atom_ia (atom, ptr, name)
integer (C_int), dimension(:), pointer, intent(out) :: atom
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
type (C_ptr) :: Cptr
integer (C_int), pointer :: nelements
call lammps_extract_global_i (nelements, ptr, 'nlocal')
Cptr = lammps_extract_atom_Cptr (ptr, name)
call C_F_pointer (Cptr, atom, (/nelements/))
end subroutine lammps_extract_atom_ia
subroutine lammps_extract_atom_dpa (atom, ptr, name)
real (C_double), dimension(:), pointer, intent(out) :: atom
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
type (C_ptr) :: Cptr
integer (C_int), pointer :: nlocal
integer :: nelements
real (C_double), dimension(:), pointer :: Fptr
if ( name == 'mass' ) then
nelements = lammps_get_ntypes (ptr) + 1
else if ( name == 'x' .or. name == 'v' .or. name == 'f' .or. &
name == 'mu' .or. name == 'omega' .or. name == 'torque' .or. &
name == 'angmom' ) then
! We should not be getting a rank-2 array here!
call lammps_error_all (ptr, FLERR, 'You cannot extract those atom&
& data (' // trim(name) // ') into a rank 1 array.')
return
else
! Everything else we can get is probably nlocal units long
call lammps_extract_global_i (nlocal, ptr, 'nlocal')
nelements = nlocal
end if
Cptr = lammps_extract_atom_Cptr (ptr, name)
call C_F_pointer (Cptr, Fptr, (/nelements/))
if ( name == 'mass' ) then
!atom(0:) => Fptr
atom => Fptr
else
atom => Fptr
end if
end subroutine lammps_extract_atom_dpa
subroutine lammps_extract_atom_dp2a (atom, ptr, name)
real (C_double), dimension(:,:), pointer, intent(out) :: atom
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
type (C_ptr) :: Cptr
type (C_ptr), pointer, dimension(:) :: Catom
integer (C_int), pointer :: nelements
if ( name /= 'x' .and. name /= 'v' .and. name /= 'f' .and. &
name /= 'mu' .and. name /= 'omega' .and. name /= 'tandque' .and. &
name /= 'angmom' .and. name /= 'fexternal' ) then
! We should not be getting a rank-2 array here!
call lammps_error_all (ptr, FLERR, 'You cannot extract those atom&
& data (' // trim(name) // ') into a rank 2 array.')
return
end if
Cptr = lammps_extract_atom_Cptr (ptr, name)
call lammps_extract_global_i (nelements, ptr, 'nlocal')
! Catom will now be the array of void* pointers that the void** pointer
! pointed to. Catom(1) is now the pointer to the first element.
call C_F_pointer (Cptr, Catom, (/nelements/))
! Now get the actual array, which has its shape transposed from what we
! might think of it in C
call C_F_pointer (Catom(1), atom, (/3, nelements/))
end subroutine lammps_extract_atom_dp2a
!-----------------------------------------------------------------------------
! lammps_extract_compute {{{2
function lammps_extract_compute_Cptr (ptr, id, style, type) result (compute)
type (C_ptr) :: compute
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type
integer (kind=C_int) :: Cstyle, Ctype
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
Cid = string2Cstring (id)
Cstyle = style
Ctype = type
compute = lammps_actual_extract_compute (ptr, Cid, Cstyle, Ctype)
end function lammps_extract_compute_Cptr
subroutine lammps_extract_compute_dp (compute, ptr, id, style, type)
real (C_double), pointer, intent(out) :: compute
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type
type (C_ptr) :: Cptr
! The only valid values of (style,type) are (0,0) for scalar 'compute'
if ( style /= 0 ) then
call lammps_error_all (ptr, FLERR, 'You cannot pack per-atom/local&
& data into a scalar.')
return
end if
if ( type == 1 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& vector (rank 1) into a scalar.')
return
else if ( type == 2 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& array (rank 2) into a scalar.')
return
end if
Cptr = lammps_extract_compute_Cptr (ptr, id, style, type)
call C_F_pointer (Cptr, compute)
end subroutine lammps_extract_compute_dp
subroutine lammps_extract_compute_dpa (compute, ptr, id, style, type)
real (C_double), dimension(:), pointer, intent(out) :: compute
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type
type (C_ptr) :: Cptr
integer :: nelements
! Check for the correct dimensionality
if ( type == 0 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& scalar (rank 0) into a rank 1 variable.')
return
else if ( type == 2 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& array (rank 2) into a rank 1 variable.')
return
end if
nelements = lammps_extract_compute_vectorsize (ptr, id, style)
Cptr = lammps_extract_compute_Cptr (ptr, id, style, type)
call C_F_pointer (Cptr, compute, (/nelements/))
end subroutine lammps_extract_compute_dpa
subroutine lammps_extract_compute_dp2a (compute, ptr, id, style, type)
real (C_double), dimension(:,:), pointer, intent(out) :: compute
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type
type (C_ptr) :: Cptr
type (C_ptr), pointer, dimension(:) :: Ccompute
integer :: nr, nc
! Check for the correct dimensionality
if ( type == 0 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& scalar (rank 0) into a rank 2 variable.')
return
else if ( type == 1 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a compute&
& array (rank 1) into a rank 2 variable.')
return
end if
call lammps_extract_compute_arraysize (ptr, id, style, nr, nc)
Cptr = lammps_extract_compute_Cptr (ptr, id, style, type)
call C_F_pointer (Cptr, Ccompute, (/nr/))
! Note that the matrix is transposed, from Fortran's perspective
call C_F_pointer (Ccompute(1), compute, (/nc, nr/))
end subroutine lammps_extract_compute_dp2a
!-----------------------------------------------------------------------------
! lammps_extract_fix {{{2
function lammps_extract_fix_Cptr (ptr, id, style, type, i, j) &
result (fix)
type (C_ptr) :: fix
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type, i, j
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
integer (kind=C_int) :: Cstyle, Ctype, Ci, Cj
Cid = string2Cstring (id)
Cstyle = style
Ctype = type
Ci = i - 1 ! This is for consistency with the values from f_ID[i],
Cj = j - 1 ! which is different from what library.cpp uses!
if ( (type >= 1 .and. Ci < 0) .or. &
(type == 2 .and. (Ci < 0 .or. Cj < 0) ) ) then
call lammps_error_all (ptr, FLERR, 'Index out of range in&
& lammps_extract_fix')
end if
fix = lammps_actual_extract_fix (ptr, Cid, Cstyle, Ctype, Ci, Cj)
end function lammps_extract_fix_Cptr
subroutine lammps_extract_fix_dp (fix, ptr, id, style, type, i, j)
real (C_double), intent(out) :: fix
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type, i, j
type (C_ptr) :: Cptr
real (C_double), pointer :: Fptr
! Check for the correct dimensionality
if ( style /= 0 ) then
select case (type)
case (0)
call lammps_error_all (ptr, FLERR, 'There is no per-atom or local&
& scalar data available from fixes.')
case (1)
call lammps_error_all (ptr, FLERR, 'You cannot extract a fix''s &
&per-atom/local vector (rank 1) into a scalar.')
case (2)
call lammps_error_all (ptr, FLERR, 'You cannot extract a fix''s &
&per-atom/local array (rank 2) into a scalar.')
case default
call lammps_error_all (ptr, FLERR, 'Invalid extract_fix style/&
&type combination.')
end select
return
end if
Cptr = lammps_extract_fix_Cptr (ptr, id, style, type, i, j)
call C_F_pointer (Cptr, Fptr)
fix = Fptr
nullify (Fptr)
! Memory is only allocated for "global" fix variables
if ( style == 0 ) call lammps_free (Cptr)
end subroutine lammps_extract_fix_dp
subroutine lammps_extract_fix_dpa (fix, ptr, id, style, type, i, j)
real (C_double), dimension(:), pointer, intent(out) :: fix
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type, i, j
type (C_ptr) :: Cptr
integer :: fix_len
! Check for the correct dimensionality
if ( style == 0 ) then
call lammps_error_all (ptr, FLERR, 'You can''t extract the&
& whole vector from global fix data')
return
else if ( type == 0 ) then
call lammps_error_all (ptr, FLERR, 'You can''t extract a fix&
& scalar into a rank 1 variable')
return
else if ( type == 2 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a fix&
& array into a rank 1 variable.')
return
else if ( type /= 1 ) then
call lammps_error_all (ptr, FLERR, 'Invalid type for fix extraction.')
return
end if
fix_len = lammps_extract_fix_vectorsize (ptr, id, style)
call C_F_pointer (Cptr, fix, (/fix_len/))
! Memory is only allocated for "global" fix variables, which we should
! never get here, so no need to call lammps_free!
end subroutine lammps_extract_fix_dpa
subroutine lammps_extract_fix_dp2a (fix, ptr, id, style, type, i, j)
real (C_double), dimension(:,:), pointer, intent(out) :: fix
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style, type, i, j
type (C_ptr) :: Cptr
type (C_ptr), pointer, dimension(:) :: Cfix
integer :: nr, nc
! Check for the correct dimensionality
if ( style == 0 ) then
call lammps_error_all (ptr, FLERR, 'It is not possible to extract the&
& entire array from global fix data.')
return
else if ( type == 0 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a fix&
& scalar (rank 0) into a rank 2 variable.')
return
else if ( type == 1 ) then
call lammps_error_all (ptr, FLERR, 'You cannot extract a fix&
& vector (rank 1) into a rank 2 variable.')
return
end if
call lammps_extract_fix_arraysize (ptr, id, style, nr, nc)
! Extract pointer to first element as Cfix(1)
call C_F_pointer (Cptr, Cfix, (/nr/))
! Now extract the array, which is transposed
call C_F_pointer (Cfix(1), fix, (/nc, nr/))
end subroutine lammps_extract_fix_dp2a
!-----------------------------------------------------------------------------
! lammps_extract_variable {{{2
function lammps_extract_variable_Cptr (ptr, name, group) result (variable)
type (C_ptr) :: ptr, variable
character (len=*) :: name
character (len=*), optional :: group
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
character (kind=C_char), dimension(:), allocatable :: Cgroup
Cname = string2Cstring (name)
if ( present(group) ) then
allocate (Cgroup(len_trim(group)+1))
Cgroup = string2Cstring (group)
else
allocate (Cgroup(1))
Cgroup(1) = C_NULL_CHAR
end if
variable = lammps_actual_extract_variable (ptr, Cname, Cgroup)
deallocate (Cgroup)
end function lammps_extract_variable_Cptr
subroutine lammps_extract_variable_dp (variable, ptr, name, group)
real (C_double), intent(out) :: variable
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
character (len=*), intent(in), optional :: group
type (C_ptr) :: Cptr
real (C_double), pointer :: Fptr
if ( present(group) ) then
Cptr = lammps_extract_variable_Cptr (ptr, name, group)
else
Cptr = lammps_extract_variable_Cptr (ptr, name)
end if
call C_F_pointer (Cptr, Fptr)
variable = Fptr
nullify (Fptr)
call lammps_free (Cptr)
end subroutine lammps_extract_variable_dp
subroutine lammps_extract_variable_dpa (variable, ptr, name, group)
real (C_double), dimension(:), allocatable, intent(out) :: variable
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
character (len=*), intent(in), optional :: group
type (C_ptr) :: Cptr
real (C_double), dimension(:), pointer :: Fptr
integer :: natoms
if ( present(group) ) then
Cptr = lammps_extract_variable_Cptr (ptr, name, group)
else
Cptr = lammps_extract_variable_Cptr (ptr, name)
end if
natoms = lammps_get_natoms (ptr)
allocate (variable(natoms))
call C_F_pointer (Cptr, Fptr, (/natoms/))
variable = Fptr
nullify (Fptr)
call lammps_free (Cptr)
end subroutine lammps_extract_variable_dpa
!-------------------------------------------------------------------------2}}}
subroutine lammps_gather_atoms_ia (ptr, name, count, data)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
integer, intent(in) :: count
integer, dimension(:), allocatable, intent(out) :: data
type (C_ptr) :: Cdata
integer (C_int), dimension(:), pointer :: Fdata
integer (C_int) :: natoms
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
integer (C_int), parameter :: Ctype = 0_C_int
integer (C_int) :: Ccount
natoms = lammps_get_natoms (ptr)
Cname = string2Cstring (name)
if ( count /= 1 .and. count /= 3 ) then
call lammps_error_all (ptr, FLERR, 'lammps_gather_atoms requires&
& count to be either 1 or 3')
else
Ccount = count
end if
allocate ( Fdata(count*natoms) )
allocate ( data(count*natoms) )
Cdata = C_loc (Fdata(1))
call lammps_actual_gather_atoms (ptr, Cname, Ctype, Ccount, Cdata)
data = Fdata
deallocate (Fdata)
end subroutine lammps_gather_atoms_ia
subroutine lammps_gather_atoms_dpa (ptr, name, count, data)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
integer, intent(in) :: count
double precision, dimension(:), allocatable, intent(out) :: data
type (C_ptr) :: Cdata
real (C_double), dimension(:), pointer :: Fdata
integer (C_int) :: natoms
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
integer (C_int), parameter :: Ctype = 1_C_int
integer (C_int) :: Ccount
natoms = lammps_get_natoms (ptr)
Cname = string2Cstring (name)
if ( count /= 1 .and. count /= 3 ) then
call lammps_error_all (ptr, FLERR, 'lammps_gather_atoms requires&
& count to be either 1 or 3')
else
Ccount = count
end if
allocate ( Fdata(count*natoms) )
allocate ( data(count*natoms) )
Cdata = C_loc (Fdata(1))
call lammps_actual_gather_atoms (ptr, Cname, Ctype, Ccount, Cdata)
data = Fdata(:)
deallocate (Fdata)
end subroutine lammps_gather_atoms_dpa
!-----------------------------------------------------------------------------
subroutine lammps_scatter_atoms_ia (ptr, name, data)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
integer, dimension(:), intent(in) :: data
integer (kind=C_int) :: natoms, Ccount
integer (kind=C_int), parameter :: Ctype = 0_C_int
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
integer (C_int), dimension(size(data)), target :: Fdata
type (C_ptr) :: Cdata
natoms = lammps_get_natoms (ptr)
Cname = string2Cstring (name)
Ccount = size(data) / natoms
if ( Ccount /= 1 .and. Ccount /= 3 ) &
call lammps_error_all (ptr, FLERR, 'lammps_gather_atoms requires&
& count to be either 1 or 3')
Fdata = data
Cdata = C_loc (Fdata(1))
call lammps_actual_scatter_atoms (ptr, Cname, Ctype, Ccount, Cdata)
end subroutine lammps_scatter_atoms_ia
subroutine lammps_scatter_atoms_dpa (ptr, name, data)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: name
double precision, dimension(:), intent(in) :: data
integer (kind=C_int) :: natoms, Ccount
integer (kind=C_int), parameter :: Ctype = 1_C_int
character (kind=C_char), dimension(len_trim(name)+1) :: Cname
real (C_double), dimension(size(data)), target :: Fdata
type (C_ptr) :: Cdata
natoms = lammps_get_natoms (ptr)
Cname = string2Cstring (name)
Ccount = size(data) / natoms
if ( Ccount /= 1 .and. Ccount /= 3 ) &
call lammps_error_all (ptr, FLERR, 'lammps_gather_atoms requires&
& count to be either 1 or 3')
Fdata = data
Cdata = C_loc (Fdata(1))
call lammps_actual_scatter_atoms (ptr, Cname, Ctype, Ccount, Cdata)
end subroutine lammps_scatter_atoms_dpa
!-----------------------------------------------------------------------------
function lammps_extract_compute_vectorsize (ptr, id, style) &
result (vectorsize)
integer :: vectorsize
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style
integer (C_int) :: Cvectorsize, Cstyle
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
Cid = string2Cstring (id)
Cstyle = int(style, C_int)
Cvectorsize = lammps_actual_extract_compute_vectorsize (ptr, Cid, Cstyle)
vectorsize = int(Cvectorsize, kind(vectorsize))
end function lammps_extract_compute_vectorsize
!-----------------------------------------------------------------------------
function lammps_extract_fix_vectorsize (ptr, id, style) &
result (vectorsize)
integer :: vectorsize
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style
integer (C_int) :: Cvectorsize, Cstyle
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
Cid = string2Cstring (id)
Cstyle = int(style, C_int)
Cvectorsize = lammps_actual_extract_fix_vectorsize (ptr, Cid, Cstyle)
vectorsize = int(Cvectorsize, kind(vectorsize))
end function lammps_extract_fix_vectorsize
!-----------------------------------------------------------------------------
subroutine lammps_extract_compute_arraysize (ptr, id, style, nrows, ncols)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style
integer, intent(out) :: nrows, ncols
integer (C_int) :: Cstyle, Cnrows, Cncols
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
Cid = string2Cstring (id)
Cstyle = int (style, C_int)
call lammps_actual_extract_compute_arraysize (ptr, Cid, Cstyle, &
Cnrows, Cncols)
nrows = int (Cnrows, kind(nrows))
ncols = int (Cncols, kind(ncols))
end subroutine lammps_extract_compute_arraysize
!-----------------------------------------------------------------------------
subroutine lammps_extract_fix_arraysize (ptr, id, style, nrows, ncols)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: id
integer, intent(in) :: style
integer, intent(out) :: nrows, ncols
integer (C_int) :: Cstyle, Cnrows, Cncols
character (kind=C_char), dimension(len_trim(id)+1) :: Cid
Cid = string2Cstring (id)
Cstyle = int (style, kind(Cstyle))
call lammps_actual_extract_fix_arraysize (ptr, Cid, Cstyle, &
Cnrows, Cncols)
nrows = int (Cnrows, kind(nrows))
ncols = int (Cncols, kind(ncols))
end subroutine lammps_extract_fix_arraysize
!-----------------------------------------------------------------------------
subroutine lammps_error_all (ptr, file, line, str)
type (C_ptr), intent(in) :: ptr
character (len=*), intent(in) :: file, str
integer, intent(in) :: line
character (kind=C_char), dimension(len_trim(file)+1) :: Cfile
character (kind=C_char), dimension(len_trim(str)+1) :: Cstr
integer (C_int) :: Cline
Cline = int(line, kind(Cline))
Cfile = string2Cstring (file)
Cstr = string2Cstring (str)
call lammps_actual_error_all (ptr, Cfile, Cline, Cstr)
end subroutine lammps_error_all
!-----------------------------------------------------------------------------
! Locally defined helper functions {{{1
pure function string2Cstring (string) result (C_string)
use, intrinsic :: ISO_C_binding, only : C_char, C_NULL_CHAR
character (len=*), intent(in) :: string
character (len=1, kind=C_char) :: C_string (len_trim(string)+1)
integer :: i, n
n = len_trim (string)
forall (i = 1:n)
C_string(i) = string(i:i)
end forall
C_string(n+1) = C_NULL_CHAR
end function string2Cstring
!-----------------------------------------------------------------------------
subroutine Cstring2argcargv (Cstring, argc, argv)
!! Converts a C-style string to argc and argv, that is, words in Cstring
!! become C-style strings in argv. IMPORTANT: Cstring is modified by
!! this routine! I would make Cstring local TO this routine and accept
!! a Fortran-style string instead, but we run into scoping and
!! allocation problems that way. This routine assumes the string is
!! null-terminated, as all C-style strings must be.
character (kind=C_char), dimension(*), target, intent(inout) :: Cstring
integer (C_int), intent(out) :: argc
type (C_ptr), dimension(:), allocatable, intent(out) :: argv
integer :: StringStart, SpaceIndex, strlen, argnum
argc = 1_C_int
! Find the length of the string
strlen = 1
do while ( Cstring(strlen) /= C_NULL_CHAR )
strlen = strlen + 1
end do
! Find the number of non-escaped spaces
SpaceIndex = 2
do while ( SpaceIndex < strlen )
if ( Cstring(SpaceIndex) == ' ' .and. &
Cstring(SpaceIndex-1) /= '\' ) then
argc = argc + 1_C_int
! Find the next non-space character
do while ( Cstring(SpaceIndex+1) == ' ')
SpaceIndex = SpaceIndex + 1
end do
end if
SpaceIndex = SpaceIndex + 1
end do
! Now allocate memory for argv
allocate (argv(argc))
! Now find the string starting and ending locations
StringStart = 1
SpaceIndex = 2
argnum = 1
do while ( SpaceIndex < strlen )
if ( Cstring(SpaceIndex) == ' ' .and. &
Cstring(SpaceIndex-1) /= '\' ) then
! Found a real space => split strings and store this one
Cstring(Spaceindex) = C_NULL_CHAR ! Replaces space with NULL
argv(argnum) = C_loc(Cstring(StringStart))
argnum = argnum + 1
! Find the next non-space character
do while ( Cstring(SpaceIndex+1) == ' ')
SpaceIndex = SpaceIndex + 1
end do
StringStart = SpaceIndex + 1
else if ( Cstring(SpaceIndex) == ' ' .and. &
Cstring(SpaceIndex-1) == '\' ) then
! Escaped space => remove backslash and move rest of array
Cstring(SpaceIndex-1:strlen-1) = Cstring(SpaceIndex:strlen)
strlen = strlen - 1 ! Last character is still C_NULL_CHAR
end if
SpaceIndex = SpaceIndex + 1
end do
! Now handle the last argument
argv(argnum) = C_loc(Cstring(StringStart))
end subroutine Cstring2argcargv
! 1}}}
end module LAMMPS
! vim: foldmethod=marker tabstop=3 softtabstop=3 shiftwidth=3 expandtab
diff --git a/examples/COUPLE/fortran3/README b/examples/COUPLE/fortran_dftb/README
similarity index 78%
rename from examples/COUPLE/fortran3/README
rename to examples/COUPLE/fortran_dftb/README
index 9effa35ec..39a2f1816 100644
--- a/examples/COUPLE/fortran3/README
+++ b/examples/COUPLE/fortran_dftb/README
@@ -1,33 +1,37 @@
This directory has an example of using a callback function to obtain
forces from a fortran code for a LAMMPS simulation. The reader should
refer to the README file in COUPLE/fortran2 before proceeding. Here,
the LAMMPS.F90 file has been modified slightly and additional files
named LAMMPS-wrapper2.h and LAMMPS-wrapper2.cpp have been included in
-order to supply wrapper functions to set the LAMMPS callback function
-and total energy.
+order to supply wrapper functions to set the LAMMPS callback function,
+total energy, virial, and electronic entropy contribution (needed for
+MSST simulations with a quantum code).
In this example, the callback function is set to run the
semi-empirical quantum code DFTB+ in serial and then read in the total
energy, forces, and stress tensor from file. In this case, nlocal =
the total number of atoms in the system, so particle positions can be
read from the pos array directly, and DFTB+ forces can simply be
included via the fext array. The user should take care in the case of
a parallel calculation, where LAMMPS can assign different particules
to each processor. For example, the user should use functions such as
lammps_gather_atoms() and lammps_scatter_atoms() in the case where the
fortran force calculating code requires the positions of all atoms,
etc.
A few more important notes:
--The stress tensor from DFTB+ is passed in to LAMMPS via pointer.
-Calling the subroutine lammps_set_callback() is required in order to set
a pointer to the callback function in LAMMPS.
-The subroutine lammps_set_user_energy() passes in the potential energy
- from DFTB+ to LAMMPS.
+ from DFTB+ to LAMMPS. Similarly, lammps_set_user_virial passes the stress tensor.
+
+-The electronic entropy contribution is set via lammps_set_external_vector(). Their needs
+ to be a call to lammps_set_external_vector_length() before this value can be
+ passed to LAMMPS.
This example was created by Nir Goldman, whom you can contact with
questions:
Nir Goldman, LLNL
ngoldman@llnl.gov
diff --git a/examples/COUPLE/fortran3/data.diamond b/examples/COUPLE/fortran_dftb/data.diamond
similarity index 100%
rename from examples/COUPLE/fortran3/data.diamond
rename to examples/COUPLE/fortran_dftb/data.diamond
diff --git a/examples/COUPLE/fortran_dftb/dftb_in.hsd b/examples/COUPLE/fortran_dftb/dftb_in.hsd
new file mode 100644
index 000000000..104a4c04c
--- /dev/null
+++ b/examples/COUPLE/fortran_dftb/dftb_in.hsd
@@ -0,0 +1,40 @@
+#sample DFTB+ script to run this test code
+Geometry = GenFormat {
+<<< "lammps.gen"
+}
+
+Driver = {
+}
+
+Hamiltonian = DFTB {
+ LAMMPS = Yes # keyword to print energy, forces, and stress tensor to file(results.out)
+ SCC = No
+ MaxAngularMomentum = {
+ C = "p"
+ }
+ Charge = 0.0
+ Eigensolver = Standard {}
+ Filling = Fermi {
+ Temperature [Kelvin] = 298.0
+ }
+ SlaterKosterFiles = Type2FileNames {
+ Prefix = "~/slako/mio-1-1/" # the user must define the location of the skf files
+ Separator = "-"
+ Suffix = ".skf"
+ LowerCaseTypeName = No
+ }
+ KPointsAndWeights = {
+ 0.0000000000000 0.0000000000000 0.0000000000000 1.00000000000000
+ }
+}
+
+Options = {
+ CalculateForces = Yes
+ WriteDetailedOut = No
+ WriteBandOut = No
+ RandomSeed = 12345
+}
+
+ParserOptions = {
+ ParserVersion = 3
+}
diff --git a/examples/COUPLE/fortran_dftb/dftb_pin.hsd b/examples/COUPLE/fortran_dftb/dftb_pin.hsd
new file mode 100644
index 000000000..6d9dea4a1
--- /dev/null
+++ b/examples/COUPLE/fortran_dftb/dftb_pin.hsd
@@ -0,0 +1,129 @@
+Geometry = GenFormat {
+64 S
+C
+1 1 7.099007 7.117657 7.119139
+2 1 0.858709 0.867233 0.882294
+3 1 1.772527 1.811776 7.120239
+4 1 2.702145 2.681271 0.901362
+5 1 0.017539 1.794455 1.788454
+6 1 0.885593 2.694118 2.707994
+7 1 1.795055 7.120787 1.777896
+8 1 2.642849 0.868278 2.670699
+9 1 0.016060 0.017156 3.568644
+10 1 0.891891 0.896406 4.439286
+11 1 1.766086 1.764402 3.550134
+12 1 2.677349 2.648926 4.427174
+13 1 0.010133 1.771283 5.342173
+14 1 0.858153 2.653565 6.241596
+15 1 1.804087 0.020636 5.353268
+16 1 2.689680 0.907188 6.224575
+17 1 0.017845 3.577563 7.113016
+18 1 0.910027 4.459286 0.910286
+19 1 1.766394 5.376046 0.015526
+20 1 2.683727 6.220728 0.898553
+21 1 0.003357 5.363423 1.774139
+22 1 0.856735 6.238324 2.660213
+23 1 1.761079 3.549776 1.797054
+24 1 2.667227 4.463441 2.646074
+25 1 7.132499 3.551558 3.599764
+26 1 0.920387 4.482191 4.479257
+27 1 1.772194 5.337132 3.555569
+28 1 2.675010 6.251629 4.483124
+29 1 0.005702 5.371095 5.351147
+30 1 0.880807 6.249819 6.264231
+31 1 1.793177 3.592396 5.369939
+32 1 2.653179 4.463595 6.274044
+33 1 3.557243 7.118913 0.026006
+34 1 4.458971 0.889331 0.904950
+35 1 5.367903 1.759757 7.104941
+36 1 6.271565 2.658454 0.890168
+37 1 3.591915 1.768681 1.793880
+38 1 4.435612 2.662184 2.676722
+39 1 5.371040 0.000196 1.783464
+40 1 6.226453 0.886640 2.653384
+41 1 3.583339 0.005449 3.600177
+42 1 4.453692 0.909417 4.459713
+43 1 5.314554 1.805409 3.584215
+44 1 6.210181 2.642660 4.486206
+45 1 3.545704 1.802745 5.365369
+46 1 4.476660 2.701226 6.220451
+47 1 5.332820 0.029557 5.347965
+48 1 6.215725 0.915081 6.230289
+49 1 3.536446 3.551469 7.106600
+50 1 4.451181 4.426439 0.900180
+51 1 5.368735 5.377996 7.109524
+52 1 6.230666 6.220985 0.862175
+53 1 3.596626 5.372822 1.797613
+54 1 4.485613 6.221252 2.699652
+55 1 5.364421 3.549838 1.796281
+56 1 6.261739 4.459046 2.648152
+57 1 3.588752 3.581054 3.581755
+58 1 4.462342 4.467270 4.478800
+59 1 5.355202 5.318323 3.556531
+60 1 6.268570 6.259831 4.465795
+61 1 3.588636 5.354278 5.362327
+62 1 4.475747 6.263866 6.227803
+63 1 5.331158 3.554349 5.318368
+64 1 6.254581 4.436344 6.209681
+0.0 0.0 0.0
+7.13400000000000 0 0
+0 7.13400000000000 0
+0 0 7.13400000000000
+}
+Driver = {}
+Hamiltonian = DFTB {
+ LAMMPS = Yes
+ SCC = No
+ MaxAngularMomentum = {
+ C = "p"
+ }
+ Charge = 0.0
+ Eigensolver = Standard {}
+ Filling = Fermi {
+ Temperature [Kelvin] = 298.0
+ IndependentKFilling = No
+ }
+ SlaterKosterFiles = Type2FileNames {
+ Prefix = "~/slako/mio-1-1/"
+ Separator = "-"
+ Suffix = ".skf"
+ LowerCaseTypeName = No
+ }
+ KPointsAndWeights = {
+0.0000000000000 0.0000000000000 0.0000000000000 1.00000000000000
+ }
+ PolynomialRepulsive = {}
+ OldRepulsiveSum = No
+ OrbitalResolvedSCC = No
+ OldSKInterpolation = No
+ NoErep = No
+ Dispersion = {}
+ ThirdOrder = No
+ ThirdOrderFull = No
+}
+Options = {
+ CalculateForces = Yes
+ WriteDetailedOut = No
+ WriteBandOut = No
+ RandomSeed = 12345
+ MullikenAnalysis = No
+ WriteEigenvectors = No
+ WriteAutotestTag = No
+ WriteDetailedXML = No
+ WriteResultsTag = No
+ AtomResolvedEnergies = No
+ WriteHS = No
+ WriteRealHS = No
+ MinimiseMemoryUsage = No
+ ShowFoldedCoords = No
+}
+ParserOptions = {
+ ParserVersion = 3
+ WriteHSDInput = Yes
+ WriteXMLInput = No
+ StopAfterParsing = No
+ IgnoreUnprocessedNodes = No
+}
+Analysis = {
+ ProjectStates = {}
+}
diff --git a/examples/COUPLE/fortran3/in.simple b/examples/COUPLE/fortran_dftb/in.simple
similarity index 100%
rename from examples/COUPLE/fortran3/in.simple
rename to examples/COUPLE/fortran_dftb/in.simple
diff --git a/examples/COUPLE/fortran_dftb/log.simple b/examples/COUPLE/fortran_dftb/log.simple
new file mode 100644
index 000000000..3496e94eb
--- /dev/null
+++ b/examples/COUPLE/fortran_dftb/log.simple
@@ -0,0 +1,71 @@
+LAMMPS (6 Jul 2017)
+units real
+atom_style charge
+atom_modify map array
+atom_modify sort 0 0.0
+read_data data.diamond
+ triclinic box = (0 0 0) to (7.134 7.134 7.134) with tilt (0 0 0)
+ 1 by 1 by 1 MPI processor grid
+ reading atoms ...
+ 64 atoms
+ reading velocities ...
+ 64 velocities
+neighbor 1.0 bin
+neigh_modify delay 0 every 5 check no
+fix 1 all nve
+fix 2 all external pf/callback 1 1
+
+fix_modify 2 energy yes
+thermo_style custom step temp etotal ke pe lx ly lz pxx pyy pzz press
+
+thermo 1
+timestep 0.5
+
+run 10
+Neighbor list info ...
+ update every 5 steps, delay 0 steps, check no
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0
+ ghost atom cutoff = 0
+ binsize = 7.134, bins = 1 1 1
+ 0 neighbor lists, perpetual/occasional/extra = 0 0 0
+Per MPI rank memory allocation (min/avg/max) = 2.3 | 2.3 | 2.3 Mbytes
+Step Temp TotEng KinEng PotEng Lx Ly Lz Pxx Pyy Pzz Press
+ 0 298.24835 -69593.587 56.008365 -69649.595 7.134 7.134 7.134 -19980.19 -21024.038 -21097.458 -20700.562
+ 1 295.24358 -69593.585 55.444098 -69649.029 7.134 7.134 7.134 -19778.833 -20799.657 -20854.156 -20477.549
+ 2 286.37211 -69593.58 53.778115 -69647.358 7.134 7.134 7.134 -19227.52 -20177.28 -20176.12 -19860.306
+ 3 272.062 -69593.572 51.090804 -69644.663 7.134 7.134 7.134 -18360.869 -19189.684 -19100.021 -18883.525
+ 4 253.01834 -69593.561 47.514575 -69641.075 7.134 7.134 7.134 -17198.143 -17855.03 -17652.036 -17568.403
+ 5 230.19242 -69593.547 43.228073 -69636.775 7.134 7.134 7.134 -15750.247 -16183.764 -15854.145 -15929.386
+ 6 204.71787 -69593.533 38.44418 -69631.977 7.134 7.134 7.134 -14083.498 -14247.434 -13789.835 -14040.256
+ 7 177.82397 -69593.518 33.393748 -69626.911 7.134 7.134 7.134 -12340.963 -12202.878 -11623.171 -12055.671
+ 8 150.76736 -69593.503 28.312758 -69621.816 7.134 7.134 7.134 -10637.824 -10180.827 -9495.0496 -10104.567
+ 9 124.7737 -69593.49 23.431383 -69616.921 7.134 7.134 7.134 -9113.3842 -8339.0492 -7572.8076 -8341.747
+ 10 100.98183 -69593.478 18.963481 -69612.442 7.134 7.134 7.134 -7833.9349 -6756.9749 -5945.8968 -6845.6022
+Loop time of 2.20497 on 1 procs for 10 steps with 64 atoms
+
+Performance: 0.196 ns/day, 122.499 hours/ns, 4.535 timesteps/s
+0.2% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0 | 0 | 0 | 0.0 | 0.00
+Neigh | 1.4305e-06 | 1.4305e-06 | 1.4305e-06 | 0.0 | 0.00
+Comm | 4.22e-05 | 4.22e-05 | 4.22e-05 | 0.0 | 0.00
+Output | 0.00067687 | 0.00067687 | 0.00067687 | 0.0 | 0.03
+Modify | 2.2042 | 2.2042 | 2.2042 | 0.0 | 99.96
+Other | | 6.533e-05 | | | 0.00
+
+Nlocal: 64 ave 64 max 64 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 0 ave 0 max 0 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 0 ave 0 max 0 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 0
+Ave neighs/atom = 0
+Neighbor list builds = 2
+Dangerous builds not checked
+Total wall time: 0:00:02
diff --git a/examples/COUPLE/fortran3/makefile b/examples/COUPLE/fortran_dftb/makefile
similarity index 95%
rename from examples/COUPLE/fortran3/makefile
rename to examples/COUPLE/fortran_dftb/makefile
index 86dea3085..225bd0025 100644
--- a/examples/COUPLE/fortran3/makefile
+++ b/examples/COUPLE/fortran_dftb/makefile
@@ -1,45 +1,45 @@
SHELL = /bin/sh
# Path to LAMMPS extraction directory
LAMMPS_ROOT = ../../..
LAMMPS_SRC = $(LAMMPS_ROOT)/src
# Uncomment the line below if using the MPI stubs library
MPI_STUBS = #-I$(LAMMPS_SRC)/STUBS
FC = mpif90 # replace with your Fortran compiler
CXX = mpicc # replace with your C++ compiler
# Flags for Fortran compiler, C++ compiler, and C preprocessor, respectively
FFLAGS = -O2 -fPIC
CXXFLAGS = -O2 -fPIC
CPPFLAGS = -DOMPI_SKIP_MPICXX=1 -DMPICH_SKIP_MPICXX
all : liblammps_fortran.a liblammps_fortran.so simpleF.x
liblammps_fortran.so : LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o
$(FC) $(FFLAGS) -shared -o $@ $^
simpleF.x: simple.o LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o
- $(FC) $(FFLAGS) simple.o -o simpleF.x liblammps_fortran.a $(LAMMPS_SRC)/liblammps_mvapich.a -lstdc++ /usr/local/tools/fftw/lib/libfftw.a
+ $(FC) $(FFLAGS) simple.o -o simpleF.x liblammps_fortran.a $(LAMMPS_SRC)/liblammps_mvapich.a -lstdc++ /usr/lib64/libfftw3.a
liblammps_fortran.a : LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o
$(AR) rs $@ $^
LAMMPS.o lammps.mod : LAMMPS.F90
$(FC) $(CPPFLAGS) $(FFLAGS) -c $<
simple.o : simple.f90
$(FC) $(FFLAGS) -c $<
LAMMPS-wrapper.o : LAMMPS-wrapper.cpp LAMMPS-wrapper.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -I$(LAMMPS_SRC) $(MPI_STUBS)
LAMMPS-wrapper2.o : LAMMPS-wrapper2.cpp LAMMPS-wrapper2.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -I$(LAMMPS_SRC) $(MPI_STUBS)
clean :
$(RM) *.o *.mod liblammps_fortran.a liblammps_fortran.so
dist :
tar -czvf fortran-interface-callback.tar.gz LAMMPS-wrapper.h LAMMPS-wrapper.cpp LAMMPS-wrapper2.h LAMMPS-wrapper2.cpp LAMMPS.F90 makefile README simple.f90
diff --git a/examples/COUPLE/fortran3/simple.f90 b/examples/COUPLE/fortran_dftb/simple.f90
similarity index 91%
rename from examples/COUPLE/fortran3/simple.f90
rename to examples/COUPLE/fortran_dftb/simple.f90
index 40f8bf8b8..4604b4e4a 100644
--- a/examples/COUPLE/fortran3/simple.f90
+++ b/examples/COUPLE/fortran_dftb/simple.f90
@@ -1,114 +1,110 @@
module callback
implicit none
contains
subroutine fortran_callback(lmp, timestep, nlocal, ids, c_pos, c_fext) &
& bind(C, name='f_callback')
use, intrinsic :: ISO_C_binding
use LAMMPS
implicit none
type (C_ptr), value :: lmp
integer(C_int64_t), intent(in), value :: timestep
integer(C_int), intent(in), value :: nlocal
real (C_double), dimension(:,:), pointer :: x
type(c_ptr) :: c_pos, c_fext, c_ids
double precision, pointer :: fext(:,:), pos(:,:)
integer, intent(in) :: ids(nlocal)
- real (C_double), dimension(:), pointer :: virial => NULL()
+ real(C_double) :: virial(6)
real (C_double) :: etot
real(C_double), pointer :: ts_lmp
double precision :: stress(3,3), ts_dftb
integer :: natom , i
real (C_double), parameter :: econv = 627.4947284155114 ! converts from Ha to
double precision, parameter :: fconv = 1185.793095983065 ! converts from Ha/bohr to
double precision, parameter :: autoatm = 2.9037166638E8
double precision lx, ly, lz
real (C_double), pointer :: boxxlo, boxxhi
real (C_double), pointer :: boxylo, boxyhi
real (C_double), pointer :: boxzlo, boxzhi
double precision, parameter :: nktv2p = 68568.4149999999935972
double precision :: volume
type (C_ptr) :: Cptr
type (C_ptr), pointer, dimension(:) :: Catom
call c_f_pointer(c_pos, pos, [3,nlocal])
call c_f_pointer(c_fext, fext, [3,nlocal])
call lammps_extract_global(boxxlo, lmp, 'boxxlo')
call lammps_extract_global(boxxhi, lmp, 'boxxhi')
call lammps_extract_global(boxylo, lmp, 'boxylo')
call lammps_extract_global(boxyhi, lmp, 'boxyhi')
call lammps_extract_global(boxzlo, lmp, 'boxzlo')
call lammps_extract_global(boxzhi, lmp, 'boxzhi')
lx = boxxhi - boxxlo
ly = boxyhi - boxylo
lz = boxzhi - boxzlo
volume = lx*ly*lz
open (unit = 10, status = 'replace', action = 'write', file='lammps.gen')
write(10,*)nlocal,"S"
write(10,*) "C"
do i = 1, nlocal
write(10,'(2I,3F15.6)')i,1,pos(:,ids(i))
enddo
write(10,*)"0.0 0.0 0.0"
write(10,*)lx,0,0
write(10,*)0,ly,0
write(10,*)0,0,lz
close(10)
call system("./dftb+ > dftb.out")
open (unit = 10, status = 'old', file = 'results.out')
read(10,*)etot
read(10,*)ts_dftb
do i = 1, 3
read(10,*)stress(i,:)
enddo
stress (:,:) = stress(:,:)*autoatm
+ virial(1) = stress(1,1)/(nktv2p/volume)
+ virial(2) = stress(2,2)/(nktv2p/volume)
+ virial(3) = stress(3,3)/(nktv2p/volume)
+ virial(4) = stress(1,2)/(nktv2p/volume)
+ virial(5) = stress(1,3)/(nktv2p/volume)
+ virial(6) = stress(2,3)/(nktv2p/volume)
etot = etot*econv
- call lammps_extract_global(ts_lmp, lmp, 'TS_dftb')
- ts_lmp = ts_dftb
+ call lammps_set_external_vector(lmp,1,ts_dftb*econv)
do i = 1, nlocal
read(10,*)fext(:,ids(i))
fext(:,ids(i)) = fext(:,ids(i))*fconv
enddo
close(10)
call lammps_set_user_energy (lmp, etot)
- call lammps_extract_atom (virial, lmp, 'virial')
- if (.not. associated(virial)) then
- print*,'virial pointer not associated.'
- STOP
- endif
- virial(1) = stress(1,1)/(nktv2p/volume)
- virial(2) = stress(2,2)/(nktv2p/volume)
- virial(3) = stress(3,3)/(nktv2p/volume)
- virial(4) = stress(1,2)/(nktv2p/volume)
- virial(5) = stress(1,3)/(nktv2p/volume)
- virial(6) = stress(2,3)/(nktv2p/volume)
+ call lammps_set_user_virial (lmp, virial)
end subroutine
end module callback
program simple_fortran_callback
use MPI
use LAMMPS
use callback
use, intrinsic :: ISO_C_binding, only : C_double, C_ptr, C_int, C_FUNPTR
implicit none
type (C_ptr) :: lmp
integer :: error, narg, me, nprocs
call MPI_Init (error)
call MPI_Comm_rank (MPI_COMM_WORLD, me, error)
call MPI_Comm_size (MPI_COMM_WORLD, nprocs, error)
call lammps_open_no_mpi ('lmp -log log.simple', lmp)
call lammps_file (lmp, 'in.simple')
call lammps_set_callback(lmp)
+ call lammps_set_external_vector_length(lmp,2)
call lammps_command (lmp, 'run 10')
call lammps_close (lmp)
call MPI_Finalize (error)
end program simple_fortran_callback
diff --git a/examples/README b/examples/README
index e4312e259..0b037f5c3 100644
--- a/examples/README
+++ b/examples/README
@@ -1,178 +1,170 @@
LAMMPS example problems
There are 3 flavors of sub-directories in this file, each with sample
problems you can run with LAMMPS.
lower-case directories = simple test problems for LAMMPS and its packages
upper-case directories = more complex problems
USER directory with its own sub-directories = tests for USER packages
Each is discussed below.
------------------------------------------
Lower-case directories
Each of these sub-directories contains a sample problem you can run
with LAMMPS. Most are 2d models so that they run quickly, requiring a
few seconds to a few minutes to run on a desktop machine. Each
problem has an input script (in.*) and produces a log file (log.*) and
(optionally) a dump file (dump.*) or image files (image.*) or movie
(movie.mpg) when it runs. Some use a data file (data.*) of initial
coordinates as additional input. Some require that you install one or
more optional LAMMPS packages.
A few sample log file outputs on different machines and different
numbers of processors are included in the directories to compare your
answers to. E.g. a log file like log.crack.date.foo.P means it ran on
P processors of machine "foo" with the dated version of LAMMPS. Note
that these problems should get statistically similar answers when run
on different machines or different numbers of processors, but not
identical answers to those in the log of dump files included here.
See the Errors section of the LAMMPS documentation for more
discussion.
Most of the example input scripts have commented-out lines that
produce dump snapshots of the running simulation in any of 3 formats.
If you uncomment the dump command in the input script, a text dump
file will be produced, which can be animated by various visualization
programs (see http://lammps.sandia.gov/viz.html) such as Ovito, VMD,
or AtomEye.
If you uncomment the dump image command in the input script, and
assuming you have built LAMMPS with a JPG library, JPG snapshot images
will be produced when the simulation runs. They can be quickly
post-processed into a movie using commands described on the dump image
doc page.
If you uncomment the dump movie command in the input script, and
assuming you have built LAMMPS with the FFMPEG library, an MPG movie
will be produced when the simulation runs. The movie file can be
played using various viewers, such as mplayer or QuickTime.
Animations of many of these examples can be viewed on the Movies
section of the LAMMPS WWW Site.
These are the sample problems and their output in the various
sub-directories:
accelerate: use of all the various accelerator packages
+airebo: example for using AIREBO and AIREBO-M
balance: dynamic load balancing, 2d system
body: body particles, 2d system
cmap: CMAP 5-body contributions to CHARMM force field
colloid: big colloid particles in a small particle solvent, 2d system
comb: models using the COMB potential
coreshell: adiabatic core/shell model
controller: use of fix controller as a thermostat
crack: crack propagation in a 2d solid
deposit: deposition of atoms and molecules onto a 3d substrate
dipole: point dipolar particles, 2d system
dreiding: methanol via Dreiding FF
eim: NaCl using the EIM potential
ellipse: ellipsoidal particles in spherical solvent, 2d system
flow: Couette and Poiseuille flow in a 2d channel
friction: frictional contact of spherical asperities between 2d surfaces
gcmc: Grand Canonical Monte Carlo (GCMC) via the fix gcmc command
granregion: use of fix wall/region/gran as boundary on granular particles
hugoniostat: Hugoniostat shock dynamics
indent: spherical indenter into a 2d solid
kim: use of potentials in Knowledge Base for Interatomic Models (KIM)
meam: MEAM test for SiC and shear (same as shear examples)
melt: rapid melt of 3d LJ system
micelle: self-assembly of small lipid-like molecules into 2d bilayers
min: energy minimization of 2d LJ melt
mscg: parameterize a multi-scale coarse-graining (MSCG) model
msst: MSST shock dynamics
nb3b: use of nonbonded 3-body harmonic pair style
neb: nudged elastic band (NEB) calculation for barrier finding
nemd: non-equilibrium MD of 2d sheared system
obstacle: flow around two voids in a 2d channel
peptide: dynamics of a small solvated peptide chain (5-mer)
peri: Peridynamic model of cylinder impacted by indenter
pour: pouring of granular particles into a 3d box, then chute flow
prd: parallel replica dynamics of vacancy diffusion in bulk Si
python: use of PYTHON package to invoke Python code from input script
qeq: use of QEQ package for charge equilibration
reax: RDX and TATB models using the ReaxFF
rigid: rigid bodies modeled as independent or coupled
shear: sideways shear applied to 2d solid, with and without a void
snap: use of SNAP potential for Ta
srd: stochastic rotation dynamics (SRD) particles as solvent
snap: NVE dynamics for BCC tantalum crystal using SNAP potential
streitz: Streitz-Mintmire potential for Al2O3
tad: temperature-accelerated dynamics of vacancy diffusion in bulk Si
vashishta: models using the Vashishta potential
voronoi: Voronoi tesselation via compute voronoi/atom command
-Here is a src/Make.py command which will perform a parallel build of a
-LAMMPS executable "lmp_mpi" with all the packages needed by all the
-examples, with the exception of the accelerate sub-directory. See the
-accelerate/README for Make.py commands suitable for its example
-scripts.
-
-cd src
-Make.py -j 16 -p none std no-lib reax meam poems reaxc orig -a lib-all mpi
-
Here is how you might run and visualize one of the sample problems:
cd indent
cp ../../src/lmp_mpi . # copy LAMMPS executable to this dir
-lmp_mpi < in.indent # run the problem
+lmp_mpi -in in.indent # run the problem
Running the simulation produces the files {dump.indent} and
{log.lammps}. You can visualize the dump file as follows:
../../tools/xmovie/xmovie -scale dump.indent
If you uncomment the dump image line(s) in the input script a series
of JPG images will be produced by the run. These can be viewed
individually or turned into a movie or animated by tools like
ImageMagick or QuickTime or various Windows-based tools. See the dump
image doc page for more details. E.g. this Imagemagick command would
create a GIF file suitable for viewing in a browser.
% convert -loop 1 *.jpg foo.gif
------------------------------------------
Upper-case directories
The ASPHERE directory has examples of how to model aspherical
particles with or without solvent, in 3 styles LAMMPS provides.
Namely point ellipsoids, rigid bodies, and generalized aspherical
bodies built from line/triangle surface facets in 2d/3d. See the
ASPHERE/README file to get started.
The COUPLE directory has examples of how to use LAMMPS as a library,
either by itself or in tandem with another code or library. See the
COUPLE/README file to get started.
The ELASTIC directory has an example script for computing elastic
constants at zero temperature, using an Si example. See the
ELASTIC/in.elastic file for more info.
The ELASTIC_T directory has an example script for computing elastic
constants at finite temperature, using an Si example. See the
ELASTIC_T/in.elastic file for more info.
The HEAT directory has example scripts for heat exchange algorithms
(e.g. used for establishing a thermal gradient), using two different
methods. See the HEAT/README file for more info.
The KAPPA directory has example scripts for computing the thermal
conductivity (kappa) of a LJ liquid using 5 different methods. See
the KAPPA/README file for more info.
The MC directory has an example script for using LAMMPS as an
energy-evaluation engine in a iterative Monte Carlo energy-relaxation
loop.
The USER directory contains subdirectories of user-provided example
scripts for ser packages. See the README files in those directories
for more info. See the doc/Section_start.html file for more info
about installing and building user packages.
The VISCOSITY directory has example scripts for computing the
viscosity of a LJ liquid using 4 different methods. See the
VISCOSITY/README file for more info.
diff --git a/examples/USER/misc/flow_gauss/README b/examples/USER/misc/flow_gauss/README
index 4966cd2dc..ef7cc82d9 100644
--- a/examples/USER/misc/flow_gauss/README
+++ b/examples/USER/misc/flow_gauss/README
@@ -1,45 +1,45 @@
The input script in.GD is an example simulation using Gaussian dynamics (GD).
The simulation is of a simple 2d Lennard-Jones fluid flowing through a pipe.
-For details see online LAMMPS documentation and
+For details see online LAMMPS documentation and
Strong and Eaves, J. Phys. Chem. Lett. 7(10) 2016, p. 1907.
-Note that the run times and box size are chosen to allow a fast example run.
-They are not adequate for a real simulation.
+Note that the run times and box size are chosen to allow a fast example run.
+They are not adequate for a real simulation.
The script has the following parts:
1) initialize variables
- These can be modified to customize the simulation. Note that if the
- pipe dimensions L or d are changed, the geometry should be checked
- by visualizing the coordinates in all.init.lammpstrj.
+ These can be modified to customize the simulation. Note that if the
+ pipe dimensions L or d are changed, the geometry should be checked
+ by visualizing the coordinates in all.init.lammpstrj.
2) create box
-
+
3) set up potential
4) create atoms
5) set up profile-unbiased thermostat (PUT)
- see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172
- By default, this uses boxes which contain on average 8 molecules.
+ see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172
+ By default, this uses boxes which contain on average 8 molecules.
6) equilibrate without GD
-
+
7) initialize the center-of-mass velocity and run to achieve steady-state
- The system is initialized with a uniform velocity profile, which
- relaxes over the course of the simulation.
+ The system is initialized with a uniform velocity profile, which
+ relaxes over the course of the simulation.
8) collect data
- The data is output in several files:
- GD.out contains the force that GD applies, and the flux in the x- and
- y- directions. The output Jx should be equal to the value of
- J set in section 1, which is 0.1 by default.
- x_profiles contains the velocity, density, and pressure profiles in
- the x-direction. The pressure profile is given by
- (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a
- slice. The pressure profile is computed with IK1, see
- Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627.
- Note that to compare with the pump method, or to
- compute a pressure drop, you must correct this pressure
- profile as described in Strong 2016 above.
- Vy_profile is the velocity profile inside the pipe along the
- y-direction, u_x(y).
+ The data is output in several files:
+ GD.out contains the force that GD applies, and the flux in the x- and
+ y- directions. The output Jx should be equal to the value of
+ J set in section 1, which is 0.1 by default.
+ x_profiles contains the velocity, density, and pressure profiles in
+ the x-direction. The pressure profile is given by
+ (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a
+ slice. The pressure profile is computed with IK1, see
+ Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627.
+ Note that to compare with the pump method, or to
+ compute a pressure drop, you must correct this pressure
+ profile as described in Strong 2016 above.
+ Vy_profile is the velocity profile inside the pipe along the
+ y-direction, u_x(y).
diff --git a/examples/USER/misc/flow_gauss/in.GD b/examples/USER/misc/flow_gauss/in.GD
old mode 100755
new mode 100644
index 8117715c1..bcff4d4c5
--- a/examples/USER/misc/flow_gauss/in.GD
+++ b/examples/USER/misc/flow_gauss/in.GD
@@ -1,258 +1,262 @@
#LAMMPS input script
#in.GD
#see README for details
###############################################################################
#initialize variables
clear
#frequency for outputting info (timesteps)
-variable dump_rate equal 50
-variable thermo_rate equal 10
+variable dump_rate equal 50
+variable thermo_rate equal 10
#equilibration time (timesteps)
-variable equil equal 1000
+variable equil equal 1000
#stabilization time (timesteps to reach steady-state)
-variable stabil equal 1000
+variable stabil equal 1000
#data collection time (timesteps)
-variable run equal 2000
+variable run equal 2000
#length of pipe
-variable L equal 30
+variable L equal 30
#width of pipe
-variable d equal 20
+variable d equal 20
#flux (mass/sigma*tau)
-variable J equal 0.1
+variable J equal 0.1
#simulation box dimensions
-variable Lx equal 100
-variable Ly equal 40
+variable Lx equal 100
+variable Ly equal 40
#bulk fluid density
-variable dens equal 0.8
+variable dens equal 0.8
#lattice spacing for wall atoms
-variable aWall equal 1.0 #1.7472
+variable aWall equal 1.0 #1.7472
#timestep
-variable ts equal 0.001
+variable ts equal 0.001
#temperature
-variable T equal 2.0
+variable T equal 2.0
#thermostat damping constant
-variable tdamp equal ${ts}*100
+variable tdamp equal ${ts}*100
-units lj
-dimension 2
-atom_style atomic
+units lj
+dimension 2
+atom_style atomic
###############################################################################
#create box
#create lattice with the spacing aWall
-variable rhoWall equal ${aWall}^(-2)
-lattice sq ${rhoWall}
+variable rhoWall equal ${aWall}^(-2)
+lattice sq ${rhoWall}
#modify input dimensions to be multiples of aWall
-variable L1 equal round($L/${aWall})*${aWall}
-variable d1 equal round($d/${aWall})*${aWall}
-variable Ly1 equal round(${Ly}/${aWall})*${aWall}
-variable Lx1 equal round(${Lx}/${aWall})*${aWall}
+variable L1 equal round($L/${aWall})*${aWall}
+variable d1 equal round($d/${aWall})*${aWall}
+variable Ly1 equal round(${Ly}/${aWall})*${aWall}
+variable Lx1 equal round(${Lx}/${aWall})*${aWall}
#create simulation box
-variable lx2 equal ${Lx1}/2
-variable ly2 equal ${Ly1}/2
-region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box
-create_box 2 simbox
+variable lx2 equal ${Lx1}/2
+variable ly2 equal ${Ly1}/2
+region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box
+create_box 2 simbox
#####################################################################
#set up potential
-mass 1 1.0 #fluid atoms
-mass 2 1.0 #wall atoms
+mass 1 1.0 #fluid atoms
+mass 2 1.0 #wall atoms
-pair_style lj/cut 2.5
-pair_modify shift yes
-pair_coeff 1 1 1.0 1.0 2.5
-pair_coeff 1 2 1.0 1.0 1.12246
-pair_coeff 2 2 0.0 0.0 0.0
+pair_style lj/cut 2.5
+pair_modify shift yes
+pair_coeff 1 1 1.0 1.0 2.5
+pair_coeff 1 2 1.0 1.0 1.12246
+pair_coeff 2 2 0.0 0.0
-timestep ${ts}
+neigh_modify exclude type 2 2
+
+timestep ${ts}
#####################################################################
#create atoms
#create wall atoms everywhere
create_atoms 2 box
#define region which is "walled off"
-variable dhalf equal ${d1}/2
-variable Lhalf equal ${L1}/2
-region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 &
- units box
-region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 &
- units box
-region outsidewall union 2 walltop wallbot side out
+variable dhalf equal ${d1}/2
+variable Lhalf equal ${L1}/2
+region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 &
+ units box
+region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 &
+ units box
+region outsidewall union 2 walltop wallbot side out
#remove wall atoms outside wall region
-group outside region outsidewall
-delete_atoms group outside
+group outside region outsidewall
+delete_atoms group outside
#remove wall atoms that aren't on edge of wall region
-variable x1 equal ${Lhalf}-${aWall}
-variable y1 equal ${dhalf}+${aWall}
-region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box
-region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box
-region insideWall union 2 insideTop insideBot
-group insideWall region insideWall
-delete_atoms group insideWall
+variable x1 equal ${Lhalf}-${aWall}
+variable y1 equal ${dhalf}+${aWall}
+region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box
+region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box
+region insideWall union 2 insideTop insideBot
+group insideWall region insideWall
+delete_atoms group insideWall
#define new lattice, to give correct fluid density
#y lattice const must be a multiple of aWall
-variable atrue equal ${dens}^(-1/2)
-variable ay equal round(${atrue}/${aWall})*${aWall}
+variable atrue equal ${dens}^(-1/2)
+variable ay equal round(${atrue}/${aWall})*${aWall}
#choose x lattice const to give correct density
-variable ax equal (${ay}*${dens})^(-1)
+variable ax equal (${ay}*${dens})^(-1)
#change Lx to be multiple of ax
-variable Lx1 equal round(${Lx}/${ax})*${ax}
-variable lx2 equal ${Lx1}/2
-change_box all x final -${lx2} ${lx2} units box
+variable Lx1 equal round(${Lx}/${ax})*${ax}
+variable lx2 equal ${Lx1}/2
+change_box all x final -${lx2} ${lx2} units box
#define new lattice
-lattice custom ${dens} &
- a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 &
- basis 0.0 0.0 0.0
+lattice custom ${dens} &
+ a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 &
+ basis 0.0 0.0 0.0
#fill in rest of box with bulk particles
-variable delta equal 0.001
-variable Ldelt equal ${Lhalf}+${delta}
-variable dDelt equal ${dhalf}-${delta}
-region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box
-region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box
-region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 &
- units box
+variable delta equal 0.001
+variable Ldelt equal ${Lhalf}+${delta}
+variable dDelt equal ${dhalf}-${delta}
+region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box
+region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box
+region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 &
+ units box
-region bulk union 3 left pipe right
-create_atoms 1 region bulk
+region bulk union 3 left pipe right
+create_atoms 1 region bulk
-group bulk type 1
-group wall type 2
+group bulk type 1
+group wall type 2
#remove atoms that are too close to wall
delete_atoms overlap 0.9 bulk wall
-neighbor 0.3 bin
-neigh_modify delay 0 every 1 check yes
+neighbor 0.3 bin
+neigh_modify delay 0 every 1 check yes
neigh_modify exclude group wall wall
-velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom
+velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom
#####################################################################
#set up PUT
#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172
#average number of particles per box, Evans and Morriss used 2.0
-variable NperBox equal 8.0
+variable NperBox equal 8.0
#calculate box sizes
-variable boxSide equal sqrt(${NperBox}/${dens})
-variable nX equal round(lx/${boxSide})
-variable nY equal round(ly/${boxSide})
-variable dX equal lx/${nX}
-variable dY equal ly/${nY}
+variable boxSide equal sqrt(${NperBox}/${dens})
+variable nX equal round(lx/${boxSide})
+variable nY equal round(ly/${boxSide})
+variable dX equal lx/${nX}
+variable dY equal ly/${nY}
#temperature of fluid (excluding wall)
-compute myT bulk temp
+compute myT bulk temp
#profile-unbiased temperature of fluid
-compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY}
+compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY}
#thermo setup
-thermo ${thermo_rate}
-thermo_style custom step c_myT c_myTp etotal press
+thermo ${thermo_rate}
+thermo_style custom step c_myT c_myTp etotal press
#dump initial configuration
-dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz
-dump 56 wall custom 1 wall.init.lammpstrj id type x y z
-dump_modify 55 sort id
-dump_modify 56 sort id
-run 0
-undump 55
-undump 56
+# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz
+# dump 56 wall custom 1 wall.init.lammpstrj id type x y z
+# dump_modify 55 sort id
+# dump_modify 56 sort id
+run 0
+# undump 55
+# undump 56
#####################################################################
#equilibrate without GD
-fix nvt bulk nvt temp $T $T ${tdamp}
-fix_modify nvt temp myTp
-fix 2 bulk enforce2d
+fix nvt bulk nvt temp $T $T ${tdamp}
+fix_modify nvt temp myTp
+fix 2 bulk enforce2d
-run ${equil}
+run ${equil}
#####################################################################
#initialize the COM velocity and run to achieve steady-state
#calculate velocity to add: V=J/rho_total
-variable Vadd equal $J*lx*ly/count(bulk)
+variable Vadd equal $J*lx*ly/count(bulk)
#first remove any COM velocity, then add back the streaming velocity
velocity bulk zero linear
-velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no
+velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no
-fix GD bulk flow/gauss 1 0 0 #energy yes
-#fix_modify GD energy yes
+fix GD bulk flow/gauss 1 0 0 #energy yes
+#fix_modify GD energy yes
-run ${stabil}
+run ${stabil}
#####################################################################
#collect data
#print the applied force and total flux to ensure conservation of Jx
-variable Fapp equal f_GD[1]
-compute vxBulk bulk reduce sum vx
-compute vyBulk bulk reduce sum vy
+variable Fapp equal f_GD[1]
+compute vxBulk bulk reduce sum vx
+compute vyBulk bulk reduce sum vy
variable invVol equal 1.0/(lx*ly)
-variable jx equal c_vxBulk*${invVol}
-variable jy equal c_vyBulk*${invVol}
-variable curr_step equal step
-fix print_vCOM all print ${dump_rate} &
- "${curr_step} ${Fapp} ${jx} ${jy}" file GD.out screen no &
- title "timestep Fapp Jx Jy"
-
-#compute IK1 pressure profile
+variable jx equal c_vxBulk*${invVol}
+variable jy equal c_vyBulk*${invVol}
+variable curr_step equal step
+variable p_Fapp format Fapp %.3f
+variable p_jx format jx %.5g
+variable p_jy format jy %.5g
+fix print_vCOM all print ${dump_rate} &
+ "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no &
+ title "timestep Fapp Jx Jy"
+
+#compute IK1 pressure profile
#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627
#use profile-unbiased temperature to remove the streaming velocity
#from the kinetic part of the pressure
-compute spa bulk stress/atom myTp
+compute spa bulk stress/atom myTp
#for the pressure profile, use the same grid as the PUT
-compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box
+compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box
#output pressure profile and other profiles
#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where
#V is the volume of a slice
-fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX &
- vx density/mass c_spa[1] c_spa[2] &
- file x_profiles ave running overwrite
+fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX &
+ vx density/mass c_spa[1] c_spa[2] &
+ file x_profiles ave running overwrite
#compute velocity profile across the pipe with a finer grid
-variable dYnew equal ${dY}/10
-compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box &
- region pipe
-fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY &
- vx file Vy_profile ave running overwrite
+variable dYnew equal ${dY}/10
+compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box &
+ region pipe
+fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY &
+ vx file Vy_profile ave running overwrite
#full trajectory
-dump 7 bulk custom ${dump_rate} bulk.lammpstrj &
- id type x y z
-dump_modify 7 sort id
+# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z
+# dump_modify 7 sort id
-run ${run}
+run ${run}
diff --git a/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.1 b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.1
new file mode 100644
index 000000000..bb9167f49
--- /dev/null
+++ b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.1
@@ -0,0 +1,909 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+#LAMMPS input script
+#in.GD
+#see README for details
+
+###############################################################################
+#initialize variables
+clear
+ using 1 OpenMP thread(s) per MPI task
+
+#frequency for outputting info (timesteps)
+variable dump_rate equal 50
+variable thermo_rate equal 10
+
+#equilibration time (timesteps)
+variable equil equal 1000
+
+#stabilization time (timesteps to reach steady-state)
+variable stabil equal 1000
+
+#data collection time (timesteps)
+variable run equal 2000
+
+#length of pipe
+variable L equal 30
+
+#width of pipe
+variable d equal 20
+
+#flux (mass/sigma*tau)
+variable J equal 0.1
+
+#simulation box dimensions
+variable Lx equal 100
+variable Ly equal 40
+
+#bulk fluid density
+variable dens equal 0.8
+
+#lattice spacing for wall atoms
+variable aWall equal 1.0 #1.7472
+
+#timestep
+variable ts equal 0.001
+
+#temperature
+variable T equal 2.0
+
+#thermostat damping constant
+variable tdamp equal ${ts}*100
+variable tdamp equal 0.001*100
+
+units lj
+dimension 2
+atom_style atomic
+
+
+###############################################################################
+#create box
+
+#create lattice with the spacing aWall
+variable rhoWall equal ${aWall}^(-2)
+variable rhoWall equal 1^(-2)
+lattice sq ${rhoWall}
+lattice sq 1
+Lattice spacing in x,y,z = 1 1 1
+
+#modify input dimensions to be multiples of aWall
+variable L1 equal round($L/${aWall})*${aWall}
+variable L1 equal round(30/${aWall})*${aWall}
+variable L1 equal round(30/1)*${aWall}
+variable L1 equal round(30/1)*1
+variable d1 equal round($d/${aWall})*${aWall}
+variable d1 equal round(20/${aWall})*${aWall}
+variable d1 equal round(20/1)*${aWall}
+variable d1 equal round(20/1)*1
+variable Ly1 equal round(${Ly}/${aWall})*${aWall}
+variable Ly1 equal round(40/${aWall})*${aWall}
+variable Ly1 equal round(40/1)*${aWall}
+variable Ly1 equal round(40/1)*1
+variable Lx1 equal round(${Lx}/${aWall})*${aWall}
+variable Lx1 equal round(100/${aWall})*${aWall}
+variable Lx1 equal round(100/1)*${aWall}
+variable Lx1 equal round(100/1)*1
+
+#create simulation box
+variable lx2 equal ${Lx1}/2
+variable lx2 equal 100/2
+variable ly2 equal ${Ly1}/2
+variable ly2 equal 40/2
+region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 ${lx2} -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 50 -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 50 -20 ${ly2} 0 0.1 units box
+region simbox block -50 50 -20 20 0 0.1 units box
+create_box 2 simbox
+Created orthogonal box = (-50 -20 0) to (50 20 0.1)
+ 1 by 1 by 1 MPI processor grid
+
+#####################################################################
+#set up potential
+
+mass 1 1.0 #fluid atoms
+mass 2 1.0 #wall atoms
+
+pair_style lj/cut 2.5
+pair_modify shift yes
+pair_coeff 1 1 1.0 1.0 2.5
+pair_coeff 1 2 1.0 1.0 1.12246
+pair_coeff 2 2 0.0 0.0
+
+neigh_modify exclude type 2 2
+
+timestep ${ts}
+timestep 0.001
+
+#####################################################################
+#create atoms
+
+#create wall atoms everywhere
+create_atoms 2 box
+Created 4000 atoms
+
+#define region which is "walled off"
+variable dhalf equal ${d1}/2
+variable dhalf equal 20/2
+variable Lhalf equal ${L1}/2
+variable Lhalf equal 30/2
+region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 15 ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 15 10 EDGE -0.1 0.1 units box
+region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 15 EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 15 EDGE -10 -0.1 0.1 units box
+region outsidewall union 2 walltop wallbot side out
+
+#remove wall atoms outside wall region
+group outside region outsidewall
+3349 atoms in group outside
+delete_atoms group outside
+Deleted 3349 atoms, new total = 651
+
+#remove wall atoms that aren't on edge of wall region
+variable x1 equal ${Lhalf}-${aWall}
+variable x1 equal 15-${aWall}
+variable x1 equal 15-1
+variable y1 equal ${dhalf}+${aWall}
+variable y1 equal 10+${aWall}
+variable y1 equal 10+1
+region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 ${x1} ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 14 ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 14 11 EDGE -0.1 0.1 units box
+region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 ${x1} EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 14 EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 14 EDGE -11 -0.1 0.1 units box
+region insideWall union 2 insideTop insideBot
+group insideWall region insideWall
+551 atoms in group insideWall
+delete_atoms group insideWall
+Deleted 551 atoms, new total = 100
+
+#define new lattice, to give correct fluid density
+#y lattice const must be a multiple of aWall
+variable atrue equal ${dens}^(-1/2)
+variable atrue equal 0.8^(-1/2)
+variable ay equal round(${atrue}/${aWall})*${aWall}
+variable ay equal round(1.11803398874989/${aWall})*${aWall}
+variable ay equal round(1.11803398874989/1)*${aWall}
+variable ay equal round(1.11803398874989/1)*1
+
+#choose x lattice const to give correct density
+variable ax equal (${ay}*${dens})^(-1)
+variable ax equal (1*${dens})^(-1)
+variable ax equal (1*0.8)^(-1)
+
+#change Lx to be multiple of ax
+variable Lx1 equal round(${Lx}/${ax})*${ax}
+variable Lx1 equal round(100/${ax})*${ax}
+variable Lx1 equal round(100/1.25)*${ax}
+variable Lx1 equal round(100/1.25)*1.25
+variable lx2 equal ${Lx1}/2
+variable lx2 equal 100/2
+change_box all x final -${lx2} ${lx2} units box
+change_box all x final -50 ${lx2} units box
+change_box all x final -50 50 units box
+ orthogonal box = (-50 -20 0) to (50 20 0.1)
+
+#define new lattice
+lattice custom ${dens} a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 1 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+Lattice spacing in x,y,z = 1.25 1 1
+
+#fill in rest of box with bulk particles
+variable delta equal 0.001
+variable Ldelt equal ${Lhalf}+${delta}
+variable Ldelt equal 15+${delta}
+variable Ldelt equal 15+0.001
+variable dDelt equal ${dhalf}-${delta}
+variable dDelt equal 10-${delta}
+variable dDelt equal 10-0.001
+region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box
+region left block EDGE -15.001 EDGE EDGE -0.1 0.1 units box
+region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box
+region right block 15.001 EDGE EDGE EDGE -0.1 0.1 units box
+region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -9.999 ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -9.999 9.999 -0.1 0.1 units box
+
+region bulk union 3 left pipe right
+create_atoms 1 region bulk
+Created 2675 atoms
+
+group bulk type 1
+2675 atoms in group bulk
+group wall type 2
+100 atoms in group wall
+
+#remove atoms that are too close to wall
+delete_atoms overlap 0.9 bulk wall
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 2.8
+ ghost atom cutoff = 2.8
+ binsize = 1.4, bins = 72 29 1
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) command delete_atoms, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/2d
+ bin: standard
+ (2) pair lj/cut, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/2d/newton
+ bin: standard
+Deleted 0 atoms, new total = 2775
+
+neighbor 0.3 bin
+neigh_modify delay 0 every 1 check yes
+neigh_modify exclude group wall wall
+
+velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom
+velocity bulk create 2 78915 dist gaussian rot yes mom yes loop geom
+
+#####################################################################
+#set up PUT
+#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172
+
+#average number of particles per box, Evans and Morriss used 2.0
+variable NperBox equal 8.0
+
+#calculate box sizes
+variable boxSide equal sqrt(${NperBox}/${dens})
+variable boxSide equal sqrt(8/${dens})
+variable boxSide equal sqrt(8/0.8)
+variable nX equal round(lx/${boxSide})
+variable nX equal round(lx/3.16227766016838)
+variable nY equal round(ly/${boxSide})
+variable nY equal round(ly/3.16227766016838)
+variable dX equal lx/${nX}
+variable dX equal lx/32
+variable dY equal ly/${nY}
+variable dY equal ly/13
+
+#temperature of fluid (excluding wall)
+compute myT bulk temp
+
+#profile-unbiased temperature of fluid
+compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY}
+compute myTp bulk temp/profile 1 1 0 xy 32 ${nY}
+compute myTp bulk temp/profile 1 1 0 xy 32 13
+
+#thermo setup
+thermo ${thermo_rate}
+thermo 10
+thermo_style custom step c_myT c_myTp etotal press
+
+#dump initial configuration
+# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz
+# dump 56 wall custom 1 wall.init.lammpstrj id type x y z
+# dump_modify 55 sort id
+# dump_modify 56 sort id
+run 0
+WARNING: No fixes defined, atoms won't move (../verlet.cpp:55)
+Neighbor list info ...
+ update every 1 steps, delay 0 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 2.8
+ ghost atom cutoff = 2.8
+ binsize = 1.4, bins = 72 29 1
+ 1 neighbor lists, perpetual/occasional/extra = 1 0 0
+ (1) pair lj/cut, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/2d/newton
+ bin: standard
+Per MPI rank memory allocation (min/avg/max) = 3.103 | 3.103 | 3.103 Mbytes
+Step c_myT c_myTp TotEng Press
+ 0 2 2.0555109 0.77892922 7.3417096
+Loop time of 9.53674e-07 on 1 procs for 0 steps with 2775 atoms
+
+314.6% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0 | 0 | 0 | 0.0 | 0.00
+Neigh | 0 | 0 | 0 | 0.0 | 0.00
+Comm | 0 | 0 | 0 | 0.0 | 0.00
+Output | 0 | 0 | 0 | 0.0 | 0.00
+Modify | 0 | 0 | 0 | 0.0 | 0.00
+Other | | 9.537e-07 | | |100.00
+
+Nlocal: 2775 ave 2775 max 2775 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 510 ave 510 max 510 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 26406 ave 26406 max 26406 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 26406
+Ave neighs/atom = 9.51568
+Neighbor list builds = 0
+Dangerous builds = 0
+# undump 55
+# undump 56
+
+#####################################################################
+#equilibrate without GD
+
+fix nvt bulk nvt temp $T $T ${tdamp}
+fix nvt bulk nvt temp 2 $T ${tdamp}
+fix nvt bulk nvt temp 2 2 ${tdamp}
+fix nvt bulk nvt temp 2 2 0.1
+fix_modify nvt temp myTp
+WARNING: Temperature for fix modify is not for group all (../fix_nh.cpp:1395)
+fix 2 bulk enforce2d
+
+run ${equil}
+run 1000
+Per MPI rank memory allocation (min/avg/max) = 3.166 | 3.166 | 3.166 Mbytes
+Step c_myT c_myTp TotEng Press
+ 0 2 2.0555109 0.77892922 7.3417096
+ 10 1.9173594 1.9390034 0.77876976 7.6702228
+ 20 1.7033394 1.6974676 0.77977799 8.5614784
+ 30 1.5026161 1.4723993 0.78456655 9.4308258
+ 40 1.4880481 1.4591602 0.79486693 9.6134304
+ 50 1.6192437 1.6150635 0.81109069 9.2592835
+ 60 1.7404087 1.7583444 0.82955456 8.952392
+ 70 1.7757591 1.8006606 0.8452778 8.9717917
+ 80 1.7573847 1.7813629 0.85769389 9.1936368
+ 90 1.7491183 1.7726908 0.86882429 9.3712357
+ 100 1.7798944 1.8079583 0.88029084 9.3871755
+ 110 1.8440582 1.8793133 0.89259397 9.2582848
+ 120 1.9191606 1.9673434 0.90533438 9.0680574
+ 130 1.9883299 2.0484299 0.91755461 8.88117
+ 140 2.0463366 2.1111872 0.92818114 8.7184178
+ 150 2.0953769 2.167849 0.93639789 8.5713408
+ 160 2.1442147 2.2216228 0.94145082 8.4082835
+ 170 2.1797848 2.2631458 0.94246877 8.2767903
+ 180 2.1863476 2.2700986 0.93873326 8.2311689
+ 190 2.1832866 2.2710551 0.93003012 8.1959062
+ 200 2.1937154 2.2868403 0.91642537 8.0842007
+ 210 2.2022708 2.2915142 0.89824533 7.9575312
+ 220 2.1884715 2.2770564 0.87677613 7.9000591
+ 230 2.1671124 2.2496063 0.85409501 7.8673156
+ 240 2.1560417 2.2379998 0.83167878 7.8003228
+ 250 2.1421449 2.2240624 0.81004723 7.7491508
+ 260 2.1172164 2.1971044 0.78931978 7.7457415
+ 270 2.0856847 2.1672998 0.76956352 7.7719788
+ 280 2.0670685 2.1449303 0.75073364 7.7524614
+ 290 2.0639481 2.1428374 0.73258016 7.6727716
+ 300 2.055776 2.1361719 0.7147669 7.6095248
+ 310 2.038425 2.1209353 0.69722853 7.5797085
+ 320 2.0203023 2.1066031 0.68006634 7.5521081
+ 330 2.0118478 2.1039797 0.66330302 7.4877535
+ 340 2.0159442 2.1096258 0.64673694 7.3761703
+ 350 2.0166408 2.1075061 0.63020017 7.2788
+ 360 2.0059407 2.0806316 0.61387618 7.2263941
+ 370 1.9964281 2.0642074 0.59814148 7.1728041
+ 380 1.9918446 2.0567527 0.58303017 7.101597
+ 390 1.992835 2.0548138 0.56852431 7.0084774
+ 400 2.0012934 2.0615016 0.55438401 6.8865948
+ 410 2.0084291 2.073418 0.54034073 6.7697478
+ 420 2.007464 2.0786717 0.52617041 6.6849032
+ 430 1.9983712 2.0704366 0.51188183 6.6323103
+ 440 1.9884651 2.0588515 0.49765394 6.5868356
+ 450 1.982221 2.0467396 0.4837102 6.5311681
+ 460 1.9738673 2.031238 0.47021649 6.4882783
+ 470 1.9574246 2.0060447 0.45740021 6.4814923
+ 480 1.9361065 1.9734507 0.44557947 6.4995199
+ 490 1.9251024 1.9562469 0.43506067 6.4858343
+ 500 1.9279545 1.9572145 0.42577835 6.4274765
+ 510 1.9267504 1.9570246 0.41755013 6.3927027
+ 520 1.9093405 1.9393872 0.41031829 6.4281888
+ 530 1.8820555 1.9060756 0.40432569 6.5099401
+ 540 1.86537 1.8912682 0.3999087 6.55843
+ 550 1.8694252 1.9043192 0.39717519 6.5337875
+ 560 1.8835224 1.9294105 0.39589322 6.4760141
+ 570 1.8898719 1.9462433 0.39573596 6.4520041
+ 580 1.8887698 1.9472764 0.39649878 6.4602989
+ 590 1.8945125 1.9550624 0.39810844 6.4470226
+ 600 1.9106571 1.9735939 0.40045321 6.3971026
+ 610 1.9273243 1.98509 0.40330026 6.3474421
+ 620 1.9351802 1.9888986 0.4064498 6.3340566
+ 630 1.9337889 1.9846794 0.40981479 6.3610556
+ 640 1.9257018 1.9757153 0.4134641 6.4184721
+ 650 1.9204429 1.9718256 0.41750942 6.4679594
+ 660 1.9220449 1.9701963 0.42202455 6.4919724
+ 670 1.9230578 1.9707406 0.4270412 6.5178484
+ 680 1.9204554 1.9740485 0.43255127 6.5572507
+ 690 1.9201811 1.9762854 0.43847123 6.5869126
+ 700 1.9271511 1.9867455 0.44474356 6.5882669
+ 710 1.9418851 2.0042477 0.45120727 6.558573
+ 720 1.9544547 2.0186724 0.4576061 6.5338329
+ 730 1.9687971 2.0326169 0.46367507 6.4988775
+ 740 1.9830308 2.0466267 0.46920367 6.4618136
+ 750 1.9936981 2.0526606 0.47397868 6.4367349
+ 760 2.0008431 2.0535449 0.47786748 6.4249001
+ 770 1.9982133 2.0483219 0.48085757 6.4504786
+ 780 1.9841544 2.0311693 0.48306488 6.5200512
+ 790 1.9683122 2.0158738 0.48475632 6.5959263
+ 800 1.9604618 2.003224 0.48619405 6.6392559
+ 810 1.9629155 2.0075077 0.48756075 6.6406486
+ 820 1.9683056 2.0110554 0.48883443 6.6269424
+ 830 1.975409 2.0189161 0.48995399 6.6030215
+ 840 1.9897264 2.035016 0.4907852 6.5485575
+ 850 2.0094338 2.0555358 0.49104505 6.4719926
+ 860 2.0217589 2.0643603 0.49040437 6.4233305
+ 870 2.0147718 2.0641627 0.48866908 6.4491964
+ 880 1.9883859 2.0324092 0.48592007 6.5488061
+ 890 1.9625853 2.0028776 0.48263002 6.6452734
+ 900 1.9520401 1.9889124 0.47925524 6.6808078
+ 910 1.9559583 1.9952984 0.47597346 6.6573059
+ 920 1.9657244 2.0083503 0.47268726 6.6073704
+ 930 1.969288 2.0152339 0.4692054 6.5780416
+ 940 1.9652206 2.0116384 0.4654438 6.5769812
+ 950 1.9567495 1.9960693 0.46147541 6.5942022
+ 960 1.9418452 1.980858 0.45753557 6.6369454
+ 970 1.9247196 1.9585585 0.45390337 6.6888821
+ 980 1.9128262 1.9481721 0.45090045 6.7198221
+ 990 1.9167211 1.9451096 0.44869731 6.6912394
+ 1000 1.935529 1.9662384 0.44728238 6.6079829
+Loop time of 1.307 on 1 procs for 1000 steps with 2775 atoms
+
+Performance: 66105.601 tau/day, 765.111 timesteps/s
+98.7% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.7676 | 0.7676 | 0.7676 | 0.0 | 58.73
+Neigh | 0.088947 | 0.088947 | 0.088947 | 0.0 | 6.81
+Comm | 0.0094135 | 0.0094135 | 0.0094135 | 0.0 | 0.72
+Output | 0.019547 | 0.019547 | 0.019547 | 0.0 | 1.50
+Modify | 0.39755 | 0.39755 | 0.39755 | 0.0 | 30.42
+Other | | 0.02394 | | | 1.83
+
+Nlocal: 2775 ave 2775 max 2775 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 527 ave 527 max 527 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 24332 ave 24332 max 24332 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 24332
+Ave neighs/atom = 8.76829
+Neighbor list builds = 38
+Dangerous builds = 0
+
+#####################################################################
+#initialize the COM velocity and run to achieve steady-state
+
+#calculate velocity to add: V=J/rho_total
+variable Vadd equal $J*lx*ly/count(bulk)
+variable Vadd equal 0.1*lx*ly/count(bulk)
+
+#first remove any COM velocity, then add back the streaming velocity
+velocity bulk zero linear
+velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no
+velocity bulk set 0.149532710280374 0.0 0.0 units box sum yes mom no
+
+fix GD bulk flow/gauss 1 0 0 #energy yes
+#fix_modify GD energy yes
+
+run ${stabil}
+run 1000
+Per MPI rank memory allocation (min/avg/max) = 3.166 | 3.166 | 3.166 Mbytes
+Step c_myT c_myTp TotEng Press
+ 1000 1.9466974 1.9662384 0.45804438 6.615449
+ 1010 1.9605467 1.9815754 0.45717241 6.5545496
+ 1020 1.9560139 1.9823875 0.45660431 6.5672421
+ 1030 1.9348326 1.9691606 0.45633148 6.6463667
+ 1040 1.9167809 1.9449522 0.45657707 6.7139486
+ 1050 1.9193541 1.943342 0.45767968 6.7014054
+ 1060 1.9410751 1.9720491 0.45967742 6.6150379
+ 1070 1.9658493 1.9964883 0.46221539 6.5178418
+ 1080 1.9767205 2.0074304 0.46491236 6.4768594
+ 1090 1.9714544 2.0003054 0.46759126 6.5026957
+ 1100 1.9647035 1.9927455 0.4703109 6.5400181
+ 1110 1.9657667 1.9959656 0.47317481 6.5519094
+ 1120 1.9706062 1.9980802 0.476185 6.5512675
+ 1130 1.9747655 2.0062292 0.47932281 6.554091
+ 1140 1.9761245 2.0075076 0.48248327 6.5670381
+ 1150 1.9744197 2.0073027 0.48562483 6.5914441
+ 1160 1.9722698 2.0046687 0.48874207 6.6165575
+ 1170 1.9692145 2.0013845 0.49187442 6.6438115
+ 1180 1.9665609 1.9970724 0.49508053 6.6693821
+ 1190 1.9625031 1.9908427 0.49843816 6.7002606
+ 1200 1.960528 1.993084 0.50203044 6.7237076
+ 1210 1.9649156 1.9981485 0.50587066 6.7217755
+ 1220 1.9788059 2.0134511 0.50987442 6.6833452
+ 1230 1.9952283 2.0343101 0.51379781 6.6340278
+ 1240 2.0039391 2.0494196 0.51730872 6.6129751
+ 1250 2.0019006 2.0526773 0.52014603 6.6320217
+ 1260 1.9974025 2.0528914 0.52221385 6.6601786
+ 1270 1.9953949 2.0561121 0.5234754 6.6796142
+ 1280 1.9893864 2.0470375 0.5238632 6.7140134
+ 1290 1.9694951 2.019253 0.5235093 6.798442
+ 1300 1.9473901 1.9965919 0.52280384 6.8863369
+ 1310 1.9511151 2.006161 0.52203882 6.8700917
+ 1320 1.979341 2.0388959 0.52106938 6.7529595
+ 1330 2.0073235 2.0720045 0.51935291 6.6297731
+ 1340 2.0202482 2.0841419 0.51624273 6.55803
+ 1350 2.0177489 2.0669046 0.51142591 6.5401753
+ 1360 2.0069274 2.04717 0.50505824 6.5506533
+ 1370 1.994854 2.0311383 0.49743042 6.5633001
+ 1380 1.9793176 2.0077184 0.48890503 6.5859072
+ 1390 1.9580907 1.9839831 0.48004316 6.6288992
+ 1400 1.9415542 1.9594192 0.47143599 6.6534105
+ 1410 1.9405188 1.9591825 0.46353105 6.620549
+ 1420 1.9504784 1.9730647 0.45640199 6.5471784
+ 1430 1.9594158 1.9819854 0.44995052 6.4802874
+ 1440 1.9615108 1.9863792 0.44406411 6.44391
+ 1450 1.9544127 1.9806249 0.43873409 6.4484818
+ 1460 1.9384927 1.9614953 0.43408605 6.4905259
+ 1470 1.9214711 1.9425515 0.43035972 6.5390434
+ 1480 1.9170761 1.9300809 0.42775046 6.5409502
+ 1490 1.9242904 1.9385731 0.42631007 6.5005057
+ 1500 1.9307133 1.9446119 0.4258836 6.4660754
+ 1510 1.9303576 1.9435389 0.42633976 6.4616415
+ 1520 1.9248382 1.9408306 0.42765441 6.4832059
+ 1530 1.9120794 1.9278123 0.42986958 6.5380951
+ 1540 1.899122 1.9125029 0.4331459 6.5987181
+ 1550 1.9030956 1.9187821 0.43765067 6.6012019
+ 1560 1.9182961 1.9453782 0.44330842 6.5674222
+ 1570 1.9272863 1.9613129 0.44971962 6.5619794
+ 1580 1.931679 1.9698134 0.45643436 6.5780809
+ 1590 1.9336692 1.9728684 0.46314752 6.6035675
+ 1600 1.938895 1.9823104 0.46964519 6.6138411
+ 1610 1.9510838 1.9937914 0.47568807 6.5916989
+ 1620 1.9685387 2.0087314 0.48102339 6.5424432
+ 1630 1.9894416 2.0295715 0.48539861 6.4757743
+ 1640 1.9982699 2.0426949 0.48860411 6.4512418
+ 1650 1.9901677 2.0363837 0.49062424 6.4879985
+ 1660 1.9814216 2.0291326 0.49172203 6.5248034
+ 1670 1.9812111 2.0293629 0.49218297 6.5253876
+ 1680 1.9903906 2.0408376 0.49211747 6.4852787
+ 1690 2.0015983 2.0538843 0.4914581 6.4325081
+ 1700 2.009727 2.0503407 0.49011163 6.3878577
+ 1710 2.0167822 2.0531002 0.4881688 6.3477054
+ 1720 2.0189021 2.0445033 0.48564798 6.3273063
+ 1730 2.0129713 2.0354734 0.48270666 6.3385541
+ 1740 2.0048763 2.0199836 0.47950943 6.3587586
+ 1750 1.9994843 2.0085942 0.47624908 6.3694119
+ 1760 1.9940025 2.0072098 0.47305283 6.3816295
+ 1770 1.9817431 1.9974066 0.46994486 6.4224295
+ 1780 1.965171 1.9805421 0.4670779 6.4832371
+ 1790 1.9474078 1.9662605 0.46466823 6.5516524
+ 1800 1.9286009 1.9507751 0.46292015 6.6263366
+ 1810 1.9168087 1.9437961 0.46199899 6.6759834
+ 1820 1.9107555 1.9306323 0.46204129 6.7029857
+ 1830 1.9135569 1.930819 0.46316484 6.6949737
+ 1840 1.9345342 1.9553413 0.46532704 6.6178988
+ 1850 1.9630349 1.9929548 0.46822932 6.5137866
+ 1860 1.9820746 2.0188839 0.47135068 6.4489028
+ 1870 1.9834959 2.0217145 0.47427805 6.4552721
+ 1880 1.9731564 2.0120293 0.47692755 6.5100251
+ 1890 1.9653605 2.0070624 0.47943307 6.5594235
+ 1900 1.9630631 2.0095488 0.48192185 6.5912876
+ 1910 1.9556778 2.0035006 0.48443107 6.6437189
+ 1920 1.9408788 1.9828296 0.48710124 6.7228731
+ 1930 1.9292393 1.9732376 0.49025327 6.7880112
+ 1940 1.9263081 1.9708942 0.49416086 6.8162477
+ 1950 1.9358375 1.976323 0.49899895 6.7946964
+ 1960 1.9520543 1.9936542 0.50485961 6.7467481
+ 1970 1.9709064 2.0108957 0.51165586 6.6909455
+ 1980 1.9940026 2.0375428 0.51918913 6.6250463
+ 1990 2.0171261 2.0646948 0.52705638 6.5649879
+ 2000 2.0302713 2.0802515 0.53472229 6.5470853
+Loop time of 1.34877 on 1 procs for 1000 steps with 2775 atoms
+
+Performance: 64058.154 tau/day, 741.414 timesteps/s
+98.7% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.77091 | 0.77091 | 0.77091 | 0.0 | 57.16
+Neigh | 0.085835 | 0.085835 | 0.085835 | 0.0 | 6.36
+Comm | 0.0093472 | 0.0093472 | 0.0093472 | 0.0 | 0.69
+Output | 0.019047 | 0.019047 | 0.019047 | 0.0 | 1.41
+Modify | 0.43949 | 0.43949 | 0.43949 | 0.0 | 32.58
+Other | | 0.02415 | | | 1.79
+
+Nlocal: 2775 ave 2775 max 2775 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 530 ave 530 max 530 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 24404 ave 24404 max 24404 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 24404
+Ave neighs/atom = 8.79423
+Neighbor list builds = 36
+Dangerous builds = 0
+
+#####################################################################
+#collect data
+
+#print the applied force and total flux to ensure conservation of Jx
+variable Fapp equal f_GD[1]
+compute vxBulk bulk reduce sum vx
+compute vyBulk bulk reduce sum vy
+variable invVol equal 1.0/(lx*ly)
+variable jx equal c_vxBulk*${invVol}
+variable jx equal c_vxBulk*0.00025
+variable jy equal c_vyBulk*${invVol}
+variable jy equal c_vyBulk*0.00025
+variable curr_step equal step
+variable p_Fapp format Fapp %.3f
+variable p_jx format jx %.5g
+variable p_jy format jy %.5g
+fix print_vCOM all print ${dump_rate} "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy"
+fix print_vCOM all print 50 "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy"
+
+#compute IK1 pressure profile
+#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627
+#use profile-unbiased temperature to remove the streaming velocity
+#from the kinetic part of the pressure
+compute spa bulk stress/atom myTp
+
+#for the pressure profile, use the same grid as the PUT
+compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box
+compute chunkX bulk chunk/atom bin/1d x lower 3.125 units box
+
+#output pressure profile and other profiles
+#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where
+#V is the volume of a slice
+fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite
+fix profiles bulk ave/chunk 1 1 50 chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite
+
+#compute velocity profile across the pipe with a finer grid
+variable dYnew equal ${dY}/10
+variable dYnew equal 3.07692307692308/10
+compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box region pipe
+compute chunkY bulk chunk/atom bin/1d y center 0.307692307692308 units box region pipe
+fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY vx file Vy_profile ave running overwrite
+fix velYprof bulk ave/chunk 1 1 50 chunkY vx file Vy_profile ave running overwrite
+
+#full trajectory
+# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z
+# dump_modify 7 sort id
+
+run ${run}
+run 2000
+Per MPI rank memory allocation (min/avg/max) = 5.174 | 5.174 | 5.174 Mbytes
+Step c_myT c_myTp TotEng Press
+ 2000 2.0302713 2.0802515 0.53472229 6.5470853
+ 2010 2.0303419 2.0806129 0.54177821 6.5808527
+ 2020 2.0245167 2.0792991 0.54803523 6.6381758
+ 2030 2.0169072 2.065404 0.55345227 6.7008962
+ 2040 2.0052526 2.0513817 0.55818432 6.7755868
+ 2050 1.9953625 2.0366564 0.56245299 6.8382569
+ 2060 2.0003667 2.0462109 0.56649798 6.8390557
+ 2070 2.0238288 2.0834553 0.57023651 6.7637821
+ 2080 2.045765 2.1173867 0.5730944 6.6861321
+ 2090 2.0563925 2.1370313 0.57430831 6.6422581
+ 2100 2.0620437 2.1480293 0.57319824 6.6080678
+ 2110 2.0584437 2.1473173 0.56913597 6.5969671
+ 2120 2.0532825 2.1393006 0.56154606 6.5799417
+ 2130 2.0450143 2.1234905 0.55009479 6.5616931
+ 2140 2.0229537 2.1004507 0.53511912 6.5854627
+ 2150 1.9832556 2.0554119 0.51812599 6.6700591
+ 2160 1.9444027 2.0110758 0.50163049 6.7534263
+ 2170 1.9267473 1.9904528 0.48759542 6.76469
+ 2180 1.9262232 1.9809353 0.47662199 6.7188048
+ 2190 1.9359331 1.9854626 0.46836289 6.6406985
+ 2200 1.9530728 1.9971865 0.4620366 6.5409943
+ 2210 1.9657099 2.0056761 0.45692542 6.4639397
+ 2220 1.9661008 2.0046161 0.45253504 6.4388081
+ 2230 1.9574696 1.9947839 0.44864257 6.4528687
+ 2240 1.9522284 1.9922663 0.44518111 6.4584458
+ 2250 1.9518203 1.9950044 0.44206844 6.4491722
+ 2260 1.9527908 1.9989603 0.4391804 6.4377912
+ 2270 1.9452231 1.9932538 0.43643529 6.4607516
+ 2280 1.9249341 1.9759145 0.43392742 6.5320897
+ 2290 1.9087464 1.960985 0.43186869 6.5875176
+ 2300 1.9103289 1.964731 0.43039882 6.5765021
+ 2310 1.9182062 1.9783814 0.4294628 6.5434488
+ 2320 1.9204281 1.9796609 0.42889381 6.5351629
+ 2330 1.916279 1.9720659 0.42866391 6.5562619
+ 2340 1.9062866 1.9587628 0.42890166 6.6033936
+ 2350 1.9024117 1.9566812 0.42979475 6.6297969
+ 2360 1.908153 1.960687 0.43141898 6.6215148
+ 2370 1.9115944 1.9663337 0.43376668 6.6236491
+ 2380 1.9086193 1.9637867 0.4367911 6.6529568
+ 2390 1.9039907 1.9610268 0.44053991 6.6926343
+ 2400 1.9034944 1.9609406 0.44508818 6.7193441
+ 2410 1.9151521 1.9753641 0.4504458 6.7015957
+ 2420 1.9314517 1.9925924 0.45644382 6.6669864
+ 2430 1.9433933 2.0062001 0.46277215 6.6481527
+ 2440 1.9504631 2.0087015 0.46917209 6.6475757
+ 2450 1.9550092 2.0094957 0.47550077 6.6556459
+ 2460 1.9609689 2.0147997 0.48170141 6.6568282
+ 2470 1.9730726 2.0328127 0.48763131 6.6337545
+ 2480 1.9838562 2.0466643 0.49303443 6.6143423
+ 2490 1.9862031 2.0473388 0.49767532 6.6245587
+ 2500 1.9817565 2.0455432 0.50152131 6.6573893
+ 2510 1.9785788 2.0423176 0.50460561 6.6808042
+ 2520 1.9823006 2.0505106 0.50696374 6.6726698
+ 2530 1.9907178 2.0553736 0.50852885 6.6402082
+ 2540 2.0005205 2.0690408 0.50919421 6.5966469
+ 2550 2.0079727 2.0809816 0.50872954 6.5568419
+ 2560 2.0133128 2.096271 0.50682742 6.5199915
+ 2570 2.0141298 2.0990846 0.50314491 6.4951991
+ 2580 2.0048768 2.0874319 0.49750096 6.5025454
+ 2590 1.9876498 2.0638834 0.4900201 6.5333038
+ 2600 1.9720479 2.0474479 0.48105263 6.5527157
+ 2610 1.9596324 2.0355764 0.4710001 6.5547867
+ 2620 1.9439039 2.0106405 0.46046644 6.5646889
+ 2630 1.9321714 1.9924346 0.45021207 6.5589454
+ 2640 1.9349378 1.9923889 0.44082833 6.5012762
+ 2650 1.9448459 2.0069955 0.43251999 6.4228945
+ 2660 1.9446852 2.0050346 0.42525857 6.3921645
+ 2670 1.9325594 1.9884937 0.41913362 6.4169726
+ 2680 1.9121687 1.9606084 0.41434428 6.4821267
+ 2690 1.8923613 1.9339385 0.41105831 6.5517615
+ 2700 1.8807238 1.9191801 0.40933203 6.5949447
+ 2710 1.8797367 1.918758 0.40906826 6.6001309
+ 2720 1.8852961 1.9225996 0.41005611 6.58191
+ 2730 1.8937478 1.9357751 0.41204348 6.5541946
+ 2740 1.9019279 1.9449374 0.41476104 6.5278575
+ 2750 1.9134396 1.9614415 0.41800066 6.4890769
+ 2760 1.9339551 1.9913779 0.42150554 6.4159805
+ 2770 1.9597826 2.0220988 0.42487614 6.3232273
+ 2780 1.9753466 2.0414907 0.42771704 6.2715489
+ 2790 1.9720423 2.0402016 0.42976012 6.2949288
+ 2800 1.9512893 2.0172711 0.43109201 6.3878056
+ 2810 1.9232302 1.9870212 0.4320928 6.5101822
+ 2820 1.9026913 1.959286 0.43326424 6.6024967
+ 2830 1.9033802 1.9621601 0.43500785 6.6114274
+ 2840 1.9214292 1.9833838 0.43733454 6.5508757
+ 2850 1.9440563 2.0087358 0.43995473 6.4713496
+ 2860 1.9589136 2.0211107 0.44250821 6.4232961
+ 2870 1.9588429 2.022232 0.44477492 6.4355861
+ 2880 1.9456751 2.0009513 0.44676532 6.5021746
+ 2890 1.9269155 1.9782929 0.44877858 6.5926531
+ 2900 1.9125262 1.9554653 0.45121196 6.6657808
+ 2910 1.9187855 1.9572583 0.45438665 6.6589954
+ 2920 1.9416112 1.9784518 0.45839212 6.5888253
+ 2930 1.9613579 1.9975032 0.46305788 6.5317424
+ 2940 1.9711529 2.0102501 0.46812715 6.5148943
+ 2950 1.9707865 2.0133283 0.47345305 6.5389543
+ 2960 1.9732526 2.0170219 0.47898306 6.5537092
+ 2970 1.9871126 2.0282309 0.48465048 6.5273492
+ 2980 1.9953449 2.0404164 0.49032615 6.5227325
+ 2990 1.9909136 2.037246 0.49581423 6.5664662
+ 3000 1.9872474 2.0307896 0.5011051 6.6060698
+ 3010 1.9944885 2.0457308 0.5062755 6.6031811
+ 3020 2.0103461 2.0599491 0.51116655 6.5654871
+ 3030 2.0240275 2.077342 0.5154921 6.5358852
+ 3040 2.0205953 2.0704954 0.51898871 6.5708937
+ 3050 2.0032184 2.0463036 0.52167438 6.657741
+ 3060 1.9889341 2.0265284 0.52385964 6.7329171
+ 3070 1.9795143 2.0201081 0.52588914 6.7881407
+ 3080 1.9713362 2.0123964 0.52797238 6.8362858
+ 3090 1.9692592 2.0106467 0.53025538 6.8616268
+ 3100 1.9722487 2.0259566 0.53277635 6.8689898
+ 3110 1.9703322 2.0314028 0.53541462 6.895271
+ 3120 1.9594359 2.0217586 0.53808512 6.954362
+ 3130 1.9524729 2.0148628 0.5409094 6.9965233
+ 3140 1.9630381 2.0260807 0.54400259 6.968082
+ 3150 1.9902598 2.0549364 0.54720142 6.8698796
+ 3160 2.029715 2.0923999 0.54995378 6.7193678
+ 3170 2.0581544 2.1137995 0.55150021 6.6053728
+ 3180 2.0590739 2.1156535 0.55123668 6.5919337
+ 3190 2.0400682 2.0904721 0.54894762 6.6505757
+ 3200 2.0211594 2.0682597 0.54484887 6.7046468
+ 3210 2.012712 2.0573114 0.53922056 6.7130909
+ 3220 2.0102377 2.0554701 0.53219251 6.6919068
+ 3230 2.0017671 2.0505068 0.52386898 6.6867054
+ 3240 1.9854941 2.0308454 0.51458791 6.7051085
+ 3250 1.9767009 2.0187664 0.50486784 6.6916859
+ 3260 1.9771733 2.0186148 0.49510721 6.6424305
+ 3270 1.974003 2.0136039 0.48556818 6.6078903
+ 3280 1.9627665 1.9989122 0.47654147 6.6067904
+ 3290 1.9491247 1.9826247 0.46834865 6.6186709
+ 3300 1.9414093 1.9724941 0.4612122 6.6119543
+ 3310 1.9433901 1.9715482 0.45518879 6.570612
+ 3320 1.9518837 1.9872717 0.45010165 6.5057947
+ 3330 1.9603874 1.9957995 0.44566728 6.4428221
+ 3340 1.9615962 1.9945224 0.44167201 6.4099339
+ 3350 1.955918 1.9882866 0.4380303 6.4070811
+ 3360 1.9463445 1.9763654 0.43480086 6.4241178
+ 3370 1.9411187 1.9683081 0.4320639 6.4296577
+ 3380 1.9407224 1.9580074 0.42991627 6.4210217
+ 3390 1.9402479 1.9530447 0.42850635 6.4170536
+ 3400 1.9451337 1.9555771 0.42787382 6.3990336
+ 3410 1.9475586 1.9612432 0.42797178 6.3953251
+ 3420 1.9434927 1.960532 0.4286887 6.4210681
+ 3430 1.9339054 1.9516935 0.43003682 6.4707071
+ 3440 1.9234014 1.9464343 0.43214965 6.5248205
+ 3450 1.9191846 1.9444777 0.43516361 6.5558451
+ 3460 1.923218 1.9594606 0.43915611 6.5549213
+ 3470 1.9328953 1.9792053 0.44397878 6.5327637
+ 3480 1.9466227 1.9997841 0.44940599 6.4954965
+ 3490 1.9672374 2.0323219 0.45511091 6.4358811
+ 3500 1.9799622 2.0479841 0.46061029 6.4100217
+ 3510 1.97942 2.0493411 0.46551964 6.4368108
+ 3520 1.9725674 2.0389602 0.46976379 6.4892049
+ 3530 1.9716429 2.0389798 0.47344292 6.5200899
+ 3540 1.9789254 2.0486162 0.47659268 6.5198212
+ 3550 1.9872455 2.0577517 0.47908145 6.5144586
+ 3560 1.9808834 2.0545963 0.48076562 6.5633282
+ 3570 1.9637165 2.0335394 0.4816783 6.6519124
+ 3580 1.9407948 2.0067763 0.48212406 6.7605224
+ 3590 1.9226532 1.9825887 0.482523 6.8486041
+ 3600 1.9135067 1.9700999 0.48328349 6.8977859
+ 3610 1.9157516 1.9720028 0.48470695 6.8977759
+ 3620 1.9328644 2.0001154 0.48688778 6.8361569
+ 3630 1.9568208 2.0243053 0.48963934 6.7442107
+ 3640 1.9824587 2.0569223 0.49259174 6.6452535
+ 3650 1.9934906 2.0686357 0.49529039 6.6020218
+ 3660 1.9996281 2.0747054 0.49732231 6.5808905
+ 3670 2.0038801 2.0772777 0.49838834 6.5691351
+ 3680 1.9941342 2.0712365 0.49826732 6.6088108
+ 3690 1.9762631 2.0486045 0.49689109 6.6739003
+ 3700 1.9667284 2.034939 0.49438991 6.7010266
+ 3710 1.9615089 2.0168112 0.49093736 6.7040385
+ 3720 1.9613068 2.014749 0.48673789 6.6813041
+ 3730 1.9731234 2.0290151 0.48175562 6.6096756
+ 3740 1.9829764 2.0461907 0.47575174 6.5424752
+ 3750 1.9792839 2.0454423 0.4685271 6.5237752
+ 3760 1.9599692 2.0287015 0.46022485 6.5616271
+ 3770 1.935975 2.0000948 0.45138017 6.6136471
+ 3780 1.9236713 1.9834802 0.44262437 6.6187463
+ 3790 1.9268004 1.9875324 0.43430113 6.5632772
+ 3800 1.932601 1.9872595 0.42649564 6.4984765
+ 3810 1.9322506 1.9814946 0.41928856 6.4617054
+ 3820 1.9245737 1.9712821 0.4128224 6.461378
+ 3830 1.9148568 1.9555602 0.40721003 6.4774474
+ 3840 1.9049961 1.9457058 0.4026118 6.5029211
+ 3850 1.8915137 1.9265199 0.39914962 6.5483592
+ 3860 1.8784768 1.9058055 0.39700153 6.5962113
+ 3870 1.8755236 1.9045158 0.39632769 6.6079033
+ 3880 1.8841415 1.9140314 0.39710038 6.5777071
+ 3890 1.8958027 1.9331148 0.39918951 6.5359786
+ 3900 1.9064085 1.948805 0.40238576 6.4998591
+ 3910 1.9185092 1.9675732 0.40647523 6.4610682
+ 3920 1.9342595 1.9933225 0.41115392 6.4122308
+ 3930 1.9482664 2.007614 0.41603495 6.373684
+ 3940 1.9557759 2.0161573 0.42084462 6.3636707
+ 3950 1.9573687 2.016612 0.42540421 6.3804123
+ 3960 1.9486354 1.9998027 0.42974612 6.4404943
+ 3970 1.936214 1.980721 0.43412037 6.5176787
+ 3980 1.9274292 1.9595259 0.43885103 6.5846211
+ 3990 1.9233082 1.953436 0.44425085 6.6354275
+ 4000 1.9289165 1.9522097 0.45042645 6.6513836
+Loop time of 2.49114 on 1 procs for 2000 steps with 2775 atoms
+
+Performance: 69365.902 tau/day, 802.846 timesteps/s
+98.9% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 1.4257 | 1.4257 | 1.4257 | 0.0 | 57.23
+Neigh | 0.15501 | 0.15501 | 0.15501 | 0.0 | 6.22
+Comm | 0.017206 | 0.017206 | 0.017206 | 0.0 | 0.69
+Output | 0.034183 | 0.034183 | 0.034183 | 0.0 | 1.37
+Modify | 0.81531 | 0.81531 | 0.81531 | 0.0 | 32.73
+Other | | 0.04374 | | | 1.76
+
+Nlocal: 2775 ave 2775 max 2775 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 517 ave 517 max 517 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 24366 ave 24366 max 24366 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 24366
+Ave neighs/atom = 8.78054
+Neighbor list builds = 72
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:00:05
diff --git a/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.4 b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.4
new file mode 100644
index 000000000..6171c0da5
--- /dev/null
+++ b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.4
@@ -0,0 +1,909 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+#LAMMPS input script
+#in.GD
+#see README for details
+
+###############################################################################
+#initialize variables
+clear
+ using 1 OpenMP thread(s) per MPI task
+
+#frequency for outputting info (timesteps)
+variable dump_rate equal 50
+variable thermo_rate equal 10
+
+#equilibration time (timesteps)
+variable equil equal 1000
+
+#stabilization time (timesteps to reach steady-state)
+variable stabil equal 1000
+
+#data collection time (timesteps)
+variable run equal 2000
+
+#length of pipe
+variable L equal 30
+
+#width of pipe
+variable d equal 20
+
+#flux (mass/sigma*tau)
+variable J equal 0.1
+
+#simulation box dimensions
+variable Lx equal 100
+variable Ly equal 40
+
+#bulk fluid density
+variable dens equal 0.8
+
+#lattice spacing for wall atoms
+variable aWall equal 1.0 #1.7472
+
+#timestep
+variable ts equal 0.001
+
+#temperature
+variable T equal 2.0
+
+#thermostat damping constant
+variable tdamp equal ${ts}*100
+variable tdamp equal 0.001*100
+
+units lj
+dimension 2
+atom_style atomic
+
+
+###############################################################################
+#create box
+
+#create lattice with the spacing aWall
+variable rhoWall equal ${aWall}^(-2)
+variable rhoWall equal 1^(-2)
+lattice sq ${rhoWall}
+lattice sq 1
+Lattice spacing in x,y,z = 1 1 1
+
+#modify input dimensions to be multiples of aWall
+variable L1 equal round($L/${aWall})*${aWall}
+variable L1 equal round(30/${aWall})*${aWall}
+variable L1 equal round(30/1)*${aWall}
+variable L1 equal round(30/1)*1
+variable d1 equal round($d/${aWall})*${aWall}
+variable d1 equal round(20/${aWall})*${aWall}
+variable d1 equal round(20/1)*${aWall}
+variable d1 equal round(20/1)*1
+variable Ly1 equal round(${Ly}/${aWall})*${aWall}
+variable Ly1 equal round(40/${aWall})*${aWall}
+variable Ly1 equal round(40/1)*${aWall}
+variable Ly1 equal round(40/1)*1
+variable Lx1 equal round(${Lx}/${aWall})*${aWall}
+variable Lx1 equal round(100/${aWall})*${aWall}
+variable Lx1 equal round(100/1)*${aWall}
+variable Lx1 equal round(100/1)*1
+
+#create simulation box
+variable lx2 equal ${Lx1}/2
+variable lx2 equal 100/2
+variable ly2 equal ${Ly1}/2
+variable ly2 equal 40/2
+region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 ${lx2} -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 50 -${ly2} ${ly2} 0 0.1 units box
+region simbox block -50 50 -20 ${ly2} 0 0.1 units box
+region simbox block -50 50 -20 20 0 0.1 units box
+create_box 2 simbox
+Created orthogonal box = (-50 -20 0) to (50 20 0.1)
+ 4 by 1 by 1 MPI processor grid
+
+#####################################################################
+#set up potential
+
+mass 1 1.0 #fluid atoms
+mass 2 1.0 #wall atoms
+
+pair_style lj/cut 2.5
+pair_modify shift yes
+pair_coeff 1 1 1.0 1.0 2.5
+pair_coeff 1 2 1.0 1.0 1.12246
+pair_coeff 2 2 0.0 0.0
+
+neigh_modify exclude type 2 2
+
+timestep ${ts}
+timestep 0.001
+
+#####################################################################
+#create atoms
+
+#create wall atoms everywhere
+create_atoms 2 box
+Created 4000 atoms
+
+#define region which is "walled off"
+variable dhalf equal ${d1}/2
+variable dhalf equal 20/2
+variable Lhalf equal ${L1}/2
+variable Lhalf equal 30/2
+region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 15 ${dhalf} EDGE -0.1 0.1 units box
+region walltop block -15 15 10 EDGE -0.1 0.1 units box
+region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 15 EDGE -${dhalf} -0.1 0.1 units box
+region wallbot block -15 15 EDGE -10 -0.1 0.1 units box
+region outsidewall union 2 walltop wallbot side out
+
+#remove wall atoms outside wall region
+group outside region outsidewall
+3349 atoms in group outside
+delete_atoms group outside
+Deleted 3349 atoms, new total = 651
+
+#remove wall atoms that aren't on edge of wall region
+variable x1 equal ${Lhalf}-${aWall}
+variable x1 equal 15-${aWall}
+variable x1 equal 15-1
+variable y1 equal ${dhalf}+${aWall}
+variable y1 equal 10+${aWall}
+variable y1 equal 10+1
+region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 ${x1} ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 14 ${y1} EDGE -0.1 0.1 units box
+region insideTop block -14 14 11 EDGE -0.1 0.1 units box
+region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 ${x1} EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 14 EDGE -${y1} -0.1 0.1 units box
+region insideBot block -14 14 EDGE -11 -0.1 0.1 units box
+region insideWall union 2 insideTop insideBot
+group insideWall region insideWall
+551 atoms in group insideWall
+delete_atoms group insideWall
+Deleted 551 atoms, new total = 100
+
+#define new lattice, to give correct fluid density
+#y lattice const must be a multiple of aWall
+variable atrue equal ${dens}^(-1/2)
+variable atrue equal 0.8^(-1/2)
+variable ay equal round(${atrue}/${aWall})*${aWall}
+variable ay equal round(1.11803398874989/${aWall})*${aWall}
+variable ay equal round(1.11803398874989/1)*${aWall}
+variable ay equal round(1.11803398874989/1)*1
+
+#choose x lattice const to give correct density
+variable ax equal (${ay}*${dens})^(-1)
+variable ax equal (1*${dens})^(-1)
+variable ax equal (1*0.8)^(-1)
+
+#change Lx to be multiple of ax
+variable Lx1 equal round(${Lx}/${ax})*${ax}
+variable Lx1 equal round(100/${ax})*${ax}
+variable Lx1 equal round(100/1.25)*${ax}
+variable Lx1 equal round(100/1.25)*1.25
+variable lx2 equal ${Lx1}/2
+variable lx2 equal 100/2
+change_box all x final -${lx2} ${lx2} units box
+change_box all x final -50 ${lx2} units box
+change_box all x final -50 50 units box
+ orthogonal box = (-50 -20 0) to (50 20 0.1)
+
+#define new lattice
+lattice custom ${dens} a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 1 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0
+Lattice spacing in x,y,z = 1.25 1 1
+
+#fill in rest of box with bulk particles
+variable delta equal 0.001
+variable Ldelt equal ${Lhalf}+${delta}
+variable Ldelt equal 15+${delta}
+variable Ldelt equal 15+0.001
+variable dDelt equal ${dhalf}-${delta}
+variable dDelt equal 10-${delta}
+variable dDelt equal 10-0.001
+region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box
+region left block EDGE -15.001 EDGE EDGE -0.1 0.1 units box
+region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box
+region right block 15.001 EDGE EDGE EDGE -0.1 0.1 units box
+region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -${dDelt} ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -9.999 ${dDelt} -0.1 0.1 units box
+region pipe block -15.001 15.001 -9.999 9.999 -0.1 0.1 units box
+
+region bulk union 3 left pipe right
+create_atoms 1 region bulk
+Created 2675 atoms
+
+group bulk type 1
+2675 atoms in group bulk
+group wall type 2
+100 atoms in group wall
+
+#remove atoms that are too close to wall
+delete_atoms overlap 0.9 bulk wall
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 2.8
+ ghost atom cutoff = 2.8
+ binsize = 1.4, bins = 72 29 1
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) command delete_atoms, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/2d
+ bin: standard
+ (2) pair lj/cut, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/2d/newton
+ bin: standard
+Deleted 0 atoms, new total = 2775
+
+neighbor 0.3 bin
+neigh_modify delay 0 every 1 check yes
+neigh_modify exclude group wall wall
+
+velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom
+velocity bulk create 2 78915 dist gaussian rot yes mom yes loop geom
+
+#####################################################################
+#set up PUT
+#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172
+
+#average number of particles per box, Evans and Morriss used 2.0
+variable NperBox equal 8.0
+
+#calculate box sizes
+variable boxSide equal sqrt(${NperBox}/${dens})
+variable boxSide equal sqrt(8/${dens})
+variable boxSide equal sqrt(8/0.8)
+variable nX equal round(lx/${boxSide})
+variable nX equal round(lx/3.16227766016838)
+variable nY equal round(ly/${boxSide})
+variable nY equal round(ly/3.16227766016838)
+variable dX equal lx/${nX}
+variable dX equal lx/32
+variable dY equal ly/${nY}
+variable dY equal ly/13
+
+#temperature of fluid (excluding wall)
+compute myT bulk temp
+
+#profile-unbiased temperature of fluid
+compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY}
+compute myTp bulk temp/profile 1 1 0 xy 32 ${nY}
+compute myTp bulk temp/profile 1 1 0 xy 32 13
+
+#thermo setup
+thermo ${thermo_rate}
+thermo 10
+thermo_style custom step c_myT c_myTp etotal press
+
+#dump initial configuration
+# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz
+# dump 56 wall custom 1 wall.init.lammpstrj id type x y z
+# dump_modify 55 sort id
+# dump_modify 56 sort id
+run 0
+WARNING: No fixes defined, atoms won't move (../verlet.cpp:55)
+Neighbor list info ...
+ update every 1 steps, delay 0 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 2.8
+ ghost atom cutoff = 2.8
+ binsize = 1.4, bins = 72 29 1
+ 1 neighbor lists, perpetual/occasional/extra = 1 0 0
+ (1) pair lj/cut, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/2d/newton
+ bin: standard
+Per MPI rank memory allocation (min/avg/max) = 3.067 | 3.068 | 3.07 Mbytes
+Step c_myT c_myTp TotEng Press
+ 0 2 2.0555109 0.77892922 7.3417096
+Loop time of 4.35114e-06 on 4 procs for 0 steps with 2775 atoms
+
+114.9% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0 | 0 | 0 | 0.0 | 0.00
+Neigh | 0 | 0 | 0 | 0.0 | 0.00
+Comm | 0 | 0 | 0 | 0.0 | 0.00
+Output | 0 | 0 | 0 | 0.0 | 0.00
+Modify | 0 | 0 | 0 | 0.0 | 0.00
+Other | | 4.351e-06 | | |100.00
+
+Nlocal: 693.75 ave 800 max 578 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Nghost: 266.25 ave 325 max 198 min
+Histogram: 1 1 0 0 0 0 0 0 0 2
+Neighs: 6601.5 ave 8000 max 5147 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+
+Total # of neighbors = 26406
+Ave neighs/atom = 9.51568
+Neighbor list builds = 0
+Dangerous builds = 0
+# undump 55
+# undump 56
+
+#####################################################################
+#equilibrate without GD
+
+fix nvt bulk nvt temp $T $T ${tdamp}
+fix nvt bulk nvt temp 2 $T ${tdamp}
+fix nvt bulk nvt temp 2 2 ${tdamp}
+fix nvt bulk nvt temp 2 2 0.1
+fix_modify nvt temp myTp
+WARNING: Temperature for fix modify is not for group all (../fix_nh.cpp:1395)
+fix 2 bulk enforce2d
+
+run ${equil}
+run 1000
+Per MPI rank memory allocation (min/avg/max) = 3.13 | 3.131 | 3.132 Mbytes
+Step c_myT c_myTp TotEng Press
+ 0 2 2.0555109 0.77892922 7.3417096
+ 10 1.9173594 1.9390034 0.77876976 7.6702228
+ 20 1.7033394 1.6974676 0.77977799 8.5614784
+ 30 1.5026161 1.4723993 0.78456655 9.4308258
+ 40 1.4880481 1.4591602 0.79486693 9.6134304
+ 50 1.6192437 1.6150635 0.81109069 9.2592835
+ 60 1.7404087 1.7583444 0.82955456 8.952392
+ 70 1.7757591 1.8006606 0.8452778 8.9717917
+ 80 1.7573847 1.7813629 0.85769389 9.1936368
+ 90 1.7491183 1.7726908 0.86882429 9.3712357
+ 100 1.7798944 1.8079583 0.88029084 9.3871755
+ 110 1.8440582 1.8793133 0.89259397 9.2582848
+ 120 1.9191606 1.9673434 0.90533438 9.0680574
+ 130 1.9883299 2.0484299 0.91755461 8.88117
+ 140 2.0463366 2.1111872 0.92818114 8.7184178
+ 150 2.0953769 2.167849 0.93639789 8.5713408
+ 160 2.1442147 2.2216228 0.94145082 8.4082835
+ 170 2.1797848 2.2631458 0.94246877 8.2767903
+ 180 2.1863476 2.2700986 0.93873326 8.2311689
+ 190 2.1832866 2.2710551 0.93003012 8.1959062
+ 200 2.1937154 2.2868403 0.91642537 8.0842007
+ 210 2.2022708 2.2915142 0.89824533 7.9575312
+ 220 2.1884715 2.2770564 0.87677613 7.9000591
+ 230 2.1671124 2.2496063 0.85409501 7.8673156
+ 240 2.1560417 2.2379998 0.83167878 7.8003228
+ 250 2.1421449 2.2240624 0.81004723 7.7491508
+ 260 2.1172164 2.1971044 0.78931978 7.7457415
+ 270 2.0856847 2.1672998 0.76956352 7.7719788
+ 280 2.0670685 2.1449303 0.75073364 7.7524614
+ 290 2.0639481 2.1428374 0.73258016 7.6727716
+ 300 2.055776 2.1361719 0.7147669 7.6095248
+ 310 2.038425 2.1209353 0.69722853 7.5797085
+ 320 2.0203023 2.1066031 0.68006634 7.5521081
+ 330 2.0118478 2.1039797 0.66330302 7.4877535
+ 340 2.0159442 2.1096258 0.64673694 7.3761703
+ 350 2.0166408 2.1075061 0.63020017 7.2788
+ 360 2.0059407 2.0806316 0.61387618 7.2263941
+ 370 1.9964281 2.0642074 0.59814148 7.1728041
+ 380 1.9918446 2.0567527 0.58303017 7.101597
+ 390 1.992835 2.0548138 0.56852431 7.0084774
+ 400 2.0012934 2.0615016 0.55438401 6.8865948
+ 410 2.0084291 2.073418 0.54034073 6.7697478
+ 420 2.007464 2.0786717 0.52617041 6.6849032
+ 430 1.9983712 2.0704366 0.51188183 6.6323103
+ 440 1.9884651 2.0588515 0.49765394 6.5868356
+ 450 1.982221 2.0467396 0.4837102 6.5311681
+ 460 1.9738673 2.031238 0.47021649 6.4882783
+ 470 1.9574246 2.0060447 0.45740021 6.4814923
+ 480 1.9361065 1.9734507 0.44557947 6.4995199
+ 490 1.9251024 1.9562469 0.43506067 6.4858343
+ 500 1.9279545 1.9572145 0.42577835 6.4274765
+ 510 1.9267504 1.9570246 0.41755013 6.3927027
+ 520 1.9093405 1.9393872 0.41031829 6.4281888
+ 530 1.8820555 1.9060756 0.40432569 6.5099401
+ 540 1.86537 1.8912682 0.3999087 6.55843
+ 550 1.8694252 1.9043192 0.39717519 6.5337875
+ 560 1.8835224 1.9294105 0.39589322 6.4760141
+ 570 1.8898719 1.9462433 0.39573596 6.4520041
+ 580 1.8887698 1.9472764 0.39649878 6.4602989
+ 590 1.8945125 1.9550624 0.39810844 6.4470226
+ 600 1.9106571 1.9735939 0.40045321 6.3971026
+ 610 1.9273243 1.98509 0.40330026 6.3474421
+ 620 1.9351802 1.9888986 0.4064498 6.3340566
+ 630 1.9337889 1.9846794 0.40981479 6.3610556
+ 640 1.9257018 1.9757153 0.4134641 6.4184721
+ 650 1.9204429 1.9718256 0.41750942 6.4679594
+ 660 1.9220449 1.9701963 0.42202455 6.4919724
+ 670 1.9230578 1.9707406 0.4270412 6.5178484
+ 680 1.9204554 1.9740485 0.43255127 6.5572507
+ 690 1.9201811 1.9762854 0.43847123 6.5869126
+ 700 1.9271511 1.9867455 0.44474356 6.5882669
+ 710 1.9418851 2.0042477 0.45120727 6.558573
+ 720 1.9544547 2.0186724 0.4576061 6.5338329
+ 730 1.9687971 2.0326169 0.46367507 6.4988775
+ 740 1.9830308 2.0466267 0.46920367 6.4618136
+ 750 1.9936981 2.0526606 0.47397868 6.4367349
+ 760 2.0008431 2.0535449 0.47786748 6.4249001
+ 770 1.9982133 2.0483219 0.48085757 6.4504786
+ 780 1.9841544 2.0311693 0.48306488 6.5200512
+ 790 1.9683122 2.0158738 0.48475632 6.5959263
+ 800 1.9604618 2.003224 0.48619405 6.6392559
+ 810 1.9629155 2.0075077 0.48756075 6.6406486
+ 820 1.9683056 2.0110554 0.48883443 6.6269424
+ 830 1.975409 2.0189161 0.48995399 6.6030215
+ 840 1.9897264 2.035016 0.4907852 6.5485575
+ 850 2.0094338 2.0555358 0.49104505 6.4719926
+ 860 2.0217589 2.0643603 0.49040437 6.4233305
+ 870 2.0147718 2.0641627 0.48866908 6.4491964
+ 880 1.9883859 2.0324092 0.48592007 6.5488061
+ 890 1.9625853 2.0028776 0.48263002 6.6452734
+ 900 1.9520401 1.9889124 0.47925524 6.6808078
+ 910 1.9559583 1.9952984 0.47597346 6.6573059
+ 920 1.9657244 2.0083503 0.47268726 6.6073704
+ 930 1.969288 2.0152339 0.4692054 6.5780416
+ 940 1.9652206 2.0116384 0.4654438 6.5769812
+ 950 1.9567495 1.9960693 0.46147541 6.5942022
+ 960 1.9418452 1.980858 0.45753557 6.6369454
+ 970 1.9247196 1.9585585 0.45390337 6.6888821
+ 980 1.9128262 1.9481721 0.45090045 6.7198221
+ 990 1.9167211 1.9451096 0.44869731 6.6912394
+ 1000 1.935529 1.9662384 0.44728238 6.6079829
+Loop time of 0.474418 on 4 procs for 1000 steps with 2775 atoms
+
+Performance: 182118.045 tau/day, 2107.848 timesteps/s
+98.4% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.13953 | 0.19068 | 0.23764 | 10.4 | 40.19
+Neigh | 0.016439 | 0.022345 | 0.027069 | 3.2 | 4.71
+Comm | 0.018215 | 0.068071 | 0.12178 | 18.6 | 14.35
+Output | 0.011982 | 0.012633 | 0.013047 | 0.4 | 2.66
+Modify | 0.14494 | 0.15597 | 0.16628 | 2.4 | 32.88
+Other | | 0.02472 | | | 5.21
+
+Nlocal: 693.75 ave 800 max 584 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Nghost: 255.5 ave 323 max 192 min
+Histogram: 2 0 0 0 0 0 0 0 1 1
+Neighs: 6083 ave 7384 max 4742 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+
+Total # of neighbors = 24332
+Ave neighs/atom = 8.76829
+Neighbor list builds = 38
+Dangerous builds = 0
+
+#####################################################################
+#initialize the COM velocity and run to achieve steady-state
+
+#calculate velocity to add: V=J/rho_total
+variable Vadd equal $J*lx*ly/count(bulk)
+variable Vadd equal 0.1*lx*ly/count(bulk)
+
+#first remove any COM velocity, then add back the streaming velocity
+velocity bulk zero linear
+velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no
+velocity bulk set 0.149532710280374 0.0 0.0 units box sum yes mom no
+
+fix GD bulk flow/gauss 1 0 0 #energy yes
+#fix_modify GD energy yes
+
+run ${stabil}
+run 1000
+Per MPI rank memory allocation (min/avg/max) = 3.13 | 3.131 | 3.132 Mbytes
+Step c_myT c_myTp TotEng Press
+ 1000 1.9466974 1.9662384 0.45804438 6.615449
+ 1010 1.9605467 1.9815754 0.45717241 6.5545496
+ 1020 1.9560139 1.9823875 0.45660431 6.5672421
+ 1030 1.9348326 1.9691606 0.45633148 6.6463667
+ 1040 1.9167809 1.9449522 0.45657707 6.7139486
+ 1050 1.9193541 1.943342 0.45767968 6.7014054
+ 1060 1.9410751 1.9720491 0.45967742 6.6150379
+ 1070 1.9658493 1.9964883 0.46221539 6.5178418
+ 1080 1.9767205 2.0074304 0.46491236 6.4768594
+ 1090 1.9714544 2.0003054 0.46759126 6.5026957
+ 1100 1.9647035 1.9927455 0.4703109 6.5400181
+ 1110 1.9657667 1.9959656 0.47317481 6.5519094
+ 1120 1.9706062 1.9980802 0.476185 6.5512675
+ 1130 1.9747655 2.0062292 0.47932281 6.554091
+ 1140 1.9761245 2.0075076 0.48248327 6.5670381
+ 1150 1.9744197 2.0073027 0.48562483 6.5914441
+ 1160 1.9722698 2.0046687 0.48874207 6.6165575
+ 1170 1.9692145 2.0013845 0.49187442 6.6438115
+ 1180 1.9665609 1.9970724 0.49508053 6.6693821
+ 1190 1.9625031 1.9908427 0.49843816 6.7002606
+ 1200 1.960528 1.993084 0.50203044 6.7237076
+ 1210 1.9649156 1.9981485 0.50587066 6.7217755
+ 1220 1.9788059 2.0134511 0.50987442 6.6833452
+ 1230 1.9952283 2.0343101 0.51379781 6.6340278
+ 1240 2.0039391 2.0494196 0.51730872 6.6129751
+ 1250 2.0019006 2.0526773 0.52014603 6.6320217
+ 1260 1.9974025 2.0528914 0.52221385 6.6601786
+ 1270 1.9953949 2.0561121 0.5234754 6.6796142
+ 1280 1.9893864 2.0470375 0.5238632 6.7140134
+ 1290 1.9694951 2.019253 0.5235093 6.798442
+ 1300 1.9473901 1.9965919 0.52280384 6.8863369
+ 1310 1.9511151 2.006161 0.52203882 6.8700917
+ 1320 1.979341 2.0388959 0.52106938 6.7529595
+ 1330 2.0073235 2.0720045 0.51935291 6.6297731
+ 1340 2.0202482 2.0841419 0.51624273 6.55803
+ 1350 2.0177489 2.0669046 0.51142591 6.5401753
+ 1360 2.0069274 2.04717 0.50505824 6.5506533
+ 1370 1.994854 2.0311383 0.49743042 6.5633001
+ 1380 1.9793176 2.0077184 0.48890503 6.5859072
+ 1390 1.9580907 1.9839831 0.48004316 6.6288992
+ 1400 1.9415542 1.9594192 0.47143599 6.6534105
+ 1410 1.9405188 1.9591825 0.46353105 6.620549
+ 1420 1.9504784 1.9730647 0.45640199 6.5471784
+ 1430 1.9594158 1.9819854 0.44995052 6.4802874
+ 1440 1.9615108 1.9863792 0.44406411 6.44391
+ 1450 1.9544127 1.9806249 0.43873409 6.4484818
+ 1460 1.9384927 1.9614953 0.43408605 6.4905259
+ 1470 1.9214711 1.9425515 0.43035972 6.5390434
+ 1480 1.9170761 1.9300809 0.42775046 6.5409502
+ 1490 1.9242904 1.9385731 0.42631007 6.5005057
+ 1500 1.9307133 1.9446119 0.4258836 6.4660754
+ 1510 1.9303576 1.9435389 0.42633976 6.4616415
+ 1520 1.9248382 1.9408306 0.42765441 6.4832059
+ 1530 1.9120794 1.9278123 0.42986958 6.5380951
+ 1540 1.899122 1.9125029 0.4331459 6.5987181
+ 1550 1.9030956 1.9187821 0.43765067 6.6012019
+ 1560 1.9182961 1.9453782 0.44330842 6.5674222
+ 1570 1.9272863 1.9613129 0.44971962 6.5619794
+ 1580 1.931679 1.9698134 0.45643436 6.5780809
+ 1590 1.9336692 1.9728684 0.46314752 6.6035675
+ 1600 1.938895 1.9823104 0.46964519 6.6138411
+ 1610 1.9510838 1.9937914 0.47568807 6.5916989
+ 1620 1.9685387 2.0087314 0.48102339 6.5424432
+ 1630 1.9894416 2.0295715 0.48539861 6.4757743
+ 1640 1.9982699 2.0426949 0.48860411 6.4512418
+ 1650 1.9901677 2.0363837 0.49062424 6.4879985
+ 1660 1.9814216 2.0291326 0.49172203 6.5248034
+ 1670 1.9812111 2.0293629 0.49218297 6.5253876
+ 1680 1.9903906 2.0408376 0.49211747 6.4852787
+ 1690 2.0015983 2.0538843 0.4914581 6.4325081
+ 1700 2.009727 2.0503407 0.49011163 6.3878577
+ 1710 2.0167822 2.0531002 0.4881688 6.3477054
+ 1720 2.0189021 2.0445033 0.48564798 6.3273063
+ 1730 2.0129713 2.0354734 0.48270666 6.3385541
+ 1740 2.0048763 2.0199836 0.47950943 6.3587586
+ 1750 1.9994843 2.0085942 0.47624908 6.3694119
+ 1760 1.9940025 2.0072098 0.47305283 6.3816295
+ 1770 1.9817431 1.9974066 0.46994486 6.4224295
+ 1780 1.965171 1.9805421 0.4670779 6.4832371
+ 1790 1.9474078 1.9662605 0.46466823 6.5516524
+ 1800 1.9286009 1.9507751 0.46292015 6.6263366
+ 1810 1.9168087 1.9437961 0.46199899 6.6759834
+ 1820 1.9107555 1.9306323 0.46204129 6.7029857
+ 1830 1.9135569 1.930819 0.46316484 6.6949737
+ 1840 1.9345342 1.9553413 0.46532704 6.6178988
+ 1850 1.9630349 1.9929548 0.46822932 6.5137866
+ 1860 1.9820746 2.0188839 0.47135068 6.4489028
+ 1870 1.9834959 2.0217145 0.47427805 6.4552721
+ 1880 1.9731564 2.0120293 0.47692755 6.5100251
+ 1890 1.9653605 2.0070624 0.47943307 6.5594235
+ 1900 1.9630631 2.0095488 0.48192185 6.5912876
+ 1910 1.9556778 2.0035006 0.48443107 6.6437189
+ 1920 1.9408788 1.9828296 0.48710124 6.7228731
+ 1930 1.9292393 1.9732376 0.49025327 6.7880112
+ 1940 1.9263081 1.9708942 0.49416086 6.8162477
+ 1950 1.9358375 1.976323 0.49899895 6.7946964
+ 1960 1.9520543 1.9936542 0.50485961 6.7467481
+ 1970 1.9709064 2.0108957 0.51165586 6.6909455
+ 1980 1.9940026 2.0375428 0.51918913 6.6250463
+ 1990 2.0171261 2.0646948 0.52705638 6.5649879
+ 2000 2.0302713 2.0802515 0.53472229 6.5470853
+Loop time of 0.482133 on 4 procs for 1000 steps with 2775 atoms
+
+Performance: 179203.608 tau/day, 2074.116 timesteps/s
+98.6% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.1081 | 0.18228 | 0.23471 | 12.7 | 37.81
+Neigh | 0.011443 | 0.019967 | 0.025651 | 4.1 | 4.14
+Comm | 0.01639 | 0.073615 | 0.15634 | 21.8 | 15.27
+Output | 0.011851 | 0.012603 | 0.013287 | 0.5 | 2.61
+Modify | 0.14306 | 0.16634 | 0.18018 | 3.6 | 34.50
+Other | | 0.02733 | | | 5.67
+
+Nlocal: 693.75 ave 797 max 590 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Nghost: 259 ave 320 max 195 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Neighs: 6101 ave 7360 max 4853 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+
+Total # of neighbors = 24404
+Ave neighs/atom = 8.79423
+Neighbor list builds = 36
+Dangerous builds = 0
+
+#####################################################################
+#collect data
+
+#print the applied force and total flux to ensure conservation of Jx
+variable Fapp equal f_GD[1]
+compute vxBulk bulk reduce sum vx
+compute vyBulk bulk reduce sum vy
+variable invVol equal 1.0/(lx*ly)
+variable jx equal c_vxBulk*${invVol}
+variable jx equal c_vxBulk*0.00025
+variable jy equal c_vyBulk*${invVol}
+variable jy equal c_vyBulk*0.00025
+variable curr_step equal step
+variable p_Fapp format Fapp %.3f
+variable p_jx format jx %.5g
+variable p_jy format jy %.5g
+fix print_vCOM all print ${dump_rate} "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy"
+fix print_vCOM all print 50 "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy"
+
+#compute IK1 pressure profile
+#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627
+#use profile-unbiased temperature to remove the streaming velocity
+#from the kinetic part of the pressure
+compute spa bulk stress/atom myTp
+
+#for the pressure profile, use the same grid as the PUT
+compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box
+compute chunkX bulk chunk/atom bin/1d x lower 3.125 units box
+
+#output pressure profile and other profiles
+#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where
+#V is the volume of a slice
+fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite
+fix profiles bulk ave/chunk 1 1 50 chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite
+
+#compute velocity profile across the pipe with a finer grid
+variable dYnew equal ${dY}/10
+variable dYnew equal 3.07692307692308/10
+compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box region pipe
+compute chunkY bulk chunk/atom bin/1d y center 0.307692307692308 units box region pipe
+fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY vx file Vy_profile ave running overwrite
+fix velYprof bulk ave/chunk 1 1 50 chunkY vx file Vy_profile ave running overwrite
+
+#full trajectory
+# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z
+# dump_modify 7 sort id
+
+run ${run}
+run 2000
+Per MPI rank memory allocation (min/avg/max) = 5.138 | 5.139 | 5.14 Mbytes
+Step c_myT c_myTp TotEng Press
+ 2000 2.0302713 2.0802515 0.53472229 6.5470853
+ 2010 2.0303419 2.0806129 0.54177821 6.5808527
+ 2020 2.0245167 2.0792991 0.54803523 6.6381758
+ 2030 2.0169072 2.065404 0.55345227 6.7008962
+ 2040 2.0052526 2.0513817 0.55818432 6.7755868
+ 2050 1.9953625 2.0366564 0.56245299 6.8382569
+ 2060 2.0003667 2.0462109 0.56649798 6.8390557
+ 2070 2.0238288 2.0834553 0.57023651 6.7637821
+ 2080 2.045765 2.1173867 0.5730944 6.6861321
+ 2090 2.0563925 2.1370313 0.57430831 6.6422581
+ 2100 2.0620437 2.1480293 0.57319824 6.6080678
+ 2110 2.0584437 2.1473173 0.56913597 6.5969671
+ 2120 2.0532825 2.1393006 0.56154606 6.5799417
+ 2130 2.0450143 2.1234905 0.55009479 6.5616931
+ 2140 2.0229537 2.1004507 0.53511912 6.5854627
+ 2150 1.9832556 2.0554119 0.51812599 6.6700591
+ 2160 1.9444027 2.0110758 0.50163049 6.7534263
+ 2170 1.9267473 1.9904528 0.48759542 6.76469
+ 2180 1.9262232 1.9809353 0.47662199 6.7188048
+ 2190 1.9359331 1.9854626 0.46836289 6.6406985
+ 2200 1.9530728 1.9971865 0.4620366 6.5409943
+ 2210 1.9657099 2.0056761 0.45692542 6.4639397
+ 2220 1.9661008 2.0046161 0.45253504 6.4388081
+ 2230 1.9574696 1.9947839 0.44864257 6.4528687
+ 2240 1.9522284 1.9922663 0.44518111 6.4584458
+ 2250 1.9518203 1.9950044 0.44206844 6.4491722
+ 2260 1.9527908 1.9989603 0.4391804 6.4377912
+ 2270 1.9452231 1.9932538 0.43643529 6.4607516
+ 2280 1.9249341 1.9759145 0.43392742 6.5320897
+ 2290 1.9087464 1.960985 0.43186869 6.5875176
+ 2300 1.9103289 1.964731 0.43039882 6.5765021
+ 2310 1.9182062 1.9783814 0.4294628 6.5434488
+ 2320 1.9204281 1.9796609 0.42889381 6.5351629
+ 2330 1.916279 1.9720659 0.42866391 6.5562619
+ 2340 1.9062866 1.9587628 0.42890166 6.6033936
+ 2350 1.9024117 1.9566812 0.42979475 6.6297969
+ 2360 1.908153 1.960687 0.43141898 6.6215148
+ 2370 1.9115944 1.9663337 0.43376668 6.6236491
+ 2380 1.9086193 1.9637867 0.4367911 6.6529568
+ 2390 1.9039907 1.9610268 0.44053991 6.6926343
+ 2400 1.9034944 1.9609406 0.44508818 6.7193441
+ 2410 1.9151521 1.9753641 0.4504458 6.7015957
+ 2420 1.9314517 1.9925924 0.45644382 6.6669864
+ 2430 1.9433933 2.0062001 0.46277215 6.6481527
+ 2440 1.9504631 2.0087015 0.46917209 6.6475757
+ 2450 1.9550092 2.0094957 0.47550077 6.6556459
+ 2460 1.9609689 2.0147997 0.48170141 6.6568282
+ 2470 1.9730726 2.0328127 0.48763131 6.6337545
+ 2480 1.9838562 2.0466643 0.49303443 6.6143423
+ 2490 1.9862031 2.0473388 0.49767532 6.6245587
+ 2500 1.9817565 2.0455432 0.50152131 6.6573893
+ 2510 1.9785788 2.0423176 0.50460561 6.6808042
+ 2520 1.9823006 2.0505106 0.50696374 6.6726698
+ 2530 1.9907178 2.0553736 0.50852885 6.6402082
+ 2540 2.0005205 2.0690408 0.50919421 6.5966469
+ 2550 2.0079727 2.0809816 0.50872954 6.5568419
+ 2560 2.0133128 2.096271 0.50682742 6.5199915
+ 2570 2.0141298 2.0990846 0.50314491 6.4951991
+ 2580 2.0048768 2.0874319 0.49750096 6.5025454
+ 2590 1.9876498 2.0638834 0.4900201 6.5333038
+ 2600 1.9720479 2.0474479 0.48105263 6.5527157
+ 2610 1.9596324 2.0355764 0.4710001 6.5547867
+ 2620 1.9439039 2.0106405 0.46046644 6.5646889
+ 2630 1.9321714 1.9924346 0.45021207 6.5589454
+ 2640 1.9349378 1.9923889 0.44082833 6.5012762
+ 2650 1.9448459 2.0069955 0.43251999 6.4228945
+ 2660 1.9446852 2.0050346 0.42525857 6.3921645
+ 2670 1.9325594 1.9884937 0.41913362 6.4169726
+ 2680 1.9121687 1.9606084 0.41434428 6.4821267
+ 2690 1.8923613 1.9339385 0.41105831 6.5517615
+ 2700 1.8807238 1.9191801 0.40933203 6.5949447
+ 2710 1.8797367 1.918758 0.40906826 6.6001309
+ 2720 1.8852961 1.9225996 0.41005611 6.58191
+ 2730 1.8937478 1.9357751 0.41204348 6.5541946
+ 2740 1.9019279 1.9449374 0.41476104 6.5278575
+ 2750 1.9134396 1.9614415 0.41800066 6.4890769
+ 2760 1.9339551 1.9913779 0.42150554 6.4159805
+ 2770 1.9597826 2.0220988 0.42487614 6.3232273
+ 2780 1.9753466 2.0414907 0.42771704 6.2715489
+ 2790 1.9720423 2.0402016 0.42976012 6.2949288
+ 2800 1.9512893 2.0172711 0.43109201 6.3878056
+ 2810 1.9232302 1.9870212 0.4320928 6.5101822
+ 2820 1.9026913 1.959286 0.43326424 6.6024967
+ 2830 1.9033802 1.9621601 0.43500785 6.6114274
+ 2840 1.9214292 1.9833838 0.43733454 6.5508757
+ 2850 1.9440563 2.0087358 0.43995473 6.4713496
+ 2860 1.9589136 2.0211107 0.44250821 6.4232961
+ 2870 1.9588429 2.022232 0.44477492 6.4355861
+ 2880 1.9456751 2.0009513 0.44676532 6.5021746
+ 2890 1.9269155 1.9782929 0.44877858 6.5926531
+ 2900 1.9125262 1.9554653 0.45121196 6.6657808
+ 2910 1.9187855 1.9572583 0.45438665 6.6589954
+ 2920 1.9416112 1.9784518 0.45839212 6.5888253
+ 2930 1.9613579 1.9975032 0.46305788 6.5317424
+ 2940 1.9711529 2.0102501 0.46812715 6.5148943
+ 2950 1.9707865 2.0133283 0.47345305 6.5389543
+ 2960 1.9732526 2.0170219 0.47898306 6.5537092
+ 2970 1.9871126 2.0282309 0.48465048 6.5273492
+ 2980 1.9953449 2.0404164 0.49032615 6.5227325
+ 2990 1.9909136 2.037246 0.49581423 6.5664662
+ 3000 1.9872474 2.0307896 0.50110509 6.6060698
+ 3010 1.9944885 2.0457308 0.5062755 6.6031811
+ 3020 2.0103461 2.0599491 0.51116655 6.5654871
+ 3030 2.0240275 2.077342 0.5154921 6.5358852
+ 3040 2.0205953 2.0704954 0.51898871 6.5708937
+ 3050 2.0032184 2.0463036 0.52167438 6.657741
+ 3060 1.9889341 2.0265284 0.52385964 6.7329171
+ 3070 1.9795143 2.0201081 0.52588914 6.7881407
+ 3080 1.9713362 2.0123964 0.52797238 6.8362858
+ 3090 1.9692592 2.0106467 0.53025538 6.8616268
+ 3100 1.9722487 2.0259566 0.53277635 6.8689898
+ 3110 1.9703322 2.0314028 0.53541462 6.895271
+ 3120 1.9594359 2.0217586 0.53808512 6.954362
+ 3130 1.9524729 2.0148628 0.5409094 6.9965233
+ 3140 1.9630381 2.0260807 0.54400259 6.968082
+ 3150 1.9902598 2.0549364 0.54720142 6.8698796
+ 3160 2.029715 2.0923999 0.54995378 6.7193678
+ 3170 2.0581544 2.1137995 0.55150021 6.6053728
+ 3180 2.059074 2.1156535 0.55123668 6.5919337
+ 3190 2.0400682 2.0904721 0.54894762 6.6505757
+ 3200 2.0211594 2.0682597 0.54484887 6.7046468
+ 3210 2.012712 2.0573114 0.53922057 6.7130909
+ 3220 2.0102377 2.0554701 0.53219251 6.6919069
+ 3230 2.0017671 2.0505068 0.52386898 6.6867054
+ 3240 1.9854941 2.0308454 0.51458792 6.7051085
+ 3250 1.9767009 2.0187664 0.50486785 6.6916859
+ 3260 1.9771733 2.0186148 0.49510722 6.6424305
+ 3270 1.974003 2.0136039 0.48556819 6.6078903
+ 3280 1.9627665 1.9989122 0.47654147 6.6067904
+ 3290 1.9491247 1.9826248 0.46834866 6.6186709
+ 3300 1.9414093 1.9724941 0.4612122 6.6119543
+ 3310 1.9433901 1.9715482 0.45518879 6.570612
+ 3320 1.9518837 1.9872717 0.45010165 6.5057947
+ 3330 1.9603874 1.9957995 0.44566728 6.4428221
+ 3340 1.9615962 1.9945224 0.44167201 6.4099339
+ 3350 1.955918 1.9882866 0.4380303 6.4070811
+ 3360 1.9463445 1.9763654 0.43480086 6.4241178
+ 3370 1.9411187 1.9683081 0.43206391 6.4296577
+ 3380 1.9407224 1.9580074 0.42991627 6.4210217
+ 3390 1.9402479 1.9530447 0.42850635 6.4170536
+ 3400 1.9451337 1.9555771 0.42787382 6.3990336
+ 3410 1.9475586 1.9612432 0.42797178 6.3953251
+ 3420 1.9434927 1.960532 0.4286887 6.4210681
+ 3430 1.9339054 1.9516935 0.43003682 6.4707071
+ 3440 1.9234014 1.9464343 0.43214965 6.5248205
+ 3450 1.9191846 1.9444777 0.43516361 6.5558451
+ 3460 1.923218 1.9594606 0.43915611 6.5549213
+ 3470 1.9328953 1.9792053 0.44397878 6.5327637
+ 3480 1.9466227 1.9997841 0.44940599 6.4954965
+ 3490 1.9672374 2.0323219 0.45511091 6.4358811
+ 3500 1.9799622 2.0479841 0.46061029 6.4100217
+ 3510 1.97942 2.0493411 0.46551964 6.4368108
+ 3520 1.9725674 2.0389602 0.46976378 6.4892049
+ 3530 1.9716429 2.0389798 0.47344292 6.5200899
+ 3540 1.9789254 2.0486162 0.47659268 6.5198212
+ 3550 1.9872455 2.0577517 0.47908145 6.5144586
+ 3560 1.9808834 2.0545962 0.48076561 6.5633282
+ 3570 1.9637165 2.0335394 0.4816783 6.6519124
+ 3580 1.9407948 2.0067763 0.48212405 6.7605224
+ 3590 1.9226532 1.9825887 0.48252299 6.8486041
+ 3600 1.9135067 1.9700999 0.48328348 6.8977858
+ 3610 1.9157516 1.9720028 0.48470695 6.8977759
+ 3620 1.9328644 2.0001154 0.48688777 6.8361569
+ 3630 1.9568208 2.0243053 0.48963933 6.7442107
+ 3640 1.9824587 2.0569223 0.49259173 6.6452535
+ 3650 1.9934906 2.0686356 0.49529038 6.6020218
+ 3660 1.9996281 2.0747054 0.4973223 6.5808904
+ 3670 2.0038801 2.0772777 0.49838833 6.5691351
+ 3680 1.9941342 2.0712365 0.49826732 6.6088107
+ 3690 1.9762631 2.0486045 0.49689108 6.6739002
+ 3700 1.9667284 2.0349391 0.4943899 6.7010265
+ 3710 1.9615089 2.0168112 0.49093735 6.7040384
+ 3720 1.9613068 2.0147489 0.48673788 6.6813041
+ 3730 1.9731234 2.0290151 0.48175561 6.6096757
+ 3740 1.9829764 2.0461907 0.47575173 6.5424752
+ 3750 1.9792839 2.0454423 0.46852709 6.5237753
+ 3760 1.9599692 2.0287014 0.46022484 6.5616271
+ 3770 1.935975 2.0000948 0.45138016 6.6136471
+ 3780 1.9236713 1.9834802 0.44262435 6.6187463
+ 3790 1.9268004 1.9875324 0.43430112 6.5632772
+ 3800 1.932601 1.9872595 0.42649563 6.4984764
+ 3810 1.9322506 1.9814946 0.41928855 6.4617054
+ 3820 1.9245737 1.9712821 0.4128224 6.4613779
+ 3830 1.9148568 1.9555602 0.40721003 6.4774474
+ 3840 1.9049961 1.9457058 0.40261179 6.5029211
+ 3850 1.8915137 1.9265199 0.39914961 6.5483592
+ 3860 1.8784768 1.9058055 0.39700153 6.5962113
+ 3870 1.8755236 1.9045158 0.39632768 6.6079033
+ 3880 1.8841415 1.9140314 0.39710037 6.577707
+ 3890 1.8958027 1.9331149 0.39918951 6.5359785
+ 3900 1.9064085 1.948805 0.40238576 6.499859
+ 3910 1.9185092 1.9675733 0.40647523 6.4610682
+ 3920 1.9342595 1.9933225 0.41115392 6.4122308
+ 3930 1.9482664 2.0076139 0.41603495 6.3736841
+ 3940 1.9557759 2.0161573 0.42084462 6.3636708
+ 3950 1.9573687 2.016612 0.42540421 6.3804124
+ 3960 1.9486354 1.9998027 0.42974612 6.4404944
+ 3970 1.936214 1.9807209 0.43412037 6.5176788
+ 3980 1.9274292 1.9595259 0.43885103 6.5846212
+ 3990 1.9233082 1.953436 0.44425085 6.6354276
+ 4000 1.9289166 1.9522097 0.45042645 6.6513835
+Loop time of 0.998413 on 4 procs for 2000 steps with 2775 atoms
+
+Performance: 173074.634 tau/day, 2003.179 timesteps/s
+98.9% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.25646 | 0.3672 | 0.47947 | 15.7 | 36.78
+Neigh | 0.027925 | 0.039163 | 0.050221 | 4.5 | 3.92
+Comm | 0.032807 | 0.14565 | 0.27684 | 25.4 | 14.59
+Output | 0.025572 | 0.032272 | 0.035355 | 2.2 | 3.23
+Modify | 0.31519 | 0.35781 | 0.375 | 4.1 | 35.84
+Other | | 0.05632 | | | 5.64
+
+Nlocal: 693.75 ave 805 max 582 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Nghost: 255.5 ave 312 max 199 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+Neighs: 6091.5 ave 7423 max 4780 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+
+Total # of neighbors = 24366
+Ave neighs/atom = 8.78054
+Neighbor list builds = 72
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:00:01
diff --git a/examples/USER/misc/flow_gauss/output-files/GD.out b/examples/USER/misc/flow_gauss/output-files/GD.out
new file mode 100644
index 000000000..e3049830b
--- /dev/null
+++ b/examples/USER/misc/flow_gauss/output-files/GD.out
@@ -0,0 +1,41 @@
+timestep Fapp Jx Jy
+2050 -215.835 0.1 -0.002562
+2100 -220.455 0.1 -0.0019705
+2150 55.212 0.1 -0.0028338
+2200 87.052 0.1 -0.0042335
+2250 -62.998 0.1 -0.0045646
+2300 71.630 0.1 -0.0039858
+2350 43.159 0.1 -0.0029771
+2400 109.930 0.1 -0.0018522
+2450 110.735 0.1 -0.0011188
+2500 107.071 0.1 0.0005978
+2550 335.449 0.1 0.0010164
+2600 159.694 0.1 -0.00015953
+2650 6.532 0.1 -0.0004907
+2700 65.524 0.1 -0.00093116
+2750 79.662 0.1 -0.0033425
+2800 69.846 0.1 -0.0055377
+2850 122.175 0.1 -0.00721
+2900 32.456 0.1 -0.0086166
+2950 -85.137 0.1 -0.01107
+3000 154.735 0.1 -0.011337
+3050 72.979 0.1 -0.0095316
+3100 -24.457 0.1 -0.0098708
+3150 -0.383 0.1 -0.0094961
+3200 132.434 0.1 -0.011524
+3250 48.222 0.1 -0.014966
+3300 -73.186 0.1 -0.016999
+3350 172.062 0.1 -0.018554
+3400 106.144 0.1 -0.021202
+3450 -22.860 0.1 -0.01949
+3500 22.120 0.1 -0.016033
+3550 -254.920 0.1 -0.012172
+3600 -147.218 0.1 -0.011162
+3650 -12.508 0.1 -0.010255
+3700 81.846 0.1 -0.0085117
+3750 -79.406 0.1 -0.0061294
+3800 -34.994 0.1 -0.0026239
+3850 94.992 0.1 -0.0015312
+3900 -0.345 0.1 -0.0011157
+3950 -88.693 0.1 -0.0018929
+4000 156.029 0.1 -0.0024547
diff --git a/examples/USER/misc/flow_gauss/output-files/Vy_profile b/examples/USER/misc/flow_gauss/output-files/Vy_profile
new file mode 100644
index 000000000..2df746836
--- /dev/null
+++ b/examples/USER/misc/flow_gauss/output-files/Vy_profile
@@ -0,0 +1,134 @@
+# Chunk-averaged data for fix velYprof and group file
+# Timestep Number-of-chunks Total-count
+# Chunk Coord1 Ncount vx
+4000 130 18774
+ 1 -19.8462 0 0
+ 2 -19.5385 0 0
+ 3 -19.2308 0 0
+ 4 -18.9231 0 0
+ 5 -18.6154 0 0
+ 6 -18.3077 0 0
+ 7 -18 0 0
+ 8 -17.6923 0 0
+ 9 -17.3846 0 0
+ 10 -17.0769 0 0
+ 11 -16.7692 0 0
+ 12 -16.4615 0 0
+ 13 -16.1538 0 0
+ 14 -15.8462 0 0
+ 15 -15.5385 0 0
+ 16 -15.2308 0 0
+ 17 -14.9231 0 0
+ 18 -14.6154 0 0
+ 19 -14.3077 0 0
+ 20 -14 0 0
+ 21 -13.6923 0 0
+ 22 -13.3846 0 0
+ 23 -13.0769 0 0
+ 24 -12.7692 0 0
+ 25 -12.4615 0 0
+ 26 -12.1538 0 0
+ 27 -11.8462 0 0
+ 28 -11.5385 0 0
+ 29 -11.2308 0 0
+ 30 -10.9231 0 0
+ 31 -10.6154 0 0
+ 32 -10.3077 0 0
+ 33 -10 0 0
+ 34 -9.69231 0 0
+ 35 -9.38462 0 0
+ 36 -9.07692 12.3415 0.126356
+ 37 -8.76923 9.14634 0.119194
+ 38 -8.46154 3.46341 0.0688559
+ 39 -8.15385 7.26829 0.180935
+ 40 -7.84615 9.97561 0.114685
+ 41 -7.53846 6.14634 0.158317
+ 42 -7.23077 7.17073 0.128092
+ 43 -6.92308 8.56098 0.30356
+ 44 -6.61538 7.7561 0.118822
+ 45 -6.30769 6.04878 0.170019
+ 46 -6 8.19512 0.146873
+ 47 -5.69231 8.4878 0.258003
+ 48 -5.38462 7.21951 0.0612577
+ 49 -5.07692 7.14634 0.394221
+ 50 -4.76923 7.34146 0.214609
+ 51 -4.46154 7.90244 0.1583
+ 52 -4.15385 6.36585 0.191919
+ 53 -3.84615 8.04878 0.202891
+ 54 -3.53846 7.2439 -0.00173288
+ 55 -3.23077 7.53659 0.117062
+ 56 -2.92308 6.41463 0.324614
+ 57 -2.61538 7.60976 0.496272
+ 58 -2.30769 8.39024 0.364642
+ 59 -2 6.73171 0.292624
+ 60 -1.69231 7.02439 0.517913
+ 61 -1.38462 8.43902 0.534594
+ 62 -1.07692 7.21951 0.497622
+ 63 -0.769231 6.95122 0.303701
+ 64 -0.461538 8.68293 0.406682
+ 65 -0.153846 7.5122 0.218835
+ 66 0.153846 6.82927 0.189413
+ 67 0.461538 8.26829 0.228409
+ 68 0.769231 7.2439 0.506845
+ 69 1.07692 7.97561 0.154118
+ 70 1.38462 8.26829 0.144882
+ 71 1.69231 6.58537 0.192568
+ 72 2 7.46341 0.360144
+ 73 2.30769 8.95122 0.0112179
+ 74 2.61538 6.58537 0.276061
+ 75 2.92308 6.53659 0.114354
+ 76 3.23077 8.46341 0.0386417
+ 77 3.53846 8 0.0711626
+ 78 3.84615 6.92683 0.203194
+ 79 4.15385 8.4878 0.317789
+ 80 4.46154 7.5122 0.268122
+ 81 4.76923 6.58537 -0.112372
+ 82 5.07692 9.02439 0.115702
+ 83 5.38462 7.41463 -0.067424
+ 84 5.69231 6.07317 0.0626918
+ 85 6 8.34146 -0.0153977
+ 86 6.30769 8.21951 0.281342
+ 87 6.61538 6.29268 0.359939
+ 88 6.92308 8.87805 0.110875
+ 89 7.23077 6.09756 0.134999
+ 90 7.53846 6.65854 0.0841478
+ 91 7.84615 10.8537 0.144519
+ 92 8.15385 5.58537 0.309331
+ 93 8.46154 5.80488 0.103667
+ 94 8.76923 7.60976 0.39288
+ 95 9.07692 12.0244 0.462022
+ 96 9.38462 0 0
+ 97 9.69231 0 0
+ 98 10 0 0
+ 99 10.3077 0 0
+ 100 10.6154 0 0
+ 101 10.9231 0 0
+ 102 11.2308 0 0
+ 103 11.5385 0 0
+ 104 11.8462 0 0
+ 105 12.1538 0 0
+ 106 12.4615 0 0
+ 107 12.7692 0 0
+ 108 13.0769 0 0
+ 109 13.3846 0 0
+ 110 13.6923 0 0
+ 111 14 0 0
+ 112 14.3077 0 0
+ 113 14.6154 0 0
+ 114 14.9231 0 0
+ 115 15.2308 0 0
+ 116 15.5385 0 0
+ 117 15.8462 0 0
+ 118 16.1538 0 0
+ 119 16.4615 0 0
+ 120 16.7692 0 0
+ 121 17.0769 0 0
+ 122 17.3846 0 0
+ 123 17.6923 0 0
+ 124 18 0 0
+ 125 18.3077 0 0
+ 126 18.6154 0 0
+ 127 18.9231 0 0
+ 128 19.2308 0 0
+ 129 19.5385 0 0
+ 130 19.8462 0 0
diff --git a/examples/USER/misc/flow_gauss/output-files/x_profiles b/examples/USER/misc/flow_gauss/output-files/x_profiles
new file mode 100644
index 000000000..7a761345a
--- /dev/null
+++ b/examples/USER/misc/flow_gauss/output-files/x_profiles
@@ -0,0 +1,36 @@
+# Chunk-averaged data for fix profiles and group density/mass
+# Timestep Number-of-chunks Total-count
+# Chunk Coord1 Ncount vx density/mass c_spa[1] c_spa[2]
+4000 32 109675
+ 1 -48.4375 97.7805 0.159561 0.782244 -9.17487 -8.9018
+ 2 -45.3125 100.927 0.187846 0.807415 -9.24302 -9.92813
+ 3 -42.1875 99.0976 0.227036 0.79278 -9.03415 -9.66032
+ 4 -39.0625 101.146 0.243495 0.809171 -8.89515 -9.25314
+ 5 -35.9375 98.7805 0.194616 0.790244 -9.13265 -8.52663
+ 6 -32.8125 97.8049 0.165768 0.782439 -9.26009 -8.52446
+ 7 -29.6875 100.195 0.0758064 0.801561 -9.02933 -8.50733
+ 8 -26.5625 98.4878 0.054432 0.787902 -9.61672 -9.24963
+ 9 -23.4375 99.9268 0.0740914 0.799415 -9.88959 -9.94984
+ 10 -20.3125 99.7561 0.130294 0.798049 -10.2459 -9.39412
+ 11 -17.1875 102.463 0.120168 0.819707 -10.6072 -10.254
+ 12 -14.0625 47.6341 0.208545 0.381073 -9.85715 -10.0799
+ 13 -10.9375 48.1951 0.238051 0.385561 -9.81349 -10.569
+ 14 -7.8125 47.439 0.287107 0.379512 -10.0184 -9.63087
+ 15 -4.6875 48.2439 0.22506 0.385951 -9.83794 -9.6963
+ 16 -1.5625 48.4634 0.208869 0.387707 -9.29366 -10.0114
+ 17 1.5625 46.4878 0.19447 0.371902 -10.2409 -9.84627
+ 18 4.6875 47.2927 0.168034 0.378341 -10.1523 -11.908
+ 19 7.8125 48.6829 0.145552 0.389463 -10.24 -11.0582
+ 20 10.9375 48.8293 0.214036 0.390634 -9.27729 -10.1074
+ 21 14.0625 46.9756 0.267083 0.375805 -9.24833 -9.83182
+ 22 17.1875 97.2683 0.175404 0.778146 -9.64001 -8.61724
+ 23 20.3125 101.146 0.10746 0.809171 -9.33416 -9.82308
+ 24 23.4375 101.927 0.157503 0.815415 -9.76491 -10.1909
+ 25 26.5625 101.024 0.179934 0.808195 -9.72775 -9.98559
+ 26 29.6875 100.976 0.180631 0.807805 -9.33871 -10.0228
+ 27 32.8125 96.4146 0.144418 0.771317 -9.74826 -9.79723
+ 28 35.9375 101.244 0.117224 0.809951 -8.95584 -8.80226
+ 29 39.0625 102 0.10507 0.816 -9.15563 -8.98232
+ 30 42.1875 101.195 0.040236 0.809561 -9.1499 -8.95112
+ 31 45.3125 96.9512 0.0312252 0.77561 -9.20475 -9.0005
+ 32 48.4375 100.244 0.103032 0.801951 -9.16324 -8.77526
diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular
new file mode 100644
index 000000000..24d21d676
--- /dev/null
+++ b/examples/USER/quip/in.molecular
@@ -0,0 +1,48 @@
+units metal
+atom_style full
+boundary p p p
+processors 1 1 1
+timestep 0.0001 # 0.1 fs
+
+read_data methane-box-8.data
+
+# DISCLAIMER: This potential mixes parameters from methane and silane
+# potentials and is NOT intended to be a realistic representation of either
+# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials,
+# including the use of separate 'special_bonds' settings.
+
+pair_style hybrid/overlay lj/cut 8.0 quip
+
+# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0,
+# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut
+special_bonds lj/coul 0.999999999 0.999999999 0.999999999
+
+# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996))
+# Coulomb interactions ommitted for simplicity
+pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT
+pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC
+pair_coeff 1 2 lj/cut 0.0019295487 2.95
+pair_modify shift no
+# change exclusion settings for lj/cut only: exclude bonded pairs
+pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0
+
+# Intramolecular
+# Tell QUIP to pretend this is silane (which is covered by the parameter file)
+pair_coeff * * quip ip.parms.SW.xml "IP SW" 14 1
+bond_style none
+angle_style none
+
+fix 1 all nve
+
+# Include diagnostics that allow us to compare to a pure QUIP run
+compute equip all pair quip
+compute evdw all pair lj/cut
+compute vir all pressure NULL virial
+
+thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip
+thermo 1
+
+# dump 1 all custom 1 dump.molecular id type x y z fx fy fz
+# dump_modify 1 sort id
+
+run 10
diff --git a/examples/USER/quip/methane-box-8.data b/examples/USER/quip/methane-box-8.data
new file mode 100644
index 000000000..2a55fcf55
--- /dev/null
+++ b/examples/USER/quip/methane-box-8.data
@@ -0,0 +1,162 @@
+LAMMPS data file. CGCMM style. atom_style full generated by VMD/TopoTools v1.1 on Sat Oct 22 17:48:43 BST 2016. Original generated with Packmol
+ 40 atoms
+ 32 bonds
+ 48 angles
+ 0 dihedrals
+ 0 impropers
+ 2 atom types
+ 1 bond types
+ 1 angle types
+ 0 dihedral types
+ 0 improper types
+ -0.499095 8.410905 xlo xhi
+ -0.270629 8.639371 ylo yhi
+ 0.131683 9.041683 zlo zhi
+
+# Pair Coeffs
+#
+# 1 CT
+# 2 HC
+
+# Bond Coeffs
+#
+# 1 CT-HC
+
+# Angle Coeffs
+#
+# 1 HC-CT-HC
+
+ Masses
+
+ 1 12.011000 # CT
+ 2 1.008000 # HC
+
+ Atoms
+
+1 1 1 -0.240000 3.937038 0.677603 7.362249 # CT
+2 1 2 0.060000 4.193022 1.709034 7.595834 # HC
+3 1 2 0.060000 2.905136 0.486052 7.649386 # HC
+4 1 2 0.060000 4.596317 0.007308 7.909996 # HC
+5 1 2 0.060000 4.053670 0.507989 6.293814 # HC
+6 2 1 -0.240000 6.131801 2.711096 0.901469 # CT
+7 2 2 0.060000 6.787439 1.886720 0.628555 # HC
+8 2 2 0.060000 5.728610 3.167652 -0.000171 # HC
+9 2 2 0.060000 6.696346 3.453106 1.462433 # HC
+10 2 2 0.060000 5.314820 2.336948 1.515051 # HC
+11 3 1 -0.240000 5.723143 6.225007 1.430856 # CT
+12 3 2 0.060000 5.585279 6.712817 2.393651 # HC
+13 3 2 0.060000 5.584847 6.951755 0.632938 # HC
+14 3 2 0.060000 4.994507 5.424203 1.322354 # HC
+15 3 2 0.060000 6.727906 5.811248 1.374455 # HC
+16 4 1 -0.240000 5.573754 5.038579 4.999124 # CT
+17 4 2 0.060000 4.512787 5.184293 5.191620 # HC
+18 4 2 0.060000 6.006150 5.966299 4.629893 # HC
+19 4 2 0.060000 5.703088 4.256326 4.253924 # HC
+20 4 2 0.060000 6.073008 4.747398 5.921016 # HC
+21 5 1 -0.240000 2.108870 2.623461 3.348534 # CT
+22 5 2 0.060000 2.886488 2.470897 2.602897 # HC
+23 5 2 0.060000 1.382727 3.341833 2.973541 # HC
+24 5 2 0.060000 2.554989 3.003606 4.265288 # HC
+25 5 2 0.060000 1.611274 1.677549 3.552431 # HC
+26 6 1 -0.240000 6.106165 2.015183 5.526875 # CT
+27 6 2 0.060000 6.075817 2.038391 4.439456 # HC
+28 6 2 0.060000 6.076127 0.982573 5.868599 # HC
+29 6 2 0.060000 5.248943 2.554122 5.925227 # HC
+30 6 2 0.060000 7.023739 2.485633 5.874240 # HC
+31 7 1 -0.240000 0.644265 2.699668 7.212713 # CT
+32 7 2 0.060000 0.403413 2.521819 6.166625 # HC
+33 7 2 0.060000 0.098429 1.993976 7.835627 # HC
+34 7 2 0.060000 0.361861 3.715309 7.482326 # HC
+35 7 2 0.060000 1.713326 2.567585 7.366300 # HC
+36 8 1 -0.240000 0.588072 6.428183 7.473536 # CT
+37 8 2 0.060000 0.540903 6.363141 6.388417 # HC
+38 8 2 0.060000 -0.008121 5.629967 7.910991 # HC
+39 8 2 0.060000 0.197701 7.391140 7.796481 # HC
+40 8 2 0.060000 1.621770 6.328495 7.798280 # HC
+
+ Bonds
+
+1 1 1 3
+2 1 1 5
+3 1 1 2
+4 1 1 4
+5 1 6 7
+6 1 6 9
+7 1 6 8
+8 1 6 10
+9 1 11 14
+10 1 11 13
+11 1 11 12
+12 1 11 15
+13 1 16 17
+14 1 16 18
+15 1 16 19
+16 1 16 20
+17 1 21 22
+18 1 21 24
+19 1 21 25
+20 1 21 23
+21 1 26 27
+22 1 26 28
+23 1 26 29
+24 1 26 30
+25 1 31 33
+26 1 31 32
+27 1 31 34
+28 1 31 35
+29 1 36 38
+30 1 36 37
+31 1 36 39
+32 1 36 40
+
+ Angles
+
+1 1 3 1 5
+2 1 2 1 3
+3 1 3 1 4
+4 1 2 1 5
+5 1 4 1 5
+6 1 2 1 4
+7 1 7 6 9
+8 1 7 6 8
+9 1 7 6 10
+10 1 8 6 9
+11 1 9 6 10
+12 1 8 6 10
+13 1 13 11 14
+14 1 12 11 14
+15 1 14 11 15
+16 1 12 11 13
+17 1 13 11 15
+18 1 12 11 15
+19 1 17 16 18
+20 1 17 16 19
+21 1 17 16 20
+22 1 18 16 19
+23 1 18 16 20
+24 1 19 16 20
+25 1 22 21 24
+26 1 22 21 25
+27 1 22 21 23
+28 1 24 21 25
+29 1 23 21 24
+30 1 23 21 25
+31 1 27 26 28
+32 1 27 26 29
+33 1 27 26 30
+34 1 28 26 29
+35 1 28 26 30
+36 1 29 26 30
+37 1 32 31 33
+38 1 33 31 34
+39 1 33 31 35
+40 1 32 31 34
+41 1 32 31 35
+42 1 34 31 35
+43 1 37 36 38
+44 1 38 36 39
+45 1 38 36 40
+46 1 37 36 39
+47 1 37 36 40
+48 1 39 36 40
+
diff --git a/examples/USER/quip/out.molecular b/examples/USER/quip/out.molecular
new file mode 100644
index 000000000..0e8d07d38
--- /dev/null
+++ b/examples/USER/quip/out.molecular
@@ -0,0 +1,93 @@
+LAMMPS (6 Jul 2017)
+Reading data file ...
+ orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168)
+ 1 by 1 by 1 MPI processor grid
+ reading atoms ...
+ 40 atoms
+ scanning bonds ...
+ 4 = max bonds/atom
+ scanning angles ...
+ 6 = max angles/atom
+ reading bonds ...
+ 32 bonds
+ reading angles ...
+ 48 angles
+Finding 1-2 1-3 1-4 neighbors ...
+ special bond factors lj: 0 0 0
+ special bond factors coul: 0 0 0
+ 4 = max # of 1-2 neighbors
+ 3 = max # of 1-3 neighbors
+ 3 = max # of 1-4 neighbors
+ 4 = max # of special neighbors
+Finding 1-2 1-3 1-4 neighbors ...
+ special bond factors lj: 1 1 1
+ special bond factors coul: 1 1 1
+ 4 = max # of 1-2 neighbors
+ 3 = max # of 1-3 neighbors
+ 3 = max # of 1-4 neighbors
+ 4 = max # of special neighbors
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 10
+ ghost atom cutoff = 10
+ binsize = 5, bins = 2 2 2
+ 2 neighbor lists, perpetual/occasional/extra = 2 0 0
+ (1) pair lj/cut, perpetual, half/full from (2)
+ attributes: half, newton on
+ pair build: halffull/newton
+ stencil: none
+ bin: none
+ (2) pair quip, perpetual
+ attributes: full, newton on
+ pair build: full/bin
+ stencil: full/bin/3d
+ bin: standard
+Setting up Verlet run ...
+ Unit style : metal
+ Current step : 0
+ Time step : 0.0001
+Per MPI rank memory allocation (min/avg/max) = 9.543 | 9.543 | 9.543 Mbytes
+Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip
+ 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805
+ 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093
+ 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932
+ 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264
+ 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557
+ 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546
+ 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782
+ 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787
+ 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801
+ 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653
+ 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266
+Loop time of 0.131692 on 1 procs for 10 steps with 40 atoms
+
+Performance: 0.656 ns/day, 36.581 hours/ns, 75.935 timesteps/s
+97.2% CPU use with 1 MPI tasks x no OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 0.12961 | 0.12961 | 0.12961 | 0.0 | 98.42
+Bond | 7.391e-06 | 7.391e-06 | 7.391e-06 | 0.0 | 0.01
+Neigh | 0 | 0 | 0 | 0.0 | 0.00
+Comm | 0.00013185 | 0.00013185 | 0.00013185 | 0.0 | 0.10
+Output | 0.0018771 | 0.0018771 | 0.0018771 | 0.0 | 1.43
+Modify | 2.5988e-05 | 2.5988e-05 | 2.5988e-05 | 0.0 | 0.02
+Other | | 4.268e-05 | | | 0.03
+
+Nlocal: 40 ave 40 max 40 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 1175 ave 1175 max 1175 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 4768 ave 4768 max 4768 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+FullNghs: 9536 ave 9536 max 9536 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 9536
+Ave neighs/atom = 238.4
+Ave special neighs/atom = 4
+Neighbor list builds = 0
+Dangerous builds = 0
+Total wall time: 0:00:00
diff --git a/examples/accelerate/README b/examples/accelerate/README
index 1fab296a5..c4eb5dcc8 100644
--- a/examples/accelerate/README
+++ b/examples/accelerate/README
@@ -1,158 +1,106 @@
These are example scripts that can be run with any of
the acclerator packages in LAMMPS:
-USER-CUDA, GPU, USER-INTEL, KOKKOS, USER-OMP, OPT
+GPU, USER-INTEL, KOKKOS, USER-OMP, OPT
The easiest way to build LAMMPS with these packages
-is via the src/Make.py tool described in Section 2.4
-of the manual. You can also type "Make.py -h" to see
-its options. The easiest way to run these scripts
-is by using the appropriate
-
+is via the flags described in Section 4 of the manual.
+The easiest way to run these scripts is by using the appropriate
Details on the individual accelerator packages
can be found in doc/Section_accelerate.html.
---------------------
Build LAMMPS with one or more of the accelerator packages
-The following command will invoke the src/Make.py tool with one of the
-command-lines from the Make.list file:
-
-../../src/Make.py -r Make.list target
-
-target = one or more of the following:
- cpu, omp, opt
- cuda_double, cuda_mixed, cuda_single
- gpu_double, gpu_mixed, gpu_single
- intel_cpu, intel_phi
- kokkos_omp, kokkos_cuda, kokkos_phi
-
-If successful, the build will produce the file lmp_target in this
-directory.
-
Note that in addition to any accelerator packages, these packages also
need to be installed to run all of the example scripts: ASPHERE,
MOLECULE, KSPACE, RIGID.
These two targets will build a single LAMMPS executable with all the
CPU accelerator packages installed (USER-INTEL for CPU, KOKKOS for
OMP, USER-OMP, OPT) or all the GPU accelerator packages installed
-(USER-CUDA, GPU, KOKKOS for CUDA):
-
-target = all_cpu, all_gpu
-
-Note that the Make.py commands in Make.list assume an MPI environment
-exists on your machine and use mpicxx as the wrapper compiler with
-whatever underlying compiler it wraps by default. If you add "-cc mpi
-wrap=g++" or "-cc mpi wrap=icc" after the target, you can choose the
-underlying compiler for mpicxx to invoke. E.g.
-
-../../src/Make.py -r Make.list intel_cpu -cc mpi wrap=icc
+(GPU, KOKKOS for CUDA):
-You should do this for any build that includes the USER-INTEL
-package, since it will perform best with the Intel compilers.
-
-Note that for kokkos_cuda, it needs to be "-cc nvcc" instead of "mpi",
-since a KOKKOS for CUDA build requires NVIDIA nvcc as the wrapper
-compiler.
-
-Also note that the Make.py commands in Make.list use the default
-FFT support which is via the KISS library. If you want to
-build with another FFT library, e.g. FFTW3, then you can add
-"-fft fftw3" after the target, e.g.
-
-../../src/Make.py -r Make.list gpu -fft fftw3
-
-For any build with USER-CUDA, GPU, or KOKKOS for CUDA, be sure to set
+For any build with GPU, or KOKKOS for CUDA, be sure to set
the arch=XX setting to the appropriate value for the GPUs and Cuda
-environment on your system. What is defined in the Make.list file is
-arch=21 for older Fermi GPUs. This can be overridden as follows,
-e.g. for Kepler GPUs:
-
-../../src/Make.py -r Make.list gpu_double -gpu mode=double arch=35
+environment on your system.
---------------------
Running with each of the accelerator packages
All of the input scripts have a default problem size and number of
timesteps:
in.lj = LJ melt with cutoff of 2.5 = 32K atoms for 100 steps
in.lj.5.0 = same with cutoff of 5.0 = 32K atoms for 100 steps
in.phosphate = 11K atoms for 100 steps
in.rhodo = 32K atoms for 100 steps
in.lc = 33K atoms for 100 steps (after 200 steps equilibration)
These can be reset using the x,y,z and t variables in the command
line. E.g. adding "-v x 2 -v y 2 -v z 4 -t 1000" to any of the run
command below would run a 16x larger problem (2x2x4) for 1000 steps.
Here are example run commands using each of the accelerator packages:
** CPU only
lmp_cpu < in.lj
mpirun -np 4 lmp_cpu -in in.lj
** OPT package
lmp_opt -sf opt < in.lj
mpirun -np 4 lmp_opt -sf opt -in in.lj
** USER-OMP package
lmp_omp -sf omp -pk omp 1 < in.lj
mpirun -np 4 lmp_omp -sf opt -pk omp 1 -in in.lj # 4 MPI, 1 thread/MPI
mpirun -np 2 lmp_omp -sf opt -pk omp 4 -in in.lj # 2 MPI, 4 thread/MPI
** GPU package
lmp_gpu_double -sf gpu < in.lj
mpirun -np 8 lmp_gpu_double -sf gpu < in.lj # 8 MPI, 8 MPI/GPU
mpirun -np 12 lmp_gpu_double -sf gpu -pk gpu 2 < in.lj # 12 MPI, 6 MPI/GPU
mpirun -np 4 lmp_gpu_double -sf gpu -pk gpu 2 tpa 8 < in.lj.5.0 # 4 MPI, 2 MPI/GPU
Note that when running in.lj.5.0 (which has a long cutoff) with the
GPU package, the "-pk tpa" setting should be > 1 (e.g. 8) for best
performance.
-** USER-CUDA package
-
-lmp_machine -c on -sf cuda < in.lj
-mpirun -np 1 lmp_machine -c on -sf cuda < in.lj # 1 MPI, 1 MPI/GPU
-mpirun -np 2 lmp_machine -c on -sf cuda -pk cuda 2 < in.lj # 2 MPI, 1 MPI/GPU
-
** KOKKOS package for OMP
lmp_kokkos_omp -k on t 1 -sf kk -pk kokkos neigh half < in.lj
mpirun -np 2 lmp_kokkos_omp -k on t 4 -sf kk < in.lj # 2 MPI, 4 thread/MPI
Note that when running with just 1 thread/MPI, "-pk kokkos neigh half"
was specified to use half neighbor lists which are faster when running
on just 1 thread.
** KOKKOS package for CUDA
lmp_kokkos_cuda -k on t 1 -sf kk < in.lj # 1 thread, 1 GPU
mpirun -np 2 lmp_kokkos_cuda -k on t 6 g 2 -sf kk < in.lj # 2 MPI, 6 thread/MPI, 1 MPI/GPU
** KOKKOS package for PHI
mpirun -np 1 lmp_kokkos_phi -k on t 240 -sf kk -in in.lj # 1 MPI, 240 threads/MPI
mpirun -np 30 lmp_kokkos_phi -k on t 8 -sf kk -in in.lj # 30 MPI, 8 threads/MPI
** USER-INTEL package for CPU
lmp_intel_cpu -sf intel < in.lj
mpirun -np 4 lmp_intl_cpu -sf intel < in.lj # 4 MPI
mpirun -np 4 lmp_intl_cpu -sf intel -pk omp 2 < in.lj # 4 MPI, 2 thread/MPI
** USER-INTEL package for PHI
lmp_intel_phi -sf intel -pk intel 1 omp 16 < in.lc # 1 MPI, 16 CPU thread/MPI, 1 Phi, 240 Phi thread/MPI
mpirun -np 4 lmp_intel_phi -sf intel -pk intel 1 omp 2 < in.lc # 4 MPI, 2 CPU threads/MPI, 1 Phi, 60 Phi thread/MPI
Note that there is currently no Phi support for pair_style lj/cut in
the USER-INTEL package.
diff --git a/examples/peri/in.peri b/examples/peri/in.peri-pmb
similarity index 100%
copy from examples/peri/in.peri
copy to examples/peri/in.peri-pmb
diff --git a/examples/peri/in.peri b/examples/peri/in.peri.eps
similarity index 67%
copy from examples/peri/in.peri
copy to examples/peri/in.peri.eps
index e1cbe2e50..5ddea4172 100644
--- a/examples/peri/in.peri
+++ b/examples/peri/in.peri.eps
@@ -1,45 +1,45 @@
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
create_atoms 1 region target
-pair_style peri/pmb
-pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
+pair_style peri/eps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8
set group all density 2200
set group all volume 1.25e-10
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
diff --git a/examples/peri/in.peri b/examples/peri/in.peri.lps
similarity index 67%
copy from examples/peri/in.peri
copy to examples/peri/in.peri.lps
index e1cbe2e50..af0462b5d 100644
--- a/examples/peri/in.peri
+++ b/examples/peri/in.peri.lps
@@ -1,45 +1,45 @@
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
create_atoms 1 region target
-pair_style peri/pmb
-pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
+pair_style peri/lps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25
set group all density 2200
set group all volume 1.25e-10
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
diff --git a/examples/peri/in.peri b/examples/peri/in.peri.pmb
similarity index 74%
copy from examples/peri/in.peri
copy to examples/peri/in.peri.pmb
index e1cbe2e50..f9f5d5423 100644
--- a/examples/peri/in.peri
+++ b/examples/peri/in.peri.pmb
@@ -1,45 +1,45 @@
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
create_atoms 1 region target
pair_style peri/pmb
pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
set group all density 2200
set group all volume 1.25e-10
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
diff --git a/examples/peri/in.peri b/examples/peri/in.peri.ves
similarity index 67%
rename from examples/peri/in.peri
rename to examples/peri/in.peri.ves
index e1cbe2e50..3787e676a 100644
--- a/examples/peri/in.peri
+++ b/examples/peri/in.peri.ves
@@ -1,45 +1,45 @@
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
create_atoms 1 region target
-pair_style peri/pmb
-pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
+pair_style peri/ves
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001
set group all density 2200
set group all volume 1.25e-10
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type &
-# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type &
+# axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
diff --git a/examples/peri/log.6Jul17.peri.eps.g++.1 b/examples/peri/log.6Jul17.peri.eps.g++.1
new file mode 100644
index 000000000..6aa4314d5
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.eps.g++.1
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 1 by 1 by 1 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/eps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/eps, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 50.29 | 50.29 | 50.29 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 8.3466308e+24 247103.03 0 849681.45 8.0295601e+11 5.0030006e-07
+ 200 1.1784921e+27 1098605.6 0 86178912 1.0246967e+14 5.5353162e-07
+ 300 2.6263212e+27 4118581.6 0 1.9372377e+08 1.662415e+14 7.6036043e-07
+ 400 3.3085888e+27 9397203.3 0 2.4825816e+08 1.561692e+14 1.0196674e-06
+ 500 3.9151799e+27 18408722 0 3.0106204e+08 1.5298661e+14 1.2317127e-06
+ 600 6.2936721e+27 11346143 0 4.6571282e+08 1.9645007e+14 1.5419242e-06
+ 700 1.2721597e+28 3830223.2 0 9.2225588e+08 3.0235577e+14 2.0250441e-06
+ 800 1.3190107e+28 2831668.7 0 9.5508099e+08 2.4853932e+14 2.5542553e-06
+ 900 1.3166045e+28 1911868.6 0 9.524241e+08 1.9729649e+14 3.2117896e-06
+ 1000 1.3159578e+28 1995827.6 0 9.5204114e+08 1.6722163e+14 3.7875695e-06
+Loop time of 72.5574 on 1 procs for 1000 steps with 3487 atoms
+
+99.7% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 71.779 | 71.779 | 71.779 | 0.0 | 98.93
+Neigh | 0.5596 | 0.5596 | 0.5596 | 0.0 | 0.77
+Comm | 0.0040631 | 0.0040631 | 0.0040631 | 0.0 | 0.01
+Output | 0.00056624 | 0.00056624 | 0.00056624 | 0.0 | 0.00
+Modify | 0.18403 | 0.18403 | 0.18403 | 0.0 | 0.25
+Other | | 0.03016 | | | 0.04
+
+Nlocal: 3487 ave 3487 max 3487 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 0 ave 0 max 0 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 569177 ave 569177 max 569177 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 40
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:01:12
diff --git a/examples/peri/log.6Jul17.peri.eps.g++.4 b/examples/peri/log.6Jul17.peri.eps.g++.4
new file mode 100644
index 000000000..1423ec463
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.eps.g++.4
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 2 by 1 by 2 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/eps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/eps, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 44.77 | 45.04 | 45.14 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 8.3466308e+24 247103.03 0 849681.45 8.0295601e+11 5.0030006e-07
+ 200 1.1784921e+27 1098605.6 0 86178912 1.0246967e+14 5.5353162e-07
+ 300 2.6263212e+27 4118581.6 0 1.9372377e+08 1.662415e+14 7.6036043e-07
+ 400 3.3085888e+27 9397203.3 0 2.4825816e+08 1.561692e+14 1.0196674e-06
+ 500 3.9151799e+27 18408722 0 3.0106204e+08 1.5298661e+14 1.2317127e-06
+ 600 6.2936721e+27 11346143 0 4.6571282e+08 1.9645007e+14 1.5419242e-06
+ 700 1.2721597e+28 3830223.2 0 9.2225588e+08 3.0235577e+14 2.0250441e-06
+ 800 1.3190107e+28 2831668.7 0 9.5508099e+08 2.4853932e+14 2.5542553e-06
+ 900 1.3166045e+28 1911869.3 0 9.524241e+08 1.9729649e+14 3.2117896e-06
+ 1000 1.3159578e+28 1995833.9 0 9.5204114e+08 1.6722163e+14 3.7875695e-06
+Loop time of 29.6266 on 4 procs for 1000 steps with 3487 atoms
+
+98.8% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 25.905 | 26.18 | 26.326 | 3.2 | 88.37
+Neigh | 0.15352 | 0.1872 | 0.22394 | 7.6 | 0.63
+Comm | 3.0374 | 3.1471 | 3.3731 | 7.5 | 10.62
+Output | 0.00047588 | 0.00062978 | 0.00097752 | 0.0 | 0.00
+Modify | 0.073521 | 0.081854 | 0.093222 | 2.7 | 0.28
+Other | | 0.02989 | | | 0.10
+
+Nlocal: 871.75 ave 908 max 838 min
+Histogram: 1 0 0 0 1 1 0 0 0 1
+Nghost: 1368.25 ave 1402 max 1332 min
+Histogram: 1 0 0 0 1 1 0 0 0 1
+Neighs: 142294 ave 159233 max 124729 min
+Histogram: 2 0 0 0 0 0 0 0 0 2
+FullNghs: 302269 ave 346070 max 260820 min
+Histogram: 1 0 0 0 2 0 0 0 0 1
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 40
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:00:29
diff --git a/examples/peri/log.6Jul17.peri.lps.g++.1 b/examples/peri/log.6Jul17.peri.lps.g++.1
new file mode 100644
index 000000000..4b2ac532d
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.lps.g++.1
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 1 by 1 by 1 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/lps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/lps, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 34.91 | 34.91 | 34.91 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 1.684629e+24 133446.65 0 255067.11 1.6206343e+11 5.0030006e-07
+ 200 1.1380148e+27 684478.05 0 82842557 9.9178307e+13 5.5225839e-07
+ 300 2.5659218e+27 5944645.9 0 1.9118934e+08 1.6231114e+14 7.6086254e-07
+ 400 2.9916164e+27 13677434 0 2.2965481e+08 1.4081705e+14 1.0224963e-06
+ 500 3.3570343e+27 11130894 0 2.5348933e+08 1.2577633e+14 1.2846002e-06
+ 600 3.9506165e+27 6986672.5 0 2.9219831e+08 1.2659956e+14 1.5019096e-06
+ 700 7.8366157e+27 11716082 0 5.7747436e+08 1.9480124e+14 1.9361899e-06
+ 800 8.2483231e+27 4671647.2 0 6.0015282e+08 1.7040064e+14 2.3297298e-06
+ 900 8.2720965e+27 1249680.9 0 5.9844715e+08 1.4117116e+14 2.8202052e-06
+ 1000 8.2441462e+27 2278265.6 0 5.9745788e+08 1.234652e+14 3.213751e-06
+Loop time of 62.3833 on 1 procs for 1000 steps with 3487 atoms
+
+99.5% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 61.608 | 61.608 | 61.608 | 0.0 | 98.76
+Neigh | 0.57177 | 0.57177 | 0.57177 | 0.0 | 0.92
+Comm | 0.0030825 | 0.0030825 | 0.0030825 | 0.0 | 0.00
+Output | 0.00051951 | 0.00051951 | 0.00051951 | 0.0 | 0.00
+Modify | 0.17278 | 0.17278 | 0.17278 | 0.0 | 0.28
+Other | | 0.02745 | | | 0.04
+
+Nlocal: 3487 ave 3487 max 3487 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 0 ave 0 max 0 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 576568 ave 576568 max 576568 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 37
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:01:02
diff --git a/examples/peri/log.6Jul17.peri.lps.g++.4 b/examples/peri/log.6Jul17.peri.lps.g++.4
new file mode 100644
index 000000000..04244f012
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.lps.g++.4
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 2 by 1 by 2 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/lps
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/lps, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 29.4 | 29.66 | 29.76 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 1.684629e+24 133446.65 0 255067.11 1.6206343e+11 5.0030006e-07
+ 200 1.1380148e+27 684478.05 0 82842557 9.9178307e+13 5.5225839e-07
+ 300 2.5659218e+27 5944645.9 0 1.9118934e+08 1.6231114e+14 7.6086254e-07
+ 400 2.9916164e+27 13677434 0 2.2965481e+08 1.4081705e+14 1.0224963e-06
+ 500 3.3570343e+27 11130894 0 2.5348933e+08 1.2577633e+14 1.2846002e-06
+ 600 3.9506165e+27 6986672.5 0 2.9219831e+08 1.2659956e+14 1.5019096e-06
+ 700 7.8366157e+27 11716082 0 5.7747436e+08 1.9480124e+14 1.9361899e-06
+ 800 8.2483231e+27 4671647.2 0 6.0015282e+08 1.7040064e+14 2.3297298e-06
+ 900 8.2720965e+27 1249680.9 0 5.9844715e+08 1.4117116e+14 2.8202052e-06
+ 1000 8.2441489e+27 2277476.2 0 5.9745729e+08 1.2346524e+14 3.213751e-06
+Loop time of 23.2656 on 4 procs for 1000 steps with 3487 atoms
+
+99.2% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 20.801 | 21.119 | 21.525 | 6.3 | 90.78
+Neigh | 0.13851 | 0.18557 | 0.22747 | 8.5 | 0.80
+Comm | 1.5175 | 1.8689 | 2.1386 | 18.0 | 8.03
+Output | 0.00049806 | 0.00059026 | 0.00071931 | 0.0 | 0.00
+Modify | 0.063441 | 0.066235 | 0.069135 | 0.9 | 0.28
+Other | | 0.02496 | | | 0.11
+
+Nlocal: 871.75 ave 939 max 805 min
+Histogram: 1 0 0 0 1 1 0 0 0 1
+Nghost: 1343.25 ave 1410 max 1276 min
+Histogram: 1 0 0 0 1 1 0 0 0 1
+Neighs: 144142 ave 176488 max 113797 min
+Histogram: 1 0 1 0 0 0 1 0 0 1
+FullNghs: 302269 ave 346070 max 260820 min
+Histogram: 1 0 0 0 2 0 0 0 0 1
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 37
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:00:23
diff --git a/examples/peri/log.5Oct16.peri.g++.1 b/examples/peri/log.6Jul17.peri.pmb.g++.1
similarity index 62%
rename from examples/peri/log.5Oct16.peri.g++.1
rename to examples/peri/log.6Jul17.peri.pmb.g++.1
index 687876f97..84a439674 100644
--- a/examples/peri/log.5Oct16.peri.g++.1
+++ b/examples/peri/log.6Jul17.peri.pmb.g++.1
@@ -1,104 +1,115 @@
-LAMMPS (5 Oct 2016)
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
1 by 1 by 1 MPI processor grid
create_atoms 1 region target
Created 3487 atoms
pair_style peri/pmb
pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
set group all density 2200
3487 settings made for density
set group all volume 1.25e-10
3487 settings made for volume
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
Neighbor list info ...
- 2 neighbor list requests
update every 1 steps, delay 10 steps, check yes
max neighbors/atom: 2000, page size: 100000
master list distance cutoff = 0.0025001
ghost atom cutoff = 0.0025001
- binsize = 0.00125005 -> bins = 9 5 9
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/pmb, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
Peridynamic bonds:
total # of bonds = 335966
bonds/atom = 96.3482
-Memory usage per processor = 26.6858 Mbytes
+Per MPI rank memory allocation (min/avg/max) = 34.79 | 34.79 | 34.79 Mbytes
Step Temp E_pair E_mol TotEng Press Volume
0 0 0 0 0 0 5.0030006e-07
100 1.7890585e+24 552721.8 0 681881.47 1.7210968e+11 5.0030006e-07
200 1.3549879e+27 3097027.6 0 1.0091931e+08 1.1829272e+14 5.5130066e-07
300 3.3009625e+27 6331254.8 0 2.4464163e+08 1.9647265e+14 8.0862953e-07
400 3.815184e+27 6225081.7 0 2.8165928e+08 1.8189267e+14 1.0095118e-06
500 4.2580877e+27 20212686 0 3.2762196e+08 1.6249923e+14 1.2611723e-06
600 5.5126512e+27 30861342 0 4.2884284e+08 1.7320038e+14 1.531873e-06
700 1.1807414e+28 23119941 0 8.7554687e+08 2.9477434e+14 1.9278632e-06
- 800 1.2424839e+28 2407361.6 0 8.994088e+08 2.3787786e+14 2.5138992e-06
- 900 1.2358395e+28 4532520.6 0 8.9673706e+08 1.9097312e+14 3.1145903e-06
- 1000 1.2341057e+28 3219939.5 0 8.9417279e+08 1.5968597e+14 3.7196039e-06
-Loop time of 20.3026 on 1 procs for 1000 steps with 3487 atoms
+ 800 1.2424839e+28 2407365.1 0 8.994088e+08 2.3787786e+14 2.5138992e-06
+ 900 1.2358397e+28 4532424.3 0 8.9673716e+08 1.9097316e+14 3.1145903e-06
+ 1000 1.2341048e+28 3219355.8 0 8.9417154e+08 1.5968585e+14 3.7196039e-06
+Loop time of 28.565 on 1 procs for 1000 steps with 3487 atoms
-99.9% CPU use with 1 MPI tasks x no OpenMP threads
+99.5% CPU use with 1 MPI tasks x 1 OpenMP threads
MPI task timing breakdown:
Section | min time | avg time | max time |%varavg| %total
---------------------------------------------------------------
-Pair | 19.625 | 19.625 | 19.625 | 0.0 | 96.66
-Neigh | 0.57013 | 0.57013 | 0.57013 | 0.0 | 2.81
-Comm | 0.0014448 | 0.0014448 | 0.0014448 | 0.0 | 0.01
-Output | 0.00024772 | 0.00024772 | 0.00024772 | 0.0 | 0.00
-Modify | 0.092173 | 0.092173 | 0.092173 | 0.0 | 0.45
-Other | | 0.01359 | | | 0.07
+Pair | 27.721 | 27.721 | 27.721 | 0.0 | 97.04
+Neigh | 0.66353 | 0.66353 | 0.66353 | 0.0 | 2.32
+Comm | 0.0027969 | 0.0027969 | 0.0027969 | 0.0 | 0.01
+Output | 0.00042295 | 0.00042295 | 0.00042295 | 0.0 | 0.00
+Modify | 0.1566 | 0.1566 | 0.1566 | 0.0 | 0.55
+Other | | 0.02086 | | | 0.07
Nlocal: 3487 ave 3487 max 3487 min
Histogram: 1 0 0 0 0 0 0 0 0 0
Nghost: 0 ave 0 max 0 min
Histogram: 1 0 0 0 0 0 0 0 0 0
-Neighs: 567140 ave 567140 max 567140 min
+Neighs: 567132 ave 567132 max 567132 min
Histogram: 1 0 0 0 0 0 0 0 0 0
FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min
Histogram: 1 0 0 0 0 0 0 0 0 0
Total # of neighbors = 1209076
Ave neighs/atom = 346.738
Neighbor list builds = 46
Dangerous builds = 0
Please see the log.cite file for references relevant to this simulation
-Total wall time: 0:00:20
+Total wall time: 0:00:28
diff --git a/examples/peri/log.5Oct16.peri.g++.4 b/examples/peri/log.6Jul17.peri.pmb.g++.4
similarity index 58%
rename from examples/peri/log.5Oct16.peri.g++.4
rename to examples/peri/log.6Jul17.peri.pmb.g++.4
index cb478772a..637b2cc26 100644
--- a/examples/peri/log.5Oct16.peri.g++.4
+++ b/examples/peri/log.6Jul17.peri.pmb.g++.4
@@ -1,104 +1,115 @@
-LAMMPS (5 Oct 2016)
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
# small Peridynamic cylinder hit by projectile
-units si
+units si
boundary s s s
atom_style peri
-atom_modify map array
+atom_modify map array
neighbor 0.0010 bin
# small target
lattice sc 0.0005
Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
create_box 1 target
Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
2 by 1 by 2 MPI processor grid
create_atoms 1 region target
Created 3487 atoms
pair_style peri/pmb
pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25
set group all density 2200
3487 settings made for density
set group all volume 1.25e-10
3487 settings made for volume
velocity all set 0.0 0.0 0.0 sum no units box
fix 1 all nve
# spherical indenter to shatter target
variable y0 equal 0.00155
variable vy equal -100
variable y equal "v_y0 + step*dt*v_vy"
fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
compute 1 all damage/atom
timestep 1.0e-7
thermo 100
#dump 1 all custom 100 dump.peri id type x y z c_1
-#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 2 pad 4
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
-#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
-#dump_modify 3 pad 4
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
run 1000
Neighbor list info ...
- 2 neighbor list requests
update every 1 steps, delay 10 steps, check yes
max neighbors/atom: 2000, page size: 100000
master list distance cutoff = 0.0025001
ghost atom cutoff = 0.0025001
- binsize = 0.00125005 -> bins = 9 5 9
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/pmb, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
Peridynamic bonds:
total # of bonds = 335966
bonds/atom = 96.3482
-Memory usage per processor = 26.9049 Mbytes
+Per MPI rank memory allocation (min/avg/max) = 29.27 | 29.54 | 29.64 Mbytes
Step Temp E_pair E_mol TotEng Press Volume
0 0 0 0 0 0 5.0030006e-07
100 1.7890585e+24 552721.8 0 681881.47 1.7210968e+11 5.0030006e-07
200 1.3549879e+27 3097027.6 0 1.0091931e+08 1.1829272e+14 5.5130066e-07
300 3.3009625e+27 6331254.8 0 2.4464163e+08 1.9647265e+14 8.0862953e-07
400 3.815184e+27 6225081.7 0 2.8165928e+08 1.8189267e+14 1.0095118e-06
500 4.2580877e+27 20212686 0 3.2762196e+08 1.6249923e+14 1.2611723e-06
600 5.5126512e+27 30861342 0 4.2884284e+08 1.7320038e+14 1.531873e-06
700 1.1807414e+28 23119941 0 8.7554687e+08 2.9477434e+14 1.9278632e-06
- 800 1.2424839e+28 2407361.5 0 8.994088e+08 2.3787786e+14 2.5138992e-06
- 900 1.2358395e+28 4532520.1 0 8.9673706e+08 1.9097312e+14 3.1145903e-06
- 1000 1.2341057e+28 3219974.3 0 8.9417286e+08 1.5968598e+14 3.7196039e-06
-Loop time of 5.91321 on 4 procs for 1000 steps with 3487 atoms
+ 800 1.2424839e+28 2407365.2 0 8.994088e+08 2.3787786e+14 2.5138992e-06
+ 900 1.2358397e+28 4532423 0 8.9673716e+08 1.9097316e+14 3.1145903e-06
+ 1000 1.2341048e+28 3219408.7 0 8.9417158e+08 1.5968585e+14 3.7196039e-06
+Loop time of 9.59889 on 4 procs for 1000 steps with 3487 atoms
-99.6% CPU use with 4 MPI tasks x no OpenMP threads
+99.2% CPU use with 4 MPI tasks x 1 OpenMP threads
MPI task timing breakdown:
Section | min time | avg time | max time |%varavg| %total
---------------------------------------------------------------
-Pair | 4.5763 | 5.0164 | 5.502 | 15.8 | 84.83
-Neigh | 0.11212 | 0.14636 | 0.1811 | 7.8 | 2.48
-Comm | 0.18545 | 0.70922 | 1.1869 | 45.6 | 11.99
-Output | 0.00026011 | 0.00030977 | 0.00038433 | 0.3 | 0.01
-Modify | 0.028668 | 0.029356 | 0.030043 | 0.4 | 0.50
-Other | | 0.01158 | | | 0.20
-
-Nlocal: 871.75 ave 920 max 824 min
-Histogram: 1 0 0 1 0 0 1 0 0 1
-Nghost: 1343.25 ave 1391 max 1295 min
-Histogram: 1 0 0 1 0 0 1 0 0 1
-Neighs: 141785 ave 170754 max 115891 min
-Histogram: 1 1 0 0 0 0 0 1 0 1
+Pair | 7.9131 | 8.1341 | 8.3286 | 6.7 | 84.74
+Neigh | 0.19736 | 0.22539 | 0.25643 | 5.6 | 2.35
+Comm | 0.92843 | 1.1536 | 1.402 | 18.4 | 12.02
+Output | 0.00053358 | 0.00059688 | 0.00070548 | 0.0 | 0.01
+Modify | 0.060774 | 0.06358 | 0.068375 | 1.2 | 0.66
+Other | | 0.02165 | | | 0.23
+
+Nlocal: 871.75 ave 920 max 829 min
+Histogram: 1 0 0 0 2 0 0 0 0 1
+Nghost: 1343.25 ave 1386 max 1295 min
+Histogram: 1 0 0 0 0 2 0 0 0 1
+Neighs: 141783 ave 157099 max 127518 min
+Histogram: 2 0 0 0 0 0 0 0 1 1
FullNghs: 302269 ave 346070 max 260820 min
Histogram: 1 0 0 0 2 0 0 0 0 1
Total # of neighbors = 1209076
Ave neighs/atom = 346.738
Neighbor list builds = 46
Dangerous builds = 0
Please see the log.cite file for references relevant to this simulation
-Total wall time: 0:00:05
+Total wall time: 0:00:09
diff --git a/examples/peri/log.6Jul17.peri.ves.g++.1 b/examples/peri/log.6Jul17.peri.ves.g++.1
new file mode 100644
index 000000000..3d1d156d4
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.ves.g++.1
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 1 by 1 by 1 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/ves
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/ves, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 65.41 | 65.41 | 65.41 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 8.3392177e+24 247040.57 0 849083.8 8.0224286e+11 5.0030006e-07
+ 200 1.1849022e+27 1158030.5 0 86701105 1.0301578e+14 5.5359205e-07
+ 300 2.6287222e+27 4389155.1 0 1.9416767e+08 1.6636212e+14 7.6050375e-07
+ 400 3.2718778e+27 7458219 0 2.4366885e+08 1.5439709e+14 1.0199269e-06
+ 500 3.8413187e+27 6151611.4 0 2.8347258e+08 1.5008974e+14 1.2318007e-06
+ 600 6.1409926e+27 18424316 0 4.6176842e+08 1.9507512e+14 1.5151227e-06
+ 700 1.0046131e+28 11478344 0 7.3675086e+08 2.4228512e+14 1.9956447e-06
+ 800 1.0402132e+28 4421233.6 0 7.5539495e+08 2.0512303e+14 2.4407262e-06
+ 900 1.0419515e+28 7223261.3 0 7.594519e+08 1.6647307e+14 3.0124137e-06
+ 1000 1.0503737e+28 2621490.6 0 7.6093049e+08 1.4315634e+14 3.5313793e-06
+Loop time of 77.2175 on 1 procs for 1000 steps with 3487 atoms
+
+99.4% CPU use with 1 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 76.421 | 76.421 | 76.421 | 0.0 | 98.97
+Neigh | 0.56616 | 0.56616 | 0.56616 | 0.0 | 0.73
+Comm | 0.0038247 | 0.0038247 | 0.0038247 | 0.0 | 0.00
+Output | 0.00051951 | 0.00051951 | 0.00051951 | 0.0 | 0.00
+Modify | 0.19434 | 0.19434 | 0.19434 | 0.0 | 0.25
+Other | | 0.03197 | | | 0.04
+
+Nlocal: 3487 ave 3487 max 3487 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Nghost: 0 ave 0 max 0 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+Neighs: 561942 ave 561942 max 561942 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min
+Histogram: 1 0 0 0 0 0 0 0 0 0
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 37
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:01:17
diff --git a/examples/peri/log.6Jul17.peri.ves.g++.4 b/examples/peri/log.6Jul17.peri.ves.g++.4
new file mode 100644
index 000000000..bd05d58e9
--- /dev/null
+++ b/examples/peri/log.6Jul17.peri.ves.g++.4
@@ -0,0 +1,115 @@
+LAMMPS (6 Jul 2017)
+ using 1 OpenMP thread(s) per MPI task
+# small Peridynamic cylinder hit by projectile
+
+units si
+boundary s s s
+atom_style peri
+atom_modify map array
+neighbor 0.0010 bin
+
+# small target
+
+lattice sc 0.0005
+Lattice spacing in x,y,z = 0.0005 0.0005 0.0005
+region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box
+create_box 1 target
+Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005)
+ 2 by 1 by 2 MPI processor grid
+create_atoms 1 region target
+Created 3487 atoms
+
+pair_style peri/ves
+pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001
+set group all density 2200
+ 3487 settings made for density
+set group all volume 1.25e-10
+ 3487 settings made for volume
+velocity all set 0.0 0.0 0.0 sum no units box
+fix 1 all nve
+
+# spherical indenter to shatter target
+
+variable y0 equal 0.00155
+variable vy equal -100
+variable y equal "v_y0 + step*dt*v_vy"
+
+fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box
+
+compute 1 all damage/atom
+timestep 1.0e-7
+thermo 100
+
+#dump 1 all custom 100 dump.peri id type x y z c_1
+
+#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 2 pad 4
+
+#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006
+#dump_modify 3 pad 4
+
+run 1000
+Neighbor list info ...
+ update every 1 steps, delay 10 steps, check yes
+ max neighbors/atom: 2000, page size: 100000
+ master list distance cutoff = 0.0025001
+ ghost atom cutoff = 0.0025001
+ binsize = 0.00125005, bins = 9 5 9
+ 2 neighbor lists, perpetual/occasional/extra = 1 1 0
+ (1) pair peri/ves, perpetual
+ attributes: half, newton on
+ pair build: half/bin/atomonly/newton
+ stencil: half/bin/3d/newton
+ bin: standard
+ (2) fix PERI_NEIGH, occasional
+ attributes: full, newton on
+ pair build: full/bin/atomonly
+ stencil: full/bin/3d
+ bin: standard
+Peridynamic bonds:
+ total # of bonds = 335966
+ bonds/atom = 96.3482
+Per MPI rank memory allocation (min/avg/max) = 59.9 | 60.16 | 60.26 Mbytes
+Step Temp E_pair E_mol TotEng Press Volume
+ 0 0 0 0 0 0 5.0030006e-07
+ 100 8.3392177e+24 247040.57 0 849083.8 8.0224286e+11 5.0030006e-07
+ 200 1.1849022e+27 1158030.5 0 86701105 1.0301578e+14 5.5359205e-07
+ 300 2.6287222e+27 4389155.1 0 1.9416767e+08 1.6636212e+14 7.6050375e-07
+ 400 3.2718778e+27 7458219 0 2.4366885e+08 1.5439709e+14 1.0199269e-06
+ 500 3.8413187e+27 6151611.4 0 2.8347258e+08 1.5008974e+14 1.2318007e-06
+ 600 6.1409926e+27 18424316 0 4.6176842e+08 1.9507512e+14 1.5151227e-06
+ 700 1.0046131e+28 11478344 0 7.3675086e+08 2.4228512e+14 1.9956447e-06
+ 800 1.0402132e+28 4421233.6 0 7.5539495e+08 2.0512303e+14 2.4407262e-06
+ 900 1.0419515e+28 7223258.7 0 7.594519e+08 1.6647307e+14 3.0124137e-06
+ 1000 1.0503738e+28 2621480.4 0 7.6093057e+08 1.4315636e+14 3.5313793e-06
+Loop time of 25.9768 on 4 procs for 1000 steps with 3487 atoms
+
+99.1% CPU use with 4 MPI tasks x 1 OpenMP threads
+
+MPI task timing breakdown:
+Section | min time | avg time | max time |%varavg| %total
+---------------------------------------------------------------
+Pair | 22.455 | 23.348 | 24.175 | 14.1 | 89.88
+Neigh | 0.14472 | 0.18294 | 0.2299 | 8.6 | 0.70
+Comm | 1.4715 | 2.3485 | 3.2075 | 44.8 | 9.04
+Output | 0.000489 | 0.00059682 | 0.0007987 | 0.0 | 0.00
+Modify | 0.063634 | 0.071411 | 0.076907 | 1.9 | 0.27
+Other | | 0.02506 | | | 0.10
+
+Nlocal: 871.75 ave 896 max 852 min
+Histogram: 2 0 0 0 0 0 0 1 0 1
+Nghost: 1293.25 ave 1313 max 1269 min
+Histogram: 1 0 1 0 0 0 0 0 0 2
+Neighs: 140486 ave 167239 max 121255 min
+Histogram: 2 0 0 0 0 0 1 0 0 1
+FullNghs: 302269 ave 346070 max 260820 min
+Histogram: 1 0 0 0 2 0 0 0 0 1
+
+Total # of neighbors = 1209076
+Ave neighs/atom = 346.738
+Neighbor list builds = 37
+Dangerous builds = 0
+
+Please see the log.cite file for references relevant to this simulation
+
+Total wall time: 0:00:26
diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py
index 18b426f92..af658fa26 100644
--- a/lib/colvars/Install.py
+++ b/lib/colvars/Install.py
@@ -1,82 +1,142 @@
#!/usr/bin/env python
-# install.py tool to do a generic build of a library
-# soft linked to by many of the lib/Install.py files
-# used to automate the steps described in the corresponding lib/README
+# Install.py tool to do automate build of Colvars
-import sys,commands,os
+from __future__ import print_function
+import sys,os,subprocess
# help message
help = """
-Syntax: python Install.py -m machine -e suffix
- specify -m and optionally -e, order does not matter
+Syntax from src dir: make lib-colvars args="-m machine -e suffix"
+Syntax from lib/colvars dir: python Install.py -m machine -e suffix
+
+specify -m and optionally -e, order does not matter
+
-m = peform a clean followed by "make -f Makefile.machine"
- machine = suffix of a lib/Makefile.* file
+ machine = suffix of a lib/colvars/Makefile.* or of a
+ src/MAKE/MACHINES/Makefile.* file
-e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix
does not alter existing Makefile.machine
+
+Examples:
+
+make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler
"""
# print error message or help
def error(str=None):
- if not str: print help
- else: print "ERROR",str
+ if not str: print(help)
+ else: print("ERROR"),str
sys.exit()
# parse args
args = sys.argv[1:]
nargs = len(args)
if nargs == 0: error()
machine = None
-extraflag = 0
+extraflag = False
iarg = 0
while iarg < nargs:
if args[iarg] == "-m":
- if iarg+2 > nargs: error()
+ if iarg+2 > len(args): error()
machine = args[iarg+1]
iarg += 2
elif args[iarg] == "-e":
- if iarg+2 > nargs: error()
- extraflag = 1
+ if iarg+2 > len(args): error()
+ extraflag = True
suffix = args[iarg+1]
iarg += 2
else: error()
# set lib from working dir
cwd = os.getcwd()
lib = os.path.basename(cwd)
-# create Makefile.auto as copy of Makefile.machine
-# reset EXTRAMAKE if requested
-
+def get_lammps_machine_flags(machine):
+ """Parse Makefile.machine from LAMMPS, return dictionary of compiler flags"""
+ if not os.path.exists("../../src/MAKE/MACHINES/Makefile.%s" % machine):
+ error("Cannot locate src/MAKE/MACHINES/Makefile.%s" % machine)
+ lines = open("../../src/MAKE/MACHINES/Makefile.%s" % machine,
+ 'r').readlines()
+ machine_flags = {}
+ for line in lines:
+ line = line.partition('#')[0]
+ line = line.rstrip()
+ words = line.split()
+ if (len(words) > 2):
+ if ((words[0] == 'CC') or (words[0] == 'CCFLAGS') or
+ (words[0] == 'SHFLAGS') or (words[0] == 'ARCHIVE') or
+ (words[0] == 'ARFLAGS') or (words[0] == 'SHELL')):
+ machine_flags[words[0]] = ' '.join(words[2:])
+ return machine_flags
+
+def gen_colvars_makefile_machine(machine, machine_flags):
+ """Generate Makefile.machine for Colvars given the compiler flags"""
+ machine_makefile = open("Makefile.%s" % machine, 'w')
+ machine_makefile.write('''# -*- makefile -*- to build Colvars module with %s
+
+COLVARS_LIB = libcolvars.a
+COLVARS_OBJ_DIR =
+
+CXX = %s
+CXXFLAGS = %s %s
+AR = %s
+ARFLAGS = %s
+SHELL = %s
+
+include Makefile.common
+
+.PHONY: default clean
+
+default: $(COLVARS_LIB) Makefile.lammps
+
+clean:
+ -rm -f $(COLVARS_OBJS) $(COLVARS_LIB)
+''' % (machine, machine_flags['CC'],
+ machine_flags['CCFLAGS'], machine_flags['SHFLAGS'] ,
+ machine_flags['ARCHIVE'], machine_flags['ARFLAGS'],
+ machine_flags['SHELL']))
+
+if not os.path.exists("Makefile.%s" % machine):
+ machine_flags = get_lammps_machine_flags(machine)
+ gen_colvars_makefile_machine(machine, machine_flags)
if not os.path.exists("Makefile.%s" % machine):
error("lib/%s/Makefile.%s does not exist" % (lib,machine))
+# create Makefile.auto as copy of Makefile.machine
+# reset EXTRAMAKE if requested
+
lines = open("Makefile.%s" % machine,'r').readlines()
fp = open("Makefile.auto",'w')
-
for line in lines:
words = line.split()
if len(words) == 3 and extraflag and \
words[0] == "EXTRAMAKE" and words[1] == '=':
line = line.replace(words[2],"Makefile.lammps.%s" % suffix)
- print >>fp,line,
-
+ fp.write(line)
fp.close()
# make the library via Makefile.auto
-print "Building lib%s.a ..." % lib
-cmd = "make -f Makefile.auto clean; make -f Makefile.auto"
-txt = commands.getoutput(cmd)
-print txt
+try:
+ import multiprocessing
+ n_cpus = multiprocessing.cpu_count()
+except:
+ n_cpus = 1
+
+print("Building lib%s.a ..." % lib)
+cmd = ["make -f Makefile.auto clean"]
+print(subprocess.check_output(cmd, shell=True).decode())
+cmd = ["make -f Makefile.auto -j%d" % n_cpus]
+print(subprocess.check_output(cmd, shell=True).decode())
-if os.path.exists("lib%s.a" % lib): print "Build was successful"
+if os.path.exists("lib%s.a" % lib): print("Build was successful")
else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib))
if not os.path.exists("Makefile.lammps"):
- print "lib/%s/Makefile.lammps was NOT created" % lib
+ print("lib/%s/Makefile.lammps was NOT created" % lib)
diff --git a/lib/colvars/Makefile.colvars b/lib/colvars/Makefile.colvars
deleted file mode 100644
index d1a204403..000000000
--- a/lib/colvars/Makefile.colvars
+++ /dev/null
@@ -1,119 +0,0 @@
-# library build -*- makefile -*- for colvars module
-
-# which file will be copied to Makefile.lammps
-
-EXTRAMAKE = Makefile.lammps.empty
-
-# ------ SETTINGS ------
-
-CXX = g++
-CXXFLAGS = -O2 -g -Wall -fPIC -funroll-loops # -DCOLVARS_DEBUG
-ARCHIVE = ar
-ARCHFLAG = -rscv
-SHELL = /bin/sh
-
-# ------ DEFINITIONS ------
-
-SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \
- colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \
- colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \
- colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \
- colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \
- colvarscript.cpp colvartypes.cpp colvarvalue.cpp
-
-LIB = libcolvars.a
-OBJ = $(SRC:.cpp=.o)
-EXE = #colvars_standalone
-
-# ------ MAKE PROCEDURE ------
-
-default: $(LIB) $(EXE) Makefile.lammps
-
-Makefile.lammps:
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(LIB): $(OBJ)
- $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ)
-
-colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB)
- $(CXX) -o $@ $(CXXFLAGS) $^
-
-# ------ MAKE FLAGS ------
-
-.SUFFIXES:
-.SUFFIXES: .cpp .o
-
-.PHONY: default clean
-
-# ------ COMPILE RULES ------
-
-.cpp.o:
- $(CXX) $(CXXFLAGS) -c $<
-
-# ------ DEPENDENCIES ------
-#
-colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h
-colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarbias_abf.h colvarbias.h colvargrid.h
-colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_restraint.h colvarbias.h
-colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h
-colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvarbias_meta.h colvarbias.h colvargrid.h
-colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \
- colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvaratoms.h colvar.h colvarcomp.h
-colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
- colvaratoms.h
-colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvarscript.h colvarbias.h
-colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h
-colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvargrid.h
-colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \
- colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \
- colvarscript.h
-colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \
- colvarparse.h colvardeps.h
-colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h
-
-# ------ CLEAN ------
-
-clean:
- -rm *.o *~ $(LIB)
-
diff --git a/lib/colvars/Makefile.common b/lib/colvars/Makefile.common
new file mode 100644
index 000000000..f47403f77
--- /dev/null
+++ b/lib/colvars/Makefile.common
@@ -0,0 +1,65 @@
+# Shared -*- makefile -*- for multiple architectures
+
+# # Detect settings from PYTHON package (if defined)
+# sinclude ../../src/Makefile.package.settings
+# ifeq ($(python_SYSINC),)
+# COLVARS_PYTHON_INCFLAGS =
+# else
+# COLVARS_PYTHON_INCFLAGS = -DCOLVARS_PYTHON $(python_SYSINC)
+# endif
+
+# Detect debug settings
+ifeq ($(COLVARS_DEBUG),)
+COLVARS_DEBUG_INCFLAGS =
+else
+COLVARS_DEBUG_INCFLAGS= -DCOLVARS_DEBUG
+endif
+
+COLVARS_INCFLAGS = $(COLVARS_DEBUG_INCFLAGS) $(COLVARS_PYTHON_INCFLAGS)
+
+
+.SUFFIXES:
+.SUFFIXES: .cpp .o
+
+COLVARS_SRCS = \
+ colvaratoms.cpp \
+ colvarbias_abf.cpp \
+ colvarbias_alb.cpp \
+ colvarbias.cpp \
+ colvarbias_histogram.cpp \
+ colvarbias_meta.cpp \
+ colvarbias_restraint.cpp \
+ colvarcomp_angles.cpp \
+ colvarcomp_coordnums.cpp \
+ colvarcomp.cpp \
+ colvarcomp_distances.cpp \
+ colvarcomp_protein.cpp \
+ colvarcomp_rotations.cpp \
+ colvar.cpp \
+ colvardeps.cpp \
+ colvargrid.cpp \
+ colvarmodule.cpp \
+ colvarparse.cpp \
+ colvarproxy.cpp \
+ colvarscript.cpp \
+ colvartypes.cpp \
+ colvarvalue.cpp
+
+COLVARS_OBJS = $(COLVARS_SRCS:.cpp=.o)
+
+.cpp.o:
+ $(CXX) $(CXXFLAGS) $(COLVARS_INCFLAGS) -c $<
+
+$(COLVARS_LIB): Makefile.deps $(COLVARS_OBJS)
+ $(AR) $(ARFLAGS) $(COLVARS_LIB) $(COLVARS_OBJS)
+
+
+Makefile.deps: $(COLVARS_SRCS)
+ @echo > $@
+ @for src in $^ ; do \
+ obj=`basename $$src .cpp`.o ; \
+ $(CXX) -MM $(COLVARS_INCFLAGS) \
+ -MT '$$(COLVARS_OBJ_DIR)'$$obj $$src >> $@ ; \
+ done
+
+include Makefile.deps
diff --git a/lib/colvars/Makefile.deps b/lib/colvars/Makefile.deps
new file mode 100644
index 000000000..f463da5f8
--- /dev/null
+++ b/lib/colvars/Makefile.deps
@@ -0,0 +1,78 @@
+
+$(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarparse.h colvaratoms.h colvardeps.h
+$(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvar.h \
+ colvarparse.h colvardeps.h colvarbias_abf.h colvarbias.h colvargrid.h
+$(COLVARS_OBJ_DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarbias_alb.h colvar.h colvarparse.h colvardeps.h colvarbias.h
+$(COLVARS_OBJ_DIR)colvarbias.o: colvarbias.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h \
+ colvar.h colvarparse.h colvardeps.h
+$(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarbias_histogram.h \
+ colvarbias.h colvargrid.h
+$(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h colvardeps.h colvarbias_meta.h colvarbias.h \
+ colvargrid.h
+$(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarbias_restraint.h colvarbias.h colvar.h colvarparse.h \
+ colvardeps.h
+$(COLVARS_OBJ_DIR)colvarcomp_angles.o: colvarcomp_angles.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
+ colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h colvaratoms.h colvardeps.h colvar.h \
+ colvarcomp.h
+$(COLVARS_OBJ_DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvar.h \
+ colvarparse.h colvardeps.h colvarcomp.h colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarcomp_distances.o: colvarcomp_distances.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \
+ colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \
+ colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \
+ colvaratoms.h
+$(COLVARS_OBJ_DIR)colvar.o: colvar.cpp colvarmodule.h colvars_version.h \
+ colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvar.h \
+ colvardeps.h colvarcomp.h colvaratoms.h colvarscript.h colvarbias.h
+$(COLVARS_OBJ_DIR)colvardeps.o: colvardeps.cpp colvardeps.h \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarparse.h
+$(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarparse.h colvar.h colvardeps.h colvarcomp.h colvaratoms.h \
+ colvargrid.h
+$(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarparse.h colvar.h colvardeps.h colvarbias.h colvarbias_abf.h \
+ colvargrid.h colvarbias_alb.h colvarbias_histogram.h colvarbias_meta.h \
+ colvarbias_restraint.h colvarscript.h colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarparse.h
+$(COLVARS_OBJ_DIR)colvarproxy.o: colvarproxy.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarscript.h colvarbias.h colvar.h colvarparse.h colvardeps.h \
+ colvaratoms.h
+$(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarscript.h \
+ colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \
+ colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
+$(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \
+ colvarparse.h
+$(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \
+ colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h
diff --git a/lib/colvars/Makefile.fermi b/lib/colvars/Makefile.fermi
deleted file mode 100644
index 906675ae1..000000000
--- a/lib/colvars/Makefile.fermi
+++ /dev/null
@@ -1,120 +0,0 @@
-# library build -*- makefile -*- for colvars module
-
-# which file will be copied to Makefile.lammps
-
-EXTRAMAKE = Makefile.lammps.empty
-
-# ------ SETTINGS ------
-
-CXX = g++
-CXXFLAGS = -O2 -mpc64 -g -fPIC \
- -Wall -Wno-sign-compare # -DCOLVARS_DEBUG
-ARCHIVE = ar
-ARCHFLAG = -rscv
-SHELL = /bin/sh
-
-# ------ DEFINITIONS ------
-
-SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \
- colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \
- colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \
- colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \
- colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \
- colvarscript.cpp colvartypes.cpp colvarvalue.cpp
-
-LIB = libcolvars.a
-OBJ = $(SRC:.cpp=.o)
-EXE = #colvars_standalone
-
-# ------ MAKE PROCEDURE ------
-
-default: $(LIB) $(EXE) Makefile.lammps
-
-Makefile.lammps:
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(LIB): $(OBJ)
- $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ)
-
-colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB)
- $(CXX) -o $@ $(CXXFLAGS) $^
-
-# ------ MAKE FLAGS ------
-
-.SUFFIXES:
-.SUFFIXES: .cpp .o
-
-.PHONY: default clean
-
-# ------ COMPILE RULES ------
-
-.cpp.o:
- $(CXX) $(CXXFLAGS) -c $<
-
-# ------ DEPENDENCIES ------
-#
-colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h
-colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarbias_abf.h colvarbias.h colvargrid.h
-colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_restraint.h colvarbias.h
-colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h
-colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvarbias_meta.h colvarbias.h colvargrid.h
-colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \
- colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvaratoms.h colvar.h colvarcomp.h
-colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
- colvaratoms.h
-colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvarscript.h colvarbias.h
-colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h
-colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvargrid.h
-colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \
- colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \
- colvarscript.h
-colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \
- colvarparse.h colvardeps.h
-colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h
-
-# ------ CLEAN ------
-
-clean:
- -rm *.o *~ $(LIB)
-
diff --git a/lib/colvars/Makefile.g++ b/lib/colvars/Makefile.g++
index c80fa1065..556e39d07 100644
--- a/lib/colvars/Makefile.g++
+++ b/lib/colvars/Makefile.g++
@@ -1,119 +1,25 @@
-# library build -*- makefile -*- for colvars module
-
-# which file will be copied to Makefile.lammps
+# -*- makefile -*- to build Colvars module with GNU compiler
EXTRAMAKE = Makefile.lammps.empty
-# ------ SETTINGS ------
+COLVARS_LIB = libcolvars.a
+COLVARS_OBJ_DIR =
CXX = g++
-CXXFLAGS = -O2 -g -fPIC -funroll-loops # -DCOLVARS_DEBUG
-ARCHIVE = ar
-ARCHFLAG = -rscv
+CXXFLAGS = -O2 -g -Wall -fPIC -funroll-loops
+AR = ar
+ARFLAGS = -rscv
SHELL = /bin/sh
-# ------ DEFINITIONS ------
-
-SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \
- colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \
- colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \
- colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \
- colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \
- colvarscript.cpp colvartypes.cpp colvarvalue.cpp
-
-LIB = libcolvars.a
-OBJ = $(SRC:.cpp=.o)
-EXE = #colvars_standalone
-
-# ------ MAKE PROCEDURE ------
-
-default: $(LIB) $(EXE) Makefile.lammps
-
-Makefile.lammps:
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(LIB): $(OBJ)
- $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ)
-
-colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB)
- $(CXX) -o $@ $(CXXFLAGS) $^
-
-# ------ MAKE FLAGS ------
-
-.SUFFIXES:
-.SUFFIXES: .cpp .o
-
.PHONY: default clean
-# ------ COMPILE RULES ------
+default: $(COLVARS_LIB) Makefile.lammps
-.cpp.o:
- $(CXX) $(CXXFLAGS) -c $<
-
-# ------ DEPENDENCIES ------
-#
-colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h
-colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarbias_abf.h colvarbias.h colvargrid.h
-colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_restraint.h colvarbias.h
-colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h
-colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvarbias_meta.h colvarbias.h colvargrid.h
-colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \
- colvarbias.h colvar.h colvarparse.h colvardeps.h
-colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvaratoms.h colvar.h colvarcomp.h
-colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
- colvaratoms.h
-colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarcomp.h colvaratoms.h
-colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvarscript.h colvarbias.h
-colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h
-colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvargrid.h
-colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \
- colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \
- colvarscript.h
-colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \
- colvarparse.h colvardeps.h
-colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h
-
-# ------ CLEAN ------
+include Makefile.common
clean:
- -rm *.o *~ $(LIB)
+ -rm -f $(COLVARS_OBJS) $(COLVARS_LIB)
+
+Makefile.lammps:
+ -cp $(EXTRAMAKE) Makefile.lammps
diff --git a/lib/colvars/Makefile.g++-debug b/lib/colvars/Makefile.g++-debug
new file mode 100644
index 000000000..a6ca2f812
--- /dev/null
+++ b/lib/colvars/Makefile.g++-debug
@@ -0,0 +1,5 @@
+# -*- makefile -*- to build Colvars module with GNU compiler
+
+COLVARS_DEBUG = "YES"
+
+include Makefile.g++
diff --git a/lib/colvars/Makefile.lammps.debug b/lib/colvars/Makefile.lammps
similarity index 76%
copy from lib/colvars/Makefile.lammps.debug
copy to lib/colvars/Makefile.lammps
index 1ef229d58..99f57b050 100644
--- a/lib/colvars/Makefile.lammps.debug
+++ b/lib/colvars/Makefile.lammps
@@ -1,5 +1,5 @@
# Settings that the LAMMPS build will import when this package library is used
-colvars_SYSINC = # -DCOLVARS_DEBUG
+colvars_SYSINC =
colvars_SYSLIB =
colvars_SYSPATH =
diff --git a/lib/colvars/Makefile.lammps.debug b/lib/colvars/Makefile.lammps.debug
index 1ef229d58..1c4399a2c 100644
--- a/lib/colvars/Makefile.lammps.debug
+++ b/lib/colvars/Makefile.lammps.debug
@@ -1,5 +1,5 @@
# Settings that the LAMMPS build will import when this package library is used
-colvars_SYSINC = # -DCOLVARS_DEBUG
+colvars_SYSINC = -DCOLVARS_DEBUG
colvars_SYSLIB =
colvars_SYSPATH =
diff --git a/lib/colvars/Makefile.lammps.empty b/lib/colvars/Makefile.lammps.empty
index 1ef229d58..99f57b050 100644
--- a/lib/colvars/Makefile.lammps.empty
+++ b/lib/colvars/Makefile.lammps.empty
@@ -1,5 +1,5 @@
# Settings that the LAMMPS build will import when this package library is used
-colvars_SYSINC = # -DCOLVARS_DEBUG
+colvars_SYSINC =
colvars_SYSLIB =
colvars_SYSPATH =
diff --git a/lib/colvars/Makefile.mingw32-cross b/lib/colvars/Makefile.mingw32-cross
index eba83c555..29c64b26a 100644
--- a/lib/colvars/Makefile.mingw32-cross
+++ b/lib/colvars/Makefile.mingw32-cross
@@ -1,127 +1,31 @@
-# library build -*- makefile -*- for colvars module
-
-# which file will be copied to Makefile.lammps
+# -*- makefile -*- to build Colvars module with MinGW 32-bit
EXTRAMAKE = Makefile.lammps.empty
-# ------ SETTINGS ------
+COLVARS_LIB = libcolvars.a
+COLVARS_OBJ_DIR = Obj_mingw64/
CXX = i686-w64-mingw32-g++
CXXFLAGS = -O2 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \
-fno-rtti -fno-exceptions -finline-functions \
-ffast-math -funroll-loops -fstrict-aliasing \
-Wall -W -Wno-uninitialized
-ARCHIVE = i686-w64-mingw32-ar
-ARCHFLAG = -rscv
+AR = i686-w64-mingw32-ar
+ARFLAGS = -rscv
SHELL = /bin/sh
-# ------ DEFINITIONS ------
-
-SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \
- colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \
- colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \
- colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \
- colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \
- colvarscript.cpp colvartypes.cpp colvarvalue.cpp
-
-DIR = Obj_mingw32/
-LIB = $(DIR)libcolvars.a
-OBJ = $(SRC:%.cpp=$(DIR)%.o)
-EXE = #colvars_standalone
-
-# ------ MAKE PROCEDURE ------
-
-default: $(DIR) $(LIB) $(EXE) Makefile.lammps
-
-$(DIR):
- mkdir $(DIR)
-
-Makefile.lammps:
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(LIB): $(DIR) $(OBJ)
- $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ)
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(DIR)colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB)
- $(CXX) -o $@ $(CXXFLAGS) $^
-
-# ------ MAKE FLAGS ------
-
-.SUFFIXES:
-.SUFFIXES: .cpp .o
-
.PHONY: default clean
-# ------ COMPILE RULES ------
-
-$(DIR)%.o: %.cpp
- $(CXX) $(CXXFLAGS) -c $< -o $@
+default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps
-# ------ DEPENDENCIES ------
-#
-$(DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h
-$(DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarbias_abf.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_restraint.h colvarbias.h
-$(DIR)colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
-$(DIR)colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvarbias_meta.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \
- colvarbias.h colvar.h colvarparse.h colvardeps.h
-$(DIR)colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvaratoms.h colvar.h colvarcomp.h
-$(DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
- colvaratoms.h
-$(DIR)colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-$(DIR)colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvarscript.h colvarbias.h
-$(DIR)colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h
-$(DIR)colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvargrid.h
-$(DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \
- colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \
- colvarscript.h
-$(DIR)colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-$(DIR)colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \
- colvarparse.h colvardeps.h
-$(DIR)colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-$(DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h
+include Makefile.common
-# ------ CLEAN ------
+$(COLVARS_OBJ_DIR):
+ mkdir $(COLVARS_OBJ_DIR)
clean:
- -rm $(DIR)*.o *~ $(LIB)
- -rmdir $(DIR)
+ -rm -f $(COLVARS_OBJS) $(COLVARS_LIB)
+ -rmdir $(COLVARS_OBJ_DIR)
+
+Makefile.lammps:
+ -cp $(EXTRAMAKE) Makefile.lammps
diff --git a/lib/colvars/Makefile.mingw64-cross b/lib/colvars/Makefile.mingw64-cross
index 1d83b6a0a..2fd1c6fc6 100644
--- a/lib/colvars/Makefile.mingw64-cross
+++ b/lib/colvars/Makefile.mingw64-cross
@@ -1,127 +1,31 @@
-# library build -*- makefile -*- for colvars module
-
-# which file will be copied to Makefile.lammps
+# -*- makefile -*- to build Colvars module with MinGW 32-bit
EXTRAMAKE = Makefile.lammps.empty
-# ------ SETTINGS ------
+COLVARS_LIB = libcolvars.a
+COLVARS_OBJ_DIR = Obj_mingw32/
CXX = x86_64-w64-mingw32-g++
CXXFLAGS = -O2 -march=core2 -mtune=core2 -mpc64 -msse2 \
-fno-rtti -fno-exceptions -finline-functions \
-ffast-math -funroll-loops -fstrict-aliasing \
-Wall -W -Wno-uninitialized
-ARCHIVE = x86_64-w64-mingw32-ar
-ARCHFLAG = -rscv
+AR = x86_64-w64-mingw32-ar
+ARFLAGS = -rscv
SHELL = /bin/sh
-# ------ DEFINITIONS ------
-
-SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \
- colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \
- colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \
- colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \
- colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \
- colvarscript.cpp colvartypes.cpp colvarvalue.cpp
-
-DIR = Obj_mingw64/
-LIB = $(DIR)libcolvars.a
-OBJ = $(SRC:%.cpp=$(DIR)%.o)
-EXE = #colvars_standalone
-
-# ------ MAKE PROCEDURE ------
-
-default: $(DIR) $(LIB) $(EXE) Makefile.lammps
-
-$(DIR):
- mkdir $(DIR)
-
-Makefile.lammps:
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(LIB): $(DIR) $(OBJ)
- $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ)
- @cp $(EXTRAMAKE) Makefile.lammps
-
-$(DIR)colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB)
- $(CXX) -o $@ $(CXXFLAGS) $^
-
-# ------ MAKE FLAGS ------
-
-.SUFFIXES:
-.SUFFIXES: .cpp .o
-
.PHONY: default clean
-# ------ COMPILE RULES ------
-
-$(DIR)%.o: %.cpp
- $(CXX) $(CXXFLAGS) -c $< -o $@
+default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps
-# ------ DEPENDENCIES ------
-#
-$(DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h
-$(DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarbias_abf.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_restraint.h colvarbias.h
-$(DIR)colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h
-$(DIR)colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \
- colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvarbias_meta.h colvarbias.h colvargrid.h
-$(DIR)colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \
- colvarbias.h colvar.h colvarparse.h colvardeps.h
-$(DIR)colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \
- colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvaratoms.h colvar.h colvarcomp.h
-$(DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \
- colvaratoms.h
-$(DIR)colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarcomp.h colvaratoms.h
-$(DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \
- colvar.h colvarcomp.h colvaratoms.h
-$(DIR)colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvarscript.h colvarbias.h
-$(DIR)colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h
-$(DIR)colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \
- colvaratoms.h colvargrid.h
-$(DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \
- colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \
- colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \
- colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \
- colvarscript.h
-$(DIR)colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-$(DIR)colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \
- colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \
- colvarparse.h colvardeps.h
-$(DIR)colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h colvarparse.h
-$(DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \
- colvarvalue.h
+include Makefile.common
-# ------ CLEAN ------
+$(COLVARS_OBJ_DIR):
+ mkdir $(COLVARS_OBJ_DIR)
clean:
- -rm $(DIR)*.o *~ $(LIB)
- -rmdir $(DIR)
+ -rm -f $(COLVARS_OBJS) $(COLVARS_LIB)
+ -rmdir $(COLVARS_OBJ_DIR)
+
+Makefile.lammps:
+ -cp $(EXTRAMAKE) Makefile.lammps
diff --git a/lib/colvars/README b/lib/colvars/README
index a5e5938b2..ce1d31997 100644
--- a/lib/colvars/README
+++ b/lib/colvars/README
@@ -1,73 +1,82 @@
-This library is the portable "colvars" module, originally interfaced
-with the NAMD MD code, to provide an extensible software framework,
-that allows enhanced sampling in molecular dynamics simulations.
-The module is written to maximize performance, portability,
-flexibility of usage for the user, and extensibility for the developer.
+## Collective variables module (Colvars)
-The development of the colvars library is now hosted on github at:
-http://colvars.github.io/
-You can use this site to get access to the latest development sources
-and the up-to-date documentation.
+A software module for molecular simulation and analysis that provides a
+high-performance implementation of sampling algorithms defined on a reduced
+space of continuously differentiable functions (aka collective variables).
-Copy of the specific documentation is also in
- doc/PDF/colvars-refman-lammps.pdf
+The module itself implements a variety of functions and algorithms, including
+free-energy estimators based on thermodynamic forces, non-equilibrium work and
+probability distributions.
-Please report bugs and request new features at:
-https://github.com/colvars/colvars/issues
-
-The following publications describe the principles of
-the implementation of this library:
+For a brief description see:
+ http://colvars.github.io/
+ https://github.com/colvars/colvars/
- Using collective variables to drive molecular dynamics simulations,
- Giacomo Fiorin , Michael L. Klein & Jérôme Hénin (2013):
- Molecular Physics DOI:10.1080/00268976.2013.813594
- Exploring Multidimensional Free Energy Landscapes Using
- Time-Dependent Biases on Collective Variables,
- J. Hénin, G. Fiorin, C. Chipot, and M. L. Klein,
- J. Chem. Theory Comput., 6, 35-47 (2010).
-
--------------------------------------------------
+## How to build
This directory has source files to build a library that LAMMPS
links against when using the USER-COLVARS package.
-This library must be built with a C++ compiler, before LAMMPS is
-built, so LAMMPS can link against it.
+This library must be built with a C++ compiler, *before* LAMMPS is built and
+*after* packages are configured, so that LAMMPS can link against it.
+You can use the provided Makefile.* files or create your own, specific to your
+compiler and system. For example:
-You can type "make lib-colvars" from the src directory to see help on
-how to build this library via make commands, or you can do the same
-thing by typing "python Install.py" from within this directory, or you
-can do it manually by following the instructions below.
+ cd src
+ make yes-user-colvars
+ cd ../lib/colvars
+ make -f Makefile.g++
-Build the library using one of the provided Makefile.* files or create
-your own, specific to your compiler and system. For example:
+where Makefile.g++ uses the GNU C++ compiler and is a good template to start.
-make -f Makefile.g++
+**Optional**: if you use the Install.py script provided in this folder, you
+can give the machine name as the '-m' argument. This can be the suffix of one
+of the files from either this folder, or from src/MAKE.
+*This is only supported by the Install.py within the lib/colvars folder*.
When you are done building this library, two files should
exist in this directory:
libcolvars.a the library LAMMPS will link against
Makefile.lammps settings the LAMMPS Makefile will import
-Makefile.lammps is created by the make command, by copying one of the
-Makefile.lammps.* files. See the EXTRAMAKE setting at the top of the
-Makefile.* files.
-
IMPORTANT: You must examine the final Makefile.lammps to insure it is
correct for your system, else the LAMMPS build will likely fail.
-Makefile.lammps has settings for 3 variables:
+If you want to set a debug flag recognized by the library, the
+settings in Makefile.common should work.
-user-colvars_SYSINC = leave blank for this package unless debugging
-user-colvars_SYSLIB = leave blank for this package
-user-colvars_SYSPATH = leave blank for this package
-You have several choices for these settings:
+## Documentation
-Since they do not normally need to be set, the settings in
-Makefile.lammps.empty should work.
+For the reference manual see:
+ http://colvars.github.io/colvars-refman-lammps
+
+A copy of reference manual is also in:
+ doc/PDF/colvars-refman-lammps.pdf
+
+Also included is a Doxygen-based developer documentation:
+ http://colvars.github.io/doxygen/html/
+
+The reference article is:
+ G. Fiorin, M. L. Klein, and J. Henin,
+ Molecular Physics 111, 3345 (2013).
+ http://dx.doi.org/10.1080/00268976.2013.813594
+
+
+## Updating to the latest version
+
+To recompile LAMMPS with the most recent version of this module, the `master`
+branch of this repository from GitHub, or clone it via git:
+
+ git clone https://github.com/colvars/colvars.git
+
+and run the provided `update-colvars-code.sh` script against the unpacked
+LAMMPS source tree:
+
+ ./update-colvars-code.sh /path/to/lammps/folder
+
+Please report bugs and request new features at:
+https://github.com/colvars/colvars/issues
-If you want to set a debug flag recognized by the library, the
-settings in Makefile.lammps.debug should work.
diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp
index e8c7e8832..d23bd852a 100644
--- a/lib/colvars/colvar.cpp
+++ b/lib/colvars/colvar.cpp
@@ -1,2050 +1,2284 @@
-
// -*- c++ -*-
+
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
-
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
#include "colvarscript.h"
+
+// used in build_atom_list()
#include <algorithm>
/// Compare two cvcs using their names
/// Used to sort CVC array in scripted coordinates
bool compare(colvar::cvc *i, colvar::cvc *j) {
return i->name < j->name;
}
colvar::colvar()
+ : prev_timestep(-1)
{
// Initialize static array once and for all
+ runave_os = NULL;
init_cv_requires();
}
int colvar::init(std::string const &conf)
{
cvm::log("Initializing a new collective variable.\n");
colvarparse::init(conf);
int error_code = COLVARS_OK;
colvarmodule *cv = cvm::main();
get_keyval(conf, "name", this->name,
(std::string("colvar")+cvm::to_str(cv->variables()->size()+1)));
if ((cvm::colvar_by_name(this->name) != NULL) &&
(cvm::colvar_by_name(this->name) != this)) {
cvm::error("Error: this colvar cannot have the same name, \""+this->name+
"\", as another colvar.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
// Initialize dependency members
// Could be a function defined in a different source file, for space?
this->description = "colvar " + this->name;
kinetic_energy = 0.0;
potential_energy = 0.0;
error_code |= init_components(conf);
if (error_code != COLVARS_OK) {
return cvm::get_error();
}
size_t i;
+#ifdef LEPTON
+ error_code |= init_custom_function(conf);
+ if (error_code != COLVARS_OK) {
+ return cvm::get_error();
+ }
+#endif
+
// Setup colvar as scripted function of components
if (get_keyval(conf, "scriptedFunction", scripted_function,
"", colvarparse::parse_silent)) {
enable(f_cv_scripted);
cvm::log("This colvar uses scripted function \"" + scripted_function + "\".");
std::string type_str;
get_keyval(conf, "scriptedFunctionType", type_str, "scalar");
x.type(colvarvalue::type_notset);
int t;
for (t = 0; t < colvarvalue::type_all; t++) {
if (type_str == colvarvalue::type_keyword(colvarvalue::Type(t))) {
x.type(colvarvalue::Type(t));
break;
}
}
if (x.type() == colvarvalue::type_notset) {
cvm::error("Could not parse scripted colvar type.", INPUT_ERROR);
return INPUT_ERROR;
}
cvm::log(std::string("Expecting colvar value of type ")
+ colvarvalue::type_desc(x.type()));
if (x.type() == colvarvalue::type_vector) {
int size;
if (!get_keyval(conf, "scriptedFunctionVectorSize", size)) {
cvm::error("Error: no size specified for vector scripted function.",
INPUT_ERROR);
return INPUT_ERROR;
}
x.vector1d_value.resize(size);
}
x_reported.type(x);
// Sort array of cvcs based on their names
// Note: default CVC names are in input order for same type of CVC
std::sort(cvcs.begin(), cvcs.end(), compare);
if(cvcs.size() > 1) {
cvm::log("Sorted list of components for this scripted colvar:");
for (i = 0; i < cvcs.size(); i++) {
cvm::log(cvm::to_str(i+1) + " " + cvcs[i]->name);
}
}
// Build ordered list of component values that will be
// passed to the script
for (i = 0; i < cvcs.size(); i++) {
sorted_cvc_values.push_back(&(cvcs[i]->value()));
}
}
- if (!is_enabled(f_cv_scripted)) {
+ if (!(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function))) {
colvarvalue const &cvc_value = (cvcs[0])->value();
if (cvm::debug())
cvm::log ("This collective variable is a "+
colvarvalue::type_desc(cvc_value.type())+
((cvc_value.size() > 1) ? " with "+
cvm::to_str(cvc_value.size())+" individual components.\n" :
".\n"));
x.type(cvc_value);
x_reported.type(cvc_value);
}
// If using scripted biases, any colvar may receive bias forces
// and will need its gradient
if (cvm::scripted_forces()) {
enable(f_cv_gradient);
}
// check for linear combinations
{
- bool lin = !is_enabled(f_cv_scripted);
+ bool lin = !(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function));
for (i = 0; i < cvcs.size(); i++) {
// FIXME this is a reverse dependency, ie. cv feature depends on cvc flag
// need to clarify this case
// if ((cvcs[i])->b_debug_gradients)
// enable(task_gradients);
if ((cvcs[i])->sup_np != 1) {
if (cvm::debug() && lin)
cvm::log("Warning: You are using a non-linear polynomial "
"combination to define this collective variable, "
"some biasing methods may be unavailable.\n");
lin = false;
if ((cvcs[i])->sup_np < 0) {
cvm::log("Warning: you chose a negative exponent in the combination; "
"if you apply forces, the simulation may become unstable "
"when the component \""+
(cvcs[i])->function_type+"\" approaches zero.\n");
}
}
}
set_enabled(f_cv_linear, lin);
}
// Colvar is homogeneous if:
// - it is linear (hence not scripted)
// - all cvcs have coefficient 1 or -1
// i.e. sum or difference of cvcs
{
bool homogeneous = is_enabled(f_cv_linear);
for (i = 0; i < cvcs.size(); i++) {
if ((std::fabs(cvcs[i]->sup_coeff) - 1.0) > 1.0e-10) {
homogeneous = false;
}
}
set_enabled(f_cv_homogeneous, homogeneous);
}
// Colvar is deemed periodic if:
// - it is homogeneous
// - all cvcs are periodic
// - all cvcs have the same period
if (cvcs[0]->b_periodic) { // TODO make this a CVC feature
bool b_periodic = true;
period = cvcs[0]->period;
for (i = 1; i < cvcs.size(); i++) {
if (!cvcs[i]->b_periodic || cvcs[i]->period != period) {
b_periodic = false;
period = 0.0;
cvm::log("Warning: although one component is periodic, this colvar will "
"not be treated as periodic, either because the exponent is not "
"1, or because components of different periodicity are defined. "
"Make sure that you know what you are doing!");
}
}
set_enabled(f_cv_periodic, b_periodic);
}
// check that cvcs are compatible
for (i = 0; i < cvcs.size(); i++) {
// components may have different types only for scripted functions
- if (!is_enabled(f_cv_scripted) && (colvarvalue::check_types(cvcs[i]->value(),
+ if (!(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function)) && (colvarvalue::check_types(cvcs[i]->value(),
cvcs[0]->value())) ) {
cvm::error("ERROR: you are definining this collective variable "
"by using components of different types. "
"You must use the same type in order to "
"sum them together.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
active_cvc_square_norm = 0.;
for (i = 0; i < cvcs.size(); i++) {
active_cvc_square_norm += cvcs[i]->sup_coeff * cvcs[i]->sup_coeff;
}
// at this point, the colvar's type is defined
f.type(value());
- f_accumulated.type(value());
x_old.type(value());
v_fdiff.type(value());
v_reported.type(value());
fj.type(value());
ft.type(value());
ft_reported.type(value());
f_old.type(value());
f_old.reset();
x_restart.type(value());
after_restart = false;
reset_bias_force();
+ get_keyval(conf, "timeStepFactor", time_step_factor, 1);
+ if (time_step_factor < 0) {
+ cvm::error("Error: timeStepFactor must be positive.\n");
+ return COLVARS_ERROR;
+ }
+ if (time_step_factor != 1) {
+ enable(f_cv_multiple_ts);
+ }
+
// TODO use here information from the CVCs' own natural boundaries
error_code |= init_grid_parameters(conf);
- get_keyval(conf, "timeStepFactor", time_step_factor, 1);
-
error_code |= init_extended_Lagrangian(conf);
error_code |= init_output_flags(conf);
- // Start in active state by default
+ // Now that the children are defined we can solve dependencies
enable(f_cv_active);
- // Make sure dependency side-effects are correct
- refresh_deps();
if (cvm::b_analysis)
parse_analysis(conf);
if (cvm::debug())
cvm::log("Done initializing collective variable \""+this->name+"\".\n");
return error_code;
}
+#ifdef LEPTON
+int colvar::init_custom_function(std::string const &conf)
+{
+ std::string expr;
+ std::vector<Lepton::ParsedExpression> pexprs;
+ Lepton::ParsedExpression pexpr;
+ size_t pos = 0; // current position in config string
+ double *ref;
+
+ if (!key_lookup(conf, "customFunction", &expr, &pos)) {
+ return COLVARS_OK;
+ }
+
+ enable(f_cv_custom_function);
+ cvm::log("This colvar uses a custom function.\n");
+
+ do {
+ if (cvm::debug())
+ cvm::log("Parsing expression \"" + expr + "\".\n");
+ try {
+ pexpr = Lepton::Parser::parse(expr);
+ pexprs.push_back(pexpr);
+ }
+ catch (...) {
+ cvm::error("Error parsing expression \"" + expr + "\".\n", INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+
+ try {
+ value_evaluators.push_back(
+ new Lepton::CompiledExpression(pexpr.createCompiledExpression()));
+ // Define variables for cvc values
+ // Stored in order: expr1, cvc1, cvc2, expr2, cvc1...
+ for (size_t i = 0; i < cvcs.size(); i++) {
+ for (size_t j = 0; j < cvcs[i]->value().size(); j++) {
+ std::string vn = cvcs[i]->name +
+ (cvcs[i]->value().size() > 1 ? cvm::to_str(j+1) : "");
+ try {
+ ref =&value_evaluators.back()->getVariableReference(vn);
+ }
+ catch (...) { // Variable is absent from expression
+ // To keep the same workflow, we use a pointer to a double here
+ // that will receive CVC values - even though none was allocated by Lepton
+ ref = &dev_null;
+ if (cvm::debug())
+ cvm::log("Variable " + vn + " is absent from expression \"" + expr + "\".\n");
+ }
+ value_eval_var_refs.push_back(ref);
+ }
+ }
+ }
+ catch (...) {
+ cvm::error("Error compiling expression \"" + expr + "\".\n", INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+ } while (key_lookup(conf, "customFunction", &expr, &pos));
+
+
+ // Now define derivative with respect to each scalar sub-component
+ for (size_t i = 0; i < cvcs.size(); i++) {
+ for (size_t j = 0; j < cvcs[i]->value().size(); j++) {
+ std::string vn = cvcs[i]->name +
+ (cvcs[i]->value().size() > 1 ? cvm::to_str(j+1) : "");
+ // Element ordering: we want the
+ // gradient vector of derivatives of all elements of the colvar
+ // wrt to a given element of a cvc ([i][j])
+ for (size_t c = 0; c < pexprs.size(); c++) {
+ gradient_evaluators.push_back(
+ new Lepton::CompiledExpression(pexprs[c].differentiate(vn).createCompiledExpression()));
+ // and record the refs to each variable in those expressions
+ for (size_t k = 0; k < cvcs.size(); k++) {
+ for (size_t l = 0; l < cvcs[k]->value().size(); l++) {
+ std::string vvn = cvcs[k]->name +
+ (cvcs[k]->value().size() > 1 ? cvm::to_str(l+1) : "");
+ try {
+ ref = &gradient_evaluators.back()->getVariableReference(vvn);
+ }
+ catch (...) { // Variable is absent from derivative
+ // To keep the same workflow, we use a pointer to a double here
+ // that will receive CVC values - even though none was allocated by Lepton
+ if (cvm::debug())
+ cvm::log("Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n");
+ ref = &dev_null;
+ }
+ grad_eval_var_refs.push_back(ref);
+ }
+ }
+ }
+ }
+ }
+
+
+ if (value_evaluators.size() == 0) {
+ cvm::error("Error: no custom function defined.\n", INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+
+ std::string type_str;
+ bool b_type_specified = get_keyval(conf, "customFunctionType",
+ type_str, "scalar", parse_silent);
+ x.type(colvarvalue::type_notset);
+ int t;
+ for (t = 0; t < colvarvalue::type_all; t++) {
+ if (type_str == colvarvalue::type_keyword(colvarvalue::Type(t))) {
+ x.type(colvarvalue::Type(t));
+ break;
+ }
+ }
+ if (x.type() == colvarvalue::type_notset) {
+ cvm::error("Could not parse custom colvar type.", INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+
+ // Guess type based on number of expressions
+ if (!b_type_specified) {
+ if (value_evaluators.size() == 1) {
+ x.type(colvarvalue::type_scalar);
+ } else {
+ x.type(colvarvalue::type_vector);
+ }
+ }
+
+ if (x.type() == colvarvalue::type_vector) {
+ x.vector1d_value.resize(value_evaluators.size());
+ }
+
+ x_reported.type(x);
+ cvm::log(std::string("Expecting colvar value of type ")
+ + colvarvalue::type_desc(x.type())
+ + (x.type()==colvarvalue::type_vector ? " of size " + cvm::to_str(x.size()) : "")
+ + ".\n");
+
+ if (x.size() != value_evaluators.size()) {
+ cvm::error("Error: based on custom function type, expected "
+ + cvm::to_str(x.size()) + " scalar expressions, but "
+ + cvm::to_str(value_evaluators.size() + " were found.\n"));
+ return INPUT_ERROR;
+ }
+
+ return COLVARS_OK;
+}
+
+#else
+
+int colvar::init_custom_function(std::string const &conf)
+{
+ return COLVARS_OK;
+}
+
+#endif // #ifdef LEPTON
+
+
int colvar::init_grid_parameters(std::string const &conf)
{
colvarmodule *cv = cvm::main();
get_keyval(conf, "width", width, 1.0);
if (width <= 0.0) {
cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR);
return INPUT_ERROR;
}
lower_boundary.type(value());
upper_boundary.type(value());
upper_wall.type(value());
set_enabled(f_cv_scalar, (value().type() == colvarvalue::type_scalar));
if (is_enabled(f_cv_scalar)) {
if (get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary)) {
enable(f_cv_lower_boundary);
}
std::string lw_conf, uw_conf;
if (get_keyval(conf, "lowerWallConstant", lower_wall_k, 0.0, parse_silent)) {
cvm::log("Warning: lowerWallConstant and lowerWall are deprecated, "
"please define a harmonicWalls bias instead.\n");
lower_wall.type(value());
get_keyval(conf, "lowerWall", lower_wall, lower_boundary);
lw_conf = std::string("\n\
lowerWallConstant "+cvm::to_str(lower_wall_k*width*width)+"\n\
lowerWalls "+cvm::to_str(lower_wall)+"\n");
}
if (get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary)) {
enable(f_cv_upper_boundary);
}
if (get_keyval(conf, "upperWallConstant", upper_wall_k, 0.0, parse_silent)) {
cvm::log("Warning: upperWallConstant and upperWall are deprecated, "
"please define a harmonicWalls bias instead.\n");
upper_wall.type(value());
get_keyval(conf, "upperWall", upper_wall, upper_boundary);
uw_conf = std::string("\n\
upperWallConstant "+cvm::to_str(upper_wall_k*width*width)+"\n\
upperWalls "+cvm::to_str(upper_wall)+"\n");
}
if (lw_conf.size() && uw_conf.size()) {
if (lower_wall >= upper_wall) {
cvm::error("Error: the upper wall, "+
cvm::to_str(upper_wall)+
", is not higher than the lower wall, "+
cvm::to_str(lower_wall)+".\n",
INPUT_ERROR);
return INPUT_ERROR;
}
}
if (lw_conf.size() || uw_conf.size()) {
cvm::log("Generating a new harmonicWalls bias for compatibility purposes.\n");
std::string const walls_conf("\n\
harmonicWalls {\n\
name "+this->name+"w\n\
- colvars "+this->name+"\n"+lw_conf+uw_conf+
+ colvars "+this->name+"\n"+lw_conf+uw_conf+"\
+ timeStepFactor "+cvm::to_str(time_step_factor)+"\n"+
"}\n");
cv->append_new_config(walls_conf);
}
}
if (is_enabled(f_cv_lower_boundary)) {
get_keyval(conf, "hardLowerBoundary", hard_lower_boundary, false);
}
if (is_enabled(f_cv_upper_boundary)) {
get_keyval(conf, "hardUpperBoundary", hard_upper_boundary, false);
}
// consistency checks for boundaries and walls
if (is_enabled(f_cv_lower_boundary) && is_enabled(f_cv_upper_boundary)) {
if (lower_boundary >= upper_boundary) {
cvm::error("Error: the upper boundary, "+
cvm::to_str(upper_boundary)+
", is not higher than the lower boundary, "+
cvm::to_str(lower_boundary)+".\n",
INPUT_ERROR);
return INPUT_ERROR;
}
}
get_keyval(conf, "expandBoundaries", expand_boundaries, false);
if (expand_boundaries && periodic_boundaries()) {
cvm::error("Error: trying to expand boundaries that already "
"cover a whole period of a periodic colvar.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
if (expand_boundaries && hard_lower_boundary && hard_upper_boundary) {
cvm::error("Error: inconsistent configuration "
"(trying to expand boundaries with both "
"hardLowerBoundary and hardUpperBoundary enabled).\n",
INPUT_ERROR);
return INPUT_ERROR;
}
return COLVARS_OK;
}
int colvar::init_extended_Lagrangian(std::string const &conf)
{
- bool b_extended_Lagrangian;
- get_keyval(conf, "extendedLagrangian", b_extended_Lagrangian, false);
+ get_keyval_feature(this, conf, "extendedLagrangian", f_cv_extended_Lagrangian, false);
- if (b_extended_Lagrangian) {
+ if (is_enabled(f_cv_extended_Lagrangian)) {
cvm::real temp, tolerance, period;
cvm::log("Enabling the extended Lagrangian term for colvar \""+
this->name+"\".\n");
- enable(f_cv_extended_Lagrangian);
-
xr.type(value());
vr.type(value());
fr.type(value());
const bool found = get_keyval(conf, "extendedTemp", temp, cvm::temperature());
if (temp <= 0.0) {
if (found)
cvm::error("Error: \"extendedTemp\" must be positive.\n", INPUT_ERROR);
else
cvm::error("Error: a positive temperature must be provided, either "
"by enabling a thermostat, or through \"extendedTemp\".\n",
INPUT_ERROR);
return INPUT_ERROR;
}
get_keyval(conf, "extendedFluctuation", tolerance);
if (tolerance <= 0.0) {
cvm::error("Error: \"extendedFluctuation\" must be positive.\n", INPUT_ERROR);
return INPUT_ERROR;
}
ext_force_k = cvm::boltzmann() * temp / (tolerance * tolerance);
- cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " kcal/mol/U^2");
+ cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " [E]/U^2");
get_keyval(conf, "extendedTimeConstant", period, 200.0);
if (period <= 0.0) {
cvm::error("Error: \"extendedTimeConstant\" must be positive.\n", INPUT_ERROR);
}
ext_mass = (cvm::boltzmann() * temp * period * period)
/ (4.0 * PI * PI * tolerance * tolerance);
- cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " kcal/mol/(U/fs)^2 (U: colvar unit)");
+ cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " [E]/(U/fs)^2 (U: colvar unit)");
{
bool b_output_energy;
get_keyval(conf, "outputEnergy", b_output_energy, false);
if (b_output_energy) {
enable(f_cv_output_energy);
}
}
get_keyval(conf, "extendedLangevinDamping", ext_gamma, 1.0);
if (ext_gamma < 0.0) {
cvm::error("Error: \"extendedLangevinDamping\" may not be negative.\n", INPUT_ERROR);
return INPUT_ERROR;
}
if (ext_gamma != 0.0) {
enable(f_cv_Langevin);
- ext_gamma *= 1.0e-3; // convert from ps-1 to fs-1
- ext_sigma = std::sqrt(2.0 * cvm::boltzmann() * temp * ext_gamma * ext_mass / cvm::dt());
+ ext_gamma *= 1.0e-3; // correct as long as input is required in ps-1 and cvm::dt() is in fs
+ // Adjust Langevin sigma for slow time step if time_step_factor != 1
+ ext_sigma = std::sqrt(2.0 * cvm::boltzmann() * temp * ext_gamma * ext_mass / (cvm::dt() * cvm::real(time_step_factor)));
}
}
return COLVARS_OK;
}
int colvar::init_output_flags(std::string const &conf)
{
{
bool b_output_value;
get_keyval(conf, "outputValue", b_output_value, true);
if (b_output_value) {
enable(f_cv_output_value);
}
}
{
bool b_output_velocity;
get_keyval(conf, "outputVelocity", b_output_velocity, false);
if (b_output_velocity) {
enable(f_cv_output_velocity);
}
}
{
bool temp;
if (get_keyval(conf, "outputSystemForce", temp, false, colvarparse::parse_silent)) {
cvm::error("Option outputSystemForce is deprecated: only outputTotalForce is supported instead.\n"
"The two are NOT identical: see http://colvars.github.io/totalforce.html.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
get_keyval_feature(this, conf, "outputTotalForce", f_cv_output_total_force, false);
get_keyval_feature(this, conf, "outputAppliedForce", f_cv_output_applied_force, false);
get_keyval_feature(this, conf, "subtractAppliedForce", f_cv_subtract_applied_force, false);
return COLVARS_OK;
}
// read the configuration and set up corresponding instances, for
// each type of component implemented
template<typename def_class_name> int colvar::init_components_type(std::string const &conf,
char const *def_desc,
char const *def_config_key)
{
size_t def_count = 0;
std::string def_conf = "";
size_t pos = 0;
while ( this->key_lookup(conf,
def_config_key,
- def_conf,
- pos) ) {
+ &def_conf,
+ &pos) ) {
if (!def_conf.size()) continue;
cvm::log("Initializing "
"a new \""+std::string(def_config_key)+"\" component"+
(cvm::debug() ? ", with configuration:\n"+def_conf
: ".\n"));
cvm::increase_depth();
cvc *cvcp = new def_class_name(def_conf);
if (cvcp != NULL) {
cvcs.push_back(cvcp);
cvcp->check_keywords(def_conf, def_config_key);
if (cvm::get_error()) {
cvm::error("Error: in setting up component \""+
std::string(def_config_key)+"\".\n", INPUT_ERROR);
return INPUT_ERROR;
}
cvm::decrease_depth();
} else {
cvm::error("Error: in allocating component \""+
std::string(def_config_key)+"\".\n",
MEMORY_ERROR);
return MEMORY_ERROR;
}
if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) {
if ( (cvcp->function_type != std::string("distance_z")) &&
(cvcp->function_type != std::string("dihedral")) &&
+ (cvcp->function_type != std::string("polar_phi")) &&
(cvcp->function_type != std::string("spin_angle")) ) {
cvm::error("Error: invalid use of period and/or "
"wrapAround in a \""+
std::string(def_config_key)+
"\" component.\n"+
"Period: "+cvm::to_str(cvcp->period) +
" wrapAround: "+cvm::to_str(cvcp->wrap_center),
INPUT_ERROR);
return INPUT_ERROR;
}
}
if ( ! cvcs.back()->name.size()) {
std::ostringstream s;
s << def_config_key << std::setfill('0') << std::setw(4) << ++def_count;
cvcs.back()->name = s.str();
/* pad cvc number for correct ordering when sorting by name */
}
cvcs.back()->setup();
if (cvm::debug()) {
cvm::log("Done initializing a \""+
std::string(def_config_key)+
"\" component"+
(cvm::debug() ?
", named \""+cvcs.back()->name+"\""
: "")+".\n");
}
def_conf = "";
if (cvm::debug()) {
cvm::log("Parsed "+cvm::to_str(cvcs.size())+
" components at this time.\n");
}
}
return COLVARS_OK;
}
int colvar::init_components(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= init_components_type<distance>(conf, "distance", "distance");
error_code |= init_components_type<distance_vec>(conf, "distance vector", "distanceVec");
error_code |= init_components_type<cartesian>(conf, "Cartesian coordinates", "cartesian");
error_code |= init_components_type<distance_dir>(conf, "distance vector "
"direction", "distanceDir");
error_code |= init_components_type<distance_z>(conf, "distance projection "
"on an axis", "distanceZ");
error_code |= init_components_type<distance_xy>(conf, "distance projection "
"on a plane", "distanceXY");
+ error_code |= init_components_type<polar_theta>(conf, "spherical polar angle theta",
+ "polarTheta");
+ error_code |= init_components_type<polar_phi>(conf, "spherical azimuthal angle phi",
+ "polarPhi");
error_code |= init_components_type<distance_inv>(conf, "average distance "
"weighted by inverse power", "distanceInv");
error_code |= init_components_type<distance_pairs>(conf, "N1xN2-long vector "
"of pairwise distances", "distancePairs");
error_code |= init_components_type<coordnum>(conf, "coordination "
"number", "coordNum");
error_code |= init_components_type<selfcoordnum>(conf, "self-coordination "
"number", "selfCoordNum");
error_code |= init_components_type<groupcoordnum>(conf, "group-coordination "
"number", "groupCoord");
error_code |= init_components_type<angle>(conf, "angle", "angle");
error_code |= init_components_type<dipole_angle>(conf, "dipole angle", "dipoleAngle");
error_code |= init_components_type<dihedral>(conf, "dihedral", "dihedral");
error_code |= init_components_type<h_bond>(conf, "hydrogen bond", "hBond");
error_code |= init_components_type<alpha_angles>(conf, "alpha helix", "alpha");
error_code |= init_components_type<dihedPC>(conf, "dihedral "
"principal component", "dihedralPC");
error_code |= init_components_type<orientation>(conf, "orientation", "orientation");
error_code |= init_components_type<orientation_angle>(conf, "orientation "
"angle", "orientationAngle");
error_code |= init_components_type<orientation_proj>(conf, "orientation "
"projection", "orientationProj");
error_code |= init_components_type<tilt>(conf, "tilt", "tilt");
error_code |= init_components_type<spin_angle>(conf, "spin angle", "spinAngle");
error_code |= init_components_type<rmsd>(conf, "RMSD", "rmsd");
error_code |= init_components_type<gyration>(conf, "radius of "
"gyration", "gyration");
error_code |= init_components_type<inertia>(conf, "moment of "
"inertia", "inertia");
error_code |= init_components_type<inertia_z>(conf, "moment of inertia around an axis", "inertiaZ");
error_code |= init_components_type<eigenvector>(conf, "eigenvector", "eigenvector");
if (!cvcs.size() || (error_code != COLVARS_OK)) {
cvm::error("Error: no valid components were provided "
"for this collective variable.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
n_active_cvcs = cvcs.size();
cvm::log("All components initialized.\n");
// Store list of children cvcs for dependency checking purposes
for (size_t i = 0; i < cvcs.size(); i++) {
add_child(cvcs[i]);
}
return COLVARS_OK;
}
-int colvar::refresh_deps()
+void colvar::do_feature_side_effects(int id)
{
- // If enabled features are changed upstream, the features below should be refreshed
- if (is_enabled(f_cv_total_force_calc)) {
- cvm::request_total_force();
- }
- if (is_enabled(f_cv_collect_gradient) && atom_ids.size() == 0) {
- build_atom_list();
+ switch (id) {
+ case f_cv_total_force_calc:
+ cvm::request_total_force();
+ break;
+ case f_cv_collect_gradient:
+ if (atom_ids.size() == 0) {
+ build_atom_list();
+ }
+ break;
}
- return COLVARS_OK;
}
void colvar::build_atom_list(void)
{
// If atomic gradients are requested, build full list of atom ids from all cvcs
std::list<int> temp_id_list;
for (size_t i = 0; i < cvcs.size(); i++) {
for (size_t j = 0; j < cvcs[i]->atom_groups.size(); j++) {
cvm::atom_group &ag = *(cvcs[i]->atom_groups[j]);
for (size_t k = 0; k < ag.size(); k++) {
temp_id_list.push_back(ag[k].id);
}
}
}
temp_id_list.sort();
temp_id_list.unique();
// atom_ids = std::vector<int> (temp_id_list.begin(), temp_id_list.end());
unsigned int id_i = 0;
std::list<int>::iterator li;
for (li = temp_id_list.begin(); li != temp_id_list.end(); ++li) {
atom_ids[id_i] = *li;
id_i++;
}
temp_id_list.clear();
atomic_gradients.resize(atom_ids.size());
if (atom_ids.size()) {
if (cvm::debug())
cvm::log("Colvar: created atom list with " + cvm::to_str(atom_ids.size()) + " atoms.\n");
} else {
cvm::log("Warning: colvar components communicated no atom IDs.\n");
}
}
int colvar::parse_analysis(std::string const &conf)
{
// if (cvm::debug())
// cvm::log ("Parsing analysis flags for collective variable \""+
// this->name+"\".\n");
runave_length = 0;
bool b_runave = false;
if (get_keyval(conf, "runAve", b_runave) && b_runave) {
enable(f_cv_runave);
get_keyval(conf, "runAveLength", runave_length, 1000);
get_keyval(conf, "runAveStride", runave_stride, 1);
if ((cvm::restart_out_freq % runave_stride) != 0) {
cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", INPUT_ERROR);
}
- std::string runave_outfile;
get_keyval(conf, "runAveOutputFile", runave_outfile,
std::string(cvm::output_prefix()+"."+
this->name+".runave.traj"));
size_t const this_cv_width = x.output_width(cvm::cv_width);
- cvm::backup_file(runave_outfile.c_str());
- runave_os.open(runave_outfile.c_str());
- runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2)
- << " "
- << cvm::wrap_string("running average", this_cv_width)
- << " "
- << cvm::wrap_string("running stddev", this_cv_width)
- << "\n";
+ cvm::proxy->backup_file(runave_outfile);
+ runave_os = cvm::proxy->output_stream(runave_outfile);
+ *runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2)
+ << " "
+ << cvm::wrap_string("running average", this_cv_width)
+ << " "
+ << cvm::wrap_string("running stddev", this_cv_width)
+ << "\n";
}
acf_length = 0;
bool b_acf = false;
if (get_keyval(conf, "corrFunc", b_acf) && b_acf) {
enable(f_cv_corrfunc);
std::string acf_colvar_name;
get_keyval(conf, "corrFuncWithColvar", acf_colvar_name, this->name);
if (acf_colvar_name == this->name) {
cvm::log("Calculating auto-correlation function.\n");
} else {
cvm::log("Calculating correlation function with \""+
this->name+"\".\n");
}
std::string acf_type_str;
get_keyval(conf, "corrFuncType", acf_type_str, to_lower_cppstr(std::string("velocity")));
if (acf_type_str == to_lower_cppstr(std::string("coordinate"))) {
acf_type = acf_coor;
} else if (acf_type_str == to_lower_cppstr(std::string("velocity"))) {
acf_type = acf_vel;
enable(f_cv_fdiff_velocity);
if (acf_colvar_name.size())
(cvm::colvar_by_name(acf_colvar_name))->enable(f_cv_fdiff_velocity);
} else if (acf_type_str == to_lower_cppstr(std::string("coordinate_p2"))) {
acf_type = acf_p2coor;
} else {
cvm::log("Unknown type of correlation function, \""+
acf_type_str+"\".\n");
cvm::set_error_bits(INPUT_ERROR);
}
get_keyval(conf, "corrFuncOffset", acf_offset, 0);
get_keyval(conf, "corrFuncLength", acf_length, 1000);
get_keyval(conf, "corrFuncStride", acf_stride, 1);
if ((cvm::restart_out_freq % acf_stride) != 0) {
cvm::error("Error: corrFuncStride must be commensurate with the restart frequency.\n", INPUT_ERROR);
}
get_keyval(conf, "corrFuncNormalize", acf_normalize, true);
get_keyval(conf, "corrFuncOutputFile", acf_outfile,
std::string(cvm::output_prefix()+"."+this->name+
".corrfunc.dat"));
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
void colvar::setup() {
// loop over all components to reset masses of all groups
for (size_t i = 0; i < cvcs.size(); i++) {
for (size_t ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
cvm::atom_group &atoms = *(cvcs[i]->atom_groups[ig]);
atoms.setup();
atoms.reset_mass(name,i,ig);
atoms.read_positions();
}
}
}
colvar::~colvar()
{
+ // There is no need to call free_children_deps() here
+ // because the children are cvcs and will be deleted
+ // just below
+
// Clear references to this colvar's cvcs as children
// for dependency purposes
remove_all_children();
for (std::vector<cvc *>::reverse_iterator ci = cvcs.rbegin();
ci != cvcs.rend();
++ci) {
// clear all children of this cvc (i.e. its atom groups)
// because the cvc base class destructor can't do it early enough
// and we don't want to have each cvc derived class do it separately
(*ci)->remove_all_children();
delete *ci;
}
// remove reference to this colvar from the CVM
colvarmodule *cv = cvm::main();
for (std::vector<colvar *>::iterator cvi = cv->variables()->begin();
cvi != cv->variables()->end();
++cvi) {
if ( *cvi == this) {
cv->variables()->erase(cvi);
break;
}
}
+
+#ifdef LEPTON
+ for (std::vector<Lepton::CompiledExpression *>::iterator cei = value_evaluators.begin();
+ cei != value_evaluators.end();
+ ++cei) {
+ if (*cei != NULL) delete (*cei);
+ }
+ value_evaluators.clear();
+
+ for (std::vector<Lepton::CompiledExpression *>::iterator gei = gradient_evaluators.begin();
+ gei != gradient_evaluators.end();
+ ++gei) {
+ if (*gei != NULL) delete (*gei);
+ }
+ gradient_evaluators.clear();
+#endif
}
// ******************** CALC FUNCTIONS ********************
// Default schedule (everything is serialized)
int colvar::calc()
{
// Note: if anything is added here, it should be added also in the SMP block of calc_colvars()
int error_code = COLVARS_OK;
if (is_enabled(f_cv_active)) {
error_code |= update_cvc_flags();
if (error_code != COLVARS_OK) return error_code;
error_code |= calc_cvcs();
if (error_code != COLVARS_OK) return error_code;
error_code |= collect_cvc_data();
}
return error_code;
}
int colvar::calc_cvcs(int first_cvc, size_t num_cvcs)
{
int error_code = COLVARS_OK;
if (cvm::debug())
cvm::log("Calculating colvar \""+this->name+"\", components "+
cvm::to_str(first_cvc)+" through "+cvm::to_str(first_cvc+num_cvcs)+".\n");
error_code |= check_cvc_range(first_cvc, num_cvcs);
if (error_code != COLVARS_OK) {
return error_code;
}
if (cvm::step_relative() > 0) {
// Total force depends on Jacobian derivative from previous timestep
error_code |= calc_cvc_total_force(first_cvc, num_cvcs);
}
// atom coordinates are updated by the next line
error_code |= calc_cvc_values(first_cvc, num_cvcs);
error_code |= calc_cvc_gradients(first_cvc, num_cvcs);
error_code |= calc_cvc_Jacobians(first_cvc, num_cvcs);
if (cvm::debug())
cvm::log("Done calculating colvar \""+this->name+"\".\n");
return error_code;
}
int colvar::collect_cvc_data()
{
if (cvm::debug())
cvm::log("Calculating colvar \""+this->name+"\"'s properties.\n");
int error_code = COLVARS_OK;
if (cvm::step_relative() > 0) {
// Total force depends on Jacobian derivative from previous timestep
error_code |= collect_cvc_total_forces();
}
error_code |= collect_cvc_values();
error_code |= collect_cvc_gradients();
error_code |= collect_cvc_Jacobians();
error_code |= calc_colvar_properties();
if (cvm::debug())
cvm::log("Done calculating colvar \""+this->name+"\"'s properties.\n");
return error_code;
}
int colvar::check_cvc_range(int first_cvc, size_t num_cvcs)
{
if ((first_cvc < 0) || (first_cvc >= ((int) cvcs.size()))) {
cvm::error("Error: trying to address a component outside the "
"range defined for colvar \""+name+"\".\n", BUG_ERROR);
return BUG_ERROR;
}
return COLVARS_OK;
}
int colvar::calc_cvc_values(int first_cvc, size_t num_cvcs)
{
size_t const cvc_max_count = num_cvcs ? num_cvcs : num_active_cvcs();
size_t i, cvc_count;
// calculate the value of the colvar
if (cvm::debug())
cvm::log("Calculating colvar components.\n");
// First, calculate component values
cvm::increase_depth();
for (i = first_cvc, cvc_count = 0;
(i < cvcs.size()) && (cvc_count < cvc_max_count);
i++) {
if (!cvcs[i]->is_enabled()) continue;
cvc_count++;
(cvcs[i])->read_data();
(cvcs[i])->calc_value();
if (cvm::debug())
cvm::log("Colvar component no. "+cvm::to_str(i+1)+
" within colvar \""+this->name+"\" has value "+
cvm::to_str((cvcs[i])->value(),
cvm::cv_width, cvm::cv_prec)+".\n");
}
cvm::decrease_depth();
return COLVARS_OK;
}
int colvar::collect_cvc_values()
{
x.reset();
- size_t i;
// combine them appropriately, using either a scripted function or a polynomial
if (is_enabled(f_cv_scripted)) {
// cvcs combined by user script
int res = cvm::proxy->run_colvar_callback(scripted_function, sorted_cvc_values, x);
if (res == COLVARS_NOT_IMPLEMENTED) {
cvm::error("Scripted colvars are not implemented.");
return COLVARS_NOT_IMPLEMENTED;
}
if (res != COLVARS_OK) {
cvm::error("Error running scripted colvar");
return COLVARS_OK;
}
+
+#ifdef LEPTON
+ } else if (is_enabled(f_cv_custom_function)) {
+
+ size_t l = 0; // index in the vector of variable references
+
+ for (size_t i = 0; i < x.size(); i++) {
+ // Fill Lepton evaluator variables with CVC values, serialized into scalars
+ for (size_t j = 0; j < cvcs.size(); j++) {
+ for (size_t k = 0; k < cvcs[j]->value().size(); k++) {
+ *(value_eval_var_refs[l++]) = cvcs[j]->value()[k];
+ }
+ }
+ x[i] = value_evaluators[i]->evaluate();
+ }
+#endif
+
} else if (x.type() == colvarvalue::type_scalar) {
// polynomial combination allowed
- for (i = 0; i < cvcs.size(); i++) {
+ for (size_t i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
x += (cvcs[i])->sup_coeff *
( ((cvcs[i])->sup_np != 1) ?
std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np) :
(cvcs[i])->value().real_value );
}
} else {
- for (i = 0; i < cvcs.size(); i++) {
+ for (size_t i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
x += (cvcs[i])->sup_coeff * (cvcs[i])->value();
}
}
if (cvm::debug())
cvm::log("Colvar \""+this->name+"\" has value "+
cvm::to_str(x, cvm::cv_width, cvm::cv_prec)+".\n");
if (after_restart) {
if (cvm::proxy->simulation_running()) {
cvm::real const jump2 = dist2(x, x_restart) / (width*width);
if (jump2 > 0.25) {
cvm::error("Error: the calculated value of colvar \""+name+
"\":\n"+cvm::to_str(x)+"\n differs greatly from the value "
"last read from the state file:\n"+cvm::to_str(x_restart)+
"\nPossible causes are changes in configuration, "
"wrong state file, or how PBC wrapping is handled.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
}
}
return COLVARS_OK;
}
int colvar::calc_cvc_gradients(int first_cvc, size_t num_cvcs)
{
size_t const cvc_max_count = num_cvcs ? num_cvcs : num_active_cvcs();
size_t i, cvc_count;
if (cvm::debug())
cvm::log("Calculating gradients of colvar \""+this->name+"\".\n");
// calculate the gradients of each component
cvm::increase_depth();
for (i = first_cvc, cvc_count = 0;
(i < cvcs.size()) && (cvc_count < cvc_max_count);
i++) {
if (!cvcs[i]->is_enabled()) continue;
cvc_count++;
if ((cvcs[i])->is_enabled(f_cvc_gradient)) {
(cvcs[i])->calc_gradients();
// if requested, propagate (via chain rule) the gradients above
// to the atoms used to define the roto-translation
- // This could be integrated in the CVC base class
- for (size_t ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
- if (cvcs[i]->atom_groups[ig]->b_fit_gradients)
- cvcs[i]->atom_groups[ig]->calc_fit_gradients();
-
- if (cvcs[i]->is_enabled(f_cvc_debug_gradient)) {
- cvm::log("Debugging gradients for " + cvcs[i]->description);
- cvcs[i]->debug_gradients(cvcs[i]->atom_groups[ig]);
- }
- }
+ (cvcs[i])->calc_fit_gradients();
+ if ((cvcs[i])->is_enabled(f_cvc_debug_gradient))
+ (cvcs[i])->debug_gradients();
}
cvm::decrease_depth();
if (cvm::debug())
cvm::log("Done calculating gradients of colvar \""+this->name+"\".\n");
}
return COLVARS_OK;
}
int colvar::collect_cvc_gradients()
{
size_t i;
if (is_enabled(f_cv_collect_gradient)) {
-
- if (is_enabled(f_cv_scripted)) {
- cvm::error("Collecting atomic gradients is not implemented for "
- "scripted colvars.", COLVARS_NOT_IMPLEMENTED);
- return COLVARS_NOT_IMPLEMENTED;
- }
-
// Collect the atomic gradients inside colvar object
for (unsigned int a = 0; a < atomic_gradients.size(); a++) {
atomic_gradients[a].reset();
}
for (i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
// Coefficient: d(a * x^n) = a * n * x^(n-1) * dx
cvm::real coeff = (cvcs[i])->sup_coeff * cvm::real((cvcs[i])->sup_np) *
std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np-1);
for (size_t j = 0; j < cvcs[i]->atom_groups.size(); j++) {
cvm::atom_group &ag = *(cvcs[i]->atom_groups[j]);
// If necessary, apply inverse rotation to get atomic
// gradient in the laboratory frame
if (ag.b_rotate) {
cvm::rotation const rot_inv = ag.rot.inverse();
for (size_t k = 0; k < ag.size(); k++) {
size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
ag[k].id) - atom_ids.begin();
atomic_gradients[a] += coeff * rot_inv.rotate(ag[k].grad);
}
} else {
for (size_t k = 0; k < ag.size(); k++) {
size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
ag[k].id) - atom_ids.begin();
atomic_gradients[a] += coeff * ag[k].grad;
}
}
}
}
}
return COLVARS_OK;
}
int colvar::calc_cvc_total_force(int first_cvc, size_t num_cvcs)
{
size_t const cvc_max_count = num_cvcs ? num_cvcs : num_active_cvcs();
size_t i, cvc_count;
if (is_enabled(f_cv_total_force_calc)) {
if (cvm::debug())
cvm::log("Calculating total force of colvar \""+this->name+"\".\n");
cvm::increase_depth();
for (i = first_cvc, cvc_count = 0;
(i < cvcs.size()) && (cvc_count < cvc_max_count);
i++) {
if (!cvcs[i]->is_enabled()) continue;
cvc_count++;
(cvcs[i])->calc_force_invgrads();
}
cvm::decrease_depth();
if (cvm::debug())
cvm::log("Done calculating total force of colvar \""+this->name+"\".\n");
}
return COLVARS_OK;
}
int colvar::collect_cvc_total_forces()
{
if (is_enabled(f_cv_total_force_calc)) {
ft.reset();
if (cvm::step_relative() > 0) {
// get from the cvcs the total forces from the PREVIOUS step
for (size_t i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
if (cvm::debug())
cvm::log("Colvar component no. "+cvm::to_str(i+1)+
" within colvar \""+this->name+"\" has total force "+
cvm::to_str((cvcs[i])->total_force(),
cvm::cv_width, cvm::cv_prec)+".\n");
// linear combination is assumed
ft += (cvcs[i])->total_force() * (cvcs[i])->sup_coeff / active_cvc_square_norm;
}
}
if (!is_enabled(f_cv_hide_Jacobian)) {
// add the Jacobian force to the total force, and don't apply any silent
// correction internally: biases such as colvarbias_abf will handle it
ft += fj;
}
}
return COLVARS_OK;
}
int colvar::calc_cvc_Jacobians(int first_cvc, size_t num_cvcs)
{
size_t const cvc_max_count = num_cvcs ? num_cvcs : num_active_cvcs();
if (is_enabled(f_cv_Jacobian)) {
cvm::increase_depth();
size_t i, cvc_count;
for (i = first_cvc, cvc_count = 0;
(i < cvcs.size()) && (cvc_count < cvc_max_count);
i++) {
if (!cvcs[i]->is_enabled()) continue;
cvc_count++;
(cvcs[i])->calc_Jacobian_derivative();
}
cvm::decrease_depth();
}
return COLVARS_OK;
}
int colvar::collect_cvc_Jacobians()
{
if (is_enabled(f_cv_Jacobian)) {
fj.reset();
for (size_t i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
if (cvm::debug())
cvm::log("Colvar component no. "+cvm::to_str(i+1)+
" within colvar \""+this->name+"\" has Jacobian derivative"+
cvm::to_str((cvcs[i])->Jacobian_derivative(),
cvm::cv_width, cvm::cv_prec)+".\n");
// linear combination is assumed
fj += (cvcs[i])->Jacobian_derivative() * (cvcs[i])->sup_coeff / active_cvc_square_norm;
}
fj *= cvm::boltzmann() * cvm::temperature();
}
return COLVARS_OK;
}
int colvar::calc_colvar_properties()
{
if (is_enabled(f_cv_fdiff_velocity)) {
// calculate the velocity by finite differences
if (cvm::step_relative() == 0)
x_old = x;
else {
v_fdiff = fdiff_velocity(x_old, x);
v_reported = v_fdiff;
}
}
if (is_enabled(f_cv_extended_Lagrangian)) {
// initialize the restraint center in the first step to the value
// just calculated from the cvcs
if (cvm::step_relative() == 0 && !after_restart) {
xr = x;
vr.reset(); // (already 0; added for clarity)
}
// report the restraint center as "value"
x_reported = xr;
v_reported = vr;
// the "total force" with the extended Lagrangian is
// calculated in update_forces_energy() below
} else {
if (is_enabled(f_cv_subtract_applied_force)) {
// correct the total force only if it has been measured
// TODO add a specific test instead of relying on sq norm
if (ft.norm2() > 0.0) {
ft -= f_old;
}
}
x_reported = x;
ft_reported = ft;
}
// At the end of the first update after a restart, we can reset the flag
after_restart = false;
return COLVARS_OK;
}
cvm::real colvar::update_forces_energy()
{
if (cvm::debug())
cvm::log("Updating colvar \""+this->name+"\".\n");
// set to zero the applied force
f.type(value());
f.reset();
+ fr.reset();
+
+ // If we are not active at this timestep, that's all we have to do
+ // return with energy == zero
+ if (!is_enabled(f_cv_active)) return 0.;
// add the biases' force, which at this point should already have
// been summed over each bias using this colvar
f += fb;
if (is_enabled(f_cv_Jacobian)) {
// the instantaneous Jacobian force was not included in the reported total force;
// instead, it is subtracted from the applied force (silent Jacobian correction)
// This requires the Jacobian term for the *current* timestep
if (is_enabled(f_cv_hide_Jacobian))
f -= fj;
}
// At this point f is the force f from external biases that will be applied to the
// extended variable if there is one
if (is_enabled(f_cv_extended_Lagrangian)) {
if (cvm::debug()) {
cvm::log("Updating extended-Lagrangian degree of freedom.\n");
}
- cvm::real dt = cvm::dt();
+ if (prev_timestep > -1) {
+ // Keep track of slow timestep to integrate MTS colvars
+ // the colvar checks the interval after waking up twice
+ int n_timesteps = cvm::step_relative() - prev_timestep;
+ if (n_timesteps != 0 && n_timesteps != time_step_factor) {
+ cvm::error("Error: extended-Lagrangian " + description + " has timeStepFactor " +
+ cvm::to_str(time_step_factor) + ", but was activated after " + cvm::to_str(n_timesteps) +
+ " steps at timestep " + cvm::to_str(cvm::step_absolute()) + " (relative step: " +
+ cvm::to_str(cvm::step_relative()) + ").\n" +
+ "Make sure that this colvar is requested by biases at multiples of timeStepFactor.\n");
+ return 0.;
+ }
+ }
+ prev_timestep = cvm::step_relative();
+
+ // Integrate with slow timestep (if time_step_factor != 1)
+ cvm::real dt = cvm::dt() * cvm::real(time_step_factor);
+
colvarvalue f_ext(fr.type()); // force acting on the extended variable
f_ext.reset();
// the total force is applied to the fictitious mass, while the
// atoms only feel the harmonic force + wall force
// fr: bias force on extended variable (without harmonic spring), for output in trajectory
// f_ext: total force on extended variable (including harmonic spring)
// f: - initially, external biasing force
// - after this code block, colvar force to be applied to atomic coordinates
// ie. spring force (fb_actual will be added just below)
fr = f;
- f_ext = f + (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x);
- f = (-0.5 * ext_force_k) * this->dist2_rgrad(xr, x);
-
- if (is_enabled(f_cv_subtract_applied_force)) {
- // Report a "system" force without the biases on this colvar
- // that is, just the spring force
- ft_reported = (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x);
- } else {
- // The total force acting on the extended variable is f_ext
- // This will be used in the next timestep
- ft_reported = f_ext;
- }
+ // External force has been scaled for a 1-timestep impulse, scale it back because we will
+ // integrate it with the colvar's own timestep factor
+ f_ext = f / cvm::real(time_step_factor);
+ f_ext += (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x);
+ f = (-0.5 * ext_force_k) * this->dist2_rgrad(xr, x);
+ // Coupling force is a slow force, to be applied to atomic coords impulse-style
+ f *= cvm::real(time_step_factor);
+
+ // The total force acting on the extended variable is f_ext
+ // This will be used in the next timestep
+ ft_reported = f_ext;
// leapfrog: starting from x_i, f_i, v_(i-1/2)
vr += (0.5 * dt) * f_ext / ext_mass;
// Because of leapfrog, kinetic energy at time i is approximate
kinetic_energy = 0.5 * ext_mass * vr * vr;
potential_energy = 0.5 * ext_force_k * this->dist2(xr, x);
// leap to v_(i+1/2)
if (is_enabled(f_cv_Langevin)) {
vr -= dt * ext_gamma * vr;
colvarvalue rnd(x);
rnd.set_random();
vr += dt * ext_sigma * rnd / ext_mass;
}
vr += (0.5 * dt) * f_ext / ext_mass;
xr += dt * vr;
xr.apply_constraints();
if (this->is_enabled(f_cv_periodic)) this->wrap(xr);
}
- // Now adding the force on the actual colvar (for those biases who
+ // Now adding the force on the actual colvar (for those biases that
// bypass the extended Lagrangian mass)
f += fb_actual;
- // Store force to be applied, possibly summed over several timesteps
- f_accumulated += f;
-
if (is_enabled(f_cv_fdiff_velocity)) {
// set it for the next step
x_old = x;
}
if (is_enabled(f_cv_subtract_applied_force)) {
f_old = f;
}
if (cvm::debug())
cvm::log("Done updating colvar \""+this->name+"\".\n");
return (potential_energy + kinetic_energy);
}
void colvar::communicate_forces()
{
size_t i;
if (cvm::debug()) {
cvm::log("Communicating forces from colvar \""+this->name+"\".\n");
- cvm::log("Force to be applied: " + cvm::to_str(f_accumulated) + "\n");
+ cvm::log("Force to be applied: " + cvm::to_str(f) + "\n");
}
if (is_enabled(f_cv_scripted)) {
std::vector<cvm::matrix2d<cvm::real> > func_grads;
func_grads.reserve(cvcs.size());
for (i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
func_grads.push_back(cvm::matrix2d<cvm::real> (x.size(),
cvcs[i]->value().size()));
}
int res = cvm::proxy->run_colvar_gradient_callback(scripted_function, sorted_cvc_values, func_grads);
if (res != COLVARS_OK) {
if (res == COLVARS_NOT_IMPLEMENTED) {
cvm::error("Colvar gradient scripts are not implemented.", COLVARS_NOT_IMPLEMENTED);
} else {
cvm::error("Error running colvar gradient script");
}
return;
}
int grad_index = 0; // index in the scripted gradients, to account for some components being disabled
for (i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
// cvc force is colvar force times colvar/cvc Jacobian
// (vector-matrix product)
- (cvcs[i])->apply_force(colvarvalue(f_accumulated.as_vector() * func_grads[grad_index++],
+ (cvcs[i])->apply_force(colvarvalue(f.as_vector() * func_grads[grad_index++],
cvcs[i]->value().type()));
}
+
+#ifdef LEPTON
+ } else if (is_enabled(f_cv_custom_function)) {
+
+ size_t r = 0; // index in the vector of variable references
+ size_t e = 0; // index of the gradient evaluator
+
+ for (size_t i = 0; i < cvcs.size(); i++) { // gradient with respect to cvc i
+ cvm::matrix2d<cvm::real> jacobian (x.size(), cvcs[i]->value().size());
+ for (size_t j = 0; j < cvcs[i]->value().size(); j++) { // j-th element
+ for (size_t c = 0; c < x.size(); c++) { // derivative of scalar element c of the colvarvalue
+
+ // Feed cvc values to the evaluator
+ for (size_t k = 0; k < cvcs.size(); k++) { //
+ for (size_t l = 0; l < cvcs[k]->value().size(); l++) {
+ *(grad_eval_var_refs[r++]) = cvcs[k]->value()[l];
+ }
+ }
+ jacobian[c][j] = gradient_evaluators[e++]->evaluate();
+ }
+ }
+ // cvc force is colvar force times colvar/cvc Jacobian
+ // (vector-matrix product)
+ (cvcs[i])->apply_force(colvarvalue(f.as_vector() * jacobian,
+ cvcs[i]->value().type()));
+ }
+#endif
+
} else if (x.type() == colvarvalue::type_scalar) {
for (i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
- (cvcs[i])->apply_force(f_accumulated * (cvcs[i])->sup_coeff *
+ (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff *
cvm::real((cvcs[i])->sup_np) *
(std::pow((cvcs[i])->value().real_value,
(cvcs[i])->sup_np-1)) );
}
} else {
for (i = 0; i < cvcs.size(); i++) {
if (!cvcs[i]->is_enabled()) continue;
- (cvcs[i])->apply_force(f_accumulated * (cvcs[i])->sup_coeff);
+ (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff);
}
}
- // Accumulated forces have been applied, impulse-style
- // Reset to start accumulating again
- f_accumulated.reset();
-
if (cvm::debug())
cvm::log("Done communicating forces from colvar \""+this->name+"\".\n");
}
int colvar::set_cvc_flags(std::vector<bool> const &flags)
{
if (flags.size() != cvcs.size()) {
cvm::error("ERROR: Wrong number of CVC flags provided.");
return COLVARS_ERROR;
}
// We cannot enable or disable cvcs in the middle of a timestep or colvar evaluation sequence
// so we store the flags that will be enforced at the next call to calc()
cvc_flags = flags;
return COLVARS_OK;
}
int colvar::update_cvc_flags()
{
// Update the enabled/disabled status of cvcs if necessary
if (cvc_flags.size()) {
n_active_cvcs = 0;
active_cvc_square_norm = 0.;
for (size_t i = 0; i < cvcs.size(); i++) {
cvcs[i]->set_enabled(f_cvc_active, cvc_flags[i]);
if (cvcs[i]->is_enabled()) {
n_active_cvcs++;
active_cvc_square_norm += cvcs[i]->sup_coeff * cvcs[i]->sup_coeff;
}
}
if (!n_active_cvcs) {
cvm::error("ERROR: All CVCs are disabled for colvar " + this->name +"\n");
return COLVARS_ERROR;
}
- cvc_flags.resize(0);
+ cvc_flags.clear();
}
return COLVARS_OK;
}
// ******************** METRIC FUNCTIONS ********************
// Use the metrics defined by \link cvc \endlink objects
bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const
{
if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) {
cvm::log("Error: checking periodicity for collective variable \""+this->name+"\" "
"requires lower and upper boundaries to be defined.\n");
cvm::set_error_bits(INPUT_ERROR);
}
if (period > 0.0) {
if ( ((std::sqrt(this->dist2(lb, ub))) / this->width)
< 1.0E-10 ) {
return true;
}
}
return false;
}
bool colvar::periodic_boundaries() const
{
if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) {
cvm::log("Error: checking periodicity for collective variable \""+this->name+"\" "
"requires lower and upper boundaries to be defined.\n");
}
return periodic_boundaries(lower_boundary, upper_boundary);
}
cvm::real colvar::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
if (is_enabled(f_cv_homogeneous)) {
return (cvcs[0])->dist2(x1, x2);
} else {
return x1.dist2(x2);
}
}
colvarvalue colvar::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
if (is_enabled(f_cv_homogeneous)) {
return (cvcs[0])->dist2_lgrad(x1, x2);
} else {
return x1.dist2_grad(x2);
}
}
colvarvalue colvar::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
if (is_enabled(f_cv_homogeneous)) {
return (cvcs[0])->dist2_rgrad(x1, x2);
} else {
return x2.dist2_grad(x1);
}
}
void colvar::wrap(colvarvalue &x) const
{
if (is_enabled(f_cv_homogeneous)) {
(cvcs[0])->wrap(x);
}
return;
}
// ******************** INPUT FUNCTIONS ********************
std::istream & colvar::read_restart(std::istream &is)
{
size_t const start_pos = is.tellg();
std::string conf;
if ( !(is >> colvarparse::read_block("colvar", conf)) ) {
// this is not a colvar block
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
{
std::string check_name = "";
if ( (get_keyval(conf, "name", check_name,
std::string(""), colvarparse::parse_silent)) &&
(check_name != name) ) {
cvm::error("Error: the state file does not match the "
"configuration file, at colvar \""+name+"\".\n");
}
if (check_name.size() == 0) {
cvm::error("Error: Collective variable in the "
"restart file without any identifier.\n");
}
}
if ( !(get_keyval(conf, "x", x, x, colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain "
"the value of the colvar \""+
name+"\" .\n");
} else {
cvm::log("Restarting collective variable \""+name+"\" from value: "+
cvm::to_str(x)+"\n");
x_restart = x;
after_restart = true;
}
if (is_enabled(f_cv_extended_Lagrangian)) {
if ( !(get_keyval(conf, "extended_x", xr,
colvarvalue(x.type()), colvarparse::parse_silent)) &&
!(get_keyval(conf, "extended_v", vr,
colvarvalue(x.type()), colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain "
"\"extended_x\" or \"extended_v\" for the colvar \""+
name+"\", but you requested \"extendedLagrangian\".\n");
}
x_reported = xr;
} else {
x_reported = x;
}
if (is_enabled(f_cv_output_velocity)) {
if ( !(get_keyval(conf, "v", v_fdiff,
colvarvalue(x.type()), colvarparse::parse_silent)) ) {
cvm::log("Error: restart file does not contain "
"the velocity for the colvar \""+
name+"\", but you requested \"outputVelocity\".\n");
}
if (is_enabled(f_cv_extended_Lagrangian)) {
v_reported = vr;
} else {
v_reported = v_fdiff;
}
}
return is;
}
std::istream & colvar::read_traj(std::istream &is)
{
size_t const start_pos = is.tellg();
if (is_enabled(f_cv_output_value)) {
if (!(is >> x)) {
cvm::log("Error: in reading the value of colvar \""+
this->name+"\" from trajectory.\n");
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
if (is_enabled(f_cv_extended_Lagrangian)) {
is >> xr;
x_reported = xr;
} else {
x_reported = x;
}
}
if (is_enabled(f_cv_output_velocity)) {
is >> v_fdiff;
if (is_enabled(f_cv_extended_Lagrangian)) {
is >> vr;
v_reported = vr;
} else {
v_reported = v_fdiff;
}
}
if (is_enabled(f_cv_output_total_force)) {
is >> ft;
ft_reported = ft;
}
if (is_enabled(f_cv_output_applied_force)) {
is >> f;
}
return is;
}
// ******************** OUTPUT FUNCTIONS ********************
std::ostream & colvar::write_restart(std::ostream &os) {
os << "colvar {\n"
<< " name " << name << "\n"
<< " x "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< x << "\n";
if (is_enabled(f_cv_output_velocity)) {
os << " v "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< v_reported << "\n";
}
if (is_enabled(f_cv_extended_Lagrangian)) {
os << " extended_x "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< xr << "\n"
<< " extended_v "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< vr << "\n";
}
os << "}\n\n";
return os;
}
std::ostream & colvar::write_traj_label(std::ostream & os)
{
size_t const this_cv_width = x.output_width(cvm::cv_width);
os << " ";
if (is_enabled(f_cv_output_value)) {
os << " "
<< cvm::wrap_string(this->name, this_cv_width);
if (is_enabled(f_cv_extended_Lagrangian)) {
// extended DOF
os << " r_"
<< cvm::wrap_string(this->name, this_cv_width-2);
}
}
if (is_enabled(f_cv_output_velocity)) {
os << " v_"
<< cvm::wrap_string(this->name, this_cv_width-2);
if (is_enabled(f_cv_extended_Lagrangian)) {
// extended DOF
os << " vr_"
<< cvm::wrap_string(this->name, this_cv_width-3);
}
}
if (is_enabled(f_cv_output_energy)) {
os << " Ep_"
<< cvm::wrap_string(this->name, this_cv_width-3)
<< " Ek_"
<< cvm::wrap_string(this->name, this_cv_width-3);
}
if (is_enabled(f_cv_output_total_force)) {
os << " ft_"
<< cvm::wrap_string(this->name, this_cv_width-3);
}
if (is_enabled(f_cv_output_applied_force)) {
os << " fa_"
<< cvm::wrap_string(this->name, this_cv_width-3);
}
return os;
}
std::ostream & colvar::write_traj(std::ostream &os)
{
os << " ";
if (is_enabled(f_cv_output_value)) {
if (is_enabled(f_cv_extended_Lagrangian)) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< x;
}
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< x_reported;
}
if (is_enabled(f_cv_output_velocity)) {
if (is_enabled(f_cv_extended_Lagrangian)) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< v_fdiff;
}
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< v_reported;
}
if (is_enabled(f_cv_output_energy)) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< potential_energy
<< " "
<< kinetic_energy;
}
if (is_enabled(f_cv_output_total_force)) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< ft_reported;
}
if (is_enabled(f_cv_output_applied_force)) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< applied_force();
}
return os;
}
int colvar::write_output_files()
{
if (cvm::b_analysis) {
if (acf.size()) {
cvm::log("Writing acf to file \""+acf_outfile+"\".\n");
cvm::backup_file(acf_outfile.c_str());
- cvm::ofstream acf_os(acf_outfile.c_str());
- if (! acf_os.is_open()) {
- cvm::error("Cannot open file \""+acf_outfile+"\".\n", FILE_ERROR);
- }
- write_acf(acf_os);
- acf_os.close();
+ std::ostream *acf_os = cvm::proxy->output_stream(acf_outfile);
+ if (!acf_os) return cvm::get_error();
+ write_acf(*acf_os);
+ cvm::proxy->close_output_stream(acf_outfile);
}
- if (runave_os.is_open()) {
- runave_os.close();
+ if (runave_os) {
+ cvm::proxy->close_output_stream(runave_outfile);
+ runave_os = NULL;
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
// ******************** ANALYSIS FUNCTIONS ********************
void colvar::analyze()
{
if (is_enabled(f_cv_runave)) {
calc_runave();
}
if (is_enabled(f_cv_corrfunc)) {
calc_acf();
}
}
inline void history_add_value(size_t const &history_length,
std::list<colvarvalue> &history,
colvarvalue const &new_value)
{
history.push_front(new_value);
if (history.size() > history_length)
history.pop_back();
}
inline void history_incr(std::list< std::list<colvarvalue> > &history,
std::list< std::list<colvarvalue> >::iterator &history_p)
{
if ((++history_p) == history.end())
history_p = history.begin();
}
int colvar::calc_acf()
{
// using here an acf_stride-long list of vectors for either
// coordinates(acf_x_history) or velocities (acf_v_history); each vector can
// contain up to acf_length values, which are contiguous in memory
// representation but separated by acf_stride in the time series;
// the pointer to each vector is changed at every step
if (acf_x_history.empty() && acf_v_history.empty()) {
// first-step operations
colvar *cfcv = (acf_colvar_name.size() ?
cvm::colvar_by_name(acf_colvar_name) :
this);
if (colvarvalue::check_types(cfcv->value(), value())) {
cvm::error("Error: correlation function between \""+cfcv->name+
"\" and \""+this->name+"\" cannot be calculated, "
"because their value types are different.\n",
INPUT_ERROR);
}
acf_nframes = 0;
cvm::log("Colvar \""+this->name+"\": initializing ACF calculation.\n");
if (acf.size() < acf_length+1)
acf.resize(acf_length+1, 0.0);
size_t i;
switch (acf_type) {
case acf_vel:
// allocate space for the velocities history
for (i = 0; i < acf_stride; i++) {
acf_v_history.push_back(std::list<colvarvalue>());
}
acf_v_history_p = acf_v_history.begin();
break;
case acf_coor:
case acf_p2coor:
// allocate space for the coordinates history
for (i = 0; i < acf_stride; i++) {
acf_x_history.push_back(std::list<colvarvalue>());
}
acf_x_history_p = acf_x_history.begin();
break;
default:
break;
}
} else {
colvar *cfcv = (acf_colvar_name.size() ?
cvm::colvar_by_name(acf_colvar_name) :
this);
switch (acf_type) {
case acf_vel:
if (is_enabled(f_cv_fdiff_velocity)) {
// calc() should do this already, but this only happens in a
// simulation; better do it again in case a trajectory is
// being read
v_reported = v_fdiff = fdiff_velocity(x_old, cfcv->value());
}
calc_vel_acf((*acf_v_history_p), cfcv->velocity());
// store this value in the history
history_add_value(acf_length+acf_offset, *acf_v_history_p, cfcv->velocity());
// if stride is larger than one, cycle among different histories
history_incr(acf_v_history, acf_v_history_p);
break;
case acf_coor:
calc_coor_acf((*acf_x_history_p), cfcv->value());
history_add_value(acf_length+acf_offset, *acf_x_history_p, cfcv->value());
history_incr(acf_x_history, acf_x_history_p);
break;
case acf_p2coor:
calc_p2coor_acf((*acf_x_history_p), cfcv->value());
history_add_value(acf_length+acf_offset, *acf_x_history_p, cfcv->value());
history_incr(acf_x_history, acf_x_history_p);
break;
default:
break;
}
}
if (is_enabled(f_cv_fdiff_velocity)) {
// set it for the next step
x_old = x;
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvar::calc_vel_acf(std::list<colvarvalue> &v_list,
colvarvalue const &v)
{
// loop over stored velocities and add to the ACF, but only the
// length is sufficient to hold an entire row of ACF values
if (v_list.size() >= acf_length+acf_offset) {
std::list<colvarvalue>::iterator vs_i = v_list.begin();
std::vector<cvm::real>::iterator acf_i = acf.begin();
for (size_t i = 0; i < acf_offset; i++)
++vs_i;
// current vel with itself
*(acf_i) += v.norm2();
++acf_i;
// inner products of previous velocities with current (acf_i and
// vs_i are updated)
colvarvalue::inner_opt(v, vs_i, v_list.end(), acf_i);
acf_nframes++;
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
void colvar::calc_coor_acf(std::list<colvarvalue> &x_list,
colvarvalue const &x)
{
// same as above but for coordinates
if (x_list.size() >= acf_length+acf_offset) {
std::list<colvarvalue>::iterator xs_i = x_list.begin();
std::vector<cvm::real>::iterator acf_i = acf.begin();
for (size_t i = 0; i < acf_offset; i++)
++xs_i;
*(acf_i++) += x.norm2();
colvarvalue::inner_opt(x, xs_i, x_list.end(), acf_i);
acf_nframes++;
}
}
void colvar::calc_p2coor_acf(std::list<colvarvalue> &x_list,
colvarvalue const &x)
{
// same as above but with second order Legendre polynomial instead
// of just the scalar product
if (x_list.size() >= acf_length+acf_offset) {
std::list<colvarvalue>::iterator xs_i = x_list.begin();
std::vector<cvm::real>::iterator acf_i = acf.begin();
for (size_t i = 0; i < acf_offset; i++)
++xs_i;
// value of P2(0) = 1
*(acf_i++) += 1.0;
colvarvalue::p2leg_opt(x, xs_i, x_list.end(), acf_i);
acf_nframes++;
}
}
void colvar::write_acf(std::ostream &os)
{
if (!acf_nframes)
cvm::log("Warning: ACF was not calculated (insufficient frames).\n");
os.setf(std::ios::scientific, std::ios::floatfield);
os << "# Autocorrelation function for collective variable \""
<< this->name << "\"\n";
// one frame is used for normalization, the statistical sample is
// hence decreased
os << "# nframes = " << (acf_normalize ?
acf_nframes - 1 :
acf_nframes) << "\n";
cvm::real const acf_norm = acf.front() / cvm::real(acf_nframes);
std::vector<cvm::real>::iterator acf_i;
size_t it = acf_offset;
for (acf_i = acf.begin(); acf_i != acf.end(); ++acf_i) {
os << std::setw(cvm::it_width) << acf_stride * (it++) << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< ( acf_normalize ?
(*acf_i)/(acf_norm * cvm::real(acf_nframes)) :
(*acf_i)/(cvm::real(acf_nframes)) ) << "\n";
}
}
void colvar::calc_runave()
{
if (x_history.empty()) {
runave.type(value().type());
runave.reset();
// first-step operations
if (cvm::debug())
cvm::log("Colvar \""+this->name+
"\": initializing running average calculation.\n");
acf_nframes = 0;
x_history.push_back(std::list<colvarvalue>());
x_history_p = x_history.begin();
} else {
if ( (cvm::step_relative() % runave_stride) == 0) {
if ((*x_history_p).size() >= runave_length-1) {
runave = x;
std::list<colvarvalue>::iterator xs_i;
for (xs_i = (*x_history_p).begin();
xs_i != (*x_history_p).end(); ++xs_i) {
runave += (*xs_i);
}
runave *= 1.0 / cvm::real(runave_length);
runave.apply_constraints();
runave_variance = 0.0;
runave_variance += this->dist2(x, runave);
for (xs_i = (*x_history_p).begin();
xs_i != (*x_history_p).end(); ++xs_i) {
runave_variance += this->dist2(x, (*xs_i));
}
runave_variance *= 1.0 / cvm::real(runave_length-1);
- runave_os << std::setw(cvm::it_width) << cvm::step_relative()
- << " "
- << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
- << runave << " "
- << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
- << std::sqrt(runave_variance) << "\n";
+ *runave_os << std::setw(cvm::it_width) << cvm::step_relative()
+ << " "
+ << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
+ << runave << " "
+ << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
+ << std::sqrt(runave_variance) << "\n";
}
history_add_value(runave_length, *x_history_p, x);
}
}
}
// Static members
std::vector<colvardeps::feature *> colvar::cv_features;
diff --git a/lib/colvars/colvar.h b/lib/colvars/colvar.h
index 0cbda450b..6113e1678 100644
--- a/lib/colvars/colvar.h
+++ b/lib/colvars/colvar.h
@@ -1,624 +1,641 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVAR_H
#define COLVAR_H
#include <iostream>
#include <iomanip>
#include <cmath>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvardeps.h"
+#ifdef LEPTON
+#include "Lepton.h" // for runtime custom expressions
+#endif
/// \brief A collective variable (main class); to be defined, it needs
/// at least one object of a derived class of colvar::cvc; it
/// calculates and returns a \link colvarvalue \endlink object
///
/// This class parses the configuration, defines the behaviour and
/// stores the value (\link colvar::x \endlink) and all related data
/// of a collective variable. How the value is calculated is defined
/// in \link colvar::cvc \endlink and its derived classes. The
/// \link colvar \endlink object contains pointers to multiple \link
/// colvar::cvc \endlink derived objects, which can be combined
/// together into one collective variable. This makes possible to
/// implement new collective variables at runtime based on the
/// existing ones. Currently, this possibility is limited to a
/// polynomial, using the coefficients cvc::sup_coeff and the
/// exponents cvc::sup_np. In case of non-scalar variables,
/// only exponents equal to 1 are accepted.
///
/// Please note that most of its members are \link colvarvalue
/// \endlink objects, i.e. they can handle different data types
/// together, and must all be set to the same type of colvar::value()
/// before using them together in assignments or other operations; this is usually done
/// automatically in the constructor. If you add a new member of
/// \link colvarvalue \endlink type, you should also add its
/// initialization line in the \link colvar \endlink constructor.
class colvar : public colvarparse, public colvardeps {
public:
/// Name
std::string name;
/// \brief Current value (previously set by calc() or by read_traj())
colvarvalue const & value() const;
/// \brief Current actual value (not extended DOF)
colvarvalue const & actual_value() const;
/// \brief Current velocity (previously set by calc() or by read_traj())
colvarvalue const & velocity() const;
/// \brief Current total force (previously obtained from calc() or
/// read_traj()). Note: this is calculated using the atomic forces
/// from the last simulation step.
///
/// Total atom forces are read from the MD program, the total force
/// acting on the collective variable is calculated summing those
/// from all colvar components, the bias and walls forces are
/// subtracted.
colvarvalue const & total_force() const;
/// \brief Typical fluctuation amplitude for this collective
/// variable (e.g. local width of a free energy basin)
///
/// In metadynamics calculations, \link colvarbias_meta \endlink,
/// this value is used to calculate the width of a gaussian. In ABF
/// calculations, \link colvarbias_abf \endlink, it is used to
/// calculate the grid spacing in the direction of this collective
/// variable.
cvm::real width;
/// \brief Implementation of the feature list for colvar
static std::vector<feature *> cv_features;
/// \brief Implementation of the feature list accessor for colvar
std::vector<feature *> &features() {
return cv_features;
}
- int refresh_deps();
+ /// Implements possible actions to be carried out
+ /// when a given feature is enabled
+ /// This overloads the base function in colvardeps
+ void do_feature_side_effects(int id);
/// List of biases that depend on this colvar
std::vector<colvarbias *> biases;
protected:
/*
extended:
H = H_{0} + \sum_{i} 1/2*\lambda*(S_i(x(t))-s_i(t))^2 \\
+ \sum_{i} 1/2*m_i*(ds_i(t)/dt)^2 \\
+ \sum_{t'<t} W * exp(-1/2*\sum_{i} (s_i(t')-s_i(t))^2/(\delta{}s_i)^2) \\
+ \sum_{w} (\sum_{i}c_{w,i}s_i(t) - D_w)^M/(\Sigma_w)^M
normal:
H = H_{0} + \sum_{t'<t} W * exp(-1/2*\sum_{i} (S_i(x(t'))-S_i(x(t)))^2/(\delta{}S_i)^2) \\
+ \sum_{w} (\sum_{i}c_{w,i}S_i(t) - D_w)^M/(\Sigma_w)^M
output:
H = H_{0} (only output S(x), no forces)
Here:
S(x(t)) = x
s(t) = xr
DS = Ds = delta
*/
/// Value of the colvar
colvarvalue x;
// TODO: implement functionality to treat these
// /// Vector of individual values from CVCs
// colvarvalue x_cvc;
// /// Jacobian matrix of individual values from CVCs
// colvarvalue dx_cvc;
/// Cached reported value (x may be manipulated)
colvarvalue x_reported;
/// Finite-difference velocity
colvarvalue v_fdiff;
inline colvarvalue fdiff_velocity(colvarvalue const &xold,
colvarvalue const &xnew)
{
// using the gradient of the square distance to calculate the
// velocity (non-scalar variables automatically taken into
// account)
cvm::real dt = cvm::dt();
return ( ( (dt > 0.0) ? (1.0/dt) : 1.0 ) *
0.5 * dist2_lgrad(xnew, xold) );
}
/// Cached reported velocity
colvarvalue v_reported;
// Options for extended_lagrangian
/// Restraint center
colvarvalue xr;
/// Velocity of the restraint center
colvarvalue vr;
/// Mass of the restraint center
cvm::real ext_mass;
/// Restraint force constant
cvm::real ext_force_k;
/// Friction coefficient for Langevin extended dynamics
cvm::real ext_gamma;
/// Amplitude of Gaussian white noise for Langevin extended dynamics
cvm::real ext_sigma;
/// \brief Harmonic restraint force
colvarvalue fr;
/// \brief Jacobian force, when Jacobian_force is enabled
colvarvalue fj;
/// Cached reported total force
colvarvalue ft_reported;
public:
/// \brief Bias force; reset_bias_force() should be called before
/// the biases are updated
colvarvalue fb;
/// \brief Bias force to the actual value (only useful with extended Lagrangian)
colvarvalue fb_actual;
/// \brief Total \em applied force; fr (if extended_lagrangian
/// is defined), fb (if biases are applied) and the walls' forces
/// (if defined) contribute to it
colvarvalue f;
/// Applied force at the previous step (to be subtracted from total force if needed)
colvarvalue f_old;
/// \brief Total force, as derived from the atomic trajectory;
/// should equal the system force plus \link f \endlink
colvarvalue ft;
/// Period, if this variable is periodic
cvm::real period;
/// \brief Expand the boundaries of multiples of width, to keep the
/// value always within range
bool expand_boundaries;
/// \brief Location of the lower boundary
colvarvalue lower_boundary;
/// \brief Location of the lower wall
colvarvalue lower_wall;
/// \brief Force constant for the lower boundary potential (|x-xb|^2)
cvm::real lower_wall_k;
/// \brief Whether this colvar has a hard lower boundary
bool hard_lower_boundary;
/// \brief Location of the upper boundary
colvarvalue upper_boundary;
/// \brief Location of the upper wall
colvarvalue upper_wall;
/// \brief Force constant for the upper boundary potential (|x-xb|^2)
cvm::real upper_wall_k;
/// \brief Whether this colvar has a hard upper boundary
bool hard_upper_boundary;
/// \brief Is the interval defined by the two boundaries periodic?
bool periodic_boundaries() const;
/// \brief Is the interval defined by the two boundaries periodic?
bool periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const;
/// Constructor
colvar();
/// Main init function
int init(std::string const &conf);
/// Parse the CVC configuration and allocate their data
int init_components(std::string const &conf);
+ /// Parse parameters for custom function with Lepton
+ int init_custom_function(std::string const &conf);
+
/// Init defaults for grid options
int init_grid_parameters(std::string const &conf);
/// Init extended Lagrangian parameters
int init_extended_Lagrangian(std::string const &conf);
/// Init output flags
int init_output_flags(std::string const &conf);
private:
/// Parse the CVC configuration for all components of a certain type
template<typename def_class_name> int init_components_type(std::string const &conf,
char const *def_desc,
char const *def_config_key);
public:
/// Get ready for a run and re-initialize internal data if needed
void setup();
/// Destructor
~colvar();
/// \brief Calculate the colvar's value and related quantities
int calc();
/// \brief Calculate a subset of the colvar components (CVCs) currently active
/// (default: all active CVCs)
/// Note: both arguments refer to the sect of *active* CVCs, not all CVCs
int calc_cvcs(int first = 0, size_t num_cvcs = 0);
/// Ensure that the selected range of CVCs is consistent
int check_cvc_range(int first_cvc, size_t num_cvcs);
/// \brief Calculate the values of the given subset of CVCs
int calc_cvc_values(int first, size_t num_cvcs);
/// \brief Same as \link colvar::calc_cvc_values \endlink but for gradients
int calc_cvc_gradients(int first, size_t num_cvcs);
/// \brief Same as \link colvar::calc_cvc_values \endlink but for total forces
int calc_cvc_total_force(int first, size_t num_cvcs);
/// \brief Same as \link colvar::calc_cvc_values \endlink but for Jacobian derivatives/forces
int calc_cvc_Jacobians(int first, size_t num_cvcs);
/// \brief Collect quantities from CVCs and update aggregated data for the colvar
int collect_cvc_data();
/// \brief Collect the values of the CVCs
int collect_cvc_values();
/// \brief Same as \link colvar::collect_cvc_values \endlink but for gradients
int collect_cvc_gradients();
/// \brief Same as \link colvar::collect_cvc_values \endlink but for total forces
int collect_cvc_total_forces();
/// \brief Same as \link colvar::collect_cvc_values \endlink but for Jacobian derivatives/forces
int collect_cvc_Jacobians();
/// \brief Calculate the quantities associated to the colvar (but not to the CVCs)
int calc_colvar_properties();
/// Get the current applied force
inline colvarvalue const applied_force() const
{
if (is_enabled(f_cv_extended_Lagrangian)) {
return fr;
}
return f;
}
/// Set the total biasing force to zero
void reset_bias_force();
/// Add to the total force from biases
void add_bias_force(colvarvalue const &force);
/// Apply a force to the actual value (only meaningful with extended Lagrangian)
void add_bias_force_actual_value(colvarvalue const &force);
/// \brief Collect all forces on this colvar, integrate internal
/// equations of motion of internal degrees of freedom; see also
/// colvar::communicate_forces()
/// return colvar energy if extended Lagrandian active
cvm::real update_forces_energy();
/// \brief Communicate forces (previously calculated in
/// colvar::update()) to the external degrees of freedom
void communicate_forces();
/// \brief Enables and disables individual CVCs based on flags
int set_cvc_flags(std::vector<bool> const &flags);
/// \brief Updates the flags in the CVC objects, and their number
int update_cvc_flags();
protected:
/// \brief Number of CVC objects with an active flag
size_t n_active_cvcs;
/// Sum of square coefficients for active cvcs
cvm::real active_cvc_square_norm;
- /// Time step multiplier (for coarse-time-step colvars)
- /// Colvar will only be calculated at those times; biases may ignore the information and
- /// always update their own forces (which is typically inexpensive) especially if
- /// they rely on other colvars. In this case, the colvar will accumulate forces applied between
- /// colvar updates. Alternately they may use it to calculate "impulse" biasing
- /// forces at longer intervals. Impulse forces must be multiplied by the timestep factor.
- int time_step_factor;
-
- /// Biasing force collected between updates, to be applied at next update for coarse-time-step colvars
- colvarvalue f_accumulated;
+ /// \brief Absolute timestep number when this colvar was last updated
+ int prev_timestep;
public:
/// \brief Return the number of CVC objects with an active flag (as set by update_cvc_flags)
inline size_t num_active_cvcs() const { return n_active_cvcs; }
- /// \brief returns time_step_factor
- inline int get_time_step_factor() const {return time_step_factor;}
-
/// \brief Use the internal metrics (as from \link cvc
/// \endlink objects) to calculate square distances and gradients
///
/// Handles correctly symmetries and periodic boundary conditions
cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Use the internal metrics (as from \link cvc
/// \endlink objects) to calculate square distances and gradients
///
/// Handles correctly symmetries and periodic boundary conditions
colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Use the internal metrics (as from \link cvc
/// \endlink objects) to calculate square distances and gradients
///
/// Handles correctly symmetries and periodic boundary conditions
colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Use the internal metrics (as from \link cvc
/// \endlink objects) to wrap a value into a standard interval
///
/// Handles correctly symmetries and periodic boundary conditions
void wrap(colvarvalue &x) const;
/// Read the analysis tasks
int parse_analysis(std::string const &conf);
/// Perform analysis tasks
void analyze();
/// Read the value from a collective variable trajectory file
std::istream & read_traj(std::istream &is);
/// Output formatted values to the trajectory file
std::ostream & write_traj(std::ostream &os);
/// Write a label to the trajectory file (comment line)
std::ostream & write_traj_label(std::ostream &os);
/// Read the collective variable from a restart file
std::istream & read_restart(std::istream &is);
/// Write the collective variable to a restart file
std::ostream & write_restart(std::ostream &os);
/// Write output files (if defined, e.g. in analysis mode)
int write_output_files();
protected:
/// Previous value (to calculate velocities during analysis)
colvarvalue x_old;
/// Value read from the most recent state file (if any)
colvarvalue x_restart;
/// True if a state file was just read
bool after_restart;
/// Time series of values and velocities used in correlation
/// functions
std::list< std::list<colvarvalue> > acf_x_history, acf_v_history;
/// Time series of values and velocities used in correlation
/// functions (pointers)x
std::list< std::list<colvarvalue> >::iterator acf_x_history_p, acf_v_history_p;
/// Time series of values and velocities used in running averages
std::list< std::list<colvarvalue> > x_history;
/// Time series of values and velocities used in correlation
/// functions (pointers)x
std::list< std::list<colvarvalue> >::iterator x_history_p;
/// \brief Collective variable with which the correlation is
/// calculated (default: itself)
std::string acf_colvar_name;
/// Length of autocorrelation function (ACF)
size_t acf_length;
/// After how many steps the ACF starts
size_t acf_offset;
/// How many timesteps separate two ACF values
size_t acf_stride;
/// Number of frames for each ACF point
size_t acf_nframes;
/// Normalize the ACF to a maximum value of 1?
bool acf_normalize;
/// ACF values
std::vector<cvm::real> acf;
/// Name of the file to write the ACF
std::string acf_outfile;
/// Type of autocorrelation function (ACF)
enum acf_type_e {
/// Unset type
acf_notset,
/// Velocity ACF, scalar product between v(0) and v(t)
acf_vel,
/// Coordinate ACF, scalar product between x(0) and x(t)
acf_coor,
/// \brief Coordinate ACF, second order Legendre polynomial
/// between x(0) and x(t) (does not work with scalar numbers)
acf_p2coor
};
/// Type of autocorrelation function (ACF)
acf_type_e acf_type;
/// \brief Velocity ACF, scalar product between v(0) and v(t)
int calc_vel_acf(std::list<colvarvalue> &v_history,
colvarvalue const &v);
/// \brief Coordinate ACF, scalar product between x(0) and x(t)
/// (does not work with scalar numbers)
void calc_coor_acf(std::list<colvarvalue> &x_history,
colvarvalue const &x);
/// \brief Coordinate ACF, second order Legendre polynomial between
/// x(0) and x(t) (does not work with scalar numbers)
void calc_p2coor_acf(std::list<colvarvalue> &x_history,
colvarvalue const &x);
/// Calculate the auto-correlation function (ACF)
int calc_acf();
/// Save the ACF to a file
void write_acf(std::ostream &os);
/// Length of running average series
size_t runave_length;
/// Timesteps to skip between two values in the running average series
size_t runave_stride;
/// Name of the file to write the running average
- cvm::ofstream runave_os;
+ std::string runave_outfile;
+ /// File to write the running average
+ std::ostream *runave_os;
/// Current value of the running average
colvarvalue runave;
/// Current value of the square deviation from the running average
cvm::real runave_variance;
/// Calculate the running average and its standard deviation
void calc_runave();
/// If extended Lagrangian active: colvar energies (kinetic and harmonic potential)
cvm::real kinetic_energy;
cvm::real potential_energy;
public:
// collective variable component base class
class cvc;
// currently available collective variable components
// scalar colvar components
class distance;
class distance_z;
class distance_xy;
+ class polar_theta;
+ class polar_phi;
class distance_inv;
class distance_pairs;
class angle;
class dipole_angle;
class dihedral;
class coordnum;
class selfcoordnum;
class groupcoordnum;
class h_bond;
class rmsd;
class orientation_angle;
class orientation_proj;
class tilt;
class spin_angle;
class gyration;
class inertia;
class inertia_z;
class eigenvector;
class alpha_dihedrals;
class alpha_angles;
class dihedPC;
// non-scalar components
class distance_vec;
class distance_dir;
class cartesian;
class orientation;
protected:
/// \brief Array of \link cvc \endlink objects
std::vector<cvc *> cvcs;
/// \brief Flags to enable or disable cvcs at next colvar evaluation
std::vector<bool> cvc_flags;
/// \brief Initialize the sorted list of atom IDs for atoms involved
/// in all cvcs (called when enabling f_cv_collect_gradients)
void build_atom_list(void);
private:
/// Name of scripted function to be used
std::string scripted_function;
/// Current cvc values in the order requested by script
/// when using scriptedFunction
std::vector<const colvarvalue *> sorted_cvc_values;
+#ifdef LEPTON
+ /// Vector of evaluators for custom functions using Lepton
+ std::vector<Lepton::CompiledExpression *> value_evaluators;
+
+ /// Vector of evaluators for gradients of custom functions
+ std::vector<Lepton::CompiledExpression *> gradient_evaluators;
+
+ /// Vector of references to cvc values to be passed to Lepton evaluators
+ std::vector<double *> value_eval_var_refs;
+ std::vector<double *> grad_eval_var_refs;
+
+ /// Unused value that is written to when a variable simplifies out of a Lepton expression
+ double dev_null;
+#endif
+
public:
/// \brief Sorted array of (zero-based) IDs for all atoms involved
std::vector<int> atom_ids;
/// \brief Array of atomic gradients collected from all cvcs
/// with appropriate components, rotations etc.
/// For scalar variables only!
std::vector<cvm::rvector> atomic_gradients;
inline size_t n_components() const {
return cvcs.size();
}
};
inline colvarvalue const & colvar::value() const
{
return x_reported;
}
inline colvarvalue const & colvar::actual_value() const
{
return x;
}
inline colvarvalue const & colvar::velocity() const
{
return v_reported;
}
inline colvarvalue const & colvar::total_force() const
{
return ft_reported;
}
inline void colvar::add_bias_force(colvarvalue const &force)
{
if (cvm::debug()) {
cvm::log("Adding biasing force "+cvm::to_str(force)+" to colvar \""+name+"\".\n");
}
fb += force;
}
inline void colvar::add_bias_force_actual_value(colvarvalue const &force)
{
if (cvm::debug()) {
cvm::log("Adding biasing force "+cvm::to_str(force)+" to colvar \""+name+"\".\n");
}
fb_actual += force;
}
inline void colvar::reset_bias_force() {
fb.type(value());
fb.reset();
fb_actual.type(value());
fb_actual.reset();
}
#endif
diff --git a/lib/colvars/colvaratoms.cpp b/lib/colvars/colvaratoms.cpp
index 32cfadf3b..9b4a922e3 100644
--- a/lib/colvars/colvaratoms.cpp
+++ b/lib/colvars/colvaratoms.cpp
@@ -1,1244 +1,1290 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarparse.h"
#include "colvaratoms.h"
cvm::atom::atom()
{
index = -1;
id = -1;
reset_data();
}
cvm::atom::atom(int atom_number)
{
colvarproxy *p = cvm::proxy;
index = p->init_atom(atom_number);
if (cvm::debug()) {
cvm::log("The index of this atom in the colvarproxy arrays is "+
cvm::to_str(index)+".\n");
}
id = p->get_atom_id(index);
update_mass();
reset_data();
}
cvm::atom::atom(cvm::residue_id const &residue,
std::string const &atom_name,
std::string const &segment_id)
{
colvarproxy *p = cvm::proxy;
index = p->init_atom(residue, atom_name, segment_id);
if (cvm::debug()) {
cvm::log("The index of this atom in the colvarproxy_namd arrays is "+
cvm::to_str(index)+".\n");
}
id = p->get_atom_id(index);
update_mass();
reset_data();
}
cvm::atom::atom(atom const &a)
: index(a.index)
{
id = (cvm::proxy)->get_atom_id(index);
update_mass();
reset_data();
}
cvm::atom::~atom()
{
if (index >= 0) {
(cvm::proxy)->clear_atom(index);
}
}
-// TODO change this arrangement
-// Note: "conf" is the configuration of the cvc who is using this atom group;
-// "key" is the name of the atom group (e.g. "atoms", "group1", "group2", ...)
-cvm::atom_group::atom_group(std::string const &conf,
- char const *key_in)
+cvm::atom_group::atom_group()
{
- key = key_in;
- cvm::log("Defining atom group \"" + key + "\".\n");
init();
- // real work is done by parse
- parse(conf);
- setup();
}
-cvm::atom_group::atom_group(std::vector<cvm::atom> const &atoms_in)
+cvm::atom_group::atom_group(char const *key_in)
{
+ key = key_in;
init();
- atoms = atoms_in;
- setup();
}
-cvm::atom_group::atom_group()
+cvm::atom_group::atom_group(std::vector<cvm::atom> const &atoms_in)
{
init();
+ atoms = atoms_in;
+ setup();
}
cvm::atom_group::~atom_group()
{
if (is_enabled(f_ag_scalable) && !b_dummy) {
(cvm::proxy)->clear_atom_group(index);
index = -1;
}
if (fitting_group) {
delete fitting_group;
fitting_group = NULL;
}
}
int cvm::atom_group::add_atom(cvm::atom const &a)
{
if (a.id < 0) {
return COLVARS_ERROR;
}
for (size_t i = 0; i < atoms_ids.size(); i++) {
if (atoms_ids[i] == a.id) {
if (cvm::debug())
cvm::log("Discarding doubly counted atom with number "+
cvm::to_str(a.id+1)+".\n");
return COLVARS_OK;
}
}
// for consistency with add_atom_id(), we update the list as well
atoms_ids.push_back(a.id);
atoms.push_back(a);
total_mass += a.mass;
total_charge += a.charge;
return COLVARS_OK;
}
int cvm::atom_group::add_atom_id(int aid)
{
if (aid < 0) {
return COLVARS_ERROR;
}
for (size_t i = 0; i < atoms_ids.size(); i++) {
if (atoms_ids[i] == aid) {
if (cvm::debug())
cvm::log("Discarding doubly counted atom with number "+
cvm::to_str(aid+1)+".\n");
return COLVARS_OK;
}
}
atoms_ids.push_back(aid);
return COLVARS_OK;
}
int cvm::atom_group::remove_atom(cvm::atom_iter ai)
{
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: cannot remove atoms from a scalable group.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
if (!this->size()) {
cvm::error("Error: trying to remove an atom from an empty group.\n", INPUT_ERROR);
return COLVARS_ERROR;
} else {
total_mass -= ai->mass;
total_charge -= ai->charge;
atoms_ids.erase(atoms_ids.begin() + (ai - atoms.begin()));
atoms.erase(ai);
}
return COLVARS_OK;
}
int cvm::atom_group::init()
{
if (!key.size()) key = "unnamed";
description = "atom group " + key;
- // These will be overwritten by parse(), if initializing from a config string
+ // These may be overwritten by parse(), if a name is provided
atoms.clear();
// TODO: check with proxy whether atom forces etc are available
init_ag_requires();
index = -1;
b_dummy = false;
b_center = false;
b_rotate = false;
b_user_defined_fit = false;
- b_fit_gradients = false;
fitting_group = NULL;
noforce = false;
total_mass = 0.0;
total_charge = 0.0;
cog.reset();
com.reset();
return COLVARS_OK;
}
int cvm::atom_group::setup()
{
for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) {
ai->update_mass();
ai->update_charge();
}
update_total_mass();
update_total_charge();
return COLVARS_OK;
}
void cvm::atom_group::update_total_mass()
{
if (b_dummy) {
total_mass = 1.0;
return;
}
if (is_enabled(f_ag_scalable)) {
total_mass = (cvm::proxy)->get_atom_group_mass(index);
} else {
total_mass = 0.0;
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
total_mass += ai->mass;
}
}
}
void cvm::atom_group::reset_mass(std::string &name, int i, int j)
{
update_total_mass();
cvm::log("Re-initialized atom group "+name+":"+cvm::to_str(i)+"/"+
cvm::to_str(j)+". "+ cvm::to_str(atoms_ids.size())+
" atoms: total mass = "+cvm::to_str(total_mass)+".\n");
}
void cvm::atom_group::update_total_charge()
{
if (b_dummy) {
total_charge = 0.0;
return;
}
if (is_enabled(f_ag_scalable)) {
total_charge = (cvm::proxy)->get_atom_group_charge(index);
} else {
total_charge = 0.0;
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
total_charge += ai->charge;
}
}
}
-int cvm::atom_group::parse(std::string const &conf)
+int cvm::atom_group::parse(std::string const &group_conf)
{
- std::string group_conf;
-
- // TODO move this to the cvc class constructor/init
-
- // save_delimiters is set to false for this call, because "conf" is
- // not the config string of this group, but of its parent object
- // (which has already taken care of the delimiters)
- save_delimiters = false;
- key_lookup(conf, key.c_str(), group_conf, dummy_pos);
- // restoring the normal value, because we do want keywords checked
- // inside "group_conf"
- save_delimiters = true;
-
- if (group_conf.size() == 0) {
- cvm::error("Error: atom group \""+key+
- "\" is set, but has no definition.\n",
- INPUT_ERROR);
- return COLVARS_ERROR;
- }
-
- cvm::increase_depth();
-
cvm::log("Initializing atom group \""+key+"\".\n");
- description = "atom group " + key;
-
// whether or not to include messages in the log
// colvarparse::Parse_Mode mode = parse_silent;
// {
// bool b_verbose;
// get_keyval (group_conf, "verboseOutput", b_verbose, false, parse_silent);
// if (b_verbose) mode = parse_normal;
// }
// colvarparse::Parse_Mode mode = parse_normal;
int parse_error = COLVARS_OK;
+ // Optional group name will let other groups reuse atom definition
+ if (get_keyval(group_conf, "name", name)) {
+ if ((cvm::atom_group_by_name(this->name) != NULL) &&
+ (cvm::atom_group_by_name(this->name) != this)) {
+ cvm::error("Error: this atom group cannot have the same name, \""+this->name+
+ "\", as another atom group.\n",
+ INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+ cvm::main()->register_named_atom_group(this);
+ description = "atom group " + name;
+ }
+
+ // We need to know about fitting to decide whether the group is scalable
+ // and we need to know about scalability before adding atoms
+ bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false);
+ bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false);
+ // is the user setting explicit options?
+ b_user_defined_fit = b_defined_center || b_defined_rotate;
+
+ if (is_available(f_ag_scalable_com) && !b_rotate && !b_center) {
+ enable(f_ag_scalable_com);
+ enable(f_ag_scalable);
+ }
+
+ {
+ std::string atoms_of = "";
+ if (get_keyval(group_conf, "atomsOfGroup", atoms_of)) {
+ atom_group * ag = atom_group_by_name(atoms_of);
+ if (ag == NULL) {
+ cvm::error("Error: cannot find atom group with name " + atoms_of + ".\n");
+ return COLVARS_ERROR;
+ }
+ parse_error |= add_atoms_of_group(ag);
+ }
+ }
+
+// if (get_keyval(group_conf, "copyOfGroup", source)) {
+// // Goal: Initialize this as a full copy
+// // for this we'll need an atom_group copy constructor
+// return COLVARS_OK;
+// }
+
{
std::string numbers_conf = "";
size_t pos = 0;
- while (key_lookup(group_conf, "atomNumbers", numbers_conf, pos)) {
+ while (key_lookup(group_conf, "atomNumbers", &numbers_conf, &pos)) {
parse_error |= add_atom_numbers(numbers_conf);
numbers_conf = "";
}
}
{
std::string index_group_name;
if (get_keyval(group_conf, "indexGroup", index_group_name)) {
// use an index group from the index file read globally
parse_error |= add_index_group(index_group_name);
}
}
{
std::string range_conf = "";
size_t pos = 0;
while (key_lookup(group_conf, "atomNumbersRange",
- range_conf, pos)) {
+ &range_conf, &pos)) {
parse_error |= add_atom_numbers_range(range_conf);
range_conf = "";
}
}
{
std::vector<std::string> psf_segids;
get_keyval(group_conf, "psfSegID", psf_segids, std::vector<std::string>());
std::vector<std::string>::iterator psii;
for (psii = psf_segids.begin(); psii < psf_segids.end(); ++psii) {
if ( (psii->size() == 0) || (psii->size() > 4) ) {
cvm::error("Error: invalid PSF segment identifier provided, \""+
(*psii)+"\".\n", INPUT_ERROR);
}
}
std::string range_conf = "";
size_t pos = 0;
size_t range_count = 0;
psii = psf_segids.begin();
while (key_lookup(group_conf, "atomNameResidueRange",
- range_conf, pos)) {
+ &range_conf, &pos)) {
range_count++;
if (psf_segids.size() && (range_count > psf_segids.size())) {
cvm::error("Error: more instances of \"atomNameResidueRange\" than "
"values of \"psfSegID\".\n", INPUT_ERROR);
} else {
parse_error |= add_atom_name_residue_range(psf_segids.size() ?
*psii : std::string(""), range_conf);
if (psf_segids.size()) psii++;
}
range_conf = "";
}
}
{
// read the atoms from a file
std::string atoms_file_name;
if (get_keyval(group_conf, "atomsFile", atoms_file_name, std::string(""))) {
std::string atoms_col;
if (!get_keyval(group_conf, "atomsCol", atoms_col, std::string(""))) {
cvm::error("Error: parameter atomsCol is required if atomsFile is set.\n",
INPUT_ERROR);
}
double atoms_col_value;
bool const atoms_col_value_defined = get_keyval(group_conf, "atomsColValue", atoms_col_value, 0.0);
if (atoms_col_value_defined && (!atoms_col_value)) {
cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", INPUT_ERROR);
}
// NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function
cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
}
}
// Catch any errors from all the initialization steps above
if (parse_error || cvm::get_error()) return (parse_error || cvm::get_error());
// checks of doubly-counted atoms have been handled by add_atom() already
if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos())) {
b_dummy = true;
// note: atoms_ids.size() is used here in lieu of atoms.size(),
// which can be empty for scalable groups
if (atoms_ids.size()) {
cvm::error("Error: cannot set up group \""+
key+"\" as a dummy atom "
"and provide it with atom definitions.\n", INPUT_ERROR);
}
} else {
b_dummy = false;
if (!(atoms_ids.size())) {
cvm::error("Error: no atoms defined for atom group \""+
key+"\".\n", INPUT_ERROR);
}
// whether these atoms will ever receive forces or not
bool enable_forces = true;
// disableForces is deprecated
if (get_keyval(group_conf, "enableForces", enable_forces, true)) {
noforce = !enable_forces;
} else {
get_keyval(group_conf, "disableForces", noforce, false, colvarparse::parse_silent);
}
}
- // We need to know the fitting options to decide whether the group is scalable
+ // Now that atoms are defined we can parse the detailed fitting options
parse_error |= parse_fitting_options(group_conf);
- if (is_available(f_ag_scalable_com) && !b_rotate && !b_center) {
- enable(f_ag_scalable_com);
- enable(f_ag_scalable);
- }
-
if (is_enabled(f_ag_scalable) && !b_dummy) {
cvm::log("Enabling scalable calculation for group \""+this->key+"\".\n");
index = (cvm::proxy)->init_atom_group(atoms_ids);
}
bool b_print_atom_ids = false;
get_keyval(group_conf, "printAtomIDs", b_print_atom_ids, false, colvarparse::parse_silent);
- // TODO move this to colvarparse object
- check_keywords(group_conf, key.c_str());
- if (cvm::get_error()) {
- cvm::error("Error setting up atom group \""+key+"\".");
- return COLVARS_ERROR;
- }
-
// Calculate all required properties (such as total mass)
setup();
if (cvm::debug())
cvm::log("Done initializing atom group \""+key+"\".\n");
cvm::log("Atom group \""+key+"\" defined, "+
cvm::to_str(atoms_ids.size())+" atoms initialized: total mass = "+
- cvm::to_str(total_mass)+", total charge = "+
+ cvm::to_str(total_mass)+", total charge = "+
cvm::to_str(total_charge)+".\n");
if (b_print_atom_ids) {
cvm::log("Internal definition of the atom group:\n");
cvm::log(print_atom_ids());
}
- cvm::decrease_depth();
-
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
+int cvm::atom_group::add_atoms_of_group(atom_group const * ag)
+{
+ std::vector<int> const &source_ids = ag->atoms_ids;
+
+ if (source_ids.size()) {
+ atoms_ids.reserve(atoms_ids.size()+source_ids.size());
+
+ if (is_enabled(f_ag_scalable)) {
+ for (size_t i = 0; i < source_ids.size(); i++) {
+ add_atom_id(source_ids[i]);
+ }
+ } else {
+ atoms.reserve(atoms.size()+source_ids.size());
+ for (size_t i = 0; i < source_ids.size(); i++) {
+ // We could use the atom copy constructor, but only if the source
+ // group is not scalable - whereas this works in both cases
+ // atom constructor expects 1-based atom number
+ add_atom(cvm::atom(source_ids[i] + 1));
+ }
+ }
+
+ if (cvm::get_error()) return COLVARS_ERROR;
+ } else {
+ cvm::error("Error: source atom group contains no atoms\".\n", INPUT_ERROR);
+ return COLVARS_ERROR;
+ }
+
+ return COLVARS_OK;
+}
+
+
int cvm::atom_group::add_atom_numbers(std::string const &numbers_conf)
{
std::vector<int> atom_indexes;
if (numbers_conf.size()) {
std::istringstream is(numbers_conf);
int ia;
while (is >> ia) {
atom_indexes.push_back(ia);
}
}
if (atom_indexes.size()) {
atoms_ids.reserve(atoms_ids.size()+atom_indexes.size());
if (is_enabled(f_ag_scalable)) {
for (size_t i = 0; i < atom_indexes.size(); i++) {
add_atom_id((cvm::proxy)->check_atom_id(atom_indexes[i]));
}
} else {
// if we are handling the group on rank 0, better allocate the vector in one shot
atoms.reserve(atoms.size()+atom_indexes.size());
for (size_t i = 0; i < atom_indexes.size(); i++) {
add_atom(cvm::atom(atom_indexes[i]));
}
}
if (cvm::get_error()) return COLVARS_ERROR;
} else {
cvm::error("Error: no numbers provided for \""
"atomNumbers\".\n", INPUT_ERROR);
return COLVARS_ERROR;
}
return COLVARS_OK;
}
int cvm::atom_group::add_index_group(std::string const &index_group_name)
{
colvarmodule *cv = cvm::main();
std::list<std::string>::iterator names_i = cv->index_group_names.begin();
std::list<std::vector<int> >::iterator index_groups_i = cv->index_groups.begin();
for ( ; names_i != cv->index_group_names.end() ; ++names_i, ++index_groups_i) {
if (*names_i == index_group_name)
break;
}
if (names_i == cv->index_group_names.end()) {
cvm::error("Error: could not find index group "+
index_group_name+" among those provided by the index file.\n",
INPUT_ERROR);
return COLVARS_ERROR;
}
atoms_ids.reserve(atoms_ids.size()+index_groups_i->size());
if (is_enabled(f_ag_scalable)) {
for (size_t i = 0; i < index_groups_i->size(); i++) {
add_atom_id((cvm::proxy)->check_atom_id((*index_groups_i)[i]));
}
} else {
atoms.reserve(atoms.size()+index_groups_i->size());
for (size_t i = 0; i < index_groups_i->size(); i++) {
add_atom(cvm::atom((*index_groups_i)[i]));
}
}
if (cvm::get_error())
return COLVARS_ERROR;
return COLVARS_OK;
}
int cvm::atom_group::add_atom_numbers_range(std::string const &range_conf)
{
if (range_conf.size()) {
std::istringstream is(range_conf);
int initial, final;
char dash;
if ( (is >> initial) && (initial > 0) &&
(is >> dash) && (dash == '-') &&
(is >> final) && (final > 0) ) {
atoms_ids.reserve(atoms_ids.size() + (final - initial + 1));
if (is_enabled(f_ag_scalable)) {
for (int anum = initial; anum <= final; anum++) {
add_atom_id((cvm::proxy)->check_atom_id(anum));
}
} else {
atoms.reserve(atoms.size() + (final - initial + 1));
for (int anum = initial; anum <= final; anum++) {
add_atom(cvm::atom(anum));
}
}
}
if (cvm::get_error()) return COLVARS_ERROR;
} else {
cvm::error("Error: no valid definition for \"atomNumbersRange\", \""+
range_conf+"\".\n", INPUT_ERROR);
return COLVARS_ERROR;
}
return COLVARS_OK;
}
int cvm::atom_group::add_atom_name_residue_range(std::string const &psf_segid,
std::string const &range_conf)
{
if (range_conf.size()) {
std::istringstream is(range_conf);
std::string atom_name;
int initial, final;
char dash;
if ( (is >> atom_name) && (atom_name.size()) &&
(is >> initial) && (initial > 0) &&
(is >> dash) && (dash == '-') &&
(is >> final) && (final > 0) ) {
atoms_ids.reserve(atoms_ids.size() + (final - initial + 1));
if (is_enabled(f_ag_scalable)) {
for (int resid = initial; resid <= final; resid++) {
add_atom_id((cvm::proxy)->check_atom_id(resid, atom_name, psf_segid));
}
} else {
atoms.reserve(atoms.size() + (final - initial + 1));
for (int resid = initial; resid <= final; resid++) {
add_atom(cvm::atom(resid, atom_name, psf_segid));
}
}
if (cvm::get_error()) return COLVARS_ERROR;
} else {
cvm::error("Error: cannot parse definition for \""
"atomNameResidueRange\", \""+
range_conf+"\".\n");
return COLVARS_ERROR;
}
} else {
cvm::error("Error: atomNameResidueRange with empty definition.\n");
return COLVARS_ERROR;
}
return COLVARS_OK;
}
std::string const cvm::atom_group::print_atom_ids() const
{
size_t line_count = 0;
std::ostringstream os("");
for (size_t i = 0; i < atoms_ids.size(); i++) {
os << " " << std::setw(9) << atoms_ids[i];
if (++line_count == 7) {
os << "\n";
line_count = 0;
}
}
return os.str();
}
int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
{
- bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false);
- bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false);
- // is the user setting explicit options?
- b_user_defined_fit = b_defined_center || b_defined_rotate;
-
- get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true);
-
if (b_center || b_rotate) {
if (b_dummy)
cvm::error("Error: centerReference or rotateReference "
"cannot be defined for a dummy atom.\n");
bool b_ref_pos_group = false;
- if (key_lookup(group_conf, "refPositionsGroup")) {
+ std::string fitting_group_conf;
+ if (key_lookup(group_conf, "refPositionsGroup", &fitting_group_conf)) {
b_ref_pos_group = true;
cvm::log("Warning: keyword \"refPositionsGroup\" is deprecated: please use \"fittingGroup\" instead.\n");
}
- if (b_ref_pos_group || key_lookup(group_conf, "fittingGroup")) {
+ if (b_ref_pos_group || key_lookup(group_conf, "fittingGroup", &fitting_group_conf)) {
// instead of this group, define another group to compute the fit
if (fitting_group) {
cvm::error("Error: the atom group \""+
key+"\" has already a reference group "
"for the rototranslational fit, which was communicated by the "
"colvar component. You should not use fittingGroup "
- "in this case.\n");
+ "in this case.\n", INPUT_ERROR);
+ return INPUT_ERROR;
}
cvm::log("Within atom group \""+key+"\":\n");
- fitting_group = b_ref_pos_group ?
- new atom_group(group_conf, "refPositionsGroup") :
- new atom_group(group_conf, "fittingGroup");
-
- // regardless of the configuration, fit gradients must be calculated by fittingGroup
- fitting_group->b_fit_gradients = this->b_fit_gradients;
+ fitting_group = new atom_group("fittingGroup");
+ if (fitting_group->parse(fitting_group_conf) == COLVARS_OK) {
+ fitting_group->check_keywords(fitting_group_conf, "fittingGroup");
+ if (cvm::get_error()) {
+ cvm::error("Error setting up atom group \"fittingGroup\".", INPUT_ERROR);
+ return INPUT_ERROR;
+ }
+ }
}
atom_group *group_for_fit = fitting_group ? fitting_group : this;
get_keyval(group_conf, "refPositions", ref_pos, ref_pos);
std::string ref_pos_file;
if (get_keyval(group_conf, "refPositionsFile", ref_pos_file, std::string(""))) {
if (ref_pos.size()) {
cvm::error("Error: cannot specify \"refPositionsFile\" and "
"\"refPositions\" at the same time.\n");
}
std::string ref_pos_col;
double ref_pos_col_value=0.0;
if (get_keyval(group_conf, "refPositionsCol", ref_pos_col, std::string(""))) {
// if provided, use PDB column to select coordinates
bool found = get_keyval(group_conf, "refPositionsColValue", ref_pos_col_value, 0.0);
if (found && ref_pos_col_value == 0.0) {
cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
} else {
// if not, rely on existing atom indices for the group
group_for_fit->create_sorted_ids();
ref_pos.resize(group_for_fit->size());
}
cvm::load_coords(ref_pos_file.c_str(), ref_pos, group_for_fit->sorted_ids,
ref_pos_col, ref_pos_col_value);
}
if (ref_pos.size()) {
if (b_rotate) {
if (ref_pos.size() != group_for_fit->size())
cvm::error("Error: the number of reference positions provided("+
cvm::to_str(ref_pos.size())+
") does not match the number of atoms within \""+
key+
"\" ("+cvm::to_str(group_for_fit->size())+
"): to perform a rotational fit, "+
"these numbers should be equal.\n", INPUT_ERROR);
}
// save the center of geometry of ref_pos and subtract it
center_ref_pos();
} else {
cvm::error("Error: no reference positions provided.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
- if (b_fit_gradients) {
- group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0));
- rot.request_group1_gradients(group_for_fit->size());
- }
-
if (b_rotate && !noforce) {
cvm::log("Warning: atom group \""+key+
"\" will be aligned to a fixed orientation given by the reference positions provided. "
"If the internal structure of the group changes too much (i.e. its RMSD is comparable "
"to its radius of gyration), the optimal rotation and its gradients may become discontinuous. "
"If that happens, use fittingGroup (or a different definition for it if already defined) "
"to align the coordinates.\n");
// initialize rot member data
rot.request_group1_gradients(group_for_fit->size());
}
}
+ // Enable fit gradient calculation only if necessary, and not disabled by the user
+ // This must happen after fitting group is defined so that side-effects are performed
+ // properly (ie. allocating fitting group gradients)
+ {
+ bool b_fit_gradients;
+ get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true);
+
+ if (b_fit_gradients && (b_center || b_rotate)) {
+ enable(f_ag_fit_gradients);
+ }
+ }
+
return COLVARS_OK;
}
+void cvm::atom_group::do_feature_side_effects(int id)
+{
+ // If enabled features are changed upstream, the features below should be refreshed
+ switch (id) {
+ case f_ag_fit_gradients:
+ if (b_center || b_rotate) {
+ atom_group *group_for_fit = fitting_group ? fitting_group : this;
+ group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0));
+ rot.request_group1_gradients(group_for_fit->size());
+ }
+ break;
+ }
+}
+
+
int cvm::atom_group::create_sorted_ids(void)
{
// Only do the work if the vector is not yet populated
if (sorted_ids.size())
return COLVARS_OK;
std::list<int> temp_id_list;
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
temp_id_list.push_back(ai->id);
}
temp_id_list.sort();
temp_id_list.unique();
if (temp_id_list.size() != this->size()) {
cvm::error("Error: duplicate atom IDs in atom group? (found " +
cvm::to_str(temp_id_list.size()) +
" unique atom IDs instead of" +
cvm::to_str(this->size()) + ").\n");
return COLVARS_ERROR;
}
sorted_ids = std::vector<int> (temp_id_list.size());
unsigned int id_i = 0;
std::list<int>::iterator li;
for (li = temp_id_list.begin(); li != temp_id_list.end(); ++li) {
sorted_ids[id_i] = *li;
id_i++;
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
void cvm::atom_group::center_ref_pos()
{
ref_pos_cog = cvm::atom_pos(0.0, 0.0, 0.0);
std::vector<cvm::atom_pos>::iterator pi;
for (pi = ref_pos.begin(); pi != ref_pos.end(); ++pi) {
ref_pos_cog += *pi;
}
ref_pos_cog /= (cvm::real) ref_pos.size();
for (pi = ref_pos.begin(); pi != ref_pos.end(); ++pi) {
(*pi) -= ref_pos_cog;
}
}
void cvm::atom_group::read_positions()
{
if (b_dummy) return;
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_position();
}
if (fitting_group)
fitting_group->read_positions();
}
int cvm::atom_group::calc_required_properties()
{
// TODO check if the com is needed?
calc_center_of_mass();
calc_center_of_geometry();
if (!is_enabled(f_ag_scalable)) {
if (b_center || b_rotate) {
if (fitting_group) {
fitting_group->calc_center_of_geometry();
}
calc_apply_roto_translation();
// update COM and COG after fitting
calc_center_of_geometry();
calc_center_of_mass();
if (fitting_group) {
fitting_group->calc_center_of_geometry();
}
}
}
// TODO calculate elements of scalable cvc's here before reduction
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
void cvm::atom_group::calc_apply_roto_translation()
{
// store the laborarory-frame COGs for when they are needed later
cog_orig = this->center_of_geometry();
if (fitting_group) {
fitting_group->cog_orig = fitting_group->center_of_geometry();
}
if (b_center) {
// center on the origin first
cvm::atom_pos const rpg_cog = fitting_group ?
fitting_group->center_of_geometry() : this->center_of_geometry();
apply_translation(-1.0 * rpg_cog);
if (fitting_group) {
fitting_group->apply_translation(-1.0 * rpg_cog);
}
}
if (b_rotate) {
// rotate the group (around the center of geometry if b_center is
// true, around the origin otherwise)
rot.calc_optimal_rotation(fitting_group ?
fitting_group->positions() :
this->positions(),
ref_pos);
cvm::atom_iter ai;
for (ai = this->begin(); ai != this->end(); ai++) {
ai->pos = rot.rotate(ai->pos);
}
if (fitting_group) {
for (ai = fitting_group->begin(); ai != fitting_group->end(); ai++) {
ai->pos = rot.rotate(ai->pos);
}
}
}
if (b_center) {
// align with the center of geometry of ref_pos
apply_translation(ref_pos_cog);
if (fitting_group) {
fitting_group->apply_translation(ref_pos_cog);
}
}
// update of COM and COG is done from the calling routine
}
void cvm::atom_group::apply_translation(cvm::rvector const &t)
{
if (b_dummy) {
cvm::error("Error: cannot translate the coordinates of a dummy atom group.\n", INPUT_ERROR);
return;
}
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: cannot translate the coordinates of a scalable atom group.\n", INPUT_ERROR);
return;
}
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->pos += t;
}
}
void cvm::atom_group::read_velocities()
{
if (b_dummy) return;
if (b_rotate) {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_velocity();
ai->vel = rot.rotate(ai->vel);
}
} else {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_velocity();
}
}
}
// TODO make this a calc function
void cvm::atom_group::read_total_forces()
{
if (b_dummy) return;
if (b_rotate) {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_total_force();
ai->total_force = rot.rotate(ai->total_force);
}
} else {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_total_force();
}
}
}
int cvm::atom_group::calc_center_of_geometry()
{
if (b_dummy) {
cog = dummy_atom_pos;
} else {
cog.reset();
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
cog += ai->pos;
}
cog /= this->size();
}
return COLVARS_OK;
}
int cvm::atom_group::calc_center_of_mass()
{
if (b_dummy) {
com = dummy_atom_pos;
if (cvm::debug()) {
cvm::log("Dummy atom center of mass = "+cvm::to_str(com)+"\n");
}
} else if (is_enabled(f_ag_scalable)) {
com = (cvm::proxy)->get_atom_group_com(index);
} else {
com.reset();
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
com += ai->mass * ai->pos;
}
com /= total_mass;
}
return COLVARS_OK;
}
int cvm::atom_group::calc_dipole(cvm::atom_pos const &com)
{
if (b_dummy) {
cvm::error("Error: trying to compute the dipole of an empty group.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
dip.reset();
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
dip += ai->charge * (ai->pos - com);
}
return COLVARS_OK;
}
void cvm::atom_group::set_weighted_gradient(cvm::rvector const &grad)
{
if (b_dummy) return;
if (is_enabled(f_ag_scalable)) {
scalar_com_gradient = grad;
return;
}
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->grad = (ai->mass/total_mass) * grad;
}
}
void cvm::atom_group::calc_fit_gradients()
{
- if (b_dummy) return;
+ if (b_dummy || ! is_enabled(f_ag_fit_gradients)) return;
if (cvm::debug())
cvm::log("Calculating fit gradients.\n");
- atom_group *group_for_fit = fitting_group ? fitting_group : this;
+ cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this;
if (b_center) {
// add the center of geometry contribution to the gradients
cvm::rvector atom_grad;
for (size_t i = 0; i < this->size(); i++) {
atom_grad += atoms[i].grad;
}
if (b_rotate) atom_grad = (rot.inverse()).rotate(atom_grad);
atom_grad *= (-1.0)/(cvm::real(group_for_fit->size()));
for (size_t j = 0; j < group_for_fit->size(); j++) {
group_for_fit->fit_gradients[j] = atom_grad;
}
}
if (b_rotate) {
// add the rotation matrix contribution to the gradients
cvm::rotation const rot_inv = rot.inverse();
for (size_t i = 0; i < this->size(); i++) {
// compute centered, unrotated position
cvm::atom_pos const pos_orig =
rot_inv.rotate((b_center ? (atoms[i].pos - ref_pos_cog) : (atoms[i].pos)));
// calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i
cvm::quaternion const dxdq =
rot.q.position_derivative_inner(pos_orig, atoms[i].grad);
for (size_t j = 0; j < group_for_fit->size(); j++) {
// multiply by {\partial q}/\partial\vec{x}_j and add it to the fit gradients
for (size_t iq = 0; iq < 4; iq++) {
group_for_fit->fit_gradients[j] += dxdq[iq] * rot.dQ0_1[j][iq];
}
}
}
}
if (cvm::debug())
cvm::log("Done calculating fit gradients.\n");
}
std::vector<cvm::atom_pos> cvm::atom_group::positions() const
{
if (b_dummy) {
cvm::error("Error: positions are not available "
"from a dummy atom group.\n", INPUT_ERROR);
}
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic positions are not available "
"from a scalable atom group.\n", INPUT_ERROR);
}
std::vector<cvm::atom_pos> x(this->size(), 0.0);
cvm::atom_const_iter ai = this->begin();
std::vector<cvm::atom_pos>::iterator xi = x.begin();
for ( ; ai != this->end(); ++xi, ++ai) {
*xi = ai->pos;
}
return x;
}
std::vector<cvm::atom_pos> cvm::atom_group::positions_shifted(cvm::rvector const &shift) const
{
if (b_dummy) {
cvm::error("Error: positions are not available "
"from a dummy atom group.\n", INPUT_ERROR);
}
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic positions are not available "
"from a scalable atom group.\n", INPUT_ERROR);
}
std::vector<cvm::atom_pos> x(this->size(), 0.0);
cvm::atom_const_iter ai = this->begin();
std::vector<cvm::atom_pos>::iterator xi = x.begin();
for ( ; ai != this->end(); ++xi, ++ai) {
*xi = (ai->pos + shift);
}
return x;
}
std::vector<cvm::rvector> cvm::atom_group::velocities() const
{
if (b_dummy) {
cvm::error("Error: velocities are not available "
"from a dummy atom group.\n", INPUT_ERROR);
}
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic velocities are not available "
"from a scalable atom group.\n", INPUT_ERROR);
}
std::vector<cvm::rvector> v(this->size(), 0.0);
cvm::atom_const_iter ai = this->begin();
std::vector<cvm::atom_pos>::iterator vi = v.begin();
for ( ; ai != this->end(); vi++, ai++) {
*vi = ai->vel;
}
return v;
}
std::vector<cvm::rvector> cvm::atom_group::total_forces() const
{
if (b_dummy) {
cvm::error("Error: total forces are not available "
"from a dummy atom group.\n", INPUT_ERROR);
}
if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic total forces are not available "
"from a scalable atom group.\n", INPUT_ERROR);
}
std::vector<cvm::rvector> f(this->size(), 0.0);
cvm::atom_const_iter ai = this->begin();
std::vector<cvm::atom_pos>::iterator fi = f.begin();
for ( ; ai != this->end(); ++fi, ++ai) {
*fi = ai->total_force;
}
return f;
}
// TODO make this an accessor
cvm::rvector cvm::atom_group::total_force() const
{
if (b_dummy) {
cvm::error("Error: total total forces are not available "
"from a dummy atom group.\n", INPUT_ERROR);
}
if (is_enabled(f_ag_scalable)) {
return (cvm::proxy)->get_atom_group_total_force(index);
}
cvm::rvector f(0.0);
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
f += ai->total_force;
}
return f;
}
void cvm::atom_group::apply_colvar_force(cvm::real const &force)
{
if (cvm::debug()) {
log("Communicating a colvar force from atom group to the MD engine.\n");
}
if (b_dummy) return;
if (noforce) {
cvm::error("Error: sending a force to a group that has "
"\"enableForces\" set to off.\n");
return;
}
if (is_enabled(f_ag_scalable)) {
(cvm::proxy)->apply_atom_group_force(index, force * scalar_com_gradient);
return;
}
if (b_rotate) {
// rotate forces back to the original frame
cvm::rotation const rot_inv = rot.inverse();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate(force * ai->grad));
}
} else {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(force * ai->grad);
}
}
- if ((b_center || b_rotate) && b_fit_gradients) {
+ if ((b_center || b_rotate) && is_enabled(f_ag_fit_gradients)) {
atom_group *group_for_fit = fitting_group ? fitting_group : this;
// Fit gradients are already calculated in "laboratory" frame
for (size_t j = 0; j < group_for_fit->size(); j++) {
(*group_for_fit)[j].apply_force(force * group_for_fit->fit_gradients[j]);
}
}
}
void cvm::atom_group::apply_force(cvm::rvector const &force)
{
if (cvm::debug()) {
log("Communicating a colvar force from atom group to the MD engine.\n");
}
if (b_dummy) return;
if (noforce) {
cvm::error("Error: sending a force to a group that has "
"\"enableForces\" set to off.\n");
return;
}
if (is_enabled(f_ag_scalable)) {
(cvm::proxy)->apply_atom_group_force(index, force);
return;
}
if (b_rotate) {
cvm::rotation const rot_inv = rot.inverse();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate((ai->mass/total_mass) * force));
}
} else {
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force((ai->mass/total_mass) * force);
}
}
}
// Static members
std::vector<colvardeps::feature *> cvm::atom_group::ag_features;
diff --git a/lib/colvars/colvaratoms.h b/lib/colvars/colvaratoms.h
index 85f621295..dba2890ab 100644
--- a/lib/colvars/colvaratoms.h
+++ b/lib/colvars/colvaratoms.h
@@ -1,470 +1,471 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARATOMS_H
#define COLVARATOMS_H
#include "colvarmodule.h"
#include "colvarparse.h"
#include "colvardeps.h"
/// \brief Stores numeric id, mass and all mutable data for an atom,
/// mostly used by a \link cvc \endlink
///
/// This class may be used to keep atomic data such as id, mass,
/// position and collective variable derivatives) altogether.
/// There may be multiple instances with identical
/// numeric id, all acting independently: forces communicated through
/// these instances will be summed together.
class colvarmodule::atom {
protected:
/// Index in the colvarproxy arrays (\b NOT in the global topology!)
int index;
public:
/// Identifier for the MD program (0-based)
int id;
/// Mass
cvm::real mass;
/// Charge
cvm::real charge;
/// \brief Current position (copied from the program, can be
/// modified if necessary)
cvm::atom_pos pos;
/// \brief Current velocity (copied from the program, can be
/// modified if necessary)
cvm::rvector vel;
/// \brief System force at the previous step (copied from the
/// program, can be modified if necessary)
cvm::rvector total_force;
/// \brief Gradient of a scalar collective variable with respect
/// to this atom
///
/// This can only handle a scalar collective variable (i.e. when
/// the \link colvarvalue::real_value \endlink member is used
/// from the \link colvarvalue \endlink class), which is also the
/// most frequent case. For more complex types of \link
/// colvarvalue \endlink objects, atomic gradients should be
/// defined within the specific \link cvc \endlink
/// implementation
cvm::rvector grad;
/// \brief Default constructor (sets index and id both to -1)
atom();
/// \brief Initialize an atom for collective variable calculation
/// and get its internal identifier \param atom_number Atom index in
/// the system topology (1-based)
atom(int atom_number);
/// \brief Initialize an atom for collective variable calculation
/// and get its internal identifier \param residue Residue number
/// \param atom_name Name of the atom in the residue \param
/// segment_id For PSF topologies, the segment identifier; for other
/// type of topologies, may not be required
atom(cvm::residue_id const &residue,
std::string const &atom_name,
std::string const &segment_id);
/// Copy constructor
atom(atom const &a);
/// Destructor
~atom();
/// Set mutable data (everything except id and mass) to zero; update mass
inline void reset_data()
{
pos = cvm::atom_pos(0.0);
vel = grad = total_force = cvm::rvector(0.0);
}
/// Get the latest value of the mass
inline void update_mass()
{
mass = (cvm::proxy)->get_atom_mass(index);
}
/// Get the latest value of the charge
inline void update_charge()
{
charge = (cvm::proxy)->get_atom_charge(index);
}
/// Get the current position
inline void read_position()
{
pos = (cvm::proxy)->get_atom_position(index);
}
/// Get the current velocity
inline void read_velocity()
{
vel = (cvm::proxy)->get_atom_velocity(index);
}
/// Get the total force
inline void read_total_force()
{
total_force = (cvm::proxy)->get_atom_total_force(index);
}
/// \brief Apply a force to the atom
///
/// Note: the force is not applied instantly, but will be used later
/// by the MD integrator (the colvars module does not integrate
/// equations of motion.
///
/// Multiple calls to this function by either the same
/// \link atom \endlink object or different objects with identical
/// \link id \endlink will all be added together.
inline void apply_force(cvm::rvector const &new_force) const
{
(cvm::proxy)->apply_atom_force(index, new_force);
}
};
/// \brief Group of \link atom \endlink objects, mostly used by a
/// \link cvc \endlink object to gather all atomic data
class colvarmodule::atom_group
: public colvarparse, public colvardeps
{
public:
- /// \brief Initialize the group by looking up its configuration
- /// string in conf and parsing it; this is actually done by parse(),
- /// which is a member function so that a group can be initialized
- /// also after construction
- atom_group(std::string const &conf,
- char const *key);
+
+ /// \brief Default constructor
+ atom_group();
+
+ /// \brief Create a group object, assign a name to it
+ atom_group(char const *key);
+
+ /// \brief Initialize the group after a (temporary) vector of atoms
+ atom_group(std::vector<cvm::atom> const &atoms_in);
+
+ /// \brief Destructor
+ ~atom_group();
+
+ /// \brief Optional name to reuse properties of this in other groups
+ std::string name;
/// \brief Keyword used to define the group
// TODO Make this field part of the data structures that link a group to a CVC
std::string key;
/// \brief Set default values for common flags
int init();
/// \brief Update data required to calculate cvc's
int setup();
/// \brief Initialize the group by looking up its configuration
/// string in conf and parsing it
int parse(std::string const &conf);
int add_atom_numbers(std::string const &numbers_conf);
+ int add_atoms_of_group(atom_group const * ag);
int add_index_group(std::string const &index_group_name);
int add_atom_numbers_range(std::string const &range_conf);
int add_atom_name_residue_range(std::string const &psf_segid,
std::string const &range_conf);
int parse_fitting_options(std::string const &group_conf);
- /// \brief Initialize the group after a (temporary) vector of atoms
- atom_group(std::vector<cvm::atom> const &atoms_in);
-
/// \brief Add an atom object to this group
int add_atom(cvm::atom const &a);
/// \brief Add an atom ID to this group (the actual atomicdata will be not be handled by the group)
int add_atom_id(int aid);
/// \brief Remove an atom object from this group
int remove_atom(cvm::atom_iter ai);
/// \brief Re-initialize the total mass of a group.
/// This is needed in case the hosting MD code has an option to
/// change atom masses after their initialization.
void reset_mass(std::string &name, int i, int j);
/// \brief Implementation of the feature list for atom group
static std::vector<feature *> ag_features;
/// \brief Implementation of the feature list accessor for atom group
virtual std::vector<feature *> &features() {
return ag_features;
}
- /// \brief Default constructor
- atom_group();
-
- /// \brief Destructor
- ~atom_group();
-
protected:
/// \brief Array of atom objects
std::vector<cvm::atom> atoms;
/// \brief Array of atom identifiers for the MD program (0-based)
std::vector<int> atoms_ids;
/// \brief Dummy atom position
cvm::atom_pos dummy_atom_pos;
/// \brief Index in the colvarproxy arrays (if the group is scalable)
int index;
public:
inline cvm::atom & operator [] (size_t const i)
{
return atoms[i];
}
inline cvm::atom const & operator [] (size_t const i) const
{
return atoms[i];
}
inline cvm::atom_iter begin()
{
return atoms.begin();
}
inline cvm::atom_const_iter begin() const
{
return atoms.begin();
}
inline cvm::atom_iter end()
{
return atoms.end();
}
inline cvm::atom_const_iter end() const
{
return atoms.end();
}
inline size_t size() const
{
return atoms.size();
}
std::string const print_atom_ids() const;
/// \brief If this option is on, this group merely acts as a wrapper
/// for a fixed position; any calls to atoms within or to
/// functions that return disaggregated data will fail
bool b_dummy;
/// Sorted list of zero-based (internal) atom ids
/// (populated on-demand by create_sorted_ids)
std::vector<int> sorted_ids;
/// Allocates and populates the sorted list of atom ids
int create_sorted_ids(void);
/// \brief When updating atomic coordinates, translate them to align with the
/// center of mass of the reference coordinates
bool b_center;
/// \brief When updating atom coordinates (and after
/// centering them if b_center is set), rotate the group to
/// align with the reference coordinates.
///
/// Note: gradients will be calculated in the rotated frame: when
/// forces will be applied, they will rotated back to the original
/// frame
bool b_rotate;
/// The rotation calculated automatically if b_rotate is defined
cvm::rotation rot;
/// \brief Indicates that the user has explicitly set centerReference or
/// rotateReference, and the corresponding reference:
/// cvc's (eg rmsd, eigenvector) will not override the user's choice
bool b_user_defined_fit;
- /// \brief Whether or not the derivatives of the roto-translation
- /// should be included when calculating the colvar's gradients (default: yes)
- bool b_fit_gradients;
-
/// \brief use reference coordinates for b_center or b_rotate
std::vector<cvm::atom_pos> ref_pos;
/// \brief Center of geometry of the reference coordinates; regardless
/// of whether b_center is true, ref_pos is centered to zero at
/// initialization, and ref_pos_cog serves to center the positions
cvm::atom_pos ref_pos_cog;
/// \brief If b_center or b_rotate is true, use this group to
/// define the transformation (default: this group itself)
atom_group *fitting_group;
/// Total mass of the atom group
cvm::real total_mass;
void update_total_mass();
/// Total charge of the atom group
cvm::real total_charge;
void update_total_charge();
/// \brief Don't apply any force on this group (use its coordinates
/// only to calculate a colvar)
bool noforce;
/// \brief Get the current positions
void read_positions();
/// \brief (Re)calculate the optimal roto-translation
void calc_apply_roto_translation();
/// \brief Save aside the center of geometry of the reference positions,
/// then subtract it from them
///
/// In this way it will be possible to use ref_pos also for the
/// rotational fit.
/// This is called either by atom_group::parse or by CVCs that assign
/// reference positions (eg. RMSD, eigenvector).
void center_ref_pos();
/// \brief Move all positions
void apply_translation(cvm::rvector const &t);
/// \brief Get the current velocities; this must be called always
/// *after* read_positions(); if b_rotate is defined, the same
/// rotation applied to the coordinates will be used
void read_velocities();
/// \brief Get the current total_forces; this must be called always
/// *after* read_positions(); if b_rotate is defined, the same
/// rotation applied to the coordinates will be used
void read_total_forces();
/// Call reset_data() for each atom
inline void reset_atoms_data()
{
for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++)
ai->reset_data();
if (fitting_group)
fitting_group->reset_atoms_data();
}
/// \brief Recompute all mutable quantities that are required to compute CVCs
int calc_required_properties();
/// \brief Return a copy of the current atom positions
std::vector<cvm::atom_pos> positions() const;
/// \brief Calculate the center of geometry of the atomic positions, assuming
/// that they are already pbc-wrapped
int calc_center_of_geometry();
private:
/// \brief Center of geometry
cvm::atom_pos cog;
/// \brief Center of geometry before any fitting
cvm::atom_pos cog_orig;
public:
/// \brief Return the center of geometry of the atomic positions
inline cvm::atom_pos center_of_geometry() const
{
return cog;
}
/// \brief Calculate the center of mass of the atomic positions, assuming that
/// they are already pbc-wrapped
int calc_center_of_mass();
private:
/// \brief Center of mass
cvm::atom_pos com;
/// \brief The derivative of a scalar variable with respect to the COM
// TODO for scalable calculations of more complex variables (e.g. rotation),
// use a colvarvalue of vectors to hold the entire derivative
cvm::rvector scalar_com_gradient;
public:
/// \brief Return the center of mass of the atomic positions
inline cvm::atom_pos center_of_mass() const
{
return com;
}
/// \brief Return a copy of the current atom positions, shifted by a constant vector
std::vector<cvm::atom_pos> positions_shifted(cvm::rvector const &shift) const;
/// \brief Return a copy of the current atom velocities
std::vector<cvm::rvector> velocities() const;
///\brief Calculate the dipole of the atom group around the specified center
int calc_dipole(cvm::atom_pos const &com);
private:
cvm::rvector dip;
public:
///\brief Return the (previously calculated) dipole of the atom group
inline cvm::rvector dipole() const
{
return dip;
}
/// \brief Return a copy of the total forces
std::vector<cvm::rvector> total_forces() const;
/// \brief Return a copy of the aggregated total force on the group
cvm::rvector total_force() const;
/// \brief Shorthand: save the specified gradient on each atom,
/// weighting with the atom mass (mostly used in combination with
/// \link center_of_mass() \endlink)
void set_weighted_gradient(cvm::rvector const &grad);
/// \brief Calculate the derivatives of the fitting transformation
void calc_fit_gradients();
/// \brief Derivatives of the fitting transformation
std::vector<cvm::atom_pos> fit_gradients;
/// \brief Used by a (scalar) colvar to apply its force on its \link
/// atom_group \endlink members
///
/// The (scalar) force is multiplied by the colvar gradient for each
/// atom; this should be used when a colvar with scalar \link
/// colvarvalue \endlink type is used (this is the most frequent
/// case: for colvars with a non-scalar type, the most convenient
/// solution is to sum together the Cartesian forces from all the
/// colvar components, and use apply_force() or apply_forces()). If
/// the group is being rotated to a reference frame (e.g. to express
/// the colvar independently from the solute rotation), the
/// gradients are temporarily rotated to the original frame.
void apply_colvar_force(cvm::real const &force);
/// \brief Apply a force "to the center of mass", i.e. the force is
/// distributed on each atom according to its mass
///
/// If the group is being rotated to a reference frame (e.g. to
/// express the colvar independently from the solute rotation), the
/// force is rotated back to the original frame. Colvar gradients
/// are not used, either because they were not defined (e.g because
/// the colvar has not a scalar value) or the biases require to
/// micromanage the force.
/// This function will be phased out eventually, in favor of
/// apply_colvar_force() once that is implemented for non-scalar values
void apply_force(cvm::rvector const &force);
+ /// Implements possible actions to be carried out
+ /// when a given feature is enabled
+ /// This overloads the base function in colvardeps
+ void do_feature_side_effects(int id);
};
#endif
diff --git a/lib/colvars/colvarbias.cpp b/lib/colvars/colvarbias.cpp
index 3779c82aa..e437466be 100644
--- a/lib/colvars/colvarbias.cpp
+++ b/lib/colvars/colvarbias.cpp
@@ -1,379 +1,393 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarbias.h"
colvarbias::colvarbias(char const *key)
: bias_type(to_lower_cppstr(key))
{
init_cvb_requires();
rank = 1;
has_data = false;
b_output_energy = false;
reset();
state_file_step = 0;
-
- // Start in active state by default
- enable(f_cvb_active);
+ description = "uninitialized " + cvm::to_str(key) + " bias";
}
int colvarbias::init(std::string const &conf)
{
colvarparse::init(conf);
if (name.size() == 0) {
// first initialization
cvm::log("Initializing a new \""+bias_type+"\" instance.\n");
rank = cvm::num_biases_type(bias_type);
get_keyval(conf, "name", name, bias_type+cvm::to_str(rank));
{
colvarbias *bias_with_name = cvm::bias_by_name(this->name);
if (bias_with_name != NULL) {
if ((bias_with_name->rank != this->rank) ||
(bias_with_name->bias_type != this->bias_type)) {
cvm::error("Error: this bias cannot have the same name, \""+this->name+
"\", as another bias.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
}
description = "bias " + name;
{
// lookup the associated colvars
std::vector<std::string> colvar_names;
if (get_keyval(conf, "colvars", colvar_names)) {
if (num_variables()) {
cvm::error("Error: cannot redefine the colvars that a bias was already defined on.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
for (size_t i = 0; i < colvar_names.size(); i++) {
add_colvar(colvar_names[i]);
}
}
}
if (!num_variables()) {
cvm::error("Error: no collective variables specified.\n", INPUT_ERROR);
return INPUT_ERROR;
}
-
} else {
cvm::log("Reinitializing bias \""+name+"\".\n");
}
output_prefix = cvm::output_prefix();
get_keyval(conf, "outputEnergy", b_output_energy, b_output_energy);
+ get_keyval(conf, "timeStepFactor", time_step_factor, 1);
+ if (time_step_factor < 1) {
+ cvm::error("Error: timeStepFactor must be 1 or greater.\n");
+ return COLVARS_ERROR;
+ }
+
+ // Now that children are defined, we can solve dependencies
+ enable(f_cvb_active);
+ if (cvm::debug()) print_state();
+
return COLVARS_OK;
}
int colvarbias::reset()
{
bias_energy = 0.0;
for (size_t i = 0; i < num_variables(); i++) {
colvar_forces[i].reset();
}
return COLVARS_OK;
}
colvarbias::colvarbias()
: colvarparse(), has_data(false)
{}
colvarbias::~colvarbias()
{
colvarbias::clear();
}
int colvarbias::clear()
{
+ free_children_deps();
+
// Remove references to this bias from colvars
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
++cvi) {
for (std::vector<colvarbias *>::iterator bi = (*cvi)->biases.begin();
bi != (*cvi)->biases.end();
++bi) {
if ( *bi == this) {
(*cvi)->biases.erase(bi);
break;
}
}
}
colvarmodule *cv = cvm::main();
// ...and from the colvars module
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
bi != cv->biases.end();
++bi) {
if ( *bi == this) {
cv->biases.erase(bi);
break;
}
}
return COLVARS_OK;
}
int colvarbias::add_colvar(std::string const &cv_name)
{
if (colvar *cv = cvm::colvar_by_name(cv_name)) {
if (cvm::debug()) {
cvm::log("Applying this bias to collective variable \""+
cv->name+"\".\n");
}
colvars.push_back(cv);
colvar_forces.push_back(colvarvalue());
colvar_forces.back().type(cv->value()); // make sure each force is initialized to zero
colvar_forces.back().is_derivative(); // colvar constraints are not applied to the force
colvar_forces.back().reset();
cv->biases.push_back(this); // add back-reference to this bias to colvar
if (is_enabled(f_cvb_apply_force)) {
cv->enable(f_cv_gradient);
}
// Add dependency link.
// All biases need at least the value of each colvar
// although possibly not at all timesteps
add_child(cv);
} else {
cvm::error("Error: cannot find a colvar named \""+
cv_name+"\".\n", INPUT_ERROR);
return INPUT_ERROR;
}
return COLVARS_OK;
}
int colvarbias::update()
{
if (cvm::debug()) {
cvm::log("Updating the "+bias_type+" bias \""+this->name+"\".\n");
}
has_data = true;
bias_energy = 0.0;
for (size_t ir = 0; ir < num_variables(); ir++) {
colvar_forces[ir].reset();
}
return COLVARS_OK;
}
void colvarbias::communicate_forces()
{
for (size_t i = 0; i < num_variables(); i++) {
if (cvm::debug()) {
cvm::log("Communicating a force to colvar \""+
variables(i)->name+"\".\n");
}
- variables(i)->add_bias_force(colvar_forces[i]);
+ // Impulse-style multiple timestep
+ // Note that biases with different values of time_step_factor
+ // may send forces to the same colvar
+ // which is why rescaling has to happen now: the colvar is not
+ // aware of this bias' time_step_factor
+ variables(i)->add_bias_force(cvm::real(time_step_factor) * colvar_forces[i]);
}
}
int colvarbias::change_configuration(std::string const &conf)
{
cvm::error("Error: change_configuration() not implemented.\n",
COLVARS_NOT_IMPLEMENTED);
return COLVARS_NOT_IMPLEMENTED;
}
cvm::real colvarbias::energy_difference(std::string const &conf)
{
cvm::error("Error: energy_difference() not implemented.\n",
COLVARS_NOT_IMPLEMENTED);
return 0.0;
}
// So far, these are only implemented in colvarbias_abf
int colvarbias::bin_num()
{
cvm::error("Error: bin_num() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::current_bin()
{
cvm::error("Error: current_bin() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::bin_count(int bin_index)
{
cvm::error("Error: bin_count() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
int colvarbias::replica_share()
{
cvm::error("Error: replica_share() not implemented.\n");
return COLVARS_NOT_IMPLEMENTED;
}
std::string const colvarbias::get_state_params() const
{
std::ostringstream os;
os << "step " << cvm::step_absolute() << "\n"
<< "name " << this->name << "\n";
return os.str();
}
int colvarbias::set_state_params(std::string const &conf)
{
std::string new_name = "";
if (colvarparse::get_keyval(conf, "name", new_name,
std::string(""), colvarparse::parse_silent) &&
(new_name != this->name)) {
cvm::error("Error: in the state file, the "
"\""+bias_type+"\" block has a different name, \""+new_name+
"\": different system?\n", INPUT_ERROR);
}
if (name.size() == 0) {
cvm::error("Error: \""+bias_type+"\" block within the restart file "
"has no identifiers.\n", INPUT_ERROR);
}
colvarparse::get_keyval(conf, "step", state_file_step,
cvm::step_absolute(), colvarparse::parse_silent);
return COLVARS_OK;
}
std::ostream & colvarbias::write_state(std::ostream &os)
{
if (cvm::debug()) {
cvm::log("Writing state file for bias \""+name+"\"\n");
}
os.setf(std::ios::scientific, std::ios::floatfield);
os.precision(cvm::cv_prec);
os << bias_type << " {\n"
<< " configuration {\n";
std::istringstream is(get_state_params());
std::string line;
while (std::getline(is, line)) {
os << " " << line << "\n";
}
os << " }\n";
write_state_data(os);
os << "}\n\n";
return os;
}
std::istream & colvarbias::read_state(std::istream &is)
{
size_t const start_pos = is.tellg();
std::string key, brace, conf;
if ( !(is >> key) || !(key == bias_type) ||
!(is >> brace) || !(brace == "{") ||
!(is >> colvarparse::read_block("configuration", conf)) ||
(set_state_params(conf) != COLVARS_OK) ) {
cvm::error("Error: in reading state configuration for \""+bias_type+"\" bias \""+
this->name+"\" at position "+
cvm::to_str(is.tellg())+" in stream.\n", INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
if (!read_state_data(is)) {
cvm::error("Error: in reading state data for \""+bias_type+"\" bias \""+
this->name+"\" at position "+
cvm::to_str(is.tellg())+" in stream.\n", INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
}
is >> brace;
if (brace != "}") {
cvm::error("Error: corrupt restart information for \""+bias_type+"\" bias \""+
this->name+"\": no matching brace at position "+
cvm::to_str(is.tellg())+" in stream.\n");
is.setstate(std::ios::failbit);
}
return is;
}
std::istream & colvarbias::read_state_data_key(std::istream &is, char const *key)
{
size_t const start_pos = is.tellg();
std::string key_in;
if ( !(is >> key_in) ||
!(key_in == to_lower_cppstr(std::string(key))) ) {
cvm::error("Error: in reading restart configuration for "+
bias_type+" bias \""+this->name+"\" at position "+
cvm::to_str(is.tellg())+" in stream.\n", INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
return is;
}
std::ostream & colvarbias::write_traj_label(std::ostream &os)
{
os << " ";
if (b_output_energy)
os << " E_"
<< cvm::wrap_string(this->name, cvm::en_width-2);
return os;
}
std::ostream & colvarbias::write_traj(std::ostream &os)
{
os << " ";
if (b_output_energy)
os << " "
<< bias_energy;
return os;
}
// Static members
std::vector<colvardeps::feature *> colvarbias::cvb_features;
diff --git a/lib/colvars/colvarbias.h b/lib/colvars/colvarbias.h
index 6d5776d3d..205e761cf 100644
--- a/lib/colvars/colvarbias.h
+++ b/lib/colvars/colvarbias.h
@@ -1,208 +1,208 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARBIAS_H
#define COLVARBIAS_H
#include "colvar.h"
#include "colvarparse.h"
#include "colvardeps.h"
/// \brief Collective variable bias, base class
class colvarbias
: public virtual colvarparse, public virtual colvardeps {
public:
/// Name of this bias
std::string name;
/// Type of this bias
std::string bias_type;
/// If there is more than one bias of this type, record its rank
int rank;
/// Add a new collective variable to this bias
int add_colvar(std::string const &cv_name);
/// How many variables are defined for this bias
inline size_t num_variables() const
{
return colvars.size();
}
/// Access the variables vector
inline std::vector<colvar *> *variables()
{
return &colvars;
}
/// Access the i-th variable
inline colvar * variables(int i) const
{
return colvars[i];
}
/// Retrieve colvar values and calculate their biasing forces
/// Return bias energy
virtual int update();
/// \brief Compute the energy of the bias with alternative values of the
/// collective variables (suitable for bias exchange)
- virtual int calc_energy(std::vector<colvarvalue> const &values =
+ virtual int calc_energy(std::vector<colvarvalue> const &values =
std::vector<colvarvalue>(0))
{
cvm::error("Error: calc_energy() not implemented.\n", COLVARS_NOT_IMPLEMENTED);
return COLVARS_NOT_IMPLEMENTED;
}
/// Send forces to the collective variables
virtual void communicate_forces();
/// Load new configuration - force constant and/or centers only
virtual int change_configuration(std::string const &conf);
/// Calculate change in energy from using alternate configuration
virtual cvm::real energy_difference(std::string const &conf);
/// Give the total number of bins for a given bias.
// FIXME this is currently 1D only
virtual int bin_num();
/// Calculate the bin index for a given bias.
// FIXME this is currently 1D only
virtual int current_bin();
//// Give the count at a given bin index.
// FIXME this is currently 1D only
virtual int bin_count(int bin_index);
//// Share information between replicas, whatever it may be.
virtual int replica_share();
/// Perform analysis tasks
virtual void analyze() {}
/// \brief Constructor
colvarbias(char const *key);
/// \brief Parse config string and (re)initialize
virtual int init(std::string const &conf);
/// \brief Set to zero all mutable data
virtual int reset();
private:
/// Default constructor
colvarbias();
/// Copy constructor
colvarbias(colvarbias &);
public:
/// \brief Delete everything
virtual int clear();
/// Destructor
virtual ~colvarbias();
/// Write the values of specific mutable properties to a string
virtual std::string const get_state_params() const;
/// Read the values of specific mutable properties from a string
virtual int set_state_params(std::string const &state_conf);
/// Write all mutable data not already written by get_state_params()
virtual std::ostream & write_state_data(std::ostream &os)
{
return os;
}
/// Read all mutable data not already set by set_state_params()
virtual std::istream & read_state_data(std::istream &is)
{
return is;
}
/// Read a keyword from the state data (typically a header)
std::istream & read_state_data_key(std::istream &is, char const *key);
/// Write the bias configuration to a restart file or other stream
virtual std::ostream & write_state(std::ostream &os);
/// Read the bias configuration from a restart file or other stream
virtual std::istream & read_state(std::istream &is);
/// Write a label to the trajectory file (comment line)
virtual std::ostream & write_traj_label(std::ostream &os);
/// Output quantities such as the bias energy to the trajectory file
virtual std::ostream & write_traj(std::ostream &os);
/// (Re)initialize the output files (does not write them yet)
virtual int setup_output()
{
return COLVARS_OK;
}
/// Write any output files that this bias may have (e.g. PMF files)
virtual int write_output_files()
{
return COLVARS_OK;
}
/// Use this prefix for all output files
std::string output_prefix;
/// If this bias is communicating with other replicas through files, send it to them
virtual int write_state_to_replicas()
{
return COLVARS_OK;
}
inline cvm::real get_energy()
{
return bias_energy;
}
/// \brief Implementation of the feature list for colvarbias
static std::vector<feature *> cvb_features;
/// \brief Implementation of the feature list accessor for colvarbias
virtual std::vector<feature *> &features()
{
return cvb_features;
}
protected:
/// \brief Pointers to collective variables to which the bias is
/// applied; current values and metric functions will be obtained
/// through each colvar object
std::vector<colvar *> colvars;
/// \brief Current forces from this bias to the variables
std::vector<colvarvalue> colvar_forces;
/// \brief Current energy of this bias (colvar_forces should be obtained by deriving this)
cvm::real bias_energy;
/// Whether to write the current bias energy from this bias to the trajectory file
bool b_output_energy;
/// \brief Whether this bias has already accumulated information
/// (for history-dependent biases)
bool has_data;
/// \brief Step number read from the last state file
size_t state_file_step;
};
#endif
diff --git a/lib/colvars/colvarbias_abf.cpp b/lib/colvars/colvarbias_abf.cpp
index d039004f0..a96fc21d6 100644
--- a/lib/colvars/colvarbias_abf.cpp
+++ b/lib/colvars/colvarbias_abf.cpp
@@ -1,662 +1,676 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvar.h"
#include "colvarbias_abf.h"
colvarbias_abf::colvarbias_abf(char const *key)
: colvarbias(key),
system_force(NULL),
gradients(NULL),
samples(NULL),
z_gradients(NULL),
z_samples(NULL),
czar_gradients(NULL),
last_gradients(NULL),
last_samples(NULL)
{
}
int colvarbias_abf::init(std::string const &conf)
{
colvarbias::init(conf);
enable(f_cvb_scalar_variables);
enable(f_cvb_calc_pmf);
// TODO relax this in case of VMD plugin
if (cvm::temperature() == 0.0)
cvm::log("WARNING: ABF should not be run without a thermostat or at 0 Kelvin!\n");
// ************* parsing general ABF options ***********************
get_keyval_feature((colvarparse *)this, conf, "applyBias", f_cvb_apply_force, true);
if (!is_enabled(f_cvb_apply_force)){
cvm::log("WARNING: ABF biases will *not* be applied!\n");
}
get_keyval(conf, "updateBias", update_bias, true);
if (update_bias) {
enable(f_cvb_history_dependent);
} else {
cvm::log("WARNING: ABF biases will *not* be updated!\n");
}
get_keyval(conf, "hideJacobian", hide_Jacobian, false);
if (hide_Jacobian) {
cvm::log("Jacobian (geometric) forces will be handled internally.\n");
} else {
cvm::log("Jacobian (geometric) forces will be included in reported free energy gradients.\n");
}
get_keyval(conf, "fullSamples", full_samples, 200);
if ( full_samples <= 1 ) full_samples = 1;
min_samples = full_samples / 2;
// full_samples - min_samples >= 1 is guaranteed
get_keyval(conf, "inputPrefix", input_prefix, std::vector<std::string>());
get_keyval(conf, "outputFreq", output_freq, cvm::restart_out_freq);
get_keyval(conf, "historyFreq", history_freq, 0);
b_history_files = (history_freq > 0);
// shared ABF
get_keyval(conf, "shared", shared_on, false);
if (shared_on) {
- if (!cvm::replica_enabled() || cvm::replica_num() <= 1)
+ if (!cvm::replica_enabled() || cvm::replica_num() <= 1) {
cvm::error("Error: shared ABF requires more than one replica.");
- else
- cvm::log("shared ABF will be applied among "+ cvm::to_str(cvm::replica_num()) + " replicas.\n");
+ return COLVARS_ERROR;
+ }
+ cvm::log("shared ABF will be applied among "+ cvm::to_str(cvm::replica_num()) + " replicas.\n");
+ if (cvm::proxy->smp_enabled() == COLVARS_OK) {
+ cvm::error("Error: shared ABF is currently not available with SMP parallelism; "
+ "please set \"SMP off\" at the top of the Colvars configuration file.\n",
+ COLVARS_NOT_IMPLEMENTED);
+ return COLVARS_NOT_IMPLEMENTED;
+ }
// If shared_freq is not set, we default to output_freq
get_keyval(conf, "sharedFreq", shared_freq, output_freq);
}
// ************* checking the associated colvars *******************
if (colvars.size() == 0) {
cvm::error("Error: no collective variables specified for the ABF bias.\n");
+ return COLVARS_ERROR;
}
if (update_bias) {
- // Request calculation of total force (which also checks for availability)
- // TODO - change this to a dependency - needs ABF-specific features
+ // Request calculation of total force
if(enable(f_cvb_get_total_force)) return cvm::get_error();
}
bool b_extended = false;
for (size_t i = 0; i < colvars.size(); i++) {
if (colvars[i]->value().type() != colvarvalue::type_scalar) {
cvm::error("Error: ABF bias can only use scalar-type variables.\n");
}
colvars[i]->enable(f_cv_grid);
if (hide_Jacobian) {
colvars[i]->enable(f_cv_hide_Jacobian);
}
// If any colvar is extended-system, we need to collect the extended
// system gradient
if (colvars[i]->is_enabled(f_cv_extended_Lagrangian))
b_extended = true;
+ // Cannot mix and match coarse time steps with ABF because it gives
+ // wrong total force averages - total force needs to be averaged over
+ // every time step
+ if (colvars[i]->get_time_step_factor() != time_step_factor) {
+ cvm::error("Error: " + colvars[i]->description + " has a value of timeStepFactor ("
+ + cvm::to_str(colvars[i]->get_time_step_factor()) + ") different from that of "
+ + description + " (" + cvm::to_str(time_step_factor) + ").\n");
+ return COLVARS_ERROR;
+ }
+
// Here we could check for orthogonality of the Cartesian coordinates
// and make it just a warning if some parameter is set?
}
if (get_keyval(conf, "maxForce", max_force)) {
if (max_force.size() != colvars.size()) {
cvm::error("Error: Number of parameters to maxForce does not match number of colvars.");
}
for (size_t i = 0; i < colvars.size(); i++) {
if (max_force[i] < 0.0) {
cvm::error("Error: maxForce should be non-negative.");
}
}
cap_force = true;
} else {
cap_force = false;
}
bin.assign(colvars.size(), 0);
force_bin.assign(colvars.size(), 0);
system_force = new cvm::real [colvars.size()];
// Construct empty grids based on the colvars
if (cvm::debug()) {
cvm::log("Allocating count and free energy gradient grids.\n");
}
samples = new colvar_grid_count(colvars);
gradients = new colvar_grid_gradient(colvars);
gradients->samples = samples;
samples->has_parent_data = true;
// Data for eABF z-based estimator
if (b_extended) {
// CZAR output files for stratified eABF
get_keyval(conf, "writeCZARwindowFile", b_czar_window_file, false,
colvarparse::parse_silent);
z_bin.assign(colvars.size(), 0);
z_samples = new colvar_grid_count(colvars);
z_samples->request_actual_value();
z_gradients = new colvar_grid_gradient(colvars);
z_gradients->request_actual_value();
z_gradients->samples = z_samples;
z_samples->has_parent_data = true;
czar_gradients = new colvar_grid_gradient(colvars);
}
// For shared ABF, we store a second set of grids.
// This used to be only if "shared" was defined,
// but now we allow calling share externally (e.g. from Tcl).
last_samples = new colvar_grid_count(colvars);
last_gradients = new colvar_grid_gradient(colvars);
last_gradients->samples = last_samples;
last_samples->has_parent_data = true;
shared_last_step = -1;
// If custom grids are provided, read them
if ( input_prefix.size() > 0 ) {
read_gradients_samples();
}
cvm::log("Finished ABF setup.\n");
return COLVARS_OK;
}
/// Destructor
colvarbias_abf::~colvarbias_abf()
{
if (samples) {
delete samples;
samples = NULL;
}
if (gradients) {
delete gradients;
gradients = NULL;
}
if (z_samples) {
delete z_samples;
z_samples = NULL;
}
if (z_gradients) {
delete z_gradients;
z_gradients = NULL;
}
if (czar_gradients) {
delete czar_gradients;
czar_gradients = NULL;
}
// shared ABF
// We used to only do this if "shared" was defined,
// but now we can call shared externally
if (last_samples) {
delete last_samples;
last_samples = NULL;
}
if (last_gradients) {
delete last_gradients;
last_gradients = NULL;
}
if (system_force) {
delete [] system_force;
system_force = NULL;
}
}
/// Update the FE gradient, compute and apply biasing force
/// also output data to disk if needed
int colvarbias_abf::update()
{
if (cvm::debug()) cvm::log("Updating ABF bias " + this->name);
if (cvm::step_relative() == 0) {
// At first timestep, do only:
// initialization stuff (file operations relying on n_abf_biases
// compute current value of colvars
for (size_t i = 0; i < colvars.size(); i++) {
bin[i] = samples->current_bin_scalar(i);
}
} else {
for (size_t i = 0; i < colvars.size(); i++) {
bin[i] = samples->current_bin_scalar(i);
}
if ( update_bias && samples->index_ok(force_bin) ) {
// Only if requested and within bounds of the grid...
for (size_t i = 0; i < colvars.size(); i++) {
// get total forces (lagging by 1 timestep) from colvars
// and subtract previous ABF force if necessary
update_system_force(i);
}
gradients->acc_force(force_bin, system_force);
}
if ( z_gradients && update_bias ) {
for (size_t i = 0; i < colvars.size(); i++) {
z_bin[i] = z_samples->current_bin_scalar(i);
}
if ( z_samples->index_ok(z_bin) ) {
for (size_t i = 0; i < colvars.size(); i++) {
// If we are outside the range of xi, the force has not been obtained above
// the function is just an accessor, so cheap to call again anyway
update_system_force(i);
}
z_gradients->acc_force(z_bin, system_force);
}
}
}
// save bin for next timestep
force_bin = bin;
// Reset biasing forces from previous timestep
for (size_t i = 0; i < colvars.size(); i++) {
colvar_forces[i].reset();
}
// Compute and apply the new bias, if applicable
if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) {
- size_t count = samples->value(bin);
- cvm::real fact = 1.0;
+ size_t count = samples->value(bin);
+ cvm::real fact = 1.0;
// Factor that ensures smooth introduction of the force
if ( count < full_samples ) {
- fact = ( count < min_samples) ? 0.0 :
+ fact = (count < min_samples) ? 0.0 :
(cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples));
}
const cvm::real * grad = &(gradients->value(bin));
if ( fact != 0.0 ) {
if ( (colvars.size() == 1) && colvars[0]->periodic_boundaries() ) {
// Enforce a zero-mean bias on periodic, 1D coordinates
// in other words: boundary condition is that the biasing potential is periodic
colvar_forces[0].real_value = fact * (grad[0] / cvm::real(count) - gradients->average());
} else {
for (size_t i = 0; i < colvars.size(); i++) {
// subtracting the mean force (opposite of the FE gradient) means adding the gradient
colvar_forces[i].real_value = fact * grad[i] / cvm::real(count);
}
}
if (cap_force) {
for (size_t i = 0; i < colvars.size(); i++) {
if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) {
colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]);
}
}
}
}
}
// update the output prefix; TODO: move later to setup_output() function
if (cvm::num_biases_feature(colvardeps::f_cvb_calc_pmf) == 1) {
// This is the only bias computing PMFs
output_prefix = cvm::output_prefix();
} else {
output_prefix = cvm::output_prefix() + "." + this->name;
}
if (output_freq && (cvm::step_absolute() % output_freq) == 0) {
if (cvm::debug()) cvm::log("ABF bias trying to write gradients and samples to disk");
write_gradients_samples(output_prefix);
}
if (b_history_files && (cvm::step_absolute() % history_freq) == 0) {
// file already exists iff cvm::step_relative() > 0
// otherwise, backup and replace
write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0));
}
if (shared_on && shared_last_step >= 0 && cvm::step_absolute() % shared_freq == 0) {
// Share gradients and samples for shared ABF.
replica_share();
}
// Prepare for the first sharing.
if (shared_last_step < 0) {
// Copy the current gradient and count values into last.
last_gradients->copy_grid(*gradients);
last_samples->copy_grid(*samples);
shared_last_step = cvm::step_absolute();
cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+".");
}
return COLVARS_OK;
}
int colvarbias_abf::replica_share() {
int p;
if ( !cvm::replica_enabled() ) {
cvm::error("Error: shared ABF: No replicas.\n");
return COLVARS_ERROR;
}
// We must have stored the last_gradients and last_samples.
if (shared_last_step < 0 ) {
cvm::error("Error: shared ABF: Tried to apply shared ABF before any sampling had occurred.\n");
return COLVARS_ERROR;
}
// Share gradients for shared ABF.
cvm::log("shared ABF: Sharing gradient and samples among replicas at step "+cvm::to_str(cvm::step_absolute()) );
// Count of data items.
size_t data_n = gradients->raw_data_num();
size_t samp_start = data_n*sizeof(cvm::real);
size_t msg_total = data_n*sizeof(size_t) + samp_start;
char* msg_data = new char[msg_total];
if (cvm::replica_index() == 0) {
// Replica 0 collects the delta gradient and count from the others.
for (p = 1; p < cvm::replica_num(); p++) {
// Receive the deltas.
cvm::replica_comm_recv(msg_data, msg_total, p);
// Map the deltas from the others into the grids.
last_gradients->raw_data_in((cvm::real*)(&msg_data[0]));
last_samples->raw_data_in((size_t*)(&msg_data[samp_start]));
// Combine the delta gradient and count of the other replicas
// with Replica 0's current state (including its delta).
gradients->add_grid( *last_gradients );
samples->add_grid( *last_samples );
}
// Now we must send the combined gradient to the other replicas.
gradients->raw_data_out((cvm::real*)(&msg_data[0]));
samples->raw_data_out((size_t*)(&msg_data[samp_start]));
for (p = 1; p < cvm::replica_num(); p++) {
cvm::replica_comm_send(msg_data, msg_total, p);
}
} else {
// All other replicas send their delta gradient and count.
// Calculate the delta gradient and count.
last_gradients->delta_grid(*gradients);
last_samples->delta_grid(*samples);
// Cast the raw char data to the gradient and samples.
last_gradients->raw_data_out((cvm::real*)(&msg_data[0]));
last_samples->raw_data_out((size_t*)(&msg_data[samp_start]));
cvm::replica_comm_send(msg_data, msg_total, 0);
// We now receive the combined gradient from Replica 0.
cvm::replica_comm_recv(msg_data, msg_total, 0);
// We sync to the combined gradient computed by Replica 0.
gradients->raw_data_in((cvm::real*)(&msg_data[0]));
samples->raw_data_in((size_t*)(&msg_data[samp_start]));
}
// Without a barrier it's possible that one replica starts
// share 2 when other replicas haven't finished share 1.
cvm::replica_comm_barrier();
// Done syncing the replicas.
delete[] msg_data;
// Copy the current gradient and count values into last.
last_gradients->copy_grid(*gradients);
last_samples->copy_grid(*samples);
shared_last_step = cvm::step_absolute();
return COLVARS_OK;
}
void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool append)
{
std::string samples_out_name = prefix + ".count";
std::string gradients_out_name = prefix + ".grad";
std::ios::openmode mode = (append ? std::ios::app : std::ios::out);
- cvm::ofstream samples_os;
- cvm::ofstream gradients_os;
-
- if (!append) cvm::backup_file(samples_out_name.c_str());
- samples_os.open(samples_out_name.c_str(), mode);
- if (!samples_os.is_open()) {
+ std::ostream *samples_os =
+ cvm::proxy->output_stream(samples_out_name, mode);
+ if (!samples_os) {
cvm::error("Error opening ABF samples file " + samples_out_name + " for writing");
}
- samples->write_multicol(samples_os);
- samples_os.close();
+ samples->write_multicol(*samples_os);
+ cvm::proxy->close_output_stream(samples_out_name);
- if (!append) cvm::backup_file(gradients_out_name.c_str());
- gradients_os.open(gradients_out_name.c_str(), mode);
- if (!gradients_os.is_open()) {
+ std::ostream *gradients_os =
+ cvm::proxy->output_stream(gradients_out_name, mode);
+ if (!gradients_os) {
cvm::error("Error opening ABF gradient file " + gradients_out_name + " for writing");
}
- gradients->write_multicol(gradients_os);
- gradients_os.close();
+ gradients->write_multicol(*gradients_os);
+ cvm::proxy->close_output_stream(gradients_out_name);
if (colvars.size() == 1) {
- std::string pmf_out_name = prefix + ".pmf";
- if (!append) cvm::backup_file(pmf_out_name.c_str());
- cvm::ofstream pmf_os;
// Do numerical integration and output a PMF
- pmf_os.open(pmf_out_name.c_str(), mode);
- if (!pmf_os.is_open()) cvm::error("Error opening pmf file " + pmf_out_name + " for writing");
- gradients->write_1D_integral(pmf_os);
- pmf_os << std::endl;
- pmf_os.close();
+ std::string pmf_out_name = prefix + ".pmf";
+ std::ostream *pmf_os = cvm::proxy->output_stream(pmf_out_name, mode);
+ if (!pmf_os) {
+ cvm::error("Error opening pmf file " + pmf_out_name + " for writing");
+ }
+ gradients->write_1D_integral(*pmf_os);
+ *pmf_os << std::endl;
+ cvm::proxy->close_output_stream(pmf_out_name);
}
if (z_gradients) {
// Write eABF-related quantities
std::string z_samples_out_name = prefix + ".zcount";
- cvm::ofstream z_samples_os;
- if (!append) cvm::backup_file(z_samples_out_name.c_str());
- z_samples_os.open(z_samples_out_name.c_str(), mode);
- if (!z_samples_os.is_open()) {
+ std::ostream *z_samples_os =
+ cvm::proxy->output_stream(z_samples_out_name, mode);
+ if (!z_samples_os) {
cvm::error("Error opening eABF z-histogram file " + z_samples_out_name + " for writing");
}
- z_samples->write_multicol(z_samples_os);
- z_samples_os.close();
+ z_samples->write_multicol(*z_samples_os);
+ cvm::proxy->close_output_stream(z_samples_out_name);
if (b_czar_window_file) {
std::string z_gradients_out_name = prefix + ".zgrad";
- cvm::ofstream z_gradients_os;
- if (!append) cvm::backup_file(z_gradients_out_name.c_str());
- z_gradients_os.open(z_gradients_out_name.c_str(), mode);
- if (!z_gradients_os.is_open()) {
+ std::ostream *z_gradients_os =
+ cvm::proxy->output_stream(z_gradients_out_name, mode);
+ if (!z_gradients_os) {
cvm::error("Error opening eABF z-gradient file " + z_gradients_out_name + " for writing");
}
- z_gradients->write_multicol(z_gradients_os);
- z_gradients_os.close();
+ z_gradients->write_multicol(*z_gradients_os);
+ cvm::proxy->close_output_stream(z_gradients_out_name);
}
// Calculate CZAR estimator of gradients
for (std::vector<int> ix = czar_gradients->new_index();
czar_gradients->index_ok(ix); czar_gradients->incr(ix)) {
for (size_t n = 0; n < czar_gradients->multiplicity(); n++) {
czar_gradients->set_value(ix, z_gradients->value_output(ix, n)
- cvm::temperature() * cvm::boltzmann() * z_samples->log_gradient_finite_diff(ix, n),
n);
}
}
std::string czar_gradients_out_name = prefix + ".czar.grad";
- cvm::ofstream czar_gradients_os;
- if (!append) cvm::backup_file(czar_gradients_out_name.c_str());
- czar_gradients_os.open(czar_gradients_out_name.c_str(), mode);
- if (!czar_gradients_os.is_open()) {
+ std::ostream *czar_gradients_os =
+ cvm::proxy->output_stream(czar_gradients_out_name, mode);
+ if (!czar_gradients_os) {
cvm::error("Error opening CZAR gradient file " + czar_gradients_out_name + " for writing");
}
- czar_gradients->write_multicol(czar_gradients_os);
- czar_gradients_os.close();
+ czar_gradients->write_multicol(*czar_gradients_os);
+ cvm::proxy->close_output_stream(czar_gradients_out_name);
if (colvars.size() == 1) {
- std::string czar_pmf_out_name = prefix + ".czar.pmf";
- if (!append) cvm::backup_file(czar_pmf_out_name.c_str());
- cvm::ofstream czar_pmf_os;
// Do numerical integration and output a PMF
- czar_pmf_os.open(czar_pmf_out_name.c_str(), mode);
- if (!czar_pmf_os.is_open()) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing");
- czar_gradients->write_1D_integral(czar_pmf_os);
- czar_pmf_os << std::endl;
- czar_pmf_os.close();
+ std::string czar_pmf_out_name = prefix + ".czar.pmf";
+ std::ostream *czar_pmf_os =
+ cvm::proxy->output_stream(czar_pmf_out_name, mode);
+ if (!czar_pmf_os) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing");
+ czar_gradients->write_1D_integral(*czar_pmf_os);
+ *czar_pmf_os << std::endl;
+ cvm::proxy->close_output_stream(czar_pmf_out_name);
}
}
return;
}
// For Tcl implementation of selection rules.
/// Give the total number of bins for a given bias.
int colvarbias_abf::bin_num() {
return samples->number_of_points(0);
}
/// Calculate the bin index for a given bias.
int colvarbias_abf::current_bin() {
return samples->current_bin_scalar(0);
}
/// Give the count at a given bin index.
int colvarbias_abf::bin_count(int bin_index) {
if (bin_index < 0 || bin_index >= bin_num()) {
cvm::error("Error: Tried to get bin count from invalid bin index "+cvm::to_str(bin_index));
return -1;
}
std::vector<int> ix(1,(int)bin_index);
return samples->value(ix);
}
void colvarbias_abf::read_gradients_samples()
{
std::string samples_in_name, gradients_in_name, z_samples_in_name, z_gradients_in_name;
for ( size_t i = 0; i < input_prefix.size(); i++ ) {
samples_in_name = input_prefix[i] + ".count";
gradients_in_name = input_prefix[i] + ".grad";
z_samples_in_name = input_prefix[i] + ".zcount";
z_gradients_in_name = input_prefix[i] + ".zgrad";
// For user-provided files, the per-bias naming scheme may not apply
std::ifstream is;
cvm::log("Reading sample count from " + samples_in_name + " and gradient from " + gradients_in_name);
is.open(samples_in_name.c_str());
if (!is.is_open()) cvm::error("Error opening ABF samples file " + samples_in_name + " for reading");
samples->read_multicol(is, true);
is.close();
is.clear();
is.open(gradients_in_name.c_str());
- if (!is.is_open()) cvm::error("Error opening ABF gradient file " + gradients_in_name + " for reading");
- gradients->read_multicol(is, true);
- is.close();
+ if (!is.is_open()) {
+ cvm::error("Error opening ABF gradient file " +
+ gradients_in_name + " for reading", INPUT_ERROR);
+ } else {
+ gradients->read_multicol(is, true);
+ is.close();
+ }
if (z_gradients) {
// Read eABF z-averaged data for CZAR
cvm::log("Reading z-histogram from " + z_samples_in_name + " and z-gradient from " + z_gradients_in_name);
is.clear();
is.open(z_samples_in_name.c_str());
if (!is.is_open()) cvm::error("Error opening eABF z-histogram file " + z_samples_in_name + " for reading");
z_samples->read_multicol(is, true);
is.close();
is.clear();
is.open(z_gradients_in_name.c_str());
if (!is.is_open()) cvm::error("Error opening eABF z-gradient file " + z_gradients_in_name + " for reading");
z_gradients->read_multicol(is, true);
is.close();
}
}
return;
}
std::ostream & colvarbias_abf::write_state_data(std::ostream& os)
{
std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format
os << "\nsamples\n";
samples->write_raw(os, 8);
os.flags(flags);
os << "\ngradient\n";
gradients->write_raw(os, 8);
if (z_gradients) {
os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format
os << "\nz_samples\n";
z_samples->write_raw(os, 8);
os.flags(flags);
os << "\nz_gradient\n";
z_gradients->write_raw(os, 8);
}
os.flags(flags);
return os;
}
std::istream & colvarbias_abf::read_state_data(std::istream& is)
{
if ( input_prefix.size() > 0 ) {
cvm::error("ERROR: cannot provide both inputPrefix and a colvars state file.\n", INPUT_ERROR);
}
if (! read_state_data_key(is, "samples")) {
return is;
}
if (! samples->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "gradient")) {
return is;
}
if (! gradients->read_raw(is)) {
return is;
}
if (z_gradients) {
if (! read_state_data_key(is, "z_samples")) {
return is;
}
if (! z_samples->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "z_gradient")) {
return is;
}
if (! z_gradients->read_raw(is)) {
return is;
}
}
return is;
}
diff --git a/lib/colvars/colvarbias_alb.cpp b/lib/colvars/colvarbias_alb.cpp
index d096ac3da..124a15c5d 100644
--- a/lib/colvars/colvarbias_alb.cpp
+++ b/lib/colvars/colvarbias_alb.cpp
@@ -1,420 +1,420 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "colvarmodule.h"
#include "colvarbias_alb.h"
#include "colvarbias.h"
#ifdef _MSC_VER
#if _MSC_VER <= 1700
#define copysign(A,B) _copysign(A,B)
double fmax(double A, double B) { return ( A > B ? A : B ); }
double fmin(double A, double B) { return ( A < B ? A : B ); }
#endif
#endif
/* Note about nomenclature. Force constant is called a coupling
* constant here to emphasize its changing in the code. Outwards,
* everything is called a force constant to keep it consistent with
* the rest of colvars.
*
*/
colvarbias_alb::colvarbias_alb(char const *key)
: colvarbias(key), update_calls(0), b_equilibration(true)
{
}
int colvarbias_alb::init(std::string const &conf)
{
colvarbias::init(conf);
enable(f_cvb_scalar_variables);
size_t i;
// get the initial restraint centers
colvar_centers.resize(colvars.size());
means.resize(colvars.size());
ssd.resize(colvars.size()); //sum of squares of differences from mean
//setup force vectors
max_coupling_range.resize(colvars.size());
max_coupling_rate.resize(colvars.size());
coupling_accum.resize(colvars.size());
set_coupling.resize(colvars.size());
current_coupling.resize(colvars.size());
coupling_rate.resize(colvars.size());
enable(f_cvb_apply_force);
for (i = 0; i < colvars.size(); i++) {
colvar_centers[i].type(colvars[i]->value());
//zero moments
means[i] = ssd[i] = 0;
//zero force some of the force vectors that aren't initialized
coupling_accum[i] = current_coupling[i] = 0;
}
if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
for (i = 0; i < colvars.size(); i++) {
colvar_centers[i].apply_constraints();
}
} else {
colvar_centers.clear();
cvm::fatal_error("Error: must define the initial centers of adaptive linear bias .\n");
}
if (colvar_centers.size() != colvars.size())
cvm::fatal_error("Error: number of centers does not match "
"that of collective variables.\n");
if (!get_keyval(conf, "UpdateFrequency", update_freq, 0))
cvm::fatal_error("Error: must set updateFrequency for adaptive linear bias.\n");
//we split the time between updating and equilibrating
update_freq /= 2;
if (update_freq <= 1)
cvm::fatal_error("Error: must set updateFrequency to greater than 2.\n");
enable(f_cvb_history_dependent);
get_keyval(conf, "outputCenters", b_output_centers, false);
get_keyval(conf, "outputGradient", b_output_grad, false);
get_keyval(conf, "outputCoupling", b_output_coupling, true);
get_keyval(conf, "hardForceRange", b_hard_coupling_range, true);
//initial guess
if (!get_keyval(conf, "forceConstant", set_coupling, set_coupling))
for (i =0 ; i < colvars.size(); i++)
set_coupling[i] = 0.;
//how we're going to increase to that point
for (i = 0; i < colvars.size(); i++)
coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq;
if (!get_keyval(conf, "forceRange", max_coupling_range, max_coupling_range)) {
//set to default
for (i = 0; i < colvars.size(); i++) {
if (cvm::temperature() > 0)
max_coupling_range[i] = 3 * cvm::temperature() * cvm::boltzmann();
else
max_coupling_range[i] = 3 * cvm::boltzmann();
}
}
if (!get_keyval(conf, "rateMax", max_coupling_rate, max_coupling_rate)) {
//set to default
for (i = 0; i < colvars.size(); i++) {
max_coupling_rate[i] = max_coupling_range[i] / (10 * update_freq);
}
}
if (cvm::debug())
cvm::log(" bias.\n");
return COLVARS_OK;
}
colvarbias_alb::~colvarbias_alb()
{
}
int colvarbias_alb::update()
{
bias_energy = 0.0;
update_calls++;
if (cvm::debug())
cvm::log("Updating the adaptive linear bias \""+this->name+"\".\n");
//log the moments of the CVs
// Force and energy calculation
bool finished_equil_flag = 1;
cvm::real delta;
for (size_t i = 0; i < colvars.size(); i++) {
colvar_forces[i] = -1.0 * restraint_force(restraint_convert_k(current_coupling[i], colvars[i]->width),
colvars[i],
colvar_centers[i]);
bias_energy += restraint_potential(restraint_convert_k(current_coupling[i], colvars[i]->width),
- colvars[i],
- colvar_centers[i]);
+ colvars[i],
+ colvar_centers[i]);
if (!b_equilibration) {
//Welford, West, and Hanso online variance method
delta = static_cast<cvm::real>(colvars[i]->value()) - means[i];
means[i] += delta / update_calls;
ssd[i] += delta * (static_cast<cvm::real>(colvars[i]->value()) - means[i]);
} else {
//check if we've reached the setpoint
if (coupling_rate[i] == 0 || pow(current_coupling[i] - set_coupling[i],2) < pow(coupling_rate[i],2)) {
- finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points
+ finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points
}
else {
- current_coupling[i] += coupling_rate[i];
- finished_equil_flag = 0;
+ current_coupling[i] += coupling_rate[i];
+ finished_equil_flag = 0;
}
//update max_coupling_range
if (!b_hard_coupling_range && fabs(current_coupling[i]) > max_coupling_range[i]) {
- std::ostringstream logStream;
- logStream << "Coupling constant for "
- << colvars[i]->name
- << " has exceeded coupling range of "
- << max_coupling_range[i]
- << ".\n";
-
- max_coupling_range[i] *= 1.25;
- logStream << "Expanding coupling range to " << max_coupling_range[i] << ".\n";
- cvm::log(logStream.str());
+ std::ostringstream logStream;
+ logStream << "Coupling constant for "
+ << colvars[i]->name
+ << " has exceeded coupling range of "
+ << max_coupling_range[i]
+ << ".\n";
+
+ max_coupling_range[i] *= 1.25;
+ logStream << "Expanding coupling range to " << max_coupling_range[i] << ".\n";
+ cvm::log(logStream.str());
}
}
}
if (b_equilibration && finished_equil_flag) {
b_equilibration = false;
update_calls = 0;
}
//now we update coupling constant, if necessary
if (!b_equilibration && update_calls == update_freq) {
//use estimated variance to take a step
cvm::real step_size = 0;
cvm::real temp;
//reset means and sum of squares of differences
for (size_t i = 0; i < colvars.size(); i++) {
temp = 2. * (means[i] / (static_cast<cvm::real> (colvar_centers[i])) - 1) * ssd[i] / (update_calls - 1);
if (cvm::temperature() > 0)
- step_size = temp / (cvm::temperature() * cvm::boltzmann());
+ step_size = temp / (cvm::temperature() * cvm::boltzmann());
else
- step_size = temp / cvm::boltzmann();
+ step_size = temp / cvm::boltzmann();
means[i] = 0;
ssd[i] = 0;
//stochastic if we do that update or not
if (colvars.size() == 1 || rand() < RAND_MAX / ((int) colvars.size())) {
- coupling_accum[i] += step_size * step_size;
- current_coupling[i] = set_coupling[i];
- set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size;
- coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq;
- //set to the minimum rate and then put the sign back on it
- coupling_rate[i] = copysign(fmin(fabs(coupling_rate[i]), max_coupling_rate[i]), coupling_rate[i]);
+ coupling_accum[i] += step_size * step_size;
+ current_coupling[i] = set_coupling[i];
+ set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size;
+ coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq;
+ //set to the minimum rate and then put the sign back on it
+ coupling_rate[i] = copysign(fmin(fabs(coupling_rate[i]), max_coupling_rate[i]), coupling_rate[i]);
} else {
- coupling_rate[i] = 0;
+ coupling_rate[i] = 0;
}
}
update_calls = 0;
b_equilibration = true;
}
return COLVARS_OK;
}
int colvarbias_alb::set_state_params(std::string const &conf)
{
if (!get_keyval(conf, "setCoupling", set_coupling))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "currentCoupling", current_coupling))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "maxCouplingRange", max_coupling_range))
cvm::fatal_error("Error: maxCouplingRange is missing from the restart.\n");
if (!get_keyval(conf, "couplingRate", coupling_rate))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "couplingAccum", coupling_accum))
cvm::fatal_error("Error: couplingAccum is missing from the restart.\n");
if (!get_keyval(conf, "mean", means))
cvm::fatal_error("Error: current mean is missing from the restart.\n");
if (!get_keyval(conf, "ssd", ssd))
cvm::fatal_error("Error: current ssd is missing from the restart.\n");
if (!get_keyval(conf, "updateCalls", update_calls))
cvm::fatal_error("Error: current updateCalls is missing from the restart.\n");
if (!get_keyval(conf, "b_equilibration", b_equilibration))
cvm::fatal_error("Error: current updateCalls is missing from the restart.\n");
return COLVARS_OK;
}
std::string const colvarbias_alb::get_state_params() const
{
std::ostringstream os;
os << " setCoupling ";
size_t i;
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << set_coupling[i] << "\n";
}
os << " currentCoupling ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << current_coupling[i] << "\n";
}
os << " maxCouplingRange ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << max_coupling_range[i] << "\n";
}
os << " couplingRate ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << coupling_rate[i] << "\n";
}
os << " couplingAccum ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << coupling_accum[i] << "\n";
}
os << " mean ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << means[i] << "\n";
}
os << " ssd ";
for (i = 0; i < colvars.size(); i++) {
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << ssd[i] << "\n";
}
os << " updateCalls " << update_calls << "\n";
if (b_equilibration)
os << " b_equilibration yes\n";
else
os << " b_equilibration no\n";
return os.str();
}
std::ostream & colvarbias_alb::write_traj_label(std::ostream &os)
{
os << " ";
if (b_output_energy)
os << " E_"
<< cvm::wrap_string(this->name, cvm::en_width-2);
if (b_output_coupling)
for (size_t i = 0; i < current_coupling.size(); i++) {
os << " ForceConst_" << i
- <<std::setw(cvm::en_width - 6 - (i / 10 + 1))
- << "";
+ <<std::setw(cvm::en_width - 6 - (i / 10 + 1))
+ << "";
}
if (b_output_grad)
for (size_t i = 0; i < means.size(); i++) {
os << "Grad_"
- << cvm::wrap_string(colvars[i]->name, cvm::cv_width - 4);
+ << cvm::wrap_string(colvars[i]->name, cvm::cv_width - 4);
}
if (b_output_centers)
for (size_t i = 0; i < colvars.size(); i++) {
size_t const this_cv_width = (colvars[i]->value()).output_width(cvm::cv_width);
os << " x0_"
<< cvm::wrap_string(colvars[i]->name, this_cv_width-3);
}
return os;
}
std::ostream & colvarbias_alb::write_traj(std::ostream &os)
{
os << " ";
if (b_output_energy)
os << " "
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
<< bias_energy;
if (b_output_coupling)
for (size_t i = 0; i < current_coupling.size(); i++) {
os << " "
- << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
- << current_coupling[i];
+ << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
+ << current_coupling[i];
}
if (b_output_centers)
for (size_t i = 0; i < colvars.size(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< colvar_centers[i];
}
if (b_output_grad)
for (size_t i = 0; i < means.size(); i++) {
os << " "
- << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
- << -2. * (means[i] / (static_cast<cvm::real> (colvar_centers[i])) - 1) * ssd[i] / (fmax(update_calls,2) - 1);
+ << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
+ << -2. * (means[i] / (static_cast<cvm::real> (colvar_centers[i])) - 1) * ssd[i] / (fmax(update_calls,2) - 1);
}
return os;
}
cvm::real colvarbias_alb::restraint_potential(cvm::real k,
colvar const *x,
colvarvalue const &xcenter) const
{
return k * (x->value() - xcenter);
}
colvarvalue colvarbias_alb::restraint_force(cvm::real k,
colvar const *x,
colvarvalue const &xcenter) const
{
return k;
}
cvm::real colvarbias_alb::restraint_convert_k(cvm::real k,
cvm::real dist_measure) const
{
return k / dist_measure;
}
diff --git a/lib/colvars/colvarbias_histogram.cpp b/lib/colvars/colvarbias_histogram.cpp
index 502a7455b..0722e6384 100644
--- a/lib/colvars/colvarbias_histogram.cpp
+++ b/lib/colvars/colvarbias_histogram.cpp
@@ -1,224 +1,226 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvar.h"
#include "colvarbias_histogram.h"
/// Histogram "bias" constructor
colvarbias_histogram::colvarbias_histogram(char const *key)
: colvarbias(key),
grid(NULL), out_name("")
{
}
int colvarbias_histogram::init(std::string const &conf)
{
colvarbias::init(conf);
enable(f_cvb_scalar_variables);
enable(f_cvb_history_dependent);
size_t i;
get_keyval(conf, "outputFile", out_name, std::string(""));
get_keyval(conf, "outputFileDX", out_name_dx, std::string(""));
get_keyval(conf, "outputFreq", output_freq, cvm::restart_out_freq);
/// with VMD, this may not be an error
// if ( output_freq == 0 ) {
// cvm::error("User required histogram with zero output frequency");
// }
colvar_array_size = 0;
{
bool colvar_array = false;
get_keyval(conf, "gatherVectorColvars", colvar_array, colvar_array);
if (colvar_array) {
for (i = 0; i < colvars.size(); i++) { // should be all vector
if (colvars[i]->value().type() != colvarvalue::type_vector) {
cvm::error("Error: used gatherVectorColvars with non-vector colvar.\n", INPUT_ERROR);
return INPUT_ERROR;
}
if (i == 0) {
colvar_array_size = colvars[i]->value().size();
if (colvar_array_size < 1) {
cvm::error("Error: vector variable has dimension less than one.\n", INPUT_ERROR);
return INPUT_ERROR;
}
} else {
if (colvar_array_size != colvars[i]->value().size()) {
cvm::error("Error: trying to combine vector colvars of different lengths.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
}
} else {
for (i = 0; i < colvars.size(); i++) { // should be all scalar
if (colvars[i]->value().type() != colvarvalue::type_scalar) {
cvm::error("Error: only scalar colvars are supported when gatherVectorColvars is off.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
}
}
if (colvar_array_size > 0) {
weights.assign(colvar_array_size, 1.0);
get_keyval(conf, "weights", weights, weights);
}
for (i = 0; i < colvars.size(); i++) {
colvars[i]->enable(f_cv_grid);
}
grid = new colvar_grid_scalar();
grid->init_from_colvars(colvars);
{
std::string grid_conf;
- if (key_lookup(conf, "histogramGrid", grid_conf)) {
+ if (key_lookup(conf, "histogramGrid", &grid_conf)) {
grid->parse_params(grid_conf);
+ grid->check_keywords(grid_conf, "histogramGrid");
}
}
return COLVARS_OK;
}
colvarbias_histogram::~colvarbias_histogram()
{
if (grid) {
delete grid;
grid = NULL;
}
}
int colvarbias_histogram::update()
{
int error_code = COLVARS_OK;
// update base class
error_code |= colvarbias::update();
if (cvm::debug()) {
cvm::log("Updating histogram bias " + this->name);
}
// assign a valid bin size
bin.assign(colvars.size(), 0);
if (out_name.size() == 0) {
// At the first timestep, we need to assign out_name since
// output_prefix is unset during the constructor
if (cvm::step_relative() == 0) {
out_name = cvm::output_prefix() + "." + this->name + ".dat";
cvm::log("Histogram " + this->name + " will be written to file \"" + out_name + "\"");
}
}
if (out_name_dx.size() == 0) {
if (cvm::step_relative() == 0) {
out_name_dx = cvm::output_prefix() + "." + this->name + ".dx";
cvm::log("Histogram " + this->name + " will be written to file \"" + out_name_dx + "\"");
}
}
if (colvar_array_size == 0) {
// update indices for scalar values
size_t i;
for (i = 0; i < colvars.size(); i++) {
bin[i] = grid->current_bin_scalar(i);
}
if (grid->index_ok(bin)) {
grid->acc_value(bin, 1.0);
}
} else {
// update indices for vector/array values
size_t iv, i;
for (iv = 0; iv < colvar_array_size; iv++) {
for (i = 0; i < colvars.size(); i++) {
bin[i] = grid->current_bin_scalar(i, iv);
}
if (grid->index_ok(bin)) {
grid->acc_value(bin, weights[iv]);
}
}
}
if (output_freq && (cvm::step_absolute() % output_freq) == 0) {
write_output_files();
}
error_code |= cvm::get_error();
return error_code;
}
int colvarbias_histogram::write_output_files()
{
if (!has_data) {
// nothing to write
return COLVARS_OK;
}
if (out_name.size()) {
cvm::log("Writing the histogram file \""+out_name+"\".\n");
cvm::backup_file(out_name.c_str());
- cvm::ofstream grid_os(out_name.c_str());
- if (!grid_os.is_open()) {
- cvm::error("Error opening histogram file " + out_name + " for writing.\n", FILE_ERROR);
+ std::ostream *grid_os = cvm::proxy->output_stream(out_name);
+ if (!grid_os) {
+ return cvm::error("Error opening histogram file "+out_name+
+ " for writing.\n", FILE_ERROR);
}
- // TODO add return code here
- grid->write_multicol(grid_os);
- grid_os.close();
+ grid->write_multicol(*grid_os);
+ cvm::proxy->close_output_stream(out_name);
}
if (out_name_dx.size()) {
cvm::log("Writing the histogram file \""+out_name_dx+"\".\n");
cvm::backup_file(out_name_dx.c_str());
- cvm::ofstream grid_os(out_name_dx.c_str());
- if (!grid_os.is_open()) {
- cvm::error("Error opening histogram file " + out_name_dx + " for writing.\n", FILE_ERROR);
+ std::ostream *grid_os = cvm::proxy->output_stream(out_name_dx);
+ if (!grid_os) {
+ return cvm::error("Error opening histogram file "+out_name_dx+
+ " for writing.\n", FILE_ERROR);
}
- // TODO add return code here
- grid->write_opendx(grid_os);
- grid_os.close();
+ grid->write_opendx(*grid_os);
+ cvm::proxy->close_output_stream(out_name_dx);
}
+
return COLVARS_OK;
}
std::istream & colvarbias_histogram::read_state_data(std::istream& is)
{
if (! read_state_data_key(is, "grid")) {
return is;
}
if (! grid->read_raw(is)) {
return is;
}
return is;
}
std::ostream & colvarbias_histogram::write_state_data(std::ostream& os)
{
std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n";
grid->write_raw(os, 8);
os.flags(flags);
return os;
}
diff --git a/lib/colvars/colvarbias_meta.cpp b/lib/colvars/colvarbias_meta.cpp
index b0acfe974..66806fc9f 100644
--- a/lib/colvars/colvarbias_meta.cpp
+++ b/lib/colvars/colvarbias_meta.cpp
@@ -1,1853 +1,1862 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <algorithm>
// used to set the absolute path of a replica file
#if defined(WIN32) && !defined(__CYGWIN__)
#include <direct.h>
#define CHDIR ::_chdir
#define GETCWD ::_getcwd
#define PATHSEP "\\"
#else
#include <unistd.h>
#define CHDIR ::chdir
#define GETCWD ::getcwd
#define PATHSEP "/"
#endif
#include "colvar.h"
#include "colvarbias_meta.h"
colvarbias_meta::colvarbias_meta(char const *key)
: colvarbias(key)
{
new_hills_begin = hills.end();
+ hills_traj_os = NULL;
+ replica_hills_os = NULL;
}
int colvarbias_meta::init(std::string const &conf)
{
colvarbias::init(conf);
enable(f_cvb_calc_pmf);
get_keyval(conf, "hillWeight", hill_weight, 0.0);
if (hill_weight > 0.0) {
enable(f_cvb_apply_force);
} else {
cvm::error("Error: hillWeight must be provided, and a positive number.\n", INPUT_ERROR);
}
get_keyval(conf, "newHillFrequency", new_hill_freq, 1000);
if (new_hill_freq > 0) {
enable(f_cvb_history_dependent);
}
get_keyval(conf, "hillWidth", hill_width, std::sqrt(2.0 * PI) / 2.0);
cvm::log("Half-widths of the Gaussian hills (sigma's):\n");
for (size_t i = 0; i < num_variables(); i++) {
cvm::log(variables(i)->name+std::string(": ")+
cvm::to_str(0.5 * variables(i)->width * hill_width));
}
{
bool b_replicas = false;
get_keyval(conf, "multipleReplicas", b_replicas, false);
if (b_replicas)
comm = multiple_replicas;
else
comm = single_replica;
}
// in all cases, the first replica is this bias itself
if (replicas.size() == 0) {
replicas.push_back(this);
}
get_keyval(conf, "useGrids", use_grids, true);
if (use_grids) {
get_keyval(conf, "gridsUpdateFrequency", grids_freq, new_hill_freq);
get_keyval(conf, "rebinGrids", rebin_grids, false);
expand_grids = false;
size_t i;
for (i = 0; i < num_variables(); i++) {
variables(i)->enable(f_cv_grid);
if (variables(i)->expand_boundaries) {
expand_grids = true;
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": Will expand grids when the colvar \""+
variables(i)->name+"\" approaches its boundaries.\n");
}
}
get_keyval(conf, "keepHills", keep_hills, false);
if (! get_keyval(conf, "writeFreeEnergyFile", dump_fes, true))
get_keyval(conf, "dumpFreeEnergyFile", dump_fes, true, colvarparse::parse_silent);
if (get_keyval(conf, "saveFreeEnergyFile", dump_fes_save, false, colvarparse::parse_silent)) {
cvm::log("Option \"saveFreeEnergyFile\" is deprecated, "
"please use \"keepFreeEnergyFile\" instead.");
}
get_keyval(conf, "keepFreeEnergyFiles", dump_fes_save, dump_fes_save);
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
} else {
rebin_grids = false;
keep_hills = false;
dump_fes = false;
dump_fes_save = false;
dump_replica_fes = false;
hills_energy = NULL;
hills_energy_gradients = NULL;
}
if (comm != single_replica) {
if (expand_grids)
cvm::fatal_error("Error: expandBoundaries is not supported when "
"using more than one replicas; please allocate "
"wide enough boundaries for each colvar"
"ahead of time.\n");
if (get_keyval(conf, "dumpPartialFreeEnergyFile", dump_replica_fes, false)) {
if (dump_replica_fes && (! dump_fes)) {
cvm::log("Enabling \"dumpFreeEnergyFile\".\n");
}
}
get_keyval(conf, "replicaID", replica_id, std::string(""));
if (!replica_id.size())
cvm::error("Error: replicaID must be defined "
"when using more than one replica.\n", INPUT_ERROR);
get_keyval(conf, "replicasRegistry",
replicas_registry_file,
(this->name+".replicas.registry.txt"));
get_keyval(conf, "replicaUpdateFrequency",
replica_update_freq, new_hill_freq);
if (keep_hills)
cvm::log("Warning: in metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": keepHills with more than one replica can lead to a very "
"large amount of input/output and slow down your calculations. "
"Please consider disabling it.\n");
}
get_keyval(conf, "writeHillsTrajectory", b_hills_traj, false);
init_well_tempered_params(conf);
init_ebmeta_params(conf);
if (cvm::debug())
cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n");
- save_delimiters = false;
return COLVARS_OK;
}
int colvarbias_meta::init_well_tempered_params(std::string const &conf)
{
// for well-tempered metadynamics
get_keyval(conf, "wellTempered", well_tempered, false);
get_keyval(conf, "biasTemperature", bias_temperature, -1.0);
if ((bias_temperature == -1.0) && well_tempered) {
cvm::fatal_error("Error: biasTemperature is not set.\n");
}
if (well_tempered) {
cvm::log("Well-tempered metadynamics is used.\n");
cvm::log("The bias temperature is "+cvm::to_str(bias_temperature)+".\n");
}
return COLVARS_OK;
}
int colvarbias_meta::init_ebmeta_params(std::string const &conf)
{
// for ebmeta
target_dist = NULL;
get_keyval(conf, "ebMeta", ebmeta, false);
if(ebmeta){
if (use_grids && expand_grids) {
cvm::fatal_error("Error: expandBoundaries is not supported with "
"ebMeta please allocate wide enough boundaries for "
"each colvar ahead of time and set targetdistfile "
"accordingly. \n");
}
target_dist = new colvar_grid_scalar();
target_dist->init_from_colvars(colvars);
get_keyval(conf, "targetdistfile", target_dist_file);
std::ifstream targetdiststream(target_dist_file.c_str());
target_dist->read_multicol(targetdiststream);
cvm::real min_val = target_dist->minimum_value();
if(min_val<0){
cvm::error("Error: Target distribution of ebMeta "
"has negative values!.\n", INPUT_ERROR);
}
cvm::real min_pos_val = target_dist->minimum_pos_value();
if(min_pos_val<=0){
cvm::error("Error: Target distribution of ebMeta has negative "
"or zero minimum positive value!.\n", INPUT_ERROR);
}
if(min_val==0){
cvm::log("WARNING: Target distribution has zero values.\n");
cvm::log("Zeros will be converted to the minimum positive value.\n");
target_dist->remove_zeros(min_pos_val);
}
// normalize target distribution and multiply by effective volume = exp(differential entropy)
target_dist->multiply_constant(1.0/target_dist->integral());
cvm::real volume = std::exp(target_dist->entropy());
target_dist->multiply_constant(volume);
get_keyval(conf, "ebMetaEquilSteps", ebmeta_equil_steps, 0);
}
return COLVARS_OK;
}
colvarbias_meta::~colvarbias_meta()
{
if (hills_energy) {
delete hills_energy;
hills_energy = NULL;
}
if (hills_energy_gradients) {
delete hills_energy_gradients;
hills_energy_gradients = NULL;
}
- if (replica_hills_os.is_open())
- replica_hills_os.close();
+ if (replica_hills_os) {
+ cvm::proxy->close_output_stream(replica_hills_file);
+ replica_hills_os = NULL;
+ }
- if (hills_traj_os.is_open())
- hills_traj_os.close();
+ if (hills_traj_os) {
+ cvm::proxy->close_output_stream(hills_traj_file_name());
+ hills_traj_os = NULL;
+ }
if(target_dist) {
delete target_dist;
target_dist = NULL;
}
}
// **********************************************************************
// Hill management member functions
// **********************************************************************
std::list<colvarbias_meta::hill>::const_iterator
colvarbias_meta::create_hill(colvarbias_meta::hill const &h)
{
hill_iter const hills_end = hills.end();
hills.push_back(h);
if (new_hills_begin == hills_end) {
// if new_hills_begin is unset, set it for the first time
new_hills_begin = hills.end();
new_hills_begin--;
}
if (use_grids) {
// also add it to the list of hills that are off-grid, which may
// need to be computed analytically when the colvar returns
// off-grid
cvm::real const min_dist = hills_energy->bin_distance_from_boundaries(h.centers, true);
if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) {
hills_off_grid.push_back(h);
}
}
// output to trajectory (if specified)
- if (hills_traj_os.is_open()) {
- hills_traj_os << (hills.back()).output_traj();
- hills_traj_os.flush();
+ if (hills_traj_os) {
+ *hills_traj_os << (hills.back()).output_traj();
+ cvm::proxy->flush_output_stream(hills_traj_os);
}
has_data = true;
return hills.end();
}
std::list<colvarbias_meta::hill>::const_iterator
colvarbias_meta::delete_hill(hill_iter &h)
{
if (cvm::debug()) {
cvm::log("Deleting hill from the metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
", with step number "+
cvm::to_str(h->it)+(h->replica.size() ?
", replica id \""+h->replica :
"")+".\n");
}
if (use_grids && !hills_off_grid.empty()) {
for (hill_iter hoff = hills_off_grid.begin();
hoff != hills_off_grid.end(); hoff++) {
if (*h == *hoff) {
hills_off_grid.erase(hoff);
break;
}
}
}
- if (hills_traj_os.is_open()) {
+ if (hills_traj_os) {
// output to the trajectory
- hills_traj_os << "# DELETED this hill: "
- << (hills.back()).output_traj()
- << "\n";
- hills_traj_os.flush();
+ *hills_traj_os << "# DELETED this hill: "
+ << (hills.back()).output_traj()
+ << "\n";
+ cvm::proxy->flush_output_stream(hills_traj_os);
}
return hills.erase(h);
}
int colvarbias_meta::update()
{
int error_code = COLVARS_OK;
// update base class
error_code |= colvarbias::update();
// update grid definition, if needed
error_code |= update_grid_params();
// add new biasing energy/forces
error_code |= update_bias();
// update grid content to reflect new bias
error_code |= update_grid_data();
if (comm != single_replica &&
(cvm::step_absolute() % replica_update_freq) == 0) {
// sync with the other replicas (if needed)
error_code |= replica_share();
}
error_code |= calc_energy();
error_code |= calc_forces();
return error_code;
}
int colvarbias_meta::update_grid_params()
{
if (use_grids) {
std::vector<int> curr_bin = hills_energy->get_colvars_index();
if (cvm::debug()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": current coordinates on the grid: "+
cvm::to_str(curr_bin)+".\n");
}
if (expand_grids) {
// first of all, expand the grids, if specified
bool changed_grids = false;
int const min_buffer =
(3 * (size_t) std::floor(hill_width)) + 1;
std::vector<int> new_sizes(hills_energy->sizes());
std::vector<colvarvalue> new_lower_boundaries(hills_energy->lower_boundaries);
std::vector<colvarvalue> new_upper_boundaries(hills_energy->upper_boundaries);
for (size_t i = 0; i < num_variables(); i++) {
if (! variables(i)->expand_boundaries)
continue;
cvm::real &new_lb = new_lower_boundaries[i].real_value;
cvm::real &new_ub = new_upper_boundaries[i].real_value;
int &new_size = new_sizes[i];
bool changed_lb = false, changed_ub = false;
if (!variables(i)->hard_lower_boundary)
if (curr_bin[i] < min_buffer) {
int const extra_points = (min_buffer - curr_bin[i]);
new_lb -= extra_points * variables(i)->width;
new_size += extra_points;
// changed offset in this direction => the pointer needs to
// be changed, too
curr_bin[i] += extra_points;
changed_lb = true;
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": new lower boundary for colvar \""+
variables(i)->name+"\", at "+
cvm::to_str(new_lower_boundaries[i])+".\n");
}
if (!variables(i)->hard_upper_boundary)
if (curr_bin[i] > new_size - min_buffer - 1) {
int const extra_points = (curr_bin[i] - (new_size - 1) + min_buffer);
new_ub += extra_points * variables(i)->width;
new_size += extra_points;
changed_ub = true;
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": new upper boundary for colvar \""+
variables(i)->name+"\", at "+
cvm::to_str(new_upper_boundaries[i])+".\n");
}
if (changed_lb || changed_ub)
changed_grids = true;
}
if (changed_grids) {
// map everything into new grids
colvar_grid_scalar *new_hills_energy =
new colvar_grid_scalar(*hills_energy);
colvar_grid_gradient *new_hills_energy_gradients =
new colvar_grid_gradient(*hills_energy_gradients);
// supply new boundaries to the new grids
new_hills_energy->lower_boundaries = new_lower_boundaries;
new_hills_energy->upper_boundaries = new_upper_boundaries;
new_hills_energy->setup(new_sizes, 0.0, 1);
new_hills_energy_gradients->lower_boundaries = new_lower_boundaries;
new_hills_energy_gradients->upper_boundaries = new_upper_boundaries;
new_hills_energy_gradients->setup(new_sizes, 0.0, num_variables());
new_hills_energy->map_grid(*hills_energy);
new_hills_energy_gradients->map_grid(*hills_energy_gradients);
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new_hills_energy;
hills_energy_gradients = new_hills_energy_gradients;
curr_bin = hills_energy->get_colvars_index();
if (cvm::debug())
cvm::log("Coordinates on the new grid: "+
cvm::to_str(curr_bin)+".\n");
}
}
}
return COLVARS_OK;
}
int colvarbias_meta::update_bias()
{
// add a new hill if the required time interval has passed
if ((cvm::step_absolute() % new_hill_freq) == 0 &&
is_enabled(f_cvb_history_dependent)) {
if (cvm::debug()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": adding a new hill at step "+cvm::to_str(cvm::step_absolute())+".\n");
}
cvm::real hills_scale=1.0;
if (ebmeta) {
hills_scale *= 1.0/target_dist->value(target_dist->get_colvars_index());
if(cvm::step_absolute() <= long(ebmeta_equil_steps)) {
cvm::real const hills_lambda =
(cvm::real(long(ebmeta_equil_steps) - cvm::step_absolute())) /
(cvm::real(ebmeta_equil_steps));
hills_scale = hills_lambda + (1-hills_lambda)*hills_scale;
}
}
if (well_tempered) {
cvm::real hills_energy_sum_here = 0.0;
if (use_grids) {
std::vector<int> curr_bin = hills_energy->get_colvars_index();
hills_energy_sum_here = hills_energy->value(curr_bin);
} else {
calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here);
}
hills_scale *= std::exp(-1.0*hills_energy_sum_here/(bias_temperature*cvm::boltzmann()));
}
switch (comm) {
case single_replica:
create_hill(hill(hill_weight*hills_scale, colvars, hill_width));
break;
case multiple_replicas:
create_hill(hill(hill_weight*hills_scale, colvars, hill_width, replica_id));
- if (replica_hills_os.is_open()) {
- replica_hills_os << hills.back();
+ if (replica_hills_os) {
+ *replica_hills_os << hills.back();
} else {
- cvm::fatal_error("Error: in metadynamics bias \""+this->name+"\""+
- ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
- " while writing hills for the other replicas.\n");
+ return cvm::error("Error: in metadynamics bias \""+this->name+"\""+
+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
+ " while writing hills for the other replicas.\n", FILE_ERROR);
}
break;
}
}
return COLVARS_OK;
}
int colvarbias_meta::update_grid_data()
{
if ((cvm::step_absolute() % grids_freq) == 0) {
// map the most recent gaussians to the grids
project_hills(new_hills_begin, hills.end(),
hills_energy, hills_energy_gradients);
new_hills_begin = hills.end();
// TODO: we may want to condense all into one replicas array,
// including "this" as the first element
if (comm == multiple_replicas) {
for (size_t ir = 0; ir < replicas.size(); ir++) {
replicas[ir]->project_hills(replicas[ir]->new_hills_begin,
replicas[ir]->hills.end(),
replicas[ir]->hills_energy,
replicas[ir]->hills_energy_gradients);
replicas[ir]->new_hills_begin = replicas[ir]->hills.end();
}
}
}
return COLVARS_OK;
}
int colvarbias_meta::calc_energy(std::vector<colvarvalue> const &values)
{
size_t ir = 0;
for (ir = 0; ir < replicas.size(); ir++) {
replicas[ir]->bias_energy = 0.0;
}
std::vector<int> const curr_bin = values.size() ?
hills_energy->get_colvars_index(values) :
hills_energy->get_colvars_index();
if (hills_energy->index_ok(curr_bin)) {
// index is within the grid: get the energy from there
for (ir = 0; ir < replicas.size(); ir++) {
bias_energy += replicas[ir]->hills_energy->value(curr_bin);
if (cvm::debug()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": current coordinates on the grid: "+
cvm::to_str(curr_bin)+".\n");
cvm::log("Grid energy = "+cvm::to_str(bias_energy)+".\n");
}
}
} else {
// off the grid: compute analytically only the hills at the grid's edges
for (ir = 0; ir < replicas.size(); ir++) {
calc_hills(replicas[ir]->hills_off_grid.begin(),
replicas[ir]->hills_off_grid.end(),
bias_energy,
values);
}
}
// now include the hills that have not been binned yet (starting
// from new_hills_begin)
for (ir = 0; ir < replicas.size(); ir++) {
calc_hills(replicas[ir]->new_hills_begin,
replicas[ir]->hills.end(),
bias_energy);
if (cvm::debug()) {
cvm::log("Hills energy = "+cvm::to_str(bias_energy)+".\n");
}
}
return COLVARS_OK;
}
int colvarbias_meta::calc_forces(std::vector<colvarvalue> const &values)
{
size_t ir = 0, ic = 0;
for (ir = 0; ir < replicas.size(); ir++) {
for (ic = 0; ic < num_variables(); ic++) {
replicas[ir]->colvar_forces[ic].reset();
}
}
std::vector<int> const curr_bin = values.size() ?
hills_energy->get_colvars_index(values) :
hills_energy->get_colvars_index();
if (hills_energy->index_ok(curr_bin)) {
for (ir = 0; ir < replicas.size(); ir++) {
cvm::real const *f = &(replicas[ir]->hills_energy_gradients->value(curr_bin));
for (ic = 0; ic < num_variables(); ic++) {
// the gradients are stored, not the forces
colvar_forces[ic].real_value += -1.0 * f[ic];
}
}
} else {
// off the grid: compute analytically only the hills at the grid's edges
for (ir = 0; ir < replicas.size(); ir++) {
for (ic = 0; ic < num_variables(); ic++) {
calc_hills_force(ic,
replicas[ir]->hills_off_grid.begin(),
replicas[ir]->hills_off_grid.end(),
colvar_forces,
values);
}
}
}
// now include the hills that have not been binned yet (starting
// from new_hills_begin)
if (cvm::debug()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": adding the forces from the other replicas.\n");
}
for (ir = 0; ir < replicas.size(); ir++) {
for (ic = 0; ic < num_variables(); ic++) {
calc_hills_force(ic,
replicas[ir]->new_hills_begin,
replicas[ir]->hills.end(),
colvar_forces,
values);
if (cvm::debug()) {
cvm::log("Hills forces = "+cvm::to_str(colvar_forces)+".\n");
}
}
}
return COLVARS_OK;
}
void colvarbias_meta::calc_hills(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
cvm::real &energy,
std::vector<colvarvalue> const &colvar_values)
{
size_t i = 0;
std::vector<colvarvalue> curr_values(num_variables());
for (i = 0; i < num_variables(); i++) {
curr_values[i].type(variables(i)->value());
}
if (colvar_values.size()) {
for (i = 0; i < num_variables(); i++) {
curr_values[i] = colvar_values[i];
}
} else {
for (i = 0; i < num_variables(); i++) {
curr_values[i] = variables(i)->value();
}
}
for (hill_iter h = h_first; h != h_last; h++) {
// compute the gaussian exponent
cvm::real cv_sqdev = 0.0;
for (i = 0; i < num_variables(); i++) {
colvarvalue const &x = curr_values[i];
colvarvalue const &center = h->centers[i];
cvm::real const half_width = 0.5 * h->widths[i];
cv_sqdev += (variables(i)->dist2(x, center)) / (half_width*half_width);
}
// compute the gaussian
if (cv_sqdev > 23.0) {
// set it to zero if the exponent is more negative than log(1.0E-05)
h->value(0.0);
} else {
h->value(std::exp(-0.5*cv_sqdev));
}
energy += h->energy();
}
}
void colvarbias_meta::calc_hills_force(size_t const &i,
colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
std::vector<colvarvalue> &forces,
std::vector<colvarvalue> const &values)
{
// Retrieve the value of the colvar
colvarvalue const x(values.size() ? values[i] : variables(i)->value());
// do the type check only once (all colvarvalues in the hills series
// were already saved with their types matching those in the
// colvars)
hill_iter h;
switch (variables(i)->value().type()) {
case colvarvalue::type_scalar:
for (h = h_first; h != h_last; h++) {
if (h->value() == 0.0) continue;
colvarvalue const &center = h->centers[i];
cvm::real const half_width = 0.5 * h->widths[i];
forces[i].real_value +=
( h->weight() * h->value() * (0.5 / (half_width*half_width)) *
(variables(i)->dist2_lgrad(x, center)).real_value );
}
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
for (h = h_first; h != h_last; h++) {
if (h->value() == 0.0) continue;
colvarvalue const &center = h->centers[i];
cvm::real const half_width = 0.5 * h->widths[i];
forces[i].rvector_value +=
( h->weight() * h->value() * (0.5 / (half_width*half_width)) *
(variables(i)->dist2_lgrad(x, center)).rvector_value );
}
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
for (h = h_first; h != h_last; h++) {
if (h->value() == 0.0) continue;
colvarvalue const &center = h->centers[i];
cvm::real const half_width = 0.5 * h->widths[i];
forces[i].quaternion_value +=
( h->weight() * h->value() * (0.5 / (half_width*half_width)) *
(variables(i)->dist2_lgrad(x, center)).quaternion_value );
}
break;
case colvarvalue::type_vector:
for (h = h_first; h != h_last; h++) {
if (h->value() == 0.0) continue;
colvarvalue const &center = h->centers[i];
cvm::real const half_width = 0.5 * h->widths[i];
forces[i].vector1d_value +=
( h->weight() * h->value() * (0.5 / (half_width*half_width)) *
(variables(i)->dist2_lgrad(x, center)).vector1d_value );
}
break;
case colvarvalue::type_notset:
case colvarvalue::type_all:
default:
break;
}
}
// **********************************************************************
// grid management functions
// **********************************************************************
void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
colvar_grid_scalar *he,
colvar_grid_gradient *hg,
bool print_progress)
{
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": projecting hills.\n");
// TODO: improve it by looping over a small subgrid instead of the whole grid
std::vector<colvarvalue> colvar_values(num_variables());
std::vector<cvm::real> colvar_forces_scalar(num_variables());
std::vector<int> he_ix = he->new_index();
std::vector<int> hg_ix = (hg != NULL) ? hg->new_index() : std::vector<int> (0);
cvm::real hills_energy_here = 0.0;
std::vector<colvarvalue> hills_forces_here(num_variables(), 0.0);
size_t count = 0;
size_t const print_frequency = ((hills.size() >= 1000000) ? 1 : (1000000/(hills.size()+1)));
if (hg != NULL) {
// loop over the points of the grid
for ( ;
(he->index_ok(he_ix)) && (hg->index_ok(hg_ix));
count++) {
size_t i;
for (i = 0; i < num_variables(); i++) {
colvar_values[i] = hills_energy->bin_to_value_scalar(he_ix[i], i);
}
// loop over the hills and increment the energy grid locally
hills_energy_here = 0.0;
calc_hills(h_first, h_last, hills_energy_here, colvar_values);
he->acc_value(he_ix, hills_energy_here);
for (i = 0; i < num_variables(); i++) {
hills_forces_here[i].reset();
calc_hills_force(i, h_first, h_last, hills_forces_here, colvar_values);
colvar_forces_scalar[i] = hills_forces_here[i].real_value;
}
hg->acc_force(hg_ix, &(colvar_forces_scalar.front()));
he->incr(he_ix);
hg->incr(hg_ix);
if ((count % print_frequency) == 0) {
if (print_progress) {
cvm::real const progress = cvm::real(count) / cvm::real(hg->number_of_points());
std::ostringstream os;
os.setf(std::ios::fixed, std::ios::floatfield);
os << std::setw(6) << std::setprecision(2)
<< 100.0 * progress
<< "% done.";
cvm::log(os.str());
}
}
}
} else {
// simpler version, with just the energy
for ( ; (he->index_ok(he_ix)); ) {
for (size_t i = 0; i < num_variables(); i++) {
colvar_values[i] = hills_energy->bin_to_value_scalar(he_ix[i], i);
}
hills_energy_here = 0.0;
calc_hills(h_first, h_last, hills_energy_here, colvar_values);
he->acc_value(he_ix, hills_energy_here);
he->incr(he_ix);
count++;
if ((count % print_frequency) == 0) {
if (print_progress) {
cvm::real const progress = cvm::real(count) / cvm::real(he->number_of_points());
std::ostringstream os;
os.setf(std::ios::fixed, std::ios::floatfield);
os << std::setw(6) << std::setprecision(2)
<< 100.0 * progress
<< "% done.";
cvm::log(os.str());
}
}
}
}
if (print_progress) {
cvm::log("100.00% done.");
}
if (! keep_hills) {
hills.erase(hills.begin(), hills.end());
}
}
void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
colvar_grid_scalar *he)
{
hills_off_grid.clear();
for (hill_iter h = h_first; h != h_last; h++) {
cvm::real const min_dist = hills_energy->bin_distance_from_boundaries(h->centers, true);
if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) {
hills_off_grid.push_back(*h);
}
}
}
// **********************************************************************
// multiple replicas functions
// **********************************************************************
int colvarbias_meta::replica_share()
{
// sync with the other replicas (if needed)
if (comm == multiple_replicas) {
// reread the replicas registry
update_replicas_registry();
// empty the output buffer
- if (replica_hills_os.is_open())
- replica_hills_os.flush();
+ if (replica_hills_os) {
+ cvm::proxy->flush_output_stream(replica_hills_os);
+ }
read_replica_files();
}
return COLVARS_OK;
}
void colvarbias_meta::update_replicas_registry()
{
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": updating the list of replicas, currently containing "+
cvm::to_str(replicas.size())+" elements.\n");
{
// copy the whole file into a string for convenience
std::string line("");
std::ifstream reg_file(replicas_registry_file.c_str());
if (reg_file.is_open()) {
replicas_registry.clear();
while (colvarparse::getline_nocomments(reg_file, line))
replicas_registry.append(line+"\n");
} else {
cvm::error("Error: failed to open file \""+replicas_registry_file+
"\" for reading.\n", FILE_ERROR);
}
}
// now parse it
std::istringstream reg_is(replicas_registry);
if (reg_is.good()) {
std::string new_replica("");
std::string new_replica_file("");
while ((reg_is >> new_replica) && new_replica.size() &&
(reg_is >> new_replica_file) && new_replica_file.size()) {
if (new_replica == this->replica_id) {
// this is the record for this same replica, skip it
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": skipping this replica's own record: \""+
new_replica+"\", \""+new_replica_file+"\"\n");
new_replica_file.clear();
new_replica.clear();
continue;
}
bool already_loaded = false;
for (size_t ir = 0; ir < replicas.size(); ir++) {
if (new_replica == (replicas[ir])->replica_id) {
// this replica was already added
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": skipping a replica already loaded, \""+
(replicas[ir])->replica_id+"\".\n");
already_loaded = true;
break;
}
}
if (!already_loaded) {
// add this replica to the registry
cvm::log("Metadynamics bias \""+this->name+"\""+
": accessing replica \""+new_replica+"\".\n");
replicas.push_back(new colvarbias_meta("metadynamics"));
(replicas.back())->replica_id = new_replica;
(replicas.back())->replica_list_file = new_replica_file;
(replicas.back())->replica_state_file = "";
(replicas.back())->replica_state_file_in_sync = false;
// Note: the following could become a copy constructor?
(replicas.back())->name = this->name;
(replicas.back())->colvars = colvars;
(replicas.back())->use_grids = use_grids;
(replicas.back())->dump_fes = false;
(replicas.back())->expand_grids = false;
(replicas.back())->rebin_grids = false;
(replicas.back())->keep_hills = false;
(replicas.back())->colvar_forces = colvar_forces;
(replicas.back())->comm = multiple_replicas;
if (use_grids) {
(replicas.back())->hills_energy = new colvar_grid_scalar(colvars);
(replicas.back())->hills_energy_gradients = new colvar_grid_gradient(colvars);
}
}
}
} else {
cvm::fatal_error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n");
}
// now (re)read the list file of each replica
for (size_t ir = 0; ir < replicas.size(); ir++) {
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": reading the list file for replica \""+
(replicas[ir])->replica_id+"\".\n");
std::ifstream list_is((replicas[ir])->replica_list_file.c_str());
std::string key;
std::string new_state_file, new_hills_file;
if (!(list_is >> key) ||
!(key == std::string("stateFile")) ||
!(list_is >> new_state_file) ||
!(list_is >> key) ||
!(key == std::string("hillsFile")) ||
!(list_is >> new_hills_file)) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": failed to read the file \""+
(replicas[ir])->replica_list_file+"\": will try again after "+
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->update_status++;
} else {
(replicas[ir])->update_status = 0;
if (new_state_file != (replicas[ir])->replica_state_file) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": replica \""+(replicas[ir])->replica_id+
"\" has supplied a new state file, \""+new_state_file+
"\".\n");
(replicas[ir])->replica_state_file_in_sync = false;
(replicas[ir])->replica_state_file = new_state_file;
(replicas[ir])->replica_hills_file = new_hills_file;
}
}
}
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\": the list of replicas contains "+
cvm::to_str(replicas.size())+" elements.\n");
}
void colvarbias_meta::read_replica_files()
{
// Note: we start from the 2nd replica.
for (size_t ir = 1; ir < replicas.size(); ir++) {
if (! (replicas[ir])->replica_state_file_in_sync) {
// if a new state file is being read, the hills file is also new
(replicas[ir])->replica_hills_file_pos = 0;
}
// (re)read the state file if necessary
if ( (! (replicas[ir])->has_data) ||
(! (replicas[ir])->replica_state_file_in_sync) ) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": reading the state of replica \""+
(replicas[ir])->replica_id+"\" from file \""+
(replicas[ir])->replica_state_file+"\".\n");
std::ifstream is((replicas[ir])->replica_state_file.c_str());
if (! (replicas[ir])->read_state(is)) {
cvm::log("Reading from file \""+(replicas[ir])->replica_state_file+
"\" failed or incomplete: will try again in "+
cvm::to_str(replica_update_freq)+" steps.\n");
} else {
// state file has been read successfully
(replicas[ir])->replica_state_file_in_sync = true;
(replicas[ir])->update_status = 0;
}
is.close();
}
// now read the hills added after writing the state file
if ((replicas[ir])->replica_hills_file.size()) {
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": checking for new hills from replica \""+
(replicas[ir])->replica_id+"\" in the file \""+
(replicas[ir])->replica_hills_file+"\".\n");
// read hills from the other replicas' files; for each file, resume
// the position recorded previously
std::ifstream is((replicas[ir])->replica_hills_file.c_str());
if (is.is_open()) {
// try to resume the previous position
is.seekg((replicas[ir])->replica_hills_file_pos, std::ios::beg);
if (!is.is_open()){
// if fail (the file may have been overwritten), reset this
// position
is.clear();
is.seekg(0, std::ios::beg);
// reset the counter
(replicas[ir])->replica_hills_file_pos = 0;
// schedule to reread the state file
(replicas[ir])->replica_state_file_in_sync = false;
// and record the failure
(replicas[ir])->update_status++;
cvm::log("Failed to read the file \""+(replicas[ir])->replica_hills_file+
"\" at the previous position: will try again in "+
cvm::to_str(replica_update_freq)+" steps.\n");
} else {
while ((replicas[ir])->read_hill(is)) {
// if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": received a hill from replica \""+
(replicas[ir])->replica_id+
"\" at step "+
cvm::to_str(((replicas[ir])->hills.back()).it)+".\n");
}
is.clear();
// store the position for the next read
(replicas[ir])->replica_hills_file_pos = is.tellg();
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": stopped reading file \""+(replicas[ir])->replica_hills_file+
"\" at position "+
cvm::to_str((replicas[ir])->replica_hills_file_pos)+".\n");
// test whether this is the end of the file
is.seekg(0, std::ios::end);
if (is.tellg() > (replicas[ir])->replica_hills_file_pos+1) {
(replicas[ir])->update_status++;
} else {
(replicas[ir])->update_status = 0;
}
}
} else {
cvm::log("Failed to read the file \""+(replicas[ir])->replica_hills_file+
"\": will try again in "+
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->update_status++;
// cvm::fatal_error ("Error: cannot read from file \""+
// (replicas[ir])->replica_hills_file+"\".\n");
}
is.close();
}
size_t const n_flush = (replica_update_freq/new_hill_freq + 1);
if ((replicas[ir])->update_status > 3*n_flush) {
// TODO: suspend the calculation?
cvm::log("WARNING: in metadynamics bias \""+this->name+"\""+
" failed to read completely the output of replica \""+
(replicas[ir])->replica_id+
"\" after more than "+
cvm::to_str((replicas[ir])->update_status * replica_update_freq)+
" steps. Ensure that it is still running.\n");
}
}
}
int colvarbias_meta::set_state_params(std::string const &state_conf)
{
std::string new_replica = "";
if (colvarparse::get_keyval(state_conf, "replicaID", new_replica,
std::string(""), colvarparse::parse_silent) &&
(new_replica != this->replica_id)) {
cvm::error("Error: in the state file, the "
"\"metadynamics\" block has a different replicaID: different system?\n",
INPUT_ERROR);
return INPUT_ERROR;
}
return COLVARS_OK;
}
std::istream & colvarbias_meta::read_state_data(std::istream& is)
{
bool grids_from_restart_file = use_grids;
if (use_grids) {
if (expand_grids) {
// the boundaries of the colvars may have been changed; TODO:
// this reallocation is only for backward-compatibility, and may
// be deleted when grid_parameters (i.e. colvargrid's own
// internal reallocation) has kicked in
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
}
colvar_grid_scalar *hills_energy_backup = NULL;
colvar_grid_gradient *hills_energy_gradients_backup = NULL;
if (has_data) {
if (cvm::debug())
cvm::log("Backupping grids for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n");
hills_energy_backup = hills_energy;
hills_energy_gradients_backup = hills_energy_gradients;
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
}
size_t const hills_energy_pos = is.tellg();
std::string key;
if (!(is >> key)) {
if (hills_energy_backup != NULL) {
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
}
is.clear();
is.seekg(hills_energy_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
} else if (!(key == std::string("hills_energy")) ||
!(hills_energy->read_restart(is))) {
is.clear();
is.seekg(hills_energy_pos, std::ios::beg);
grids_from_restart_file = false;
if (!rebin_grids) {
if (hills_energy_backup == NULL)
cvm::fatal_error("Error: couldn't read the free energy grid for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n");
else {
if (comm == single_replica)
cvm::log("Error: couldn't read the free energy grid for metadynamics bias \""+
this->name+"\".\n");
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
is.setstate(std::ios::failbit);
return is;
}
}
}
size_t const hills_energy_gradients_pos = is.tellg();
if (!(is >> key)) {
if (hills_energy_backup != NULL) {
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
}
is.clear();
is.seekg(hills_energy_gradients_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
} else if (!(key == std::string("hills_energy_gradients")) ||
!(hills_energy_gradients->read_restart(is))) {
is.clear();
is.seekg(hills_energy_gradients_pos, std::ios::beg);
grids_from_restart_file = false;
if (!rebin_grids) {
if (hills_energy_backup == NULL)
cvm::fatal_error("Error: couldn't read the free energy gradients grid for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n");
else {
if (comm == single_replica)
cvm::log("Error: couldn't read the free energy gradients grid for metadynamics bias \""+
this->name+"\".\n");
delete hills_energy;
delete hills_energy_gradients;
hills_energy = hills_energy_backup;
hills_energy_gradients = hills_energy_gradients_backup;
is.setstate(std::ios::failbit);
return is;
}
}
}
if (cvm::debug())
cvm::log("Successfully read new grids for bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n");
if (hills_energy_backup != NULL) {
// now that we have successfully updated the grids, delete the
// backup copies
if (cvm::debug())
cvm::log("Deallocating the older grids.\n");
delete hills_energy_backup;
delete hills_energy_gradients_backup;
}
}
bool const existing_hills = !hills.empty();
size_t const old_hills_size = hills.size();
hill_iter old_hills_end = hills.end();
hill_iter old_hills_off_grid_end = hills_off_grid.end();
// read the hills explicitly written (if there are any)
while (read_hill(is)) {
if (cvm::debug())
cvm::log("Read a previously saved hill under the "
"metadynamics bias \""+
this->name+"\", created at step "+
cvm::to_str((hills.back()).it)+".\n");
}
is.clear();
new_hills_begin = hills.end();
if (grids_from_restart_file) {
if (hills.size() > old_hills_size)
cvm::log("Read "+cvm::to_str(hills.size())+
" hills in addition to the grids.\n");
} else {
if (!hills.empty())
cvm::log("Read "+cvm::to_str(hills.size())+" hills.\n");
}
if (rebin_grids) {
// allocate new grids (based on the new boundaries and widths just
// read from the configuration file), and project onto them the
// grids just read from the restart file
colvar_grid_scalar *new_hills_energy =
new colvar_grid_scalar(colvars);
colvar_grid_gradient *new_hills_energy_gradients =
new colvar_grid_gradient(colvars);
if (!grids_from_restart_file || (keep_hills && !hills.empty())) {
// if there are hills, recompute the new grids from them
cvm::log("Rebinning the energy and forces grids from "+
cvm::to_str(hills.size())+" hills (this may take a while)...\n");
project_hills(hills.begin(), hills.end(),
new_hills_energy, new_hills_energy_gradients, true);
cvm::log("rebinning done.\n");
} else {
// otherwise, use the grids in the restart file
cvm::log("Rebinning the energy and forces grids "
"from the grids in the restart file.\n");
new_hills_energy->map_grid(*hills_energy);
new_hills_energy_gradients->map_grid(*hills_energy_gradients);
}
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new_hills_energy;
hills_energy_gradients = new_hills_energy_gradients;
// assuming that some boundaries have expanded, eliminate those
// off-grid hills that aren't necessary any more
if (!hills.empty())
recount_hills_off_grid(hills.begin(), hills.end(), hills_energy);
}
if (use_grids) {
if (!hills_off_grid.empty()) {
cvm::log(cvm::to_str(hills_off_grid.size())+" hills are near the "
"grid boundaries: they will be computed analytically "
"and saved to the state files.\n");
}
}
if (cvm::debug())
cvm::log("colvarbias_meta::read_restart() done\n");
if (existing_hills) {
hills.erase(hills.begin(), old_hills_end);
hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end);
}
has_data = true;
if (comm != single_replica) {
read_replica_files();
}
return is;
}
std::istream & colvarbias_meta::read_hill(std::istream &is)
{
if (!is) return is; // do nothing if failbit is set
size_t const start_pos = is.tellg();
std::string data;
if ( !(is >> read_block("hill", data)) ) {
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
size_t h_it;
get_keyval(data, "step", h_it, 0, parse_silent);
if (h_it <= state_file_step) {
if (cvm::debug())
cvm::log("Skipping a hill older than the state file for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n");
return is;
}
cvm::real h_weight;
get_keyval(data, "weight", h_weight, hill_weight, parse_silent);
std::vector<colvarvalue> h_centers(num_variables());
for (size_t i = 0; i < num_variables(); i++) {
h_centers[i].type(variables(i)->value());
}
{
// it is safer to read colvarvalue objects one at a time;
// TODO: change this it later
std::string centers_input;
- key_lookup(data, "centers", centers_input);
+ key_lookup(data, "centers", &centers_input);
std::istringstream centers_is(centers_input);
for (size_t i = 0; i < num_variables(); i++) {
centers_is >> h_centers[i];
}
}
std::vector<cvm::real> h_widths(num_variables());
get_keyval(data, "widths", h_widths,
std::vector<cvm::real>(num_variables(), (std::sqrt(2.0 * PI) / 2.0)),
parse_silent);
std::string h_replica = "";
if (comm != single_replica) {
get_keyval(data, "replicaID", h_replica, replica_id, parse_silent);
if (h_replica != replica_id)
cvm::fatal_error("Error: trying to read a hill created by replica \""+h_replica+
"\" for replica \""+replica_id+
"\"; did you swap output files?\n");
}
hill_iter const hills_end = hills.end();
hills.push_back(hill(h_it, h_weight, h_centers, h_widths, h_replica));
if (new_hills_begin == hills_end) {
// if new_hills_begin is unset, set it for the first time
new_hills_begin = hills.end();
new_hills_begin--;
}
if (use_grids) {
// add this also to the list of hills that are off-grid, which will
// be computed analytically
cvm::real const min_dist =
hills_energy->bin_distance_from_boundaries((hills.back()).centers, true);
if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) {
hills_off_grid.push_back(hills.back());
}
}
has_data = true;
return is;
}
int colvarbias_meta::setup_output()
{
output_prefix = cvm::output_prefix();
if (cvm::num_biases_feature(colvardeps::f_cvb_calc_pmf) > 1) {
// if this is not the only free energy integrator, append
// this bias's name, to distinguish it from the output of the other
// biases producing a .pmf file
output_prefix += ("."+this->name);
}
if (comm == multiple_replicas) {
// TODO: one may want to specify the path manually for intricated filesystems?
char *pwd = new char[3001];
if (GETCWD(pwd, 3000) == NULL)
cvm::fatal_error("Error: cannot get the path of the current working directory.\n");
replica_list_file =
(std::string(pwd)+std::string(PATHSEP)+
this->name+"."+replica_id+".files.txt");
// replica_hills_file and replica_state_file are those written
// by the current replica; within the mirror biases, they are
// those by another replica
replica_hills_file =
(std::string(pwd)+std::string(PATHSEP)+
cvm::output_prefix()+".colvars."+this->name+"."+replica_id+".hills");
replica_state_file =
(std::string(pwd)+std::string(PATHSEP)+
cvm::output_prefix()+".colvars."+this->name+"."+replica_id+".state");
delete[] pwd;
// now register this replica
// first check that it isn't already there
bool registered_replica = false;
std::ifstream reg_is(replicas_registry_file.c_str());
if (reg_is.is_open()) { // the file may not be there yet
std::string existing_replica("");
std::string existing_replica_file("");
while ((reg_is >> existing_replica) && existing_replica.size() &&
(reg_is >> existing_replica_file) && existing_replica_file.size()) {
if (existing_replica == replica_id) {
// this replica was already registered
replica_list_file = existing_replica_file;
reg_is.close();
registered_replica = true;
break;
}
}
reg_is.close();
}
// if this replica was not included yet, we should generate a
// new record for it: but first, we write this replica's files,
// for the others to read
// open the "hills" buffer file
- if (!replica_hills_os.is_open()) {
- cvm::backup_file(replica_hills_file.c_str());
- replica_hills_os.open(replica_hills_file.c_str());
- if (!replica_hills_os.is_open())
- cvm::error("Error: in opening file \""+
- replica_hills_file+"\" for writing.\n", FILE_ERROR);
- replica_hills_os.setf(std::ios::scientific, std::ios::floatfield);
+ if (!replica_hills_os) {
+ cvm::proxy->backup_file(replica_hills_file);
+ replica_hills_os = cvm::proxy->output_stream(replica_hills_file);
+ if (!replica_hills_os) return cvm::get_error();
+ replica_hills_os->setf(std::ios::scientific, std::ios::floatfield);
}
// write the state file (so that there is always one available)
write_replica_state_file();
// schedule to read the state files of the other replicas
for (size_t ir = 0; ir < replicas.size(); ir++) {
(replicas[ir])->replica_state_file_in_sync = false;
}
// if we're running without grids, use a growing list of "hills" files
// otherwise, just one state file and one "hills" file as buffer
- std::ofstream list_os(replica_list_file.c_str(),
- (use_grids ? std::ios::trunc : std::ios::app));
- if (! list_os.is_open())
- cvm::fatal_error("Error: in opening file \""+
- replica_list_file+"\" for writing.\n");
- list_os << "stateFile " << replica_state_file << "\n";
- list_os << "hillsFile " << replica_hills_file << "\n";
- list_os.close();
-
- // finally, if add a new record for this replica to the registry
+ std::ostream *list_os =
+ cvm::proxy->output_stream(replica_list_file,
+ (use_grids ? std::ios_base::trunc :
+ std::ios_base::app));
+ if (!list_os) {
+ return cvm::get_error();
+ }
+ *list_os << "stateFile " << replica_state_file << "\n";
+ *list_os << "hillsFile " << replica_hills_file << "\n";
+ cvm::proxy->close_output_stream(replica_list_file);
+
+ // finally, add a new record for this replica to the registry
if (! registered_replica) {
- std::ofstream reg_os(replicas_registry_file.c_str(), std::ios::app);
- if (! reg_os.is_open())
- cvm::error("Error: in opening file \""+
- replicas_registry_file+"\" for writing.\n", FILE_ERROR);
- reg_os << replica_id << " " << replica_list_file << "\n";
- reg_os.close();
+ std::ostream *reg_os =
+ cvm::proxy->output_stream(replicas_registry_file,
+ std::ios::app);
+ if (!reg_os) {
+ return cvm::get_error();
+ }
+ *reg_os << replica_id << " " << replica_list_file << "\n";
+ cvm::proxy->close_output_stream(replicas_registry_file);
}
}
if (b_hills_traj) {
- std::string const traj_file_name(cvm::output_prefix()+
- ".colvars."+this->name+
- ( (comm != single_replica) ?
- ("."+replica_id) :
- ("") )+
- ".hills.traj");
- if (!hills_traj_os.is_open()) {
- cvm::backup_file(traj_file_name.c_str());
- hills_traj_os.open(traj_file_name.c_str());
+ if (!hills_traj_os) {
+ hills_traj_os = cvm::proxy->output_stream(hills_traj_file_name());
+ if (!hills_traj_os) return cvm::get_error();
}
- if (!hills_traj_os.is_open())
- cvm::error("Error: in opening hills output file \"" +
- traj_file_name+"\".\n", FILE_ERROR);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
+std::string const colvarbias_meta::hills_traj_file_name() const
+{
+ return std::string(cvm::output_prefix()+
+ ".colvars."+this->name+
+ ( (comm != single_replica) ?
+ ("."+replica_id) :
+ ("") )+
+ ".hills.traj");
+}
+
+
std::string const colvarbias_meta::get_state_params() const
{
std::ostringstream os;
if (this->comm != single_replica)
os << "replicaID " << this->replica_id << "\n";
return (colvarbias::get_state_params() + os.str());
}
std::ostream & colvarbias_meta::write_state_data(std::ostream& os)
{
if (use_grids) {
// this is a very good time to project hills, if you haven't done
// it already!
project_hills(new_hills_begin, hills.end(),
hills_energy, hills_energy_gradients);
new_hills_begin = hills.end();
// write down the grids to the restart file
os << " hills_energy\n";
hills_energy->write_restart(os);
os << " hills_energy_gradients\n";
hills_energy_gradients->write_restart(os);
}
if ( (!use_grids) || keep_hills ) {
// write all hills currently in memory
for (std::list<hill>::const_iterator h = this->hills.begin();
h != this->hills.end();
h++) {
os << *h;
}
} else {
// write just those that are near the grid boundaries
for (std::list<hill>::const_iterator h = this->hills_off_grid.begin();
h != this->hills_off_grid.end();
h++) {
os << *h;
}
}
return os;
}
int colvarbias_meta::write_state_to_replicas()
{
if (comm != single_replica) {
write_replica_state_file();
// schedule to reread the state files of the other replicas (they
// have also rewritten them)
for (size_t ir = 0; ir < replicas.size(); ir++) {
(replicas[ir])->replica_state_file_in_sync = false;
}
}
return COLVARS_OK;
}
int colvarbias_meta::write_output_files()
{
if (dump_fes) {
write_pmf();
}
return COLVARS_OK;
}
void colvarbias_meta::write_pmf()
{
// allocate a new grid to store the pmf
colvar_grid_scalar *pmf = new colvar_grid_scalar(*hills_energy);
pmf->setup();
if ((comm == single_replica) || (dump_replica_fes)) {
// output the PMF from this instance or replica
pmf->reset();
pmf->add_grid(*hills_energy);
cvm::real const max = pmf->maximum_value();
pmf->add_constant(-1.0 * max);
pmf->multiply_constant(-1.0);
if (well_tempered) {
cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature;
pmf->multiply_constant(well_temper_scale);
}
{
std::string const fes_file_name(this->output_prefix +
((comm != single_replica) ? ".partial" : "") +
(dump_fes_save ?
"."+cvm::to_str(cvm::step_absolute()) : "") +
".pmf");
- cvm::backup_file(fes_file_name.c_str());
- cvm::ofstream fes_os(fes_file_name.c_str());
- pmf->write_multicol(fes_os);
- fes_os.close();
+ cvm::proxy->backup_file(fes_file_name);
+ std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name);
+ pmf->write_multicol(*fes_os);
+ cvm::proxy->close_output_stream(fes_file_name);
}
}
+
if (comm != single_replica) {
// output the combined PMF from all replicas
pmf->reset();
pmf->add_grid(*hills_energy);
for (size_t ir = 0; ir < replicas.size(); ir++) {
pmf->add_grid(*(replicas[ir]->hills_energy));
}
cvm::real const max = pmf->maximum_value();
pmf->add_constant(-1.0 * max);
pmf->multiply_constant(-1.0);
if (well_tempered) {
cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature;
pmf->multiply_constant(well_temper_scale);
}
std::string const fes_file_name(this->output_prefix +
(dump_fes_save ?
"."+cvm::to_str(cvm::step_absolute()) : "") +
".pmf");
- cvm::backup_file(fes_file_name.c_str());
- cvm::ofstream fes_os(fes_file_name.c_str());
- pmf->write_multicol(fes_os);
- fes_os.close();
+ cvm::proxy->backup_file(fes_file_name);
+ std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name);
+ pmf->write_multicol(*fes_os);
+ cvm::proxy->close_output_stream(fes_file_name);
}
delete pmf;
}
int colvarbias_meta::write_replica_state_file()
{
if (cvm::debug()) {
cvm::log("Writing replica state file for bias \""+name+"\"\n");
}
// write down also the restart for the other replicas
cvm::backup_file(replica_state_file.c_str());
std::ostream *rep_state_os = cvm::proxy->output_stream(replica_state_file);
if (rep_state_os == NULL) {
cvm::error("Error: in opening file \""+
replica_state_file+"\" for writing.\n", FILE_ERROR);
return FILE_ERROR;
}
rep_state_os->setf(std::ios::scientific, std::ios::floatfield);
if (!write_state(*rep_state_os)) {
cvm::error("Error: in writing to file \""+
replica_state_file+"\".\n", FILE_ERROR);
cvm::proxy->close_output_stream(replica_state_file);
return FILE_ERROR;
}
cvm::proxy->close_output_stream(replica_state_file);
// rep_state_os.setf(std::ios::scientific, std::ios::floatfield);
// rep_state_os << "\n"
// << "metadynamics {\n"
// << " configuration {\n"
// << " name " << this->name << "\n"
// << " step " << cvm::step_absolute() << "\n";
// if (this->comm != single_replica) {
// rep_state_os << " replicaID " << this->replica_id << "\n";
// }
// rep_state_os << " }\n\n";
// rep_state_os << " hills_energy\n";
// rep_state_os << std::setprecision(cvm::cv_prec)
// << std::setw(cvm::cv_width);
// hills_energy->write_restart(rep_state_os);
// rep_state_os << " hills_energy_gradients\n";
// rep_state_os << std::setprecision(cvm::cv_prec)
// << std::setw(cvm::cv_width);
// hills_energy_gradients->write_restart(rep_state_os);
// if ( (!use_grids) || keep_hills ) {
// // write all hills currently in memory
// for (std::list<hill>::const_iterator h = this->hills.begin();
// h != this->hills.end();
// h++) {
// rep_state_os << *h;
// }
// } else {
// // write just those that are near the grid boundaries
// for (std::list<hill>::const_iterator h = this->hills_off_grid.begin();
// h != this->hills_off_grid.end();
// h++) {
// rep_state_os << *h;
// }
// }
// rep_state_os << "}\n\n";
// rep_state_os.close();
// reopen the hills file
- replica_hills_os.close();
- cvm::backup_file(replica_hills_file.c_str());
- replica_hills_os.open(replica_hills_file.c_str());
- if (!replica_hills_os.is_open())
- cvm::fatal_error("Error: in opening file \""+
- replica_hills_file+"\" for writing.\n");
- replica_hills_os.setf(std::ios::scientific, std::ios::floatfield);
+ cvm::proxy->close_output_stream(replica_hills_file);
+ cvm::proxy->backup_file(replica_hills_file);
+ replica_hills_os = cvm::proxy->output_stream(replica_hills_file);
+ if (!replica_hills_os) return cvm::get_error();
+ replica_hills_os->setf(std::ios::scientific, std::ios::floatfield);
return COLVARS_OK;
}
std::string colvarbias_meta::hill::output_traj()
{
std::ostringstream os;
os.setf(std::ios::fixed, std::ios::floatfield);
os << std::setw(cvm::it_width) << it << " ";
os.setf(std::ios::scientific, std::ios::floatfield);
size_t i;
os << " ";
for (i = 0; i < centers.size(); i++) {
os << " ";
os << std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width) << centers[i];
}
os << " ";
for (i = 0; i < widths.size(); i++) {
os << " ";
os << std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width) << widths[i];
}
os << " ";
os << std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << W << "\n";
return os.str();
}
std::ostream & operator << (std::ostream &os, colvarbias_meta::hill const &h)
{
os.setf(std::ios::scientific, std::ios::floatfield);
os << "hill {\n";
os << " step " << std::setw(cvm::it_width) << h.it << "\n";
os << " weight "
<< std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width)
<< h.W << "\n";
if (h.replica.size())
os << " replicaID " << h.replica << "\n";
size_t i;
os << " centers ";
for (i = 0; i < (h.centers).size(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< h.centers[i];
}
os << "\n";
os << " widths ";
for (i = 0; i < (h.widths).size(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec)
<< std::setw(cvm::cv_width)
<< h.widths[i];
}
os << "\n";
os << "}\n";
return os;
}
diff --git a/lib/colvars/colvarbias_meta.h b/lib/colvars/colvarbias_meta.h
index 01921eaf6..249f7342b 100644
--- a/lib/colvars/colvarbias_meta.h
+++ b/lib/colvars/colvarbias_meta.h
@@ -1,439 +1,442 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARBIAS_META_H
#define COLVARBIAS_META_H
#include <vector>
#include <list>
#include <sstream>
#include <fstream>
#include "colvarbias.h"
#include "colvargrid.h"
/// Metadynamics bias (implementation of \link colvarbias \endlink)
class colvarbias_meta : public colvarbias {
public:
/// Communication between different replicas
enum Communication {
/// One replica (default)
single_replica,
/// Hills added concurrently by several replicas
multiple_replicas
};
/// Communication between different replicas
Communication comm;
colvarbias_meta(char const *key);
virtual int init(std::string const &conf);
virtual int init_well_tempered_params(std::string const &conf);
virtual int init_ebmeta_params(std::string const &conf);
virtual ~colvarbias_meta();
virtual int update();
virtual int update_grid_params();
virtual int update_bias();
virtual int update_grid_data();
virtual int replica_share();
virtual int calc_energy(std::vector<colvarvalue> const &values =
std::vector<colvarvalue>(0));
virtual int calc_forces(std::vector<colvarvalue> const &values =
std::vector<colvarvalue>(0));
virtual std::string const get_state_params() const;
virtual int set_state_params(std::string const &state_conf);
virtual std::ostream & write_state_data(std::ostream &os);
virtual std::istream & read_state_data(std::istream &os);
virtual int setup_output();
virtual int write_output_files();
virtual void write_pmf();
virtual int write_state_to_replicas();
class hill;
typedef std::list<hill>::iterator hill_iter;
protected:
/// \brief width of a hill
///
/// The local width of each collective variable, multiplied by this
/// number, provides the hill width along that direction
cvm::real hill_width;
/// \brief Number of simulation steps between two hills
size_t new_hill_freq;
/// Write the hill logfile
bool b_hills_traj;
/// Logfile of hill management (creation and deletion)
- cvm::ofstream hills_traj_os;
+ std::ostream *hills_traj_os;
+
+ /// Name of the hill logfile
+ std::string const hills_traj_file_name() const;
/// \brief List of hills used on this bias (total); if a grid is
/// employed, these don't need to be updated at every time step
std::list<hill> hills;
/// \brief Iterator to the first of the "newest" hills (when using
/// grids, those who haven't been mapped yet)
hill_iter new_hills_begin;
/// \brief List of hills used on this bias that are on the boundary
/// edges; these are updated regardless of whether hills are used
std::list<hill> hills_off_grid;
/// \brief Same as new_hills_begin, but for the off-grid ones
hill_iter new_hills_off_grid_begin;
/// Regenerate the hills_off_grid list
void recount_hills_off_grid(hill_iter h_first, hill_iter h_last,
colvar_grid_scalar *ge);
/// Read a hill from a file
std::istream & read_hill(std::istream &is);
/// \brief Add a new hill; if a .hills trajectory is written,
/// write it there; if there is more than one replica, communicate
/// it to the others
virtual std::list<hill>::const_iterator create_hill(hill const &h);
/// \brief Remove a previously saved hill (returns an iterator for
/// the next hill in the list)
virtual std::list<hill>::const_iterator delete_hill(hill_iter &h);
/// \brief Calculate the values of the hills, incrementing
/// bias_energy
virtual void calc_hills(hill_iter h_first,
hill_iter h_last,
cvm::real &energy,
std::vector<colvarvalue> const &values = std::vector<colvarvalue>(0));
/// \brief Calculate the forces acting on the i-th colvar,
/// incrementing colvar_forces[i]; must be called after calc_hills
/// each time the values of the colvars are changed
virtual void calc_hills_force(size_t const &i,
hill_iter h_first,
hill_iter h_last,
std::vector<colvarvalue> &forces,
std::vector<colvarvalue> const &values = std::vector<colvarvalue>(0));
/// Height of new hills
cvm::real hill_weight;
/// \brief Bin the hills on grids of energy and forces, and use them
/// to force the colvars (as opposed to deriving the hills analytically)
bool use_grids;
/// \brief Rebin the hills upon restarting
bool rebin_grids;
/// \brief Should the grids be expanded if necessary?
bool expand_grids;
/// \brief How often the hills should be projected onto the grids
size_t grids_freq;
/// \brief Whether to keep the hills in the restart file (e.g. to do
/// meaningful accurate rebinning afterwards)
bool keep_hills;
/// \brief Dump the free energy surface (.pmf file) every restartFrequency
bool dump_fes;
/// \brief Dump the free energy surface (.pmf file) every restartFrequency
/// using only the hills from this replica (only applicable to more than one replica)
bool dump_replica_fes;
/// \brief Dump the free energy surface files at different
/// time steps, appending the step number to each file
bool dump_fes_save;
/// \brief Whether to use well-tempered metadynamics
bool well_tempered;
/// \brief Biasing temperature in well-tempered metadynamics
cvm::real bias_temperature;
// EBmeta parameters
bool ebmeta;
colvar_grid_scalar* target_dist;
std::string target_dist_file;
cvm::real target_dist_volume;
size_t ebmeta_equil_steps;
/// \brief Try to read the restart information by allocating new
/// grids before replacing the current ones (used e.g. in
/// multiple_replicas)
bool safely_read_restart;
/// Hill energy, cached on a grid
colvar_grid_scalar *hills_energy;
/// Hill forces, cached on a grid
colvar_grid_gradient *hills_energy_gradients;
/// \brief Project the selected hills onto grids
void project_hills(hill_iter h_first, hill_iter h_last,
colvar_grid_scalar *ge, colvar_grid_gradient *gf,
bool print_progress = false);
// Multiple Replicas variables and functions
/// \brief Identifier for this replica
std::string replica_id;
/// \brief File containing the paths to the output files from this replica
std::string replica_file_name;
/// \brief Read the existing replicas on registry
virtual void update_replicas_registry();
/// \brief Read new data from replicas' files
virtual void read_replica_files();
/// \brief Write data to other replicas
virtual int write_replica_state_file();
/// \brief Additional, "mirror" metadynamics biases, to collect info
/// from the other replicas
///
/// These are supposed to be synchronized by reading data from the
/// other replicas, and not be modified by the "local" replica
std::vector<colvarbias_meta *> replicas;
/// \brief Frequency at which data the "mirror" biases are updated
size_t replica_update_freq;
/// List of replicas (and their output list files): contents are
/// copied into replicas_registry for convenience
std::string replicas_registry_file;
/// List of replicas (and their output list files)
std::string replicas_registry;
/// List of files written by this replica
std::string replica_list_file;
/// Hills energy and gradients written specifically for other
/// replica (in addition to its own restart file)
std::string replica_state_file;
/// Whether a mirror bias has read the latest version of its state file
bool replica_state_file_in_sync;
/// If there was a failure reading one of the files (because they
/// are not complete), this counter is incremented
size_t update_status;
/// Explicit hills communicated between replicas
///
/// This file becomes empty after replica_state_file is rewritten
std::string replica_hills_file;
/// \brief Output stream corresponding to replica_hills_file
- cvm::ofstream replica_hills_os;
+ std::ostream *replica_hills_os;
/// Position within replica_hills_file (when reading it)
int replica_hills_file_pos;
};
/// \brief A hill for the metadynamics bias
class colvarbias_meta::hill {
protected:
/// Value of the hill function (ranges between 0 and 1)
cvm::real hill_value;
/// Scale factor, which could be modified at runtime (default: 1)
cvm::real sW;
/// Maximum height in energy of the hill
cvm::real W;
/// Center of the hill in the collective variable space
std::vector<colvarvalue> centers;
/// Widths of the hill in the collective variable space
std::vector<cvm::real> widths;
public:
friend class colvarbias_meta;
/// Time step at which this hill was added
size_t it;
/// Identity of the replica who added this hill (only in multiple replica simulations)
std::string replica;
/// \brief Runtime constructor: data are read directly from
/// collective variables \param weight Weight of the hill \param
/// cv Pointer to the array of collective variables involved \param
/// replica (optional) Identity of the replica which creates the
/// hill
inline hill(cvm::real const &W_in,
std::vector<colvar *> &cv,
cvm::real const &hill_width,
std::string const &replica_in = "")
: sW(1.0),
W(W_in),
centers(cv.size()),
widths(cv.size()),
it(cvm::step_absolute()),
replica(replica_in)
{
for (size_t i = 0; i < cv.size(); i++) {
centers[i].type(cv[i]->value());
centers[i] = cv[i]->value();
widths[i] = cv[i]->width * hill_width;
}
if (cvm::debug())
cvm::log("New hill, applied to "+cvm::to_str(cv.size())+
" collective variables, with centers "+
cvm::to_str(centers)+", widths "+
cvm::to_str(widths)+" and weight "+
cvm::to_str(W)+".\n");
}
/// \brief General constructor: all data are explicitly passed as
/// arguments (used for instance when reading hills saved on a
/// file) \param it Time step of creation of the hill \param
/// weight Weight of the hill \param centers Center of the hill
/// \param widths Width of the hill around centers \param replica
/// (optional) Identity of the replica which creates the hill
inline hill(size_t const &it_in,
cvm::real const &W_in,
std::vector<colvarvalue> const &centers_in,
std::vector<cvm::real> const &widths_in,
std::string const &replica_in = "")
: sW(1.0),
W(W_in),
centers(centers_in),
widths(widths_in),
it(it_in),
replica(replica_in)
{}
/// Copy constructor
inline hill(colvarbias_meta::hill const &h)
: sW(1.0),
W(h.W),
centers(h.centers),
widths(h.widths),
it(h.it),
replica(h.replica)
{}
/// Destructor
inline ~hill()
{}
/// Get the energy
inline cvm::real energy()
{
return W * sW * hill_value;
}
/// Get the energy using another hill weight
inline cvm::real energy(cvm::real const &new_weight)
{
return new_weight * sW * hill_value;
}
/// Get the current hill value
inline cvm::real const &value()
{
return hill_value;
}
/// Set the hill value as specified
inline void value(cvm::real const &new_value)
{
hill_value = new_value;
}
/// Get the weight
inline cvm::real weight()
{
return W * sW;
}
/// Scale the weight with this factor (by default 1.0 is used)
inline void scale(cvm::real const &new_scale_fac)
{
sW = new_scale_fac;
}
/// Get the center of the hill
inline std::vector<colvarvalue> & center()
{
return centers;
}
/// Get the i-th component of the center
inline colvarvalue & center(size_t const &i)
{
return centers[i];
}
/// Comparison operator
inline friend bool operator < (hill const &h1, hill const &h2)
{
if (h1.it < h2.it) return true;
else return false;
}
/// Comparison operator
inline friend bool operator <= (hill const &h1, hill const &h2)
{
if (h1.it <= h2.it) return true;
else return false;
}
/// Comparison operator
inline friend bool operator > (hill const &h1, hill const &h2)
{
if (h1.it > h2.it) return true;
else return false;
}
/// Comparison operator
inline friend bool operator >= (hill const &h1, hill const &h2)
{
if (h1.it >= h2.it) return true;
else return false;
}
/// Comparison operator
inline friend bool operator == (hill const &h1, hill const &h2)
{
if ( (h1.it >= h2.it) && (h1.replica == h2.replica) ) return true;
else return false;
}
/// Represent the hill ina string suitable for a trajectory file
std::string output_traj();
/// Write the hill to an output stream
inline friend std::ostream & operator << (std::ostream &os,
hill const &h);
};
#endif
diff --git a/lib/colvars/colvarbias_restraint.cpp b/lib/colvars/colvarbias_restraint.cpp
index 159d9eae6..bb6d6164e 100644
--- a/lib/colvars/colvarbias_restraint.cpp
+++ b/lib/colvars/colvarbias_restraint.cpp
@@ -1,1433 +1,1449 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarbias_restraint.h"
colvarbias_restraint::colvarbias_restraint(char const *key)
: colvarbias(key)
{
}
int colvarbias_restraint::init(std::string const &conf)
{
colvarbias::init(conf);
enable(f_cvb_apply_force);
if (cvm::debug())
cvm::log("Initializing a new restraint bias.\n");
return COLVARS_OK;
}
int colvarbias_restraint::update()
{
// Update base class (bias_energy and colvar_forces are zeroed there)
colvarbias::update();
// Force and energy calculation
for (size_t i = 0; i < num_variables(); i++) {
bias_energy += restraint_potential(i);
colvar_forces[i].type(variables(i)->value());
colvar_forces[i].is_derivative();
colvar_forces[i] = restraint_force(i);
}
if (cvm::debug())
cvm::log("Done updating the restraint bias \""+this->name+"\".\n");
if (cvm::debug())
cvm::log("Current forces for the restraint bias \""+
this->name+"\": "+cvm::to_str(colvar_forces)+".\n");
return COLVARS_OK;
}
colvarbias_restraint::~colvarbias_restraint()
{
}
std::string const colvarbias_restraint::get_state_params() const
{
return colvarbias::get_state_params();
}
int colvarbias_restraint::set_state_params(std::string const &conf)
{
return colvarbias::set_state_params(conf);
}
std::ostream & colvarbias_restraint::write_traj_label(std::ostream &os)
{
return colvarbias::write_traj_label(os);
}
std::ostream & colvarbias_restraint::write_traj(std::ostream &os)
{
return colvarbias::write_traj(os);
}
colvarbias_restraint_centers::colvarbias_restraint_centers(char const *key)
: colvarbias(key), colvarbias_restraint(key)
{
}
int colvarbias_restraint_centers::init(std::string const &conf)
{
size_t i;
bool null_centers = (colvar_centers.size() == 0);
if (null_centers) {
// try to initialize the restraint centers for the first time
colvar_centers.resize(num_variables());
colvar_centers_raw.resize(num_variables());
for (i = 0; i < num_variables(); i++) {
colvar_centers[i].type(variables(i)->value());
colvar_centers[i].reset();
colvar_centers_raw[i].type(variables(i)->value());
colvar_centers_raw[i].reset();
}
}
if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
for (i = 0; i < num_variables(); i++) {
if (cvm::debug()) {
cvm::log("colvarbias_restraint: parsing initial centers, i = "+cvm::to_str(i)+".\n");
}
colvar_centers_raw[i] = colvar_centers[i];
colvar_centers[i].apply_constraints();
}
null_centers = false;
}
if (null_centers) {
colvar_centers.clear();
cvm::error("Error: must define the initial centers of the restraints.\n", INPUT_ERROR);
return INPUT_ERROR;
}
if (colvar_centers.size() != num_variables()) {
cvm::error("Error: number of centers does not match "
"that of collective variables.\n", INPUT_ERROR);
return INPUT_ERROR;
}
return COLVARS_OK;
}
int colvarbias_restraint_centers::change_configuration(std::string const &conf)
{
if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
for (size_t i = 0; i < num_variables(); i++) {
colvar_centers[i].type(variables(i)->value());
colvar_centers[i].apply_constraints();
colvar_centers_raw[i].type(variables(i)->value());
colvar_centers_raw[i] = colvar_centers[i];
}
}
return COLVARS_OK;
}
colvarbias_restraint_k::colvarbias_restraint_k(char const *key)
: colvarbias(key), colvarbias_restraint(key)
{
force_k = -1.0;
}
int colvarbias_restraint_k::init(std::string const &conf)
{
get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0));
if (force_k < 0.0) {
cvm::error("Error: undefined or invalid force constant.\n", INPUT_ERROR);
return INPUT_ERROR;
}
return COLVARS_OK;
}
int colvarbias_restraint_k::change_configuration(std::string const &conf)
{
get_keyval(conf, "forceConstant", force_k, force_k);
return COLVARS_OK;
}
colvarbias_restraint_moving::colvarbias_restraint_moving(char const *key)
{
target_nstages = 0;
target_nsteps = 0;
stage = 0;
b_chg_centers = false;
b_chg_force_k = false;
}
int colvarbias_restraint_moving::init(std::string const &conf)
{
if (b_chg_centers && b_chg_force_k) {
cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
if (b_chg_centers || b_chg_force_k) {
get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps);
if (!target_nsteps) {
cvm::error("Error: targetNumSteps must be non-zero.\n", INPUT_ERROR);
return cvm::get_error();
}
if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) &&
lambda_schedule.size()) {
cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR);
return cvm::get_error();
}
}
return COLVARS_OK;
}
std::string const colvarbias_restraint_moving::get_state_params() const
{
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
if (b_chg_centers || b_chg_force_k) {
// TODO move this
if (target_nstages) {
os << "stage " << std::setw(cvm::it_width)
<< stage << "\n";
}
}
return os.str();
}
int colvarbias_restraint_moving::set_state_params(std::string const &conf)
{
if (b_chg_centers || b_chg_force_k) {
if (target_nstages) {
// cvm::log ("Reading current stage from the restart.\n");
if (!get_keyval(conf, "stage", stage))
cvm::error("Error: current stage is missing from the restart.\n");
}
}
return COLVARS_OK;
}
colvarbias_restraint_centers_moving::colvarbias_restraint_centers_moving(char const *key)
: colvarbias(key),
colvarbias_restraint(key),
colvarbias_restraint_centers(key),
colvarbias_restraint_moving(key)
{
b_chg_centers = false;
b_output_centers = false;
b_output_acc_work = false;
acc_work = 0.0;
}
int colvarbias_restraint_centers_moving::init(std::string const &conf)
{
colvarbias_restraint_centers::init(conf);
if (cvm::debug()) {
cvm::log("colvarbias_restraint: parsing target centers.\n");
}
size_t i;
if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) {
if (colvar_centers.size() != num_variables()) {
cvm::error("Error: number of target centers does not match "
"that of collective variables.\n");
}
b_chg_centers = true;
for (i = 0; i < target_centers.size(); i++) {
target_centers[i].apply_constraints();
}
}
if (b_chg_centers) {
// parse moving restraint options
colvarbias_restraint_moving::init(conf);
} else {
target_centers.clear();
return COLVARS_OK;
}
get_keyval(conf, "outputCenters", b_output_centers, b_output_centers);
get_keyval(conf, "outputAccumulatedWork", b_output_acc_work, b_output_acc_work);
return COLVARS_OK;
}
int colvarbias_restraint_centers_moving::update()
{
if (b_chg_centers) {
if (cvm::debug()) {
cvm::log("Updating centers for the restraint bias \""+
this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
}
if (!centers_incr.size()) {
// if this is the first calculation, calculate the advancement
// at each simulation step (or stage, if applicable)
// (take current stage into account: it can be non-zero
// if we are restarting a staged calculation)
centers_incr.resize(num_variables());
for (size_t i = 0; i < num_variables(); i++) {
centers_incr[i].type(variables(i)->value());
centers_incr[i] = (target_centers[i] - colvar_centers_raw[i]) /
cvm::real( target_nstages ? (target_nstages - stage) :
(target_nsteps - cvm::step_absolute()));
}
if (cvm::debug()) {
cvm::log("Center increment for the restraint bias \""+
this->name+"\": "+cvm::to_str(centers_incr)+" at stage "+cvm::to_str(stage)+ ".\n");
}
}
if (target_nstages) {
if ((cvm::step_relative() > 0)
&& (cvm::step_absolute() % target_nsteps) == 0
&& stage < target_nstages) {
for (size_t i = 0; i < num_variables(); i++) {
colvar_centers_raw[i] += centers_incr[i];
colvar_centers[i] = colvar_centers_raw[i];
variables(i)->wrap(colvar_centers[i]);
colvar_centers[i].apply_constraints();
}
stage++;
cvm::log("Moving restraint \"" + this->name +
"\" stage " + cvm::to_str(stage) +
" : setting centers to " + cvm::to_str(colvar_centers) +
" at step " + cvm::to_str(cvm::step_absolute()));
}
} else if ((cvm::step_relative() > 0) && (cvm::step_absolute() <= target_nsteps)) {
// move the restraint centers in the direction of the targets
// (slow growth)
for (size_t i = 0; i < num_variables(); i++) {
colvar_centers_raw[i] += centers_incr[i];
colvar_centers[i] = colvar_centers_raw[i];
variables(i)->wrap(colvar_centers[i]);
colvar_centers[i].apply_constraints();
}
}
if (cvm::debug()) {
cvm::log("New centers for the restraint bias \""+
this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
}
}
return COLVARS_OK;
}
int colvarbias_restraint_centers_moving::update_acc_work()
{
if (b_output_acc_work) {
if ((cvm::step_relative() > 0) || (cvm::step_absolute() == 0)) {
for (size_t i = 0; i < num_variables(); i++) {
// project forces on the calculated increments at this step
acc_work += colvar_forces[i] * centers_incr[i];
}
}
}
return COLVARS_OK;
}
std::string const colvarbias_restraint_centers_moving::get_state_params() const
{
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
if (b_chg_centers) {
size_t i;
os << "centers ";
for (i = 0; i < num_variables(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< colvar_centers[i];
}
os << "\n";
os << "centers_raw ";
for (i = 0; i < num_variables(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< colvar_centers_raw[i];
}
os << "\n";
if (b_output_acc_work) {
os << "accumulatedWork "
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
<< acc_work << "\n";
}
}
return colvarbias_restraint_moving::get_state_params() + os.str();
}
int colvarbias_restraint_centers_moving::set_state_params(std::string const &conf)
{
colvarbias_restraint::set_state_params(conf);
if (b_chg_centers) {
// cvm::log ("Reading the updated restraint centers from the restart.\n");
if (!get_keyval(conf, "centers", colvar_centers))
cvm::error("Error: restraint centers are missing from the restart.\n");
if (!get_keyval(conf, "centers_raw", colvar_centers_raw))
cvm::error("Error: \"raw\" restraint centers are missing from the restart.\n");
if (b_output_acc_work) {
if (!get_keyval(conf, "accumulatedWork", acc_work))
cvm::error("Error: accumulatedWork is missing from the restart.\n");
}
}
return COLVARS_OK;
}
std::ostream & colvarbias_restraint_centers_moving::write_traj_label(std::ostream &os)
{
if (b_output_centers) {
for (size_t i = 0; i < num_variables(); i++) {
size_t const this_cv_width = (variables(i)->value()).output_width(cvm::cv_width);
os << " x0_"
<< cvm::wrap_string(variables(i)->name, this_cv_width-3);
}
}
if (b_output_acc_work) {
os << " W_"
<< cvm::wrap_string(this->name, cvm::en_width-2);
}
return os;
}
std::ostream & colvarbias_restraint_centers_moving::write_traj(std::ostream &os)
{
if (b_output_centers) {
for (size_t i = 0; i < num_variables(); i++) {
os << " "
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
<< colvar_centers[i];
}
}
if (b_output_acc_work) {
os << " "
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
<< acc_work;
}
return os;
}
colvarbias_restraint_k_moving::colvarbias_restraint_k_moving(char const *key)
: colvarbias(key),
colvarbias_restraint(key),
colvarbias_restraint_k(key),
colvarbias_restraint_moving(key)
{
b_chg_force_k = false;
target_equil_steps = 0;
target_force_k = 0.0;
starting_force_k = 0.0;
force_k_exp = 1.0;
restraint_FE = 0.0;
}
int colvarbias_restraint_k_moving::init(std::string const &conf)
{
colvarbias_restraint_k::init(conf);
if (get_keyval(conf, "targetForceConstant", target_force_k, target_force_k)) {
starting_force_k = force_k;
b_chg_force_k = true;
}
if (b_chg_force_k) {
// parse moving restraint options
colvarbias_restraint_moving::init(conf);
} else {
return COLVARS_OK;
}
get_keyval(conf, "targetEquilSteps", target_equil_steps, target_equil_steps);
if (get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule) &&
target_nstages > 0) {
cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR);
return cvm::get_error();
}
if (lambda_schedule.size()) {
// There is one more lambda-point than stages
target_nstages = lambda_schedule.size() - 1;
}
if (get_keyval(conf, "targetForceExponent", force_k_exp, force_k_exp)) {
if (! b_chg_force_k)
cvm::log("Warning: not changing force constant: targetForceExponent will be ignored\n");
}
if (force_k_exp < 1.0) {
cvm::log("Warning: for all practical purposes, targetForceExponent should be 1.0 or greater.\n");
}
return COLVARS_OK;
}
int colvarbias_restraint_k_moving::update()
{
if (b_chg_force_k) {
cvm::real lambda;
if (target_nstages) {
if (cvm::step_absolute() == 0) {
// Setup first stage of staged variable force constant calculation
if (lambda_schedule.size()) {
lambda = lambda_schedule[0];
} else {
lambda = 0.0;
}
force_k = starting_force_k + (target_force_k - starting_force_k)
* std::pow(lambda, force_k_exp);
cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
+ " : lambda = " + cvm::to_str(lambda)
+ ", k = " + cvm::to_str(force_k));
}
// TI calculation: estimate free energy derivative
// need current lambda
if (lambda_schedule.size()) {
lambda = lambda_schedule[stage];
} else {
lambda = cvm::real(stage) / cvm::real(target_nstages);
}
if (target_equil_steps == 0 || cvm::step_absolute() % target_nsteps >= target_equil_steps) {
// Start averaging after equilibration period, if requested
// Square distance normalized by square colvar width
cvm::real dist_sq = 0.0;
for (size_t i = 0; i < num_variables(); i++) {
dist_sq += d_restraint_potential_dk(i);
}
restraint_FE += 0.5 * force_k_exp * std::pow(lambda, force_k_exp - 1.0)
* (target_force_k - starting_force_k) * dist_sq;
}
// Finish current stage...
if (cvm::step_absolute() % target_nsteps == 0 &&
cvm::step_absolute() > 0) {
cvm::log("Restraint " + this->name + " Lambda= "
+ cvm::to_str(lambda) + " dA/dLambda= "
+ cvm::to_str(restraint_FE / cvm::real(target_nsteps - target_equil_steps)));
// ...and move on to the next one
if (stage < target_nstages) {
restraint_FE = 0.0;
stage++;
if (lambda_schedule.size()) {
lambda = lambda_schedule[stage];
} else {
lambda = cvm::real(stage) / cvm::real(target_nstages);
}
force_k = starting_force_k + (target_force_k - starting_force_k)
* std::pow(lambda, force_k_exp);
cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
+ " : lambda = " + cvm::to_str(lambda)
+ ", k = " + cvm::to_str(force_k));
}
}
} else if (cvm::step_absolute() <= target_nsteps) {
// update force constant (slow growth)
lambda = cvm::real(cvm::step_absolute()) / cvm::real(target_nsteps);
force_k = starting_force_k + (target_force_k - starting_force_k)
* std::pow(lambda, force_k_exp);
}
}
return COLVARS_OK;
}
std::string const colvarbias_restraint_k_moving::get_state_params() const
{
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
if (b_chg_force_k) {
os << "forceConstant "
<< std::setprecision(cvm::en_prec)
<< std::setw(cvm::en_width) << force_k << "\n";
}
return colvarbias_restraint_moving::get_state_params() + os.str();
}
int colvarbias_restraint_k_moving::set_state_params(std::string const &conf)
{
colvarbias_restraint::set_state_params(conf);
if (b_chg_force_k) {
// cvm::log ("Reading the updated force constant from the restart.\n");
if (!get_keyval(conf, "forceConstant", force_k, force_k))
cvm::error("Error: force constant is missing from the restart.\n");
}
return COLVARS_OK;
}
std::ostream & colvarbias_restraint_k_moving::write_traj_label(std::ostream &os)
{
return os;
}
std::ostream & colvarbias_restraint_k_moving::write_traj(std::ostream &os)
{
return os;
}
// redefined due to legacy state file keyword "harmonic"
std::istream & colvarbias_restraint::read_state(std::istream &is)
{
size_t const start_pos = is.tellg();
std::string key, brace, conf;
if ( !(is >> key) || !(key == "restraint" || key == "harmonic") ||
!(is >> brace) || !(brace == "{") ||
!(is >> colvarparse::read_block("configuration", conf)) ||
(set_state_params(conf) != COLVARS_OK) ) {
cvm::error("Error: in reading state configuration for \""+bias_type+"\" bias \""+
this->name+"\" at position "+
cvm::to_str(is.tellg())+" in stream.\n", INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
if (!read_state_data(is)) {
cvm::error("Error: in reading state data for \""+bias_type+"\" bias \""+
this->name+"\" at position "+
cvm::to_str(is.tellg())+" in stream.\n", INPUT_ERROR);
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
}
is >> brace;
if (brace != "}") {
cvm::log("brace = "+brace+"\n");
cvm::error("Error: corrupt restart information for \""+bias_type+"\" bias \""+
this->name+"\": no matching brace at position "+
cvm::to_str(is.tellg())+" in stream.\n");
is.setstate(std::ios::failbit);
}
return is;
}
std::ostream & colvarbias_restraint::write_state(std::ostream &os)
{
os.setf(std::ios::scientific, std::ios::floatfield);
os << "restraint {\n"
<< " configuration {\n";
std::istringstream is(get_state_params());
std::string line;
while (std::getline(is, line)) {
os << " " << line << "\n";
}
os << " }\n";
write_state_data(os);
os << "}\n\n";
return os;
}
colvarbias_restraint_harmonic::colvarbias_restraint_harmonic(char const *key)
: colvarbias(key),
colvarbias_restraint(key),
colvarbias_restraint_centers(key),
colvarbias_restraint_moving(key),
colvarbias_restraint_k(key),
colvarbias_restraint_centers_moving(key),
colvarbias_restraint_k_moving(key)
{
}
int colvarbias_restraint_harmonic::init(std::string const &conf)
{
colvarbias_restraint::init(conf);
colvarbias_restraint_moving::init(conf);
colvarbias_restraint_centers_moving::init(conf);
colvarbias_restraint_k_moving::init(conf);
for (size_t i = 0; i < num_variables(); i++) {
if (variables(i)->width != 1.0)
cvm::log("The force constant for colvar \""+variables(i)->name+
"\" will be rescaled to "+
cvm::to_str(force_k / (variables(i)->width * variables(i)->width))+
" according to the specified width.\n");
}
return COLVARS_OK;
}
int colvarbias_restraint_harmonic::update()
{
// update parameters (centers or force constant)
colvarbias_restraint_centers_moving::update();
colvarbias_restraint_k_moving::update();
// update restraint energy and forces
colvarbias_restraint::update();
// update accumulated work using the current forces
colvarbias_restraint_centers_moving::update_acc_work();
return COLVARS_OK;
}
cvm::real colvarbias_restraint_harmonic::restraint_potential(size_t i) const
{
return 0.5 * force_k / (variables(i)->width * variables(i)->width) *
variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
}
colvarvalue const colvarbias_restraint_harmonic::restraint_force(size_t i) const
{
return -0.5 * force_k / (variables(i)->width * variables(i)->width) *
variables(i)->dist2_lgrad(variables(i)->value(), colvar_centers[i]);
}
cvm::real colvarbias_restraint_harmonic::d_restraint_potential_dk(size_t i) const
{
return 0.5 / (variables(i)->width * variables(i)->width) *
variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
}
std::string const colvarbias_restraint_harmonic::get_state_params() const
{
return colvarbias_restraint::get_state_params() +
colvarbias_restraint_centers_moving::get_state_params() +
colvarbias_restraint_k_moving::get_state_params();
}
int colvarbias_restraint_harmonic::set_state_params(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= colvarbias_restraint::set_state_params(conf);
error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
return error_code;
}
std::ostream & colvarbias_restraint_harmonic::write_traj_label(std::ostream &os)
{
colvarbias_restraint::write_traj_label(os);
colvarbias_restraint_centers_moving::write_traj_label(os);
colvarbias_restraint_k_moving::write_traj_label(os);
return os;
}
std::ostream & colvarbias_restraint_harmonic::write_traj(std::ostream &os)
{
colvarbias_restraint::write_traj(os);
colvarbias_restraint_centers_moving::write_traj(os);
colvarbias_restraint_k_moving::write_traj(os);
return os;
}
int colvarbias_restraint_harmonic::change_configuration(std::string const &conf)
{
return colvarbias_restraint_centers::change_configuration(conf) |
colvarbias_restraint_k::change_configuration(conf);
}
cvm::real colvarbias_restraint_harmonic::energy_difference(std::string const &conf)
{
cvm::real const old_bias_energy = bias_energy;
cvm::real const old_force_k = force_k;
std::vector<colvarvalue> const old_centers = colvar_centers;
change_configuration(conf);
update();
cvm::real const result = (bias_energy - old_bias_energy);
bias_energy = old_bias_energy;
force_k = old_force_k;
colvar_centers = old_centers;
return result;
}
colvarbias_restraint_harmonic_walls::colvarbias_restraint_harmonic_walls(char const *key)
: colvarbias(key),
colvarbias_restraint(key),
colvarbias_restraint_k(key),
colvarbias_restraint_moving(key),
colvarbias_restraint_k_moving(key)
{
lower_wall_k = 0.0;
upper_wall_k = 0.0;
}
int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
{
colvarbias_restraint::init(conf);
colvarbias_restraint_moving::init(conf);
colvarbias_restraint_k_moving::init(conf);
get_keyval(conf, "lowerWallConstant", lower_wall_k,
(lower_wall_k > 0.0) ? lower_wall_k : force_k);
get_keyval(conf, "upperWallConstant", upper_wall_k,
(upper_wall_k > 0.0) ? upper_wall_k : force_k);
+ if (lower_wall_k * upper_wall_k > 0.0) {
+ for (size_t i = 0; i < num_variables(); i++) {
+ if (variables(i)->width != 1.0)
+ cvm::log("The lower and upper wall force constants for colvar \""+
+ variables(i)->name+
+ "\" will be rescaled to "+
+ cvm::to_str(lower_wall_k /
+ (variables(i)->width * variables(i)->width))+
+ " and "+
+ cvm::to_str(upper_wall_k /
+ (variables(i)->width * variables(i)->width))+
+ " according to the specified width.\n");
+ }
+ }
+
enable(f_cvb_scalar_variables);
size_t i;
bool b_null_lower_walls = false;
if (lower_walls.size() == 0) {
b_null_lower_walls = true;
lower_walls.resize(num_variables());
for (i = 0; i < num_variables(); i++) {
lower_walls[i].type(variables(i)->value());
lower_walls[i].reset();
}
}
if (!get_keyval(conf, "lowerWalls", lower_walls, lower_walls) &&
b_null_lower_walls) {
cvm::log("Lower walls were not provided.\n");
- lower_walls.resize(0);
+ lower_walls.clear();
}
bool b_null_upper_walls = false;
if (upper_walls.size() == 0) {
b_null_upper_walls = true;
upper_walls.resize(num_variables());
for (i = 0; i < num_variables(); i++) {
upper_walls[i].type(variables(i)->value());
upper_walls[i].reset();
}
}
if (!get_keyval(conf, "upperWalls", upper_walls, upper_walls) &&
b_null_upper_walls) {
cvm::log("Upper walls were not provided.\n");
- upper_walls.resize(0);
+ upper_walls.clear();
}
if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) {
cvm::error("Error: no walls provided.\n", INPUT_ERROR);
return INPUT_ERROR;
}
if ((lower_walls.size() == 0) || (upper_walls.size() == 0)) {
for (i = 0; i < num_variables(); i++) {
if (variables(i)->is_enabled(f_cv_periodic)) {
cvm::error("Error: at least one variable is periodic, "
"both walls must be provided.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
}
if ((lower_walls.size() > 0) && (upper_walls.size() > 0)) {
for (i = 0; i < num_variables(); i++) {
if (lower_walls[i] >= upper_walls[i]) {
cvm::error("Error: one upper wall, "+
cvm::to_str(upper_walls[i])+
", is not higher than the lower wall, "+
cvm::to_str(lower_walls[i])+".\n",
INPUT_ERROR);
}
}
if (lower_wall_k * upper_wall_k == 0.0) {
cvm::error("Error: lowerWallConstant and upperWallConstant, "
"when defined, must both be positive.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
force_k = lower_wall_k * upper_wall_k;
// transform the two constants to relative values
// (allow changing both via force_k)
lower_wall_k /= force_k;
upper_wall_k /= force_k;
}
for (i = 0; i < num_variables(); i++) {
if (variables(i)->width != 1.0)
cvm::log("The force constant for colvar \""+variables(i)->name+
"\" will be rescaled to "+
cvm::to_str(force_k / (variables(i)->width * variables(i)->width))+
" according to the specified width.\n");
}
return COLVARS_OK;
}
int colvarbias_restraint_harmonic_walls::update()
{
colvarbias_restraint_k_moving::update();
colvarbias_restraint::update();
return COLVARS_OK;
}
void colvarbias_restraint_harmonic_walls::communicate_forces()
{
for (size_t i = 0; i < num_variables(); i++) {
if (cvm::debug()) {
cvm::log("Communicating a force to colvar \""+
variables(i)->name+"\".\n");
}
- variables(i)->add_bias_force_actual_value(colvar_forces[i]);
+ // Impulse-style multiple timestep
+ variables(i)->add_bias_force_actual_value(cvm::real(time_step_factor) * colvar_forces[i]);
}
}
cvm::real colvarbias_restraint_harmonic_walls::colvar_distance(size_t i) const
{
colvar *cv = variables(i);
colvarvalue const &cvv = variables(i)->actual_value();
// For a periodic colvar, both walls may be applicable at the same time
// in which case we pick the closer one
if (cv->is_enabled(f_cv_periodic)) {
cvm::real const lower_wall_dist2 = cv->dist2(cvv, lower_walls[i]);
cvm::real const upper_wall_dist2 = cv->dist2(cvv, upper_walls[i]);
if (lower_wall_dist2 < upper_wall_dist2) {
cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
if (grad < 0.0) { return 0.5 * grad; }
} else {
cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
if (grad > 0.0) { return 0.5 * grad; }
}
return 0.0;
}
if (lower_walls.size() > 0) {
cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
if (grad < 0.0) { return 0.5 * grad; }
}
if (upper_walls.size() > 0) {
cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
if (grad > 0.0) { return 0.5 * grad; }
}
return 0.0;
}
cvm::real colvarbias_restraint_harmonic_walls::restraint_potential(size_t i) const
{
cvm::real const dist = colvar_distance(i);
cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
return 0.5 * force_k * scale / (variables(i)->width * variables(i)->width) *
dist * dist;
}
colvarvalue const colvarbias_restraint_harmonic_walls::restraint_force(size_t i) const
{
cvm::real const dist = colvar_distance(i);
cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
return - force_k * scale / (variables(i)->width * variables(i)->width) * dist;
}
cvm::real colvarbias_restraint_harmonic_walls::d_restraint_potential_dk(size_t i) const
{
cvm::real const dist = colvar_distance(i);
cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
return 0.5 * scale / (variables(i)->width * variables(i)->width) *
dist * dist;
}
std::string const colvarbias_restraint_harmonic_walls::get_state_params() const
{
return colvarbias_restraint::get_state_params() +
colvarbias_restraint_k_moving::get_state_params();
}
int colvarbias_restraint_harmonic_walls::set_state_params(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= colvarbias_restraint::set_state_params(conf);
error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
return error_code;
}
std::ostream & colvarbias_restraint_harmonic_walls::write_traj_label(std::ostream &os)
{
colvarbias_restraint::write_traj_label(os);
colvarbias_restraint_k_moving::write_traj_label(os);
return os;
}
std::ostream & colvarbias_restraint_harmonic_walls::write_traj(std::ostream &os)
{
colvarbias_restraint::write_traj(os);
colvarbias_restraint_k_moving::write_traj(os);
return os;
}
colvarbias_restraint_linear::colvarbias_restraint_linear(char const *key)
: colvarbias(key),
colvarbias_restraint(key),
colvarbias_restraint_centers(key),
colvarbias_restraint_moving(key),
colvarbias_restraint_k(key),
colvarbias_restraint_centers_moving(key),
colvarbias_restraint_k_moving(key)
{
}
int colvarbias_restraint_linear::init(std::string const &conf)
{
colvarbias_restraint::init(conf);
colvarbias_restraint_moving::init(conf);
colvarbias_restraint_centers_moving::init(conf);
colvarbias_restraint_k_moving::init(conf);
for (size_t i = 0; i < num_variables(); i++) {
if (variables(i)->is_enabled(f_cv_periodic)) {
cvm::error("Error: linear biases cannot be applied to periodic variables.\n",
INPUT_ERROR);
return INPUT_ERROR;
}
if (variables(i)->width != 1.0)
cvm::log("The force constant for colvar \""+variables(i)->name+
"\" will be rescaled to "+
cvm::to_str(force_k / variables(i)->width)+
" according to the specified width.\n");
}
return COLVARS_OK;
}
int colvarbias_restraint_linear::update()
{
// update parameters (centers or force constant)
colvarbias_restraint_centers_moving::update();
colvarbias_restraint_k_moving::update();
// update restraint energy and forces
colvarbias_restraint::update();
// update accumulated work using the current forces
colvarbias_restraint_centers_moving::update_acc_work();
return COLVARS_OK;
}
int colvarbias_restraint_linear::change_configuration(std::string const &conf)
{
// Only makes sense to change the force constant
return colvarbias_restraint_k::change_configuration(conf);
}
cvm::real colvarbias_restraint_linear::energy_difference(std::string const &conf)
{
cvm::real const old_bias_energy = bias_energy;
cvm::real const old_force_k = force_k;
change_configuration(conf);
update();
cvm::real const result = (bias_energy - old_bias_energy);
bias_energy = old_bias_energy;
force_k = old_force_k;
return result;
}
cvm::real colvarbias_restraint_linear::restraint_potential(size_t i) const
{
return force_k / variables(i)->width * (variables(i)->value() - colvar_centers[i]);
}
colvarvalue const colvarbias_restraint_linear::restraint_force(size_t i) const
{
return -1.0 * force_k / variables(i)->width;
}
cvm::real colvarbias_restraint_linear::d_restraint_potential_dk(size_t i) const
{
return 1.0 / variables(i)->width * (variables(i)->value() - colvar_centers[i]);
}
std::string const colvarbias_restraint_linear::get_state_params() const
{
return colvarbias_restraint::get_state_params() +
colvarbias_restraint_centers_moving::get_state_params() +
colvarbias_restraint_k_moving::get_state_params();
}
int colvarbias_restraint_linear::set_state_params(std::string const &conf)
{
int error_code = COLVARS_OK;
error_code |= colvarbias_restraint::set_state_params(conf);
error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
return error_code;
}
std::ostream & colvarbias_restraint_linear::write_traj_label(std::ostream &os)
{
colvarbias_restraint::write_traj_label(os);
colvarbias_restraint_centers_moving::write_traj_label(os);
colvarbias_restraint_k_moving::write_traj_label(os);
return os;
}
std::ostream & colvarbias_restraint_linear::write_traj(std::ostream &os)
{
colvarbias_restraint::write_traj(os);
colvarbias_restraint_centers_moving::write_traj(os);
colvarbias_restraint_k_moving::write_traj(os);
return os;
}
colvarbias_restraint_histogram::colvarbias_restraint_histogram(char const *key)
: colvarbias(key)
{
lower_boundary = 0.0;
upper_boundary = 0.0;
width = 0.0;
gaussian_width = 0.0;
}
int colvarbias_restraint_histogram::init(std::string const &conf)
{
colvarbias::init(conf);
get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary);
get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary);
get_keyval(conf, "width", width, width);
if (width <= 0.0) {
cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR);
}
get_keyval(conf, "gaussianWidth", gaussian_width, 2.0 * width, colvarparse::parse_silent);
get_keyval(conf, "gaussianSigma", gaussian_width, 2.0 * width);
if (lower_boundary >= upper_boundary) {
cvm::error("Error: the upper boundary, "+
cvm::to_str(upper_boundary)+
", is not higher than the lower boundary, "+
cvm::to_str(lower_boundary)+".\n",
INPUT_ERROR);
}
cvm::real const nbins = (upper_boundary - lower_boundary) / width;
int const nbins_round = (int)(nbins);
if (std::fabs(nbins - cvm::real(nbins_round)) > 1.0E-10) {
cvm::log("Warning: grid interval ("+
cvm::to_str(lower_boundary, cvm::cv_width, cvm::cv_prec)+" - "+
cvm::to_str(upper_boundary, cvm::cv_width, cvm::cv_prec)+
") is not commensurate to its bin width ("+
cvm::to_str(width, cvm::cv_width, cvm::cv_prec)+").\n");
}
p.resize(nbins_round);
ref_p.resize(nbins_round);
p_diff.resize(nbins_round);
bool const inline_ref_p =
get_keyval(conf, "refHistogram", ref_p.data_array(), ref_p.data_array());
std::string ref_p_file;
get_keyval(conf, "refHistogramFile", ref_p_file, std::string(""));
if (ref_p_file.size()) {
if (inline_ref_p) {
cvm::error("Error: cannot specify both refHistogram and refHistogramFile at the same time.\n",
INPUT_ERROR);
} else {
std::ifstream is(ref_p_file.c_str());
std::string data_s = "";
std::string line;
while (getline_nocomments(is, line)) {
data_s.append(line+"\n");
}
if (data_s.size() == 0) {
cvm::error("Error: file \""+ref_p_file+"\" empty or unreadable.\n", FILE_ERROR);
}
is.close();
cvm::vector1d<cvm::real> data;
if (data.from_simple_string(data_s) != 0) {
cvm::error("Error: could not read histogram from file \""+ref_p_file+"\".\n");
}
if (data.size() == 2*ref_p.size()) {
// file contains both x and p(x)
size_t i;
for (i = 0; i < ref_p.size(); i++) {
ref_p[i] = data[2*i+1];
}
} else if (data.size() == ref_p.size()) {
ref_p = data;
} else {
cvm::error("Error: file \""+ref_p_file+"\" contains a histogram of different length.\n",
INPUT_ERROR);
}
}
}
cvm::real const ref_integral = ref_p.sum() * width;
if (std::fabs(ref_integral - 1.0) > 1.0e-03) {
cvm::log("Reference distribution not normalized, normalizing to unity.\n");
ref_p /= ref_integral;
}
get_keyval(conf, "writeHistogram", b_write_histogram, false);
get_keyval(conf, "forceConstant", force_k, 1.0);
return COLVARS_OK;
}
colvarbias_restraint_histogram::~colvarbias_restraint_histogram()
{
- p.resize(0);
- ref_p.resize(0);
- p_diff.resize(0);
+ p.clear();
+ ref_p.clear();
+ p_diff.clear();
}
int colvarbias_restraint_histogram::update()
{
if (cvm::debug())
cvm::log("Updating the histogram restraint bias \""+this->name+"\".\n");
size_t vector_size = 0;
size_t icv;
for (icv = 0; icv < num_variables(); icv++) {
vector_size += variables(icv)->value().size();
}
cvm::real const norm = 1.0/(std::sqrt(2.0*PI)*gaussian_width*vector_size);
// calculate the histogram
p.reset();
for (icv = 0; icv < num_variables(); icv++) {
colvarvalue const &cv = variables(icv)->value();
if (cv.type() == colvarvalue::type_scalar) {
cvm::real const cv_value = cv.real_value;
size_t igrid;
for (igrid = 0; igrid < p.size(); igrid++) {
cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
p[igrid] += norm * std::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
(2.0 * gaussian_width * gaussian_width));
}
} else if (cv.type() == colvarvalue::type_vector) {
size_t idim;
for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
cvm::real const cv_value = cv.vector1d_value[idim];
size_t igrid;
for (igrid = 0; igrid < p.size(); igrid++) {
cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
p[igrid] += norm * std::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
(2.0 * gaussian_width * gaussian_width));
}
}
} else {
cvm::error("Error: unsupported type for variable "+variables(icv)->name+".\n",
COLVARS_NOT_IMPLEMENTED);
return COLVARS_NOT_IMPLEMENTED;
}
}
cvm::real const force_k_cv = force_k * vector_size;
// calculate the difference between current and reference
p_diff = p - ref_p;
bias_energy = 0.5 * force_k_cv * p_diff * p_diff;
// calculate the forces
for (icv = 0; icv < num_variables(); icv++) {
colvarvalue const &cv = variables(icv)->value();
colvarvalue &cv_force = colvar_forces[icv];
cv_force.type(cv);
cv_force.reset();
if (cv.type() == colvarvalue::type_scalar) {
cvm::real const cv_value = cv.real_value;
cvm::real &force = cv_force.real_value;
size_t igrid;
for (igrid = 0; igrid < p.size(); igrid++) {
cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
force += force_k_cv * p_diff[igrid] *
norm * std::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
(2.0 * gaussian_width * gaussian_width)) *
(-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
}
} else if (cv.type() == colvarvalue::type_vector) {
size_t idim;
for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
cvm::real const cv_value = cv.vector1d_value[idim];
cvm::real &force = cv_force.vector1d_value[idim];
size_t igrid;
for (igrid = 0; igrid < p.size(); igrid++) {
cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
force += force_k_cv * p_diff[igrid] *
norm * std::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
(2.0 * gaussian_width * gaussian_width)) *
(-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
}
}
} else {
// TODO
}
}
return COLVARS_OK;
}
std::ostream & colvarbias_restraint_histogram::write_restart(std::ostream &os)
{
if (b_write_histogram) {
std::string file_name(cvm::output_prefix()+"."+this->name+".hist.dat");
- std::ofstream os(file_name.c_str());
- os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width)
- << " " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3)
- << ")\n";
+ std::ostream *os = cvm::proxy->output_stream(file_name);
+ *os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width)
+ << " " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3)
+ << ")\n";
size_t igrid;
for (igrid = 0; igrid < p.size(); igrid++) {
cvm::real const x_grid = (lower_boundary + (igrid+1)*width);
- os << " "
- << std::setprecision(cvm::cv_prec)
- << std::setw(cvm::cv_width)
- << x_grid
- << " "
- << std::setprecision(cvm::cv_prec)
- << std::setw(cvm::cv_width)
- << p[igrid] << "\n";
+ *os << " "
+ << std::setprecision(cvm::cv_prec)
+ << std::setw(cvm::cv_width)
+ << x_grid
+ << " "
+ << std::setprecision(cvm::cv_prec)
+ << std::setw(cvm::cv_width)
+ << p[igrid] << "\n";
}
- os.close();
+ cvm::proxy->close_output_stream(file_name);
}
return os;
}
std::istream & colvarbias_restraint_histogram::read_restart(std::istream &is)
{
return is;
}
std::ostream & colvarbias_restraint_histogram::write_traj_label(std::ostream &os)
{
os << " ";
if (b_output_energy) {
os << " E_"
<< cvm::wrap_string(this->name, cvm::en_width-2);
}
return os;
}
std::ostream & colvarbias_restraint_histogram::write_traj(std::ostream &os)
{
os << " ";
if (b_output_energy) {
os << " "
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
<< bias_energy;
}
return os;
}
diff --git a/lib/colvars/colvarcomp.cpp b/lib/colvars/colvarcomp.cpp
index 786bc032d..589de1d32 100644
--- a/lib/colvars/colvarcomp.cpp
+++ b/lib/colvars/colvarcomp.cpp
@@ -1,334 +1,366 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::cvc::cvc()
: sup_coeff(1.0),
sup_np(1),
b_periodic(false),
b_try_scalable(true)
{
init_cvc_requires();
}
colvar::cvc::cvc(std::string const &conf)
: sup_coeff(1.0),
sup_np(1),
b_periodic(false),
b_try_scalable(true)
{
if (cvm::debug())
cvm::log("Initializing cvc base object.\n");
init_cvc_requires();
if (get_keyval(conf, "name", this->name, std::string(""), parse_silent)) {
// Temporary description until child object is initialized
description = "cvc " + name;
} else {
description = "uninitialized cvc";
}
get_keyval(conf, "componentCoeff", sup_coeff, 1.0);
get_keyval(conf, "componentExp", sup_np, 1);
get_keyval(conf, "period", period, 0.0);
get_keyval(conf, "wrapAround", wrap_center, 0.0);
get_keyval_feature((colvarparse *)this, conf, "debugGradients",
f_cvc_debug_gradient, false, parse_silent);
+ {
+ bool b_no_PBC = false;
+ get_keyval(conf, "forceNoPBC", b_no_PBC, false);
+ if (b_no_PBC) {
+ disable(f_cvc_pbc_minimum_image);
+ } else {
+ enable(f_cvc_pbc_minimum_image);
+ }
+ // this does not use get_keyval_feature() only for backward compatibility
+ }
+
// Attempt scalable calculations when in parallel? (By default yes, if available)
get_keyval(conf, "scalable", b_try_scalable, true);
if (cvm::debug())
cvm::log("Done initializing cvc base object.\n");
}
int colvar::cvc::init_total_force_params(std::string const &conf)
{
if (cvm::get_error()) return COLVARS_ERROR;
if (get_keyval_feature(this, conf, "oneSiteSystemForce",
f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
cvm::log("Warning: keyword \"oneSiteSystemForce\" is deprecated: "
"please use \"oneSiteTotalForce\" instead.\n");
}
if (get_keyval_feature(this, conf, "oneSiteTotalForce",
f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
cvm::log("Computing total force on group 1 only");
}
if (! is_enabled(f_cvc_one_site_total_force)) {
// check whether any of the other atom groups is dummy
std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
agi++;
for ( ; agi != atom_groups.end(); agi++) {
if ((*agi)->b_dummy) {
provide(f_cvc_inv_gradient, false);
provide(f_cvc_Jacobian, false);
}
}
}
return COLVARS_OK;
}
cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
char const *group_key,
bool optional)
{
cvm::atom_group *group = NULL;
+ std::string group_conf;
- if (key_lookup(conf, group_key)) {
- group = new cvm::atom_group;
- group->key = group_key;
+ if (key_lookup(conf, group_key, &group_conf)) {
+ group = new cvm::atom_group(group_key);
if (b_try_scalable) {
- if (is_available(f_cvc_scalable_com) && is_enabled(f_cvc_com_based)) {
+ if (is_available(f_cvc_scalable_com)
+ && is_enabled(f_cvc_com_based)
+ && !is_enabled(f_cvc_debug_gradient)) {
enable(f_cvc_scalable_com);
enable(f_cvc_scalable);
// The CVC makes the feature available;
// the atom group will enable it unless it needs to compute a rotational fit
group->provide(f_ag_scalable_com);
}
// TODO check for other types of parallelism here
}
- if (group->parse(conf) == COLVARS_OK) {
- atom_groups.push_back(group);
- } else {
+ if (group_conf.size() == 0) {
+ cvm::error("Error: atom group \""+group->key+
+ "\" is set, but has no definition.\n",
+ INPUT_ERROR);
+ return group;
+ }
+
+ cvm::increase_depth();
+ if (group->parse(group_conf) == COLVARS_OK) {
+ register_atom_group(group);
+ }
+ group->check_keywords(group_conf, group_key);
+ if (cvm::get_error()) {
cvm::error("Error parsing definition for atom group \""+
- std::string(group_key)+"\".\n");
+ std::string(group_key)+"\"\n.", INPUT_ERROR);
}
+ cvm::decrease_depth();
+
} else {
if (! optional) {
cvm::error("Error: definition for atom group \""+
- std::string(group_key)+"\" not found.\n");
+ std::string(group_key)+"\" not found.\n");
}
}
+
return group;
}
int colvar::cvc::setup()
{
- size_t i;
description = "cvc " + name;
-
- for (i = 0; i < atom_groups.size(); i++) {
- add_child((colvardeps *) atom_groups[i]);
- }
-
return COLVARS_OK;
}
colvar::cvc::~cvc()
{
+ free_children_deps();
remove_all_children();
for (size_t i = 0; i < atom_groups.size(); i++) {
if (atom_groups[i] != NULL) delete atom_groups[i];
}
}
-
void colvar::cvc::read_data()
{
size_t ig;
for (ig = 0; ig < atom_groups.size(); ig++) {
cvm::atom_group &atoms = *(atom_groups[ig]);
atoms.reset_atoms_data();
atoms.read_positions();
atoms.calc_required_properties();
// each atom group will take care of its own fitting_group, if defined
}
//// Don't try to get atom velocities, as no back-end currently implements it
// if (tasks[task_output_velocity] && !tasks[task_fdiff_velocity]) {
// for (i = 0; i < cvcs.size(); i++) {
// for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
// cvcs[i]->atom_groups[ig]->read_velocities();
// }
// }
// }
}
void colvar::cvc::calc_force_invgrads()
{
cvm::error("Error: calculation of inverse gradients is not implemented "
"for colvar components of type \""+function_type+"\".\n",
COLVARS_NOT_IMPLEMENTED);
}
void colvar::cvc::calc_Jacobian_derivative()
{
cvm::error("Error: calculation of inverse gradients is not implemented "
"for colvar components of type \""+function_type+"\".\n",
COLVARS_NOT_IMPLEMENTED);
}
-void colvar::cvc::debug_gradients(cvm::atom_group *group)
+void colvar::cvc::calc_fit_gradients()
+{
+ for (size_t ig = 0; ig < atom_groups.size(); ig++) {
+ atom_groups[ig]->calc_fit_gradients();
+ }
+}
+
+
+void colvar::cvc::debug_gradients()
{
- // this function should work for any scalar variable:
+ // this function should work for any scalar cvc:
// the only difference will be the name of the atom group (here, "group")
// NOTE: this assumes that groups for this cvc are non-overlapping,
// since atom coordinates are modified only within the current group
- if (group->b_dummy) return;
+ cvm::log("Debugging gradients for " + description);
- cvm::rotation const rot_0 = group->rot;
- cvm::rotation const rot_inv = group->rot.inverse();
+ for (size_t ig = 0; ig < atom_groups.size(); ig++) {
+ cvm::atom_group *group = atom_groups[ig];
+ if (group->b_dummy) continue;
- cvm::real x_0 = x.real_value;
- if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0];
+ cvm::rotation const rot_0 = group->rot;
+ cvm::rotation const rot_inv = group->rot.inverse();
- // cvm::log("gradients = "+cvm::to_str (gradients)+"\n");
+ cvm::real x_0 = x.real_value;
+ if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0];
- cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group;
- cvm::atom_pos fit_gradient_sum, gradient_sum;
+ // cvm::log("gradients = "+cvm::to_str (gradients)+"\n");
- // print the values of the fit gradients
- if (group->b_rotate || group->b_center) {
- if (group->b_fit_gradients) {
- size_t j;
+ cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group;
+ cvm::atom_pos fit_gradient_sum, gradient_sum;
- // fit_gradients are in the simulation frame: we should print them in the rotated frame
- cvm::log("Fit gradients:\n");
- for (j = 0; j < group_for_fit->fit_gradients.size(); j++) {
- cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) +
- "[" + cvm::to_str(j) + "] = " +
- (group->b_rotate ?
- cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) :
- cvm::to_str(group_for_fit->fit_gradients[j])));
- }
- }
- }
-
- // debug the gradients
- for (size_t ia = 0; ia < group->size(); ia++) {
-
- // tests are best conducted in the unrotated (simulation) frame
- cvm::rvector const atom_grad = (group->b_rotate ?
- rot_inv.rotate((*group)[ia].grad) :
- (*group)[ia].grad);
- gradient_sum += atom_grad;
+ // print the values of the fit gradients
+ if (group->b_rotate || group->b_center) {
+ if (group->is_enabled(f_ag_fit_gradients)) {
+ size_t j;
- for (size_t id = 0; id < 3; id++) {
- // (re)read original positions
- group->read_positions();
- // change one coordinate
- (*group)[ia].pos[id] += cvm::debug_gradients_step_size;
- group->calc_required_properties();
- calc_value();
- cvm::real x_1 = x.real_value;
- if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0];
- cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n");
- cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0,
- 21, 14)+"\n");
- cvm::real const dx_pred = (group->fit_gradients.size()) ?
- (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) :
- (cvm::debug_gradients_step_size * atom_grad[id]);
- cvm::log("dx(interp) = "+cvm::to_str(dx_pred,
- 21, 14)+"\n");
- cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
- cvm::to_str(std::fabs(x_1 - x_0 - dx_pred) /
- std::fabs(x_1 - x_0), 12, 5)+"\n");
+ // fit_gradients are in the simulation frame: we should print them in the rotated frame
+ cvm::log("Fit gradients:\n");
+ for (j = 0; j < group_for_fit->fit_gradients.size(); j++) {
+ cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) +
+ "[" + cvm::to_str(j) + "] = " +
+ (group->b_rotate ?
+ cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) :
+ cvm::to_str(group_for_fit->fit_gradients[j])));
+ }
+ }
}
- }
- if ((group->b_fit_gradients) && (group->fitting_group != NULL)) {
- cvm::atom_group *ref_group = group->fitting_group;
- group->read_positions();
- group->calc_required_properties();
+ // debug the gradients
+ for (size_t ia = 0; ia < group->size(); ia++) {
- for (size_t ia = 0; ia < ref_group->size(); ia++) {
-
- // fit gradients are in the unrotated (simulation) frame
- cvm::rvector const atom_grad = ref_group->fit_gradients[ia];
- fit_gradient_sum += atom_grad;
+ // tests are best conducted in the unrotated (simulation) frame
+ cvm::rvector const atom_grad = (group->b_rotate ?
+ rot_inv.rotate((*group)[ia].grad) :
+ (*group)[ia].grad);
+ gradient_sum += atom_grad;
for (size_t id = 0; id < 3; id++) {
// (re)read original positions
group->read_positions();
- ref_group->read_positions();
// change one coordinate
- (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size;
+ (*group)[ia].pos[id] += cvm::debug_gradients_step_size;
group->calc_required_properties();
calc_value();
+ cvm::real x_1 = x.real_value;
+ if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0];
+ cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n");
+ cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0,
+ 21, 14)+"\n");
+ cvm::real const dx_pred = (group->fit_gradients.size()) ?
+ (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) :
+ (cvm::debug_gradients_step_size * atom_grad[id]);
+ cvm::log("dx(interp) = "+cvm::to_str(dx_pred,
+ 21, 14)+"\n");
+ cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
+ cvm::to_str(std::fabs(x_1 - x_0 - dx_pred) /
+ std::fabs(x_1 - x_0), 12, 5)+"\n");
+ }
+ }
- cvm::real const x_1 = x.real_value;
- cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n");
- cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0,
- 21, 14)+"\n");
-
- cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id];
+ if ((group->is_enabled(f_ag_fit_gradients)) && (group->fitting_group != NULL)) {
+ cvm::atom_group *ref_group = group->fitting_group;
+ group->read_positions();
+ group->calc_required_properties();
- cvm::log("dx(interp) = "+cvm::to_str (dx_pred,
- 21, 14)+"\n");
- cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+
- cvm::to_str(std::fabs (x_1 - x_0 - dx_pred) /
- std::fabs (x_1 - x_0),
- 12, 5)+
- ".\n");
+ for (size_t ia = 0; ia < ref_group->size(); ia++) {
+
+ // fit gradients are in the unrotated (simulation) frame
+ cvm::rvector const atom_grad = ref_group->fit_gradients[ia];
+ fit_gradient_sum += atom_grad;
+
+ for (size_t id = 0; id < 3; id++) {
+ // (re)read original positions
+ group->read_positions();
+ ref_group->read_positions();
+ // change one coordinate
+ (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size;
+ group->calc_required_properties();
+ calc_value();
+
+ cvm::real const x_1 = x.real_value;
+ cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n");
+ cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0,
+ 21, 14)+"\n");
+
+ cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id];
+
+ cvm::log("dx(interp) = "+cvm::to_str (dx_pred,
+ 21, 14)+"\n");
+ cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+
+ cvm::to_str(std::fabs (x_1 - x_0 - dx_pred) /
+ std::fabs (x_1 - x_0),
+ 12, 5)+
+ ".\n");
+ }
}
}
- }
-
- cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) +
- " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) +
- " Total " + cvm::to_str(gradient_sum + fit_gradient_sum));
+ cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) +
+ " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) +
+ " Total " + cvm::to_str(gradient_sum + fit_gradient_sum));
+ }
return;
}
cvm::real colvar::cvc::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x1.dist2(x2);
}
colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x1.dist2_grad(x2);
}
colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x2.dist2_grad(x1);
}
void colvar::cvc::wrap(colvarvalue &x) const
{
return;
}
// Static members
std::vector<colvardeps::feature *> colvar::cvc::cvc_features;
diff --git a/lib/colvars/colvarcomp.h b/lib/colvars/colvarcomp.h
index ec215cbad..2c865a166 100644
--- a/lib/colvars/colvarcomp.h
+++ b/lib/colvars/colvarcomp.h
@@ -1,1286 +1,1357 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARCOMP_H
#define COLVARCOMP_H
// Declaration of colvar::cvc base class and derived ones.
//
// Future cvc's could be declared on additional header files.
// After the declaration of a new derived class, its metric
// functions must be reimplemented as well.
// If the new cvc has no symmetry or periodicity,
// this can be done straightforwardly by using the macro:
// simple_scalar_dist_functions (derived_class)
#include <fstream>
#include <cmath>
#include "colvarmodule.h"
#include "colvar.h"
#include "colvaratoms.h"
/// \brief Colvar component (base class); most implementations of
/// \link cvc \endlink utilize one or more \link
/// colvarmodule::atom \endlink or \link colvarmodule::atom_group
/// \endlink objects to access atoms.
///
/// A \link cvc \endlink object (or an object of a
/// cvc-derived class) specifies how to calculate a collective
/// variable, its gradients and other related physical quantities
/// which do not depend only on the numeric value (the \link colvar
/// \endlink class already serves this purpose).
///
/// No restriction is set to what kind of calculation a \link
/// cvc \endlink object performs (usually calculate an
/// analytical function of atomic coordinates). The only constraint
/// is that the value calculated is implemented as a \link colvarvalue
/// \endlink object. This serves to provide a unique way to calculate
/// scalar and non-scalar collective variables, and specify if and how
/// they can be combined together by the parent \link colvar \endlink
/// object.
///
/// <b> If you wish to implement a new collective variable component, you
/// should write your own class by inheriting directly from \link
/// cvc \endlink, or one of its derived classes (for instance,
/// \link distance \endlink is frequently used, because it provides
/// useful data and function members for any colvar based on two
/// atom groups). The steps are: \par
/// 1. add the name of this class under colvar.h \par
/// 2. add a call to the parser in colvar.C, within the function colvar::colvar() \par
/// 3. declare the class in colvarcomp.h \par
/// 4. implement the class in one of the files colvarcomp_*.C
///
/// </b>
/// The cvm::atom and cvm::atom_group classes are available to
/// transparently communicate with the simulation program. However,
/// they are not strictly needed, as long as all the degrees of
/// freedom associated to the cvc are properly evolved by a simple
/// call to e.g. apply_force().
class colvar::cvc
: public colvarparse, public colvardeps
{
public:
/// \brief The name of the object (helps to identify this
/// cvc instance when debugging)
std::string name;
/// \brief Description of the type of collective variable
///
/// Normally this string is set by the parent \link colvar \endlink
/// object within its constructor, when all \link cvc \endlink
/// objects are initialized; therefore the main "config string"
/// constructor does not need to define it. If a \link cvc
/// \endlink is initialized and/or a different constructor is used,
/// this variable definition should be set within the constructor.
std::string function_type;
/// \brief Coefficient in the polynomial combination (default: 1.0)
cvm::real sup_coeff;
/// \brief Exponent in the polynomial combination (default: 1)
int sup_np;
/// \brief Is this a periodic component?
bool b_periodic;
/// \brief Period of this cvc value, (default: 0.0, non periodic)
cvm::real period;
/// \brief If the component is periodic, wrap around this value (default: 0.0)
cvm::real wrap_center;
/// \brief Constructor
///
/// At least one constructor which reads a string should be defined
/// for every class inheriting from cvc \param conf Contents
/// of the configuration file pertaining to this \link cvc
/// \endlink
cvc(std::string const &conf);
/// \brief Within the constructor, make a group parse its own
/// options from the provided configuration string
/// Returns reference to new group
cvm::atom_group *parse_group(std::string const &conf,
char const *group_key,
bool optional = false);
/// \brief Parse options pertaining to total force calculation
virtual int init_total_force_params(std::string const &conf);
/// \brief After construction, set data related to dependency handling
int setup();
/// \brief Default constructor (used when \link cvc \endlink
/// objects are declared within other ones)
cvc();
/// Destructor
virtual ~cvc();
/// \brief Implementation of the feature list for colvar
static std::vector<feature *> cvc_features;
/// \brief Implementation of the feature list accessor for colvar
virtual std::vector<feature *> &features() {
return cvc_features;
}
/// \brief Obtain data needed for the calculation for the backend
virtual void read_data();
/// \brief Calculate the variable
virtual void calc_value() = 0;
/// \brief Calculate the atomic gradients, to be reused later in
/// order to apply forces
virtual void calc_gradients() = 0;
+ /// \brief Calculate the atomic fit gradients
+ void calc_fit_gradients();
+
/// \brief Calculate finite-difference gradients alongside the analytical ones, for each Cartesian component
- virtual void debug_gradients(cvm::atom_group *group);
+ virtual void debug_gradients();
/// \brief Calculate the total force from the system using the
/// inverse atomic gradients
virtual void calc_force_invgrads();
/// \brief Calculate the divergence of the inverse atomic gradients
virtual void calc_Jacobian_derivative();
/// \brief Return the previously calculated value
colvarvalue const & value() const;
/// \brief Return the previously calculated total force
colvarvalue const & total_force() const;
/// \brief Return the previously calculated divergence of the
/// inverse atomic gradients
colvarvalue const & Jacobian_derivative() const;
/// \brief Apply the collective variable force, by communicating the
/// atomic forces to the simulation program (\b Note: the \link ft
/// \endlink member is not altered by this function)
///
/// Note: multiple calls to this function within the same simulation
/// step will add the forces altogether \param cvforce The
/// collective variable force, usually coming from the biases and
/// eventually manipulated by the parent \link colvar \endlink
/// object
virtual void apply_force(colvarvalue const &cvforce) = 0;
/// \brief Square distance between x1 and x2 (can be redefined to
/// transparently implement constraints, symmetries and
/// periodicities)
///
/// colvar::cvc::dist2() and the related functions are
/// declared as "const" functions, but not "static", because
/// additional parameters defining the metrics (e.g. the
/// periodicity) may be specific to each colvar::cvc object.
///
/// If symmetries or periodicities are present, the
/// colvar::cvc::dist2() should be redefined to return the
/// "closest distance" value and colvar::cvc::dist2_lgrad(),
/// colvar::cvc::dist2_rgrad() to return its gradients.
///
/// If constraints are present (and not already implemented by any
/// of the \link colvarvalue \endlink types), the
/// colvar::cvc::dist2_lgrad() and
/// colvar::cvc::dist2_rgrad() functions should be redefined
/// to provide a gradient which is compatible with the constraint,
/// i.e. already deprived of its component normal to the constraint
/// hypersurface.
///
/// Finally, another useful application, if you are performing very
/// many operations with these functions, could be to override the
/// \link colvarvalue \endlink member functions and access directly
/// its member data. For instance: to define dist2(x1,x2) as
/// (x2.real_value-x1.real_value)*(x2.real_value-x1.real_value) in
/// case of a scalar \link colvarvalue \endlink type.
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Gradient(with respect to x1) of the square distance (can
/// be redefined to transparently implement constraints, symmetries
/// and periodicities)
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Gradient(with respect to x2) of the square distance (can
/// be redefined to transparently implement constraints, symmetries
/// and periodicities)
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Wrapp value (for periodic/symmetric cvcs)
virtual void wrap(colvarvalue &x) const;
/// \brief Pointers to all atom groups, to let colvars collect info
/// e.g. atomic gradients
std::vector<cvm::atom_group *> atom_groups;
+ /// \brief Store a pointer to new atom group, and list as child for dependencies
+ inline void register_atom_group(cvm::atom_group *ag) {
+ atom_groups.push_back(ag);
+ add_child((colvardeps *) ag);
+ }
+
/// \brief Whether or not this CVC will be computed in parallel whenever possible
bool b_try_scalable;
protected:
/// \brief Cached value
colvarvalue x;
/// \brief Value at the previous step
colvarvalue x_old;
/// \brief Calculated total force (\b Note: this is calculated from
/// the total atomic forces read from the program, subtracting fromt
/// the "internal" forces of the system the "external" forces from
/// the colvar biases)
colvarvalue ft;
/// \brief Calculated Jacobian derivative (divergence of the inverse
/// gradients): serves to calculate the phase space correction
colvarvalue jd;
};
inline colvarvalue const & colvar::cvc::value() const
{
return x;
}
inline colvarvalue const & colvar::cvc::total_force() const
{
return ft;
}
inline colvarvalue const & colvar::cvc::Jacobian_derivative() const
{
return jd;
}
/// \brief Colvar component: distance between the centers of mass of
/// two groups (colvarvalue::type_scalar type, range [0:*))
class colvar::distance
: public colvar::cvc
{
protected:
/// First atom group
cvm::atom_group *group1;
/// Second atom group
cvm::atom_group *group2;
/// Vector distance, cached to be recycled
cvm::rvector dist_v;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
public:
distance(std::string const &conf);
distance();
virtual ~distance() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
// \brief Colvar component: distance vector between centers of mass
// of two groups (\link colvarvalue::type_3vector \endlink type,
// range (-*:*)x(-*:*)x(-*:*))
class colvar::distance_vec
: public colvar::distance
{
public:
distance_vec(std::string const &conf);
distance_vec();
virtual ~distance_vec() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
/// Redefined to handle the box periodicity
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the box periodicity
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the box periodicity
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: distance unit vector (direction) between
/// centers of mass of two groups (colvarvalue::type_unit3vector type,
/// range [-1:1]x[-1:1]x[-1:1])
class colvar::distance_dir
: public colvar::distance
{
public:
distance_dir(std::string const &conf);
distance_dir();
virtual ~distance_dir() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
/// Redefined to override the distance ones
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to override the distance ones
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to override the distance ones
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: projection of the distance vector along
/// an axis(colvarvalue::type_scalar type, range (-*:*))
class colvar::distance_z
: public colvar::cvc
{
protected:
/// Main atom group
cvm::atom_group *main;
/// Reference atom group
cvm::atom_group *ref1;
/// Optional, second ref atom group
cvm::atom_group *ref2;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
/// Vector on which the distance vector is projected
cvm::rvector axis;
/// Norm of the axis
cvm::real axis_norm;
/// Vector distance, cached to be recycled
cvm::rvector dist_v;
/// Flag: using a fixed axis vector?
bool fixed_axis;
public:
distance_z(std::string const &conf);
distance_z();
virtual ~distance_z() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// \brief Redefined to make use of the user-provided period
virtual void wrap(colvarvalue &x) const;
};
/// \brief Colvar component: projection of the distance vector on a
/// plane (colvarvalue::type_scalar type, range [0:*))
class colvar::distance_xy
: public colvar::distance_z
{
protected:
/// Components of the distance vector orthogonal to the axis
cvm::rvector dist_v_ortho;
/// Vector distances
cvm::rvector v12, v13;
public:
distance_xy(std::string const &conf);
distance_xy();
virtual ~distance_xy() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
+/// \brief Colvar component: polar coordinate phi of a group
+/// (colvarvalue::type_scalar type, range [-180:180])
+class colvar::polar_phi
+ : public colvar::cvc
+{
+public:
+ polar_phi(std::string const &conf);
+ polar_phi();
+ virtual ~polar_phi() {}
+protected:
+ cvm::atom_group *atoms;
+ cvm::real r, theta, phi;
+public:
+ virtual void calc_value();
+ virtual void calc_gradients();
+ virtual void apply_force(colvarvalue const &force);
+ /// Redefined to handle the 2*PI periodicity
+ virtual cvm::real dist2(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+ /// Redefined to handle the 2*PI periodicity
+ virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+ /// Redefined to handle the 2*PI periodicity
+ virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+ /// Redefined to handle the 2*PI periodicity
+ virtual void wrap(colvarvalue &x) const;
+};
+
+
+/// \brief Colvar component: polar coordinate theta of a group
+/// (colvarvalue::type_scalar type, range [0:180])
+class colvar::polar_theta
+ : public colvar::cvc
+{
+public:
+ polar_theta(std::string const &conf);
+ polar_theta();
+ virtual ~polar_theta() {}
+protected:
+ cvm::atom_group *atoms;
+ cvm::real r, theta, phi;
+public:
+ virtual void calc_value();
+ virtual void calc_gradients();
+ virtual void apply_force(colvarvalue const &force);
+ /// Redefined to override the distance ones
+ virtual cvm::real dist2(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+ /// Redefined to override the distance ones
+ virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+ /// Redefined to override the distance ones
+ virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const;
+};
/// \brief Colvar component: average distance between two groups of atoms, weighted as the sixth power,
/// as in NMR refinements(colvarvalue::type_scalar type, range (0:*))
class colvar::distance_inv
- : public colvar::distance
+ : public colvar::cvc
{
protected:
+ /// First atom group
+ cvm::atom_group *group1;
+ /// Second atom group
+ cvm::atom_group *group2;
/// Components of the distance vector orthogonal to the axis
int exponent;
+ /// Use absolute positions, ignoring PBCs when present
+ bool b_no_PBC;
public:
distance_inv(std::string const &conf);
distance_inv();
virtual ~distance_inv() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: N1xN2 vector of pairwise distances
/// (colvarvalue::type_vector type, range (0:*) for each component)
class colvar::distance_pairs
: public colvar::cvc
{
protected:
/// First atom group
cvm::atom_group *group1;
/// Second atom group
cvm::atom_group *group2;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
public:
distance_pairs(std::string const &conf);
distance_pairs();
virtual ~distance_pairs() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
};
/// \brief Colvar component: Radius of gyration of an atom group
/// (colvarvalue::type_scalar type, range [0:*))
class colvar::gyration
: public colvar::cvc
{
protected:
/// Atoms involved
cvm::atom_group *atoms;
public:
/// Constructor
gyration(std::string const &conf);
gyration();
virtual ~gyration() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: moment of inertia of an atom group
/// (colvarvalue::type_scalar type, range [0:*))
class colvar::inertia
: public colvar::gyration
{
public:
/// Constructor
inertia(std::string const &conf);
inertia();
virtual ~inertia() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: moment of inertia of an atom group
/// around a user-defined axis (colvarvalue::type_scalar type, range [0:*))
class colvar::inertia_z
: public colvar::inertia
{
protected:
/// Vector on which the inertia tensor is projected
cvm::rvector axis;
public:
/// Constructor
inertia_z(std::string const &conf);
inertia_z();
virtual ~inertia_z() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: projection of 3N coordinates onto an
/// eigenvector(colvarvalue::type_scalar type, range (-*:*))
class colvar::eigenvector
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group * atoms;
/// Reference coordinates
std::vector<cvm::atom_pos> ref_pos;
/// Geometric center of the reference coordinates
cvm::atom_pos ref_pos_center;
/// Eigenvector (of a normal or essential mode): will always have zero center
std::vector<cvm::rvector> eigenvec;
/// Inverse square norm of the eigenvector
cvm::real eigenvec_invnorm2;
public:
/// Constructor
eigenvector(std::string const &conf);
virtual ~eigenvector() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: angle between the centers of mass of
/// three groups (colvarvalue::type_scalar type, range [0:PI])
class colvar::angle
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group *group1;
/// Atom group
cvm::atom_group *group2;
/// Atom group
cvm::atom_group *group3;
/// Inter site vectors
cvm::rvector r21, r23;
/// Inter site vector norms
cvm::real r21l, r23l;
/// Derivatives wrt group centers of mass
cvm::rvector dxdr1, dxdr3;
/// Compute total force on first site only to avoid unwanted
/// coupling to other colvars (see e.g. Ciccotti et al., 2005)
/// (or to allow dummy atoms)
bool b_1site_force;
public:
/// Initialize by parsing the configuration
angle(std::string const &conf);
/// \brief Initialize the three groups after three atoms
angle(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3);
angle();
virtual ~angle() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: angle between the dipole of a molecule and an axis
/// formed by two groups of atoms(colvarvalue::type_scalar type, range [0:PI])
class colvar::dipole_angle
: public colvar::cvc
{
protected:
/// Dipole atom group
cvm::atom_group *group1;
/// Atom group
cvm::atom_group *group2;
/// Atom group
cvm::atom_group *group3;
/// Inter site vectors
cvm::rvector r21, r23;
/// Inter site vector norms
cvm::real r21l, r23l;
/// Derivatives wrt group centers of mass
cvm::rvector dxdr1, dxdr3;
/// Compute total force on first site only to avoid unwanted
/// coupling to other colvars (see e.g. Ciccotti et al., 2005)
/// (or to allow dummy atoms)
bool b_1site_force;
public:
/// Initialize by parsing the configuration
dipole_angle (std::string const &conf);
/// \brief Initialize the three groups after three atoms
dipole_angle (cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3);
dipole_angle();
virtual ~dipole_angle() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force (colvarvalue const &force);
virtual cvm::real dist2 (colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad (colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: dihedral between the centers of mass of
/// four groups (colvarvalue::type_scalar type, range [-PI:PI])
class colvar::dihedral
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group *group1;
/// Atom group
cvm::atom_group *group2;
/// Atom group
cvm::atom_group *group3;
/// Atom group
cvm::atom_group *group4;
/// Inter site vectors
cvm::rvector r12, r23, r34;
/// \brief Compute total force on first site only to avoid unwanted
/// coupling to other colvars (see e.g. Ciccotti et al., 2005)
bool b_1site_force;
public:
/// Initialize by parsing the configuration
dihedral(std::string const &conf);
/// \brief Initialize the four groups after four atoms
dihedral(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3, cvm::atom const &a4);
dihedral();
virtual ~dihedral() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
/// Redefined to handle the 2*PI periodicity
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual void wrap(colvarvalue &x) const;
};
/// \brief Colvar component: coordination number between two groups
/// (colvarvalue::type_scalar type, range [0:N1*N2])
class colvar::coordnum
: public colvar::cvc
{
protected:
/// First atom group
cvm::atom_group *group1;
/// Second atom group
cvm::atom_group *group2;
/// \brief "Cutoff" for isotropic calculation (default)
cvm::real r0;
/// \brief "Cutoff vector" for anisotropic calculation
cvm::rvector r0_vec;
/// \brief Wheter dist/r0 or \vec{dist}*\vec{1/r0_vec} should ne be
/// used
bool b_anisotropic;
/// Integer exponent of the function numerator
int en;
/// Integer exponent of the function denominator
int ed;
/// \brief If true, group2 will be treated as a single atom
/// (default: loop over all pairs of atoms in group1 and group2)
bool b_group2_center_only;
public:
/// Constructor
coordnum(std::string const &conf);
coordnum();
virtual ~coordnum() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
template<bool b_gradients>
/// \brief Calculate a coordination number through the function
/// (1-x**n)/(1-x**m), x = |A1-A2|/r0 \param r0 "cutoff" for the
/// coordination number \param exp_num \i n exponent \param exp_den
/// \i m exponent \param A1 atom \param A2 atom
static cvm::real switching_function(cvm::real const &r0,
int const &exp_num, int const &exp_den,
cvm::atom &A1, cvm::atom &A2);
template<bool b_gradients>
/// \brief Calculate a coordination number through the function
/// (1-x**n)/(1-x**m), x = |(A1-A2)*(r0_vec)^-|1 \param r0_vec
/// vector of different cutoffs in the three directions \param
/// exp_num \i n exponent \param exp_den \i m exponent \param A1
/// atom \param A2 atom
static cvm::real switching_function(cvm::rvector const &r0_vec,
int const &exp_num, int const &exp_den,
cvm::atom &A1, cvm::atom &A2);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: self-coordination number within a group
/// (colvarvalue::type_scalar type, range [0:N*(N-1)/2])
class colvar::selfcoordnum
: public colvar::cvc
{
protected:
/// First atom group
cvm::atom_group *group1;
/// \brief "Cutoff" for isotropic calculation (default)
cvm::real r0;
/// Integer exponent of the function numerator
int en;
/// Integer exponent of the function denominator
int ed;
public:
/// Constructor
selfcoordnum(std::string const &conf);
selfcoordnum();
virtual ~selfcoordnum() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
template<bool b_gradients>
/// \brief Calculate a coordination number through the function
/// (1-x**n)/(1-x**m), x = |A1-A2|/r0 \param r0 "cutoff" for the
/// coordination number \param exp_num \i n exponent \param exp_den
/// \i m exponent \param A1 atom \param A2 atom
static cvm::real switching_function(cvm::real const &r0,
int const &exp_num, int const &exp_den,
cvm::atom &A1, cvm::atom &A2);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: coordination number between two groups
/// (colvarvalue::type_scalar type, range [0:N1*N2])
class colvar::groupcoordnum
: public colvar::distance
{
protected:
/// \brief "Cutoff" for isotropic calculation (default)
cvm::real r0;
/// \brief "Cutoff vector" for anisotropic calculation
cvm::rvector r0_vec;
/// \brief Wheter dist/r0 or \vec{dist}*\vec{1/r0_vec} should ne be
/// used
bool b_anisotropic;
/// Integer exponent of the function numerator
int en;
/// Integer exponent of the function denominator
int ed;
public:
/// Constructor
groupcoordnum(std::string const &conf);
groupcoordnum();
virtual ~groupcoordnum() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
template<bool b_gradients>
/// \brief Calculate a coordination number through the function
/// (1-x**n)/(1-x**m), x = |A1-A2|/r0 \param r0 "cutoff" for the
/// coordination number \param exp_num \i n exponent \param exp_den
/// \i m exponent \param A1 atom \param A2 atom
static cvm::real switching_function(cvm::real const &r0,
int const &exp_num, int const &exp_den,
cvm::atom &A1, cvm::atom &A2);
/*
template<bool b_gradients>
/// \brief Calculate a coordination number through the function
/// (1-x**n)/(1-x**m), x = |(A1-A2)*(r0_vec)^-|1 \param r0_vec
/// vector of different cutoffs in the three directions \param
/// exp_num \i n exponent \param exp_den \i m exponent \param A1
/// atom \param A2 atom
static cvm::real switching_function(cvm::rvector const &r0_vec,
int const &exp_num, int const &exp_den,
cvm::atom &A1, cvm::atom &A2);
*/
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: hydrogen bond, defined as the product of
/// a colvar::coordnum and 1/2*(1-cos((180-ang)/ang_tol))
/// (colvarvalue::type_scalar type, range [0:1])
class colvar::h_bond
: public colvar::cvc
{
protected:
/// \brief "Cutoff" distance between acceptor and donor
cvm::real r0;
/// Integer exponent of the function numerator
int en;
/// Integer exponent of the function denominator
int ed;
public:
h_bond(std::string const &conf);
/// Constructor for atoms already allocated
h_bond(cvm::atom const &acceptor,
cvm::atom const &donor,
cvm::real r0, int en, int ed);
h_bond();
virtual ~h_bond();
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: alpha helix content of a contiguous
/// segment of 5 or more residues, implemented as a sum of phi/psi
/// dihedral angles and hydrogen bonds (colvarvalue::type_scalar type,
/// range [0:1])
// class colvar::alpha_dihedrals
// : public colvar::cvc
// {
// protected:
// /// Alpha-helical reference phi value
// cvm::real phi_ref;
// /// Alpha-helical reference psi value
// cvm::real psi_ref;
// /// List of phi dihedral angles
// std::vector<dihedral *> phi;
// /// List of psi dihedral angles
// std::vector<dihedral *> psi;
// /// List of hydrogen bonds
// std::vector<h_bond *> hb;
// public:
// alpha_dihedrals (std::string const &conf);
// alpha_dihedrals();
// virtual ~alpha_dihedrals() {}
// virtual void calc_value();
// virtual void calc_gradients();
// virtual void apply_force (colvarvalue const &force);
// virtual cvm::real dist2 (colvarvalue const &x1,
// colvarvalue const &x2) const;
// virtual colvarvalue dist2_lgrad (colvarvalue const &x1,
// colvarvalue const &x2) const;
// virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
// colvarvalue const &x2) const;
// };
/// \brief Colvar component: alpha helix content of a contiguous
/// segment of 5 or more residues, implemented as a sum of Ca-Ca-Ca
/// angles and hydrogen bonds (colvarvalue::type_scalar type, range
/// [0:1])
class colvar::alpha_angles
: public colvar::cvc
{
protected:
/// Reference Calpha-Calpha angle (default: 88 degrees)
cvm::real theta_ref;
/// Tolerance on the Calpha-Calpha angle
cvm::real theta_tol;
/// List of Calpha-Calpha angles
std::vector<angle *> theta;
/// List of hydrogen bonds
std::vector<h_bond *> hb;
/// Contribution of the hb terms
cvm::real hb_coeff;
public:
alpha_angles(std::string const &conf);
alpha_angles();
virtual ~alpha_angles();
void calc_value();
void calc_gradients();
void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: dihedPC
/// Projection of the config onto a dihedral principal component
/// See e.g. Altis et al., J. Chem. Phys 126, 244111 (2007)
/// Based on a set of 'dihedral' cvcs
class colvar::dihedPC
: public colvar::cvc
{
protected:
std::vector<dihedral *> theta;
std::vector<cvm::real> coeffs;
public:
dihedPC(std::string const &conf);
dihedPC();
virtual ~dihedPC();
void calc_value();
void calc_gradients();
void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: orientation in space of an atom group,
/// with respect to a set of reference coordinates
/// (colvarvalue::type_quaternion type, range
/// [-1:1]x[-1:1]x[-1:1]x[-1:1])
class colvar::orientation
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group * atoms;
/// Center of geometry of the group
cvm::atom_pos atoms_cog;
/// Reference coordinates
std::vector<cvm::atom_pos> ref_pos;
/// Rotation object
cvm::rotation rot;
/// \brief This is used to remove jumps in the sign of the
/// quaternion, which may be annoying in the colvars trajectory
cvm::quaternion ref_quat;
public:
orientation(std::string const &conf);
orientation();
virtual ~orientation() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: angle of rotation with respect to a set
/// of reference coordinates (colvarvalue::type_scalar type, range
/// [0:PI))
class colvar::orientation_angle
: public colvar::orientation
{
public:
orientation_angle(std::string const &conf);
orientation_angle();
virtual ~orientation_angle() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: cosine of the angle of rotation with respect to a set
/// of reference coordinates (colvarvalue::type_scalar type, range
/// [-1:1])
class colvar::orientation_proj
: public colvar::orientation
{
public:
orientation_proj(std::string const &conf);
orientation_proj();
virtual ~orientation_proj() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: projection of the orientation vector onto
/// a predefined axis (colvarvalue::type_scalar type, range [-1:1])
class colvar::tilt
: public colvar::orientation
{
protected:
cvm::rvector axis;
public:
tilt(std::string const &conf);
tilt();
virtual ~tilt() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
/// \brief Colvar component: angle of rotation around a predefined
/// axis (colvarvalue::type_scalar type, range [-PI:PI])
class colvar::spin_angle
: public colvar::orientation
{
protected:
cvm::rvector axis;
public:
spin_angle(std::string const &conf);
spin_angle();
virtual ~spin_angle() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
/// Redefined to handle the 2*PI periodicity
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
/// Redefined to handle the 2*PI periodicity
virtual void wrap(colvarvalue &x) const;
};
/// \brief Colvar component: root mean square deviation (RMSD) of a
/// group with respect to a set of reference coordinates; uses \link
/// colvar::orientation \endlink to calculate the rotation matrix
/// (colvarvalue::type_scalar type, range [0:*))
class colvar::rmsd
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group *atoms;
/// Reference coordinates (for RMSD calculation only)
std::vector<cvm::atom_pos> ref_pos;
public:
/// Constructor
rmsd(std::string const &conf);
virtual ~rmsd() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void calc_force_invgrads();
virtual void calc_Jacobian_derivative();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
// \brief Colvar component: flat vector of Cartesian coordinates
// Mostly useful to compute scripted colvar values
class colvar::cartesian
: public colvar::cvc
{
protected:
/// Atom group
cvm::atom_group *atoms;
/// Which Cartesian coordinates to include
std::vector<size_t> axes;
public:
cartesian(std::string const &conf);
cartesian();
virtual ~cartesian() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
};
// metrics functions for cvc implementations
// simple definitions of the distance functions; these are useful only
// for optimization (the type check performed in the default
// colvarcomp functions is skipped)
// definitions assuming the scalar type
#define simple_scalar_dist_functions(TYPE) \
\
\
cvm::real colvar::TYPE::dist2(colvarvalue const &x1, \
colvarvalue const &x2) const \
{ \
return (x1.real_value - x2.real_value)*(x1.real_value - x2.real_value); \
} \
\
\
colvarvalue colvar::TYPE::dist2_lgrad(colvarvalue const &x1, \
colvarvalue const &x2) const \
{ \
return 2.0 * (x1.real_value - x2.real_value); \
} \
\
\
colvarvalue colvar::TYPE::dist2_rgrad(colvarvalue const &x1, \
colvarvalue const &x2) const \
{ \
return this->dist2_lgrad(x2, x1); \
} \
\
#endif
diff --git a/lib/colvars/colvarcomp_angles.cpp b/lib/colvars/colvarcomp_angles.cpp
index 0204f3b4b..9f879a4c4 100644
--- a/lib/colvars/colvarcomp_angles.cpp
+++ b/lib/colvars/colvarcomp_angles.cpp
@@ -1,512 +1,669 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvar.h"
#include "colvarcomp.h"
#include <cmath>
colvar::angle::angle(std::string const &conf)
: cvc(conf)
{
function_type = "angle";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3");
init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
}
colvar::angle::angle(cvm::atom const &a1,
cvm::atom const &a2,
cvm::atom const &a3)
{
function_type = "angle";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3));
- atom_groups.push_back(group1);
- atom_groups.push_back(group2);
- atom_groups.push_back(group3);
+ register_atom_group(group1);
+ register_atom_group(group2);
+ register_atom_group(group3);
x.type(colvarvalue::type_scalar);
}
colvar::angle::angle()
{
function_type = "angle";
x.type(colvarvalue::type_scalar);
}
void colvar::angle::calc_value()
{
cvm::atom_pos const g1_pos = group1->center_of_mass();
cvm::atom_pos const g2_pos = group2->center_of_mass();
cvm::atom_pos const g3_pos = group3->center_of_mass();
- r21 = cvm::position_distance(g2_pos, g1_pos);
+ r21 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g2_pos, g1_pos) :
+ g1_pos - g2_pos;
r21l = r21.norm();
- r23 = cvm::position_distance(g2_pos, g3_pos);
+ r23 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g2_pos, g3_pos) :
+ g3_pos - g2_pos;
r23l = r23.norm();
- cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
+ cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
x.real_value = (180.0/PI) * std::acos(cos_theta);
}
void colvar::angle::calc_gradients()
{
cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
cvm::real const dxdcos = -1.0 / std::sqrt(1.0 - cos_theta*cos_theta);
dxdr1 = (180.0/PI) * dxdcos *
(1.0/r21l) * ( r23/r23l + (-1.0) * cos_theta * r21/r21l );
dxdr3 = (180.0/PI) * dxdcos *
(1.0/r23l) * ( r21/r21l + (-1.0) * cos_theta * r23/r23l );
group1->set_weighted_gradient(dxdr1);
group2->set_weighted_gradient((dxdr1 + dxdr3) * (-1.0));
group3->set_weighted_gradient(dxdr3);
}
void colvar::angle::calc_force_invgrads()
{
// This uses a force measurement on groups 1 and 3 only
// to keep in line with the implicit variable change used to
// evaluate the Jacobian term (essentially polar coordinates
// centered on group2, which means group2 is kept fixed
// when propagating changes in the angle)
if (is_enabled(f_cvc_one_site_total_force)) {
group1->read_total_forces();
cvm::real norm_fact = 1.0 / dxdr1.norm2();
ft.real_value = norm_fact * dxdr1 * group1->total_force();
} else {
group1->read_total_forces();
group3->read_total_forces();
cvm::real norm_fact = 1.0 / (dxdr1.norm2() + dxdr3.norm2());
ft.real_value = norm_fact * ( dxdr1 * group1->total_force()
+ dxdr3 * group3->total_force());
}
return;
}
void colvar::angle::calc_Jacobian_derivative()
{
// det(J) = (2 pi) r^2 * sin(theta)
// hence Jd = cot(theta)
const cvm::real theta = x.real_value * PI / 180.0;
jd = PI / 180.0 * (theta != 0.0 ? std::cos(theta) / std::sin(theta) : 0.0);
}
void colvar::angle::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(angle)
colvar::dipole_angle::dipole_angle(std::string const &conf)
: cvc(conf)
{
function_type = "dipole_angle";
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3");
init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
}
colvar::dipole_angle::dipole_angle(cvm::atom const &a1,
cvm::atom const &a2,
cvm::atom const &a3)
{
function_type = "dipole_angle";
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3));
- atom_groups.push_back(group1);
- atom_groups.push_back(group2);
- atom_groups.push_back(group3);
+ register_atom_group(group1);
+ register_atom_group(group2);
+ register_atom_group(group3);
x.type(colvarvalue::type_scalar);
}
colvar::dipole_angle::dipole_angle()
{
function_type = "dipole_angle";
x.type(colvarvalue::type_scalar);
}
void colvar::dipole_angle::calc_value()
{
cvm::atom_pos const g1_pos = group1->center_of_mass();
cvm::atom_pos const g2_pos = group2->center_of_mass();
cvm::atom_pos const g3_pos = group3->center_of_mass();
group1->calc_dipole(g1_pos);
r21 = group1->dipole();
r21l = r21.norm();
- r23 = cvm::position_distance(g2_pos, g3_pos);
+ r23 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g2_pos, g3_pos) :
+ g3_pos - g2_pos;
r23l = r23.norm();
- cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
+ cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
x.real_value = (180.0/PI) * std::acos(cos_theta);
}
//to be implemented
//void colvar::dipole_angle::calc_force_invgrads(){}
//void colvar::dipole_angle::calc_Jacobian_derivative(){}
void colvar::dipole_angle::calc_gradients()
{
cvm::real const cos_theta = (r21*r23)/(r21l*r23l);
cvm::real const dxdcos = -1.0 / std::sqrt(1.0 - cos_theta*cos_theta);
dxdr1 = (180.0/PI) * dxdcos *
(1.0/r21l)* (r23/r23l + (-1.0) * cos_theta * r21/r21l );
dxdr3 = (180.0/PI) * dxdcos *
(1.0/r23l) * ( r21/r21l + (-1.0) * cos_theta * r23/r23l );
//this auxiliar variables are to avoid numerical errors inside "for"
double aux1 = group1->total_charge/group1->total_mass;
// double aux2 = group2->total_charge/group2->total_mass;
// double aux3 = group3->total_charge/group3->total_mass;
size_t i;
for (i = 0; i < group1->size(); i++) {
(*group1)[i].grad =((*group1)[i].charge + (-1)* (*group1)[i].mass * aux1) * (dxdr1);
}
for (i = 0; i < group2->size(); i++) {
(*group2)[i].grad = ((*group2)[i].mass/group2->total_mass)* dxdr3 * (-1.0);
}
for (i = 0; i < group3->size(); i++) {
(*group3)[i].grad =((*group3)[i].mass/group3->total_mass) * (dxdr3);
}
}
void colvar::dipole_angle::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(dipole_angle)
colvar::dihedral::dihedral(std::string const &conf)
: cvc(conf)
{
function_type = "dihedral";
period = 360.0;
b_periodic = true;
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
group3 = parse_group(conf, "group3");
group4 = parse_group(conf, "group4");
init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
}
colvar::dihedral::dihedral(cvm::atom const &a1,
cvm::atom const &a2,
cvm::atom const &a3,
cvm::atom const &a4)
{
if (cvm::debug())
cvm::log("Initializing dihedral object from atom groups.\n");
function_type = "dihedral";
period = 360.0;
b_periodic = true;
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
b_1site_force = false;
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
group3 = new cvm::atom_group(std::vector<cvm::atom>(1, a3));
group4 = new cvm::atom_group(std::vector<cvm::atom>(1, a4));
- atom_groups.push_back(group1);
- atom_groups.push_back(group2);
- atom_groups.push_back(group3);
- atom_groups.push_back(group4);
+ register_atom_group(group1);
+ register_atom_group(group2);
+ register_atom_group(group3);
+ register_atom_group(group4);
x.type(colvarvalue::type_scalar);
if (cvm::debug())
cvm::log("Done initializing dihedral object from atom groups.\n");
}
colvar::dihedral::dihedral()
{
function_type = "dihedral";
period = 360.0;
b_periodic = true;
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
x.type(colvarvalue::type_scalar);
}
void colvar::dihedral::calc_value()
{
cvm::atom_pos const g1_pos = group1->center_of_mass();
cvm::atom_pos const g2_pos = group2->center_of_mass();
cvm::atom_pos const g3_pos = group3->center_of_mass();
cvm::atom_pos const g4_pos = group4->center_of_mass();
// Usual sign convention: r12 = r2 - r1
- r12 = cvm::position_distance(g1_pos, g2_pos);
- r23 = cvm::position_distance(g2_pos, g3_pos);
- r34 = cvm::position_distance(g3_pos, g4_pos);
+ r12 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g1_pos, g2_pos) :
+ g2_pos - g1_pos;
+ r23 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g2_pos, g3_pos) :
+ g3_pos - g2_pos;
+ r34 = is_enabled(f_cvc_pbc_minimum_image) ?
+ cvm::position_distance(g3_pos, g4_pos) :
+ g4_pos - g3_pos;
cvm::rvector const n1 = cvm::rvector::outer(r12, r23);
cvm::rvector const n2 = cvm::rvector::outer(r23, r34);
cvm::real const cos_phi = n1 * n2;
cvm::real const sin_phi = n1 * r34 * r23.norm();
x.real_value = (180.0/PI) * std::atan2(sin_phi, cos_phi);
this->wrap(x);
}
void colvar::dihedral::calc_gradients()
{
cvm::rvector A = cvm::rvector::outer(r12, r23);
cvm::real rA = A.norm();
cvm::rvector B = cvm::rvector::outer(r23, r34);
cvm::real rB = B.norm();
cvm::rvector C = cvm::rvector::outer(r23, A);
cvm::real rC = C.norm();
cvm::real const cos_phi = (A*B)/(rA*rB);
cvm::real const sin_phi = (C*B)/(rC*rB);
cvm::rvector f1, f2, f3;
rB = 1.0/rB;
B *= rB;
if (std::fabs(sin_phi) > 0.1) {
rA = 1.0/rA;
A *= rA;
cvm::rvector const dcosdA = rA*(cos_phi*A-B);
cvm::rvector const dcosdB = rB*(cos_phi*B-A);
rA = 1.0;
cvm::real const K = (1.0/sin_phi) * (180.0/PI);
- f1 = K * cvm::rvector::outer(r23, dcosdA);
- f3 = K * cvm::rvector::outer(dcosdB, r23);
- f2 = K * (cvm::rvector::outer(dcosdA, r12)
- + cvm::rvector::outer(r34, dcosdB));
+ f1 = K * cvm::rvector::outer(r23, dcosdA);
+ f3 = K * cvm::rvector::outer(dcosdB, r23);
+ f2 = K * (cvm::rvector::outer(dcosdA, r12)
+ + cvm::rvector::outer(r34, dcosdB));
}
else {
rC = 1.0/rC;
C *= rC;
cvm::rvector const dsindC = rC*(sin_phi*C-B);
cvm::rvector const dsindB = rB*(sin_phi*B-C);
rC = 1.0;
cvm::real const K = (-1.0/cos_phi) * (180.0/PI);
f1.x = K*((r23.y*r23.y + r23.z*r23.z)*dsindC.x
- r23.x*r23.y*dsindC.y
- r23.x*r23.z*dsindC.z);
f1.y = K*((r23.z*r23.z + r23.x*r23.x)*dsindC.y
- r23.y*r23.z*dsindC.z
- r23.y*r23.x*dsindC.x);
f1.z = K*((r23.x*r23.x + r23.y*r23.y)*dsindC.z
- r23.z*r23.x*dsindC.x
- r23.z*r23.y*dsindC.y);
f3 = cvm::rvector::outer(dsindB, r23);
f3 *= K;
f2.x = K*(-(r23.y*r12.y + r23.z*r12.z)*dsindC.x
+(2.0*r23.x*r12.y - r12.x*r23.y)*dsindC.y
+(2.0*r23.x*r12.z - r12.x*r23.z)*dsindC.z
+dsindB.z*r34.y - dsindB.y*r34.z);
f2.y = K*(-(r23.z*r12.z + r23.x*r12.x)*dsindC.y
+(2.0*r23.y*r12.z - r12.y*r23.z)*dsindC.z
+(2.0*r23.y*r12.x - r12.y*r23.x)*dsindC.x
+dsindB.x*r34.z - dsindB.z*r34.x);
f2.z = K*(-(r23.x*r12.x + r23.y*r12.y)*dsindC.z
+(2.0*r23.z*r12.x - r12.z*r23.x)*dsindC.x
+(2.0*r23.z*r12.y - r12.z*r23.y)*dsindC.y
+dsindB.y*r34.x - dsindB.x*r34.y);
}
group1->set_weighted_gradient(-f1);
group2->set_weighted_gradient(-f2 + f1);
group3->set_weighted_gradient(-f3 + f2);
group4->set_weighted_gradient(f3);
}
void colvar::dihedral::calc_force_invgrads()
{
cvm::rvector const u12 = r12.unit();
cvm::rvector const u23 = r23.unit();
cvm::rvector const u34 = r34.unit();
cvm::real const d12 = r12.norm();
cvm::real const d34 = r34.norm();
cvm::rvector const cross1 = (cvm::rvector::outer(u23, u12)).unit();
cvm::rvector const cross4 = (cvm::rvector::outer(u23, u34)).unit();
cvm::real const dot1 = u23 * u12;
cvm::real const dot4 = u23 * u34;
cvm::real const fact1 = d12 * std::sqrt(1.0 - dot1 * dot1);
cvm::real const fact4 = d34 * std::sqrt(1.0 - dot4 * dot4);
group1->read_total_forces();
if (is_enabled(f_cvc_one_site_total_force)) {
// This is only measuring the force on group 1
ft.real_value = PI/180.0 * fact1 * (cross1 * group1->total_force());
} else {
// Default case: use groups 1 and 4
group4->read_total_forces();
ft.real_value = PI/180.0 * 0.5 * (fact1 * (cross1 * group1->total_force())
- + fact4 * (cross4 * group4->total_force()));
+ + fact4 * (cross4 * group4->total_force()));
}
}
void colvar::dihedral::calc_Jacobian_derivative()
{
// With this choice of inverse gradient ("internal coordinates"), Jacobian correction is 0
jd = 0.0;
}
void colvar::dihedral::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
if (!group3->noforce)
group3->apply_colvar_force(force.real_value);
if (!group4->noforce)
group4->apply_colvar_force(force.real_value);
}
// metrics functions for cvc implementations with a periodicity
cvm::real colvar::dihedral::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::dihedral::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::dihedral::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::dihedral::wrap(colvarvalue &x) const
{
if ((x.real_value - wrap_center) >= 180.0) {
x.real_value -= 360.0;
return;
}
if ((x.real_value - wrap_center) < -180.0) {
x.real_value += 360.0;
return;
}
return;
}
+
+
+colvar::polar_theta::polar_theta(std::string const &conf)
+ : cvc(conf)
+{
+ function_type = "polar_theta";
+ enable(f_cvc_com_based);
+
+ atoms = parse_group(conf, "atoms");
+ init_total_force_params(conf);
+ x.type(colvarvalue::type_scalar);
+}
+
+
+colvar::polar_theta::polar_theta()
+{
+ function_type = "polar_theta";
+ x.type(colvarvalue::type_scalar);
+}
+
+
+void colvar::polar_theta::calc_value()
+{
+ cvm::rvector pos = atoms->center_of_mass();
+ r = atoms->center_of_mass().norm();
+ // Internal values of theta and phi are radians
+ theta = (r > 0.) ? std::acos(pos.z / r) : 0.;
+ phi = std::atan2(pos.y, pos.x);
+ x.real_value = (180.0/PI) * theta;
+}
+
+
+void colvar::polar_theta::calc_gradients()
+{
+ if (r == 0.)
+ atoms->set_weighted_gradient(cvm::rvector(0., 0., 0.));
+ else
+ atoms->set_weighted_gradient(cvm::rvector(
+ (180.0/PI) * std::cos(theta) * std::cos(phi) / r,
+ (180.0/PI) * std::cos(theta) * std::sin(phi) / r,
+ (180.0/PI) * -std::sin(theta) / r));
+}
+
+
+void colvar::polar_theta::apply_force(colvarvalue const &force)
+{
+ if (!atoms->noforce)
+ atoms->apply_colvar_force(force.real_value);
+}
+
+
+simple_scalar_dist_functions(polar_theta)
+
+
+colvar::polar_phi::polar_phi(std::string const &conf)
+ : cvc(conf)
+{
+ function_type = "polar_phi";
+ period = 360.0;
+ enable(f_cvc_com_based);
+
+ atoms = parse_group(conf, "atoms");
+ init_total_force_params(conf);
+ x.type(colvarvalue::type_scalar);
+}
+
+
+colvar::polar_phi::polar_phi()
+{
+ function_type = "polar_phi";
+ period = 360.0;
+ x.type(colvarvalue::type_scalar);
+}
+
+
+void colvar::polar_phi::calc_value()
+{
+ cvm::rvector pos = atoms->center_of_mass();
+ r = atoms->center_of_mass().norm();
+ // Internal values of theta and phi are radians
+ theta = (r > 0.) ? std::acos(pos.z / r) : 0.;
+ phi = std::atan2(pos.y, pos.x);
+ x.real_value = (180.0/PI) * phi;
+}
+
+
+void colvar::polar_phi::calc_gradients()
+{
+ atoms->set_weighted_gradient(cvm::rvector(
+ (180.0/PI) * -std::sin(phi) / (r*std::sin(theta)),
+ (180.0/PI) * std::cos(phi) / (r*std::sin(theta)),
+ 0.));
+}
+
+
+void colvar::polar_phi::apply_force(colvarvalue const &force)
+{
+ if (!atoms->noforce)
+ atoms->apply_colvar_force(force.real_value);
+}
+
+
+// Same as dihedral, for polar_phi
+
+cvm::real colvar::polar_phi::dist2(colvarvalue const &x1,
+ colvarvalue const &x2) const
+{
+ cvm::real diff = x1.real_value - x2.real_value;
+ diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
+ return diff * diff;
+}
+
+
+colvarvalue colvar::polar_phi::dist2_lgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const
+{
+ cvm::real diff = x1.real_value - x2.real_value;
+ diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
+ return 2.0 * diff;
+}
+
+
+colvarvalue colvar::polar_phi::dist2_rgrad(colvarvalue const &x1,
+ colvarvalue const &x2) const
+{
+ cvm::real diff = x1.real_value - x2.real_value;
+ diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
+ return (-2.0) * diff;
+}
+
+
+void colvar::polar_phi::wrap(colvarvalue &x) const
+{
+ if ((x.real_value - wrap_center) >= 180.0) {
+ x.real_value -= 360.0;
+ return;
+ }
+
+ if ((x.real_value - wrap_center) < -180.0) {
+ x.real_value += 360.0;
+ return;
+ }
+
+ return;
+}
diff --git a/lib/colvars/colvarcomp_coordnums.cpp b/lib/colvars/colvarcomp_coordnums.cpp
index 987a16a81..369d489e2 100644
--- a/lib/colvars/colvarcomp_coordnums.cpp
+++ b/lib/colvars/colvarcomp_coordnums.cpp
@@ -1,506 +1,529 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cmath>
#include "colvarmodule.h"
#include "colvarparse.h"
#include "colvaratoms.h"
#include "colvarvalue.h"
#include "colvar.h"
#include "colvarcomp.h"
template<bool calculate_gradients>
cvm::real colvar::coordnum::switching_function(cvm::real const &r0,
int const &en,
int const &ed,
cvm::atom &A1,
cvm::atom &A2)
{
cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos);
cvm::real const l2 = diff.norm2()/(r0*r0);
// Assume en and ed are even integers, and avoid sqrt in the following
int const en2 = en/2;
int const ed2 = ed/2;
cvm::real const xn = std::pow(l2, en2);
cvm::real const xd = std::pow(l2, ed2);
cvm::real const func = (1.0-xn)/(1.0-xd);
if (calculate_gradients) {
cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
cvm::rvector const dl2dx = (2.0/(r0*r0))*diff;
A1.grad += (-1.0)*dFdl2*dl2dx;
A2.grad += dFdl2*dl2dx;
}
return func;
}
template<bool calculate_gradients>
cvm::real colvar::coordnum::switching_function(cvm::rvector const &r0_vec,
int const &en,
int const &ed,
cvm::atom &A1,
cvm::atom &A2)
{
cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos);
cvm::rvector const scal_diff(diff.x/r0_vec.x, diff.y/r0_vec.y, diff.z/r0_vec.z);
cvm::real const l2 = scal_diff.norm2();
// Assume en and ed are even integers, and avoid sqrt in the following
int const en2 = en/2;
int const ed2 = ed/2;
cvm::real const xn = std::pow(l2, en2);
cvm::real const xd = std::pow(l2, ed2);
cvm::real const func = (1.0-xn)/(1.0-xd);
if (calculate_gradients) {
cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
cvm::rvector const dl2dx((2.0/(r0_vec.x*r0_vec.x))*diff.x,
(2.0/(r0_vec.y*r0_vec.y))*diff.y,
(2.0/(r0_vec.z*r0_vec.z))*diff.z);
A1.grad += (-1.0)*dFdl2*dl2dx;
A2.grad += dFdl2*dl2dx;
}
return func;
}
colvar::coordnum::coordnum(std::string const &conf)
: cvc(conf), b_anisotropic(false), b_group2_center_only(false)
{
function_type = "coordnum";
x.type(colvarvalue::type_scalar);
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
- if (group1->b_dummy)
- cvm::fatal_error("Error: only group2 is allowed to be a dummy atom\n");
+ if (group1->b_dummy) {
+ cvm::error("Error: only group2 is allowed to be a dummy atom\n");
+ return;
+ }
bool const b_isotropic = get_keyval(conf, "cutoff", r0,
cvm::real(4.0 * cvm::unit_angstrom()));
if (get_keyval(conf, "cutoff3", r0_vec, cvm::rvector(4.0 * cvm::unit_angstrom(),
4.0 * cvm::unit_angstrom(),
4.0 * cvm::unit_angstrom()))) {
if (b_isotropic) {
cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" at the same time.\n",
INPUT_ERROR);
+ return;
}
b_anisotropic = true;
// remove meaningless negative signs
if (r0_vec.x < 0.0) r0_vec.x *= -1.0;
if (r0_vec.y < 0.0) r0_vec.y *= -1.0;
if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
}
get_keyval(conf, "expNumer", en, int(6) );
get_keyval(conf, "expDenom", ed, int(12));
if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponents provided, can only use even ones.\n", INPUT_ERROR);
}
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
+ cvm::log("Warning: only minimum-image distances are used by this variable.\n");
+ }
+
get_keyval(conf, "group2CenterOnly", b_group2_center_only, group2->b_dummy);
}
colvar::coordnum::coordnum()
: b_anisotropic(false), b_group2_center_only(false)
{
function_type = "coordnum";
x.type(colvarvalue::type_scalar);
}
void colvar::coordnum::calc_value()
{
x.real_value = 0.0;
if (b_group2_center_only) {
// create a fake atom to hold the group2 com coordinates
cvm::atom group2_com_atom;
group2_com_atom.pos = group2->center_of_mass();
if (b_anisotropic) {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
x.real_value += switching_function<false>(r0_vec, en, ed, *ai1, group2_com_atom);
} else {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
x.real_value += switching_function<false>(r0, en, ed, *ai1, group2_com_atom);
}
} else {
if (b_anisotropic) {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
x.real_value += switching_function<false>(r0_vec, en, ed, *ai1, *ai2);
}
} else {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
x.real_value += switching_function<false>(r0, en, ed, *ai1, *ai2);
}
}
}
}
void colvar::coordnum::calc_gradients()
{
if (b_group2_center_only) {
// create a fake atom to hold the group2 com coordinates
cvm::atom group2_com_atom;
group2_com_atom.pos = group2->center_of_mass();
if (b_anisotropic) {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
switching_function<true>(r0_vec, en, ed, *ai1, group2_com_atom);
} else {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
switching_function<true>(r0, en, ed, *ai1, group2_com_atom);
}
group2->set_weighted_gradient(group2_com_atom.grad);
} else {
if (b_anisotropic) {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
switching_function<true>(r0_vec, en, ed, *ai1, *ai2);
}
} else {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++)
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
switching_function<true>(r0, en, ed, *ai1, *ai2);
}
}
}
}
void colvar::coordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(coordnum)
// h_bond member functions
colvar::h_bond::h_bond(std::string const &conf)
: cvc(conf)
{
if (cvm::debug())
cvm::log("Initializing h_bond object.\n");
function_type = "h_bond";
x.type(colvarvalue::type_scalar);
int a_num, d_num;
get_keyval(conf, "acceptor", a_num, -1);
get_keyval(conf, "donor", d_num, -1);
if ( (a_num == -1) || (d_num == -1) ) {
- cvm::fatal_error("Error: either acceptor or donor undefined.\n");
+ cvm::error("Error: either acceptor or donor undefined.\n");
+ return;
}
cvm::atom acceptor = cvm::atom(a_num);
cvm::atom donor = cvm::atom(d_num);
- atom_groups.push_back(new cvm::atom_group);
+ register_atom_group(new cvm::atom_group);
atom_groups[0]->add_atom(acceptor);
atom_groups[0]->add_atom(donor);
get_keyval(conf, "cutoff", r0, (3.3 * cvm::unit_angstrom()));
get_keyval(conf, "expNumer", en, 6);
get_keyval(conf, "expDenom", ed, 8);
if ( (en%2) || (ed%2) ) {
- cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n");
+ cvm::error("Error: odd exponents provided, can only use even ones.\n");
+ return;
}
if (cvm::debug())
cvm::log("Done initializing h_bond object.\n");
}
colvar::h_bond::h_bond(cvm::atom const &acceptor,
cvm::atom const &donor,
cvm::real r0_i, int en_i, int ed_i)
: r0(r0_i), en(en_i), ed(ed_i)
{
function_type = "h_bond";
x.type(colvarvalue::type_scalar);
- atom_groups.push_back(new cvm::atom_group);
+ register_atom_group(new cvm::atom_group);
atom_groups[0]->add_atom(acceptor);
atom_groups[0]->add_atom(donor);
}
colvar::h_bond::h_bond()
: cvc()
{
function_type = "h_bond";
x.type(colvarvalue::type_scalar);
}
colvar::h_bond::~h_bond()
{
delete atom_groups[0];
}
void colvar::h_bond::calc_value()
{
x.real_value = colvar::coordnum::switching_function<false>(r0, en, ed, (*atom_groups[0])[0], (*atom_groups[0])[1]);
}
void colvar::h_bond::calc_gradients()
{
colvar::coordnum::switching_function<true>(r0, en, ed, (*atom_groups[0])[0], (*atom_groups[0])[1]);
}
void colvar::h_bond::apply_force(colvarvalue const &force)
{
(atom_groups[0])->apply_colvar_force(force);
}
simple_scalar_dist_functions(h_bond)
colvar::selfcoordnum::selfcoordnum(std::string const &conf)
: cvc(conf)
{
function_type = "selfcoordnum";
x.type(colvarvalue::type_scalar);
group1 = parse_group(conf, "group1");
get_keyval(conf, "cutoff", r0, cvm::real(4.0 * cvm::unit_angstrom()));
get_keyval(conf, "expNumer", en, int(6) );
get_keyval(conf, "expDenom", ed, int(12));
if ( (en%2) || (ed%2) ) {
- cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n");
+ cvm::error("Error: odd exponents provided, can only use even ones.\n");
+ return;
+ }
+
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
+ cvm::log("Warning: only minimum-image distances are used by this variable.\n");
}
}
colvar::selfcoordnum::selfcoordnum()
{
function_type = "selfcoordnum";
x.type(colvarvalue::type_scalar);
}
void colvar::selfcoordnum::calc_value()
{
x.real_value = 0.0;
for (size_t i = 0; i < group1->size() - 1; i++) {
for (size_t j = i + 1; j < group1->size(); j++) {
x.real_value += colvar::coordnum::switching_function<false>(r0, en, ed, (*group1)[i], (*group1)[j]);
}
}
}
void colvar::selfcoordnum::calc_gradients()
{
for (size_t i = 0; i < group1->size() - 1; i++) {
for (size_t j = i + 1; j < group1->size(); j++) {
colvar::coordnum::switching_function<true>(r0, en, ed, (*group1)[i], (*group1)[j]);
}
}
}
void colvar::selfcoordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce) {
group1->apply_colvar_force(force.real_value);
}
}
simple_scalar_dist_functions(selfcoordnum)
// groupcoordnum member functions
colvar::groupcoordnum::groupcoordnum(std::string const &conf)
: distance(conf), b_anisotropic(false)
{
function_type = "groupcoordnum";
x.type(colvarvalue::type_scalar);
// group1 and group2 are already initialized by distance()
- if (group1->b_dummy || group2->b_dummy)
- cvm::fatal_error("Error: neither group can be a dummy atom\n");
+ if (group1->b_dummy || group2->b_dummy) {
+ cvm::error("Error: neither group can be a dummy atom\n");
+ return;
+ }
bool const b_scale = get_keyval(conf, "cutoff", r0,
cvm::real(4.0 * cvm::unit_angstrom()));
if (get_keyval(conf, "cutoff3", r0_vec,
cvm::rvector(4.0, 4.0, 4.0), parse_silent)) {
- if (b_scale)
- cvm::fatal_error("Error: cannot specify \"scale\" and "
+ if (b_scale) {
+ cvm::error("Error: cannot specify \"scale\" and "
"\"scale3\" at the same time.\n");
+ return;
+ }
b_anisotropic = true;
// remove meaningless negative signs
if (r0_vec.x < 0.0) r0_vec.x *= -1.0;
if (r0_vec.y < 0.0) r0_vec.y *= -1.0;
if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
}
get_keyval(conf, "expNumer", en, int(6) );
get_keyval(conf, "expDenom", ed, int(12));
if ( (en%2) || (ed%2) ) {
- cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n");
+ cvm::error("Error: odd exponents provided, can only use even ones.\n");
+ return;
+ }
+
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
+ cvm::log("Warning: only minimum-image distances are used by this variable.\n");
}
}
colvar::groupcoordnum::groupcoordnum()
: b_anisotropic(false)
{
function_type = "groupcoordnum";
x.type(colvarvalue::type_scalar);
}
template<bool calculate_gradients>
cvm::real colvar::groupcoordnum::switching_function(cvm::real const &r0,
int const &en,
int const &ed,
cvm::atom &A1,
cvm::atom &A2)
{
cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos);
cvm::real const l2 = diff.norm2()/(r0*r0);
// Assume en and ed are even integers, and avoid sqrt in the following
int const en2 = en/2;
int const ed2 = ed/2;
cvm::real const xn = std::pow(l2, en2);
cvm::real const xd = std::pow(l2, ed2);
cvm::real const func = (1.0-xn)/(1.0-xd);
if (calculate_gradients) {
cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
cvm::rvector const dl2dx = (2.0/(r0*r0))*diff;
A1.grad += (-1.0)*dFdl2*dl2dx;
A2.grad += dFdl2*dl2dx;
}
return func;
}
#if 0 // AMG: I don't think there's any reason to support anisotropic,
// and I don't have those flags below in calc_value, but
// if I need them, I'll also need to uncomment this method
template<bool calculate_gradients>
cvm::real colvar::groupcoordnum::switching_function(cvm::rvector const &r0_vec,
int const &en,
int const &ed,
cvm::atom &A1,
cvm::atom &A2)
{
cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos);
cvm::rvector const scal_diff(diff.x/r0_vec.x, diff.y/r0_vec.y, diff.z/r0_vec.z);
cvm::real const l2 = scal_diff.norm2();
// Assume en and ed are even integers, and avoid sqrt in the following
int const en2 = en/2;
int const ed2 = ed/2;
cvm::real const xn = std::pow(l2, en2);
cvm::real const xd = std::pow(l2, ed2);
cvm::real const func = (1.0-xn)/(1.0-xd);
if (calculate_gradients) {
cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
cvm::rvector const dl2dx((2.0/(r0_vec.x*r0_vec.x))*diff.x,
(2.0/(r0_vec.y*r0_vec.y))*diff.y,
(2.0/(r0_vec.z*r0_vec.z))*diff.z);
A1.grad += (-1.0)*dFdl2*dl2dx;
A2.grad += dFdl2*dl2dx;
}
return func;
}
#endif
void colvar::groupcoordnum::calc_value()
{
// create fake atoms to hold the com coordinates
cvm::atom group1_com_atom;
cvm::atom group2_com_atom;
group1_com_atom.pos = group1->center_of_mass();
group2_com_atom.pos = group2->center_of_mass();
x.real_value = coordnum::switching_function<false>(r0, en, ed,
group1_com_atom, group2_com_atom);
}
void colvar::groupcoordnum::calc_gradients()
{
cvm::atom group1_com_atom;
cvm::atom group2_com_atom;
group1_com_atom.pos = group1->center_of_mass();
group2_com_atom.pos = group2->center_of_mass();
coordnum::switching_function<true>(r0, en, ed, group1_com_atom, group2_com_atom);
group1->set_weighted_gradient(group1_com_atom.grad);
group2->set_weighted_gradient(group2_com_atom.grad);
}
void colvar::groupcoordnum::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(groupcoordnum)
diff --git a/lib/colvars/colvarcomp_distances.cpp b/lib/colvars/colvarcomp_distances.cpp
index f46270246..18d154515 100644
--- a/lib/colvars/colvarcomp_distances.cpp
+++ b/lib/colvars/colvarcomp_distances.cpp
@@ -1,1463 +1,1472 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cmath>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::distance::distance(std::string const &conf)
: cvc(conf)
{
function_type = "distance";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
- if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) {
- cvm::log("Computing distance using absolute positions (not minimal-image)");
- }
-
init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
}
colvar::distance::distance()
: cvc()
{
function_type = "distance";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
- b_no_PBC = false;
x.type(colvarvalue::type_scalar);
}
void colvar::distance::calc_value()
{
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
dist_v = group2->center_of_mass() - group1->center_of_mass();
} else {
dist_v = cvm::position_distance(group1->center_of_mass(),
- group2->center_of_mass());
+ group2->center_of_mass());
}
x.real_value = dist_v.norm();
}
void colvar::distance::calc_gradients()
{
cvm::rvector const u = dist_v.unit();
group1->set_weighted_gradient(-1.0 * u);
group2->set_weighted_gradient( u);
}
void colvar::distance::calc_force_invgrads()
{
group1->read_total_forces();
if (is_enabled(f_cvc_one_site_total_force)) {
ft.real_value = -1.0 * (group1->total_force() * dist_v.unit());
} else {
group2->read_total_forces();
ft.real_value = 0.5 * ((group2->total_force() - group1->total_force()) * dist_v.unit());
}
}
void colvar::distance::calc_Jacobian_derivative()
{
jd.real_value = x.real_value ? (2.0 / x.real_value) : 0.0;
}
void colvar::distance::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(distance)
colvar::distance_vec::distance_vec(std::string const &conf)
: distance(conf)
{
function_type = "distance_vec";
enable(f_cvc_com_based);
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_3vector);
}
colvar::distance_vec::distance_vec()
: distance()
{
function_type = "distance_vec";
enable(f_cvc_com_based);
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_3vector);
}
void colvar::distance_vec::calc_value()
{
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
x.rvector_value = group2->center_of_mass() - group1->center_of_mass();
} else {
x.rvector_value = cvm::position_distance(group1->center_of_mass(),
- group2->center_of_mass());
+ group2->center_of_mass());
}
}
void colvar::distance_vec::calc_gradients()
{
// gradients are not stored: a 3x3 matrix for each atom would be
// needed to store just the identity matrix
}
void colvar::distance_vec::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_force(-1.0 * force.rvector_value);
if (!group2->noforce)
group2->apply_force( force.rvector_value);
}
cvm::real colvar::distance_vec::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
return cvm::position_dist2(x1.rvector_value, x2.rvector_value);
}
colvarvalue colvar::distance_vec::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
}
colvarvalue colvar::distance_vec::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
}
colvar::distance_z::distance_z(std::string const &conf)
: cvc(conf)
{
function_type = "distance_z";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
x.type(colvarvalue::type_scalar);
// TODO detect PBC from MD engine (in simple cases)
// and then update period in real time
if (period != 0.0)
b_periodic = true;
if ((wrap_center != 0.0) && (period == 0.0)) {
cvm::error("Error: wrapAround was defined in a distanceZ component,"
" but its period has not been set.\n");
return;
}
main = parse_group(conf, "main");
ref1 = parse_group(conf, "ref");
// this group is optional
ref2 = parse_group(conf, "ref2", true);
if (ref2 && ref2->size()) {
cvm::log("Using axis joining the centers of mass of groups \"ref\" and \"ref2\"");
fixed_axis = false;
if (key_lookup(conf, "axis"))
cvm::log("Warning: explicit axis definition will be ignored!");
} else {
if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
if (axis.norm2() == 0.0) {
cvm::error("Axis vector is zero!");
return;
}
if (axis.norm2() != 1.0) {
axis = axis.unit();
cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
}
}
fixed_axis = true;
}
- if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) {
- cvm::log("Computing distance using absolute positions (not minimal-image)");
- }
-
init_total_force_params(conf);
}
colvar::distance_z::distance_z()
{
function_type = "distance_z";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
x.type(colvarvalue::type_scalar);
}
void colvar::distance_z::calc_value()
{
if (fixed_axis) {
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
dist_v = main->center_of_mass() - ref1->center_of_mass();
} else {
dist_v = cvm::position_distance(ref1->center_of_mass(),
- main->center_of_mass());
+ main->center_of_mass());
}
} else {
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
dist_v = main->center_of_mass() -
(0.5 * (ref1->center_of_mass() + ref2->center_of_mass()));
axis = ref2->center_of_mass() - ref1->center_of_mass();
} else {
dist_v = cvm::position_distance(0.5 * (ref1->center_of_mass() +
- ref2->center_of_mass()), main->center_of_mass());
- axis = cvm::position_distance(ref1->center_of_mass(), ref2->center_of_mass());
+ ref2->center_of_mass()),
+ main->center_of_mass());
+ axis = cvm::position_distance(ref1->center_of_mass(),
+ ref2->center_of_mass());
}
axis_norm = axis.norm();
axis = axis.unit();
}
x.real_value = axis * dist_v;
this->wrap(x);
}
void colvar::distance_z::calc_gradients()
{
main->set_weighted_gradient( axis );
if (fixed_axis) {
ref1->set_weighted_gradient(-1.0 * axis);
} else {
- if (b_no_PBC) {
- ref1->set_weighted_gradient( 1.0 / axis_norm * (main->center_of_mass() - ref2->center_of_mass() -
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
+ ref1->set_weighted_gradient( 1.0 / axis_norm *
+ (main->center_of_mass() - ref2->center_of_mass() -
x.real_value * axis ));
- ref2->set_weighted_gradient( 1.0 / axis_norm * (ref1->center_of_mass() - main->center_of_mass() +
+ ref2->set_weighted_gradient( 1.0 / axis_norm *
+ (ref1->center_of_mass() - main->center_of_mass() +
x.real_value * axis ));
} else {
ref1->set_weighted_gradient( 1.0 / axis_norm * (
- cvm::position_distance(ref2->center_of_mass(), main->center_of_mass()) - x.real_value * axis ));
+ cvm::position_distance(ref2->center_of_mass(),
+ main->center_of_mass()) - x.real_value * axis ));
ref2->set_weighted_gradient( 1.0 / axis_norm * (
- cvm::position_distance(main->center_of_mass(), ref1->center_of_mass()) + x.real_value * axis ));
+ cvm::position_distance(main->center_of_mass(),
+ ref1->center_of_mass()) + x.real_value * axis ));
}
}
}
void colvar::distance_z::calc_force_invgrads()
{
main->read_total_forces();
if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
ref1->read_total_forces();
ft.real_value = 0.5 * ((main->total_force() - ref1->total_force()) * axis);
} else {
ft.real_value = main->total_force() * axis;
}
}
void colvar::distance_z::calc_Jacobian_derivative()
{
jd.real_value = 0.0;
}
void colvar::distance_z::apply_force(colvarvalue const &force)
{
if (!ref1->noforce)
ref1->apply_colvar_force(force.real_value);
if (ref2 && ref2->size() && !ref2->noforce)
ref2->apply_colvar_force(force.real_value);
if (!main->noforce)
main->apply_colvar_force(force.real_value);
}
// Differences should always be wrapped around 0 (ignoring wrap_center)
cvm::real colvar::distance_z::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
if (b_periodic) {
cvm::real shift = std::floor(diff/period + 0.5);
diff -= shift * period;
}
return diff * diff;
}
colvarvalue colvar::distance_z::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
if (b_periodic) {
cvm::real shift = std::floor(diff/period + 0.5);
diff -= shift * period;
}
return 2.0 * diff;
}
colvarvalue colvar::distance_z::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
if (b_periodic) {
cvm::real shift = std::floor(diff/period + 0.5);
diff -= shift * period;
}
return (-2.0) * diff;
}
void colvar::distance_z::wrap(colvarvalue &x) const
{
if (!b_periodic) {
// don't wrap if the period has not been set
return;
}
cvm::real shift = std::floor((x.real_value - wrap_center) / period + 0.5);
x.real_value -= shift * period;
return;
}
colvar::distance_xy::distance_xy(std::string const &conf)
: distance_z(conf)
{
function_type = "distance_xy";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
x.type(colvarvalue::type_scalar);
}
colvar::distance_xy::distance_xy()
: distance_z()
{
function_type = "distance_xy";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
enable(f_cvc_com_based);
x.type(colvarvalue::type_scalar);
}
void colvar::distance_xy::calc_value()
{
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
dist_v = main->center_of_mass() - ref1->center_of_mass();
} else {
dist_v = cvm::position_distance(ref1->center_of_mass(),
- main->center_of_mass());
+ main->center_of_mass());
}
if (!fixed_axis) {
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
v12 = ref2->center_of_mass() - ref1->center_of_mass();
} else {
- v12 = cvm::position_distance(ref1->center_of_mass(), ref2->center_of_mass());
+ v12 = cvm::position_distance(ref1->center_of_mass(),
+ ref2->center_of_mass());
}
axis_norm = v12.norm();
axis = v12.unit();
}
dist_v_ortho = dist_v - (dist_v * axis) * axis;
x.real_value = dist_v_ortho.norm();
}
void colvar::distance_xy::calc_gradients()
{
// Intermediate quantity (r_P3 / r_12 where P is the projection
// of 3(main) on the plane orthogonal to 12, containing 1 (ref1))
cvm::real A;
cvm::real x_inv;
if (x.real_value == 0.0) return;
x_inv = 1.0 / x.real_value;
if (fixed_axis) {
ref1->set_weighted_gradient(-1.0 * x_inv * dist_v_ortho);
main->set_weighted_gradient( x_inv * dist_v_ortho);
} else {
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
v13 = main->center_of_mass() - ref1->center_of_mass();
} else {
- v13 = cvm::position_distance(ref1->center_of_mass(), main->center_of_mass());
+ v13 = cvm::position_distance(ref1->center_of_mass(),
+ main->center_of_mass());
}
A = (dist_v * axis) / axis_norm;
ref1->set_weighted_gradient( (A - 1.0) * x_inv * dist_v_ortho);
ref2->set_weighted_gradient( -A * x_inv * dist_v_ortho);
main->set_weighted_gradient( 1.0 * x_inv * dist_v_ortho);
}
}
void colvar::distance_xy::calc_force_invgrads()
{
main->read_total_forces();
if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
ref1->read_total_forces();
ft.real_value = 0.5 / x.real_value * ((main->total_force() - ref1->total_force()) * dist_v_ortho);
} else {
ft.real_value = 1.0 / x.real_value * main->total_force() * dist_v_ortho;
}
}
void colvar::distance_xy::calc_Jacobian_derivative()
{
jd.real_value = x.real_value ? (1.0 / x.real_value) : 0.0;
}
void colvar::distance_xy::apply_force(colvarvalue const &force)
{
if (!ref1->noforce)
ref1->apply_colvar_force(force.real_value);
if (ref2 && ref2->size() && !ref2->noforce)
ref2->apply_colvar_force(force.real_value);
if (!main->noforce)
main->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(distance_xy)
colvar::distance_dir::distance_dir(std::string const &conf)
: distance(conf)
{
function_type = "distance_dir";
enable(f_cvc_com_based);
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_unit3vector);
}
colvar::distance_dir::distance_dir()
: distance()
{
function_type = "distance_dir";
enable(f_cvc_com_based);
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_unit3vector);
}
void colvar::distance_dir::calc_value()
{
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
dist_v = group2->center_of_mass() - group1->center_of_mass();
} else {
dist_v = cvm::position_distance(group1->center_of_mass(),
group2->center_of_mass());
}
x.rvector_value = dist_v.unit();
}
void colvar::distance_dir::calc_gradients()
{
// gradients are computed on the fly within apply_force()
// Note: could be a problem if a future bias relies on gradient
// calculations...
// TODO in new deps system: remove dependency of biasing force to gradient?
// That way we could tell apart an explicit gradient dependency
}
void colvar::distance_dir::apply_force(colvarvalue const &force)
{
// remove the radial force component
cvm::real const iprod = force.rvector_value * x.rvector_value;
cvm::rvector const force_tang = force.rvector_value - iprod * x.rvector_value;
if (!group1->noforce)
group1->apply_force(-1.0 * force_tang);
if (!group2->noforce)
group2->apply_force( force_tang);
}
cvm::real colvar::distance_dir::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
return (x1.rvector_value - x2.rvector_value).norm2();
}
colvarvalue colvar::distance_dir::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
- return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vector);
+ return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vectorderiv);
}
colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
- return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vector);
+ return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vectorderiv);
}
colvar::distance_inv::distance_inv(std::string const &conf)
- : distance(conf)
+ : cvc(conf)
{
function_type = "distance_inv";
+
+ group1 = parse_group(conf, "group1");
+ group2 = parse_group(conf, "group2");
+
get_keyval(conf, "exponent", exponent, 6);
if (exponent%2) {
cvm::error("Error: odd exponent provided, can only use even ones.\n");
return;
}
if (exponent <= 0) {
cvm::error("Error: negative or zero exponent provided.\n");
return;
}
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
if (ai1->id == ai2->id) {
cvm::error("Error: group1 and group2 have some atoms in common: this is not allowed for distanceInv.\n");
return;
}
}
}
x.type(colvarvalue::type_scalar);
}
colvar::distance_inv::distance_inv()
{
function_type = "distance_inv";
exponent = 6;
x.type(colvarvalue::type_scalar);
}
void colvar::distance_inv::calc_value()
{
x.real_value = 0.0;
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
cvm::rvector const dv = ai2->pos - ai1->pos;
cvm::real const d2 = dv.norm2();
cvm::real dinv = 1.0;
for (int ne = 0; ne < exponent/2; ne++)
dinv *= 1.0/d2;
x.real_value += dinv;
cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv;
ai1->grad += -1.0 * dsumddv;
ai2->grad += dsumddv;
}
}
} else {
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
cvm::rvector const dv = cvm::position_distance(ai1->pos, ai2->pos);
cvm::real const d2 = dv.norm2();
cvm::real dinv = 1.0;
for (int ne = 0; ne < exponent/2; ne++)
dinv *= 1.0/d2;
x.real_value += dinv;
cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv;
ai1->grad += -1.0 * dsumddv;
ai2->grad += dsumddv;
}
}
}
x.real_value *= 1.0 / cvm::real(group1->size() * group2->size());
x.real_value = std::pow(x.real_value, -1.0/(cvm::real(exponent)));
}
void colvar::distance_inv::calc_gradients()
{
cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) * std::pow(x.real_value, exponent+1) / cvm::real(group1->size() * group2->size());
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
ai1->grad *= dxdsum;
}
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
ai2->grad *= dxdsum;
}
}
void colvar::distance_inv::apply_force(colvarvalue const &force)
{
if (!group1->noforce)
group1->apply_colvar_force(force.real_value);
if (!group2->noforce)
group2->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(distance_inv)
colvar::distance_pairs::distance_pairs(std::string const &conf)
: cvc(conf)
{
function_type = "distance_pairs";
- if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) {
- cvm::log("Computing distance using absolute positions (not minimal-image)");
- }
-
group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2");
x.type(colvarvalue::type_vector);
+ enable(f_cvc_implicit_gradient);
x.vector1d_value.resize(group1->size() * group2->size());
}
colvar::distance_pairs::distance_pairs()
{
function_type = "distance_pairs";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_vector);
}
void colvar::distance_pairs::calc_value()
{
x.vector1d_value.resize(group1->size() * group2->size());
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
size_t i1, i2;
for (i1 = 0; i1 < group1->size(); i1++) {
for (i2 = 0; i2 < group2->size(); i2++) {
cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
cvm::real const d = dv.norm();
x.vector1d_value[i1*group2->size() + i2] = d;
(*group1)[i1].grad = -1.0 * dv.unit();
(*group2)[i2].grad = dv.unit();
}
}
} else {
size_t i1, i2;
for (i1 = 0; i1 < group1->size(); i1++) {
for (i2 = 0; i2 < group2->size(); i2++) {
- cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, (*group2)[i2].pos);
+ cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
+ (*group2)[i2].pos);
cvm::real const d = dv.norm();
x.vector1d_value[i1*group2->size() + i2] = d;
(*group1)[i1].grad = -1.0 * dv.unit();
(*group2)[i2].grad = dv.unit();
}
}
}
}
void colvar::distance_pairs::calc_gradients()
{
// will be calculated on the fly in apply_force()
}
void colvar::distance_pairs::apply_force(colvarvalue const &force)
{
- if (b_no_PBC) {
+ if (!is_enabled(f_cvc_pbc_minimum_image)) {
size_t i1, i2;
for (i1 = 0; i1 < group1->size(); i1++) {
for (i2 = 0; i2 < group2->size(); i2++) {
cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
(*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
(*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
}
}
} else {
size_t i1, i2;
for (i1 = 0; i1 < group1->size(); i1++) {
for (i2 = 0; i2 < group2->size(); i2++) {
- cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, (*group2)[i2].pos);
+ cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
+ (*group2)[i2].pos);
(*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
(*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
}
}
}
}
colvar::gyration::gyration(std::string const &conf)
: cvc(conf)
{
function_type = "gyration";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
atoms = parse_group(conf, "atoms");
if (atoms->b_user_defined_fit) {
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".");
} else {
atoms->b_center = true;
atoms->ref_pos.assign(1, cvm::atom_pos(0.0, 0.0, 0.0));
atoms->fit_gradients.assign(atoms->size(), cvm::rvector(0.0, 0.0, 0.0));
}
x.type(colvarvalue::type_scalar);
}
colvar::gyration::gyration()
{
function_type = "gyration";
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
x.type(colvarvalue::type_scalar);
}
void colvar::gyration::calc_value()
{
x.real_value = 0.0;
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
x.real_value += (ai->pos).norm2();
}
x.real_value = std::sqrt(x.real_value / cvm::real(atoms->size()));
}
void colvar::gyration::calc_gradients()
{
cvm::real const drdx = 1.0/(cvm::real(atoms->size()) * x.real_value);
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
ai->grad = drdx * ai->pos;
}
}
void colvar::gyration::calc_force_invgrads()
{
atoms->read_total_forces();
cvm::real const dxdr = 1.0/x.real_value;
ft.real_value = 0.0;
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
ft.real_value += dxdr * ai->pos * ai->total_force;
}
}
void colvar::gyration::calc_Jacobian_derivative()
{
jd = x.real_value ? (3.0 * cvm::real(atoms->size()) - 4.0) / x.real_value : 0.0;
}
void colvar::gyration::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(gyration)
colvar::inertia::inertia(std::string const &conf)
: gyration(conf)
{
function_type = "inertia";
x.type(colvarvalue::type_scalar);
}
colvar::inertia::inertia()
{
function_type = "inertia";
x.type(colvarvalue::type_scalar);
}
void colvar::inertia::calc_value()
{
x.real_value = 0.0;
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
x.real_value += (ai->pos).norm2();
}
}
void colvar::inertia::calc_gradients()
{
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
ai->grad = 2.0 * ai->pos;
}
}
void colvar::inertia::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(inertia_z)
colvar::inertia_z::inertia_z(std::string const &conf)
: inertia(conf)
{
function_type = "inertia_z";
if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
if (axis.norm2() == 0.0) {
cvm::error("Axis vector is zero!");
return;
}
if (axis.norm2() != 1.0) {
axis = axis.unit();
cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
}
}
x.type(colvarvalue::type_scalar);
}
colvar::inertia_z::inertia_z()
{
function_type = "inertia_z";
x.type(colvarvalue::type_scalar);
}
void colvar::inertia_z::calc_value()
{
x.real_value = 0.0;
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
cvm::real const iprod = ai->pos * axis;
x.real_value += iprod * iprod;
}
}
void colvar::inertia_z::calc_gradients()
{
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
ai->grad = 2.0 * (ai->pos * axis) * axis;
}
}
void colvar::inertia_z::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
simple_scalar_dist_functions(inertia)
colvar::rmsd::rmsd(std::string const &conf)
: cvc(conf)
{
provide(f_cvc_inv_gradient);
function_type = "rmsd";
x.type(colvarvalue::type_scalar);
atoms = parse_group(conf, "atoms");
if (!atoms || atoms->size() == 0) {
cvm::error("Error: \"atoms\" must contain at least 1 atom to compute RMSD.");
return;
}
bool b_Jacobian_derivative = true;
if (atoms->fitting_group != NULL && b_Jacobian_derivative) {
cvm::log("The option \"refPositionsGroup\" (alternative group for fitting) was enabled: "
"Jacobian derivatives of the RMSD will not be calculated.\n");
b_Jacobian_derivative = false;
}
if (b_Jacobian_derivative) provide(f_cvc_Jacobian);
// the following is a simplified version of the corresponding atom group options;
// we need this because the reference coordinates defined inside the atom group
// may be used only for fitting, and even more so if fitting_group is used
if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
cvm::log("Using reference positions from configuration file to calculate the variable.\n");
if (ref_pos.size() != atoms->size()) {
cvm::error("Error: the number of reference positions provided ("+
cvm::to_str(ref_pos.size())+
") does not match the number of atoms of group \"atoms\" ("+
cvm::to_str(atoms->size())+").\n");
return;
}
}
{
std::string ref_pos_file;
if (get_keyval(conf, "refPositionsFile", ref_pos_file, std::string(""))) {
if (ref_pos.size()) {
cvm::error("Error: cannot specify \"refPositionsFile\" and "
"\"refPositions\" at the same time.\n");
return;
}
std::string ref_pos_col;
double ref_pos_col_value=0.0;
if (get_keyval(conf, "refPositionsCol", ref_pos_col, std::string(""))) {
// if provided, use PDB column to select coordinates
bool found = get_keyval(conf, "refPositionsColValue", ref_pos_col_value, 0.0);
if (found && ref_pos_col_value==0.0) {
cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n");
return;
}
} else {
// if not, rely on existing atom indices for the group
atoms->create_sorted_ids();
ref_pos.resize(atoms->size());
}
cvm::load_coords(ref_pos_file.c_str(), ref_pos, atoms->sorted_ids,
ref_pos_col, ref_pos_col_value);
}
}
if (ref_pos.size() != atoms->size()) {
cvm::error("Error: found " + cvm::to_str(ref_pos.size()) +
" reference positions; expected " + cvm::to_str(atoms->size()));
return;
}
if (atoms->b_user_defined_fit) {
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".");
} else {
// Default: fit everything
cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating it as a variable: "
"if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
atoms->b_center = true;
atoms->b_rotate = true;
// default case: reference positions for calculating the rmsd are also those used
// for fitting
atoms->ref_pos = ref_pos;
atoms->center_ref_pos();
cvm::log("This is a standard minimum RMSD, derivatives of the optimal rotation "
"will not be computed as they cancel out in the gradients.");
- atoms->b_fit_gradients = false;
+ atoms->disable(f_ag_fit_gradients);
// request the calculation of the derivatives of the rotation defined by the atom group
atoms->rot.request_group1_gradients(atoms->size());
// request derivatives of optimal rotation wrt reference coordinates for Jacobian:
// this is only required for ABF, but we do both groups here for better caching
atoms->rot.request_group2_gradients(atoms->size());
}
}
void colvar::rmsd::calc_value()
{
// rotational-translational fit is handled by the atom group
x.real_value = 0.0;
for (size_t ia = 0; ia < atoms->size(); ia++) {
x.real_value += ((*atoms)[ia].pos - ref_pos[ia]).norm2();
}
x.real_value /= cvm::real(atoms->size()); // MSD
x.real_value = std::sqrt(x.real_value);
}
void colvar::rmsd::calc_gradients()
{
cvm::real const drmsddx2 = (x.real_value > 0.0) ?
0.5 / (x.real_value * cvm::real(atoms->size())) :
0.0;
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (drmsddx2 * 2.0 * ((*atoms)[ia].pos - ref_pos[ia]));
}
}
void colvar::rmsd::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
void colvar::rmsd::calc_force_invgrads()
{
atoms->read_total_forces();
ft.real_value = 0.0;
// Note: gradient square norm is 1/N_atoms
for (size_t ia = 0; ia < atoms->size(); ia++) {
ft.real_value += (*atoms)[ia].grad * (*atoms)[ia].total_force;
}
ft.real_value *= atoms->size();
}
void colvar::rmsd::calc_Jacobian_derivative()
{
// divergence of the rotated coordinates (including only derivatives of the rotation matrix)
cvm::real divergence = 0.0;
if (atoms->b_rotate) {
// gradient of the rotation matrix
cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
// gradients of products of 2 quaternion components
cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
for (size_t ia = 0; ia < atoms->size(); ia++) {
// Gradient of optimal quaternion wrt current Cartesian position
cvm::vector1d<cvm::rvector> &dq = atoms->rot.dQ0_1[ia];
g11 = 2.0 * (atoms->rot.q)[1]*dq[1];
g22 = 2.0 * (atoms->rot.q)[2]*dq[2];
g33 = 2.0 * (atoms->rot.q)[3]*dq[3];
g01 = (atoms->rot.q)[0]*dq[1] + (atoms->rot.q)[1]*dq[0];
g02 = (atoms->rot.q)[0]*dq[2] + (atoms->rot.q)[2]*dq[0];
g03 = (atoms->rot.q)[0]*dq[3] + (atoms->rot.q)[3]*dq[0];
g12 = (atoms->rot.q)[1]*dq[2] + (atoms->rot.q)[2]*dq[1];
g13 = (atoms->rot.q)[1]*dq[3] + (atoms->rot.q)[3]*dq[1];
g23 = (atoms->rot.q)[2]*dq[3] + (atoms->rot.q)[3]*dq[2];
// Gradient of the rotation matrix wrt current Cartesian position
grad_rot_mat[0][0] = -2.0 * (g22 + g33);
grad_rot_mat[1][0] = 2.0 * (g12 + g03);
grad_rot_mat[2][0] = 2.0 * (g13 - g02);
grad_rot_mat[0][1] = 2.0 * (g12 - g03);
grad_rot_mat[1][1] = -2.0 * (g11 + g33);
grad_rot_mat[2][1] = 2.0 * (g01 + g23);
grad_rot_mat[0][2] = 2.0 * (g02 + g13);
grad_rot_mat[1][2] = 2.0 * (g23 - g01);
grad_rot_mat[2][2] = -2.0 * (g11 + g22);
cvm::atom_pos &y = ref_pos[ia];
for (size_t alpha = 0; alpha < 3; alpha++) {
for (size_t beta = 0; beta < 3; beta++) {
divergence += grad_rot_mat[beta][alpha][alpha] * y[beta];
// Note: equation was derived for inverse rotation (see colvars paper)
// so here the matrix is transposed
// (eq would give divergence += grad_rot_mat[alpha][beta][alpha] * y[beta];)
}
}
}
}
jd.real_value = x.real_value > 0.0 ? (3.0 * atoms->size() - 4.0 - divergence) / x.real_value : 0.0;
}
simple_scalar_dist_functions(rmsd)
colvar::eigenvector::eigenvector(std::string const &conf)
: cvc(conf)
{
provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian);
function_type = "eigenvector";
x.type(colvarvalue::type_scalar);
atoms = parse_group(conf, "atoms");
{
bool const b_inline = get_keyval(conf, "refPositions", ref_pos, ref_pos);
if (b_inline) {
cvm::log("Using reference positions from input file.\n");
if (ref_pos.size() != atoms->size()) {
cvm::error("Error: reference positions do not "
"match the number of requested atoms.\n");
return;
}
}
std::string file_name;
if (get_keyval(conf, "refPositionsFile", file_name)) {
if (b_inline) {
cvm::error("Error: refPositions and refPositionsFile cannot be specified at the same time.\n");
return;
}
std::string file_col;
double file_col_value=0.0;
if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) {
// use PDB flags if column is provided
bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
if (found && file_col_value==0.0) {
cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n");
return;
}
} else {
// if not, use atom indices
atoms->create_sorted_ids();
}
ref_pos.resize(atoms->size());
cvm::load_coords(file_name.c_str(), ref_pos, atoms->sorted_ids, file_col, file_col_value);
}
}
if (ref_pos.size() == 0) {
cvm::error("Error: reference positions were not provided.\n", INPUT_ERROR);
return;
}
if (ref_pos.size() != atoms->size()) {
cvm::error("Error: reference positions do not "
"match the number of requested atoms.\n", INPUT_ERROR);
return;
}
// save for later the geometric center of the provided positions (may not be the origin)
cvm::rvector ref_pos_center(0.0, 0.0, 0.0);
for (size_t i = 0; i < atoms->size(); i++) {
ref_pos_center += ref_pos[i];
}
ref_pos_center *= 1.0 / atoms->size();
if (atoms->b_user_defined_fit) {
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n");
} else {
// default: fit everything
cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating the vector projection: "
"if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
atoms->b_center = true;
atoms->b_rotate = true;
atoms->ref_pos = ref_pos;
atoms->center_ref_pos();
- atoms->b_fit_gradients = false; // cancel out if group is fitted on itself
- // and cvc is translationally invariant
+ atoms->disable(f_ag_fit_gradients); // cancel out if group is fitted on itself
+ // and cvc is translationally invariant
// request the calculation of the derivatives of the rotation defined by the atom group
atoms->rot.request_group1_gradients(atoms->size());
// request derivatives of optimal rotation wrt reference coordinates for Jacobian:
// this is only required for ABF, but we do both groups here for better caching
atoms->rot.request_group2_gradients(atoms->size());
}
{
bool const b_inline = get_keyval(conf, "vector", eigenvec, eigenvec);
// now load the eigenvector
if (b_inline) {
cvm::log("Using vector components from input file.\n");
if (eigenvec.size() != atoms->size()) {
- cvm::fatal_error("Error: vector components do not "
+ cvm::error("Error: vector components do not "
"match the number of requested atoms->\n");
+ return;
}
}
std::string file_name;
if (get_keyval(conf, "vectorFile", file_name)) {
if (b_inline) {
cvm::error("Error: vector and vectorFile cannot be specified at the same time.\n");
return;
}
std::string file_col;
double file_col_value=0.0;
if (get_keyval(conf, "vectorCol", file_col, std::string(""))) {
// use PDB flags if column is provided
bool found = get_keyval(conf, "vectorColValue", file_col_value, 0.0);
if (found && file_col_value==0.0) {
cvm::error("Error: vectorColValue, if provided, must be non-zero.\n");
return;
}
} else {
// if not, use atom indices
atoms->create_sorted_ids();
}
eigenvec.resize(atoms->size());
cvm::load_coords(file_name.c_str(), eigenvec, atoms->sorted_ids, file_col, file_col_value);
}
}
if (!ref_pos.size() || !eigenvec.size()) {
cvm::error("Error: both reference coordinates"
"and eigenvector must be defined.\n");
return;
}
cvm::atom_pos eig_center(0.0, 0.0, 0.0);
for (size_t eil = 0; eil < atoms->size(); eil++) {
eig_center += eigenvec[eil];
}
eig_center *= 1.0 / atoms->size();
cvm::log("Geometric center of the provided vector: "+cvm::to_str(eig_center)+"\n");
bool b_difference_vector = false;
get_keyval(conf, "differenceVector", b_difference_vector, false);
if (b_difference_vector) {
if (atoms->b_center) {
// both sets should be centered on the origin for fitting
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] -= eig_center;
ref_pos[i] -= ref_pos_center;
}
}
if (atoms->b_rotate) {
atoms->rot.calc_optimal_rotation(eigenvec, ref_pos);
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] = atoms->rot.rotate(eigenvec[i]);
}
}
cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = v - x0.\n");
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] -= ref_pos[i];
}
if (atoms->b_center) {
// bring back the ref positions to where they were
for (size_t i = 0; i < atoms->size(); i++) {
ref_pos[i] += ref_pos_center;
}
}
} else {
cvm::log("Centering the provided vector to zero.\n");
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] -= eig_center;
}
}
// cvm::log("The first three components(v1x, v1y, v1z) of the resulting vector are: "+cvm::to_str (eigenvec[0])+".\n");
// for inverse gradients
eigenvec_invnorm2 = 0.0;
for (size_t ein = 0; ein < atoms->size(); ein++) {
eigenvec_invnorm2 += eigenvec[ein].norm2();
}
eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2;
if (b_difference_vector) {
cvm::log("\"differenceVector\" is on: normalizing the vector.\n");
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] *= eigenvec_invnorm2;
}
} else {
cvm::log("The norm of the vector is |v| = "+cvm::to_str(eigenvec_invnorm2)+".\n");
}
}
void colvar::eigenvector::calc_value()
{
x.real_value = 0.0;
for (size_t i = 0; i < atoms->size(); i++) {
x.real_value += ((*atoms)[i].pos - ref_pos[i]) * eigenvec[i];
}
}
void colvar::eigenvector::calc_gradients()
{
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = eigenvec[ia];
}
}
void colvar::eigenvector::apply_force(colvarvalue const &force)
{
if (!atoms->noforce)
atoms->apply_colvar_force(force.real_value);
}
void colvar::eigenvector::calc_force_invgrads()
{
atoms->read_total_forces();
ft.real_value = 0.0;
for (size_t ia = 0; ia < atoms->size(); ia++) {
ft.real_value += eigenvec_invnorm2 * (*atoms)[ia].grad *
(*atoms)[ia].total_force;
}
}
void colvar::eigenvector::calc_Jacobian_derivative()
{
// gradient of the rotation matrix
cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
cvm::quaternion &quat0 = atoms->rot.q;
// gradients of products of 2 quaternion components
cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
cvm::real sum = 0.0;
for (size_t ia = 0; ia < atoms->size(); ia++) {
// Gradient of optimal quaternion wrt current Cartesian position
// trick: d(R^-1)/dx = d(R^t)/dx = (dR/dx)^t
// we can just transpose the derivatives of the direct matrix
cvm::vector1d<cvm::rvector> &dq_1 = atoms->rot.dQ0_1[ia];
g11 = 2.0 * quat0[1]*dq_1[1];
g22 = 2.0 * quat0[2]*dq_1[2];
g33 = 2.0 * quat0[3]*dq_1[3];
g01 = quat0[0]*dq_1[1] + quat0[1]*dq_1[0];
g02 = quat0[0]*dq_1[2] + quat0[2]*dq_1[0];
g03 = quat0[0]*dq_1[3] + quat0[3]*dq_1[0];
g12 = quat0[1]*dq_1[2] + quat0[2]*dq_1[1];
g13 = quat0[1]*dq_1[3] + quat0[3]*dq_1[1];
g23 = quat0[2]*dq_1[3] + quat0[3]*dq_1[2];
// Gradient of the inverse rotation matrix wrt current Cartesian position
// (transpose of the gradient of the direct rotation)
grad_rot_mat[0][0] = -2.0 * (g22 + g33);
grad_rot_mat[0][1] = 2.0 * (g12 + g03);
grad_rot_mat[0][2] = 2.0 * (g13 - g02);
grad_rot_mat[1][0] = 2.0 * (g12 - g03);
grad_rot_mat[1][1] = -2.0 * (g11 + g33);
grad_rot_mat[1][2] = 2.0 * (g01 + g23);
grad_rot_mat[2][0] = 2.0 * (g02 + g13);
grad_rot_mat[2][1] = 2.0 * (g23 - g01);
grad_rot_mat[2][2] = -2.0 * (g11 + g22);
for (size_t i = 0; i < 3; i++) {
for (size_t j = 0; j < 3; j++) {
sum += grad_rot_mat[i][j][i] * eigenvec[ia][j];
}
}
}
jd.real_value = sum * std::sqrt(eigenvec_invnorm2);
}
simple_scalar_dist_functions(eigenvector)
colvar::cartesian::cartesian(std::string const &conf)
: cvc(conf)
{
function_type = "cartesian";
atoms = parse_group(conf, "atoms");
bool use_x, use_y, use_z;
get_keyval(conf, "useX", use_x, true);
get_keyval(conf, "useY", use_y, true);
get_keyval(conf, "useZ", use_z, true);
axes.clear();
if (use_x) axes.push_back(0);
if (use_y) axes.push_back(1);
if (use_z) axes.push_back(2);
if (axes.size() == 0) {
cvm::error("Error: a \"cartesian\" component was defined with all three axes disabled.\n");
return;
}
x.type(colvarvalue::type_vector);
+ enable(f_cvc_implicit_gradient);
x.vector1d_value.resize(atoms->size() * axes.size());
}
void colvar::cartesian::calc_value()
{
size_t const dim = axes.size();
size_t ia, j;
for (ia = 0; ia < atoms->size(); ia++) {
for (j = 0; j < dim; j++) {
x.vector1d_value[dim*ia + j] = (*atoms)[ia].pos[axes[j]];
}
}
}
void colvar::cartesian::calc_gradients()
{
// we're not using the "grad" member of each
// atom object, because it only can represent the gradient of a
// scalar colvar
}
void colvar::cartesian::apply_force(colvarvalue const &force)
{
size_t const dim = axes.size();
size_t ia, j;
if (!atoms->noforce) {
cvm::rvector f;
for (ia = 0; ia < atoms->size(); ia++) {
for (j = 0; j < dim; j++) {
f[axes[j]] = force.vector1d_value[dim*ia + j];
}
(*atoms)[ia].apply_force(f);
}
}
}
diff --git a/lib/colvars/colvarcomp_protein.cpp b/lib/colvars/colvarcomp_protein.cpp
index 393c7dcf9..b8fc96cfa 100644
--- a/lib/colvars/colvarcomp_protein.cpp
+++ b/lib/colvars/colvarcomp_protein.cpp
@@ -1,426 +1,422 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cmath>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
//////////////////////////////////////////////////////////////////////
// alpha component
//////////////////////////////////////////////////////////////////////
- // FIXME: this will not make collect_gradients work
- // because gradients in individual atom groups
- // are those of the sub-cvcs (angle, hb), not those
- // of this cvc (alpha)
- // This is true of all cvcs with sub-cvcs, and those
- // that do not calculate explicit gradients
- // SO: we need a flag giving the availability of
- // atomic gradients
-
colvar::alpha_angles::alpha_angles(std::string const &conf)
: cvc(conf)
{
if (cvm::debug())
cvm::log("Initializing alpha_angles object.\n");
function_type = "alpha_angles";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_scalar);
std::string segment_id;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
std::vector<int> residues;
{
std::string residues_conf = "";
- key_lookup(conf, "residueRange", residues_conf);
+ key_lookup(conf, "residueRange", &residues_conf);
if (residues_conf.size()) {
std::istringstream is(residues_conf);
int initial, final;
char dash;
if ( (is >> initial) && (initial > 0) &&
(is >> dash) && (dash == '-') &&
(is >> final) && (final > 0) ) {
for (int rnum = initial; rnum <= final; rnum++) {
residues.push_back(rnum);
}
}
} else {
- cvm::fatal_error("Error: no residues defined in \"residueRange\".\n");
+ cvm::error("Error: no residues defined in \"residueRange\".\n");
+ return;
}
}
if (residues.size() < 5) {
- cvm::fatal_error("Error: not enough residues defined in \"residueRange\".\n");
+ cvm::error("Error: not enough residues defined in \"residueRange\".\n");
+ return;
}
std::string const &sid = segment_id;
std::vector<int> const &r = residues;
get_keyval(conf, "hBondCoeff", hb_coeff, 0.5);
if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) {
- cvm::fatal_error("Error: hBondCoeff must be defined between 0 and 1.\n");
+ cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n");
+ return;
}
get_keyval(conf, "angleRef", theta_ref, 88.0);
get_keyval(conf, "angleTol", theta_tol, 15.0);
if (hb_coeff < 1.0) {
for (size_t i = 0; i < residues.size()-2; i++) {
theta.push_back(new colvar::angle(cvm::atom(r[i ], "CA", sid),
cvm::atom(r[i+1], "CA", sid),
cvm::atom(r[i+2], "CA", sid)));
- atom_groups.push_back(theta.back()->atom_groups[0]);
- atom_groups.push_back(theta.back()->atom_groups[1]);
- atom_groups.push_back(theta.back()->atom_groups[2]);
+ register_atom_group(theta.back()->atom_groups[0]);
+ register_atom_group(theta.back()->atom_groups[1]);
+ register_atom_group(theta.back()->atom_groups[2]);
}
} else {
cvm::log("The hBondCoeff specified will disable the Calpha-Calpha-Calpha angle terms.\n");
}
{
cvm::real r0;
size_t en, ed;
get_keyval(conf, "hBondCutoff", r0, (3.3 * cvm::unit_angstrom()));
get_keyval(conf, "hBondExpNumer", en, 6);
get_keyval(conf, "hBondExpDenom", ed, 8);
if (hb_coeff > 0.0) {
for (size_t i = 0; i < residues.size()-4; i++) {
hb.push_back(new colvar::h_bond(cvm::atom(r[i ], "O", sid),
cvm::atom(r[i+4], "N", sid),
r0, en, ed));
- atom_groups.push_back(hb.back()->atom_groups[0]);
+ register_atom_group(hb.back()->atom_groups[0]);
}
} else {
cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n");
}
}
if (cvm::debug())
cvm::log("Done initializing alpha_angles object.\n");
}
colvar::alpha_angles::alpha_angles()
: cvc()
{
function_type = "alpha_angles";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_scalar);
}
colvar::alpha_angles::~alpha_angles()
{
while (theta.size() != 0) {
delete theta.back();
theta.pop_back();
}
while (hb.size() != 0) {
delete hb.back();
hb.pop_back();
}
}
void colvar::alpha_angles::calc_value()
{
x.real_value = 0.0;
if (theta.size()) {
cvm::real const theta_norm =
(1.0-hb_coeff) / cvm::real(theta.size());
for (size_t i = 0; i < theta.size(); i++) {
(theta[i])->calc_value();
cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol;
cvm::real const f = ( (1.0 - std::pow(t, (int) 2)) /
(1.0 - std::pow(t, (int) 4)) );
x.real_value += theta_norm * f;
if (cvm::debug())
cvm::log("Calpha-Calpha angle no. "+cvm::to_str(i+1)+" in \""+
this->name+"\" has a value of "+
(cvm::to_str((theta[i])->value().real_value))+
" degrees, f = "+cvm::to_str(f)+".\n");
}
}
if (hb.size()) {
cvm::real const hb_norm =
hb_coeff / cvm::real(hb.size());
for (size_t i = 0; i < hb.size(); i++) {
(hb[i])->calc_value();
x.real_value += hb_norm * (hb[i])->value().real_value;
if (cvm::debug())
cvm::log("Hydrogen bond no. "+cvm::to_str(i+1)+" in \""+
this->name+"\" has a value of "+
(cvm::to_str((hb[i])->value().real_value))+".\n");
}
}
}
void colvar::alpha_angles::calc_gradients()
{
size_t i;
for (i = 0; i < theta.size(); i++)
(theta[i])->calc_gradients();
for (i = 0; i < hb.size(); i++)
(hb[i])->calc_gradients();
}
void colvar::alpha_angles::apply_force(colvarvalue const &force)
{
if (theta.size()) {
cvm::real const theta_norm =
(1.0-hb_coeff) / cvm::real(theta.size());
for (size_t i = 0; i < theta.size(); i++) {
cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol;
cvm::real const f = ( (1.0 - std::pow(t, (int) 2)) /
(1.0 - std::pow(t, (int) 4)) );
cvm::real const dfdt =
1.0/(1.0 - std::pow(t, (int) 4)) *
( (-2.0 * t) + (-1.0*f)*(-4.0 * std::pow(t, (int) 3)) );
(theta[i])->apply_force(theta_norm *
dfdt * (1.0/theta_tol) *
force.real_value );
}
}
if (hb.size()) {
cvm::real const hb_norm =
hb_coeff / cvm::real(hb.size());
for (size_t i = 0; i < hb.size(); i++) {
(hb[i])->apply_force(0.5 * hb_norm * force.real_value);
}
}
}
simple_scalar_dist_functions(alpha_angles)
//////////////////////////////////////////////////////////////////////
// dihedral principal component
//////////////////////////////////////////////////////////////////////
- // FIXME: this will not make collect_gradients work
- // because gradients in individual atom groups
- // are those of the sub-cvcs (dihedral), not those
- // of this cvc
- // This is true of all cvcs with sub-cvcs, and those
- // that do not calculate explicit gradients
- // SO: we need a flag giving the availability of
- // atomic gradients
-
colvar::dihedPC::dihedPC(std::string const &conf)
: cvc(conf)
{
if (cvm::debug())
cvm::log("Initializing dihedral PC object.\n");
function_type = "dihedPC";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_scalar);
std::string segment_id;
get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
std::vector<int> residues;
{
std::string residues_conf = "";
- key_lookup(conf, "residueRange", residues_conf);
+ key_lookup(conf, "residueRange", &residues_conf);
if (residues_conf.size()) {
std::istringstream is(residues_conf);
int initial, final;
char dash;
if ( (is >> initial) && (initial > 0) &&
(is >> dash) && (dash == '-') &&
(is >> final) && (final > 0) ) {
for (int rnum = initial; rnum <= final; rnum++) {
residues.push_back(rnum);
}
}
} else {
- cvm::fatal_error("Error: no residues defined in \"residueRange\".\n");
+ cvm::error("Error: no residues defined in \"residueRange\".\n");
+ return;
}
}
if (residues.size() < 2) {
- cvm::fatal_error("Error: dihedralPC requires at least two residues.\n");
+ cvm::error("Error: dihedralPC requires at least two residues.\n");
+ return;
}
std::string const &sid = segment_id;
std::vector<int> const &r = residues;
std::string vecFileName;
int vecNumber;
if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) {
get_keyval(conf, "vectorNumber", vecNumber, 0);
- if (vecNumber < 1)
- cvm::fatal_error("A positive value of vectorNumber is required.");
+ if (vecNumber < 1) {
+ cvm::error("A positive value of vectorNumber is required.");
+ return;
+ }
std::ifstream vecFile;
vecFile.open(vecFileName.c_str());
- if (!vecFile.good())
- cvm::fatal_error("Error opening dihedral PCA vector file " + vecFileName + " for reading");
+ if (!vecFile.good()) {
+ cvm::error("Error opening dihedral PCA vector file " + vecFileName + " for reading");
+ }
// TODO: adapt to different formats by setting this flag
bool eigenvectors_as_columns = true;
if (eigenvectors_as_columns) {
// Carma-style dPCA file
std::string line;
cvm::real c;
while (vecFile.good()) {
getline(vecFile, line);
if (line.length() < 2) break;
std::istringstream ls(line);
for (int i=0; i<vecNumber; i++) ls >> c;
coeffs.push_back(c);
}
}
/* TODO Uncomment this when different formats are recognized
else {
// Eigenvectors as lines
// Skip to the right line
for (int i = 1; i<vecNumber; i++)
vecFile.ignore(999999, '\n');
- if (!vecFile.good())
- cvm::fatal_error("Error reading dihedral PCA vector file " + vecFileName);
+ if (!vecFile.good()) {
+ cvm::error("Error reading dihedral PCA vector file " + vecFileName);
+ }
std::string line;
getline(vecFile, line);
std::istringstream ls(line);
cvm::real c;
while (ls.good()) {
ls >> c;
coeffs.push_back(c);
}
}
*/
vecFile.close();
} else {
get_keyval(conf, "vector", coeffs, coeffs);
}
if ( coeffs.size() != 4 * (residues.size() - 1)) {
- cvm::fatal_error("Error: wrong number of coefficients: " +
+ cvm::error("Error: wrong number of coefficients: " +
cvm::to_str(coeffs.size()) + ". Expected " +
cvm::to_str(4 * (residues.size() - 1)) +
" (4 coeffs per residue, minus one residue).\n");
+ return;
}
for (size_t i = 0; i < residues.size()-1; i++) {
// Psi
theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "N", sid),
cvm::atom(r[i ], "CA", sid),
cvm::atom(r[i ], "C", sid),
cvm::atom(r[i+1], "N", sid)));
- atom_groups.push_back(theta.back()->atom_groups[0]);
- atom_groups.push_back(theta.back()->atom_groups[1]);
- atom_groups.push_back(theta.back()->atom_groups[2]);
- atom_groups.push_back(theta.back()->atom_groups[3]);
+ register_atom_group(theta.back()->atom_groups[0]);
+ register_atom_group(theta.back()->atom_groups[1]);
+ register_atom_group(theta.back()->atom_groups[2]);
+ register_atom_group(theta.back()->atom_groups[3]);
// Phi (next res)
theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "C", sid),
cvm::atom(r[i+1], "N", sid),
cvm::atom(r[i+1], "CA", sid),
cvm::atom(r[i+1], "C", sid)));
- atom_groups.push_back(theta.back()->atom_groups[0]);
- atom_groups.push_back(theta.back()->atom_groups[1]);
- atom_groups.push_back(theta.back()->atom_groups[2]);
- atom_groups.push_back(theta.back()->atom_groups[3]);
+ register_atom_group(theta.back()->atom_groups[0]);
+ register_atom_group(theta.back()->atom_groups[1]);
+ register_atom_group(theta.back()->atom_groups[2]);
+ register_atom_group(theta.back()->atom_groups[3]);
}
if (cvm::debug())
cvm::log("Done initializing dihedPC object.\n");
}
colvar::dihedPC::dihedPC()
: cvc()
{
function_type = "dihedPC";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_scalar);
}
colvar::dihedPC::~dihedPC()
{
while (theta.size() != 0) {
delete theta.back();
theta.pop_back();
}
}
void colvar::dihedPC::calc_value()
{
x.real_value = 0.0;
for (size_t i = 0; i < theta.size(); i++) {
theta[i]->calc_value();
cvm::real const t = (PI / 180.) * theta[i]->value().real_value;
x.real_value += coeffs[2*i ] * std::cos(t)
+ coeffs[2*i+1] * std::sin(t);
}
}
void colvar::dihedPC::calc_gradients()
{
for (size_t i = 0; i < theta.size(); i++) {
theta[i]->calc_gradients();
}
}
void colvar::dihedPC::apply_force(colvarvalue const &force)
{
for (size_t i = 0; i < theta.size(); i++) {
cvm::real const t = (PI / 180.) * theta[i]->value().real_value;
cvm::real const dcosdt = - (PI / 180.) * std::sin(t);
cvm::real const dsindt = (PI / 180.) * std::cos(t);
theta[i]->apply_force((coeffs[2*i ] * dcosdt +
coeffs[2*i+1] * dsindt) * force);
}
}
simple_scalar_dist_functions(dihedPC)
diff --git a/lib/colvars/colvarcomp_rotations.cpp b/lib/colvars/colvarcomp_rotations.cpp
index 936e77016..2650a9fe1 100644
--- a/lib/colvars/colvarcomp_rotations.cpp
+++ b/lib/colvars/colvarcomp_rotations.cpp
@@ -1,421 +1,427 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cmath>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
colvar::orientation::orientation(std::string const &conf)
: cvc(conf)
{
function_type = "orientation";
atoms = parse_group(conf, "atoms");
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_quaternion);
ref_pos.reserve(atoms->size());
if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
cvm::log("Using reference positions from input file.\n");
if (ref_pos.size() != atoms->size()) {
- cvm::fatal_error("Error: reference positions do not "
+ cvm::error("Error: reference positions do not "
"match the number of requested atoms.\n");
+ return;
}
}
{
std::string file_name;
if (get_keyval(conf, "refPositionsFile", file_name)) {
std::string file_col;
double file_col_value=0.0;
if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) {
// use PDB flags if column is provided
bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
- if (found && file_col_value==0.0)
- cvm::fatal_error("Error: refPositionsColValue, "
+ if (found && file_col_value==0.0) {
+ cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n");
+ return;
+ }
} else {
// if not, use atom indices
atoms->create_sorted_ids();
}
ref_pos.resize(atoms->size());
cvm::load_coords(file_name.c_str(), ref_pos, atoms->sorted_ids, file_col, file_col_value);
}
}
if (!ref_pos.size()) {
- cvm::fatal_error("Error: must define a set of "
+ cvm::error("Error: must define a set of "
"reference coordinates.\n");
+ return;
}
cvm::log("Centering the reference coordinates: it is "
"assumed that each atom is the closest "
"periodic image to the center of geometry.\n");
cvm::rvector ref_cog(0.0, 0.0, 0.0);
size_t i;
for (i = 0; i < ref_pos.size(); i++) {
ref_cog += ref_pos[i];
}
ref_cog /= cvm::real(ref_pos.size());
for (i = 0; i < ref_pos.size(); i++) {
ref_pos[i] -= ref_cog;
}
get_keyval(conf, "closestToQuaternion", ref_quat, cvm::quaternion(1.0, 0.0, 0.0, 0.0));
// initialize rot member data
if (!atoms->noforce) {
rot.request_group2_gradients(atoms->size());
}
}
colvar::orientation::orientation()
: cvc()
{
function_type = "orientation";
+ enable(f_cvc_implicit_gradient);
x.type(colvarvalue::type_quaternion);
}
void colvar::orientation::calc_value()
{
rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
if ((rot.q).inner(ref_quat) >= 0.0) {
x.quaternion_value = rot.q;
} else {
x.quaternion_value = -1.0 * rot.q;
}
}
void colvar::orientation::calc_gradients()
{
// gradients have already been calculated and stored within the
// member object "rot"; we're not using the "grad" member of each
// atom object, because it only can represent the gradient of a
// scalar colvar
}
void colvar::orientation::apply_force(colvarvalue const &force)
{
cvm::quaternion const &FQ = force.quaternion_value;
if (!atoms->noforce) {
for (size_t ia = 0; ia < atoms->size(); ia++) {
for (size_t i = 0; i < 4; i++) {
(*atoms)[ia].apply_force(FQ[i] * rot.dQ0_2[ia][i]);
}
}
}
}
cvm::real colvar::orientation::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x1.quaternion_value.dist2(x2);
}
colvarvalue colvar::orientation::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x1.quaternion_value.dist2_grad(x2);
}
colvarvalue colvar::orientation::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
return x2.quaternion_value.dist2_grad(x1);
}
colvar::orientation_angle::orientation_angle(std::string const &conf)
: orientation(conf)
{
function_type = "orientation_angle";
x.type(colvarvalue::type_scalar);
}
colvar::orientation_angle::orientation_angle()
: orientation()
{
function_type = "orientation_angle";
x.type(colvarvalue::type_scalar);
}
void colvar::orientation_angle::calc_value()
{
atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
if ((rot.q).q0 >= 0.0) {
x.real_value = (180.0/PI) * 2.0 * std::acos((rot.q).q0);
} else {
x.real_value = (180.0/PI) * 2.0 * std::acos(-1.0 * (rot.q).q0);
}
}
void colvar::orientation_angle::calc_gradients()
{
cvm::real const dxdq0 =
( ((rot.q).q0 * (rot.q).q0 < 1.0) ?
((180.0 / PI) * (-2.0) / std::sqrt(1.0 - ((rot.q).q0 * (rot.q).q0))) :
0.0 );
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]);
}
}
void colvar::orientation_angle::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(orientation_angle)
colvar::orientation_proj::orientation_proj(std::string const &conf)
: orientation(conf)
{
function_type = "orientation_proj";
x.type(colvarvalue::type_scalar);
}
colvar::orientation_proj::orientation_proj()
: orientation()
{
function_type = "orientation_proj";
x.type(colvarvalue::type_scalar);
}
void colvar::orientation_proj::calc_value()
{
atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
x.real_value = 2.0 * (rot.q).q0 * (rot.q).q0 - 1.0;
}
void colvar::orientation_proj::calc_gradients()
{
cvm::real const dxdq0 = 2.0 * 2.0 * (rot.q).q0;
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]);
}
}
void colvar::orientation_proj::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(orientation_proj)
colvar::tilt::tilt(std::string const &conf)
: orientation(conf)
{
function_type = "tilt";
get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
if (axis.norm2() != 1.0) {
axis /= axis.norm();
cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n");
}
x.type(colvarvalue::type_scalar);
}
colvar::tilt::tilt()
: orientation()
{
function_type = "tilt";
x.type(colvarvalue::type_scalar);
}
void colvar::tilt::calc_value()
{
atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
x.real_value = rot.cos_theta(axis);
}
void colvar::tilt::calc_gradients()
{
cvm::quaternion const dxdq = rot.dcos_theta_dq(axis);
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
for (size_t iq = 0; iq < 4; iq++) {
(*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]);
}
}
}
void colvar::tilt::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
simple_scalar_dist_functions(tilt)
colvar::spin_angle::spin_angle(std::string const &conf)
: orientation(conf)
{
function_type = "spin_angle";
get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
if (axis.norm2() != 1.0) {
axis /= axis.norm();
cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n");
}
period = 360.0;
b_periodic = true;
x.type(colvarvalue::type_scalar);
}
colvar::spin_angle::spin_angle()
: orientation()
{
function_type = "spin_angle";
period = 360.0;
b_periodic = true;
x.type(colvarvalue::type_scalar);
}
void colvar::spin_angle::calc_value()
{
atoms_cog = atoms->center_of_geometry();
rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
x.real_value = rot.spin_angle(axis);
this->wrap(x);
}
void colvar::spin_angle::calc_gradients()
{
cvm::quaternion const dxdq = rot.dspin_angle_dq(axis);
for (size_t ia = 0; ia < atoms->size(); ia++) {
(*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
for (size_t iq = 0; iq < 4; iq++) {
(*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]);
}
}
}
void colvar::spin_angle::apply_force(colvarvalue const &force)
{
cvm::real const &fw = force.real_value;
if (!atoms->noforce) {
atoms->apply_colvar_force(fw);
}
}
cvm::real colvar::spin_angle::dist2(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return diff * diff;
}
colvarvalue colvar::spin_angle::dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return 2.0 * diff;
}
colvarvalue colvar::spin_angle::dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const
{
cvm::real diff = x1.real_value - x2.real_value;
diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
return (-2.0) * diff;
}
void colvar::spin_angle::wrap(colvarvalue &x) const
{
if ((x.real_value - wrap_center) >= 180.0) {
x.real_value -= 360.0;
return;
}
if ((x.real_value - wrap_center) < -180.0) {
x.real_value += 360.0;
return;
}
return;
}
diff --git a/lib/colvars/colvardeps.cpp b/lib/colvars/colvardeps.cpp
index 8252f77e6..5402836f5 100644
--- a/lib/colvars/colvardeps.cpp
+++ b/lib/colvars/colvardeps.cpp
@@ -1,569 +1,768 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvardeps.h"
+colvardeps::colvardeps()
+ : time_step_factor (1) {}
colvardeps::~colvardeps() {
size_t i;
- // Do not delete features if it's static
+ // Protest if we are deleting an object while a parent object may still depend on it
+ if (parents.size()) {
+ cvm::log("Warning: destroying \"" + description + "\" before its parents objects:");
+ for (i=0; i<parents.size(); i++) {
+ cvm::log(parents[i]->description);
+ }
+ }
+
+ // Do not delete features if it's a static object
+ // may change in the future though
// for (i=0; i<features.size(); i++) {
// if (features[i] != NULL) delete features[i];
// }
+
remove_all_children();
+}
- // Protest if we are deleting an object while a parent object may still depend on it
- // Another possible strategy is to have the child unlist itself from the parent's children
- if (parents.size()) {
- cvm::log("Warning: destroying " + description + " before its parents objects:");
- for (i=0; i<parents.size(); i++) {
- cvm::log(parents[i]->description);
+
+void colvardeps::free_children_deps() {
+ // Dereference children requirements of all enabled features
+ // Useful when object is destroyed or set inactive
+ // CAUTION: when setting the parent object inactive, disable "active" first
+ // then call this, to avoid double-dereferencing the deps of "active"
+
+ // Cannot be in the base class destructor because it needs the derived class features()
+ size_t i,j,fid;
+
+ if (cvm::debug()) cvm::log("DEPS: freeing children deps for " + description);
+
+ cvm::increase_depth();
+ for (fid = 0; fid < feature_states.size(); fid++) {
+ if (is_enabled(fid)) {
+ for (i=0; i<features()[fid]->requires_children.size(); i++) {
+ int g = features()[fid]->requires_children[i];
+ for (j=0; j<children.size(); j++) {
+ if (cvm::debug()) cvm::log("DEPS: dereferencing children's "
+ + children[j]->features()[g]->description);
+ children[j]->decr_ref_count(g);
+ }
+ }
+ }
+ }
+ cvm::decrease_depth();
+}
+
+
+// re-enable children features (and increase ref count accordingly)
+// So free_children_deps() can be called whenever an object becomes inactive
+void colvardeps::restore_children_deps() {
+ size_t i,j,fid;
+
+ cvm::increase_depth();
+ for (fid = 0; fid < feature_states.size(); fid++) {
+ if (is_enabled(fid)) {
+ for (i=0; i<features()[fid]->requires_children.size(); i++) {
+ int g = features()[fid]->requires_children[i];
+ for (j=0; j<children.size(); j++) {
+ if (cvm::debug()) cvm::log("DEPS: re-enabling children's "
+ + children[j]->features()[g]->description);
+ children[j]->enable(g, false, false);
+ }
+ }
}
}
+ cvm::decrease_depth();
}
void colvardeps::provide(int feature_id, bool truefalse) {
feature_states[feature_id].available = truefalse;
}
void colvardeps::set_enabled(int feature_id, bool truefalse) {
-// if (!is_static(feature_id)) {
-// cvm::error("Cannot set feature " + features()[feature_id]->description + " statically in " + description + ".\n");
-// return;
-// }
if (truefalse) {
- // Resolve dependencies too
enable(feature_id);
} else {
- feature_states[feature_id].enabled = false;
+ disable(feature_id);
}
}
bool colvardeps::get_keyval_feature(colvarparse *cvp,
std::string const &conf, char const *key,
int feature_id, bool const &def_value,
colvarparse::Parse_Mode const parse_mode)
{
if (!is_user(feature_id)) {
- cvm::error("Cannot set feature " + features()[feature_id]->description + " from user input in " + description + ".\n");
+ cvm::error("Cannot set feature \"" + features()[feature_id]->description + "\" from user input in \"" + description + "\".\n");
return false;
}
bool value;
bool const found = cvp->get_keyval(conf, key, value, def_value, parse_mode);
if (value) enable(feature_id);
return found;
}
int colvardeps::enable(int feature_id,
bool dry_run /* default: false */,
// dry_run: fail silently, do not enable if available
// flag is passed recursively to deps of this feature
bool toplevel /* default: true */)
// toplevel: false if this is called as part of a chain of dependency resolution
// this is used to diagnose failed dependencies by displaying the full stack
// only the toplevel dependency will throw a fatal error
{
int res;
size_t i, j;
bool ok;
feature *f = features()[feature_id];
feature_state *fs = &feature_states[feature_id];
if (cvm::debug()) {
cvm::log("DEPS: " + description +
- (dry_run ? " testing " : " requiring ") +
+ (dry_run ? " testing " : " enabling ") +
"\"" + f->description +"\"");
}
if (fs->enabled) {
- // Do not try to solve deps if already enabled
+ if (!(dry_run || toplevel)) {
+ // This is a dependency
+ // Prevent disabling this feature as long
+ // as requirement is enabled
+ fs->ref_count++;
+ if (cvm::debug())
+ cvm::log("DEPS: bumping ref_count to " + cvm::to_str(fs->ref_count));
+ }
+ // Do not try to further resolve deps
return COLVARS_OK;
}
+ std::string feature_type_descr = is_static(feature_id) ? "Static" :
+ (is_dynamic(feature_id) ? "Dynamic" : "User-controlled");
+
if (!fs->available) {
if (!dry_run) {
if (toplevel) {
- cvm::error("Error: Feature unavailable: \"" + f->description + "\" in " + description + ".");
+ cvm::error("Error: " + feature_type_descr + " feature unavailable: \""
+ + f->description + "\" in " + description + ".");
} else {
- cvm::log("Feature unavailable: \"" + f->description + "\" in " + description);
+ cvm::log(feature_type_descr + " feature unavailable: \""
+ + f->description + "\" in " + description + ".");
}
}
return COLVARS_ERROR;
}
if (!toplevel && !is_dynamic(feature_id)) {
if (!dry_run) {
- cvm::log("Non-dynamic feature : \"" + f->description
- + "\" in " + description + " may not be enabled as a dependency.\n");
+ cvm::log(feature_type_descr + " feature \"" + f->description
+ + "\" may not be enabled as a dependency in " + description + ".\n");
}
return COLVARS_ERROR;
}
// 1) enforce exclusions
+ // reminder: exclusions must be mutual for this to work
for (i=0; i<f->requires_exclude.size(); i++) {
feature *g = features()[f->requires_exclude[i]];
if (cvm::debug())
cvm::log(f->description + " requires exclude " + g->description);
if (is_enabled(f->requires_exclude[i])) {
if (!dry_run) {
- cvm::log("Features \"" + f->description + "\" is incompatible with \""
- + g->description + "\" in " + description);
+ cvm::log("Feature \"" + f->description + "\" is incompatible with \""
+ + g->description + "\" in " + description + ".");
if (toplevel) {
cvm::error("Error: Failed dependency in " + description + ".");
}
}
return COLVARS_ERROR;
}
}
// 2) solve internal deps (self)
for (i=0; i<f->requires_self.size(); i++) {
if (cvm::debug())
cvm::log(f->description + " requires self " + features()[f->requires_self[i]]->description);
res = enable(f->requires_self[i], dry_run, false);
if (res != COLVARS_OK) {
if (!dry_run) {
cvm::log("...required by \"" + f->description + "\" in " + description);
if (toplevel) {
cvm::error("Error: Failed dependency in " + description + ".");
}
}
return res;
}
}
// 3) solve internal alternate deps
for (i=0; i<f->requires_alt.size(); i++) {
// test if one is available; if yes, enable and exit w/ success
ok = false;
for (j=0; j<f->requires_alt[i].size(); j++) {
int g = f->requires_alt[i][j];
if (cvm::debug())
cvm::log(f->description + " requires alt " + features()[g]->description);
res = enable(g, true, false); // see if available
if (res == COLVARS_OK) {
ok = true;
- if (!dry_run) enable(g, false, false); // Require again, for real
+ if (!dry_run) {
+ enable(g, false, false); // Require again, for real
+ fs->alternate_refs.push_back(g); // We remember we enabled this
+ // so we can free it if this feature gets disabled
+ }
break;
}
}
if (!ok) {
if (!dry_run) {
- cvm::log("No dependency satisfied among alternates:");
- cvm::log("-----------------------------------------");
+ cvm::log("\"" + f->description + "\" in " + description
+ + " requires one of the following features, none of which can be enabled:\n");
+ cvm::log("-----------------------------------------\n");
+ cvm::increase_depth();
for (j=0; j<f->requires_alt[i].size(); j++) {
int g = f->requires_alt[i][j];
cvm::log(cvm::to_str(j+1) + ". " + features()[g]->description);
- cvm::increase_depth();
enable(g, false, false); // Just for printing error output
- cvm::decrease_depth();
}
+ cvm::decrease_depth();
cvm::log("-----------------------------------------");
- cvm::log("for \"" + f->description + "\" in " + description);
if (toplevel) {
cvm::error("Error: Failed dependency in " + description + ".");
}
}
return COLVARS_ERROR;
}
}
// 4) solve deps in children
+ // if the object is inactive, we solve but do not enable: will be enabled
+ // when the object becomes active
+ cvm::increase_depth();
for (i=0; i<f->requires_children.size(); i++) {
int g = f->requires_children[i];
for (j=0; j<children.size(); j++) {
- cvm::increase_depth();
- res = children[j]->enable(g, dry_run, false);
- cvm::decrease_depth();
+ res = children[j]->enable(g, dry_run || !is_enabled(), false);
if (res != COLVARS_OK) {
if (!dry_run) {
cvm::log("...required by \"" + f->description + "\" in " + description);
if (toplevel) {
cvm::error("Error: Failed dependency in " + description + ".");
}
}
return res;
}
}
- // If we've just touched the features of child objects, refresh them
- if (!dry_run && f->requires_children.size() != 0) {
+ }
+ cvm::decrease_depth();
+
+ // Actually enable feature only once everything checks out
+ if (!dry_run) {
+ fs->enabled = true;
+ // This should be the only reference
+ if (!toplevel) fs->ref_count = 1;
+ if (feature_id == 0) {
+ // Waking up this object, enable all deps in children
+ restore_children_deps();
+ }
+ do_feature_side_effects(feature_id);
+ if (cvm::debug())
+ cvm::log("DEPS: feature \"" + f->description + "\" in "
+ + description + " enabled, ref_count = 1.");
+ }
+ return COLVARS_OK;
+}
+
+
+int colvardeps::disable(int feature_id) {
+ size_t i, j;
+ feature *f = features()[feature_id];
+ feature_state *fs = &feature_states[feature_id];
+
+ if (cvm::debug()) cvm::log("DEPS: disabling feature \""
+ + f->description + "\" in " + description);
+
+ if (fs->enabled == false) {
+ return COLVARS_OK;
+ }
+
+ if (fs->ref_count > 1) {
+ cvm::error("Error: cannot disable feature \"" + f->description
+ + "\" in " + description + " because of " + cvm::to_str(fs->ref_count-1)
+ + " remaining references.\n" );
+ return COLVARS_ERROR;
+ }
+
+ // internal deps (self)
+ for (i=0; i<f->requires_self.size(); i++) {
+ if (cvm::debug()) cvm::log("DEPS: dereferencing self "
+ + features()[f->requires_self[i]]->description);
+ decr_ref_count(f->requires_self[i]);
+ }
+
+ // alternates
+ for (i=0; i<fs->alternate_refs.size(); i++) {
+ if (cvm::debug()) cvm::log("DEPS: dereferencing alt "
+ + features()[fs->alternate_refs[i]]->description);
+ decr_ref_count(fs->alternate_refs[i]);
+ }
+ // Forget these, now that they are dereferenced
+ fs->alternate_refs.clear();
+
+ // deps in children
+ // except if the object is inactive, then children dependencies
+ // have already been dereferenced by this function
+ // (or never referenced if feature was enabled while the object
+ // was inactive)
+ if (is_enabled()) {
+ cvm::increase_depth();
+ for (i=0; i<f->requires_children.size(); i++) {
+ int g = f->requires_children[i];
for (j=0; j<children.size(); j++) {
- children[j]->refresh_deps();
+ if (cvm::debug()) cvm::log("DEPS: dereferencing children's "
+ + children[j]->features()[g]->description);
+ children[j]->decr_ref_count(g);
}
}
+ cvm::decrease_depth();
}
- // Actually enable feature only once everything checks out
- if (!dry_run) fs->enabled = true;
+ fs->enabled = false;
+ fs->ref_count = 0;
+ if (feature_id == 0) {
+ // Putting this object to sleep
+ free_children_deps();
+ }
return COLVARS_OK;
}
+int colvardeps::decr_ref_count(int feature_id) {
+ int &rc = feature_states[feature_id].ref_count;
+ feature *f = features()[feature_id];
+
+ if (cvm::debug())
+ cvm::log("DEPS: decreasing reference count of \"" + f->description
+ + "\" in " + description + ".\n");
+
+ if (rc <= 0) {
+ cvm::error("Error: cannot decrease reference count of feature \"" + f->description
+ + "\" in " + description + ", which is " + cvm::to_str(rc) + ".\n");
+ return COLVARS_ERROR;
+ }
+
+ rc--;
+ if (rc == 0 && f->is_dynamic()) {
+ // we can auto-disable this feature
+ if (cvm::debug())
+ cvm::log("DEPS will now auto-disable dynamic feature \"" + f->description
+ + "\" in " + description + ".\n");
+ disable(feature_id);
+ }
+ return COLVARS_OK;
+}
-// disable() {
-//
-// // we need refs to parents to walk up the deps tree!
-// // or refresh
-// }
void colvardeps::init_feature(int feature_id, const char *description, feature_type type) {
features()[feature_id]->description = description;
features()[feature_id]->type = type;
}
// Shorthand macros for describing dependencies
#define f_req_self(f, g) features()[f]->requires_self.push_back(g)
// This macro ensures that exclusions are symmetric
#define f_req_exclude(f, g) features()[f]->requires_exclude.push_back(g); \
features()[g]->requires_exclude.push_back(f)
#define f_req_children(f, g) features()[f]->requires_children.push_back(g)
#define f_req_alt2(f, g, h) features()[f]->requires_alt.push_back(std::vector<int>(2));\
features()[f]->requires_alt.back()[0] = g; \
features()[f]->requires_alt.back()[1] = h
#define f_req_alt3(f, g, h, i) features()[f]->requires_alt.push_back(std::vector<int>(3));\
features()[f]->requires_alt.back()[0] = g; \
features()[f]->requires_alt.back()[1] = h; \
features()[f]->requires_alt.back()[2] = i
+#define f_req_alt4(f, g, h, i, j) features()[f]->requires_alt.push_back(std::vector<int>(4));\
+ features()[f]->requires_alt.back()[0] = g; \
+ features()[f]->requires_alt.back()[1] = h; \
+ features()[f]->requires_alt.back()[2] = i; \
+ features()[f]->requires_alt.back()[3] = j
void colvardeps::init_cvb_requires() {
int i;
if (features().size() == 0) {
for (i = 0; i < f_cvb_ntot; i++) {
features().push_back(new feature);
}
init_feature(f_cvb_active, "active", f_type_dynamic);
f_req_children(f_cvb_active, f_cv_active);
+ init_feature(f_cvb_awake, "awake", f_type_static);
+ f_req_self(f_cvb_awake, f_cvb_active);
+
init_feature(f_cvb_apply_force, "apply force", f_type_user);
f_req_children(f_cvb_apply_force, f_cv_gradient);
init_feature(f_cvb_get_total_force, "obtain total force");
f_req_children(f_cvb_get_total_force, f_cv_total_force);
init_feature(f_cvb_history_dependent, "history-dependent", f_type_static);
init_feature(f_cvb_scalar_variables, "require scalar variables", f_type_static);
f_req_children(f_cvb_scalar_variables, f_cv_scalar);
init_feature(f_cvb_calc_pmf, "calculate a PMF", f_type_static);
}
// Initialize feature_states for each instance
feature_states.reserve(f_cvb_ntot);
for (i = 0; i < f_cvb_ntot; i++) {
feature_states.push_back(feature_state(true, false));
// Most features are available, so we set them so
// and list exceptions below
}
}
void colvardeps::init_cv_requires() {
size_t i;
if (features().size() == 0) {
for (i = 0; i < f_cv_ntot; i++) {
features().push_back(new feature);
}
init_feature(f_cv_active, "active", f_type_dynamic);
- f_req_children(f_cv_active, f_cvc_active);
- // Colvars must be either a linear combination, or scalar (and polynomial) or scripted
- f_req_alt3(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted);
+ // Do not require f_cvc_active in children, as some components may be disabled
+ // Colvars must be either a linear combination, or scalar (and polynomial) or scripted/custom
+ f_req_alt4(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted, f_cv_custom_function);
+
+ init_feature(f_cv_awake, "awake", f_type_static);
+ f_req_self(f_cv_awake, f_cv_active);
init_feature(f_cv_gradient, "gradient", f_type_dynamic);
f_req_children(f_cv_gradient, f_cvc_gradient);
init_feature(f_cv_collect_gradient, "collect gradient", f_type_dynamic);
f_req_self(f_cv_collect_gradient, f_cv_gradient);
f_req_self(f_cv_collect_gradient, f_cv_scalar);
+ // The following exlusion could be lifted by implementing the feature
+ f_req_exclude(f_cv_collect_gradient, f_cv_scripted);
- init_feature(f_cv_fdiff_velocity, "fdiff_velocity", f_type_dynamic);
+ init_feature(f_cv_fdiff_velocity, "velocity from finite differences", f_type_dynamic);
// System force: either trivial (spring force); through extended Lagrangian, or calculated explicitly
init_feature(f_cv_total_force, "total force", f_type_dynamic);
f_req_alt2(f_cv_total_force, f_cv_extended_Lagrangian, f_cv_total_force_calc);
// Deps for explicit total force calculation
init_feature(f_cv_total_force_calc, "total force calculation", f_type_dynamic);
f_req_self(f_cv_total_force_calc, f_cv_scalar);
f_req_self(f_cv_total_force_calc, f_cv_linear);
f_req_children(f_cv_total_force_calc, f_cvc_inv_gradient);
f_req_self(f_cv_total_force_calc, f_cv_Jacobian);
init_feature(f_cv_Jacobian, "Jacobian derivative", f_type_dynamic);
f_req_self(f_cv_Jacobian, f_cv_scalar);
f_req_self(f_cv_Jacobian, f_cv_linear);
f_req_children(f_cv_Jacobian, f_cvc_Jacobian);
init_feature(f_cv_hide_Jacobian, "hide Jacobian force", f_type_user);
f_req_self(f_cv_hide_Jacobian, f_cv_Jacobian); // can only hide if calculated
init_feature(f_cv_extended_Lagrangian, "extended Lagrangian", f_type_user);
f_req_self(f_cv_extended_Lagrangian, f_cv_scalar);
f_req_self(f_cv_extended_Lagrangian, f_cv_gradient);
init_feature(f_cv_Langevin, "Langevin dynamics", f_type_user);
f_req_self(f_cv_Langevin, f_cv_extended_Lagrangian);
init_feature(f_cv_linear, "linear", f_type_static);
init_feature(f_cv_scalar, "scalar", f_type_static);
init_feature(f_cv_output_energy, "output energy", f_type_user);
init_feature(f_cv_output_value, "output value", f_type_user);
init_feature(f_cv_output_velocity, "output velocity", f_type_user);
f_req_self(f_cv_output_velocity, f_cv_fdiff_velocity);
init_feature(f_cv_output_applied_force, "output applied force", f_type_user);
init_feature(f_cv_output_total_force, "output total force", f_type_user);
f_req_self(f_cv_output_total_force, f_cv_total_force);
init_feature(f_cv_subtract_applied_force, "subtract applied force from total force", f_type_user);
f_req_self(f_cv_subtract_applied_force, f_cv_total_force);
+ // There is no well-defined way to implement f_cv_subtract_applied_force
+ // in the case of extended-Lagrangian colvars
+ f_req_exclude(f_cv_subtract_applied_force, f_cv_extended_Lagrangian);
init_feature(f_cv_lower_boundary, "lower boundary", f_type_user);
f_req_self(f_cv_lower_boundary, f_cv_scalar);
init_feature(f_cv_upper_boundary, "upper boundary", f_type_user);
f_req_self(f_cv_upper_boundary, f_cv_scalar);
init_feature(f_cv_grid, "grid", f_type_user);
f_req_self(f_cv_grid, f_cv_lower_boundary);
f_req_self(f_cv_grid, f_cv_upper_boundary);
init_feature(f_cv_runave, "running average", f_type_user);
init_feature(f_cv_corrfunc, "correlation function", f_type_user);
- init_feature(f_cv_scripted, "scripted", f_type_static);
+ init_feature(f_cv_scripted, "scripted", f_type_user);
+
+ init_feature(f_cv_custom_function, "custom function", f_type_user);
+ f_req_exclude(f_cv_custom_function, f_cv_scripted);
+
init_feature(f_cv_periodic, "periodic", f_type_static);
f_req_self(f_cv_periodic, f_cv_homogeneous);
init_feature(f_cv_scalar, "scalar", f_type_static);
init_feature(f_cv_linear, "linear", f_type_static);
init_feature(f_cv_homogeneous, "homogeneous", f_type_static);
+
+ // because total forces are obtained from the previous time step,
+ // we cannot (currently) have colvar values and total forces for the same timestep
+ init_feature(f_cv_multiple_ts, "multiple timestep colvar");
+ f_req_exclude(f_cv_multiple_ts, f_cv_total_force_calc);
}
// Initialize feature_states for each instance
feature_states.reserve(f_cv_ntot);
for (i = 0; i < f_cv_ntot; i++) {
feature_states.push_back(feature_state(true, false));
// Most features are available, so we set them so
// and list exceptions below
}
-
-// // properties that may NOT be enabled as a dependency
-// // This will be deprecated by feature types
-// int unavailable_deps[] = {
-// f_cv_lower_boundary,
-// f_cv_upper_boundary,
-// f_cv_extended_Lagrangian,
-// f_cv_Langevin,
-// f_cv_scripted,
-// f_cv_periodic,
-// f_cv_scalar,
-// f_cv_linear,
-// f_cv_homogeneous
-// };
-// for (i = 0; i < sizeof(unavailable_deps) / sizeof(unavailable_deps[0]); i++) {
-// feature_states[unavailable_deps[i]].available = false;
-// }
}
void colvardeps::init_cvc_requires() {
size_t i;
// Initialize static array once and for all
if (features().size() == 0) {
for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
features().push_back(new feature);
}
init_feature(f_cvc_active, "active", f_type_dynamic);
// The dependency below may become useful if we use dynamic atom groups
// f_req_children(f_cvc_active, f_ag_active);
init_feature(f_cvc_scalar, "scalar", f_type_static);
init_feature(f_cvc_gradient, "gradient", f_type_dynamic);
+ init_feature(f_cvc_implicit_gradient, "implicit gradient", f_type_static);
+ f_req_children(f_cvc_implicit_gradient, f_ag_implicit_gradient);
+
init_feature(f_cvc_inv_gradient, "inverse gradient", f_type_dynamic);
f_req_self(f_cvc_inv_gradient, f_cvc_gradient);
init_feature(f_cvc_debug_gradient, "debug gradient", f_type_user);
f_req_self(f_cvc_debug_gradient, f_cvc_gradient);
+ f_req_exclude(f_cvc_debug_gradient, f_cvc_implicit_gradient);
init_feature(f_cvc_Jacobian, "Jacobian derivative", f_type_dynamic);
f_req_self(f_cvc_Jacobian, f_cvc_inv_gradient);
init_feature(f_cvc_com_based, "depends on group centers of mass", f_type_static);
+ // init_feature(f_cvc_pbc_minimum_image, "use minimum-image distances with PBCs", f_type_user);
+
// Compute total force on first site only to avoid unwanted
// coupling to other colvars (see e.g. Ciccotti et al., 2005)
- init_feature(f_cvc_one_site_total_force, "compute total collective force only from one group center", f_type_user);
+ init_feature(f_cvc_one_site_total_force, "compute total force from one group", f_type_user);
f_req_self(f_cvc_one_site_total_force, f_cvc_com_based);
init_feature(f_cvc_scalable, "scalable calculation", f_type_static);
f_req_self(f_cvc_scalable, f_cvc_scalable_com);
init_feature(f_cvc_scalable_com, "scalable calculation of centers of mass", f_type_static);
f_req_self(f_cvc_scalable_com, f_cvc_com_based);
// TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group
// f_req_children(f_cvc_scalable, f_ag_scalable);
// f_req_children(f_cvc_scalable_com, f_ag_scalable_com);
}
// Initialize feature_states for each instance
// default as available, not enabled
// except dynamic features which default as unavailable
feature_states.reserve(f_cvc_ntot);
for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
bool avail = is_dynamic(i) ? false : true;
feature_states.push_back(feature_state(avail, false));
}
+ // CVCs are enabled from the start - get disabled based on flags
+ feature_states[f_cvc_active].enabled = true;
+
// Features that are implemented by all cvcs by default
// Each cvc specifies what other features are available
feature_states[f_cvc_active].available = true;
feature_states[f_cvc_gradient].available = true;
+ // Use minimum-image distances by default
+ feature_states[f_cvc_pbc_minimum_image].enabled = true;
+
// Features that are implemented by default if their requirements are
feature_states[f_cvc_one_site_total_force].available = true;
// Features That are implemented only for certain simulation engine configurations
feature_states[f_cvc_scalable_com].available = (cvm::proxy->scalable_group_coms() == COLVARS_OK);
feature_states[f_cvc_scalable].available = feature_states[f_cvc_scalable_com].available;
}
void colvardeps::init_ag_requires() {
size_t i;
// Initialize static array once and for all
if (features().size() == 0) {
for (i = 0; i < f_ag_ntot; i++) {
features().push_back(new feature);
}
init_feature(f_ag_active, "active", f_type_dynamic);
init_feature(f_ag_center, "translational fit", f_type_static);
init_feature(f_ag_rotate, "rotational fit", f_type_static);
init_feature(f_ag_fitting_group, "reference positions group", f_type_static);
- init_feature(f_ag_fit_gradient_group, "fit gradient for main group", f_type_static);
- init_feature(f_ag_fit_gradient_ref, "fit gradient for reference group", f_type_static);
+ init_feature(f_ag_implicit_gradient, "implicit atom gradient", f_type_dynamic);
+ init_feature(f_ag_fit_gradients, "fit gradients", f_type_user);
+ f_req_exclude(f_ag_fit_gradients, f_ag_implicit_gradient);
+
init_feature(f_ag_atom_forces, "atomic forces", f_type_dynamic);
// parallel calculation implies that we have at least a scalable center of mass,
// but f_ag_scalable is kept as a separate feature to deal with future dependencies
init_feature(f_ag_scalable, "scalable group calculation", f_type_static);
init_feature(f_ag_scalable_com, "scalable group center of mass calculation", f_type_static);
f_req_self(f_ag_scalable, f_ag_scalable_com);
// init_feature(f_ag_min_msd_fit, "minimum MSD fit")
// f_req_self(f_ag_min_msd_fit, f_ag_center)
// f_req_self(f_ag_min_msd_fit, f_ag_rotate)
// f_req_exclude(f_ag_min_msd_fit, f_ag_fitting_group)
}
// Initialize feature_states for each instance
// default as unavailable, not enabled
feature_states.reserve(f_ag_ntot);
for (i = 0; i < colvardeps::f_ag_ntot; i++) {
feature_states.push_back(feature_state(false, false));
}
// Features that are implemented (or not) by all atom groups
feature_states[f_ag_active].available = true;
// f_ag_scalable_com is provided by the CVC iff it is COM-based
feature_states[f_ag_scalable_com].available = false;
// TODO make f_ag_scalable depend on f_ag_scalable_com (or something else)
feature_states[f_ag_scalable].available = true;
+ feature_states[f_ag_fit_gradients].available = true;
+ feature_states[f_ag_implicit_gradient].available = true;
}
void colvardeps::print_state() {
size_t i;
- cvm::log("Enabled features of " + description);
+ cvm::log("Enabled features of \"" + description + "\" (with reference count)");
for (i = 0; i < feature_states.size(); i++) {
- if (feature_states[i].enabled)
- cvm::log("- " + features()[i]->description);
+ if (is_enabled(i))
+ cvm::log("- " + features()[i]->description + " ("
+ + cvm::to_str(feature_states[i].ref_count) + ")");
}
+ cvm::increase_depth();
for (i=0; i<children.size(); i++) {
cvm::log("* child " + cvm::to_str(i+1));
- cvm::increase_depth();
children[i]->print_state();
- cvm::decrease_depth();
}
+ cvm::decrease_depth();
}
void colvardeps::add_child(colvardeps *child) {
+
children.push_back(child);
child->parents.push_back((colvardeps *)this);
+
+ // Solve dependencies of already enabled parent features
+ // in the new child
+
+ size_t i, fid;
+ cvm::increase_depth();
+ for (fid = 0; fid < feature_states.size(); fid++) {
+ if (is_enabled(fid)) {
+ for (i=0; i<features()[fid]->requires_children.size(); i++) {
+ int g = features()[fid]->requires_children[i];
+ if (cvm::debug()) cvm::log("DEPS: re-enabling children's "
+ + child->features()[g]->description);
+ child->enable(g, false, false);
+ }
+ }
+ }
+ cvm::decrease_depth();
}
void colvardeps::remove_child(colvardeps *child) {
int i;
bool found = false;
for (i = children.size()-1; i>=0; --i) {
if (children[i] == child) {
children.erase(children.begin() + i);
found = true;
break;
}
}
if (!found) {
cvm::error("Trying to remove missing child reference from " + description + "\n");
}
found = false;
for (i = child->parents.size()-1; i>=0; --i) {
if (child->parents[i] == this) {
child->parents.erase(child->parents.begin() + i);
found = true;
break;
}
}
if (!found) {
cvm::error("Trying to remove missing parent reference from " + child->description + "\n");
}
}
void colvardeps::remove_all_children() {
size_t i;
int j;
bool found;
for (i = 0; i < children.size(); ++i) {
found = false;
for (j = children[i]->parents.size()-1; j>=0; --j) {
if (children[i]->parents[j] == this) {
children[i]->parents.erase(children[i]->parents.begin() + j);
found = true;
break;
}
}
if (!found) {
cvm::error("Trying to remove missing parent reference from " + children[i]->description + "\n");
}
}
children.clear();
}
diff --git a/lib/colvars/colvardeps.h b/lib/colvars/colvardeps.h
index fd07cb645..b810a5fca 100644
--- a/lib/colvars/colvardeps.h
+++ b/lib/colvars/colvardeps.h
@@ -1,310 +1,354 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARDEPS_H
#define COLVARDEPS_H
#include "colvarmodule.h"
#include "colvarparse.h"
/// \brief Parent class for a member object of a bias, cv or cvc etc. containing features and
/// their dependencies, and handling dependency resolution
///
/// There are 3 kinds of features:
/// 1. Dynamic features are under the control of the dependency resolution
/// system. They may be enabled or disabled depending on dependencies.
/// 2. User features may be enabled based on user input (they may trigger a failure upon dependency resolution, though)
/// 3. Static features are static properties of the object, determined
/// programatically at initialization time.
///
+/// In all classes, feature 0 is active. When an object is inactivated
+/// all its children dependencies are dereferenced (free_children_deps)
+/// While the object is inactive, no dependency solving is done on children
+/// it is done when the object is activated back (restore_children_deps)
class colvardeps {
public:
- colvardeps() {}
+ colvardeps();
virtual ~colvardeps();
// Subclasses should initialize the following members:
std::string description; // reference to object name (cv, cvc etc.)
/// This contains the current state of each feature for each object
+ // since the feature class only contains static properties
struct feature_state {
feature_state(bool a, bool e)
- : available(a), enabled(e) {}
+ : available(a), enabled(e), ref_count(0) {}
/// Feature may be enabled, subject to possible dependencies
bool available;
/// Currently enabled - this flag is subject to change dynamically
/// TODO consider implications for dependency solving: anyone who disables
/// it should trigger a refresh of parent objects
bool enabled; // see if this should be private depending on implementation
+
// bool enabledOnce; // this should trigger an update when object is evaluated
+
+ /// Number of features requiring this one as a dependency
+ /// When it falls to zero:
+ /// - a dynamic feature is disabled automatically
+ /// - other features may be disabled statically
+ int ref_count;
+ /// List of features that were enabled by this one
+ /// as part of an alternate requirement (for ref counting purposes)
+ /// This is necessary because we don't know which feature in the list
+ /// we enabled, otherwise
+ std::vector<int> alternate_refs;
};
+protected:
+ /// Time step multiplier (for coarse-timestep biases & colvars)
+ /// Biases and colvars will only be calculated at those times
+ /// (f_cvb_awake and f_cv_awake); a
+ /// Biases use this to apply "impulse" biasing forces at the outer timestep
+ /// Unused by lower-level objects (cvcs and atom groups)
+ int time_step_factor;
private:
/// List of the states of all features
std::vector<feature_state> feature_states;
/// Enum of possible feature types
enum feature_type {
f_type_not_set,
f_type_dynamic,
f_type_user,
f_type_static
};
public:
+ /// \brief returns time_step_factor
+ inline int get_time_step_factor() const {return time_step_factor;}
+
/// Pair a numerical feature ID with a description and type
void init_feature(int feature_id, const char *description, feature_type type = f_type_not_set);
- /// Describes a feature and its dependecies
+ /// Describes a feature and its dependencies
/// used in a static array within each subclass
class feature {
public:
feature() {}
~feature() {}
std::string description; // Set by derived object initializer
// features that this feature requires in the same object
// NOTE: we have no safety mechanism against circular dependencies, however, they would have to be internal to an object (ie. requires_self or requires_alt)
std::vector<int> requires_self;
// Features that are incompatible, ie. required disabled
// if enabled, they will cause a dependency failure (they will not be disabled)
// To enforce these dependencies regardless of the order in which they
// are enabled, they are always set in a symmetric way, so whichever is enabled
// second will cause the dependency to fail
std::vector<int> requires_exclude;
// sets of features that are required in an alternate way
// when parent feature is enabled, if none are enabled, the first one listed that is available will be enabled
std::vector<std::vector<int> > requires_alt;
// features that this feature requires in children
std::vector<int> requires_children;
inline bool is_dynamic() { return type == f_type_dynamic; }
inline bool is_static() { return type == f_type_static; }
inline bool is_user() { return type == f_type_user; }
/// Type of this feature, from the enum feature_type
feature_type type;
};
inline bool is_dynamic(int id) { return features()[id]->type == f_type_dynamic; }
inline bool is_static(int id) { return features()[id]->type == f_type_static; }
inline bool is_user(int id) { return features()[id]->type == f_type_user; }
// Accessor to array of all features with deps, static in most derived classes
// Subclasses with dynamic dependency trees may override this
// with a non-static array
// Intermediate classes (colvarbias and colvarcomp, which are also base classes)
// implement this as virtual to allow overriding
virtual std::vector<feature *>&features() = 0;
void add_child(colvardeps *child);
void remove_child(colvardeps *child);
/// Used before deleting an object, if not handled by that object's destructor
/// (useful for cvcs because their children are member objects)
void remove_all_children();
private:
- // pointers to objects this object depends on
- // list should be maintained by any code that modifies the object
- // this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions
+ /// pointers to objects this object depends on
+ /// list should be maintained by any code that modifies the object
+ /// this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions
std::vector<colvardeps *> children;
- // pointers to objects that depend on this object
- // the size of this array is in effect a reference counter
+ /// pointers to objects that depend on this object
+ /// the size of this array is in effect a reference counter
std::vector<colvardeps *> parents;
public:
- // disabling a feature f:
- // if parents depend on f, tell them to refresh / check that they are ok?
- // if children provide features to satisfy f ONLY, disable that
-
- // When the state of this object has changed, recursively tell parents
- // to enforce their dependencies
-// void refresh_parents() {
-//
-// }
-
- // std::vector<colvardeps *> parents; // Needed to trigger a refresh if capabilities of this object change
-
- // End of members to be initialized by subclasses
-
// Checks whether given feature is enabled
// Defaults to querying f_*_active
inline bool is_enabled(int f = f_cv_active) const {
return feature_states[f].enabled;
}
// Checks whether given feature is available
// Defaults to querying f_*_active
inline bool is_available(int f = f_cv_active) const {
return feature_states[f].available;
}
/// Set the feature's available flag, without checking
/// To be used for dynamic properties
/// dependencies will be checked by enable()
void provide(int feature_id, bool truefalse = true);
- /// Set the feature's enabled flag, without dependency check or resolution
- /// To be used for static properties only
- /// Checking for availability is up to the caller
+ /// Enable or disable, depending on flag value
void set_enabled(int feature_id, bool truefalse = true);
protected:
/// Parse a keyword and enable a feature accordingly
bool get_keyval_feature(colvarparse *cvp,
std::string const &conf, char const *key,
int feature_id, bool const &def_value,
colvarparse::Parse_Mode const parse_mode = colvarparse::parse_normal);
public:
- int enable(int f, bool dry_run = false, bool toplevel = true); // enable a feature and recursively solve its dependencies
- // dry_run is set to true to recursively test if a feature is available, without enabling it
-// int disable(int f);
+ /// enable a feature and recursively solve its dependencies
+ /// for proper reference counting, one should not add
+ /// spurious calls to enable()
+ /// dry_run is set to true to recursively test if a feature is available, without enabling it
+ int enable(int f, bool dry_run = false, bool toplevel = true);
+
+ /// Disable a feature, decrease the reference count of its dependencies
+ /// and recursively disable them as applicable
+ int disable(int f);
+
+ /// disable all enabled features to free their dependencies
+ /// to be done when deleting the object
+ /// Cannot be in the base class destructor because it needs the derived class features()
+ void free_children_deps();
+
+ /// re-enable children features (to be used when object becomes active)
+ void restore_children_deps();
+ /// Decrement the reference count of a feature
+ /// disabling it if it's dynamic and count reaches zero
+ int decr_ref_count(int f);
- /// This function is called whenever feature states are changed outside
- /// of the object's control, that is, by parents
- /// Eventually it may also be used when properties of children change
- virtual int refresh_deps() { return COLVARS_OK; }
+ /// Implements possible actions to be carried out
+ /// when a given feature is enabled
+ /// Base function does nothing, can be overloaded
+ virtual void do_feature_side_effects(int id) {}
// NOTE that all feature enums should start with f_*_active
enum features_biases {
/// \brief Bias is active
f_cvb_active,
- f_cvb_apply_force, // will apply forces
- f_cvb_get_total_force, // requires total forces
- f_cvb_history_dependent, // depends on simulation history
- f_cvb_scalar_variables, // requires scalar colvars
- f_cvb_calc_pmf, // whether this bias will compute a PMF
+ /// \brief Bias is awake (active on its own accord) this timestep
+ f_cvb_awake,
+ /// \brief will apply forces
+ f_cvb_apply_force,
+ /// \brief requires total forces
+ f_cvb_get_total_force,
+ /// \brief depends on simulation history
+ f_cvb_history_dependent,
+ /// \brief requires scalar colvars
+ f_cvb_scalar_variables,
+ /// \brief whether this bias will compute a PMF
+ f_cvb_calc_pmf,
f_cvb_ntot
};
enum features_colvar {
/// \brief Calculate colvar
f_cv_active,
+ /// \brief Colvar is awake (active on its own accord) this timestep
+ f_cv_awake,
/// \brief Gradients are calculated and temporarily stored, so
/// that external forces can be applied
f_cv_gradient,
/// \brief Collect atomic gradient data from all cvcs into vector
/// atomic_gradient
f_cv_collect_gradient,
/// \brief Calculate the velocity with finite differences
f_cv_fdiff_velocity,
/// \brief The total force is calculated, projecting the atomic
/// forces on the inverse gradient
f_cv_total_force,
/// \brief Calculate total force from atomic forces
f_cv_total_force_calc,
/// \brief Subtract the applied force from the total force
f_cv_subtract_applied_force,
/// \brief Estimate Jacobian derivative
f_cv_Jacobian,
/// \brief Do not report the Jacobian force as part of the total force
/// instead, apply a correction internally to cancel it
f_cv_hide_Jacobian,
/// \brief The variable has a harmonic restraint around a moving
/// center with fictitious mass; bias forces will be applied to
/// the center
f_cv_extended_Lagrangian,
/// \brief The extended system coordinate undergoes Langevin dynamics
f_cv_Langevin,
/// \brief Output the potential and kinetic energies
/// (for extended Lagrangian colvars only)
f_cv_output_energy,
/// \brief Output the value to the trajectory file (on by default)
f_cv_output_value,
/// \brief Output the velocity to the trajectory file
f_cv_output_velocity,
/// \brief Output the applied force to the trajectory file
f_cv_output_applied_force,
/// \brief Output the total force to the trajectory file
f_cv_output_total_force,
/// \brief A lower boundary is defined
f_cv_lower_boundary,
/// \brief An upper boundary is defined
f_cv_upper_boundary,
/// \brief Provide a discretization of the values of the colvar to
/// be used by the biases or in analysis (needs lower and upper
/// boundary)
f_cv_grid,
/// \brief Compute running average
f_cv_runave,
/// \brief Compute time correlation function
f_cv_corrfunc,
/// \brief Value and gradient computed by user script
f_cv_scripted,
+ /// \brief Value and gradient computed by user function through Lepton
+ f_cv_custom_function,
/// \brief Colvar is periodic
f_cv_periodic,
/// \brief is scalar
f_cv_scalar,
f_cv_linear,
f_cv_homogeneous,
+ /// \brief multiple timestep through time_step_factor
+ f_cv_multiple_ts,
/// \brief Number of colvar features
f_cv_ntot
};
enum features_cvc {
f_cvc_active,
f_cvc_scalar,
f_cvc_gradient,
+ /// \brief CVC doesn't calculate and store explicit atom gradients
+ f_cvc_implicit_gradient,
f_cvc_inv_gradient,
/// \brief If enabled, calc_gradients() will call debug_gradients() for every group needed
f_cvc_debug_gradient,
f_cvc_Jacobian,
+ f_cvc_pbc_minimum_image,
f_cvc_one_site_total_force,
f_cvc_com_based,
f_cvc_scalable,
f_cvc_scalable_com,
f_cvc_ntot
};
enum features_atomgroup {
f_ag_active,
f_ag_center,
f_ag_rotate,
f_ag_fitting_group,
/// Perform a standard minimum msd fit for given atoms
/// ie. not using refpositionsgroup
// f_ag_min_msd_fit,
- f_ag_fit_gradient_group,// TODO check that these are sometimes needed separately
- // maybe for minimum RMSD?
- f_ag_fit_gradient_ref,
+ /// \brief Does not have explicit atom gradients from parent CVC
+ f_ag_implicit_gradient,
+ f_ag_fit_gradients,
f_ag_atom_forces,
f_ag_scalable,
f_ag_scalable_com,
f_ag_ntot
};
void init_cvb_requires();
void init_cv_requires();
void init_cvc_requires();
void init_ag_requires();
/// \brief print all enabled features and those of children, for debugging
void print_state();
};
#endif
diff --git a/lib/colvars/colvargrid.cpp b/lib/colvars/colvargrid.cpp
index 3b25acd2e..9016e2c23 100644
--- a/lib/colvars/colvargrid.cpp
+++ b/lib/colvars/colvargrid.cpp
@@ -1,193 +1,194 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
#include "colvargrid.h"
colvar_grid_count::colvar_grid_count()
: colvar_grid<size_t>()
{
mult = 1;
}
colvar_grid_count::colvar_grid_count(std::vector<int> const &nx_i,
size_t const &def_count)
: colvar_grid<size_t>(nx_i, def_count, 1)
{}
colvar_grid_count::colvar_grid_count(std::vector<colvar *> &colvars,
size_t const &def_count)
: colvar_grid<size_t>(colvars, def_count, 1)
{}
colvar_grid_scalar::colvar_grid_scalar()
: colvar_grid<cvm::real>(), samples(NULL), grad(NULL)
{}
colvar_grid_scalar::colvar_grid_scalar(colvar_grid_scalar const &g)
: colvar_grid<cvm::real>(g), samples(NULL), grad(NULL)
{
grad = new cvm::real[nd];
}
colvar_grid_scalar::colvar_grid_scalar(std::vector<int> const &nx_i)
: colvar_grid<cvm::real>(nx_i, 0.0, 1), samples(NULL), grad(NULL)
{
grad = new cvm::real[nd];
}
colvar_grid_scalar::colvar_grid_scalar(std::vector<colvar *> &colvars, bool margin)
: colvar_grid<cvm::real>(colvars, 0.0, 1, margin), samples(NULL), grad(NULL)
{
grad = new cvm::real[nd];
}
colvar_grid_scalar::~colvar_grid_scalar()
{
if (grad) {
delete [] grad;
grad = NULL;
}
}
cvm::real colvar_grid_scalar::maximum_value() const
{
cvm::real max = data[0];
for (size_t i = 0; i < nt; i++) {
if (data[i] > max) max = data[i];
}
return max;
}
cvm::real colvar_grid_scalar::minimum_value() const
{
cvm::real min = data[0];
for (size_t i = 0; i < nt; i++) {
if (data[i] < min) min = data[i];
}
return min;
}
cvm::real colvar_grid_scalar::minimum_pos_value() const
{
cvm::real minpos = data[0];
size_t i;
for (i = 0; i < nt; i++) {
if(data[i] > 0) {
minpos = data[i];
break;
}
}
for (i = 0; i < nt; i++) {
if (data[i] > 0 && data[i] < minpos) minpos = data[i];
}
return minpos;
}
cvm::real colvar_grid_scalar::integral() const
{
cvm::real sum = 0.0;
for (size_t i = 0; i < nt; i++) {
sum += data[i];
}
cvm::real bin_volume = 1.0;
for (size_t id = 0; id < widths.size(); id++) {
bin_volume *= widths[id];
}
return bin_volume * sum;
}
cvm::real colvar_grid_scalar::entropy() const
{
cvm::real sum = 0.0;
for (size_t i = 0; i < nt; i++) {
sum += -1.0 * data[i] * std::log(data[i]);
}
cvm::real bin_volume = 1.0;
for (size_t id = 0; id < widths.size(); id++) {
bin_volume *= widths[id];
}
return bin_volume * sum;
}
colvar_grid_gradient::colvar_grid_gradient()
: colvar_grid<cvm::real>(), samples(NULL)
{}
colvar_grid_gradient::colvar_grid_gradient(std::vector<int> const &nx_i)
: colvar_grid<cvm::real>(nx_i, 0.0, nx_i.size()), samples(NULL)
{}
colvar_grid_gradient::colvar_grid_gradient(std::vector<colvar *> &colvars)
: colvar_grid<cvm::real>(colvars, 0.0, colvars.size()), samples(NULL)
{}
void colvar_grid_gradient::write_1D_integral(std::ostream &os)
{
cvm::real bin, min, integral;
std::vector<cvm::real> int_vals;
os << "# xi A(xi)\n";
if ( cv.size() != 1 ) {
- cvm::fatal_error("Cannot write integral for multi-dimensional gradient grids.");
+ cvm::error("Cannot write integral for multi-dimensional gradient grids.");
+ return;
}
integral = 0.0;
int_vals.push_back( 0.0 );
min = 0.0;
// correction for periodic colvars, so that the PMF is periodic
cvm::real corr;
if ( periodic[0] ) {
corr = average();
} else {
corr = 0.0;
}
for (std::vector<int> ix = new_index(); index_ok(ix); incr(ix)) {
if (samples) {
size_t const samples_here = samples->value(ix);
if (samples_here)
integral += (value(ix) / cvm::real(samples_here) - corr) * cv[0]->width;
} else {
integral += (value(ix) - corr) * cv[0]->width;
}
if ( integral < min ) min = integral;
int_vals.push_back( integral );
}
bin = 0.0;
for ( int i = 0; i < nx[0]; i++, bin += 1.0 ) {
os << std::setw(10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " "
<< std::setw(cvm::cv_width)
<< std::setprecision(cvm::cv_prec)
<< int_vals[i] - min << "\n";
}
os << std::setw(10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " "
<< std::setw(cvm::cv_width)
<< std::setprecision(cvm::cv_prec)
<< int_vals[nx[0]] - min << "\n";
return;
}
diff --git a/lib/colvars/colvargrid.h b/lib/colvars/colvargrid.h
index d4b9295c6..6f06cb106 100644
--- a/lib/colvars/colvargrid.h
+++ b/lib/colvars/colvargrid.h
@@ -1,1497 +1,1493 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARGRID_H
#define COLVARGRID_H
#include <iostream>
#include <iomanip>
#include <cmath>
#include "colvar.h"
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
/// \brief Grid of values of a function of several collective
/// variables \param T The data type
///
/// Only scalar colvars supported so far: vector colvars are treated as arrays
template <class T> class colvar_grid : public colvarparse {
protected:
/// Number of dimensions
size_t nd;
/// Number of points along each dimension
std::vector<int> nx;
/// Cumulative number of points along each dimension
std::vector<int> nxc;
/// \brief Multiplicity of each datum (allow the binning of
/// non-scalar types such as atomic gradients)
size_t mult;
/// Total number of grid points
size_t nt;
/// Low-level array of values
std::vector<T> data;
/// Newly read data (used for count grids, when adding several grids read from disk)
std::vector<size_t> new_data;
/// Colvars collected in this grid
std::vector<colvar *> cv;
/// Do we request actual value (for extended-system colvars)?
std::vector<bool> actual_value;
/// Get the low-level index corresponding to an index
inline size_t address(std::vector<int> const &ix) const
{
size_t addr = 0;
for (size_t i = 0; i < nd; i++) {
addr += ix[i]*nxc[i];
if (cvm::debug()) {
if (ix[i] >= nx[i]) {
cvm::error("Error: exceeding bounds in colvar_grid.\n", BUG_ERROR);
return 0;
}
}
}
return addr;
}
public:
/// Lower boundaries of the colvars in this grid
std::vector<colvarvalue> lower_boundaries;
/// Upper boundaries of the colvars in this grid
std::vector<colvarvalue> upper_boundaries;
/// Whether some colvars are periodic
std::vector<bool> periodic;
/// Whether some colvars have hard lower boundaries
std::vector<bool> hard_lower_boundaries;
/// Whether some colvars have hard upper boundaries
std::vector<bool> hard_upper_boundaries;
/// Widths of the colvars in this grid
std::vector<cvm::real> widths;
/// True if this is a count grid related to another grid of data
bool has_parent_data;
/// Whether this grid has been filled with data or is still empty
bool has_data;
/// Return the number of colvars
inline size_t number_of_colvars() const
{
return nd;
}
/// Return the number of points in the i-th direction, if provided, or
/// the total number
inline size_t number_of_points(int const icv = -1) const
{
if (icv < 0) {
return nt;
} else {
return nx[icv];
}
}
/// Get the sizes in each direction
inline std::vector<int> const & sizes() const
{
return nx;
}
/// Set the sizes in each direction
inline void set_sizes(std::vector<int> const &new_sizes)
{
nx = new_sizes;
}
/// Return the multiplicity of the type used
inline size_t multiplicity() const
{
return mult;
}
/// \brief Request grid to use actual values of extended coords
inline void request_actual_value(bool b = true)
{
size_t i;
for (i = 0; i < actual_value.size(); i++) {
actual_value[i] = b;
}
}
/// \brief Allocate data
int setup(std::vector<int> const &nx_i,
T const &t = T(),
size_t const &mult_i = 1)
{
if (cvm::debug()) {
cvm::log("Allocating grid: multiplicity = "+cvm::to_str(mult_i)+
", dimensions = "+cvm::to_str(nx_i)+".\n");
}
mult = mult_i;
data.clear();
nx = nx_i;
nd = nx.size();
nxc.resize(nd);
// setup dimensions
nt = mult;
for (int i = nd-1; i >= 0; i--) {
if (nx[i] <= 0) {
cvm::error("Error: providing an invalid number of grid points, "+
cvm::to_str(nx[i])+".\n", BUG_ERROR);
return COLVARS_ERROR;
}
nxc[i] = nt;
nt *= nx[i];
}
if (cvm::debug()) {
cvm::log("Total number of grid elements = "+cvm::to_str(nt)+".\n");
}
data.reserve(nt);
data.assign(nt, t);
return COLVARS_OK;
}
/// \brief Allocate data (allow initialization also after construction)
int setup()
{
return setup(this->nx, T(), this->mult);
}
/// \brief Reset data (in case the grid is being reused)
void reset(T const &t = T())
{
data.assign(nt, t);
}
/// Default constructor
colvar_grid() : has_data(false)
{
- save_delimiters = false;
nd = nt = 0;
mult = 1;
this->setup();
}
/// Destructor
virtual ~colvar_grid()
{}
/// \brief "Almost copy-constructor": only copies configuration
/// parameters from another grid, but doesn't reallocate stuff;
/// setup() must be called after that;
colvar_grid(colvar_grid<T> const &g) : nd(g.nd),
nx(g.nx),
mult(g.mult),
data(),
cv(g.cv),
actual_value(g.actual_value),
lower_boundaries(g.lower_boundaries),
upper_boundaries(g.upper_boundaries),
periodic(g.periodic),
hard_lower_boundaries(g.hard_lower_boundaries),
hard_upper_boundaries(g.hard_upper_boundaries),
widths(g.widths),
has_data(false)
{
- save_delimiters = false;
}
/// \brief Constructor from explicit grid sizes \param nx_i Number
/// of grid points along each dimension \param t Initial value for
/// the function at each point (optional) \param mult_i Multiplicity
/// of each value
colvar_grid(std::vector<int> const &nx_i,
T const &t = T(),
size_t mult_i = 1)
: has_data(false)
{
- save_delimiters = false;
this->setup(nx_i, t, mult_i);
}
/// \brief Constructor from a vector of colvars
colvar_grid(std::vector<colvar *> const &colvars,
T const &t = T(),
size_t mult_i = 1,
bool margin = false)
: has_data(false)
{
- save_delimiters = false;
this->init_from_colvars(colvars, t, mult_i, margin);
}
int init_from_colvars(std::vector<colvar *> const &colvars,
T const &t = T(),
size_t mult_i = 1,
bool margin = false)
{
if (cvm::debug()) {
cvm::log("Reading grid configuration from collective variables.\n");
}
cv = colvars;
nd = colvars.size();
mult = mult_i;
size_t i;
if (cvm::debug()) {
cvm::log("Allocating a grid for "+cvm::to_str(colvars.size())+
" collective variables, multiplicity = "+cvm::to_str(mult_i)+".\n");
}
for (i = 0; i < cv.size(); i++) {
if (cv[i]->value().type() != colvarvalue::type_scalar) {
cvm::error("Colvar grids can only be automatically "
"constructed for scalar variables. "
"ABF and histogram can not be used; metadynamics "
"can be used with useGrids disabled.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
if (cv[i]->width <= 0.0) {
cvm::error("Tried to initialize a grid on a "
"variable with negative or zero width.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
widths.push_back(cv[i]->width);
hard_lower_boundaries.push_back(cv[i]->hard_lower_boundary);
hard_upper_boundaries.push_back(cv[i]->hard_upper_boundary);
periodic.push_back(cv[i]->periodic_boundaries());
// By default, get reported colvar value (for extended Lagrangian colvars)
actual_value.push_back(false);
// except if a colvar is specified twice in a row
// then the first instance is the actual value
// For histograms of extended-system coordinates
if (i > 0 && cv[i-1] == cv[i]) {
actual_value[i-1] = true;
}
if (margin) {
if (periodic[i]) {
// Shift the grid by half the bin width (values at edges instead of center of bins)
lower_boundaries.push_back(cv[i]->lower_boundary.real_value - 0.5 * widths[i]);
upper_boundaries.push_back(cv[i]->upper_boundary.real_value - 0.5 * widths[i]);
} else {
// Make this grid larger by one bin width
lower_boundaries.push_back(cv[i]->lower_boundary.real_value - 0.5 * widths[i]);
upper_boundaries.push_back(cv[i]->upper_boundary.real_value + 0.5 * widths[i]);
}
} else {
lower_boundaries.push_back(cv[i]->lower_boundary);
upper_boundaries.push_back(cv[i]->upper_boundary);
}
}
this->init_from_boundaries();
return this->setup();
}
int init_from_boundaries(T const &t = T(),
size_t const &mult_i = 1)
{
if (cvm::debug()) {
cvm::log("Configuring grid dimensions from colvars boundaries.\n");
}
// these will have to be updated
nx.clear();
nxc.clear();
nt = 0;
for (size_t i = 0; i < lower_boundaries.size(); i++) {
cvm::real nbins = ( upper_boundaries[i].real_value -
lower_boundaries[i].real_value ) / widths[i];
int nbins_round = (int)(nbins+0.5);
if (std::fabs(nbins - cvm::real(nbins_round)) > 1.0E-10) {
cvm::log("Warning: grid interval("+
cvm::to_str(lower_boundaries[i], cvm::cv_width, cvm::cv_prec)+" - "+
cvm::to_str(upper_boundaries[i], cvm::cv_width, cvm::cv_prec)+
") is not commensurate to its bin width("+
cvm::to_str(widths[i], cvm::cv_width, cvm::cv_prec)+").\n");
upper_boundaries[i].real_value = lower_boundaries[i].real_value +
(nbins_round * widths[i]);
}
if (cvm::debug())
cvm::log("Number of points is "+cvm::to_str((int) nbins_round)+
" for the colvar no. "+cvm::to_str(i+1)+".\n");
nx.push_back(nbins_round);
}
return COLVARS_OK;
}
/// Wrap an index vector around periodic boundary conditions
/// also checks validity of non-periodic indices
inline void wrap(std::vector<int> & ix) const
{
for (size_t i = 0; i < nd; i++) {
if (periodic[i]) {
ix[i] = (ix[i] + nx[i]) % nx[i]; //to ensure non-negative result
} else {
if (ix[i] < 0 || ix[i] >= nx[i]) {
cvm::error("Trying to wrap illegal index vector (non-PBC) for a grid point: "
+ cvm::to_str(ix), BUG_ERROR);
return;
}
}
}
}
/// \brief Report the bin corresponding to the current value of variable i
inline int current_bin_scalar(int const i) const
{
return value_to_bin_scalar(actual_value[i] ? cv[i]->actual_value() : cv[i]->value(), i);
}
/// \brief Report the bin corresponding to the current value of variable i
/// and assign first or last bin if out of boundaries
inline int current_bin_scalar_bound(int const i) const
{
return value_to_bin_scalar_bound(actual_value[i] ? cv[i]->actual_value() : cv[i]->value(), i);
}
/// \brief Report the bin corresponding to the current value of item iv in variable i
inline int current_bin_scalar(int const i, int const iv) const
{
return value_to_bin_scalar(actual_value[i] ?
cv[i]->actual_value().vector1d_value[iv] :
cv[i]->value().vector1d_value[iv], i);
}
/// \brief Use the lower boundary and the width to report which bin
/// the provided value is in
inline int value_to_bin_scalar(colvarvalue const &value, const int i) const
{
return (int) std::floor( (value.real_value - lower_boundaries[i].real_value) / widths[i] );
}
/// \brief Use the lower boundary and the width to report which bin
/// the provided value is in and assign first or last bin if out of boundaries
inline int value_to_bin_scalar_bound(colvarvalue const &value, const int i) const
{
int bin_index = std::floor( (value.real_value - lower_boundaries[i].real_value) / widths[i] );
if (bin_index < 0) bin_index=0;
if (bin_index >=int(nx[i])) bin_index=int(nx[i])-1;
return (int) bin_index;
}
/// \brief Same as the standard version, but uses another grid definition
inline int value_to_bin_scalar(colvarvalue const &value,
colvarvalue const &new_offset,
cvm::real const &new_width) const
{
return (int) std::floor( (value.real_value - new_offset.real_value) / new_width );
}
/// \brief Use the two boundaries and the width to report the
/// central value corresponding to a bin index
inline colvarvalue bin_to_value_scalar(int const &i_bin, int const i) const
{
return lower_boundaries[i].real_value + widths[i] * (0.5 + i_bin);
}
/// \brief Same as the standard version, but uses different parameters
inline colvarvalue bin_to_value_scalar(int const &i_bin,
colvarvalue const &new_offset,
cvm::real const &new_width) const
{
return new_offset.real_value + new_width * (0.5 + i_bin);
}
/// Set the value at the point with index ix
inline void set_value(std::vector<int> const &ix,
T const &t,
size_t const &imult = 0)
{
data[this->address(ix)+imult] = t;
has_data = true;
}
/// \brief Get the change from this to other_grid
/// and store the result in this.
/// this_grid := other_grid - this_grid
/// Grids must have the same dimensions.
void delta_grid(colvar_grid<T> const &other_grid)
{
if (other_grid.multiplicity() != this->multiplicity()) {
cvm::error("Error: trying to subtract two grids with "
"different multiplicity.\n");
return;
}
if (other_grid.data.size() != this->data.size()) {
cvm::error("Error: trying to subtract two grids with "
"different size.\n");
return;
}
for (size_t i = 0; i < data.size(); i++) {
data[i] = other_grid.data[i] - data[i];
}
has_data = true;
}
/// \brief Copy data from another grid of the same type, AND
/// identical definition (boundaries, widths)
/// Added for shared ABF.
void copy_grid(colvar_grid<T> const &other_grid)
{
if (other_grid.multiplicity() != this->multiplicity()) {
cvm::error("Error: trying to copy two grids with "
"different multiplicity.\n");
return;
}
if (other_grid.data.size() != this->data.size()) {
cvm::error("Error: trying to copy two grids with "
"different size.\n");
return;
}
for (size_t i = 0; i < data.size(); i++) {
data[i] = other_grid.data[i];
}
has_data = true;
}
/// \brief Extract the grid data as they are represented in memory.
/// Put the results in "out_data".
void raw_data_out(T* out_data) const
{
for (size_t i = 0; i < data.size(); i++) out_data[i] = data[i];
}
/// \brief Input the data as they are represented in memory.
void raw_data_in(const T* in_data)
{
for (size_t i = 0; i < data.size(); i++) data[i] = in_data[i];
has_data = true;
}
/// \brief Size of the data as they are represented in memory.
size_t raw_data_num() const { return data.size(); }
/// \brief Get the binned value indexed by ix, or the first of them
/// if the multiplicity is larger than 1
inline T const & value(std::vector<int> const &ix,
size_t const &imult = 0) const
{
return data[this->address(ix) + imult];
}
/// \brief Add a constant to all elements (fast loop)
inline void add_constant(T const &t)
{
for (size_t i = 0; i < nt; i++)
data[i] += t;
has_data = true;
}
/// \brief Multiply all elements by a scalar constant (fast loop)
inline void multiply_constant(cvm::real const &a)
{
for (size_t i = 0; i < nt; i++)
data[i] *= a;
}
/// \brief Assign all zero elements a scalar constant (fast loop)
inline void remove_zeros(cvm::real const &a)
{
for (size_t i = 0; i < nt; i++)
if(data[i]==0) data[i] = a;
}
/// \brief Get the bin indices corresponding to the provided values of
/// the colvars
inline std::vector<int> const get_colvars_index(std::vector<colvarvalue> const &values) const
{
std::vector<int> index = new_index();
for (size_t i = 0; i < nd; i++) {
index[i] = value_to_bin_scalar(values[i], i);
}
return index;
}
/// \brief Get the bin indices corresponding to the current values
/// of the colvars
inline std::vector<int> const get_colvars_index() const
{
std::vector<int> index = new_index();
for (size_t i = 0; i < nd; i++) {
index[i] = current_bin_scalar(i);
}
return index;
}
/// \brief Get the bin indices corresponding to the provided values of
/// the colvars and assign first or last bin if out of boundaries
inline std::vector<int> const get_colvars_index_bound() const
{
std::vector<int> index = new_index();
for (size_t i = 0; i < nd; i++) {
index[i] = current_bin_scalar_bound(i);
}
return index;
}
/// \brief Get the minimal distance (in number of bins) from the
/// boundaries; a negative number is returned if the given point is
/// off-grid
inline cvm::real bin_distance_from_boundaries(std::vector<colvarvalue> const &values,
bool skip_hard_boundaries = false)
{
cvm::real minimum = 1.0E+16;
for (size_t i = 0; i < nd; i++) {
if (periodic[i]) continue;
cvm::real dl = std::sqrt(cv[i]->dist2(values[i], lower_boundaries[i])) / widths[i];
cvm::real du = std::sqrt(cv[i]->dist2(values[i], upper_boundaries[i])) / widths[i];
if (values[i].real_value < lower_boundaries[i])
dl *= -1.0;
if (values[i].real_value > upper_boundaries[i])
du *= -1.0;
if ( ((!skip_hard_boundaries) || (!hard_lower_boundaries[i])) && (dl < minimum))
minimum = dl;
if ( ((!skip_hard_boundaries) || (!hard_upper_boundaries[i])) && (du < minimum))
minimum = du;
}
return minimum;
}
/// \brief Add data from another grid of the same type
///
/// Note: this function maps other_grid inside this one regardless
/// of whether it fits or not.
void map_grid(colvar_grid<T> const &other_grid)
{
if (other_grid.multiplicity() != this->multiplicity()) {
cvm::error("Error: trying to merge two grids with values of "
"different multiplicity.\n");
return;
}
std::vector<colvarvalue> const &gb = this->lower_boundaries;
std::vector<cvm::real> const &gw = this->widths;
std::vector<colvarvalue> const &ogb = other_grid.lower_boundaries;
std::vector<cvm::real> const &ogw = other_grid.widths;
std::vector<int> ix = this->new_index();
std::vector<int> oix = other_grid.new_index();
if (cvm::debug())
cvm::log("Remapping grid...\n");
for ( ; this->index_ok(ix); this->incr(ix)) {
for (size_t i = 0; i < nd; i++) {
oix[i] =
value_to_bin_scalar(bin_to_value_scalar(ix[i], gb[i], gw[i]),
ogb[i],
ogw[i]);
}
if (! other_grid.index_ok(oix)) {
continue;
}
for (size_t im = 0; im < mult; im++) {
this->set_value(ix, other_grid.value(oix, im), im);
}
}
has_data = true;
if (cvm::debug())
cvm::log("Remapping done.\n");
}
/// \brief Add data from another grid of the same type, AND
/// identical definition (boundaries, widths)
void add_grid(colvar_grid<T> const &other_grid,
cvm::real scale_factor = 1.0)
{
if (other_grid.multiplicity() != this->multiplicity()) {
cvm::error("Error: trying to sum togetehr two grids with values of "
"different multiplicity.\n");
return;
}
if (scale_factor != 1.0)
for (size_t i = 0; i < data.size(); i++) {
data[i] += scale_factor * other_grid.data[i];
}
else
// skip multiplication if possible
for (size_t i = 0; i < data.size(); i++) {
data[i] += other_grid.data[i];
}
has_data = true;
}
/// \brief Return the value suitable for output purposes (so that it
/// may be rescaled or manipulated without changing it permanently)
virtual inline T value_output(std::vector<int> const &ix,
size_t const &imult = 0)
{
return value(ix, imult);
}
/// \brief Get the value from a formatted output and transform it
/// into the internal representation (the two may be different,
/// e.g. when using colvar_grid_count)
virtual inline void value_input(std::vector<int> const &ix,
T const &t,
size_t const &imult = 0,
bool add = false)
{
if ( add )
data[address(ix) + imult] += t;
else
data[address(ix) + imult] = t;
has_data = true;
}
// /// Get the pointer to the binned value indexed by ix
// inline T const *value_p (std::vector<int> const &ix)
// {
// return &(data[address (ix)]);
// }
/// \brief Get the index corresponding to the "first" bin, to be
/// used as the initial value for an index in looping
inline std::vector<int> const new_index() const
{
return std::vector<int> (nd, 0);
}
/// \brief Check that the index is within range in each of the
/// dimensions
inline bool index_ok(std::vector<int> const &ix) const
{
for (size_t i = 0; i < nd; i++) {
if ( (ix[i] < 0) || (ix[i] >= int(nx[i])) )
return false;
}
return true;
}
/// \brief Increment the index, in a way that will make it loop over
/// the whole nd-dimensional array
inline void incr(std::vector<int> &ix) const
{
for (int i = ix.size()-1; i >= 0; i--) {
ix[i]++;
if (ix[i] >= nx[i]) {
if (i > 0) {
ix[i] = 0;
continue;
} else {
// this is the last iteration, a non-valid index is being
// set for the outer index, which will be caught by
// index_ok()
ix[0] = nx[0];
return;
}
} else {
return;
}
}
}
/// \brief Write the grid parameters (number of colvars, boundaries, width and number of points)
std::ostream & write_params(std::ostream &os)
{
size_t i;
os << "grid_parameters {\n n_colvars " << nd << "\n";
os << " lower_boundaries ";
for (i = 0; i < nd; i++)
os << " " << lower_boundaries[i];
os << "\n";
os << " upper_boundaries ";
for (i = 0; i < nd; i++)
os << " " << upper_boundaries[i];
os << "\n";
os << " widths ";
for (i = 0; i < nd; i++)
os << " " << widths[i];
os << "\n";
os << " sizes ";
for (i = 0; i < nd; i++)
os << " " << nx[i];
os << "\n";
os << "}\n";
return os;
}
/// Read a grid definition from a config string
int parse_params(std::string const &conf,
colvarparse::Parse_Mode const parse_mode = colvarparse::parse_normal)
{
if (cvm::debug()) cvm::log("Reading grid configuration from string.\n");
std::vector<int> old_nx = nx;
std::vector<colvarvalue> old_lb = lower_boundaries;
{
size_t nd_in = 0;
// this is only used in state files
colvarparse::get_keyval(conf, "n_colvars", nd_in, nd, colvarparse::parse_silent);
if (nd_in != nd) {
cvm::error("Error: trying to read data for a grid "
"that contains a different number of colvars ("+
cvm::to_str(nd_in)+") than the grid defined "
"in the configuration file("+cvm::to_str(nd)+
").\n");
return COLVARS_ERROR;
}
}
// underscore keywords are used in state file
colvarparse::get_keyval(conf, "lower_boundaries",
lower_boundaries, lower_boundaries, colvarparse::parse_silent);
colvarparse::get_keyval(conf, "upper_boundaries",
upper_boundaries, upper_boundaries, colvarparse::parse_silent);
// camel case keywords are used in config file
colvarparse::get_keyval(conf, "lowerBoundaries",
lower_boundaries, lower_boundaries, parse_mode);
colvarparse::get_keyval(conf, "upperBoundaries",
upper_boundaries, upper_boundaries, parse_mode);
colvarparse::get_keyval(conf, "widths", widths, widths, parse_mode);
// only used in state file
colvarparse::get_keyval(conf, "sizes", nx, nx, colvarparse::parse_silent);
if (nd < lower_boundaries.size()) nd = lower_boundaries.size();
if (! actual_value.size()) actual_value.assign(nd, false);
if (! periodic.size()) periodic.assign(nd, false);
if (! widths.size()) widths.assign(nd, 1.0);
bool new_params = false;
if (old_nx.size()) {
for (size_t i = 0; i < nd; i++) {
if ( (old_nx[i] != nx[i]) ||
(std::sqrt(cv[i]->dist2(old_lb[i],
lower_boundaries[i])) > 1.0E-10) ) {
new_params = true;
}
}
} else {
new_params = true;
}
// reallocate the array in case the grid params have just changed
if (new_params) {
init_from_boundaries();
- // data.resize(0); // no longer needed: setup calls clear()
+ // data.clear(); // no longer needed: setup calls clear()
return this->setup(nx, T(), mult);
}
return COLVARS_OK;
}
/// \brief Check that the grid information inside (boundaries,
/// widths, ...) is consistent with the current setting of the
/// colvars
void check_consistency()
{
for (size_t i = 0; i < nd; i++) {
if ( (std::sqrt(cv[i]->dist2(cv[i]->lower_boundary,
lower_boundaries[i])) > 1.0E-10) ||
(std::sqrt(cv[i]->dist2(cv[i]->upper_boundary,
upper_boundaries[i])) > 1.0E-10) ||
(std::sqrt(cv[i]->dist2(cv[i]->width,
widths[i])) > 1.0E-10) ) {
cvm::error("Error: restart information for a grid is "
"inconsistent with that of its colvars.\n");
return;
}
}
}
/// \brief Check that the grid information inside (boundaries,
/// widths, ...) is consistent with that of another grid
void check_consistency(colvar_grid<T> const &other_grid)
{
for (size_t i = 0; i < nd; i++) {
// we skip dist2(), because periodicities and the like should
// matter: boundaries should be EXACTLY the same (otherwise,
// map_grid() should be used)
if ( (std::fabs(other_grid.lower_boundaries[i] -
lower_boundaries[i]) > 1.0E-10) ||
(std::fabs(other_grid.upper_boundaries[i] -
upper_boundaries[i]) > 1.0E-10) ||
(std::fabs(other_grid.widths[i] -
widths[i]) > 1.0E-10) ||
(data.size() != other_grid.data.size()) ) {
cvm::error("Error: inconsistency between "
"two grids that are supposed to be equal, "
"aside from the data stored.\n");
return;
}
}
}
/// \brief Read grid entry in restart file
std::istream & read_restart(std::istream &is)
{
size_t const start_pos = is.tellg();
std::string key, conf;
if ((is >> key) && (key == std::string("grid_parameters"))) {
is.seekg(start_pos, std::ios::beg);
is >> colvarparse::read_block("grid_parameters", conf);
parse_params(conf, colvarparse::parse_silent);
} else {
cvm::log("Grid parameters are missing in the restart file, using those from the configuration.\n");
is.seekg(start_pos, std::ios::beg);
}
read_raw(is);
return is;
}
/// \brief Write grid entry in restart file
std::ostream & write_restart(std::ostream &os)
{
write_params(os);
write_raw(os);
return os;
}
/// \brief Write the grid data without labels, as they are
/// represented in memory
/// \param buf_size Number of values per line
std::ostream & write_raw(std::ostream &os,
size_t const buf_size = 3)
{
std::streamsize const w = os.width();
std::streamsize const p = os.precision();
std::vector<int> ix = new_index();
size_t count = 0;
for ( ; index_ok(ix); incr(ix)) {
for (size_t imult = 0; imult < mult; imult++) {
os << " "
<< std::setw(w) << std::setprecision(p)
<< value_output(ix, imult);
if (((++count) % buf_size) == 0)
os << "\n";
}
}
// write a final newline only if buffer is not empty
if ((count % buf_size) != 0)
os << "\n";
return os;
}
/// \brief Read data written by colvar_grid::write_raw()
std::istream & read_raw(std::istream &is)
{
size_t const start_pos = is.tellg();
for (std::vector<int> ix = new_index(); index_ok(ix); incr(ix)) {
for (size_t imult = 0; imult < mult; imult++) {
T new_value;
if (is >> new_value) {
value_input(ix, new_value, imult);
} else {
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
cvm::error("Error: failed to read all of the grid points from file. Possible explanations: grid parameters in the configuration (lowerBoundary, upperBoundary, width) are different from those in the file, or the file is corrupt/incomplete.\n");
return is;
}
}
}
has_data = true;
return is;
}
/// \brief Write the grid in a format which is both human readable
/// and suitable for visualization e.g. with gnuplot
void write_multicol(std::ostream &os)
{
std::streamsize const w = os.width();
std::streamsize const p = os.precision();
// Data in the header: nColvars, then for each
// xiMin, dXi, nPoints, periodic
os << std::setw(2) << "# " << nd << "\n";
for (size_t i = 0; i < nd; i++) {
os << "# "
<< std::setw(10) << lower_boundaries[i]
<< std::setw(10) << widths[i]
<< std::setw(10) << nx[i] << " "
<< periodic[i] << "\n";
}
for (std::vector<int> ix = new_index(); index_ok(ix); incr(ix) ) {
if (ix.back() == 0) {
// if the last index is 0, add a new line to mark the new record
os << "\n";
}
for (size_t i = 0; i < nd; i++) {
os << " "
<< std::setw(w) << std::setprecision(p)
<< bin_to_value_scalar(ix[i], i);
}
os << " ";
for (size_t imult = 0; imult < mult; imult++) {
os << " "
<< std::setw(w) << std::setprecision(p)
<< value_output(ix, imult);
}
os << "\n";
}
}
/// \brief Read a grid written by colvar_grid::write_multicol()
/// Adding data if add is true, replacing if false
std::istream & read_multicol(std::istream &is, bool add = false)
{
// Data in the header: nColvars, then for each
// xiMin, dXi, nPoints, periodic
std::string hash;
cvm::real lower, width, x;
size_t n, periodic;
bool remap;
std::vector<T> new_value;
std::vector<int> nx_read;
std::vector<int> bin;
if ( cv.size() != nd ) {
cvm::error("Cannot read grid file: missing reference to colvars.");
return is;
}
if ( !(is >> hash) || (hash != "#") ) {
cvm::error("Error reading grid at position "+
cvm::to_str(is.tellg())+" in stream(read \"" + hash + "\")\n");
return is;
}
is >> n;
if ( n != nd ) {
cvm::error("Error reading grid: wrong number of collective variables.\n");
return is;
}
nx_read.resize(n);
bin.resize(n);
new_value.resize(mult);
if (this->has_parent_data && add) {
new_data.resize(data.size());
}
remap = false;
for (size_t i = 0; i < nd; i++ ) {
if ( !(is >> hash) || (hash != "#") ) {
cvm::error("Error reading grid at position "+
cvm::to_str(is.tellg())+" in stream(read \"" + hash + "\")\n");
return is;
}
is >> lower >> width >> nx_read[i] >> periodic;
if ( (std::fabs(lower - lower_boundaries[i].real_value) > 1.0e-10) ||
(std::fabs(width - widths[i] ) > 1.0e-10) ||
(nx_read[i] != nx[i]) ) {
cvm::log("Warning: reading from different grid definition (colvar "
+ cvm::to_str(i+1) + "); remapping data on new grid.\n");
remap = true;
}
}
if ( remap ) {
// re-grid data
while (is.good()) {
bool end_of_file = false;
for (size_t i = 0; i < nd; i++ ) {
if ( !(is >> x) ) end_of_file = true;
bin[i] = value_to_bin_scalar(x, i);
}
if (end_of_file) break;
for (size_t imult = 0; imult < mult; imult++) {
is >> new_value[imult];
}
if ( index_ok(bin) ) {
for (size_t imult = 0; imult < mult; imult++) {
value_input(bin, new_value[imult], imult, add);
}
}
}
} else {
// do not re-grid the data but assume the same grid is used
for (std::vector<int> ix = new_index(); index_ok(ix); incr(ix) ) {
for (size_t i = 0; i < nd; i++ ) {
is >> x;
}
for (size_t imult = 0; imult < mult; imult++) {
is >> new_value[imult];
value_input(ix, new_value[imult], imult, add);
}
}
}
has_data = true;
return is;
}
/// \brief Write the grid data without labels, as they are
/// represented in memory
std::ostream & write_opendx(std::ostream &os)
{
// write the header
os << "object 1 class gridpositions counts";
size_t icv;
for (icv = 0; icv < number_of_colvars(); icv++) {
os << " " << number_of_points(icv);
}
os << "\n";
os << "origin";
for (icv = 0; icv < number_of_colvars(); icv++) {
os << " " << (lower_boundaries[icv].real_value + 0.5 * widths[icv]);
}
os << "\n";
for (icv = 0; icv < number_of_colvars(); icv++) {
os << "delta";
for (size_t icv2 = 0; icv2 < number_of_colvars(); icv2++) {
if (icv == icv2) os << " " << widths[icv];
else os << " " << 0.0;
}
os << "\n";
}
os << "object 2 class gridconnections counts";
for (icv = 0; icv < number_of_colvars(); icv++) {
os << " " << number_of_points(icv);
}
os << "\n";
os << "object 3 class array type double rank 0 items "
<< number_of_points() << " data follows\n";
write_raw(os);
os << "object \"collective variables scalar field\" class field\n";
return os;
}
};
/// \brief Colvar_grid derived class to hold counters in discrete
/// n-dim colvar space
class colvar_grid_count : public colvar_grid<size_t>
{
public:
/// Default constructor
colvar_grid_count();
/// Destructor
virtual inline ~colvar_grid_count()
{}
/// Constructor
colvar_grid_count(std::vector<int> const &nx_i,
size_t const &def_count = 0);
/// Constructor from a vector of colvars
colvar_grid_count(std::vector<colvar *> &colvars,
size_t const &def_count = 0);
/// Increment the counter at given position
inline void incr_count(std::vector<int> const &ix)
{
++(data[this->address(ix)]);
}
/// \brief Get the binned count indexed by ix from the newly read data
inline size_t const & new_count(std::vector<int> const &ix,
size_t const &imult = 0)
{
return new_data[address(ix) + imult];
}
/// \brief Get the value from a formatted output and transform it
/// into the internal representation (it may have been rescaled or
/// manipulated)
virtual inline void value_input(std::vector<int> const &ix,
size_t const &t,
size_t const &imult = 0,
bool add = false)
{
if (add) {
data[address(ix)] += t;
if (this->has_parent_data) {
// save newly read data for inputting parent grid
new_data[address(ix)] = t;
}
} else {
data[address(ix)] = t;
}
has_data = true;
}
/// \brief Return the log-gradient from finite differences
/// on the *same* grid for dimension n
inline cvm::real log_gradient_finite_diff(const std::vector<int> &ix0,
int n = 0)
{
int A0, A1, A2;
std::vector<int> ix = ix0;
if (periodic[n]) {
ix[n]--; wrap(ix);
A0 = data[address(ix)];
ix = ix0;
ix[n]++; wrap(ix);
A1 = data[address(ix)];
if (A0 * A1 == 0) {
return 0.; // can't handle empty bins
} else {
return (std::log((cvm::real)A1) - std::log((cvm::real)A0))
/ (widths[n] * 2.);
}
} else if (ix[n] > 0 && ix[n] < nx[n]-1) { // not an edge
ix[n]--;
A0 = data[address(ix)];
ix = ix0;
ix[n]++;
A1 = data[address(ix)];
if (A0 * A1 == 0) {
return 0.; // can't handle empty bins
} else {
return (std::log((cvm::real)A1) - std::log((cvm::real)A0))
/ (widths[n] * 2.);
}
} else {
// edge: use 2nd order derivative
int increment = (ix[n] == 0 ? 1 : -1);
// move right from left edge, or the other way around
A0 = data[address(ix)];
ix[n] += increment; A1 = data[address(ix)];
ix[n] += increment; A2 = data[address(ix)];
if (A0 * A1 * A2 == 0) {
return 0.; // can't handle empty bins
} else {
return (-1.5 * std::log((cvm::real)A0) + 2. * std::log((cvm::real)A1)
- 0.5 * std::log((cvm::real)A2)) * increment / widths[n];
}
}
}
};
/// Class for accumulating a scalar function on a grid
class colvar_grid_scalar : public colvar_grid<cvm::real>
{
public:
/// \brief Provide the associated sample count by which each binned value
/// should be divided
colvar_grid_count *samples;
/// Default constructor
colvar_grid_scalar();
/// Copy constructor (needed because of the grad pointer)
colvar_grid_scalar(colvar_grid_scalar const &g);
/// Destructor
~colvar_grid_scalar();
/// Constructor from specific sizes arrays
colvar_grid_scalar(std::vector<int> const &nx_i);
/// Constructor from a vector of colvars
colvar_grid_scalar(std::vector<colvar *> &colvars,
bool margin = 0);
/// Accumulate the value
inline void acc_value(std::vector<int> const &ix,
cvm::real const &new_value,
size_t const &imult = 0)
{
// only legal value of imult here is 0
data[address(ix)] += new_value;
if (samples)
samples->incr_count(ix);
has_data = true;
}
/// Return the gradient of the scalar field from finite differences
inline const cvm::real * gradient_finite_diff( const std::vector<int> &ix0 )
{
cvm::real A0, A1;
std::vector<int> ix;
if (nd != 2) {
cvm::error("Finite differences available in dimension 2 only.");
return grad;
}
for (unsigned int n = 0; n < nd; n++) {
ix = ix0;
A0 = data[address(ix)];
ix[n]++; wrap(ix);
A1 = data[address(ix)];
ix[1-n]++; wrap(ix);
A1 += data[address(ix)];
ix[n]--; wrap(ix);
A0 += data[address(ix)];
grad[n] = 0.5 * (A1 - A0) / widths[n];
}
return grad;
}
/// \brief Return the value of the function at ix divided by its
/// number of samples (if the count grid is defined)
virtual cvm::real value_output(std::vector<int> const &ix,
size_t const &imult = 0)
{
if (imult > 0) {
cvm::error("Error: trying to access a component "
"larger than 1 in a scalar data grid.\n");
return 0.;
}
if (samples) {
return (samples->value(ix) > 0) ?
(data[address(ix)] / cvm::real(samples->value(ix))) :
0.0;
} else {
return data[address(ix)];
}
}
/// \brief Get the value from a formatted output and transform it
/// into the internal representation (it may have been rescaled or
/// manipulated)
virtual void value_input(std::vector<int> const &ix,
cvm::real const &new_value,
size_t const &imult = 0,
bool add = false)
{
if (imult > 0) {
cvm::error("Error: trying to access a component "
"larger than 1 in a scalar data grid.\n");
return;
}
if (add) {
if (samples)
data[address(ix)] += new_value * samples->new_count(ix);
else
data[address(ix)] += new_value;
} else {
if (samples)
data[address(ix)] = new_value * samples->value(ix);
else
data[address(ix)] = new_value;
}
has_data = true;
}
/// \brief Return the highest value
cvm::real maximum_value() const;
/// \brief Return the lowest value
cvm::real minimum_value() const;
/// \brief Return the lowest positive value
cvm::real minimum_pos_value() const;
/// \brief Calculates the integral of the map (uses widths if they are defined)
cvm::real integral() const;
/// \brief Assuming that the map is a normalized probability density,
/// calculates the entropy (uses widths if they are defined)
cvm::real entropy() const;
private:
// gradient
cvm::real * grad;
};
/// Class for accumulating the gradient of a scalar function on a grid
class colvar_grid_gradient : public colvar_grid<cvm::real>
{
public:
/// \brief Provide the sample count by which each binned value
/// should be divided
colvar_grid_count *samples;
/// Default constructor
colvar_grid_gradient();
/// Destructor
virtual inline ~colvar_grid_gradient()
{}
/// Constructor from specific sizes arrays
colvar_grid_gradient(std::vector<int> const &nx_i);
/// Constructor from a vector of colvars
colvar_grid_gradient(std::vector<colvar *> &colvars);
/// \brief Accumulate the gradient
inline void acc_grad(std::vector<int> const &ix, cvm::real const *grads) {
for (size_t imult = 0; imult < mult; imult++) {
data[address(ix) + imult] += grads[imult];
}
if (samples)
samples->incr_count(ix);
}
/// \brief Accumulate the gradient based on the force (i.e. sums the
/// opposite of the force)
inline void acc_force(std::vector<int> const &ix, cvm::real const *forces) {
for (size_t imult = 0; imult < mult; imult++) {
data[address(ix) + imult] -= forces[imult];
}
if (samples)
samples->incr_count(ix);
}
/// \brief Return the value of the function at ix divided by its
/// number of samples (if the count grid is defined)
virtual inline cvm::real value_output(std::vector<int> const &ix,
size_t const &imult = 0)
{
if (samples)
return (samples->value(ix) > 0) ?
(data[address(ix) + imult] / cvm::real(samples->value(ix))) :
0.0;
else
return data[address(ix) + imult];
}
/// \brief Get the value from a formatted output and transform it
/// into the internal representation (it may have been rescaled or
/// manipulated)
virtual inline void value_input(std::vector<int> const &ix,
cvm::real const &new_value,
size_t const &imult = 0,
bool add = false)
{
if (add) {
if (samples)
data[address(ix) + imult] += new_value * samples->new_count(ix);
else
data[address(ix) + imult] += new_value;
} else {
if (samples)
data[address(ix) + imult] = new_value * samples->value(ix);
else
data[address(ix) + imult] = new_value;
}
has_data = true;
}
/// Compute and return average value for a 1D gradient grid
inline cvm::real average()
{
size_t n = 0;
if (nd != 1 || nx[0] == 0) {
return 0.0;
}
cvm::real sum = 0.0;
std::vector<int> ix = new_index();
if (samples) {
for ( ; index_ok(ix); incr(ix)) {
if ( (n = samples->value(ix)) )
sum += value(ix) / n;
}
} else {
for ( ; index_ok(ix); incr(ix)) {
sum += value(ix);
}
}
return (sum / cvm::real(nx[0]));
}
/// \brief If the grid is 1-dimensional, integrate it and write the
/// integral to a file
void write_1D_integral(std::ostream &os);
};
#endif
diff --git a/lib/colvars/colvarmodule.cpp b/lib/colvars/colvarmodule.cpp
index 10cd3c0e4..780dc28af 100644
--- a/lib/colvars/colvarmodule.cpp
+++ b/lib/colvars/colvarmodule.cpp
@@ -1,1718 +1,1760 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <sstream>
#include <string.h>
#include "colvarmodule.h"
#include "colvarparse.h"
#include "colvarproxy.h"
#include "colvar.h"
#include "colvarbias.h"
#include "colvarbias_abf.h"
#include "colvarbias_alb.h"
#include "colvarbias_histogram.h"
#include "colvarbias_meta.h"
#include "colvarbias_restraint.h"
#include "colvarscript.h"
+#include "colvaratoms.h"
colvarmodule::colvarmodule(colvarproxy *proxy_in)
{
+ depth_s = 0;
+ cv_traj_os = NULL;
+
// pointer to the proxy object
if (proxy == NULL) {
proxy = proxy_in;
parse = new colvarparse();
} else {
// TODO relax this error to handle multiple molecules in VMD
// once the module is not static anymore
cvm::error("Error: trying to allocate the collective "
- "variable module twice.\n");
+ "variable module twice.\n", BUG_ERROR);
return;
}
- depth_s = 0;
-
cvm::log(cvm::line_marker);
cvm::log("Initializing the collective variables module, version "+
cvm::to_str(COLVARS_VERSION)+".\n");
cvm::log("Please cite Fiorin et al, Mol Phys 2013:\n "
"http://dx.doi.org/10.1080/00268976.2013.813594\n"
"in any publication based on this calculation.\n");
if (proxy->smp_enabled() == COLVARS_OK) {
cvm::log("SMP parallelism is available.\n");
}
// set initial default values
// "it_restart" will be set by the input state file, if any;
// "it" should be updated by the proxy
colvarmodule::it = colvarmodule::it_restart = 0;
colvarmodule::it_restart_from_state_file = true;
colvarmodule::use_scripted_forces = false;
colvarmodule::b_analysis = false;
colvarmodule::debug_gradients_step_size = 1.0e-07;
colvarmodule::rotation::monitor_crossings = false;
colvarmodule::rotation::crossing_threshold = 1.0e-02;
colvarmodule::cv_traj_freq = 100;
colvarmodule::restart_out_freq = proxy->restart_frequency();
// by default overwrite the existing trajectory file
colvarmodule::cv_traj_append = false;
}
colvarmodule * colvarmodule::main()
{
return proxy->colvars;
}
std::vector<colvar *> *colvarmodule::variables()
{
return &colvars;
}
std::vector<colvar *> *colvarmodule::variables_active()
{
return &colvars_active;
}
std::vector<colvar *> *colvarmodule::variables_active_smp()
{
return &colvars_smp;
}
std::vector<int> *colvarmodule::variables_active_smp_items()
{
return &colvars_smp_items;
}
std::vector<colvarbias *> *colvarmodule::biases_active()
{
return &(biases_active_);
}
size_t colvarmodule::size() const
{
return colvars.size() + biases.size();
}
int colvarmodule::read_config_file(char const *config_filename)
{
cvm::log(cvm::line_marker);
cvm::log("Reading new configuration from file \""+
std::string(config_filename)+"\":\n");
// open the configfile
config_s.open(config_filename);
if (!config_s.is_open()) {
cvm::error("Error: in opening configuration file \""+
std::string(config_filename)+"\".\n",
FILE_ERROR);
return COLVARS_ERROR;
}
// read the config file into a string
std::string conf = "";
std::string line;
while (colvarparse::getline_nocomments(config_s, line)) {
// Delete lines that contain only white space after removing comments
if (line.find_first_not_of(colvarparse::white_space) != std::string::npos)
conf.append(line+"\n");
}
config_s.close();
return parse_config(conf);
}
int colvarmodule::read_config_string(std::string const &config_str)
{
cvm::log(cvm::line_marker);
cvm::log("Reading new configuration:\n");
std::istringstream config_s(config_str);
// strip the comments away
std::string conf = "";
std::string line;
while (colvarparse::getline_nocomments(config_s, line)) {
// Delete lines that contain only white space after removing comments
if (line.find_first_not_of(colvarparse::white_space) != std::string::npos)
conf.append(line+"\n");
}
return parse_config(conf);
}
std::istream & colvarmodule::getline(std::istream &is, std::string &line)
{
std::string l;
if (std::getline(is, l)) {
size_t const sz = l.size();
if (sz > 0) {
if (l[sz-1] == '\r' ) {
line = l.substr(0, sz-1);
} else {
line = l;
}
} else {
line.clear();
}
}
return is;
}
int colvarmodule::parse_config(std::string &conf)
{
extra_conf.clear();
// parse global options
if (catch_input_errors(parse_global_params(conf))) {
return get_error();
}
// parse the options for collective variables
if (catch_input_errors(parse_colvars(conf))) {
return get_error();
}
// parse the options for biases
if (catch_input_errors(parse_biases(conf))) {
return get_error();
}
// done parsing known keywords, check that all keywords found were valid ones
if (catch_input_errors(parse->check_keywords(conf, "colvarmodule"))) {
return get_error();
}
if (extra_conf.size()) {
catch_input_errors(parse_global_params(extra_conf));
catch_input_errors(parse_colvars(extra_conf));
catch_input_errors(parse_biases(extra_conf));
parse->check_keywords(extra_conf, "colvarmodule");
extra_conf.clear();
if (get_error() != COLVARS_OK) return get_error();
}
cvm::log(cvm::line_marker);
cvm::log("Collective variables module (re)initialized.\n");
cvm::log(cvm::line_marker);
// update any necessary proxy data
proxy->setup();
- if (cv_traj_os.is_open()) {
+ if (cv_traj_os != NULL) {
// configuration might have changed, better redo the labels
- write_traj_label(cv_traj_os);
+ write_traj_label(*cv_traj_os);
}
return get_error();
}
int colvarmodule::append_new_config(std::string const &new_conf)
{
extra_conf += new_conf;
return COLVARS_OK;
}
int colvarmodule::parse_global_params(std::string const &conf)
{
colvarmodule *cvm = cvm::main();
std::string index_file_name;
if (parse->get_keyval(conf, "indexFile", index_file_name)) {
cvm->read_index_file(index_file_name.c_str());
}
if (parse->get_keyval(conf, "smp", proxy->b_smp_active, proxy->b_smp_active)) {
if (proxy->b_smp_active == false) {
cvm::log("SMP parallelism has been disabled.\n");
}
}
parse->get_keyval(conf, "analysis", b_analysis, b_analysis);
parse->get_keyval(conf, "debugGradientsStepSize", debug_gradients_step_size,
debug_gradients_step_size,
colvarparse::parse_silent);
parse->get_keyval(conf, "monitorEigenvalueCrossing",
colvarmodule::rotation::monitor_crossings,
colvarmodule::rotation::monitor_crossings,
colvarparse::parse_silent);
parse->get_keyval(conf, "eigenvalueCrossingThreshold",
colvarmodule::rotation::crossing_threshold,
colvarmodule::rotation::crossing_threshold,
colvarparse::parse_silent);
parse->get_keyval(conf, "colvarsTrajFrequency", cv_traj_freq, cv_traj_freq);
parse->get_keyval(conf, "colvarsRestartFrequency",
restart_out_freq, restart_out_freq);
// if this is true when initializing, it means
// we are continuing after a reset(): default to true
parse->get_keyval(conf, "colvarsTrajAppend", cv_traj_append, cv_traj_append);
parse->get_keyval(conf, "scriptedColvarForces", use_scripted_forces, false);
parse->get_keyval(conf, "scriptingAfterBiases", scripting_after_biases, true);
if (use_scripted_forces && !proxy->force_script_defined) {
cvm::error("User script for scripted colvar forces not found.", INPUT_ERROR);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::parse_colvars(std::string const &conf)
{
if (cvm::debug())
cvm::log("Initializing the collective variables.\n");
std::string colvar_conf = "";
size_t pos = 0;
- while (parse->key_lookup(conf, "colvar", colvar_conf, pos)) {
+ while (parse->key_lookup(conf, "colvar", &colvar_conf, &pos)) {
if (colvar_conf.size()) {
cvm::log(cvm::line_marker);
cvm::increase_depth();
colvars.push_back(new colvar());
if (((colvars.back())->init(colvar_conf) != COLVARS_OK) ||
((colvars.back())->check_keywords(colvar_conf, "colvar") != COLVARS_OK)) {
cvm::log("Error while constructing colvar number " +
cvm::to_str(colvars.size()) + " : deleting.");
delete colvars.back(); // the colvar destructor updates the colvars array
return COLVARS_ERROR;
}
cvm::decrease_depth();
} else {
cvm::error("Error: \"colvar\" keyword found without any configuration.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
cvm::decrease_depth();
colvar_conf = "";
}
if (!colvars.size()) {
cvm::log("Warning: no collective variables defined.\n");
}
if (colvars.size())
cvm::log(cvm::line_marker);
cvm::log("Collective variables initialized, "+
cvm::to_str(colvars.size())+
" in total.\n");
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
bool colvarmodule::check_new_bias(std::string &conf, char const *key)
{
if (cvm::get_error() ||
(biases.back()->check_keywords(conf, key) != COLVARS_OK)) {
cvm::log("Error while constructing bias number " +
cvm::to_str(biases.size()) + " : deleting.\n");
delete biases.back(); // the bias destructor updates the biases array
return true;
}
return false;
}
template <class bias_type>
int colvarmodule::parse_biases_type(std::string const &conf,
char const *keyword)
{
std::string bias_conf = "";
size_t conf_saved_pos = 0;
- while (parse->key_lookup(conf, keyword, bias_conf, conf_saved_pos)) {
+ while (parse->key_lookup(conf, keyword, &bias_conf, &conf_saved_pos)) {
if (bias_conf.size()) {
cvm::log(cvm::line_marker);
cvm::increase_depth();
biases.push_back(new bias_type(keyword));
biases.back()->init(bias_conf);
if (cvm::check_new_bias(bias_conf, keyword) != COLVARS_OK) {
return COLVARS_ERROR;
}
cvm::decrease_depth();
} else {
cvm::error("Error: keyword \""+std::string(keyword)+"\" found without configuration.\n",
INPUT_ERROR);
return COLVARS_ERROR;
}
bias_conf = "";
}
return COLVARS_OK;
}
int colvarmodule::parse_biases(std::string const &conf)
{
if (cvm::debug())
cvm::log("Initializing the collective variables biases.\n");
/// initialize ABF instances
parse_biases_type<colvarbias_abf>(conf, "abf");
/// initialize adaptive linear biases
parse_biases_type<colvarbias_alb>(conf, "ALB");
/// initialize harmonic restraints
parse_biases_type<colvarbias_restraint_harmonic>(conf, "harmonic");
/// initialize harmonic walls restraints
parse_biases_type<colvarbias_restraint_harmonic_walls>(conf, "harmonicWalls");
/// initialize histograms
parse_biases_type<colvarbias_histogram>(conf, "histogram");
/// initialize histogram restraints
parse_biases_type<colvarbias_restraint_histogram>(conf, "histogramRestraint");
/// initialize linear restraints
parse_biases_type<colvarbias_restraint_linear>(conf, "linear");
/// initialize metadynamics instances
parse_biases_type<colvarbias_meta>(conf, "metadynamics");
if (use_scripted_forces) {
cvm::log(cvm::line_marker);
cvm::increase_depth();
cvm::log("User forces script will be run at each bias update.");
cvm::decrease_depth();
}
size_t i;
- for (i = 0; i < biases.size(); i++) {
- biases[i]->enable(colvardeps::f_cvb_active);
- if (cvm::debug())
- biases[i]->print_state();
- }
-
size_t n_hist_dep_biases = 0;
std::vector<std::string> hist_dep_biases_names;
for (i = 0; i < biases.size(); i++) {
if (biases[i]->is_enabled(colvardeps::f_cvb_apply_force) &&
biases[i]->is_enabled(colvardeps::f_cvb_history_dependent)) {
n_hist_dep_biases++;
hist_dep_biases_names.push_back(biases[i]->name);
}
}
if (n_hist_dep_biases > 1) {
cvm::log("WARNING: there are "+cvm::to_str(n_hist_dep_biases)+
" history-dependent biases with non-zero force parameters:\n"+
cvm::to_str(hist_dep_biases_names)+"\n"+
"Please make sure that their forces do not counteract each other.\n");
}
if (biases.size() || use_scripted_forces) {
cvm::log(cvm::line_marker);
cvm::log("Collective variables biases initialized, "+
cvm::to_str(biases.size())+" in total.\n");
} else {
if (!use_scripted_forces) {
cvm::log("No collective variables biases were defined.\n");
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::num_biases_feature(int feature_id)
{
colvarmodule *cv = cvm::main();
size_t n = 0;
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
bi != cv->biases.end();
bi++) {
if ((*bi)->is_enabled(feature_id)) {
n++;
}
}
return n;
}
int colvarmodule::num_biases_type(std::string const &type)
{
colvarmodule *cv = cvm::main();
size_t n = 0;
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
bi != cv->biases.end();
bi++) {
if ((*bi)->bias_type == type) {
n++;
}
}
return n;
}
int colvarmodule::catch_input_errors(int result)
{
if (result != COLVARS_OK || get_error()) {
set_error_bits(result);
set_error_bits(INPUT_ERROR);
parse->init();
return get_error();
}
return COLVARS_OK;
}
-colvarbias * colvarmodule::bias_by_name(std::string const &name) {
+colvarbias * colvarmodule::bias_by_name(std::string const &name)
+{
colvarmodule *cv = cvm::main();
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
bi != cv->biases.end();
bi++) {
if ((*bi)->name == name) {
return (*bi);
}
}
return NULL;
}
-colvar *colvarmodule::colvar_by_name(std::string const &name) {
+colvar *colvarmodule::colvar_by_name(std::string const &name)
+{
colvarmodule *cv = cvm::main();
for (std::vector<colvar *>::iterator cvi = cv->colvars.begin();
cvi != cv->colvars.end();
cvi++) {
if ((*cvi)->name == name) {
return (*cvi);
}
}
return NULL;
}
+cvm::atom_group *colvarmodule::atom_group_by_name(std::string const &name)
+{
+ colvarmodule *cv = cvm::main();
+ for (std::vector<cvm::atom_group *>::iterator agi = cv->named_atom_groups.begin();
+ agi != cv->named_atom_groups.end();
+ agi++) {
+ if ((*agi)->name == name) {
+ return (*agi);
+ }
+ }
+ return NULL;
+}
+
+
int colvarmodule::change_configuration(std::string const &bias_name,
std::string const &conf)
{
// This is deprecated; supported strategy is to delete the bias
// and parse the new config
cvm::increase_depth();
colvarbias *b;
b = bias_by_name(bias_name);
- if (b == NULL) { cvm::error("Error: bias not found: " + bias_name); }
+ if (b == NULL) {
+ cvm::error("Error: bias not found: " + bias_name);
+ return COLVARS_ERROR;
+ }
b->change_configuration(conf);
cvm::decrease_depth();
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
std::string colvarmodule::read_colvar(std::string const &name)
{
cvm::increase_depth();
colvar *c;
std::stringstream ss;
c = colvar_by_name(name);
- if (c == NULL) { cvm::fatal_error("Error: colvar not found: " + name); }
+ if (c == NULL) {
+ cvm::error("Error: colvar not found: " + name);
+ return std::string();
+ }
ss << c->value();
cvm::decrease_depth();
return ss.str();
}
cvm::real colvarmodule::energy_difference(std::string const &bias_name,
std::string const &conf)
{
cvm::increase_depth();
colvarbias *b;
cvm::real energy_diff = 0.;
b = bias_by_name(bias_name);
- if (b == NULL) { cvm::fatal_error("Error: bias not found: " + bias_name); }
+ if (b == NULL) {
+ cvm::error("Error: bias not found: " + bias_name);
+ return 0.;
+ }
energy_diff = b->energy_difference(conf);
cvm::decrease_depth();
return energy_diff;
}
int colvarmodule::bias_current_bin(std::string const &bias_name)
{
cvm::increase_depth();
int ret;
colvarbias *b = bias_by_name(bias_name);
if (b != NULL) {
ret = b->current_bin();
} else {
cvm::error("Error: bias not found.\n");
ret = COLVARS_ERROR;
}
cvm::decrease_depth();
return ret;
}
int colvarmodule::bias_bin_num(std::string const &bias_name)
{
cvm::increase_depth();
int ret;
colvarbias *b = bias_by_name(bias_name);
if (b != NULL) {
ret = b->bin_num();
} else {
cvm::error("Error: bias not found.\n");
ret = COLVARS_ERROR;
}
cvm::decrease_depth();
return ret;
}
int colvarmodule::bias_bin_count(std::string const &bias_name, size_t bin_index)
{
cvm::increase_depth();
int ret;
colvarbias *b = bias_by_name(bias_name);
if (b != NULL) {
ret = b->bin_count(bin_index);
} else {
cvm::error("Error: bias not found.\n");
ret = COLVARS_ERROR;
}
cvm::decrease_depth();
return ret;
}
int colvarmodule::bias_share(std::string const &bias_name)
{
cvm::increase_depth();
int ret;
colvarbias *b = bias_by_name(bias_name);
if (b != NULL) {
b->replica_share();
ret = COLVARS_OK;
} else {
cvm::error("Error: bias not found.\n");
ret = COLVARS_ERROR;
}
cvm::decrease_depth();
return ret;
}
int colvarmodule::calc()
{
int error_code = COLVARS_OK;
if (cvm::debug()) {
cvm::log(cvm::line_marker);
cvm::log("Collective variables module, step no. "+
cvm::to_str(cvm::step_absolute())+"\n");
}
error_code |= calc_colvars();
// set biasing forces to zero before biases are calculated and summed over
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end(); cvi++) {
(*cvi)->reset_bias_force();
}
error_code |= calc_biases();
error_code |= update_colvar_forces();
if (cvm::b_analysis) {
error_code |= analyze();
}
// write trajectory files, if needed
if (cv_traj_freq && cv_traj_name.size()) {
error_code |= write_traj_files();
}
// write restart files, if needed
if (restart_out_freq && restart_out_name.size()) {
error_code |= write_restart_files();
}
return error_code;
}
int colvarmodule::calc_colvars()
{
if (cvm::debug())
cvm::log("Calculating collective variables.\n");
// calculate collective variables and their gradients
+ // First, we need to decide which biases are awake
+ // so they can activate colvars as needed
+ std::vector<colvarbias *>::iterator bi;
+ for (bi = biases.begin(); bi != biases.end(); bi++) {
+ int tsf = (*bi)->get_time_step_factor();
+ if (tsf > 0 && (step_absolute() % tsf == 0)) {
+ (*bi)->enable(colvardeps::f_cvb_awake);
+ } else {
+ (*bi)->disable(colvardeps::f_cvb_awake);
+ }
+ }
+
int error_code = COLVARS_OK;
std::vector<colvar *>::iterator cvi;
// Determine which colvars are active at this iteration
- variables_active()->resize(0);
+ variables_active()->clear();
variables_active()->reserve(variables()->size());
for (cvi = variables()->begin(); cvi != variables()->end(); cvi++) {
- // This is a dynamic feature - the next call should be to enable()
- // or disable() when dynamic dependency resolution is fully implemented
- (*cvi)->set_enabled(colvardeps::f_cv_active,
- step_absolute() % (*cvi)->get_time_step_factor() == 0);
- variables_active()->push_back(*cvi);
+ // Wake up or put to sleep variables
+ int tsf = (*cvi)->get_time_step_factor();
+ if (tsf > 0 && (step_absolute() % tsf == 0)) {
+ (*cvi)->enable(colvardeps::f_cv_awake);
+ } else {
+ (*cvi)->disable(colvardeps::f_cv_awake);
+ }
+
+ if ((*cvi)->is_enabled()) {
+ variables_active()->push_back(*cvi);
+ }
}
// if SMP support is available, split up the work
if (proxy->smp_enabled() == COLVARS_OK) {
// first, calculate how much work (currently, how many active CVCs) each colvar has
- variables_active_smp()->resize(0);
- variables_active_smp_items()->resize(0);
+ variables_active_smp()->clear();
+ variables_active_smp_items()->clear();
variables_active_smp()->reserve(variables_active()->size());
variables_active_smp_items()->reserve(variables_active()->size());
// set up a vector containing all components
cvm::increase_depth();
for (cvi = variables_active()->begin(); cvi != variables_active()->end(); cvi++) {
error_code |= (*cvi)->update_cvc_flags();
size_t num_items = (*cvi)->num_active_cvcs();
variables_active_smp()->reserve(variables_active_smp()->size() + num_items);
variables_active_smp_items()->reserve(variables_active_smp_items()->size() + num_items);
for (size_t icvc = 0; icvc < num_items; icvc++) {
variables_active_smp()->push_back(*cvi);
variables_active_smp_items()->push_back(icvc);
}
}
cvm::decrease_depth();
// calculate colvar components in parallel
error_code |= proxy->smp_colvars_loop();
cvm::increase_depth();
for (cvi = variables_active()->begin(); cvi != variables_active()->end(); cvi++) {
error_code |= (*cvi)->collect_cvc_data();
}
cvm::decrease_depth();
} else {
// calculate colvars one at a time
cvm::increase_depth();
for (cvi = variables_active()->begin(); cvi != variables_active()->end(); cvi++) {
error_code |= (*cvi)->calc();
if (cvm::get_error()) {
return COLVARS_ERROR;
}
}
cvm::decrease_depth();
}
error_code |= cvm::get_error();
return error_code;
}
int colvarmodule::calc_biases()
{
// update the biases and communicate their forces to the collective
// variables
if (cvm::debug() && biases.size())
cvm::log("Updating collective variable biases.\n");
std::vector<colvarbias *>::iterator bi;
int error_code = COLVARS_OK;
// Total bias energy is reset before calling scripted biases
total_bias_energy = 0.0;
// update the list of active biases
- biases_active()->resize(0);
+ // which may have changed based on f_cvb_awake in calc_colvars()
+ biases_active()->clear();
biases_active()->reserve(biases.size());
for (bi = biases.begin(); bi != biases.end(); bi++) {
if ((*bi)->is_enabled()) {
biases_active()->push_back(*bi);
}
}
// if SMP support is available, split up the work
if (proxy->smp_enabled() == COLVARS_OK) {
if (use_scripted_forces && !scripting_after_biases) {
// calculate biases and scripted forces in parallel
error_code |= proxy->smp_biases_script_loop();
} else {
// calculate biases in parallel
error_code |= proxy->smp_biases_loop();
}
} else {
if (use_scripted_forces && !scripting_after_biases) {
error_code |= calc_scripted_forces();
}
cvm::increase_depth();
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
error_code |= (*bi)->update();
if (cvm::get_error()) {
return error_code;
}
}
cvm::decrease_depth();
}
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
total_bias_energy += (*bi)->get_energy();
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::update_colvar_forces()
{
int error_code = COLVARS_OK;
std::vector<colvar *>::iterator cvi;
std::vector<colvarbias *>::iterator bi;
// sum the forces from all biases for each collective variable
if (cvm::debug() && biases.size())
cvm::log("Collecting forces from all biases.\n");
cvm::increase_depth();
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
(*bi)->communicate_forces();
if (cvm::get_error()) {
return COLVARS_ERROR;
}
}
cvm::decrease_depth();
if (use_scripted_forces && scripting_after_biases) {
error_code |= calc_scripted_forces();
}
// Now we have collected energies from both built-in and scripted biases
if (cvm::debug())
cvm::log("Adding total bias energy: " + cvm::to_str(total_bias_energy) + "\n");
proxy->add_energy(total_bias_energy);
cvm::real total_colvar_energy = 0.0;
// sum up the forces for each colvar, including wall forces
// and integrate any internal
// equation of motion (extended system)
if (cvm::debug())
cvm::log("Updating the internal degrees of freedom "
"of colvars (if they have any).\n");
cvm::increase_depth();
for (cvi = variables()->begin(); cvi != variables()->end(); cvi++) {
- // Here we call even inactive colvars, so they accumulate biasing forces
- // as well as update their extended-system dynamics
+ // Inactive colvars will only reset their forces and return 0 energy
total_colvar_energy += (*cvi)->update_forces_energy();
if (cvm::get_error()) {
return COLVARS_ERROR;
}
}
cvm::decrease_depth();
if (cvm::debug())
cvm::log("Adding total colvar energy: " + cvm::to_str(total_colvar_energy) + "\n");
proxy->add_energy(total_colvar_energy);
// make collective variables communicate their forces to their
// coupled degrees of freedom (i.e. atoms)
if (cvm::debug())
cvm::log("Communicating forces from the colvars to the atoms.\n");
cvm::increase_depth();
for (cvi = variables_active()->begin(); cvi != variables_active()->end(); cvi++) {
if ((*cvi)->is_enabled(colvardeps::f_cv_gradient)) {
(*cvi)->communicate_forces();
if (cvm::get_error()) {
return COLVARS_ERROR;
}
}
}
cvm::decrease_depth();
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::calc_scripted_forces()
{
// Run user force script, if provided,
// potentially adding scripted forces to the colvars
int res;
res = proxy->run_force_callback();
if (res == COLVARS_NOT_IMPLEMENTED) {
cvm::error("Colvar forces scripts are not implemented.");
return COLVARS_NOT_IMPLEMENTED;
}
if (res != COLVARS_OK) {
cvm::error("Error running user colvar forces script");
return COLVARS_ERROR;
}
return COLVARS_OK;
}
int colvarmodule::write_restart_files()
{
if ( (cvm::step_relative() > 0) &&
((cvm::step_absolute() % restart_out_freq) == 0) ) {
cvm::log("Writing the state file \""+
restart_out_name+"\".\n");
- proxy->backup_file(restart_out_name.c_str());
- restart_out_os.open(restart_out_name.c_str());
- if (!restart_out_os.is_open() || !write_restart(restart_out_os))
- cvm::error("Error: in writing restart file.\n");
- restart_out_os.close();
+ proxy->backup_file(restart_out_name);
+ std::ostream *restart_out_os = proxy->output_stream(restart_out_name);
+ if (!restart_out_os) return cvm::get_error();
+ if (!write_restart(*restart_out_os)) {
+ return cvm::error("Error: in writing restart file.\n", FILE_ERROR);
+ }
+ proxy->close_output_stream(restart_out_name);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::write_traj_files()
{
- if (!cv_traj_os.is_open()) {
+ if (cv_traj_os == NULL) {
open_traj_file(cv_traj_name);
}
// write labels in the traj file every 1000 lines and at first timestep
if ((cvm::step_absolute() % (cv_traj_freq * 1000)) == 0 || cvm::step_relative() == 0) {
- write_traj_label(cv_traj_os);
+ write_traj_label(*cv_traj_os);
}
if ((cvm::step_absolute() % cv_traj_freq) == 0) {
- write_traj(cv_traj_os);
+ write_traj(*cv_traj_os);
}
- if (restart_out_freq && cv_traj_os.is_open()) {
+ if (restart_out_freq && (cv_traj_os != NULL)) {
// flush the trajectory file if we are at the restart frequency
if ( (cvm::step_relative() > 0) &&
((cvm::step_absolute() % restart_out_freq) == 0) ) {
cvm::log("Synchronizing (emptying the buffer of) trajectory file \""+
cv_traj_name+"\".\n");
- cv_traj_os.flush();
+ proxy->flush_output_stream(cv_traj_os);
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::analyze()
{
if (cvm::debug()) {
cvm::log("colvarmodule::analyze(), step = "+cvm::to_str(it)+".\n");
}
if (cvm::step_relative() == 0)
cvm::log("Performing analysis.\n");
// perform colvar-specific analysis
for (std::vector<colvar *>::iterator cvi = variables_active()->begin();
cvi != variables_active()->end();
cvi++) {
cvm::increase_depth();
(*cvi)->analyze();
cvm::decrease_depth();
}
// perform bias-specific analysis
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
cvm::increase_depth();
(*bi)->analyze();
cvm::decrease_depth();
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::setup()
{
if (this->size() == 0) return cvm::get_error();
// loop over all components of all colvars to reset masses of all groups
for (std::vector<colvar *>::iterator cvi = variables()->begin();
cvi != variables()->end(); cvi++) {
(*cvi)->setup();
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
colvarmodule::~colvarmodule()
{
if ((proxy->smp_thread_id() == COLVARS_NOT_IMPLEMENTED) ||
(proxy->smp_thread_id() == 0)) {
reset();
delete parse;
parse = NULL;
proxy = NULL;
}
}
int colvarmodule::reset()
{
parse->init();
cvm::log("Resetting the Collective Variables Module.\n");
// Iterate backwards because we are deleting the elements as we go
for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin();
bi != biases.rend();
bi++) {
delete *bi; // the bias destructor updates the biases array
}
biases.clear();
// Iterate backwards because we are deleting the elements as we go
for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin();
cvi != colvars.rend();
cvi++) {
delete *cvi; // the colvar destructor updates the colvars array
}
colvars.clear();
index_groups.clear();
index_group_names.clear();
- if (cv_traj_os.is_open()) {
+ proxy->reset();
+
+ if (cv_traj_os != NULL) {
// Do not close file here, as we might not be done with it yet.
- cv_traj_os.flush();
+ proxy->flush_output_stream(cv_traj_os);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::setup_input()
{
if (this->size() == 0) return cvm::get_error();
std::string restart_in_name("");
// read the restart configuration, if available
if (proxy->input_prefix().size()) {
// read the restart file
restart_in_name = proxy->input_prefix();
std::ifstream input_is(restart_in_name.c_str());
if (!input_is.good()) {
// try by adding the suffix
input_is.clear();
restart_in_name = restart_in_name+std::string(".colvars.state");
input_is.open(restart_in_name.c_str());
}
if (!input_is.good()) {
cvm::error("Error: in opening input file \""+
std::string(restart_in_name)+"\".\n",
FILE_ERROR);
return COLVARS_ERROR;
} else {
cvm::log(cvm::line_marker);
cvm::log("Restarting from file \""+restart_in_name+"\".\n");
read_restart(input_is);
if (cvm::get_error() != COLVARS_OK) {
return COLVARS_ERROR;
} else {
proxy->input_prefix().clear();
}
cvm::log(cvm::line_marker);
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::setup_output()
{
if (this->size() == 0) return cvm::get_error();
int error_code = COLVARS_OK;
// output state file (restart)
restart_out_name = proxy->restart_output_prefix().size() ?
std::string(proxy->restart_output_prefix()+".colvars.state") :
std::string("");
if (restart_out_name.size()) {
cvm::log("The restart output state file will be \""+restart_out_name+"\".\n");
}
output_prefix() = proxy->output_prefix();
if (output_prefix().size()) {
cvm::log("The final output state file will be \""+
(output_prefix().size() ?
std::string(output_prefix()+".colvars.state") :
std::string("colvars.state"))+"\".\n");
// cvm::log (cvm::line_marker);
}
cv_traj_name =
(output_prefix().size() ?
std::string(output_prefix()+".colvars.traj") :
std::string(""));
if (cv_traj_freq && cv_traj_name.size()) {
error_code |= open_traj_file(cv_traj_name);
}
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
error_code |= (*bi)->setup_output();
}
if (error_code != COLVARS_OK || cvm::get_error()) {
set_error_bits(FILE_ERROR);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
std::istream & colvarmodule::read_restart(std::istream &is)
{
bool warn_total_forces = false;
{
// read global restart information
std::string restart_conf;
if (is >> colvarparse::read_block("configuration", restart_conf)) {
if (it_restart_from_state_file) {
parse->get_keyval(restart_conf, "step",
it_restart, (size_t) 0,
colvarparse::parse_silent);
it = it_restart;
}
std::string restart_version;
parse->get_keyval(restart_conf, "version",
restart_version, std::string(""),
colvarparse::parse_silent);
if (restart_version.size() && (restart_version != std::string(COLVARS_VERSION))) {
cvm::log("This state file was generated with version "+restart_version+"\n");
}
if ((restart_version.size() == 0) || (restart_version.compare(std::string(COLVARS_VERSION)) < 0)) {
// check for total force change
if (proxy->total_forces_enabled()) {
warn_total_forces = true;
}
}
}
is.clear();
parse->clear_keyword_registry();
}
// colvars restart
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
if ( !((*cvi)->read_restart(is)) ) {
cvm::error("Error: in reading restart configuration for collective variable \""+
(*cvi)->name+"\".\n",
INPUT_ERROR);
}
}
// biases restart
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
if (!((*bi)->read_state(is))) {
cvm::error("Error: in reading restart configuration for bias \""+
(*bi)->name+"\".\n",
INPUT_ERROR);
}
}
cvm::decrease_depth();
if (warn_total_forces) {
cvm::log(cvm::line_marker);
cvm::log("WARNING:\n");
std::string const warning("### CHANGES IN THE DEFINITION OF SYSTEM FORCES (NOW TOTAL FORCES)\n\
\n\
Starting from the version 2016-08-10 of the Colvars module, \n\
the role of system forces has been replaced by total forces.\n\
\n\
These include *all* forces acting on a collective variable, whether they\n\
come from the force field potential or from external terms\n\
(e.g. restraints), including forces applied by Colvars itself.\n\
\n\
In NAMD, forces applied by Colvars, IMD, SMD, TMD, symmetry\n\
restraints and tclForces are now all counted in the total force.\n\
\n\
In LAMMPS, forces applied by Colvars itself are now counted in the total\n\
force (all forces from other fixes were being counted already).\n\
\n\
\n\
### WHEN IS THIS CHANGE RELEVANT\n\
\n\
This change affects results *only* when (1) outputSystemForce is\n\
requested or (2) the ABF bias is used. All other usage cases are\n\
*unaffected* (colvar restraints, metadynamics, etc).\n\
\n\
When system forces are reported (flag: outputSystemForce), their values\n\
in the output may change, but the physical trajectory is never affected.\n\
The physical results of ABF calculations may be affected in some cases.\n\
\n\
\n\
### CHANGES TO ABF CALCULATIONS\n\
\n\
Compared to previous Colvars versions, the ABF method will now attempt\n\
to cancel external forces (for example, boundary walls) and it may be\n\
not possible to resume through a state file a simulation that was\n\
performed with a previous version.\n\
\n\
There are three possible scenarios:\n\
\n\
1. No external forces are applied to the atoms used by ABF: results are\n\
unchanged.\n\
\n\
2. Some of the atoms used by ABF experience external forces, but these\n\
forces are not applied directly to the variables used by ABF\n\
(e.g. another colvar that uses the same atoms, tclForces, etc): in this\n\
case, we recommend beginning a new simulation.\n\
\n\
3. External forces are applied to one or more of the colvars used by\n\
ABF, but no other forces are applied to their atoms: you may use the\n\
subtractAppliedForce keyword inside the corresponding colvars to\n\
continue the previous simulation.\n\n");
cvm::log(warning);
cvm::log(cvm::line_marker);
// update this ahead of time in this special case
output_prefix() = proxy->input_prefix();
cvm::log("All output files will now be saved with the prefix \""+output_prefix()+".tmp.*\".\n");
cvm::log(cvm::line_marker);
cvm::log("Please review the important warning above. After that, you may rename:\n\
\""+output_prefix()+".tmp.colvars.state\"\n\
to:\n\
\""+ proxy->input_prefix()+".colvars.state\"\n");
output_prefix() = output_prefix()+".tmp";
write_output_files();
cvm::error("Exiting with error until issue is addressed.\n", FATAL_ERROR);
}
return is;
}
int colvarmodule::backup_file(char const *filename)
{
return proxy->backup_file(filename);
}
int colvarmodule::write_output_files()
{
// if this is a simulation run (i.e. not a postprocessing), output data
// must be written to be able to restart the simulation
std::string const out_name =
(output_prefix().size() ?
std::string(output_prefix()+".colvars.state") :
std::string("colvars.state"));
cvm::log("Saving collective variables state to \""+out_name+"\".\n");
std::ostream * os = proxy->output_stream(out_name);
os->setf(std::ios::scientific, std::ios::floatfield);
this->write_restart(*os);
proxy->close_output_stream(out_name);
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
(*cvi)->write_output_files();
}
cvm::decrease_depth();
cvm::increase_depth();
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
(*bi)->write_output_files();
(*bi)->write_state_to_replicas();
}
cvm::decrease_depth();
- if (cv_traj_os.is_open()) {
- // do not close to avoid problems with multiple NAMD runs
- cv_traj_os.flush();
+ if (cv_traj_os != NULL) {
+ // do not close, there may be another run command
+ proxy->flush_output_stream(cv_traj_os);
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int colvarmodule::read_traj(char const *traj_filename,
long traj_read_begin,
long traj_read_end)
{
cvm::log("Opening trajectory file \""+
std::string(traj_filename)+"\".\n");
std::ifstream traj_is(traj_filename);
while (true) {
while (true) {
std::string line("");
do {
if (!colvarparse::getline_nocomments(traj_is, line)) {
cvm::log("End of file \""+std::string(traj_filename)+
"\" reached, or corrupted file.\n");
traj_is.close();
return false;
}
} while (line.find_first_not_of(colvarparse::white_space) == std::string::npos);
std::istringstream is(line);
if (!(is >> it)) return false;
if ( (it < traj_read_begin) ) {
if ((it % 1000) == 0)
std::cerr << "Skipping trajectory step " << it
<< " \r";
continue;
} else {
if ((it % 1000) == 0)
std::cerr << "Reading from trajectory, step = " << it
<< " \r";
if ( (traj_read_end > traj_read_begin) &&
(it > traj_read_end) ) {
std::cerr << "\n";
cvm::error("Reached the end of the trajectory, "
"read_end = "+cvm::to_str(traj_read_end)+"\n",
FILE_ERROR);
return COLVARS_ERROR;
}
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
if (!(*cvi)->read_traj(is)) {
cvm::error("Error: in reading colvar \""+(*cvi)->name+
"\" from trajectory file \""+
std::string(traj_filename)+"\".\n",
FILE_ERROR);
return COLVARS_ERROR;
}
}
break;
}
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
std::ostream & colvarmodule::write_restart(std::ostream &os)
{
os.setf(std::ios::scientific, std::ios::floatfield);
os << "configuration {\n"
<< " step " << std::setw(it_width)
<< it << "\n"
<< " dt " << dt() << "\n"
<< " version " << std::string(COLVARS_VERSION) << "\n"
<< "}\n\n";
int error_code = COLVARS_OK;
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
(*cvi)->write_restart(os);
error_code |= (*cvi)->write_output_files();
}
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
(*bi)->write_state(os);
error_code |= (*bi)->write_state_to_replicas();
error_code |= (*bi)->write_output_files();
}
cvm::decrease_depth();
if (error_code != COLVARS_OK) {
// TODO make this function return an int instead
os.setstate(std::ios::failbit);
}
return os;
}
+
int colvarmodule::open_traj_file(std::string const &file_name)
{
- if (cv_traj_os.is_open()) {
+ if (cv_traj_os != NULL) {
return COLVARS_OK;
}
// (re)open trajectory file
if (cv_traj_append) {
cvm::log("Appending to colvar trajectory file \""+file_name+
"\".\n");
- cv_traj_os.open(file_name.c_str(), std::ios::app);
+ cv_traj_os = (cvm::proxy)->output_stream(file_name, std::ios::app);
} else {
cvm::log("Writing to colvar trajectory file \""+file_name+
"\".\n");
proxy->backup_file(file_name.c_str());
- cv_traj_os.open(file_name.c_str());
+ cv_traj_os = (cvm::proxy)->output_stream(file_name);
}
- if (!cv_traj_os.is_open()) {
+ if (cv_traj_os == NULL) {
cvm::error("Error: cannot write to file \""+file_name+"\".\n",
FILE_ERROR);
}
- return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
+ return cvm::get_error();
}
+
int colvarmodule::close_traj_file()
{
- if (cv_traj_os.is_open()) {
- cv_traj_os.close();
+ if (cv_traj_os != NULL) {
+ proxy->close_output_stream(cv_traj_name);
+ cv_traj_os = NULL;
}
- return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
+ return cvm::get_error();
}
+
std::ostream & colvarmodule::write_traj_label(std::ostream &os)
{
- if (!os.good()) {
- cvm::error("Cannot write to trajectory file.");
- return os;
- }
os.setf(std::ios::scientific, std::ios::floatfield);
os << "# " << cvm::wrap_string("step", cvm::it_width-2)
<< " ";
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
(*cvi)->write_traj_label(os);
}
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
(*bi)->write_traj_label(os);
}
os << "\n";
+
if (cvm::debug()) {
- os.flush();
+ proxy->flush_output_stream(&os);
}
+
cvm::decrease_depth();
return os;
}
+
std::ostream & colvarmodule::write_traj(std::ostream &os)
{
os.setf(std::ios::scientific, std::ios::floatfield);
os << std::setw(cvm::it_width) << it
<< " ";
cvm::increase_depth();
for (std::vector<colvar *>::iterator cvi = colvars.begin();
cvi != colvars.end();
cvi++) {
(*cvi)->write_traj(os);
}
for (std::vector<colvarbias *>::iterator bi = biases.begin();
bi != biases.end();
bi++) {
(*bi)->write_traj(os);
}
os << "\n";
+
if (cvm::debug()) {
- os.flush();
+ proxy->flush_output_stream(&os);
}
+
cvm::decrease_depth();
return os;
}
void cvm::log(std::string const &message)
{
// allow logging when the module is not fully initialized
size_t const d = (cvm::main() != NULL) ? depth() : 0;
if (d > 0)
proxy->log((std::string(2*d, ' '))+message);
else
proxy->log(message);
}
void cvm::increase_depth()
{
(depth())++;
}
void cvm::decrease_depth()
{
if (depth() > 0) {
(depth())--;
}
}
size_t & cvm::depth()
{
// NOTE: do not call log() or error() here, to avoid recursion
colvarmodule *cv = cvm::main();
if (proxy->smp_enabled() == COLVARS_OK) {
int const nt = proxy->smp_num_threads();
if (int(cv->depth_v.size()) != nt) {
proxy->smp_lock();
// update array of depths
if (cv->depth_v.size() > 0) { cv->depth_s = cv->depth_v[0]; }
cv->depth_v.clear();
cv->depth_v.assign(nt, cv->depth_s);
proxy->smp_unlock();
}
return cv->depth_v[proxy->smp_thread_id()];
}
return cv->depth_s;
}
void colvarmodule::set_error_bits(int code)
{
if (code < 0) {
cvm::fatal_error("Error: set_error_bits() received negative error code.\n");
return;
}
proxy->smp_lock();
errorCode |= code | COLVARS_ERROR;
proxy->smp_unlock();
}
bool colvarmodule::get_error_bit(int code)
{
return bool(errorCode & code);
}
void colvarmodule::clear_error()
{
proxy->smp_lock();
errorCode = COLVARS_OK;
proxy->smp_unlock();
}
-void cvm::error(std::string const &message, int code)
+int colvarmodule::error(std::string const &message, int code)
{
set_error_bits(code);
proxy->error(message);
+ return get_error();
}
-void cvm::fatal_error(std::string const &message)
+int colvarmodule::fatal_error(std::string const &message)
{
- // TODO once all non-fatal errors have been set to be handled by error(),
- // set DELETE_COLVARS here for VMD to handle it
set_error_bits(FATAL_ERROR);
proxy->fatal_error(message);
-}
-
-
-void cvm::exit(std::string const &message)
-{
- proxy->exit(message);
+ return get_error();
}
int cvm::read_index_file(char const *filename)
{
std::ifstream is(filename, std::ios::binary);
if (!is.good()) {
cvm::error("Error: in opening index file \""+
std::string(filename)+"\".\n",
FILE_ERROR);
}
while (is.good()) {
char open, close;
std::string group_name;
if ( (is >> open) && (open == '[') &&
(is >> group_name) &&
(is >> close) && (close == ']') ) {
for (std::list<std::string>::iterator names_i = index_group_names.begin();
names_i != index_group_names.end();
names_i++) {
if (*names_i == group_name) {
cvm::error("Error: the group name \""+group_name+
"\" appears in multiple index files.\n",
FILE_ERROR);
}
}
index_group_names.push_back(group_name);
index_groups.push_back(std::vector<int>());
} else {
cvm::error("Error: in parsing index file \""+
std::string(filename)+"\".\n",
INPUT_ERROR);
}
int atom_number = 1;
size_t pos = is.tellg();
while ( (is >> atom_number) && (atom_number > 0) ) {
(index_groups.back()).push_back(atom_number);
pos = is.tellg();
}
is.clear();
is.seekg(pos, std::ios::beg);
std::string delim;
if ( (is >> delim) && (delim == "[") ) {
// new group
is.clear();
is.seekg(pos, std::ios::beg);
} else {
break;
}
}
cvm::log("The following index groups were read from the index file \""+
std::string(filename)+"\":\n");
std::list<std::string>::iterator names_i = index_group_names.begin();
std::list<std::vector<int> >::iterator lists_i = index_groups.begin();
for ( ; names_i != index_group_names.end() ; names_i++, lists_i++) {
cvm::log(" "+(*names_i)+" ("+cvm::to_str(lists_i->size())+" atoms).\n");
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
int cvm::load_atoms(char const *file_name,
cvm::atom_group &atoms,
std::string const &pdb_field,
double const pdb_field_value)
{
return proxy->load_atoms(file_name, atoms, pdb_field, pdb_field_value);
}
int cvm::load_coords(char const *file_name,
std::vector<cvm::atom_pos> &pos,
const std::vector<int> &indices,
std::string const &pdb_field,
double const pdb_field_value)
{
// Differentiate between PDB and XYZ files
// for XYZ files, use CVM internal parser
// otherwise call proxy function for PDB
std::string const ext(strlen(file_name) > 4 ? (file_name + (strlen(file_name) - 4)) : file_name);
if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) {
if ( pdb_field.size() > 0 ) {
cvm::error("Error: PDB column may not be specified for XYZ coordinate file.\n", INPUT_ERROR);
return COLVARS_ERROR;
}
return cvm::load_coords_xyz(file_name, pos, indices);
} else {
return proxy->load_coords(file_name, pos, indices, pdb_field, pdb_field_value);
}
}
int cvm::load_coords_xyz(char const *filename,
std::vector<atom_pos> &pos,
const std::vector<int> &indices)
{
std::ifstream xyz_is(filename);
unsigned int natoms;
char symbol[256];
std::string line;
if ( ! (xyz_is >> natoms) ) {
cvm::error("Error: cannot parse XYZ file "
+ std::string(filename) + ".\n", INPUT_ERROR);
}
// skip comment line
cvm::getline(xyz_is, line);
cvm::getline(xyz_is, line);
xyz_is.width(255);
std::vector<atom_pos>::iterator pos_i = pos.begin();
if (pos.size() != natoms) { // Use specified indices
int next = 0; // indices are zero-based
std::vector<int>::const_iterator index = indices.begin();
for ( ; pos_i != pos.end() ; pos_i++, index++) {
while ( next < *index ) {
cvm::getline(xyz_is, line);
next++;
}
xyz_is >> symbol;
xyz_is >> (*pos_i)[0] >> (*pos_i)[1] >> (*pos_i)[2];
}
} else { // Use all positions
for ( ; pos_i != pos.end() ; pos_i++) {
xyz_is >> symbol;
xyz_is >> (*pos_i)[0] >> (*pos_i)[1] >> (*pos_i)[2];
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
// shared pointer to the proxy object
colvarproxy *colvarmodule::proxy = NULL;
// static runtime data
cvm::real colvarmodule::debug_gradients_step_size = 1.0e-07;
int colvarmodule::errorCode = 0;
long colvarmodule::it = 0;
long colvarmodule::it_restart = 0;
size_t colvarmodule::restart_out_freq = 0;
size_t colvarmodule::cv_traj_freq = 0;
bool colvarmodule::b_analysis = false;
bool colvarmodule::use_scripted_forces = false;
bool colvarmodule::scripting_after_biases = true;
// i/o constants
size_t const colvarmodule::it_width = 12;
size_t const colvarmodule::cv_prec = 14;
size_t const colvarmodule::cv_width = 21;
size_t const colvarmodule::en_prec = 14;
size_t const colvarmodule::en_width = 21;
const char * const colvarmodule::line_marker = (const char *)
"----------------------------------------------------------------------\n";
diff --git a/lib/colvars/colvarmodule.h b/lib/colvars/colvarmodule.h
index b4f80e0b5..0f6efd14c 100644
--- a/lib/colvars/colvarmodule.h
+++ b/lib/colvars/colvarmodule.h
@@ -1,736 +1,702 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARMODULE_H
#define COLVARMODULE_H
-#ifndef COLVARS_VERSION
-#define COLVARS_VERSION "2017-03-09"
-#endif
+#include "colvars_version.h"
#ifndef COLVARS_DEBUG
#define COLVARS_DEBUG false
#endif
/*! \mainpage Main page
This is the Developer's documentation for the Collective Variables Module.
You can browse the class hierarchy or the list of source files.
*/
/// \file colvarmodule.h
/// \brief Collective variables main module
///
/// This file declares the main class for defining and manipulating
/// collective variables: there should be only one instance of this
/// class, because several variables are made static (i.e. they are
/// shared between all object instances) to be accessed from other
/// objects.
#define COLVARS_OK 0
#define COLVARS_ERROR 1
#define COLVARS_NOT_IMPLEMENTED (1<<1)
#define INPUT_ERROR (1<<2) // out of bounds or inconsistent input
#define BUG_ERROR (1<<3) // Inconsistent state indicating bug
#define FILE_ERROR (1<<4)
#define MEMORY_ERROR (1<<5)
#define FATAL_ERROR (1<<6) // Should be set, or not, together with other bits
#define DELETE_COLVARS (1<<7) // Instruct the caller to delete cvm
#define COLVARS_NO_SUCH_FRAME (1<<8) // Cannot load the requested frame
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <sstream>
#include <fstream>
#include <cmath>
#include <vector>
#include <list>
-#ifdef NAMD_VERSION
-// use Lustre-friendly wrapper to POSIX write()
-#include "fstream_namd.h"
-#endif
-
class colvarparse;
class colvar;
class colvarbias;
class colvarproxy;
class colvarscript;
/// \brief Collective variables module (main class)
///
/// Class to control the collective variables calculation. An object
/// (usually one) of this class is spawned from the MD program,
/// containing all i/o routines and general interface.
///
/// At initialization, the colvarmodule object creates a proxy object
/// to provide a transparent interface between the MD program and the
/// child objects
class colvarmodule {
private:
/// Impossible to initialize the main object without arguments
colvarmodule();
public:
friend class colvarproxy;
// TODO colvarscript should be unaware of colvarmodule's internals
friend class colvarscript;
/// Defining an abstract real number allows to switch precision
typedef double real;
/// Residue identifier
typedef int residue_id;
class rvector;
template <class T> class vector1d;
template <class T> class matrix2d;
class quaternion;
class rotation;
/// \brief Atom position (different type name from rvector, to make
/// possible future PBC-transparent implementations)
typedef rvector atom_pos;
/// \brief 3x3 matrix of real numbers
class rmatrix;
// allow these classes to access protected data
class atom;
class atom_group;
friend class atom;
friend class atom_group;
typedef std::vector<atom>::iterator atom_iter;
typedef std::vector<atom>::const_iterator atom_const_iter;
/// Module-wide error state
/// see constants at the top of this file
protected:
static int errorCode;
public:
static void set_error_bits(int code);
static bool get_error_bit(int code);
static inline int get_error()
{
return errorCode;
}
static void clear_error();
/// Current step number
static long it;
/// Starting step number for this run
static long it_restart;
/// Return the current step number from the beginning of this run
static inline long step_relative()
{
return it - it_restart;
}
/// Return the current step number from the beginning of the whole
/// calculation
static inline long step_absolute()
{
return it;
}
/// If true, get it_restart from the state file; if set to false,
/// the MD program is providing it
bool it_restart_from_state_file;
/// \brief Finite difference step size (if there is no dynamics, or
/// if gradients need to be tested independently from the size of
/// dt)
static real debug_gradients_step_size;
private:
/// Prefix for all output files for this run
std::string cvm_output_prefix;
public:
/// Accessor for the above
static inline std::string &output_prefix()
{
colvarmodule *cv = colvarmodule::main();
return cv->cvm_output_prefix;
}
private:
/// Array of collective variables
std::vector<colvar *> colvars;
/// Array of collective variables
std::vector<colvar *> colvars_active;
/// Collective variables to be calculated on different threads;
/// colvars with multple items (e.g. multiple active CVCs) are duplicated
std::vector<colvar *> colvars_smp;
/// Indexes of the items to calculate for each colvar
std::vector<int> colvars_smp_items;
+ /// Array of named atom groups
+ std::vector<atom_group *> named_atom_groups;
public:
+ /// Register a named atom group into named_atom_groups
+ inline void register_named_atom_group(atom_group * ag) {
+ named_atom_groups.push_back(ag);
+ }
/// Array of collective variables
std::vector<colvar *> *variables();
/* TODO: implement named CVCs
/// Array of named (reusable) collective variable components
static std::vector<cvc *> cvcs;
/// Named cvcs register themselves at initialization time
inline void register_cvc(cvc *p) {
cvcs.push_back(p);
}
*/
/// Collective variables with the active flag on
std::vector<colvar *> *variables_active();
/// Collective variables to be calculated on different threads;
/// colvars with multple items (e.g. multiple active CVCs) are duplicated
std::vector<colvar *> *variables_active_smp();
/// Indexes of the items to calculate for each colvar
std::vector<int> *variables_active_smp_items();
/// Array of collective variable biases
std::vector<colvarbias *> biases;
/// Energy of built-in and scripted biases, summed per time-step
real total_bias_energy;
private:
/// Array of active collective variable biases
std::vector<colvarbias *> biases_active_;
public:
/// Array of active collective variable biases
std::vector<colvarbias *> *biases_active();
/// \brief Whether debug output should be enabled (compile-time option)
static inline bool debug()
{
return COLVARS_DEBUG;
}
/// \brief How many objects are configured yet?
size_t size() const;
/// \brief Constructor \param config_name Configuration file name
/// \param restart_name (optional) Restart file name
colvarmodule(colvarproxy *proxy);
/// Destructor
~colvarmodule();
/// Actual function called by the destructor
int reset();
/// Open a config file, load its contents, and pass it to config_string()
int read_config_file(char const *config_file_name);
/// \brief Parse a config string assuming it is a complete configuration
/// (i.e. calling all parse functions)
int read_config_string(std::string const &conf);
/// \brief Parse a "clean" config string (no comments)
int parse_config(std::string &conf);
// Parse functions (setup internal data based on a string)
/// Allow reading from Windows text files using using std::getline
/// (which can still be used when the text is produced by Colvars itself)
static std::istream & getline(std::istream &is, std::string &line);
/// Parse the few module's global parameters
int parse_global_params(std::string const &conf);
/// Parse and initialize collective variables
int parse_colvars(std::string const &conf);
/// Parse and initialize collective variable biases
int parse_biases(std::string const &conf);
/// \brief Add new configuration during parsing (e.g. to implement
/// back-compatibility); cannot be nested, i.e. conf should not contain
/// anything that triggers another call
int append_new_config(std::string const &conf);
private:
/// Auto-generated configuration during parsing (e.g. to implement
/// back-compatibility)
std::string extra_conf;
/// Parse and initialize collective variable biases of a specific type
template <class bias_type>
int parse_biases_type(std::string const &conf, char const *keyword);
/// Test error condition and keyword parsing
/// on error, delete new bias
bool check_new_bias(std::string &conf, char const *key);
public:
/// Return how many biases have this feature enabled
static int num_biases_feature(int feature_id);
/// Return how many biases are defined with this type
static int num_biases_type(std::string const &type);
private:
/// Useful wrapper to interrupt parsing if any error occurs
int catch_input_errors(int result);
public:
// "Setup" functions (change internal data based on related data
// from the proxy that may change during program execution)
// No additional parsing is done within these functions
/// (Re)initialize internal data (currently used by LAMMPS)
/// Also calls setup() member functions of colvars and biases
int setup();
/// (Re)initialize and (re)read the input state file calling read_restart()
int setup_input();
/// (Re)initialize the output trajectory and state file (does not write it yet)
int setup_output();
-#ifdef NAMD_VERSION
- typedef ofstream_namd ofstream;
-#else
- typedef std::ofstream ofstream;
-#endif
-
/// Read the input restart file
std::istream & read_restart(std::istream &is);
/// Write the output restart file
std::ostream & write_restart(std::ostream &os);
/// Open a trajectory file if requested (and leave it open)
int open_traj_file(std::string const &file_name);
- /// Close it
+ /// Close it (note: currently unused)
int close_traj_file();
/// Write in the trajectory file
std::ostream & write_traj(std::ostream &os);
/// Write explanatory labels in the trajectory file
std::ostream & write_traj_label(std::ostream &os);
/// Write all trajectory files
int write_traj_files();
/// Write all restart files
int write_restart_files();
/// Write all FINAL output files
int write_output_files();
/// Backup a file before writing it
static int backup_file(char const *filename);
/// Look up a bias by name; returns NULL if not found
static colvarbias * bias_by_name(std::string const &name);
/// Look up a colvar by name; returns NULL if not found
static colvar * colvar_by_name(std::string const &name);
+ /// Look up a named atom group by name; returns NULL if not found
+ static atom_group * atom_group_by_name(std::string const &name);
+
/// Load new configuration for the given bias -
/// currently works for harmonic (force constant and/or centers)
int change_configuration(std::string const &bias_name, std::string const &conf);
/// Read a colvar value
std::string read_colvar(std::string const &name);
/// Calculate change in energy from using alt. config. for the given bias -
/// currently works for harmonic (force constant and/or centers)
real energy_difference(std::string const &bias_name, std::string const &conf);
/// Give the total number of bins for a given bias.
int bias_bin_num(std::string const &bias_name);
/// Calculate the bin index for a given bias.
int bias_current_bin(std::string const &bias_name);
//// Give the count at a given bin index.
int bias_bin_count(std::string const &bias_name, size_t bin_index);
//// Share among replicas.
int bias_share(std::string const &bias_name);
/// Main worker function
int calc();
/// Calculate collective variables
int calc_colvars();
/// Calculate biases
int calc_biases();
/// Integrate bias and restraint forces, send colvar forces to atoms
int update_colvar_forces();
/// Perform analysis
int analyze();
/// \brief Read a collective variable trajectory (post-processing
/// only, not called at runtime)
int read_traj(char const *traj_filename,
long traj_read_begin,
long traj_read_end);
/// Quick conversion of an object to a string
template<typename T> static std::string to_str(T const &x,
size_t const &width = 0,
size_t const &prec = 0);
/// Quick conversion of a vector of objects to a string
template<typename T> static std::string to_str(std::vector<T> const &x,
size_t const &width = 0,
size_t const &prec = 0);
/// Reduce the number of characters in a string
static inline std::string wrap_string(std::string const &s,
size_t const &nchars)
{
if (!s.size())
return std::string(nchars, ' ');
else
return ( (s.size() <= size_t(nchars)) ?
(s+std::string(nchars-s.size(), ' ')) :
(std::string(s, 0, nchars)) );
}
/// Number of characters to represent a time step
static size_t const it_width;
/// Number of digits to represent a collective variables value(s)
static size_t const cv_prec;
/// Number of characters to represent a collective variables value(s)
static size_t const cv_width;
/// Number of digits to represent the collective variables energy
static size_t const en_prec;
/// Number of characters to represent the collective variables energy
static size_t const en_width;
/// Line separator in the log output
static const char * const line_marker;
// proxy functions
/// \brief Value of the unit for atomic coordinates with respect to
/// angstroms (used by some variables for hard-coded default values)
static real unit_angstrom();
/// \brief Boltmann constant
static real boltzmann();
/// \brief Temperature of the simulation (K)
static real temperature();
/// \brief Time step of MD integrator (fs)
static real dt();
/// Request calculation of total force from MD engine
static void request_total_force();
/// Print a message to the main log
static void log(std::string const &message);
/// Print a message to the main log and exit with error code
- static void fatal_error(std::string const &message);
+ static int fatal_error(std::string const &message);
/// Print a message to the main log and set global error code
- static void error(std::string const &message, int code = COLVARS_ERROR);
+ static int error(std::string const &message, int code = COLVARS_ERROR);
/// Print a message to the main log and exit normally
static void exit(std::string const &message);
// Replica exchange commands.
static bool replica_enabled();
static int replica_index();
static int replica_num();
static void replica_comm_barrier();
static int replica_comm_recv(char* msg_data, int buf_len, int src_rep);
static int replica_comm_send(char* msg_data, int msg_len, int dest_rep);
/// \brief Get the distance between two atomic positions with pbcs handled
/// correctly
static rvector position_distance(atom_pos const &pos1,
- atom_pos const &pos2);
-
+ atom_pos const &pos2);
/// \brief Get the square distance between two positions (with
/// periodic boundary conditions handled transparently)
///
/// Note: in the case of periodic boundary conditions, this provides
/// an analytical square distance (while taking the square of
/// position_distance() would produce leads to a cusp)
static real position_dist2(atom_pos const &pos1,
- atom_pos const &pos2);
-
- /// \brief Get the closest periodic image to a reference position
- /// \param pos The position to look for the closest periodic image
- /// \param ref_pos (optional) The reference position
- static void select_closest_image(atom_pos &pos,
- atom_pos const &ref_pos);
-
- /// \brief Perform select_closest_image() on a set of atomic positions
- ///
- /// After that, distance vectors can then be calculated directly,
- /// without using position_distance()
- static void select_closest_images(std::vector<atom_pos> &pos,
- atom_pos const &ref_pos);
-
+ atom_pos const &pos2);
/// \brief Names of groups from a Gromacs .ndx file to be read at startup
std::list<std::string> index_group_names;
/// \brief Groups from a Gromacs .ndx file read at startup
std::list<std::vector<int> > index_groups;
/// \brief Read a Gromacs .ndx file
int read_index_file(char const *filename);
/// \brief Create atoms from a file \param filename name of the file
/// (usually a PDB) \param atoms array of the atoms to be allocated
/// \param pdb_field (optiona) if "filename" is a PDB file, use this
/// field to determine which are the atoms to be set
static int load_atoms(char const *filename,
atom_group &atoms,
std::string const &pdb_field,
double const pdb_field_value = 0.0);
/// \brief Load the coordinates for a group of atoms from a file
/// (PDB or XYZ)
static int load_coords(char const *filename,
std::vector<atom_pos> &pos,
const std::vector<int> &indices,
std::string const &pdb_field,
double const pdb_field_value = 0.0);
/// \brief Load the coordinates for a group of atoms from an
/// XYZ file
static int load_coords_xyz(char const *filename,
std::vector<atom_pos> &pos,
const std::vector<int> &indices);
/// Frequency for collective variables trajectory output
static size_t cv_traj_freq;
/// \brief True if only analysis is performed and not a run
static bool b_analysis;
/// Frequency for saving output restarts
static size_t restart_out_freq;
/// Output restart file name
std::string restart_out_name;
/// Pseudo-random number with Gaussian distribution
static real rand_gaussian(void);
protected:
/// Configuration file
std::ifstream config_s;
/// Configuration file parser object
colvarparse *parse;
/// Name of the trajectory file
std::string cv_traj_name;
/// Collective variables output trajectory file
- colvarmodule::ofstream cv_traj_os;
+ std::ostream *cv_traj_os;
/// Appending to the existing trajectory file?
bool cv_traj_append;
- /// Output restart file
- colvarmodule::ofstream restart_out_os;
-
private:
/// Counter for the current depth in the object hierarchy (useg e.g. in output)
size_t depth_s;
/// Thread-specific depth
std::vector<size_t> depth_v;
public:
/// Get the current object depth in the hierarchy
static size_t & depth();
/// Increase the depth (number of indentations in the output)
static void increase_depth();
/// Decrease the depth (number of indentations in the output)
static void decrease_depth();
static inline bool scripted_forces()
{
return use_scripted_forces;
}
/// Use scripted colvars forces?
static bool use_scripted_forces;
/// Wait for all biases before calculating scripted forces?
static bool scripting_after_biases;
/// Calculate the energy and forces of scripted biases
int calc_scripted_forces();
/// \brief Pointer to the proxy object, used to retrieve atomic data
/// from the hosting program; it is static in order to be accessible
/// from static functions in the colvarmodule class
static colvarproxy *proxy;
/// \brief Accessor for the above
static colvarmodule *main();
};
/// Shorthand for the frequently used type prefix
typedef colvarmodule cvm;
#include "colvartypes.h"
std::ostream & operator << (std::ostream &os, cvm::rvector const &v);
std::istream & operator >> (std::istream &is, cvm::rvector &v);
template<typename T> std::string cvm::to_str(T const &x,
size_t const &width,
size_t const &prec) {
std::ostringstream os;
if (width) os.width(width);
if (prec) {
os.setf(std::ios::scientific, std::ios::floatfield);
os.precision(prec);
}
os << x;
return os.str();
}
template<typename T> std::string cvm::to_str(std::vector<T> const &x,
size_t const &width,
size_t const &prec) {
if (!x.size()) return std::string("");
std::ostringstream os;
if (prec) {
os.setf(std::ios::scientific, std::ios::floatfield);
}
os << "{ ";
if (width) os.width(width);
if (prec) os.precision(prec);
os << x[0];
for (size_t i = 1; i < x.size(); i++) {
os << ", ";
if (width) os.width(width);
if (prec) os.precision(prec);
os << x[i];
}
os << " }";
return os.str();
}
#include "colvarproxy.h"
inline cvm::real cvm::unit_angstrom()
{
return proxy->unit_angstrom();
}
inline cvm::real cvm::boltzmann()
{
return proxy->boltzmann();
}
inline cvm::real cvm::temperature()
{
return proxy->temperature();
}
inline cvm::real cvm::dt()
{
return proxy->dt();
}
// Replica exchange commands
inline bool cvm::replica_enabled() {
return proxy->replica_enabled();
}
inline int cvm::replica_index() {
return proxy->replica_index();
}
inline int cvm::replica_num() {
return proxy->replica_num();
}
inline void cvm::replica_comm_barrier() {
return proxy->replica_comm_barrier();
}
inline int cvm::replica_comm_recv(char* msg_data, int buf_len, int src_rep) {
return proxy->replica_comm_recv(msg_data,buf_len,src_rep);
}
inline int cvm::replica_comm_send(char* msg_data, int msg_len, int dest_rep) {
return proxy->replica_comm_send(msg_data,msg_len,dest_rep);
}
inline void cvm::request_total_force()
{
proxy->request_total_force(true);
}
-inline void cvm::select_closest_image(atom_pos &pos,
- atom_pos const &ref_pos)
-{
- proxy->select_closest_image(pos, ref_pos);
-}
-
-inline void cvm::select_closest_images(std::vector<atom_pos> &pos,
- atom_pos const &ref_pos)
-{
- proxy->select_closest_images(pos, ref_pos);
-}
-
inline cvm::rvector cvm::position_distance(atom_pos const &pos1,
atom_pos const &pos2)
{
return proxy->position_distance(pos1, pos2);
}
inline cvm::real cvm::position_dist2(cvm::atom_pos const &pos1,
cvm::atom_pos const &pos2)
{
return proxy->position_dist2(pos1, pos2);
}
inline cvm::real cvm::rand_gaussian(void)
{
return proxy->rand_gaussian();
}
#endif
diff --git a/lib/colvars/colvarparse.cpp b/lib/colvars/colvarparse.cpp
index 8055d925d..9f333b7b7 100644
--- a/lib/colvars/colvarparse.cpp
+++ b/lib/colvars/colvarparse.cpp
@@ -1,799 +1,798 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <sstream>
#include <iostream>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
// space & tab
-std::string const colvarparse::white_space = " \t";
-
-std::string colvarparse::dummy_string = "";
-size_t colvarparse::dummy_pos = 0;
+char const * const colvarparse::white_space = " \t";
// definition of single-value keyword parsers
template<typename TYPE> bool colvarparse::_get_keyval_scalar_(std::string const &conf,
char const *key,
TYPE &value,
TYPE const &def_value,
Parse_Mode const parse_mode)
{
std::string data;
bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0;
do {
std::string data_this = "";
- b_found = key_lookup(conf, key, data_this, save_pos);
+ b_found = key_lookup(conf, key, &data_this, &save_pos);
if (b_found) {
if (!b_found_any)
b_found_any = true;
found_count++;
data = data_this;
}
} while (b_found);
if (found_count > 1)
cvm::log("Warning: found more than one instance of \""+
std::string(key)+"\".\n");
if (data.size()) {
std::istringstream is(data);
TYPE x(def_value);
if (is >> x) {
value = x;
} else {
cvm::error("Error: in parsing \""+
std::string(key)+"\".\n", INPUT_ERROR);
}
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
cvm::to_str(value)+"\n");
}
} else {
if (b_found_any) {
cvm::error("Error: improper or missing value "
"for \""+std::string(key)+"\".\n", INPUT_ERROR);
}
value = def_value;
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
cvm::to_str(def_value)+" [default]\n");
}
}
return b_found_any;
}
bool colvarparse::_get_keyval_scalar_string_(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value,
Parse_Mode const parse_mode)
{
std::string data;
bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0;
do {
std::string data_this = "";
- b_found = key_lookup(conf, key, data_this, save_pos);
+ b_found = key_lookup(conf, key, &data_this, &save_pos);
if (b_found) {
if (!b_found_any)
b_found_any = true;
found_count++;
data = data_this;
}
} while (b_found);
if (found_count > 1)
cvm::log("Warning: found more than one instance of \""+
std::string(key)+"\".\n");
if (data.size()) {
std::istringstream is(data);
size_t data_count = 0;
std::string x(def_value);
while (is >> x) {
value = x;
data_count++;
}
if (data_count == 0)
cvm::error("Error: in parsing \""+
std::string(key)+"\".\n", INPUT_ERROR);
if (data_count > 1) {
cvm::error("Error: multiple values "
"are not allowed for keyword \""+
std::string(key)+"\".\n", INPUT_ERROR);
}
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = \""+
cvm::to_str(value)+"\"\n");
}
} else {
if (b_found_any) {
cvm::error("Error: improper or missing value "
"for \""+std::string(key)+"\".\n", INPUT_ERROR);
}
value = def_value;
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = \""+
cvm::to_str(def_value)+"\" [default]\n");
}
}
return b_found_any;
}
// multiple-value keyword parsers
template<typename TYPE> bool colvarparse::_get_keyval_vector_(std::string const &conf,
char const *key,
std::vector<TYPE> &values,
std::vector<TYPE> const &def_values,
Parse_Mode const parse_mode)
{
std::string data;
bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0;
do {
std::string data_this = "";
- b_found = key_lookup(conf, key, data_this, save_pos);
+ b_found = key_lookup(conf, key, &data_this, &save_pos);
if (b_found) {
if (!b_found_any)
b_found_any = true;
found_count++;
data = data_this;
}
} while (b_found);
if (found_count > 1)
cvm::log("Warning: found more than one instance of \""+
std::string(key)+"\".\n");
if (data.size()) {
std::istringstream is(data);
if (values.size() == 0) {
std::vector<TYPE> x;
if (def_values.size())
x = def_values;
else
x.assign(1, TYPE());
for (size_t i = 0;
( is >> x[ ((i<x.size()) ? i : x.size()-1) ] );
i++) {
values.push_back(x[ ((i<x.size()) ? i : x.size()-1) ]);
}
} else {
size_t i = 0;
for ( ; i < values.size(); i++) {
TYPE x(values[i]);
if (is >> x) {
values[i] = x;
} else {
cvm::error("Error: in parsing \""+
std::string(key)+"\".\n", INPUT_ERROR);
}
}
}
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
cvm::to_str(values)+"\n");
}
} else {
if (b_found_any) {
cvm::error("Error: improper or missing values for \""+
std::string(key)+"\".\n", INPUT_ERROR);
}
for (size_t i = 0; i < values.size(); i++)
values[i] = def_values[ (i > def_values.size()) ? 0 : i ];
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
cvm::to_str(def_values)+" [default]\n");
}
}
return b_found_any;
}
// single-value keyword parsers
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
int &value,
int const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<int>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
size_t &value,
size_t const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<size_t>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
long &value,
long const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<long>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_string_(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
cvm::real &value,
cvm::real const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<cvm::real>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
cvm::rvector &value,
cvm::rvector const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<cvm::rvector>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
cvm::quaternion &value,
cvm::quaternion const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<cvm::quaternion>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
colvarvalue &value,
colvarvalue const &def_value,
Parse_Mode const parse_mode)
{
return _get_keyval_scalar_<colvarvalue>(conf, key, value, def_value, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
bool &value,
bool const &def_value,
Parse_Mode const parse_mode)
{
std::string data;
bool b_found = false, b_found_any = false;
size_t save_pos = 0, found_count = 0;
do {
std::string data_this = "";
- b_found = key_lookup(conf, key, data_this, save_pos);
+ b_found = key_lookup(conf, key, &data_this, &save_pos);
if (b_found) {
if (!b_found_any)
b_found_any = true;
found_count++;
data = data_this;
}
} while (b_found);
if (found_count > 1)
cvm::log("Warning: found more than one instance of \""+
std::string(key)+"\".\n");
if (data.size()) {
if ( (data == std::string("on")) ||
(data == std::string("yes")) ||
(data == std::string("true")) ) {
value = true;
} else if ( (data == std::string("off")) ||
(data == std::string("no")) ||
(data == std::string("false")) ) {
value = false;
} else
cvm::error("Error: boolean values only are allowed "
"for \""+std::string(key)+"\".\n", INPUT_ERROR);
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
(value ? "on" : "off")+"\n");
}
} else {
if (b_found_any) {
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = on\n");
}
value = true;
} else {
value = def_value;
if (parse_mode != parse_silent) {
cvm::log("# "+std::string(key)+" = "+
(def_value ? "on" : "off")+" [default]\n");
}
}
}
return b_found_any;
}
// multiple-value keyword parsers
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<int> &values,
std::vector<int> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<int>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<size_t> &values,
std::vector<size_t> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<size_t>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<long> &values,
std::vector<long> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<long>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<std::string> &values,
std::vector<std::string> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<std::string>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::real> &values,
std::vector<cvm::real> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<cvm::real>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::rvector> &values,
std::vector<cvm::rvector> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<cvm::rvector>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::quaternion> &values,
std::vector<cvm::quaternion> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<cvm::quaternion>(conf, key, values, def_values, parse_mode);
}
bool colvarparse::get_keyval(std::string const &conf,
char const *key,
std::vector<colvarvalue> &values,
std::vector<colvarvalue> const &def_values,
Parse_Mode const parse_mode)
{
return _get_keyval_vector_<colvarvalue>(conf, key, values, def_values, parse_mode);
}
void colvarparse::add_keyword(char const *key)
{
for (std::list<std::string>::iterator ki = allowed_keywords.begin();
ki != allowed_keywords.end(); ki++) {
if (to_lower_cppstr(std::string(key)) == *ki)
return;
}
// not found in the list
// if (cvm::debug())
// cvm::log("Registering a new keyword, \""+std::string (key)+"\".\n");
allowed_keywords.push_back(to_lower_cppstr(std::string(key)));
}
void colvarparse::strip_values(std::string &conf)
{
size_t offset = 0;
data_begin_pos.sort();
data_end_pos.sort();
std::list<size_t>::iterator data_begin = data_begin_pos.begin();
std::list<size_t>::iterator data_end = data_end_pos.begin();
for ( ; (data_begin != data_begin_pos.end()) &&
(data_end != data_end_pos.end()) ;
data_begin++, data_end++) {
// std::cerr << "data_begin, data_end "
// << *data_begin << ", " << *data_end
// << "\n";
size_t const nchars = *data_end-*data_begin;
// std::cerr << "conf[data_begin:data_end] = \""
// << std::string (conf, *data_begin - offset, nchars)
// << "\"\n";
conf.erase(*data_begin - offset, nchars);
offset += nchars;
// std::cerr << ("Stripped config = \"\n"+conf+"\"\n");
}
}
void colvarparse::clear_keyword_registry()
{
allowed_keywords.clear();
data_begin_pos.clear();
data_end_pos.clear();
}
int colvarparse::check_keywords(std::string &conf, char const *key)
{
if (cvm::debug())
cvm::log("Configuration string for \""+std::string(key)+
"\": \"\n"+conf+"\".\n");
strip_values(conf);
// after stripping, the config string has either empty lines, or
// lines beginning with a keyword
std::string line;
std::istringstream is(conf);
while (cvm::getline(is, line)) {
if (line.size() == 0)
continue;
if (line.find_first_not_of(white_space) ==
std::string::npos)
continue;
std::string uk;
std::istringstream line_is(line);
line_is >> uk;
// if (cvm::debug())
// cvm::log ("Checking the validity of \""+uk+"\" from line:\n" + line);
uk = to_lower_cppstr(uk);
bool found_keyword = false;
for (std::list<std::string>::iterator ki = allowed_keywords.begin();
ki != allowed_keywords.end(); ki++) {
if (uk == *ki) {
found_keyword = true;
break;
}
}
if (!found_keyword) {
cvm::error("Error: keyword \""+uk+"\" is not supported, "
"or not recognized in this context.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
clear_keyword_registry();
return COLVARS_OK;
}
std::istream & colvarparse::getline_nocomments(std::istream &is,
std::string &line)
{
cvm::getline(is, line);
size_t const comment = line.find('#');
if (comment != std::string::npos) {
line.erase(comment);
}
return is;
}
bool colvarparse::key_lookup(std::string const &conf,
char const *key_in,
- std::string &data,
- size_t &save_pos)
+ std::string *data,
+ size_t *save_pos)
{
if (cvm::debug()) {
cvm::log("Looking for the keyword \""+std::string(key_in)+"\" and its value.\n");
}
// add this keyword to the register (in its camelCase version)
add_keyword(key_in);
// use the lowercase version from now on
std::string const key(to_lower_cppstr(key_in));
// "conf_lower" is only used to lookup the keyword, but its value
// will be read from "conf", in order not to mess up file names
std::string const conf_lower(to_lower_cppstr(conf));
// by default, there is no value, unless we found one
- data = "";
-
- // when the function is invoked without save_pos, ensure that we
- // start from zero
- colvarparse::dummy_pos = 0;
+ if (data != NULL) {
+ data->clear();
+ }
// start from the first occurrence of key
- size_t pos = conf_lower.find(key, save_pos);
+ size_t pos = conf_lower.find(key, (save_pos != NULL) ? *save_pos : 0);
// iterate over all instances of the substring until it finds it as isolated keyword
while (true) {
if (pos == std::string::npos) {
// no valid instance of the keyword has been found
if (cvm::debug()) {
cvm::log("Keyword \""+std::string(key_in)+"\" not found.\n");
}
return false;
}
bool b_isolated_left = true, b_isolated_right = true;
if (pos > 0) {
- if ( std::string("\n"+white_space+
+ if ( std::string("\n"+std::string(white_space)+
"}").find(conf[pos-1]) ==
std::string::npos ) {
// none of the valid delimiting characters is on the left of key
b_isolated_left = false;
}
}
if (pos < conf.size()-key.size()-1) {
- if ( std::string("\n"+white_space+
+ if ( std::string("\n"+std::string(white_space)+
"{").find(conf[pos+key.size()]) ==
std::string::npos ) {
// none of the valid delimiting characters is on the right of key
b_isolated_right = false;
}
}
// check that there are matching braces between here and the end of conf
bool const b_not_within_block = brace_check(conf, pos);
bool const b_isolated = (b_isolated_left && b_isolated_right &&
b_not_within_block);
if (b_isolated) {
// found it
break;
} else {
// try the next occurrence of key
pos = conf_lower.find(key, pos+key.size());
}
}
+ if (save_pos != NULL) {
// save the pointer for a future call (when iterating over multiple
// valid instances of the same keyword)
- save_pos = pos + key.size();
+ *save_pos = pos + key.size();
+ }
// get the remainder of the line
size_t pl = conf.rfind("\n", pos);
size_t line_begin = (pl == std::string::npos) ? 0 : pos;
size_t nl = conf.find("\n", pos);
size_t line_end = (nl == std::string::npos) ? conf.size() : nl;
std::string line(conf, line_begin, (line_end-line_begin));
size_t data_begin = (to_lower_cppstr(line)).find(key) + key.size();
data_begin = line.find_first_not_of(white_space, data_begin+1);
if (data_begin != std::string::npos) {
size_t data_end = line.find_last_not_of(white_space) + 1;
data_end = (data_end == std::string::npos) ? line.size() : data_end;
size_t brace = line.find('{', data_begin); // look for an opening brace
size_t brace_last = brace;
if (brace != std::string::npos) {
// find the matching closing brace
// if (cvm::debug()) {
// cvm::log("Multi-line value, config is now \""+line+"\".\n");
// }
int brace_count = 1;
while (brace_count > 0) {
brace = line.find_first_of("{}", brace_last+1);
// find all braces within this line
while (brace < std::string::npos) {
brace_last = brace;
if (line[brace] == '{') brace_count++;
if (line[brace] == '}') brace_count--;
if (brace_count == 0) {
data_end = brace+1;
break;
}
brace = line.find_first_of("{}", brace+1);
}
if (brace_count == 0) {
data_end = brace+1;
break;
}
if (brace == std::string::npos) {
// add a new line
if (line_end >= conf.size()) {
cvm::error("Parse error: reached the end while "
"looking for closing brace; until now "
"the following was parsed: \"\n"+
line+"\".\n", INPUT_ERROR);
return false;
}
line_begin = line_end;
nl = conf.find('\n', line_begin+1);
if (nl == std::string::npos)
line_end = conf.size();
else
line_end = nl;
line.append(conf, line_begin, (line_end-line_begin));
// if (cvm::debug()) {
// cvm::log("Added a new line, config is now \""+line+"\".\n");
// }
}
if (brace_count < 0) {
cvm::error("Error: found closing brace without opening brace.\n", INPUT_ERROR);
}
}
// strip the leading and trailing braces
data_begin = line.find_first_of('{') + 1;
data_begin = line.find_first_not_of(white_space,
data_begin);
data_end = line.find_last_of('}', line.size()) - 1;
data_end = line.find_last_not_of(white_space,
data_end) + 1;
}
- data.append(line, data_begin, (data_end-data_begin));
+ if (data != NULL) {
+ data->append(line, data_begin, (data_end-data_begin));
- if (cvm::debug()) {
- cvm::log("Keyword value = \""+data+"\".\n");
- }
+ if (cvm::debug()) {
+ cvm::log("Keyword value = \""+*data+"\".\n");
+ }
- if (data.size() && save_delimiters) {
- data_begin_pos.push_back(conf.find(data, pos+key.size()));
- data_end_pos.push_back(data_begin_pos.back()+data.size());
+ if (data->size()) {
+ data_begin_pos.push_back(conf.find(*data, pos+key.size()));
+ data_end_pos.push_back(data_begin_pos.back()+data->size());
+ }
}
}
- save_pos = line_end;
+ if (save_pos != NULL) *save_pos = line_end;
return true;
}
std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb)
{
size_t start_pos = is.tellg();
std::string read_key, next;
if ( !(is >> read_key) || !(read_key == rb.key) ||
!(is >> next) ) {
// the requested keyword has not been found, or it is not possible
// to read data after it
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
if (next != "{") {
(*rb.data) = next;
return is;
}
size_t brace_count = 1;
std::string line;
while (colvarparse::getline_nocomments(is, line)) {
size_t br = 0, br_old = 0;
while ( (br = line.find_first_of("{}", br)) != std::string::npos) {
if (line[br] == '{') brace_count++;
if (line[br] == '}') brace_count--;
br_old = br;
br++;
}
if (brace_count) (*rb.data).append(line + "\n");
else {
(*rb.data).append(line, 0, br_old);
break;
}
}
if (brace_count) {
// end-of-file reached
// restore initial position
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
}
return is;
}
bool colvarparse::brace_check(std::string const &conf,
size_t const start_pos)
{
size_t brace_count = 0;
size_t brace = start_pos;
while ( (brace = conf.find_first_of("{}", brace)) != std::string::npos) {
if (conf[brace] == '{') brace_count++;
if (conf[brace] == '}') brace_count--;
brace++;
}
if (brace_count != 0)
return false;
else
return true;
}
diff --git a/lib/colvars/colvarparse.h b/lib/colvars/colvarparse.h
index 9f116caaf..9389bc49d 100644
--- a/lib/colvars/colvarparse.h
+++ b/lib/colvars/colvarparse.h
@@ -1,316 +1,299 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARPARSE_H
#define COLVARPARSE_H
#include <cstring>
#include <string>
#include "colvarmodule.h"
#include "colvarvalue.h"
/// \file colvarparse.h Parsing functions for collective variables
/// \brief Base class containing parsing functions; all objects which
/// need to parse input inherit from this
class colvarparse {
-protected:
+private:
/// \brief List of legal keywords for this object: this is updated
/// by each call to colvarparse::get_keyval() or
/// colvarparse::key_lookup()
std::list<std::string> allowed_keywords;
/// \brief List of delimiters for the values of each keyword in the
/// configuration string; all keywords will be stripped of their
/// values before the keyword check is performed
std::list<size_t> data_begin_pos;
/// \brief List of delimiters for the values of each keyword in the
/// configuration string; all keywords will be stripped of their
/// values before the keyword check is performed
std::list<size_t> data_end_pos;
- /// \brief Whether or not to accumulate data_begin_pos and
- /// data_end_pos in key_lookup(); it may be useful to disable
- /// this after the constructor is called, because other files may be
- /// read (e.g. restart) that would mess up the registry; in any
- /// case, nothing serious happens until check_keywords() is invoked
- /// (which should happen only right after construction)
- bool save_delimiters;
-
/// \brief Add a new valid keyword to the list
void add_keyword(char const *key);
/// \brief Remove all the values from the config string
void strip_values(std::string &conf);
/// \brief Configuration string of the object
std::string config_string;
public:
inline colvarparse()
- : save_delimiters(true)
{
init();
}
/// Constructor that stores the object's config string
inline colvarparse(const std::string& conf)
- : save_delimiters(true)
{
init(conf);
}
/// Set the object ready to parse a new configuration string
inline void init()
{
config_string.clear();
clear_keyword_registry();
}
/// Set a new config string for this object
inline void init(const std::string& conf)
{
if (! config_string.size()) {
init();
config_string = conf;
}
}
inline const std::string& get_config()
{
return config_string;
}
/// How a keyword is parsed in a string
enum Parse_Mode {
/// \brief(default) Read the first instance of a keyword (if
/// any), report its value, and print a warning when there is more
/// than one
parse_normal,
/// \brief Like parse_normal, but don't send any message to the log
/// (useful e.g. in restart files when such messages are very
/// numerous and redundant)
parse_silent
};
/// \brief Check that all the keywords within "conf" are in the list
/// of allowed keywords; this will invoke strip_values() first and
/// then loop over all words
int check_keywords(std::string &conf, char const *key);
/// \brief Use this after parsing a config string (note that check_keywords() calls it already)
void clear_keyword_registry();
-public:
-
/// \fn get_keyval bool const get_keyval (std::string const &conf,
/// char const *key, _type_ &value, _type_ const &def_value,
/// Parse_Mode const parse_mode) \brief Helper function to parse
/// keywords in the configuration and get their values
///
/// In normal circumstances, you should use either version the
/// get_keyval function. Both of them look for the C string "key"
/// in the C++ string "conf", and assign the corresponding value (if
/// available) to the variable "value" (first version), or assign as
/// many values as found to the vector "values" (second version).
///
/// If "key" is found but no value is associated to it, the default
/// value is provided (either one copy or as many copies as the
/// current length of the vector "values" specifies). A message
/// will print, unless parse_mode is equal to parse_silent. The
/// return value of both forms of get_keyval is true if "key" is
/// found (with or without value), and false when "key" is absent in
/// the string "conf". If there is more than one instance of the
/// keyword, a warning will be raised; instead, to loop over
/// multiple instances key_lookup() should be invoked directly.
///
/// If you introduce a new data type, add two new instances of this
/// functions, or insert this type in the \link colvarvalue \endlink
/// wrapper class (colvarvalue.h).
bool get_keyval(std::string const &conf,
char const *key,
int &value,
int const &def_value = (int)0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
size_t &value,
size_t const &def_value = (size_t)0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
long &value,
long const &def_value = 0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value = std::string(""),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::real &value,
cvm::real const &def_value = (cvm::real)0.0,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::rvector &value,
cvm::rvector const &def_value = cvm::rvector(),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
cvm::quaternion &value,
cvm::quaternion const &def_value = cvm::quaternion(),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
colvarvalue &value,
colvarvalue const &def_value = colvarvalue(colvarvalue::type_notset),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
bool &value,
bool const &def_value = false,
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<int> &values,
std::vector<int> const &def_values = std::vector<int>(0, (int)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<size_t> &values,
std::vector<size_t> const &def_values = std::vector<size_t>(0, (size_t)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<long> &values,
std::vector<long> const &def_values = std::vector<long>(0, (long)0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<std::string> &values,
std::vector<std::string> const &def_values = std::vector<std::string>(0, std::string("")),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::real> &values,
std::vector<cvm::real> const &def_values = std::vector<cvm::real>(0, (cvm::real)0.0),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::rvector> &values,
std::vector<cvm::rvector> const &def_values = std::vector<cvm::rvector>(0, cvm::rvector()),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<cvm::quaternion> &values,
std::vector<cvm::quaternion> const &def_values = std::vector<cvm::quaternion>(0, cvm::quaternion()),
Parse_Mode const parse_mode = parse_normal);
bool get_keyval(std::string const &conf,
char const *key,
std::vector<colvarvalue> &values,
std::vector<colvarvalue> const &def_values = std::vector<colvarvalue>(0, colvarvalue(colvarvalue::type_notset)),
Parse_Mode const parse_mode = parse_normal);
protected:
// Templates
template<typename TYPE> bool _get_keyval_scalar_(std::string const &conf,
char const *key,
TYPE &value,
TYPE const &def_value,
Parse_Mode const parse_mode);
bool _get_keyval_scalar_string_(std::string const &conf,
char const *key,
std::string &value,
std::string const &def_value,
Parse_Mode const parse_mode);
template<typename TYPE> bool _get_keyval_vector_(std::string const &conf,
char const *key,
std::vector<TYPE> &values,
std::vector<TYPE> const &def_values,
Parse_Mode const parse_mode);
public:
/// \brief Return a lowercased copy of the string
static inline std::string to_lower_cppstr(std::string const &in)
{
std::string out = "";
for (size_t i = 0; i < in.size(); i++) {
out.append(1, (char) ::tolower(in[i]) );
}
return out;
}
/// \brief Helper class to read a block of the type "key { ... }"
/// from a stream and store it in a string
///
/// Useful on restarts, where the file is too big to be loaded in a
/// string by key_lookup; it can only check that the keyword is
/// correct and the block is properly delimited by braces, not
/// skipping other blocks
class read_block {
std::string const key;
std::string * const data;
public:
inline read_block(std::string const &key_in, std::string &data_in)
: key(key_in), data(&data_in)
{}
inline ~read_block() {}
friend std::istream & operator >> (std::istream &is, read_block const &rb);
};
/// Accepted white space delimiters, used in key_lookup()
- static std::string const white_space;
+ static const char * const white_space;
/// \brief Low-level function for parsing configuration strings;
/// automatically adds the requested keyword to the list of valid
/// ones. \param conf the content of the configuration file or one
/// of its blocks \param key the keyword to search within "conf" \param
/// data (optional) holds the string provided after "key", if any
/// \param save_pos (optional) stores the position of the keyword
/// within "conf", useful when doing multiple calls
bool key_lookup(std::string const &conf,
char const *key,
- std::string &data = dummy_string,
- size_t &save_pos = dummy_pos);
-
- /// Used as a default argument by key_lookup
- static std::string dummy_string;
- /// Used as a default argument by key_lookup
- static size_t dummy_pos;
+ std::string *data = NULL,
+ size_t *save_pos = NULL);
/// \brief Works as std::getline() but also removes everything
/// between a comment character and the following newline
static std::istream & getline_nocomments(std::istream &is,
std::string &s);
/// Check if the content of the file has matching braces
bool brace_check(std::string const &conf,
size_t const start_pos = 0);
};
#endif
diff --git a/lib/colvars/colvarproxy.cpp b/lib/colvars/colvarproxy.cpp
new file mode 100644
index 000000000..fa24091d5
--- /dev/null
+++ b/lib/colvars/colvarproxy.cpp
@@ -0,0 +1,492 @@
+// -*- c++ -*-
+
+// This file is part of the Collective Variables module (Colvars).
+// The original version of Colvars and its updates are located at:
+// https://github.com/colvars/colvars
+// Please update all Colvars source files before making any changes.
+// If you wish to distribute your changes, please submit them to the
+// Colvars repository at GitHub.
+
+#include <sstream>
+#include <string.h>
+
+#include "colvarmodule.h"
+#include "colvarproxy.h"
+#include "colvarscript.h"
+#include "colvaratoms.h"
+
+
+
+colvarproxy_system::colvarproxy_system() {}
+
+
+colvarproxy_system::~colvarproxy_system() {}
+
+
+void colvarproxy_system::add_energy(cvm::real energy) {}
+
+
+void colvarproxy_system::request_total_force(bool yesno)
+{
+ if (yesno == true)
+ cvm::error("Error: total forces are currently not implemented.\n",
+ COLVARS_NOT_IMPLEMENTED);
+}
+
+
+bool colvarproxy_system::total_forces_enabled() const
+{
+ return false;
+}
+
+
+cvm::real colvarproxy_system::position_dist2(cvm::atom_pos const &pos1,
+ cvm::atom_pos const &pos2)
+{
+ return (position_distance(pos1, pos2)).norm2();
+}
+
+
+
+colvarproxy_atoms::colvarproxy_atoms() {}
+
+
+colvarproxy_atoms::~colvarproxy_atoms()
+{
+ reset();
+}
+
+
+int colvarproxy_atoms::reset()
+{
+ atoms_ids.clear();
+ atoms_ncopies.clear();
+ atoms_masses.clear();
+ atoms_charges.clear();
+ atoms_positions.clear();
+ atoms_total_forces.clear();
+ atoms_new_colvar_forces.clear();
+ return COLVARS_OK;
+}
+
+
+int colvarproxy_atoms::add_atom_slot(int atom_id)
+{
+ atoms_ids.push_back(atom_id);
+ atoms_ncopies.push_back(1);
+ atoms_masses.push_back(1.0);
+ atoms_charges.push_back(0.0);
+ atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ return (atoms_ids.size() - 1);
+}
+
+
+int colvarproxy_atoms::init_atom(cvm::residue_id const &residue,
+ std::string const &atom_name,
+ std::string const &segment_id)
+{
+ cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n",
+ COLVARS_NOT_IMPLEMENTED);
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_atoms::check_atom_id(cvm::residue_id const &residue,
+ std::string const &atom_name,
+ std::string const &segment_id)
+{
+ colvarproxy_atoms::init_atom(residue, atom_name, segment_id);
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+void colvarproxy_atoms::clear_atom(int index)
+{
+ if (((size_t) index) >= atoms_ids.size()) {
+ cvm::error("Error: trying to disable an atom that was not previously requested.\n",
+ INPUT_ERROR);
+ }
+ if (atoms_ncopies[index] > 0) {
+ atoms_ncopies[index] -= 1;
+ }
+}
+
+
+int colvarproxy_atoms::load_atoms(char const *filename,
+ cvm::atom_group &atoms,
+ std::string const &pdb_field,
+ double const)
+{
+ return cvm::error("Error: loading atom identifiers from a file "
+ "is currently not implemented.\n",
+ COLVARS_NOT_IMPLEMENTED);
+}
+
+
+int colvarproxy_atoms::load_coords(char const *filename,
+ std::vector<cvm::atom_pos> &pos,
+ const std::vector<int> &indices,
+ std::string const &pdb_field,
+ double const)
+{
+ return cvm::error("Error: loading atomic coordinates from a file "
+ "is currently not implemented.\n",
+ COLVARS_NOT_IMPLEMENTED);
+}
+
+
+
+colvarproxy_atom_groups::colvarproxy_atom_groups() {}
+
+
+colvarproxy_atom_groups::~colvarproxy_atom_groups()
+{
+ reset();
+}
+
+
+int colvarproxy_atom_groups::reset()
+{
+ atom_groups_ids.clear();
+ atom_groups_ncopies.clear();
+ atom_groups_masses.clear();
+ atom_groups_charges.clear();
+ atom_groups_coms.clear();
+ atom_groups_total_forces.clear();
+ atom_groups_new_colvar_forces.clear();
+ return COLVARS_OK;
+}
+
+
+int colvarproxy_atom_groups::add_atom_group_slot(int atom_group_id)
+{
+ atom_groups_ids.push_back(atom_group_id);
+ atom_groups_ncopies.push_back(1);
+ atom_groups_masses.push_back(1.0);
+ atom_groups_charges.push_back(0.0);
+ atom_groups_coms.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ atom_groups_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ atom_groups_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
+ return (atom_groups_ids.size() - 1);
+}
+
+
+int colvarproxy_atom_groups::scalable_group_coms()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_atom_groups::init_atom_group(std::vector<int> const &atoms_ids)
+{
+ cvm::error("Error: initializing a group outside of the Colvars module "
+ "is currently not supported.\n",
+ COLVARS_NOT_IMPLEMENTED);
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+void colvarproxy_atom_groups::clear_atom_group(int index)
+{
+ if (((size_t) index) >= atom_groups_ids.size()) {
+ cvm::error("Error: trying to disable an atom group "
+ "that was not previously requested.\n",
+ INPUT_ERROR);
+ }
+ if (atom_groups_ncopies[index] > 0) {
+ atom_groups_ncopies[index] -= 1;
+ }
+}
+
+
+
+colvarproxy_smp::colvarproxy_smp()
+{
+ b_smp_active = true;
+}
+
+
+colvarproxy_smp::~colvarproxy_smp() {}
+
+
+int colvarproxy_smp::smp_enabled()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_colvars_loop()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_biases_loop()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_biases_script_loop()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_thread_id()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_num_threads()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_smp::smp_lock()
+{
+ return COLVARS_OK;
+}
+
+
+int colvarproxy_smp::smp_trylock()
+{
+ return COLVARS_OK;
+}
+
+
+int colvarproxy_smp::smp_unlock()
+{
+ return COLVARS_OK;
+}
+
+
+
+
+colvarproxy_replicas::colvarproxy_replicas() {}
+
+
+colvarproxy_replicas::~colvarproxy_replicas() {}
+
+
+bool colvarproxy_replicas::replica_enabled()
+{
+ return false;
+}
+
+
+int colvarproxy_replicas::replica_index()
+{
+ return 0;
+}
+
+
+int colvarproxy_replicas::replica_num()
+{
+ return 1;
+}
+
+
+void colvarproxy_replicas::replica_comm_barrier() {}
+
+
+int colvarproxy_replicas::replica_comm_recv(char* msg_data,
+ int buf_len,
+ int src_rep)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_replicas::replica_comm_send(char* msg_data,
+ int msg_len,
+ int dest_rep)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+
+
+colvarproxy_script::colvarproxy_script()
+{
+ script = NULL;
+}
+
+
+colvarproxy_script::~colvarproxy_script() {}
+
+
+char *colvarproxy_script::script_obj_to_str(unsigned char *obj)
+{
+ return reinterpret_cast<char *>(obj);
+}
+
+
+int colvarproxy_script::run_force_callback()
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_script::run_colvar_callback(
+ std::string const &name,
+ std::vector<const colvarvalue *> const &cvcs,
+ colvarvalue &value)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_script::run_colvar_gradient_callback(
+ std::string const &name,
+ std::vector<const colvarvalue *> const &cvcs,
+ std::vector<cvm::matrix2d<cvm::real> > &gradient)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+
+
+colvarproxy_io::colvarproxy_io() {}
+
+
+colvarproxy_io::~colvarproxy_io() {}
+
+
+int colvarproxy_io::get_frame(long int&)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+int colvarproxy_io::set_frame(long int)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+std::ostream * colvarproxy_io::output_stream(std::string const &output_name,
+ std::ios_base::openmode mode)
+{
+ if (cvm::debug()) {
+ cvm::log("Using colvarproxy::output_stream()\n");
+ }
+ std::list<std::ostream *>::iterator osi = output_files.begin();
+ std::list<std::string>::iterator osni = output_stream_names.begin();
+ for ( ; osi != output_files.end(); osi++, osni++) {
+ if (*osni == output_name) {
+ return *osi;
+ }
+ }
+ if (!(mode & (std::ios_base::app | std::ios_base::ate))) {
+ backup_file(output_name);
+ }
+ std::ofstream *os = new std::ofstream(output_name.c_str(), mode);
+ if (!os->is_open()) {
+ cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n",
+ FILE_ERROR);
+ return NULL;
+ }
+ output_stream_names.push_back(output_name);
+ output_files.push_back(os);
+ return os;
+}
+
+
+int colvarproxy_io::flush_output_stream(std::ostream *os)
+{
+ std::list<std::ostream *>::iterator osi = output_files.begin();
+ std::list<std::string>::iterator osni = output_stream_names.begin();
+ for ( ; osi != output_files.end(); osi++, osni++) {
+ if (*osi == os) {
+ ((std::ofstream *) (*osi))->flush();
+ return COLVARS_OK;
+ }
+ }
+ return cvm::error("Error: trying to flush an output file/channel "
+ "that wasn't open.\n", BUG_ERROR);
+}
+
+
+int colvarproxy_io::close_output_stream(std::string const &output_name)
+{
+ std::list<std::ostream *>::iterator osi = output_files.begin();
+ std::list<std::string>::iterator osni = output_stream_names.begin();
+ for ( ; osi != output_files.end(); osi++, osni++) {
+ if (*osni == output_name) {
+ ((std::ofstream *) (*osi))->close();
+ output_files.erase(osi);
+ output_stream_names.erase(osni);
+ return COLVARS_OK;
+ }
+ }
+ return cvm::error("Error: trying to close an output file/channel "
+ "that wasn't open.\n", BUG_ERROR);
+}
+
+
+int colvarproxy_io::backup_file(char const *filename)
+{
+ return COLVARS_NOT_IMPLEMENTED;
+}
+
+
+
+colvarproxy::colvarproxy()
+{
+ colvars = NULL;
+ b_simulation_running = true;
+}
+
+
+colvarproxy::~colvarproxy() {}
+
+
+int colvarproxy::reset()
+{
+ int error_code = COLVARS_OK;
+ error_code |= colvarproxy_atoms::reset();
+ error_code |= colvarproxy_atom_groups::reset();
+ return error_code;
+}
+
+
+int colvarproxy::setup()
+{
+ return COLVARS_OK;
+}
+
+
+int colvarproxy::update_input()
+{
+ return COLVARS_OK;
+}
+
+
+int colvarproxy::update_output()
+{
+ return COLVARS_OK;
+}
+
+
+size_t colvarproxy::restart_frequency()
+{
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h
index 5b216c9d4..95d13cd7e 100644
--- a/lib/colvars/colvarproxy.h
+++ b/lib/colvars/colvarproxy.h
@@ -1,647 +1,589 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARPROXY_H
#define COLVARPROXY_H
#include <fstream>
#include <list>
#include "colvarmodule.h"
#include "colvarvalue.h"
+
+/// \file colvarproxy.h
+/// \brief Colvars proxy classes
+///
+/// This file declares the class for the object responsible for interfacing
+/// Colvars with other codes (MD engines, VMD, Python). The \link colvarproxy
+/// \endlink class is a derivative of multiple classes, each devoted to a
+/// specific task (e.g. \link colvarproxy_atoms \endlink to access data for
+/// individual atoms).
+///
+/// To interface to a new MD engine, the simplest solution is to derive a new
+/// class from \link colvarproxy \endlink. Currently implemented are: \link
+/// colvarproxy_lammps, \endlink, \link colvarproxy_namd, \endlink, \link
+/// colvarproxy_vmd, \endlink.
+
+
// forward declarations
class colvarscript;
-/// \brief Interface between the collective variables module and
-/// the simulation or analysis program (NAMD, VMD, LAMMPS...).
-/// This is the base class: each interfaced program is supported by a derived class.
-/// Only pure virtual functions ("= 0") must be reimplemented to ensure baseline functionality.
-class colvarproxy {
+/// Methods for accessing the simulation system (PBCs, integrator, etc)
+class colvarproxy_system {
public:
- /// Pointer to the main object
- colvarmodule *colvars;
-
/// Constructor
- colvarproxy()
- {
- colvars = NULL;
- b_simulation_running = true;
- b_smp_active = true;
- script = NULL;
- }
+ colvarproxy_system();
/// Destructor
- virtual ~colvarproxy()
- {}
-
- /// (Re)initialize required member data after construction
- virtual int setup()
- {
- return COLVARS_OK;
- }
-
- /// \brief Update data required by the colvars module (e.g. cache atom positions)
- ///
- /// TODO Break up colvarproxy_namd and colvarproxy_lammps function into these
- virtual int update_input()
- {
- return COLVARS_OK;
- }
-
- /// \brief Update data based from the results of a module update (e.g. send forces)
- virtual int update_output()
- {
- return COLVARS_OK;
- }
-
- // **************** SIMULATION PARAMETERS ****************
+ virtual ~colvarproxy_system();
/// \brief Value of the unit for atomic coordinates with respect to
/// angstroms (used by some variables for hard-coded default values)
virtual cvm::real unit_angstrom() = 0;
/// \brief Boltzmann constant
virtual cvm::real boltzmann() = 0;
- /// \brief Temperature of the simulation (K)
+ /// \brief Target temperature of the simulation (K units)
virtual cvm::real temperature() = 0;
/// \brief Time step of the simulation (fs)
virtual cvm::real dt() = 0;
/// \brief Pseudo-random number with Gaussian distribution
virtual cvm::real rand_gaussian(void) = 0;
- /// \brief Get the current frame number
- // Returns error code
- virtual int get_frame(long int&) { return COLVARS_NOT_IMPLEMENTED; }
-
- /// \brief Set the current frame number (as well as colvarmodule::it)
- // Returns error code
- virtual int set_frame(long int) { return COLVARS_NOT_IMPLEMENTED; }
+ /// Pass restraint energy value for current timestep to MD engine
+ virtual void add_energy(cvm::real energy) = 0;
- /// \brief Prefix to be used for input files (restarts, not
- /// configuration)
- std::string input_prefix_str, output_prefix_str, restart_output_prefix_str;
+ /// \brief Get the PBC-aware distance vector between two positions
+ virtual cvm::rvector position_distance(cvm::atom_pos const &pos1,
+ cvm::atom_pos const &pos2) = 0;
- inline std::string & input_prefix()
- {
- return input_prefix_str;
- }
+ /// \brief Get the PBC-aware square distance between two positions;
+ /// may need to be reimplemented independently from position_distance() for optimization purposes
+ virtual cvm::real position_dist2(cvm::atom_pos const &pos1,
+ cvm::atom_pos const &pos2);
- /// \brief Prefix to be used for output restart files
- inline std::string restart_output_prefix()
- {
- return restart_output_prefix_str;
- }
+ /// Tell the proxy whether total forces are needed (may not always be available)
+ virtual void request_total_force(bool yesno);
- /// \brief Prefix to be used for output files (final system
- /// configuration)
- inline std::string output_prefix()
- {
- return output_prefix_str;
- }
+ /// Are total forces being used?
+ virtual bool total_forces_enabled() const;
+};
- /// \brief Restarts will be written each time this number of steps has passed
- virtual size_t restart_frequency()
- {
- return 0;
- }
-protected:
-
- /// Whether a simulation is running (and try to prevent irrecovarable errors)
- bool b_simulation_running;
+/// \brief Container of atomic data for processing by Colvars
+class colvarproxy_atoms {
public:
- /// Whether a simulation is running (and try to prevent irrecovarable errors)
- virtual bool simulation_running() const
- {
- return b_simulation_running;
- }
-
-protected:
+ /// Constructor
+ colvarproxy_atoms();
- /// \brief Currently opened output files: by default, these are ofstream objects.
- /// Allows redefinition to implement different output mechanisms
- std::list<std::ostream *> output_files;
- /// \brief Identifiers for output_stream objects: by default, these are the names of the files
- std::list<std::string> output_stream_names;
+ /// Destructor
+ virtual ~colvarproxy_atoms();
-public:
+ /// Prepare this atom for collective variables calculation, selecting it by
+ /// numeric index (1-based)
+ virtual int init_atom(int atom_number) = 0;
- // ***************** SHARED-MEMORY PARALLELIZATION *****************
+ /// Check that this atom number is valid, but do not initialize the
+ /// corresponding atom yet
+ virtual int check_atom_id(int atom_number) = 0;
- /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature)
- virtual int smp_enabled()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// Select this atom for collective variables calculation, using name and
+ /// residue number. Not all programs support this: leave this function as
+ /// is in those cases.
+ virtual int init_atom(cvm::residue_id const &residue,
+ std::string const &atom_name,
+ std::string const &segment_id);
- /// Whether threaded parallelization should be used (TODO: make this a cvm::deps feature)
- bool b_smp_active;
+ /// Check that this atom is valid, but do not initialize it yet
+ virtual int check_atom_id(cvm::residue_id const &residue,
+ std::string const &atom_name,
+ std::string const &segment_id);
- /// Distribute calculation of colvars (and their components) across threads
- virtual int smp_colvars_loop()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// \brief Used by the atom class destructor: rather than deleting the array slot
+ /// (costly) set the corresponding atoms_ncopies to zero
+ virtual void clear_atom(int index);
- /// Distribute calculation of biases across threads
- virtual int smp_biases_loop()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// \brief Read atom identifiers from a file \param filename name of
+ /// the file (usually a PDB) \param atoms array to which atoms read
+ /// from "filename" will be appended \param pdb_field (optiona) if
+ /// "filename" is a PDB file, use this field to determine which are
+ /// the atoms to be set
+ virtual int load_atoms(char const *filename,
+ cvm::atom_group &atoms,
+ std::string const &pdb_field,
+ double const pdb_field_value = 0.0);
- /// Distribute calculation of biases across threads 2nd through last, with all scripted biased on 1st thread
- virtual int smp_biases_script_loop()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// \brief Load the coordinates for a group of atoms from a file
+ /// (usually a PDB); if "pos" is already allocated, the number of its
+ /// elements must match the number of atoms in "filename"
+ virtual int load_coords(char const *filename,
+ std::vector<cvm::atom_pos> &pos,
+ const std::vector<int> &indices,
+ std::string const &pdb_field,
+ double const pdb_field_value = 0.0);
- /// Index of this thread
- virtual int smp_thread_id()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// Clear atomic data
+ int reset();
- /// Number of threads sharing this address space
- virtual int smp_num_threads()
+ /// Get the numeric ID of the given atom (for the program)
+ inline int get_atom_id(int index) const
{
- return COLVARS_NOT_IMPLEMENTED;
+ return atoms_ids[index];
}
- /// Lock the proxy's shared data for access by a thread, if threads are implemented; if not implemented, does nothing
- virtual int smp_lock()
+ /// Get the mass of the given atom
+ inline cvm::real get_atom_mass(int index) const
{
- return COLVARS_OK;
+ return atoms_masses[index];
}
- /// Attempt to lock the proxy's shared data
- virtual int smp_trylock()
+ /// Get the charge of the given atom
+ inline cvm::real get_atom_charge(int index) const
{
- return COLVARS_OK;
+ return atoms_charges[index];
}
- /// Release the lock
- virtual int smp_unlock()
+ /// Read the current position of the given atom
+ inline cvm::rvector get_atom_position(int index) const
{
- return COLVARS_OK;
- }
-
- // **************** MULTIPLE REPLICAS COMMUNICATION ****************
-
- // Replica exchange commands:
-
- /// \brief Indicate if multi-replica support is available and active
- virtual bool replica_enabled() { return false; }
-
- /// \brief Index of this replica
- virtual int replica_index() { return 0; }
-
- /// \brief Total number of replica
- virtual int replica_num() { return 1; }
-
- /// \brief Synchronize replica
- virtual void replica_comm_barrier() {}
-
- /// \brief Receive data from other replica
- virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep) {
- return COLVARS_NOT_IMPLEMENTED;
- }
-
- /// \brief Send data to other replica
- virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep) {
- return COLVARS_NOT_IMPLEMENTED;
+ return atoms_positions[index];
}
-
- // **************** SCRIPTING INTERFACE ****************
-
- /// Pointer to the scripting interface object
- /// (does not need to be allocated in a new interface)
- colvarscript *script;
-
- /// is a user force script defined?
- bool force_script_defined;
-
- /// Do we have a scripting interface?
- bool have_scripts;
-
- /// Run a user-defined colvar forces script
- virtual int run_force_callback() { return COLVARS_NOT_IMPLEMENTED; }
-
- virtual int run_colvar_callback(std::string const &name,
- std::vector<const colvarvalue *> const &cvcs,
- colvarvalue &value)
- { return COLVARS_NOT_IMPLEMENTED; }
-
- virtual int run_colvar_gradient_callback(std::string const &name,
- std::vector<const colvarvalue *> const &cvcs,
- std::vector<cvm::matrix2d<cvm::real> > &gradient)
- { return COLVARS_NOT_IMPLEMENTED; }
-
-
- // **************** INPUT/OUTPUT ****************
-
- /// Print a message to the main log
- virtual void log(std::string const &message) = 0;
-
- /// Print a message to the main log and let the rest of the program handle the error
- virtual void error(std::string const &message) = 0;
-
- /// Print a message to the main log and exit with error code
- virtual void fatal_error(std::string const &message) = 0;
-
- /// Print a message to the main log and exit normally
- virtual void exit(std::string const &message)
+ /// Read the current total force of the given atom
+ inline cvm::rvector get_atom_total_force(int index) const
{
- cvm::error("Error: exiting without error is not implemented, returning error code.\n",
- COLVARS_NOT_IMPLEMENTED);
+ return atoms_total_forces[index];
}
- // TODO the following definitions may be moved to a .cpp file
-
- /// \brief Returns a reference to the given output channel;
- /// if this is not open already, then open it
- virtual std::ostream * output_stream(std::string const &output_name)
+ /// Request that this force is applied to the given atom
+ inline void apply_atom_force(int index, cvm::rvector const &new_force)
{
- std::list<std::ostream *>::iterator osi = output_files.begin();
- std::list<std::string>::iterator osni = output_stream_names.begin();
- for ( ; osi != output_files.end(); osi++, osni++) {
- if (*osni == output_name) {
- return *osi;
- }
- }
- output_stream_names.push_back(output_name);
- std::ofstream * os = new std::ofstream(output_name.c_str());
- if (!os->is_open()) {
- cvm::error("Error: cannot write to file \""+output_name+"\".\n",
- FILE_ERROR);
- }
- output_files.push_back(os);
- return os;
+ atoms_new_colvar_forces[index] += new_force;
}
- /// \brief Closes the given output channel
- virtual int close_output_stream(std::string const &output_name)
+ /// Read the current velocity of the given atom
+ inline cvm::rvector get_atom_velocity(int index)
{
- std::list<std::ostream *>::iterator osi = output_files.begin();
- std::list<std::string>::iterator osni = output_stream_names.begin();
- for ( ; osi != output_files.end(); osi++, osni++) {
- if (*osni == output_name) {
- ((std::ofstream *) (*osi))->close();
- output_files.erase(osi);
- output_stream_names.erase(osni);
- return COLVARS_OK;
- }
- }
- cvm::error("Error: trying to close an output file or stream that wasn't open.\n",
- BUG_ERROR);
- return COLVARS_ERROR;
+ cvm::error("Error: reading the current velocity of an atom "
+ "is not yet implemented.\n",
+ COLVARS_NOT_IMPLEMENTED);
+ return cvm::rvector(0.0);
}
- /// \brief Rename the given file, before overwriting it
- virtual int backup_file(char const *filename)
+ inline std::vector<int> *modify_atom_ids()
{
- return COLVARS_NOT_IMPLEMENTED;
+ return &atoms_ids;
}
-
-
- // **************** ACCESS SYSTEM DATA ****************
-
- /// Pass restraint energy value for current timestep to MD engine
- virtual void add_energy(cvm::real energy) = 0;
-
- /// Tell the proxy whether total forces are needed (may not always be available)
- virtual void request_total_force(bool yesno)
+ inline std::vector<cvm::real> *modify_atom_masses()
{
- if (yesno == true)
- cvm::error("Error: total forces are currently not implemented.\n",
- COLVARS_NOT_IMPLEMENTED);
+ return &atoms_masses;
}
- /// Are total forces being used?
- virtual bool total_forces_enabled() const
+ inline std::vector<cvm::real> *modify_atom_charges()
{
- return false;
+ return &atoms_charges;
}
- /// \brief Get the PBC-aware distance vector between two positions
- virtual cvm::rvector position_distance(cvm::atom_pos const &pos1,
- cvm::atom_pos const &pos2) = 0;
-
- /// \brief Get the PBC-aware square distance between two positions;
- /// may need to be reimplemented independently from position_distance() for optimization purposes
- virtual cvm::real position_dist2(cvm::atom_pos const &pos1,
- cvm::atom_pos const &pos2)
+ inline std::vector<cvm::rvector> *modify_atom_positions()
{
- return (position_distance(pos1, pos2)).norm2();
+ return &atoms_positions;
}
- /// \brief Get the closest periodic image to a reference position
- /// \param pos The position to look for the closest periodic image
- /// \param ref_pos The reference position
- virtual void select_closest_image(cvm::atom_pos &pos,
- cvm::atom_pos const &ref_pos)
+ inline std::vector<cvm::rvector> *modify_atom_total_forces()
{
- pos = position_distance(ref_pos, pos) + ref_pos;
+ return &atoms_total_forces;
}
- /// \brief Perform select_closest_image() on a set of atomic positions
- ///
- /// After that, distance vectors can then be calculated directly,
- /// without using position_distance()
- void select_closest_images(std::vector<cvm::atom_pos> &pos,
- cvm::atom_pos const &ref_pos)
+ inline std::vector<cvm::rvector> *modify_atom_new_colvar_forces()
{
- for (std::vector<cvm::atom_pos>::iterator pi = pos.begin();
- pi != pos.end(); ++pi) {
- select_closest_image(*pi, ref_pos);
- }
+ return &atoms_new_colvar_forces;
}
-
- // **************** ACCESS ATOMIC DATA ****************
protected:
/// \brief Array of 0-based integers used to uniquely associate atoms
/// within the host program
std::vector<int> atoms_ids;
/// \brief Keep track of how many times each atom is used by a separate colvar object
std::vector<size_t> atoms_ncopies;
/// \brief Masses of the atoms (allow redefinition during a run, as done e.g. in LAMMPS)
std::vector<cvm::real> atoms_masses;
/// \brief Charges of the atoms (allow redefinition during a run, as done e.g. in LAMMPS)
std::vector<cvm::real> atoms_charges;
/// \brief Current three-dimensional positions of the atoms
std::vector<cvm::rvector> atoms_positions;
/// \brief Most recent total forces on each atom
std::vector<cvm::rvector> atoms_total_forces;
/// \brief Forces applied from colvars, to be communicated to the MD integrator
std::vector<cvm::rvector> atoms_new_colvar_forces;
- /// Used by all init_atom() functions: create a slot for an atom not requested yet
- inline int add_atom_slot(int atom_id)
- {
- atoms_ids.push_back(atom_id);
- atoms_ncopies.push_back(1);
- atoms_masses.push_back(1.0);
- atoms_charges.push_back(0.0);
- atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0));
- atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
- atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
- return (atoms_ids.size() - 1);
- }
+ /// Used by all init_atom() functions: create a slot for an atom not
+ /// requested yet; returns the index in the arrays
+ int add_atom_slot(int atom_id);
+
+};
+
+
+/// \brief Container of atom group data (allow collection of aggregated atomic
+/// data)
+class colvarproxy_atom_groups {
public:
- /// Prepare this atom for collective variables calculation, selecting it by numeric index (1-based)
- virtual int init_atom(int atom_number) = 0;
+ /// Contructor
+ colvarproxy_atom_groups();
- /// Check that this atom number is valid, but do not initialize the corresponding atom yet
- virtual int check_atom_id(int atom_number) = 0;
+ /// Destructor
+ virtual ~colvarproxy_atom_groups();
- /// Select this atom for collective variables calculation, using name and residue number.
- /// Not all programs support this: leave this function as is in those cases.
- virtual int init_atom(cvm::residue_id const &residue,
- std::string const &atom_name,
- std::string const &segment_id)
- {
- cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n",
- COLVARS_NOT_IMPLEMENTED);
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// Clear atom group data
+ int reset();
- /// Check that this atom is valid, but do not initialize it yet
- virtual int check_atom_id(cvm::residue_id const &residue,
- std::string const &atom_name,
- std::string const &segment_id)
- {
- cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n",
- COLVARS_NOT_IMPLEMENTED);
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// \brief Whether this proxy implementation has capability for scalable groups
+ virtual int scalable_group_coms();
- /// \brief Used by the atom class destructor: rather than deleting the array slot
- /// (costly) set the corresponding atoms_ncopies to zero
- virtual void clear_atom(int index)
- {
- if (((size_t) index) >= atoms_ids.size()) {
- cvm::error("Error: trying to disable an atom that was not previously requested.\n",
- INPUT_ERROR);
- }
- if (atoms_ncopies[index] > 0) {
- atoms_ncopies[index] -= 1;
- }
- }
+ /// Prepare this group for collective variables calculation, selecting atoms by internal ids (0-based)
+ virtual int init_atom_group(std::vector<int> const &atoms_ids);
- /// Get the numeric ID of the given atom (for the program)
- inline int get_atom_id(int index) const
- {
- return atoms_ids[index];
- }
+ /// \brief Used by the atom_group class destructor
+ virtual void clear_atom_group(int index);
- /// Get the mass of the given atom
- inline cvm::real get_atom_mass(int index) const
+ /// Get the numeric ID of the given atom group (for the MD program)
+ inline int get_atom_group_id(int index) const
{
- return atoms_masses[index];
+ return atom_groups_ids[index];
}
- /// Get the charge of the given atom
- inline cvm::real get_atom_charge(int index) const
+ /// Get the mass of the given atom group
+ inline cvm::real get_atom_group_mass(int index) const
{
- return atoms_charges[index];
+ return atom_groups_masses[index];
}
- /// Read the current position of the given atom
- inline cvm::rvector get_atom_position(int index) const
+ /// Get the charge of the given atom group
+ inline cvm::real get_atom_group_charge(int index) const
{
- return atoms_positions[index];
+ return atom_groups_charges[index];
}
- /// Read the current total force of the given atom
- inline cvm::rvector get_atom_total_force(int index) const
+ /// Read the current position of the center of mass given atom group
+ inline cvm::rvector get_atom_group_com(int index) const
{
- return atoms_total_forces[index];
+ return atom_groups_coms[index];
}
- /// Request that this force is applied to the given atom
- inline void apply_atom_force(int index, cvm::rvector const &new_force)
+ /// Read the current total force of the given atom group
+ inline cvm::rvector get_atom_group_total_force(int index) const
{
- atoms_new_colvar_forces[index] += new_force;
+ return atom_groups_total_forces[index];
}
- /// Read the current velocity of the given atom
- virtual cvm::rvector get_atom_velocity(int index)
+ /// Request that this force is applied to the given atom group
+ inline void apply_atom_group_force(int index, cvm::rvector const &new_force)
{
- cvm::error("Error: reading the current velocity of an atom is not yet implemented.\n",
- COLVARS_NOT_IMPLEMENTED);
- return cvm::rvector(0.0);
+ atom_groups_new_colvar_forces[index] += new_force;
}
- // useful functions for data management outside this class
- inline std::vector<int> *modify_atom_ids() { return &atoms_ids; }
- inline std::vector<cvm::real> *modify_atom_masses() { return &atoms_masses; }
- inline std::vector<cvm::real> *modify_atom_charges() { return &atoms_charges; }
- inline std::vector<cvm::rvector> *modify_atom_positions() { return &atoms_positions; }
- inline std::vector<cvm::rvector> *modify_atom_total_forces() { return &atoms_total_forces; }
- inline std::vector<cvm::rvector> *modify_atom_new_colvar_forces() { return &atoms_new_colvar_forces; }
-
- /// \brief Read atom identifiers from a file \param filename name of
- /// the file (usually a PDB) \param atoms array to which atoms read
- /// from "filename" will be appended \param pdb_field (optiona) if
- /// "filename" is a PDB file, use this field to determine which are
- /// the atoms to be set
- virtual int load_atoms(char const *filename,
- cvm::atom_group &atoms,
- std::string const &pdb_field,
- double const pdb_field_value = 0.0)
+ /// Read the current velocity of the given atom group
+ inline cvm::rvector get_atom_group_velocity(int index)
{
- cvm::error("Error: loading atom identifiers from a file is currently not implemented.\n",
+ cvm::error("Error: reading the current velocity of an atom group is not yet implemented.\n",
COLVARS_NOT_IMPLEMENTED);
- return COLVARS_NOT_IMPLEMENTED;
- }
-
- /// \brief Load the coordinates for a group of atoms from a file
- /// (usually a PDB); if "pos" is already allocated, the number of its
- /// elements must match the number of atoms in "filename"
- virtual int load_coords(char const *filename,
- std::vector<cvm::atom_pos> &pos,
- const std::vector<int> &indices,
- std::string const &pdb_field,
- double const pdb_field_value = 0.0)
- {
- cvm::error("Error: loading atomic coordinates from a file is currently not implemented.\n");
- return COLVARS_NOT_IMPLEMENTED;
+ return cvm::rvector(0.0);
}
- // **************** ACCESS GROUP DATA ****************
-
protected:
/// \brief Array of 0-based integers used to uniquely associate atom groups
/// within the host program
std::vector<int> atom_groups_ids;
/// \brief Keep track of how many times each group is used by a separate cvc
std::vector<size_t> atom_groups_ncopies;
/// \brief Total masses of the atom groups
std::vector<cvm::real> atom_groups_masses;
/// \brief Total charges of the atom groups (allow redefinition during a run, as done e.g. in LAMMPS)
std::vector<cvm::real> atom_groups_charges;
/// \brief Current centers of mass of the atom groups
std::vector<cvm::rvector> atom_groups_coms;
/// \brief Most recently updated total forces on the com of each group
std::vector<cvm::rvector> atom_groups_total_forces;
/// \brief Forces applied from colvars, to be communicated to the MD integrator
std::vector<cvm::rvector> atom_groups_new_colvar_forces;
- /// TODO Add here containers of handles to cvc objects that are computed in parallel
+ /// Used by all init_atom_group() functions: create a slot for an atom group not requested yet
+ int add_atom_group_slot(int atom_group_id);
+};
+
+
+/// \brief Methods for SMP parallelization
+class colvarproxy_smp {
public:
- /// \brief Whether this proxy implementation has capability for scalable groups
- virtual int scalable_group_coms()
- {
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// Constructor
+ colvarproxy_smp();
- /// Used by all init_atom_group() functions: create a slot for an atom group not requested yet
- // TODO Add a handle to cvc objects
- inline int add_atom_group_slot(int atom_group_id)
- {
- atom_groups_ids.push_back(atom_group_id);
- atom_groups_ncopies.push_back(1);
- atom_groups_masses.push_back(1.0);
- atom_groups_charges.push_back(0.0);
- atom_groups_coms.push_back(cvm::rvector(0.0, 0.0, 0.0));
- atom_groups_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
- atom_groups_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0));
- return (atom_groups_ids.size() - 1);
- }
+ /// Destructor
+ virtual ~colvarproxy_smp();
- /// Prepare this group for collective variables calculation, selecting atoms by internal ids (0-based)
- virtual int init_atom_group(std::vector<int> const &atoms_ids) // TODO Add a handle to cvc objects
- {
- cvm::error("Error: initializing a group outside of the colvars module is currently not supported.\n",
- COLVARS_NOT_IMPLEMENTED);
- return COLVARS_NOT_IMPLEMENTED;
- }
+ /// Whether threaded parallelization should be used (TODO: make this a
+ /// cvm::deps feature)
+ bool b_smp_active;
- /// \brief Used by the atom_group class destructor
- virtual void clear_atom_group(int index)
- {
- if (cvm::debug()) {
- log("Trying to remove/disable atom group number "+cvm::to_str(index)+"\n");
- }
-
- if (((size_t) index) >= atom_groups_ids.size()) {
- cvm::error("Error: trying to disable an atom group that was not previously requested.\n",
- INPUT_ERROR);
- }
-
- if (atom_groups_ncopies[index] > 0) {
- atom_groups_ncopies[index] -= 1;
- }
- }
+ /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature)
+ virtual int smp_enabled();
- /// Get the numeric ID of the given atom group (for the MD program)
- inline cvm::real get_atom_group_id(int index) const
- {
- return atom_groups_ids[index];
- }
+ /// Distribute calculation of colvars (and their components) across threads
+ virtual int smp_colvars_loop();
- /// Get the mass of the given atom group
- inline cvm::real get_atom_group_mass(int index) const
- {
- return atom_groups_masses[index];
- }
+ /// Distribute calculation of biases across threads
+ virtual int smp_biases_loop();
- /// Get the charge of the given atom group
- inline cvm::real get_atom_group_charge(int index) const
+ /// Distribute calculation of biases across threads 2nd through last, with all scripted biased on 1st thread
+ virtual int smp_biases_script_loop();
+
+ /// Index of this thread
+ virtual int smp_thread_id();
+
+ /// Number of threads sharing this address space
+ virtual int smp_num_threads();
+
+ /// Lock the proxy's shared data for access by a thread, if threads are implemented; if not implemented, does nothing
+ virtual int smp_lock();
+
+ /// Attempt to lock the proxy's shared data
+ virtual int smp_trylock();
+
+ /// Release the lock
+ virtual int smp_unlock();
+};
+
+
+/// \brief Methods for multiple-replica communication
+class colvarproxy_replicas {
+
+public:
+
+ /// Constructor
+ colvarproxy_replicas();
+
+ /// Destructor
+ virtual ~colvarproxy_replicas();
+
+ /// \brief Indicate if multi-replica support is available and active
+ virtual bool replica_enabled();
+
+ /// \brief Index of this replica
+ virtual int replica_index();
+
+ /// \brief Total number of replica
+ virtual int replica_num();
+
+ /// \brief Synchronize replica
+ virtual void replica_comm_barrier();
+
+ /// \brief Receive data from other replica
+ virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep);
+
+ /// \brief Send data to other replica
+ virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep);
+
+};
+
+
+/// Method for scripting language interface (Tcl or Python)
+class colvarproxy_script {
+
+public:
+
+ /// Constructor
+ colvarproxy_script();
+
+ /// Destructor
+ virtual ~colvarproxy_script();
+
+ /// Convert a script object (Tcl or Python call argument) to a C string
+ virtual char *script_obj_to_str(unsigned char *obj);
+
+ /// Pointer to the scripting interface object
+ /// (does not need to be allocated in a new interface)
+ colvarscript *script;
+
+ /// is a user force script defined?
+ bool force_script_defined;
+
+ /// Do we have a scripting interface?
+ bool have_scripts;
+
+ /// Run a user-defined colvar forces script
+ virtual int run_force_callback();
+
+ virtual int run_colvar_callback(
+ std::string const &name,
+ std::vector<const colvarvalue *> const &cvcs,
+ colvarvalue &value);
+
+ virtual int run_colvar_gradient_callback(
+ std::string const &name,
+ std::vector<const colvarvalue *> const &cvcs,
+ std::vector<cvm::matrix2d<cvm::real> > &gradient);
+};
+
+
+/// Methods for data input/output
+class colvarproxy_io {
+
+public:
+
+ /// Constructor
+ colvarproxy_io();
+
+ /// Destructor
+ virtual ~colvarproxy_io();
+
+ /// \brief Save the current frame number in the argument given
+ // Returns error code
+ virtual int get_frame(long int &);
+
+ /// \brief Set the current frame number (as well as colvarmodule::it)
+ // Returns error code
+ virtual int set_frame(long int);
+
+ /// \brief Returns a reference to the given output channel;
+ /// if this is not open already, then open it
+ virtual std::ostream *output_stream(std::string const &output_name,
+ std::ios_base::openmode mode =
+ std::ios_base::out);
+
+ /// \brief Flushes the given output channel
+ virtual int flush_output_stream(std::ostream *os);
+
+ /// \brief Closes the given output channel
+ virtual int close_output_stream(std::string const &output_name);
+
+ /// \brief Rename the given file, before overwriting it
+ virtual int backup_file(char const *filename);
+
+ /// \brief Rename the given file, before overwriting it
+ inline int backup_file(std::string const &filename)
{
- return atom_groups_charges[index];
+ return backup_file(filename.c_str());
}
- /// Read the current position of the center of mass given atom group
- inline cvm::rvector get_atom_group_com(int index) const
+ /// \brief Prefix of the input state file
+ inline std::string & input_prefix()
{
- return atom_groups_coms[index];
+ return input_prefix_str;
}
- /// Read the current total force of the given atom group
- inline cvm::rvector get_atom_group_total_force(int index) const
+ /// \brief Prefix to be used for output restart files
+ inline std::string & restart_output_prefix()
{
- return atom_groups_total_forces[index];
+ return restart_output_prefix_str;
}
- /// Request that this force is applied to the given atom group
- inline void apply_atom_group_force(int index, cvm::rvector const &new_force)
+ /// \brief Prefix to be used for output files (final system
+ /// configuration)
+ inline std::string & output_prefix()
{
- atom_groups_new_colvar_forces[index] += new_force;
+ return output_prefix_str;
}
- /// Read the current velocity of the given atom group
- virtual cvm::rvector get_atom_group_velocity(int index)
+protected:
+
+ /// \brief Prefix to be used for input files (restarts, not
+ /// configuration)
+ std::string input_prefix_str, output_prefix_str, restart_output_prefix_str;
+
+ /// \brief Currently opened output files: by default, these are ofstream objects.
+ /// Allows redefinition to implement different output mechanisms
+ std::list<std::ostream *> output_files;
+ /// \brief Identifiers for output_stream objects: by default, these are the names of the files
+ std::list<std::string> output_stream_names;
+
+};
+
+
+
+/// \brief Interface between the collective variables module and
+/// the simulation or analysis program (NAMD, VMD, LAMMPS...).
+/// This is the base class: each interfaced program is supported by a derived class.
+/// Only pure virtual functions ("= 0") must be reimplemented to ensure baseline functionality.
+class colvarproxy
+ : public colvarproxy_system,
+ public colvarproxy_atoms,
+ public colvarproxy_atom_groups,
+ public colvarproxy_smp,
+ public colvarproxy_replicas,
+ public colvarproxy_script,
+ public colvarproxy_io
+{
+
+public:
+
+ /// Pointer to the main object
+ colvarmodule *colvars;
+
+ /// Constructor
+ colvarproxy();
+
+ /// Destructor
+ virtual ~colvarproxy();
+
+ /// \brief Reset proxy state, e.g. requested atoms
+ virtual int reset();
+
+ /// (Re)initialize required member data after construction
+ virtual int setup();
+
+ /// \brief Update data required by the colvars module (e.g. cache atom positions)
+ ///
+ /// TODO Break up colvarproxy_namd and colvarproxy_lammps function into these
+ virtual int update_input();
+
+ /// \brief Update data based from the results of a module update (e.g. send forces)
+ virtual int update_output();
+
+ /// Print a message to the main log
+ virtual void log(std::string const &message) = 0;
+
+ /// Print a message to the main log and let the rest of the program handle the error
+ virtual void error(std::string const &message) = 0;
+
+ /// Print a message to the main log and exit with error code
+ virtual void fatal_error(std::string const &message) = 0;
+
+ /// \brief Restarts will be written each time this number of steps has passed
+ virtual size_t restart_frequency();
+
+ /// Whether a simulation is running (warn against irrecovarable errors)
+ inline bool simulation_running() const
{
- cvm::error("Error: reading the current velocity of an atom group is not yet implemented.\n",
- COLVARS_NOT_IMPLEMENTED);
- return cvm::rvector(0.0);
+ return b_simulation_running;
}
+protected:
+
+ /// Whether a simulation is running (warn against irrecovarable errors)
+ bool b_simulation_running;
+
};
#endif
diff --git a/lib/colvars/colvars_version.h b/lib/colvars/colvars_version.h
new file mode 100644
index 000000000..e54475642
--- /dev/null
+++ b/lib/colvars/colvars_version.h
@@ -0,0 +1,8 @@
+#define COLVARS_VERSION "2017-07-15"
+// This file is part of the Collective Variables module (Colvars).
+// The original version of Colvars and its updates are located at:
+// https://github.com/colvars/colvars
+// Please update all Colvars source files before making any changes.
+// If you wish to distribute your changes, please submit them to the
+// Colvars repository at GitHub.
+
diff --git a/lib/colvars/colvarscript.cpp b/lib/colvars/colvarscript.cpp
index f192dcb7c..5bb2faae2 100644
--- a/lib/colvars/colvarscript.cpp
+++ b/lib/colvars/colvarscript.cpp
@@ -1,582 +1,582 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <cstdlib>
#include <stdlib.h>
#include <string.h>
#include "colvarscript.h"
+#include "colvarproxy.h"
#include "colvardeps.h"
colvarscript::colvarscript(colvarproxy *p)
: proxy(p),
colvars(p->colvars),
proxy_error(0)
{
}
extern "C" {
// Generic hooks; NAMD and VMD have Tcl-specific versions in the respective proxies
- int run_colvarscript_command(int argc, const char **argv)
+ int run_colvarscript_command(int objc, unsigned char *const objv[])
{
colvarproxy *cvp = cvm::proxy;
if (!cvp) {
return -1;
}
if (!cvp->script) {
cvm::error("Called run_colvarscript_command without a script object initialized.\n");
return -1;
}
- return cvp->script->run(argc, argv);
+ return cvp->script->run(objc, objv);
}
const char * get_colvarscript_result()
{
colvarproxy *cvp = cvm::proxy;
if (!cvp->script) {
cvm::error("Called run_colvarscript_command without a script object initialized.\n");
return "";
}
return cvp->script->result.c_str();
}
}
/// Run method based on given arguments
-int colvarscript::run(int argc, char const *argv[]) {
-
- result = "";
+int colvarscript::run(int objc, unsigned char *const objv[])
+{
+ result.clear();
if (cvm::debug()) {
- cvm::log("Called script run with " + cvm::to_str(argc) + " args");
- for (int i = 0; i < argc; i++) { cvm::log(argv[i]); }
+ cvm::log("Called script run with " + cvm::to_str(objc) + " args:");
+ for (int i = 0; i < objc; i++) {
+ cvm::log(obj_to_str(objv[i]));
+ }
}
- if (argc < 2) {
+ if (objc < 2) {
result = help_string();
return COLVARS_OK;
}
- std::string cmd = argv[1];
+ std::string const cmd(obj_to_str(objv[1]));
int error_code = COLVARS_OK;
if (cmd == "colvar") {
- return proc_colvar(argc-1, &(argv[1]));
+ if (objc < 3) {
+ result = "Missing parameters\n" + help_string();
+ return COLVARSCRIPT_ERROR;
+ }
+ std::string const name(obj_to_str(objv[2]));
+ colvar *cv = cvm::colvar_by_name(name);
+ if (cv == NULL) {
+ result = "Colvar not found: " + name;
+ return COLVARSCRIPT_ERROR;
+ }
+ return proc_colvar(cv, objc-1, &(objv[1]));
}
if (cmd == "bias") {
- return proc_bias(argc-1, &(argv[1]));
+ if (objc < 3) {
+ result = "Missing parameters\n" + help_string();
+ return COLVARSCRIPT_ERROR;
+ }
+ std::string const name(obj_to_str(objv[2]));
+ colvarbias *b = cvm::bias_by_name(name);
+ if (b == NULL) {
+ result = "Bias not found: " + name;
+ return COLVARSCRIPT_ERROR;
+ }
+ return proc_bias(b, objc-1, &(objv[1]));
}
if (cmd == "version") {
result = COLVARS_VERSION;
return COLVARS_OK;
}
if (cmd == "reset") {
/// Delete every child object
colvars->reset();
return COLVARS_OK;
}
if (cmd == "delete") {
// Note: the delete bit may be ignored by some backends
// it is mostly useful in VMD
colvars->set_error_bits(DELETE_COLVARS);
return COLVARS_OK;
}
if (cmd == "update") {
error_code |= proxy->update_input();
error_code |= colvars->calc();
error_code |= proxy->update_output();
if (error_code) {
- result += "Error updating the colvars module.\n";
+ result += "Error updating the Colvars module.\n";
}
return error_code;
}
if (cmd == "list") {
- if (argc == 2) {
+ if (objc == 2) {
for (std::vector<colvar *>::iterator cvi = colvars->colvars.begin();
cvi != colvars->colvars.end();
++cvi) {
result += (cvi == colvars->colvars.begin() ? "" : " ") + (*cvi)->name;
}
return COLVARS_OK;
- } else if (argc == 3 && !strcmp(argv[2], "biases")) {
+ } else if (objc == 3 && !strcmp(obj_to_str(objv[2]), "biases")) {
for (std::vector<colvarbias *>::iterator bi = colvars->biases.begin();
bi != colvars->biases.end();
++bi) {
result += (bi == colvars->biases.begin() ? "" : " ") + (*bi)->name;
}
return COLVARS_OK;
} else {
result = "Wrong arguments to command \"list\"\n" + help_string();
return COLVARSCRIPT_ERROR;
}
}
/// Parse config from file
if (cmd == "configfile") {
- if (argc < 3) {
+ if (objc < 3) {
result = "Missing arguments\n" + help_string();
return COLVARSCRIPT_ERROR;
}
- if (colvars->read_config_file(argv[2]) == COLVARS_OK) {
+ if (colvars->read_config_file(obj_to_str(objv[2])) == COLVARS_OK) {
return COLVARS_OK;
} else {
result = "Error parsing configuration file";
return COLVARSCRIPT_ERROR;
}
}
/// Parse config from string
if (cmd == "config") {
- if (argc < 3) {
+ if (objc < 3) {
result = "Missing arguments\n" + help_string();
return COLVARSCRIPT_ERROR;
}
- std::string conf = argv[2];
+ std::string const conf(obj_to_str(objv[2]));
if (colvars->read_config_string(conf) == COLVARS_OK) {
return COLVARS_OK;
} else {
result = "Error parsing configuration string";
return COLVARSCRIPT_ERROR;
}
}
/// Load an input state file
if (cmd == "load") {
- if (argc < 3) {
+ if (objc < 3) {
result = "Missing arguments\n" + help_string();
return COLVARSCRIPT_ERROR;
}
- proxy->input_prefix() = argv[2];
+ proxy->input_prefix() = obj_to_str(objv[2]);
if (colvars->setup_input() == COLVARS_OK) {
return COLVARS_OK;
} else {
result = "Error loading state file";
return COLVARSCRIPT_ERROR;
}
}
/// Save to an output state file
if (cmd == "save") {
- if (argc < 3) {
+ if (objc < 3) {
result = "Missing arguments";
return COLVARSCRIPT_ERROR;
}
- proxy->output_prefix_str = argv[2];
+ proxy->output_prefix() = obj_to_str(objv[2]);
int error = 0;
error |= colvars->setup_output();
error |= colvars->write_output_files();
return error ? COLVARSCRIPT_ERROR : COLVARS_OK;
}
/// Print the values that would go on colvars.traj
if (cmd == "printframelabels") {
std::ostringstream os;
colvars->write_traj_label(os);
result = os.str();
return COLVARS_OK;
}
if (cmd == "printframe") {
std::ostringstream os;
colvars->write_traj(os);
result = os.str();
return COLVARS_OK;
}
if (cmd == "frame") {
- if (argc == 2) {
+ if (objc == 2) {
long int f;
int error = proxy->get_frame(f);
if (error == COLVARS_OK) {
result = cvm::to_str(f);
return COLVARS_OK;
} else {
result = "Frame number is not available";
return COLVARSCRIPT_ERROR;
}
- } else if (argc == 3) {
+ } else if (objc == 3) {
// Failure of this function does not trigger an error, but
// returns nonzero, to let scripts detect available frames
- int error = proxy->set_frame(strtol(argv[2], NULL, 10));
+ int error = proxy->set_frame(strtol(obj_to_str(objv[2]), NULL, 10));
result = cvm::to_str(error == COLVARS_OK ? 0 : -1);
return COLVARS_OK;
} else {
result = "Wrong arguments to command \"frame\"\n" + help_string();
return COLVARSCRIPT_ERROR;
}
}
if (cmd == "addenergy") {
- if (argc == 3) {
- colvars->total_bias_energy += strtod(argv[2], NULL);
+ if (objc == 3) {
+ colvars->total_bias_energy += strtod(obj_to_str(objv[2]), NULL);
return COLVARS_OK;
} else {
result = "Wrong arguments to command \"addenergy\"\n" + help_string();
return COLVARSCRIPT_ERROR;
}
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
-int colvarscript::proc_colvar(int argc, char const *argv[]) {
- if (argc < 3) {
- result = "Missing parameters\n" + help_string();
- return COLVARSCRIPT_ERROR;
- }
+int colvarscript::proc_colvar(colvar *cv, int objc, unsigned char *const objv[]) {
- std::string name = argv[1];
- colvar *cv = cvm::colvar_by_name(name);
- if (cv == NULL) {
- result = "Colvar not found: " + name;
- return COLVARSCRIPT_ERROR;
- }
- std::string subcmd = argv[2];
+ std::string const subcmd(obj_to_str(objv[2]));
if (subcmd == "value") {
result = (cv->value()).to_simple_string();
return COLVARS_OK;
}
if (subcmd == "width") {
result = cvm::to_str(cv->width, 0, cvm::cv_prec);
return COLVARS_OK;
}
if (subcmd == "type") {
result = cv->value().type_desc(cv->value().value_type);
return COLVARS_OK;
}
if (subcmd == "update") {
cv->calc();
cv->update_forces_energy();
result = (cv->value()).to_simple_string();
return COLVARS_OK;
}
if (subcmd == "delete") {
size_t i;
for (i = 0; i < cv->biases.size(); i++) {
delete cv->biases[i];
}
- cv->biases.resize(0);
+ cv->biases.clear();
// colvar destructor is tasked with the cleanup
delete cv;
// TODO this could be done by the destructors
- colvars->write_traj_label(colvars->cv_traj_os);
+ colvars->write_traj_label(*(colvars->cv_traj_os));
return COLVARS_OK;
}
if (subcmd == "getconfig") {
result = cv->get_config();
return COLVARS_OK;
}
if (subcmd == "getappliedforce") {
result = (cv->applied_force()).to_simple_string();
return COLVARS_OK;
}
if (subcmd == "getsystemforce") {
// TODO warning here
result = (cv->total_force()).to_simple_string();
return COLVARS_OK;
}
if (subcmd == "gettotalforce") {
result = (cv->total_force()).to_simple_string();
return COLVARS_OK;
}
if (subcmd == "addforce") {
- if (argc < 4) {
+ if (objc < 4) {
result = "addforce: missing parameter: force value\n" + help_string();
return COLVARSCRIPT_ERROR;
}
- std::string f_str = argv[3];
+ std::string const f_str(obj_to_str(objv[3]));
std::istringstream is(f_str);
is.width(cvm::cv_width);
is.precision(cvm::cv_prec);
colvarvalue force(cv->value());
force.is_derivative();
if (force.from_simple_string(is.str()) != COLVARS_OK) {
result = "addforce : error parsing force value";
return COLVARSCRIPT_ERROR;
}
cv->add_bias_force(force);
result = force.to_simple_string();
return COLVARS_OK;
}
if (subcmd == "cvcflags") {
- if (argc < 4) {
+ if (objc < 4) {
result = "cvcflags: missing parameter: vector of flags";
return COLVARSCRIPT_ERROR;
}
- std::string flags_str = argv[3];
+ std::string const flags_str(obj_to_str(objv[3]));
std::istringstream is(flags_str);
std::vector<bool> flags;
int flag;
while (is >> flag) {
flags.push_back(flag != 0);
}
int res = cv->set_cvc_flags(flags);
if (res != COLVARS_OK) {
result = "Error setting CVC flags";
return COLVARSCRIPT_ERROR;
}
result = "0";
return COLVARS_OK;
}
if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) {
- return proc_features(cv, argc, argv);
+ return proc_features(cv, objc, objv);
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
-int colvarscript::proc_bias(int argc, char const *argv[]) {
- if (argc < 3) {
- result = "Missing parameters\n" + help_string();
- return COLVARSCRIPT_ERROR;
- }
-
- std::string name = argv[1];
- colvarbias *b = cvm::bias_by_name(name);
- if (b == NULL) {
- result = "Bias not found: " + name;
- return COLVARSCRIPT_ERROR;
- }
+int colvarscript::proc_bias(colvarbias *b, int objc, unsigned char *const objv[]) {
- std::string subcmd = argv[2];
+ std::string const key(obj_to_str(objv[0]));
+ std::string const subcmd(obj_to_str(objv[2]));
if (subcmd == "energy") {
result = cvm::to_str(b->get_energy());
return COLVARS_OK;
}
if (subcmd == "update") {
b->update();
result = cvm::to_str(b->get_energy());
return COLVARS_OK;
}
if (subcmd == "getconfig") {
result = b->get_config();
return COLVARS_OK;
}
// Subcommands for MW ABF
if (subcmd == "bin") {
int r = b->current_bin();
result = cvm::to_str(r);
return COLVARS_OK;
}
if (subcmd == "binnum") {
int r = b->bin_num();
if (r < 0) {
result = "Error: calling bin_num() for bias " + b->name;
return COLVARSCRIPT_ERROR;
}
result = cvm::to_str(r);
return COLVARS_OK;
}
if (subcmd == "share") {
int r = b->replica_share();
if (r < 0) {
result = "Error: calling replica_share() for bias " + b->name;
return COLVARSCRIPT_ERROR;
}
result = cvm::to_str(r);
return COLVARS_OK;
}
// End commands for MW ABF
if (subcmd == "delete") {
// the bias destructor takes care of the cleanup at cvm level
delete b;
// TODO this could be done by the destructors
- colvars->write_traj_label(colvars->cv_traj_os);
+ colvars->write_traj_label(*(colvars->cv_traj_os));
return COLVARS_OK;
}
if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) {
- return proc_features(b, argc, argv);
+ return proc_features(b, objc, objv);
}
- if (argc >= 4) {
- std::string param = argv[3];
+ if (objc >= 4) {
+ std::string const param(obj_to_str(objv[3]));
if (subcmd == "count") {
int index;
if (!(std::istringstream(param) >> index)) {
result = "bin_count: error parsing bin index";
return COLVARSCRIPT_ERROR;
}
result = cvm::to_str(b->bin_count(index));
return COLVARS_OK;
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
int colvarscript::proc_features(colvardeps *obj,
- int argc, char const *argv[]) {
+ int objc, unsigned char *const objv[]) {
// size was already checked before calling
- std::string subcmd = argv[2];
+ std::string const subcmd(obj_to_str(objv[2]));
- if (argc == 3) {
+ if (objc == 3) {
if (subcmd == "state") {
// TODO make this returned as result?
obj->print_state();
return COLVARS_OK;
}
// get and set commands require more arguments
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
if ((subcmd == "get") || (subcmd == "set")) {
std::vector<colvardeps::feature *> &features = obj->features();
- std::string const req_feature(argv[3]);
+ std::string const req_feature(obj_to_str(objv[3]));
colvardeps::feature *f = NULL;
int fid = 0;
for (fid = 0; fid < int(features.size()); fid++) {
if (features[fid]->description ==
colvarparse::to_lower_cppstr(req_feature)) {
f = features[fid];
break;
}
}
if (f == NULL) {
result = "Error: feature \""+req_feature+"\" does not exist.\n";
return COLVARSCRIPT_ERROR;
} else {
if (! obj->is_available(fid)) {
result = "Error: feature \""+req_feature+"\" is unavailable.\n";
return COLVARSCRIPT_ERROR;
}
if (subcmd == "get") {
result = cvm::to_str(obj->is_enabled(fid) ? 1 : 0);
return COLVARS_OK;
}
if (subcmd == "set") {
- if (argc == 5) {
+ if (objc == 5) {
std::string const yesno =
- colvarparse::to_lower_cppstr(std::string(argv[4]));
+ colvarparse::to_lower_cppstr(std::string(obj_to_str(objv[4])));
if ((yesno == std::string("yes")) ||
(yesno == std::string("on")) ||
(yesno == std::string("1"))) {
obj->enable(fid);
return COLVARS_OK;
} else if ((yesno == std::string("no")) ||
(yesno == std::string("off")) ||
(yesno == std::string("0"))) {
- // TODO disable() function does not exist yet,
- // dependencies will not be resolved
- // obj->disable(fid);
- obj->set_enabled(fid, false);
+ obj->disable(fid);
return COLVARS_OK;
}
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
}
}
result = "Syntax error\n" + help_string();
return COLVARSCRIPT_ERROR;
}
std::string colvarscript::help_string()
{
std::string buf;
buf = "Usage: cv <subcommand> [args...]\n\
\n\
-Managing the colvars module:\n\
+Managing the Colvars module:\n\
configfile <file name> -- read configuration from a file\n\
config <string> -- read configuration from the given string\n\
reset -- delete all internal configuration\n\
- delete -- delete this colvars module instance\n\
+ delete -- delete this Colvars module instance\n\
version -- return version of colvars code\n\
\n\
Input and output:\n\
list -- return a list of all variables\n\
list biases -- return a list of all biases\n\
load <file name> -- load a state file (requires configuration)\n\
save <file name> -- save a state file (requires configuration)\n\
update -- recalculate colvars and biases\n\
addenergy <E> -- add <E> to the total bias energy\n\
printframe -- return a summary of the current frame\n\
printframelabels -- return labels to annotate printframe's output\n";
long int tmp;
if (proxy->get_frame(tmp) != COLVARS_NOT_IMPLEMENTED) {
buf += "\
frame -- return current frame number\n\
frame <new_frame> -- set frame number\n";
}
buf += "\n\
Accessing collective variables:\n\
colvar <name> value -- return the current value of colvar <name>\n\
colvar <name> update -- recalculate colvar <name>\n\
colvar <name> type -- return the type of colvar <name>\n\
colvar <name> delete -- delete colvar <name>\n\
colvar <name> addforce <F> -- apply given force on colvar <name>\n\
colvar <name> getconfig -- return config string of colvar <name>\n\
colvar <name> cvcflags <fl> -- enable or disable cvcs according to 0/1 flags\n\
colvar <name> get <f> -- get the value of the colvar feature <f>\n\
colvar <name> set <f> <val> -- set the value of the colvar feature <f>\n\
\n\
Accessing biases:\n\
bias <name> energy -- return the current energy of bias <name>\n\
bias <name> update -- recalculate bias <name>\n\
bias <name> delete -- delete bias <name>\n\
bias <name> getconfig -- return config string of bias <name>\n\
bias <name> get <f> -- get the value of the bias feature <f>\n\
bias <name> set <f> <val> -- set the value of the bias feature <f>\n\
";
return buf;
}
diff --git a/lib/colvars/colvarscript.h b/lib/colvars/colvarscript.h
index 46b1ddd20..94d451809 100644
--- a/lib/colvars/colvarscript.h
+++ b/lib/colvars/colvarscript.h
@@ -1,63 +1,71 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARSCRIPT_H
#define COLVARSCRIPT_H
#include <string>
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarbias.h"
#include "colvarproxy.h"
// Only these error values are part of the scripting interface
#define COLVARSCRIPT_ERROR -1
#define COLVARSCRIPT_OK 0
class colvarscript {
private:
colvarproxy *proxy;
colvarmodule *colvars;
inline colvarscript() {} // no-argument construction forbidden
public:
friend class colvarproxy;
colvarscript(colvarproxy * p);
inline ~colvarscript() {}
/// If an error is caught by the proxy through fatal_error(), this is set to COLVARSCRIPT_ERROR
int proxy_error;
/// If an error is returned by one of the methods, it should set this to the error message
std::string result;
- /// Run script command with given positional arguments
- int run(int argc, char const *argv[]);
+ /// Run script command with given positional arguments (objects)
+ int run(int objc, unsigned char *const objv[]);
private:
/// Run subcommands on colvar
- int proc_colvar(int argc, char const *argv[]);
+ int proc_colvar(colvar *cv, int argc, unsigned char *const argv[]);
/// Run subcommands on bias
- int proc_bias(int argc, char const *argv[]);
+ int proc_bias(colvarbias *b, int argc, unsigned char *const argv[]);
/// Run subcommands on base colvardeps object (colvar, bias, ...)
int proc_features(colvardeps *obj,
- int argc, char const *argv[]);
+ int argc, unsigned char *const argv[]);
- /// Builds and return a short help
+ /// Build and return a short help
std::string help_string(void);
+
+public:
+
+ inline char const *obj_to_str(unsigned char *const obj)
+ {
+ return cvm::proxy->script_obj_to_str(obj);
+ }
+
};
#endif
diff --git a/lib/colvars/colvartypes.h b/lib/colvars/colvartypes.h
index e0cebb83b..17c09a509 100644
--- a/lib/colvars/colvartypes.h
+++ b/lib/colvars/colvartypes.h
@@ -1,1599 +1,1604 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARTYPES_H
#define COLVARTYPES_H
#include <cmath>
#include <vector>
#include "colvarmodule.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
// ----------------------------------------------------------------------
/// Linear algebra functions and data types used in the collective
/// variables implemented so far
// ----------------------------------------------------------------------
/// \brief Arbitrary size array (one dimensions) suitable for linear
/// algebra operations (i.e. for floating point numbers it can be used
/// with library functions)
template <class T> class colvarmodule::vector1d
{
protected:
std::vector<T> data;
public:
/// Default constructor
inline vector1d(size_t const n = 0)
{
data.resize(n);
reset();
}
/// Constructor from C array
inline vector1d(size_t const n, T const *t)
{
data.resize(n);
reset();
size_t i;
for (i = 0; i < size(); i++) {
data[i] = t[i];
}
}
/// Return a pointer to the data location
inline T * c_array()
{
if (data.size() > 0) {
return &(data[0]);
} else {
return NULL;
}
}
/// Return a reference to the data
inline std::vector<T> &data_array()
{
return data;
}
inline ~vector1d()
{
data.clear();
}
/// Set all elements to zero
inline void reset()
{
data.assign(data.size(), T(0.0));
}
inline size_t size() const
{
return data.size();
}
inline void resize(size_t const n)
{
data.resize(n);
}
+ inline void clear()
+ {
+ data.clear();
+ }
+
inline T & operator [] (size_t const i) {
return data[i];
}
inline T const & operator [] (size_t const i) const {
return data[i];
}
inline static void check_sizes(vector1d<T> const &v1, vector1d<T> const &v2)
{
if (v1.size() != v2.size()) {
cvm::error("Error: trying to perform an operation between vectors of different sizes, "+
cvm::to_str(v1.size())+" and "+cvm::to_str(v2.size())+".\n");
}
}
inline void operator += (vector1d<T> const &v)
{
check_sizes(*this, v);
size_t i;
for (i = 0; i < this->size(); i++) {
(*this)[i] += v[i];
}
}
inline void operator -= (vector1d<T> const &v)
{
check_sizes(*this, v);
size_t i;
for (i = 0; i < this->size(); i++) {
(*this)[i] -= v[i];
}
}
inline void operator *= (cvm::real const &a)
{
size_t i;
for (i = 0; i < this->size(); i++) {
(*this)[i] *= a;
}
}
inline void operator /= (cvm::real const &a)
{
size_t i;
for (i = 0; i < this->size(); i++) {
(*this)[i] /= a;
}
}
inline friend vector1d<T> operator + (vector1d<T> const &v1, vector1d<T> const &v2)
{
check_sizes(v1.size(), v2.size());
vector1d<T> result(v1.size());
size_t i;
for (i = 0; i < v1.size(); i++) {
result[i] = v1[i] + v2[i];
}
return result;
}
inline friend vector1d<T> operator - (vector1d<T> const &v1, vector1d<T> const &v2)
{
check_sizes(v1.size(), v2.size());
vector1d<T> result(v1.size());
size_t i;
for (i = 0; i < v1.size(); i++) {
result[i] = v1[i] - v2[i];
}
return result;
}
inline friend vector1d<T> operator * (vector1d<T> const &v, cvm::real const &a)
{
vector1d<T> result(v.size());
size_t i;
for (i = 0; i < v.size(); i++) {
result[i] = v[i] * a;
}
return result;
}
inline friend vector1d<T> operator * (cvm::real const &a, vector1d<T> const &v)
{
return v * a;
}
inline friend vector1d<T> operator / (vector1d<T> const &v, cvm::real const &a)
{
vector1d<T> result(v.size());
size_t i;
for (i = 0; i < v.size(); i++) {
result[i] = v[i] / a;
}
return result;
}
/// Inner product
inline friend T operator * (vector1d<T> const &v1, vector1d<T> const &v2)
{
check_sizes(v1.size(), v2.size());
T prod(0.0);
size_t i;
for (i = 0; i < v1.size(); i++) {
prod += v1[i] * v2[i];
}
return prod;
}
/// Squared norm
inline cvm::real norm2() const
{
cvm::real result = 0.0;
size_t i;
for (i = 0; i < this->size(); i++) {
result += (*this)[i] * (*this)[i];
}
return result;
}
inline cvm::real norm() const
{
return std::sqrt(this->norm2());
}
inline cvm::real sum() const
{
cvm::real result = 0.0;
size_t i;
for (i = 0; i < this->size(); i++) {
result += (*this)[i];
}
return result;
}
/// Slicing
inline vector1d<T> const slice(size_t const i1, size_t const i2) const
{
if ((i2 < i1) || (i2 >= this->size())) {
cvm::error("Error: trying to slice a vector using incorrect boundaries.\n");
}
vector1d<T> result(i2 - i1);
size_t i;
for (i = 0; i < (i2 - i1); i++) {
result[i] = (*this)[i1+i];
}
return result;
}
/// Assign a vector to a slice of this vector
inline void sliceassign(size_t const i1, size_t const i2, vector1d<T> const &v)
{
if ((i2 < i1) || (i2 >= this->size())) {
cvm::error("Error: trying to slice a vector using incorrect boundaries.\n");
}
size_t i;
for (i = 0; i < (i2 - i1); i++) {
(*this)[i1+i] = v[i];
}
}
/// Formatted output
inline size_t output_width(size_t const &real_width) const
{
return real_width*(this->size()) + 3*(this->size()-1) + 4;
}
inline friend std::istream & operator >> (std::istream &is, cvm::vector1d<T> &v)
{
if (v.size() == 0) return is;
size_t const start_pos = is.tellg();
char sep;
if ( !(is >> sep) || !(sep == '(') ) {
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
return is;
}
size_t count = 0;
while ( (is >> v[count]) &&
(count < (v.size()-1) ? ((is >> sep) && (sep == ',')) : true) ) {
if (++count == v.size()) break;
}
if (count < v.size()) {
is.clear();
is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit);
}
return is;
}
inline friend std::ostream & operator << (std::ostream &os, cvm::vector1d<T> const &v)
{
std::streamsize const w = os.width();
std::streamsize const p = os.precision();
os.width(2);
os << "( ";
size_t i;
for (i = 0; i < v.size()-1; i++) {
os.width(w); os.precision(p);
os << v[i] << " , ";
}
os.width(w); os.precision(p);
os << v[v.size()-1] << " )";
return os;
}
inline std::string to_simple_string() const
{
if (this->size() == 0) return std::string("");
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
os.precision(cvm::cv_prec);
os << (*this)[0];
size_t i;
for (i = 1; i < this->size(); i++) {
os << " " << (*this)[i];
}
return os.str();
}
inline int from_simple_string(std::string const &s)
{
std::stringstream stream(s);
size_t i = 0;
if (this->size()) {
while ((stream >> (*this)[i]) && (i < this->size())) {
i++;
}
if (i < this->size()) {
return COLVARS_ERROR;
}
} else {
T input;
while (stream >> input) {
if ((i % 100) == 0) {
data.reserve(data.size()+100);
}
data.resize(data.size()+1);
data[i] = input;
i++;
}
}
return COLVARS_OK;
}
};
/// \brief Arbitrary size array (two dimensions) suitable for linear
/// algebra operations (i.e. for floating point numbers it can be used
/// with library functions)
template <class T> class colvarmodule::matrix2d
{
public:
friend class row;
size_t outer_length;
size_t inner_length;
protected:
class row {
public:
T * data;
size_t length;
inline row(T * const row_data, size_t const inner_length)
: data(row_data), length(inner_length)
{}
inline T & operator [] (size_t const j) {
return *(data+j);
}
inline T const & operator [] (size_t const j) const {
return *(data+j);
}
inline operator vector1d<T>() const
{
return vector1d<T>(length, data);
}
};
std::vector<T> data;
std::vector<row> rows;
std::vector<T *> pointers;
public:
/// Allocation routine, used by all constructors
inline void resize(size_t const ol, size_t const il)
{
if ((ol > 0) && (il > 0)) {
if (data.size() > 0) {
// copy previous data
size_t i, j;
std::vector<T> new_data(ol * il);
for (i = 0; i < outer_length; i++) {
for (j = 0; j < inner_length; j++) {
new_data[il*i+j] = data[inner_length*i+j];
}
}
data.resize(ol * il);
// copy them back
data = new_data;
} else {
data.resize(ol * il);
}
outer_length = ol;
inner_length = il;
if (data.size() > 0) {
// rebuild rows
size_t i;
rows.clear();
rows.reserve(outer_length);
pointers.clear();
pointers.reserve(outer_length);
for (i = 0; i < outer_length; i++) {
rows.push_back(row(&(data[0])+inner_length*i, inner_length));
pointers.push_back(&(data[0])+inner_length*i);
}
}
} else {
// zero size
data.clear();
rows.clear();
}
}
/// Deallocation routine
inline void clear() {
rows.clear();
data.clear();
}
/// Set all elements to zero
inline void reset()
{
data.assign(data.size(), T(0.0));
}
inline size_t size() const
{
return data.size();
}
/// Default constructor
inline matrix2d()
: outer_length(0), inner_length(0)
{
this->resize(0, 0);
}
inline matrix2d(size_t const ol, size_t const il)
: outer_length(ol), inner_length(il)
{
this->resize(outer_length, inner_length);
reset();
}
/// Copy constructor
inline matrix2d(matrix2d<T> const &m)
: outer_length(m.outer_length), inner_length(m.inner_length)
{
// reinitialize data and rows arrays
this->resize(outer_length, inner_length);
// copy data
data = m.data;
}
/// Destructor
inline ~matrix2d() {
this->clear();
}
/// Return a reference to the data
inline std::vector<T> &data_array()
{
return data;
}
inline row & operator [] (size_t const i)
{
return rows[i];
}
inline row const & operator [] (size_t const i) const
{
return rows[i];
}
/// Assignment
inline matrix2d<T> & operator = (matrix2d<T> const &m)
{
if ((outer_length != m.outer_length) || (inner_length != m.inner_length)){
this->clear();
outer_length = m.outer_length;
inner_length = m.inner_length;
this->resize(outer_length, inner_length);
}
data = m.data;
return *this;
}
/// Return the 2-d C array
inline T ** c_array() {
if (rows.size() > 0) {
return &(pointers[0]);
} else {
return NULL;
}
}
inline static void check_sizes(matrix2d<T> const &m1, matrix2d<T> const &m2)
{
if ((m1.outer_length != m2.outer_length) ||
(m1.inner_length != m2.inner_length)) {
cvm::error("Error: trying to perform an operation between matrices of different sizes, "+
cvm::to_str(m1.outer_length)+"x"+cvm::to_str(m1.inner_length)+" and "+
cvm::to_str(m2.outer_length)+"x"+cvm::to_str(m2.inner_length)+".\n");
}
}
inline void operator += (matrix2d<T> const &m)
{
check_sizes(*this, m);
size_t i;
for (i = 0; i < data.size(); i++) {
data[i] += m.data[i];
}
}
inline void operator -= (matrix2d<T> const &m)
{
check_sizes(*this, m);
size_t i;
for (i = 0; i < data.size(); i++) {
data[i] -= m.data[i];
}
}
inline void operator *= (cvm::real const &a)
{
size_t i;
for (i = 0; i < data.size(); i++) {
data[i] *= a;
}
}
inline void operator /= (cvm::real const &a)
{
size_t i;
for (i = 0; i < data.size(); i++) {
data[i] /= a;
}
}
inline friend matrix2d<T> operator + (matrix2d<T> const &m1, matrix2d<T> const &m2)
{
check_sizes(m1, m2);
matrix2d<T> result(m1.outer_length, m1.inner_length);
size_t i;
for (i = 0; i < m1.data.size(); i++) {
result.data[i] = m1.data[i] + m2.data[i];
}
return result;
}
inline friend matrix2d<T> operator - (matrix2d<T> const &m1, matrix2d<T> const &m2)
{
check_sizes(m1, m2);
matrix2d<T> result(m1.outer_length, m1.inner_length);
size_t i;
for (i = 0; i < m1.data.size(); i++) {
result.data[i] = m1.data[i] - m1.data[i];
}
return result;
}
inline friend matrix2d<T> operator * (matrix2d<T> const &m, cvm::real const &a)
{
matrix2d<T> result(m.outer_length, m.inner_length);
size_t i;
for (i = 0; i < m.data.size(); i++) {
result.data[i] = m.data[i] * a;
}
return result;
}
inline friend matrix2d<T> operator * (cvm::real const &a, matrix2d<T> const &m)
{
return m * a;
}
inline friend matrix2d<T> operator / (matrix2d<T> const &m, cvm::real const &a)
{
matrix2d<T> result(m.outer_length, m.inner_length);
size_t i;
for (i = 0; i < m.data.size(); i++) {
result.data[i] = m.data[i] * a;
}
return result;
}
/// Matrix multiplication
// inline friend matrix2d<T> const & operator * (matrix2d<T> const &m1, matrix2d<T> const &m2)
// {
// matrix2d<T> result(m1.outer_length, m2.inner_length);
// if (m1.inner_length != m2.outer_length) {
// cvm::error("Error: trying to multiply two matrices of incompatible sizes, "+
// cvm::to_str(m1.outer_length)+"x"+cvm::to_str(m1.inner_length)+" and "+
// cvm::to_str(m2.outer_length)+"x"+cvm::to_str(m2.inner_length)+".\n");
// } else {
// size_t i, j, k;
// for (i = 0; i < m1.outer_length; i++) {
// for (j = 0; j < m2.inner_length; j++) {
// for (k = 0; k < m1.inner_length; k++) {
// result[i][j] += m1[i][k] * m2[k][j];
// }
// }
// }
// }
// return result;
// }
/// vector-matrix multiplication
inline friend vector1d<T> operator * (vector1d<T> const &v, matrix2d<T> const &m)
{
vector1d<T> result(m.inner_length);
if (m.outer_length != v.size()) {
cvm::error("Error: trying to multiply a vector and a matrix of incompatible sizes, "+
cvm::to_str(v.size()) + " and " + cvm::to_str(m.outer_length)+"x"+cvm::to_str(m.inner_length) + ".\n");
} else {
size_t i, k;
for (i = 0; i < m.inner_length; i++) {
for (k = 0; k < m.outer_length; k++) {
result[i] += m[k][i] * v[k];
}
}
}
return result;
}
// /// matrix-vector multiplication (unused for now)
// inline friend vector1d<T> const & operator * (matrix2d<T> const &m, vector1d<T> const &v)
// {
// vector1d<T> result(m.outer_length);
// if (m.inner_length != v.size()) {
// cvm::error("Error: trying to multiply a matrix and a vector of incompatible sizes, "+
// cvm::to_str(m.outer_length)+"x"+cvm::to_str(m.inner_length)
// + " and " + cvm::to_str(v.length) + ".\n");
// } else {
// size_t i, k;
// for (i = 0; i < m.outer_length; i++) {
// for (k = 0; k < m.inner_length; k++) {
// result[i] += m[i][k] * v[k];
// }
// }
// }
// return result;
// }
/// Formatted output
friend std::ostream & operator << (std::ostream &os,
matrix2d<T> const &m)
{
std::streamsize const w = os.width();
std::streamsize const p = os.precision();
os.width(2);
os << "( ";
size_t i;
for (i = 0; i < m.outer_length; i++) {
os << " ( ";
size_t j;
for (j = 0; j < m.inner_length-1; j++) {
os.width(w);
os.precision(p);
os << m[i][j] << " , ";
}
os.width(w);
os.precision(p);
os << m[i][m.inner_length-1] << " )";
}
os << " )";
return os;
}
inline std::string to_simple_string() const
{
if (this->size() == 0) return std::string("");
std::ostringstream os;
os.setf(std::ios::scientific, std::ios::floatfield);
os.precision(cvm::cv_prec);
os << (*this)[0];
size_t i;
for (i = 1; i < data.size(); i++) {
os << " " << data[i];
}
return os.str();
}
inline int from_simple_string(std::string const &s)
{
std::stringstream stream(s);
size_t i = 0;
while ((stream >> data[i]) && (i < data.size())) {
i++;
}
if (i < data.size()) {
return COLVARS_ERROR;
}
return COLVARS_OK;
}
};
/// vector of real numbers with three components
class colvarmodule::rvector {
public:
cvm::real x, y, z;
inline rvector()
: x(0.0), y(0.0), z(0.0)
{}
inline rvector(cvm::real const &x_i,
cvm::real const &y_i,
cvm::real const &z_i)
: x(x_i), y(y_i), z(z_i)
{}
inline rvector(cvm::vector1d<cvm::real> const &v)
: x(v[0]), y(v[1]), z(v[2])
{}
inline rvector(cvm::real t)
: x(t), y(t), z(t)
{}
/// \brief Set all components to a scalar value
inline void set(cvm::real const &value) {
x = y = z = value;
}
/// \brief Assign all components
inline void set(cvm::real const &x_i,
cvm::real const &y_i,
cvm::real const &z_i) {
x = x_i;
y = y_i;
z = z_i;
}
/// \brief Set all components to zero
inline void reset() {
x = y = z = 0.0;
}
/// \brief Access cartesian components by index
inline cvm::real & operator [] (int const &i) {
return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
}
/// \brief Access cartesian components by index
inline cvm::real const & operator [] (int const &i) const {
return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x;
}
inline cvm::vector1d<cvm::real> const as_vector() const
{
cvm::vector1d<cvm::real> result(3);
result[0] = this->x;
result[1] = this->y;
result[2] = this->z;
return result;
}
inline cvm::rvector & operator = (cvm::real const &v)
{
x = v;
y = v;
z = v;
return *this;
}
inline void operator += (cvm::rvector const &v)
{
x += v.x;
y += v.y;
z += v.z;
}
inline void operator -= (cvm::rvector const &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
}
inline void operator *= (cvm::real const &v)
{
x *= v;
y *= v;
z *= v;
}
inline void operator /= (cvm::real const& v)
{
x /= v;
y /= v;
z /= v;
}
inline cvm::real norm2() const
{
return (x*x + y*y + z*z);
}
inline cvm::real norm() const
{
return std::sqrt(this->norm2());
}
inline cvm::rvector unit() const
{
const cvm::real n = this->norm();
return (n > 0. ? cvm::rvector(x, y, z)/n : cvm::rvector(1., 0., 0.));
}
static inline size_t output_width(size_t const &real_width)
{
return 3*real_width + 10;
}
static inline cvm::rvector outer(cvm::rvector const &v1, cvm::rvector const &v2)
{
return cvm::rvector( v1.y*v2.z - v2.y*v1.z,
-v1.x*v2.z + v2.x*v1.z,
v1.x*v2.y - v2.x*v1.y);
}
friend inline cvm::rvector operator - (cvm::rvector const &v)
{
return cvm::rvector(-v.x, -v.y, -v.z);
}
friend inline int operator == (cvm::rvector const &v1, cvm::rvector const &v2)
{
return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
}
friend inline int operator != (cvm::rvector const &v1, cvm::rvector const &v2)
{
return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z);
}
friend inline cvm::rvector operator + (cvm::rvector const &v1, cvm::rvector const &v2)
{
return cvm::rvector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
friend inline cvm::rvector operator - (cvm::rvector const &v1, cvm::rvector const &v2)
{
return cvm::rvector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}
friend inline cvm::real operator * (cvm::rvector const &v1, cvm::rvector const &v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
friend inline cvm::rvector operator * (cvm::real const &a, cvm::rvector const &v)
{
return cvm::rvector(a*v.x, a*v.y, a*v.z);
}
friend inline cvm::rvector operator * (cvm::rvector const &v, cvm::real const &a)
{
return cvm::rvector(a*v.x, a*v.y, a*v.z);
}
friend inline cvm::rvector operator / (cvm::rvector const &v, cvm::real const &a)
{
return cvm::rvector(v.x/a, v.y/a, v.z/a);
}
std::string to_simple_string() const;
int from_simple_string(std::string const &s);
};
/// \brief 2-dimensional array of real numbers with three components
/// along each dimension (works with colvarmodule::rvector)
class colvarmodule::rmatrix
: public colvarmodule::matrix2d<colvarmodule::real> {
private:
public:
/// Return the xx element
inline cvm::real & xx() { return (*this)[0][0]; }
/// Return the xy element
inline cvm::real & xy() { return (*this)[0][1]; }
/// Return the xz element
inline cvm::real & xz() { return (*this)[0][2]; }
/// Return the yx element
inline cvm::real & yx() { return (*this)[1][0]; }
/// Return the yy element
inline cvm::real & yy() { return (*this)[1][1]; }
/// Return the yz element
inline cvm::real & yz() { return (*this)[1][2]; }
/// Return the zx element
inline cvm::real & zx() { return (*this)[2][0]; }
/// Return the zy element
inline cvm::real & zy() { return (*this)[2][1]; }
/// Return the zz element
inline cvm::real & zz() { return (*this)[2][2]; }
/// Return the xx element
inline cvm::real xx() const { return (*this)[0][0]; }
/// Return the xy element
inline cvm::real xy() const { return (*this)[0][1]; }
/// Return the xz element
inline cvm::real xz() const { return (*this)[0][2]; }
/// Return the yx element
inline cvm::real yx() const { return (*this)[1][0]; }
/// Return the yy element
inline cvm::real yy() const { return (*this)[1][1]; }
/// Return the yz element
inline cvm::real yz() const { return (*this)[1][2]; }
/// Return the zx element
inline cvm::real zx() const { return (*this)[2][0]; }
/// Return the zy element
inline cvm::real zy() const { return (*this)[2][1]; }
/// Return the zz element
inline cvm::real zz() const { return (*this)[2][2]; }
/// Default constructor
inline rmatrix()
: cvm::matrix2d<cvm::real>(3, 3)
{}
/// Constructor component by component
inline rmatrix(cvm::real const &xxi,
cvm::real const &xyi,
cvm::real const &xzi,
cvm::real const &yxi,
cvm::real const &yyi,
cvm::real const &yzi,
cvm::real const &zxi,
cvm::real const &zyi,
cvm::real const &zzi)
: cvm::matrix2d<cvm::real>(3, 3)
{
this->xx() = xxi;
this->xy() = xyi;
this->xz() = xzi;
this->yx() = yxi;
this->yy() = yyi;
this->yz() = yzi;
this->zx() = zxi;
this->zy() = zyi;
this->zz() = zzi;
}
/// Destructor
inline ~rmatrix()
{}
/// Return the determinant
inline cvm::real determinant() const
{
return
( xx() * (yy()*zz() - zy()*yz()))
- (yx() * (xy()*zz() - zy()*xz()))
+ (zx() * (xy()*yz() - yy()*xz()));
}
inline cvm::rmatrix transpose() const
{
return cvm::rmatrix(this->xx(),
this->yx(),
this->zx(),
this->xy(),
this->yy(),
this->zy(),
this->xz(),
this->yz(),
this->zz());
}
friend cvm::rvector operator * (cvm::rmatrix const &m, cvm::rvector const &r);
// friend inline cvm::rmatrix const operator * (cvm::rmatrix const &m1, cvm::rmatrix const &m2) {
// return cvm::rmatrix (m1.xx()*m2.xx() + m1.xy()*m2.yx() + m1.xz()*m2.yz(),
// m1.xx()*m2.xy() + m1.xy()*m2.yy() + m1.xz()*m2.zy(),
// m1.xx()*m2.xz() + m1.xy()*m2.yz() + m1.xz()*m2.zz(),
// m1.yx()*m2.xx() + m1.yy()*m2.yx() + m1.yz()*m2.yz(),
// m1.yx()*m2.xy() + m1.yy()*m2.yy() + m1.yz()*m2.yy(),
// m1.yx()*m2.xz() + m1.yy()*m2.yz() + m1.yz()*m2.yz(),
// m1.zx()*m2.xx() + m1.zy()*m2.yx() + m1.zz()*m2.yz(),
// m1.zx()*m2.xy() + m1.zy()*m2.yy() + m1.zz()*m2.yy(),
// m1.zx()*m2.xz() + m1.zy()*m2.yz() + m1.zz()*m2.yz());
// }
};
inline cvm::rvector operator * (cvm::rmatrix const &m,
cvm::rvector const &r)
{
return cvm::rvector(m.xx()*r.x + m.xy()*r.y + m.xz()*r.z,
m.yx()*r.x + m.yy()*r.y + m.yz()*r.z,
m.zx()*r.x + m.zy()*r.y + m.zz()*r.z);
}
/// Numerical recipes diagonalization
void jacobi(cvm::real **a, cvm::real *d, cvm::real **v, int *nrot);
/// Eigenvector sort
void eigsrt(cvm::real *d, cvm::real **v);
/// Transpose the matrix
void transpose(cvm::real **v);
/// \brief 1-dimensional vector of real numbers with four components and
/// a quaternion algebra
class colvarmodule::quaternion {
public:
cvm::real q0, q1, q2, q3;
/// Constructor from a 3-d vector
inline quaternion(cvm::real const &x, cvm::real const &y, cvm::real const &z)
: q0(0.0), q1(x), q2(y), q3(z)
{}
/// Constructor component by component
inline quaternion(cvm::real const qv[4])
: q0(qv[0]), q1(qv[1]), q2(qv[2]), q3(qv[3])
{}
/// Constructor component by component
inline quaternion(cvm::real const &q0i,
cvm::real const &q1i,
cvm::real const &q2i,
cvm::real const &q3i)
: q0(q0i), q1(q1i), q2(q2i), q3(q3i)
{}
inline quaternion(cvm::vector1d<cvm::real> const &v)
: q0(v[0]), q1(v[1]), q2(v[2]), q3(v[3])
{}
/// "Constructor" after Euler angles (in radians)
///
/// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
inline void set_from_euler_angles(cvm::real const &phi_in,
cvm::real const &theta_in,
cvm::real const &psi_in)
{
q0 = ( (std::cos(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::cos(psi_in/2.0)) +
(std::sin(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::sin(psi_in/2.0)) );
q1 = ( (std::sin(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::cos(psi_in/2.0)) -
(std::cos(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::sin(psi_in/2.0)) );
q2 = ( (std::cos(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::cos(psi_in/2.0)) +
(std::sin(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::sin(psi_in/2.0)) );
q3 = ( (std::cos(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::sin(psi_in/2.0)) -
(std::sin(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::cos(psi_in/2.0)) );
}
/// \brief Default constructor
inline quaternion()
{
reset();
}
/// \brief Set all components to a scalar
inline void set(cvm::real const &value = 0.0)
{
q0 = q1 = q2 = q3 = value;
}
/// \brief Set all components to zero (null quaternion)
inline void reset()
{
q0 = q1 = q2 = q3 = 0.0;
}
/// \brief Set the q0 component to 1 and the others to 0 (quaternion
/// representing no rotation)
inline void reset_rotation()
{
q0 = 1.0;
q1 = q2 = q3 = 0.0;
}
/// Tell the number of characters required to print a quaternion, given that of a real number
static inline size_t output_width(size_t const &real_width)
{
return 4*real_width + 13;
}
std::string to_simple_string() const;
int from_simple_string(std::string const &s);
/// \brief Formatted output operator
friend std::ostream & operator << (std::ostream &os, cvm::quaternion const &q);
/// \brief Formatted input operator
friend std::istream & operator >> (std::istream &is, cvm::quaternion &q);
/// Access the quaternion as a 4-d array (return a reference)
inline cvm::real & operator [] (int const &i) {
switch (i) {
case 0:
return this->q0;
case 1:
return this->q1;
case 2:
return this->q2;
case 3:
return this->q3;
default:
cvm::error("Error: incorrect quaternion component.\n");
return q0;
}
}
/// Access the quaternion as a 4-d array (return a value)
inline cvm::real operator [] (int const &i) const {
switch (i) {
case 0:
return this->q0;
case 1:
return this->q1;
case 2:
return this->q2;
case 3:
return this->q3;
default:
cvm::error("Error: trying to access a quaternion "
"component which is not between 0 and 3.\n");
return 0.0;
}
}
inline cvm::vector1d<cvm::real> const as_vector() const
{
cvm::vector1d<cvm::real> result(4);
result[0] = q0;
result[1] = q1;
result[2] = q2;
result[3] = q3;
return result;
}
/// Square norm of the quaternion
inline cvm::real norm2() const
{
return q0*q0 + q1*q1 + q2*q2 + q3*q3;
}
/// Norm of the quaternion
inline cvm::real norm() const
{
return std::sqrt(this->norm2());
}
/// Return the conjugate quaternion
inline cvm::quaternion conjugate() const
{
return cvm::quaternion(q0, -q1, -q2, -q3);
}
inline void operator *= (cvm::real const &a)
{
q0 *= a; q1 *= a; q2 *= a; q3 *= a;
}
inline void operator /= (cvm::real const &a)
{
q0 /= a; q1 /= a; q2 /= a; q3 /= a;
}
inline void set_positive()
{
if (q0 > 0.0) return;
q0 = -q0;
q1 = -q1;
q2 = -q2;
q3 = -q3;
}
inline void operator += (cvm::quaternion const &h)
{
q0+=h.q0; q1+=h.q1; q2+=h.q2; q3+=h.q3;
}
inline void operator -= (cvm::quaternion const &h)
{
q0-=h.q0; q1-=h.q1; q2-=h.q2; q3-=h.q3;
}
/// Promote a 3-vector to a quaternion
static inline cvm::quaternion promote(cvm::rvector const &v)
{
return cvm::quaternion(0.0, v.x, v.y, v.z);
}
/// Return the vector component
inline cvm::rvector get_vector() const
{
return cvm::rvector(q1, q2, q3);
}
friend inline cvm::quaternion operator + (cvm::quaternion const &h, cvm::quaternion const &q)
{
return cvm::quaternion(h.q0+q.q0, h.q1+q.q1, h.q2+q.q2, h.q3+q.q3);
}
friend inline cvm::quaternion operator - (cvm::quaternion const &h, cvm::quaternion const &q)
{
return cvm::quaternion(h.q0-q.q0, h.q1-q.q1, h.q2-q.q2, h.q3-q.q3);
}
/// \brief Provides the quaternion product. \b NOTE: for the inner
/// product use: \code h.inner (q); \endcode
friend inline cvm::quaternion operator * (cvm::quaternion const &h, cvm::quaternion const &q)
{
return cvm::quaternion(h.q0*q.q0 - h.q1*q.q1 - h.q2*q.q2 - h.q3*q.q3,
h.q0*q.q1 + h.q1*q.q0 + h.q2*q.q3 - h.q3*q.q2,
h.q0*q.q2 + h.q2*q.q0 + h.q3*q.q1 - h.q1*q.q3,
h.q0*q.q3 + h.q3*q.q0 + h.q1*q.q2 - h.q2*q.q1);
}
friend inline cvm::quaternion operator * (cvm::real const &c,
cvm::quaternion const &q)
{
return cvm::quaternion(c*q.q0, c*q.q1, c*q.q2, c*q.q3);
}
friend inline cvm::quaternion operator * (cvm::quaternion const &q,
cvm::real const &c)
{
return cvm::quaternion(q.q0*c, q.q1*c, q.q2*c, q.q3*c);
}
friend inline cvm::quaternion operator / (cvm::quaternion const &q,
cvm::real const &c)
{
return cvm::quaternion(q.q0/c, q.q1/c, q.q2/c, q.q3/c);
}
/// \brief Rotate v through this quaternion (put it in the rotated
/// reference frame)
inline cvm::rvector rotate(cvm::rvector const &v) const
{
return ((*this) * promote(v) * ((*this).conjugate())).get_vector();
}
/// \brief Rotate Q2 through this quaternion (put it in the rotated
/// reference frame)
inline cvm::quaternion rotate(cvm::quaternion const &Q2) const
{
cvm::rvector const vq_rot = this->rotate(Q2.get_vector());
return cvm::quaternion(Q2.q0, vq_rot.x, vq_rot.y, vq_rot.z);
}
/// Return the 3x3 matrix associated to this quaternion
inline cvm::rmatrix rotation_matrix() const
{
cvm::rmatrix R;
R.xx() = q0*q0 + q1*q1 - q2*q2 - q3*q3;
R.yy() = q0*q0 - q1*q1 + q2*q2 - q3*q3;
R.zz() = q0*q0 - q1*q1 - q2*q2 + q3*q3;
R.xy() = 2.0 * (q1*q2 - q0*q3);
R.xz() = 2.0 * (q0*q2 + q1*q3);
R.yx() = 2.0 * (q0*q3 + q1*q2);
R.yz() = 2.0 * (q2*q3 - q0*q1);
R.zx() = 2.0 * (q1*q3 - q0*q2);
R.zy() = 2.0 * (q0*q1 + q2*q3);
return R;
}
/// \brief Multiply the given vector by the derivative of the given
/// (rotated) position with respect to the quaternion
cvm::quaternion position_derivative_inner(cvm::rvector const &pos,
cvm::rvector const &vec) const;
/// \brief Return the cosine between the orientation frame
/// associated to this quaternion and another
inline cvm::real cosine(cvm::quaternion const &q) const
{
cvm::real const iprod = this->inner(q);
return 2.0*iprod*iprod - 1.0;
}
/// \brief Square distance from another quaternion on the
/// 4-dimensional unit sphere: returns the square of the angle along
/// the shorter of the two geodesics
inline cvm::real dist2(cvm::quaternion const &Q2) const
{
cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
this->q2*Q2.q2 + this->q3*Q2.q3;
cvm::real const omega = std::acos( (cos_omega > 1.0) ? 1.0 :
( (cos_omega < -1.0) ? -1.0 : cos_omega) );
// get the minimum distance: x and -x are the same quaternion
if (cos_omega > 0.0)
return omega * omega;
else
return (PI-omega) * (PI-omega);
}
/// Gradient of the square distance: returns a 4-vector equivalent
/// to that provided by slerp
inline cvm::quaternion dist2_grad(cvm::quaternion const &Q2) const
{
cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3;
cvm::real const omega = std::acos( (cos_omega > 1.0) ? 1.0 :
( (cos_omega < -1.0) ? -1.0 : cos_omega) );
cvm::real const sin_omega = std::sin(omega);
if (std::fabs(sin_omega) < 1.0E-14) {
// return a null 4d vector
return cvm::quaternion(0.0, 0.0, 0.0, 0.0);
}
cvm::quaternion const
grad1((-1.0)*sin_omega*Q2.q0 + cos_omega*(this->q0-cos_omega*Q2.q0)/sin_omega,
(-1.0)*sin_omega*Q2.q1 + cos_omega*(this->q1-cos_omega*Q2.q1)/sin_omega,
(-1.0)*sin_omega*Q2.q2 + cos_omega*(this->q2-cos_omega*Q2.q2)/sin_omega,
(-1.0)*sin_omega*Q2.q3 + cos_omega*(this->q3-cos_omega*Q2.q3)/sin_omega);
if (cos_omega > 0.0) {
return 2.0*omega*grad1;
}
else {
return -2.0*(PI-omega)*grad1;
}
}
/// \brief Choose the closest between Q2 and -Q2 and save it back.
/// Not required for dist2() and dist2_grad()
inline void match(cvm::quaternion &Q2) const
{
cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 +
this->q2*Q2.q2 + this->q3*Q2.q3;
if (cos_omega < 0.0) Q2 *= -1.0;
}
/// \brief Inner product (as a 4-d vector) with Q2; requires match()
/// if the largest overlap is looked for
inline cvm::real inner(cvm::quaternion const &Q2) const
{
cvm::real const prod = this->q0*Q2.q0 + this->q1*Q2.q1 +
this->q2*Q2.q2 + this->q3*Q2.q3;
return prod;
}
};
/// \brief A rotation between two sets of coordinates (for the moment
/// a wrapper for colvarmodule::quaternion)
class colvarmodule::rotation
{
public:
/// \brief The rotation itself (implemented as a quaternion)
cvm::quaternion q;
/// \brief Eigenvalue corresponding to the optimal rotation
cvm::real lambda;
/// \brief Perform gradient tests
bool b_debug_gradients;
/// \brief Positions to superimpose: the rotation should brings pos1
/// into pos2
std::vector<cvm::atom_pos> pos1, pos2;
cvm::rmatrix C;
cvm::matrix2d<cvm::real> S;
cvm::vector1d<cvm::real> S_eigval;
cvm::matrix2d<cvm::real> S_eigvec;
/// Used for debugging gradients
cvm::matrix2d<cvm::real> S_backup;
/// Derivatives of S
std::vector< cvm::matrix2d<cvm::rvector> > dS_1, dS_2;
/// Derivatives of leading eigenvalue
std::vector< cvm::rvector > dL0_1, dL0_2;
/// Derivatives of leading eigenvector
std::vector< cvm::vector1d<cvm::rvector> > dQ0_1, dQ0_2;
/// Allocate space for the derivatives of the rotation
inline void request_group1_gradients(size_t const &n)
{
dS_1.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
dL0_1.resize(n, cvm::rvector(0.0, 0.0, 0.0));
dQ0_1.resize(n, cvm::vector1d<cvm::rvector>(4));
}
/// Allocate space for the derivatives of the rotation
inline void request_group2_gradients(size_t const &n)
{
dS_2.resize(n, cvm::matrix2d<cvm::rvector>(4, 4));
dL0_2.resize(n, cvm::rvector(0.0, 0.0, 0.0));
dQ0_2.resize(n, cvm::vector1d<cvm::rvector>(4));
}
/// \brief Calculate the optimal rotation and store the
/// corresponding eigenvalue and eigenvector in the arguments l0 and
/// q0; if the gradients have been previously requested, calculate
/// them as well
///
/// The method to derive the optimal rotation is defined in:
/// Coutsias EA, Seok C, Dill KA.
/// Using quaternions to calculate RMSD.
/// J Comput Chem. 25(15):1849-57 (2004)
/// DOI: 10.1002/jcc.20110 PubMed: 15376254
void calc_optimal_rotation(std::vector<atom_pos> const &pos1,
std::vector<atom_pos> const &pos2);
/// Default constructor
inline rotation()
: b_debug_gradients(false)
{}
/// Constructor after a quaternion
inline rotation(cvm::quaternion const &qi)
: q(qi),
b_debug_gradients(false)
{
}
/// Constructor after an axis of rotation and an angle (in radians)
inline rotation(cvm::real const &angle, cvm::rvector const &axis)
: b_debug_gradients(false)
{
cvm::rvector const axis_n = axis.unit();
cvm::real const sina = std::sin(angle/2.0);
q = cvm::quaternion(std::cos(angle/2.0),
sina * axis_n.x, sina * axis_n.y, sina * axis_n.z);
}
/// Destructor
inline ~rotation()
{}
/// Return the rotated vector
inline cvm::rvector rotate(cvm::rvector const &v) const
{
return q.rotate(v);
}
/// Return the inverse of this rotation
inline cvm::rotation inverse() const
{
return cvm::rotation(this->q.conjugate());
}
/// Return the associated 3x3 matrix
inline cvm::rmatrix matrix() const
{
return q.rotation_matrix();
}
/// \brief Return the spin angle (in degrees) with respect to the
/// provided axis (which MUST be normalized)
inline cvm::real spin_angle(cvm::rvector const &axis) const
{
cvm::rvector const q_vec = q.get_vector();
cvm::real alpha = (180.0/PI) * 2.0 * std::atan2(axis * q_vec, q.q0);
while (alpha > 180.0) alpha -= 360;
while (alpha < -180.0) alpha += 360;
return alpha;
}
/// \brief Return the derivative of the spin angle with respect to
/// the quaternion
inline cvm::quaternion dspin_angle_dq(cvm::rvector const &axis) const
{
cvm::rvector const q_vec = q.get_vector();
cvm::real const iprod = axis * q_vec;
if (q.q0 != 0.0) {
// cvm::real const x = iprod/q.q0;
cvm::real const dspindx = (180.0/PI) * 2.0 * (1.0 / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
return
cvm::quaternion( dspindx * (iprod * (-1.0) / (q.q0*q.q0)),
dspindx * ((1.0/q.q0) * axis.x),
dspindx * ((1.0/q.q0) * axis.y),
dspindx * ((1.0/q.q0) * axis.z));
} else {
// (1/(1+x^2)) ~ (1/x)^2
return
cvm::quaternion((180.0/PI) * 2.0 * ((-1.0)/iprod), 0.0, 0.0, 0.0);
// XX TODO: What if iprod == 0? XX
}
}
/// \brief Return the projection of the orientation vector onto a
/// predefined axis
inline cvm::real cos_theta(cvm::rvector const &axis) const
{
cvm::rvector const q_vec = q.get_vector();
cvm::real const alpha =
(180.0/PI) * 2.0 * std::atan2(axis * q_vec, q.q0);
cvm::real const cos_spin_2 = std::cos(alpha * (PI/180.0) * 0.5);
cvm::real const cos_theta_2 = ( (cos_spin_2 != 0.0) ?
(q.q0 / cos_spin_2) :
(0.0) );
// cos(2t) = 2*cos(t)^2 - 1
return 2.0 * (cos_theta_2*cos_theta_2) - 1.0;
}
/// Return the derivative of the tilt wrt the quaternion
inline cvm::quaternion dcos_theta_dq(cvm::rvector const &axis) const
{
cvm::rvector const q_vec = q.get_vector();
cvm::real const iprod = axis * q_vec;
cvm::real const cos_spin_2 = std::cos(std::atan2(iprod, q.q0));
if (q.q0 != 0.0) {
cvm::real const d_cos_theta_dq0 =
(4.0 * q.q0 / (cos_spin_2*cos_spin_2)) *
(1.0 - (iprod*iprod)/(q.q0*q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
cvm::real const d_cos_theta_dqn =
(4.0 * q.q0 / (cos_spin_2*cos_spin_2) *
(iprod/q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0)));
return cvm::quaternion(d_cos_theta_dq0,
d_cos_theta_dqn * axis.x,
d_cos_theta_dqn * axis.y,
d_cos_theta_dqn * axis.z);
} else {
cvm::real const d_cos_theta_dqn =
(4.0 / (cos_spin_2*cos_spin_2 * iprod));
return cvm::quaternion(0.0,
d_cos_theta_dqn * axis.x,
d_cos_theta_dqn * axis.y,
d_cos_theta_dqn * axis.z);
}
}
/// \brief Whether to test for eigenvalue crossing
static bool monitor_crossings;
/// \brief Threshold for the eigenvalue crossing test
static cvm::real crossing_threshold;
protected:
/// \brief Previous value of the rotation (used to warn the user
/// when the structure changes too much, and there may be an
/// eigenvalue crossing)
cvm::quaternion q_old;
/// Build the overlap matrix S (used by calc_optimal_rotation())
void build_matrix(std::vector<cvm::atom_pos> const &pos1,
std::vector<cvm::atom_pos> const &pos2,
cvm::matrix2d<cvm::real> &S);
/// Diagonalize the overlap matrix S (used by calc_optimal_rotation())
void diagonalize_matrix(cvm::matrix2d<cvm::real> &S,
cvm::vector1d<cvm::real> &S_eigval,
cvm::matrix2d<cvm::real> &S_eigvec);
};
#endif
diff --git a/lib/colvars/colvarvalue.cpp b/lib/colvars/colvarvalue.cpp
index deccc6b7e..7b498be6d 100644
--- a/lib/colvars/colvarvalue.cpp
+++ b/lib/colvars/colvarvalue.cpp
@@ -1,631 +1,906 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <vector>
#include <sstream>
#include <iostream>
#include "colvarmodule.h"
#include "colvarvalue.h"
+std::string const colvarvalue::type_desc(Type t)
+{
+ switch (t) {
+ case colvarvalue::type_scalar:
+ return "scalar number"; break;
+ case colvarvalue::type_3vector:
+ return "3-dimensional vector"; break;
+ case colvarvalue::type_unit3vector:
+ return "3-dimensional unit vector"; break;
+ case colvarvalue::type_unit3vectorderiv:
+ return "derivative of a 3-dimensional unit vector"; break;
+ case colvarvalue::type_quaternion:
+ return "4-dimensional unit quaternion"; break;
+ case colvarvalue::type_quaternionderiv:
+ return "4-dimensional tangent vector"; break;
+ case colvarvalue::type_vector:
+ return "n-dimensional vector"; break;
+ case colvarvalue::type_notset:
+ // fallthrough
+ default:
+ return "not set"; break;
+ }
+}
+
+
+std::string const colvarvalue::type_keyword(Type t)
+{
+ switch (t) {
+ case colvarvalue::type_notset:
+ default:
+ return "not_set"; break;
+ case colvarvalue::type_scalar:
+ return "scalar"; break;
+ case colvarvalue::type_3vector:
+ return "vector3"; break;
+ case colvarvalue::type_unit3vector:
+ return "unit_vector3"; break;
+ case colvarvalue::type_unit3vectorderiv:
+ return ""; break;
+ case colvarvalue::type_quaternion:
+ return "unit_quaternion"; break;
+ case colvarvalue::type_quaternionderiv:
+ return ""; break;
+ case colvarvalue::type_vector:
+ return "vector"; break;
+ }
+}
+
+
+size_t colvarvalue::num_df(Type t)
+{
+ switch (t) {
+ case colvarvalue::type_notset:
+ default:
+ return 0; break;
+ case colvarvalue::type_scalar:
+ return 1; break;
+ case colvarvalue::type_3vector:
+ return 3; break;
+ case colvarvalue::type_unit3vector:
+ case colvarvalue::type_unit3vectorderiv:
+ return 2; break;
+ case colvarvalue::type_quaternion:
+ case colvarvalue::type_quaternionderiv:
+ return 3; break;
+ case colvarvalue::type_vector:
+ // the size of a vector is unknown without its object
+ return 0; break;
+ }
+}
+
+
+size_t colvarvalue::num_dimensions(Type t)
+{
+ switch (t) {
+ case colvarvalue::type_notset:
+ default:
+ return 0; break;
+ case colvarvalue::type_scalar:
+ return 1; break;
+ case colvarvalue::type_3vector:
+ case colvarvalue::type_unit3vector:
+ case colvarvalue::type_unit3vectorderiv:
+ return 3; break;
+ case colvarvalue::type_quaternion:
+ case colvarvalue::type_quaternionderiv:
+ return 4; break;
+ case colvarvalue::type_vector:
+ // the size of a vector is unknown without its object
+ return 0; break;
+ }
+}
+
+
+void colvarvalue::reset()
+{
+ switch (value_type) {
+ case colvarvalue::type_scalar:
+ real_value = 0.0;
+ break;
+ case colvarvalue::type_3vector:
+ case colvarvalue::type_unit3vector:
+ case colvarvalue::type_unit3vectorderiv:
+ rvector_value.reset();
+ break;
+ case colvarvalue::type_quaternion:
+ case colvarvalue::type_quaternionderiv:
+ quaternion_value.reset();
+ break;
+ case colvarvalue::type_vector:
+ vector1d_value.reset();
+ break;
+ case colvarvalue::type_notset:
+ default:
+ break;
+ }
+}
+
+
+void colvarvalue::apply_constraints()
+{
+ switch (value_type) {
+ case colvarvalue::type_scalar:
+ case colvarvalue::type_3vector:
+ case colvarvalue::type_unit3vectorderiv:
+ case colvarvalue::type_quaternionderiv:
+ break;
+ case colvarvalue::type_unit3vector:
+ rvector_value /= std::sqrt(rvector_value.norm2());
+ break;
+ case colvarvalue::type_quaternion:
+ quaternion_value /= std::sqrt(quaternion_value.norm2());
+ break;
+ case colvarvalue::type_vector:
+ if (elem_types.size() > 0) {
+ // if we have information about non-scalar types, use it
+ size_t i;
+ for (i = 0; i < elem_types.size(); i++) {
+ if (elem_sizes[i] == 1) continue; // TODO this can be optimized further
+ colvarvalue cvtmp(vector1d_value.slice(elem_indices[i],
+ elem_indices[i] + elem_sizes[i]), elem_types[i]);
+ cvtmp.apply_constraints();
+ set_elem(i, cvtmp);
+ }
+ }
+ break;
+ case colvarvalue::type_notset:
+ default:
+ break;
+ }
+}
+
+
+void colvarvalue::type(Type const &vti)
+{
+ if (vti != value_type) {
+ // reset the value based on the previous type
+ reset();
+ if ((value_type == type_vector) && (vti != type_vector)) {
+ vector1d_value.clear();
+ }
+ value_type = vti;
+ }
+}
+
+
+void colvarvalue::type(colvarvalue const &x)
+{
+ if (x.type() != value_type) {
+ // reset the value based on the previous type
+ reset();
+ if (value_type == type_vector) {
+ vector1d_value.clear();
+ }
+ value_type = x.type();
+ }
+
+ if (x.type() == type_vector) {
+ vector1d_value.resize(x.vector1d_value.size());
+ }
+}
+
+
+void colvarvalue::is_derivative()
+{
+ switch (value_type) {
+ case colvarvalue::type_scalar:
+ case colvarvalue::type_3vector:
+ case colvarvalue::type_unit3vectorderiv:
+ case colvarvalue::type_quaternionderiv:
+ break;
+ case colvarvalue::type_unit3vector:
+ type(colvarvalue::type_unit3vectorderiv);
+ break;
+ case colvarvalue::type_quaternion:
+ type(colvarvalue::type_quaternionderiv);
+ break;
+ case colvarvalue::type_vector:
+ // TODO
+ break;
+ case colvarvalue::type_notset:
+ default:
+ break;
+ }
+}
+
+
+colvarvalue::colvarvalue(colvarvalue const &x)
+ : value_type(x.type())
+{
+ switch (x.type()) {
+ case type_scalar:
+ real_value = x.real_value;
+ break;
+ case type_3vector:
+ case type_unit3vector:
+ case type_unit3vectorderiv:
+ rvector_value = x.rvector_value;
+ break;
+ case type_quaternion:
+ case type_quaternionderiv:
+ quaternion_value = x.quaternion_value;
+ break;
+ case type_vector:
+ vector1d_value = x.vector1d_value;
+ elem_types = x.elem_types;
+ elem_indices = x.elem_indices;
+ elem_sizes = x.elem_sizes;
+ case type_notset:
+ default:
+ break;
+ }
+}
+
+
+colvarvalue::colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti)
+{
+ if ((vti != type_vector) && (v.size() != num_dimensions(vti))) {
+ cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+
+ "\" using a vector of size "+cvm::to_str(v.size())+
+ ".\n");
+ value_type = type_notset;
+ } else {
+ value_type = vti;
+ switch (vti) {
+ case type_scalar:
+ real_value = v[0];
+ break;
+ case type_3vector:
+ case type_unit3vector:
+ case type_unit3vectorderiv:
+ rvector_value = cvm::rvector(v);
+ break;
+ case type_quaternion:
+ case type_quaternionderiv:
+ quaternion_value = cvm::quaternion(v);
+ break;
+ case type_vector:
+ vector1d_value = v;
+ break;
+ case type_notset:
+ default:
+ break;
+ }
+ }
+}
+
+
void colvarvalue::add_elem(colvarvalue const &x)
{
if (this->value_type != type_vector) {
cvm::error("Error: trying to set an element for a variable that is not set to be a vector.\n");
return;
}
size_t const n = vector1d_value.size();
size_t const nd = num_dimensions(x.value_type);
elem_types.push_back(x.value_type);
elem_indices.push_back(n);
elem_sizes.push_back(nd);
vector1d_value.resize(n + nd);
set_elem(n, x);
}
colvarvalue const colvarvalue::get_elem(int const i_begin, int const i_end, Type const vt) const
{
if (vector1d_value.size() > 0) {
cvm::vector1d<cvm::real> const v(vector1d_value.slice(i_begin, i_end));
return colvarvalue(v, vt);
} else {
cvm::error("Error: trying to get an element from a variable that is not a vector.\n");
return colvarvalue(type_notset);
}
}
void colvarvalue::set_elem(int const i_begin, int const i_end, colvarvalue const &x)
{
if (vector1d_value.size() > 0) {
vector1d_value.sliceassign(i_begin, i_end, x.as_vector());
} else {
cvm::error("Error: trying to set an element for a variable that is not a vector.\n");
}
}
colvarvalue const colvarvalue::get_elem(int const icv) const
{
if (elem_types.size() > 0) {
return get_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv],
elem_types[icv]);
} else {
cvm::error("Error: trying to get a colvarvalue element from a vector colvarvalue that was initialized as a plain array.\n");
return colvarvalue(type_notset);
}
}
void colvarvalue::set_elem(int const icv, colvarvalue const &x)
{
if (elem_types.size() > 0) {
check_types_assign(elem_types[icv], x.value_type);
set_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv], x);
} else {
cvm::error("Error: trying to set a colvarvalue element for a colvarvalue that was initialized as a plain array.\n");
}
}
void colvarvalue::set_random()
{
size_t ic;
switch (this->type()) {
case colvarvalue::type_scalar:
this->real_value = cvm::rand_gaussian();
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
this->rvector_value.x = cvm::rand_gaussian();
this->rvector_value.y = cvm::rand_gaussian();
this->rvector_value.z = cvm::rand_gaussian();
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
this->quaternion_value.q0 = cvm::rand_gaussian();
this->quaternion_value.q1 = cvm::rand_gaussian();
this->quaternion_value.q2 = cvm::rand_gaussian();
this->quaternion_value.q3 = cvm::rand_gaussian();
break;
case colvarvalue::type_vector:
for (ic = 0; ic < this->vector1d_value.size(); ic++) {
this->vector1d_value[ic] = cvm::rand_gaussian();
}
break;
case colvarvalue::type_notset:
default:
undef_op();
break;
}
}
+void colvarvalue::undef_op() const
+{
+ cvm::error("Error: Undefined operation on a colvar of type \""+
+ type_desc(this->type())+"\".\n");
+}
+
+
// binary operations between two colvarvalues
colvarvalue operator + (colvarvalue const &x1,
colvarvalue const &x2)
{
colvarvalue::check_types(x1, x2);
switch (x1.value_type) {
case colvarvalue::type_scalar:
return colvarvalue(x1.real_value + x2.real_value);
case colvarvalue::type_3vector:
return colvarvalue(x1.rvector_value + x2.rvector_value);
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return colvarvalue(x1.rvector_value + x2.rvector_value,
colvarvalue::type_unit3vector);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return colvarvalue(x1.quaternion_value + x2.quaternion_value);
case colvarvalue::type_vector:
return colvarvalue(x1.vector1d_value + x2.vector1d_value, colvarvalue::type_vector);
case colvarvalue::type_notset:
default:
x1.undef_op();
return colvarvalue(colvarvalue::type_notset);
};
}
colvarvalue operator - (colvarvalue const &x1,
colvarvalue const &x2)
{
colvarvalue::check_types(x1, x2);
switch (x1.value_type) {
case colvarvalue::type_scalar:
return colvarvalue(x1.real_value - x2.real_value);
case colvarvalue::type_3vector:
return colvarvalue(x1.rvector_value - x2.rvector_value);
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return colvarvalue(x1.rvector_value - x2.rvector_value,
colvarvalue::type_unit3vector);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return colvarvalue(x1.quaternion_value - x2.quaternion_value);
case colvarvalue::type_vector:
return colvarvalue(x1.vector1d_value - x2.vector1d_value, colvarvalue::type_vector);
case colvarvalue::type_notset:
default:
x1.undef_op();
return colvarvalue(colvarvalue::type_notset);
};
}
// binary operations with real numbers
colvarvalue operator * (cvm::real const &a,
colvarvalue const &x)
{
switch (x.value_type) {
case colvarvalue::type_scalar:
return colvarvalue(a * x.real_value);
case colvarvalue::type_3vector:
return colvarvalue(a * x.rvector_value);
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return colvarvalue(a * x.rvector_value,
colvarvalue::type_unit3vector);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return colvarvalue(a * x.quaternion_value);
case colvarvalue::type_vector:
return colvarvalue(x.vector1d_value * a, colvarvalue::type_vector);
case colvarvalue::type_notset:
default:
x.undef_op();
return colvarvalue(colvarvalue::type_notset);
}
}
colvarvalue operator * (colvarvalue const &x,
cvm::real const &a)
{
return a * x;
}
colvarvalue operator / (colvarvalue const &x,
cvm::real const &a)
{
switch (x.value_type) {
case colvarvalue::type_scalar:
return colvarvalue(x.real_value / a);
case colvarvalue::type_3vector:
return colvarvalue(x.rvector_value / a);
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return colvarvalue(x.rvector_value / a,
colvarvalue::type_unit3vector);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return colvarvalue(x.quaternion_value / a);
case colvarvalue::type_vector:
return colvarvalue(x.vector1d_value / a, colvarvalue::type_vector);
case colvarvalue::type_notset:
default:
x.undef_op();
return colvarvalue(colvarvalue::type_notset);
}
}
// inner product between two colvarvalues
cvm::real operator * (colvarvalue const &x1,
colvarvalue const &x2)
{
colvarvalue::check_types(x1, x2);
switch (x1.value_type) {
case colvarvalue::type_scalar:
return (x1.real_value * x2.real_value);
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return (x1.rvector_value * x2.rvector_value);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
// the "*" product is the quaternion product, here the inner
// member function is used instead
return (x1.quaternion_value.inner(x2.quaternion_value));
case colvarvalue::type_vector:
return (x1.vector1d_value * x2.vector1d_value);
case colvarvalue::type_notset:
default:
x1.undef_op();
return 0.0;
};
}
colvarvalue colvarvalue::dist2_grad(colvarvalue const &x2) const
{
colvarvalue::check_types(*this, x2);
switch (this->value_type) {
case colvarvalue::type_scalar:
return 2.0 * (this->real_value - x2.real_value);
case colvarvalue::type_3vector:
return 2.0 * (this->rvector_value - x2.rvector_value);
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
{
cvm::rvector const &v1 = this->rvector_value;
cvm::rvector const &v2 = x2.rvector_value;
cvm::real const cos_t = v1 * v2;
cvm::real const sin_t = std::sqrt(1.0 - cos_t*cos_t);
return colvarvalue( 2.0 * sin_t *
cvm::rvector((-1.0) * sin_t * v2.x +
cos_t/sin_t * (v1.x - cos_t*v2.x),
(-1.0) * sin_t * v2.y +
cos_t/sin_t * (v1.y - cos_t*v2.y),
(-1.0) * sin_t * v2.z +
cos_t/sin_t * (v1.z - cos_t*v2.z)
),
colvarvalue::type_unit3vectorderiv );
}
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return this->quaternion_value.dist2_grad(x2.quaternion_value);
case colvarvalue::type_vector:
return colvarvalue(2.0 * (this->vector1d_value - x2.vector1d_value), colvarvalue::type_vector);
break;
case colvarvalue::type_notset:
default:
this->undef_op();
return colvarvalue(colvarvalue::type_notset);
};
}
std::string colvarvalue::to_simple_string() const
{
switch (type()) {
case colvarvalue::type_scalar:
return cvm::to_str(real_value, 0, cvm::cv_prec);
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return rvector_value.to_simple_string();
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return quaternion_value.to_simple_string();
break;
case colvarvalue::type_vector:
return vector1d_value.to_simple_string();
break;
case colvarvalue::type_notset:
default:
undef_op();
break;
}
return std::string();
}
int colvarvalue::from_simple_string(std::string const &s)
{
switch (type()) {
case colvarvalue::type_scalar:
return ((std::istringstream(s) >> real_value)
? COLVARS_OK : COLVARS_ERROR);
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return rvector_value.from_simple_string(s);
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return quaternion_value.from_simple_string(s);
break;
case colvarvalue::type_vector:
return vector1d_value.from_simple_string(s);
break;
case colvarvalue::type_notset:
default:
undef_op();
break;
}
return COLVARS_ERROR;
}
std::ostream & operator << (std::ostream &os, colvarvalue const &x)
{
switch (x.type()) {
case colvarvalue::type_scalar:
os << x.real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
os << x.rvector_value;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
os << x.quaternion_value;
break;
case colvarvalue::type_vector:
os << x.vector1d_value;
break;
case colvarvalue::type_notset:
default:
os << "not set";
break;
}
return os;
}
std::ostream & operator << (std::ostream &os, std::vector<colvarvalue> const &v)
{
size_t i;
for (i = 0; i < v.size(); i++) {
os << v[i];
}
return os;
}
std::istream & operator >> (std::istream &is, colvarvalue &x)
{
if (x.type() == colvarvalue::type_notset) {
cvm::error("Trying to read from a stream a colvarvalue, "
"which has not yet been assigned a data type.\n");
return is;
}
switch (x.type()) {
case colvarvalue::type_scalar:
is >> x.real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vectorderiv:
is >> x.rvector_value;
break;
case colvarvalue::type_unit3vector:
is >> x.rvector_value;
x.apply_constraints();
break;
case colvarvalue::type_quaternion:
is >> x.quaternion_value;
x.apply_constraints();
break;
case colvarvalue::type_quaternionderiv:
is >> x.quaternion_value;
break;
case colvarvalue::type_vector:
is >> x.vector1d_value;
break;
case colvarvalue::type_notset:
default:
x.undef_op();
}
return is;
}
size_t colvarvalue::output_width(size_t const &real_width) const
{
switch (this->value_type) {
case colvarvalue::type_scalar:
return real_width;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return cvm::rvector::output_width(real_width);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return cvm::quaternion::output_width(real_width);
case colvarvalue::type_vector:
// note how this depends on the vector's size
return vector1d_value.output_width(real_width);
case colvarvalue::type_notset:
default:
return 0;
}
}
void colvarvalue::inner_opt(colvarvalue const &x,
std::vector<colvarvalue>::iterator &xv,
std::vector<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result)
{
// doing type check only once, here
colvarvalue::check_types(x, *xv);
std::vector<colvarvalue>::iterator &xvi = xv;
std::vector<cvm::real>::iterator &ii = result;
switch (x.value_type) {
case colvarvalue::type_scalar:
while (xvi != xv_end) {
*(ii++) += (xvi++)->real_value * x.real_value;
}
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
while (xvi != xv_end) {
*(ii++) += (xvi++)->rvector_value * x.rvector_value;
}
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
while (xvi != xv_end) {
*(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value);
}
break;
case colvarvalue::type_vector:
while (xvi != xv_end) {
*(ii++) += (xvi++)->vector1d_value * x.vector1d_value;
}
break;
default:
x.undef_op();
};
}
void colvarvalue::inner_opt(colvarvalue const &x,
std::list<colvarvalue>::iterator &xv,
std::list<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result)
{
// doing type check only once, here
colvarvalue::check_types(x, *xv);
std::list<colvarvalue>::iterator &xvi = xv;
std::vector<cvm::real>::iterator &ii = result;
switch (x.value_type) {
case colvarvalue::type_scalar:
while (xvi != xv_end) {
*(ii++) += (xvi++)->real_value * x.real_value;
}
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
while (xvi != xv_end) {
*(ii++) += (xvi++)->rvector_value * x.rvector_value;
}
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
while (xvi != xv_end) {
*(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value);
}
break;
case colvarvalue::type_vector:
while (xvi != xv_end) {
*(ii++) += (xvi++)->vector1d_value * x.vector1d_value;
}
break;
default:
x.undef_op();
};
}
void colvarvalue::p2leg_opt(colvarvalue const &x,
std::vector<colvarvalue>::iterator &xv,
std::vector<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result)
{
// doing type check only once, here
colvarvalue::check_types(x, *xv);
std::vector<colvarvalue>::iterator &xvi = xv;
std::vector<cvm::real>::iterator &ii = result;
switch (x.value_type) {
case colvarvalue::type_scalar:
cvm::error("Error: cannot calculate Legendre polynomials "
"for scalar variables.\n");
return;
break;
case colvarvalue::type_3vector:
while (xvi != xv_end) {
cvm::real const cosine =
((xvi)->rvector_value * x.rvector_value) /
((xvi)->rvector_value.norm() * x.rvector_value.norm());
xvi++;
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
while (xvi != xv_end) {
cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value;
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
while (xvi != xv_end) {
cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value);
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
case colvarvalue::type_vector:
while (xvi != xv_end) {
cvm::real const cosine =
((xvi)->vector1d_value * x.vector1d_value) /
((xvi)->vector1d_value.norm() * x.rvector_value.norm());
xvi++;
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
default:
x.undef_op();
};
}
void colvarvalue::p2leg_opt(colvarvalue const &x,
std::list<colvarvalue>::iterator &xv,
std::list<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result)
{
// doing type check only once, here
colvarvalue::check_types(x, *xv);
std::list<colvarvalue>::iterator &xvi = xv;
std::vector<cvm::real>::iterator &ii = result;
switch (x.value_type) {
case colvarvalue::type_scalar:
cvm::error("Error: cannot calculate Legendre polynomials "
"for scalar variables.\n");
break;
case colvarvalue::type_3vector:
while (xvi != xv_end) {
cvm::real const cosine =
((xvi)->rvector_value * x.rvector_value) /
((xvi)->rvector_value.norm() * x.rvector_value.norm());
xvi++;
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
while (xvi != xv_end) {
cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value;
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
while (xvi != xv_end) {
cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value);
*(ii++) += 1.5*cosine*cosine - 0.5;
}
break;
default:
x.undef_op();
};
}
diff --git a/lib/colvars/colvarvalue.h b/lib/colvars/colvarvalue.h
index e369feefc..fce0e1a97 100644
--- a/lib/colvars/colvarvalue.h
+++ b/lib/colvars/colvarvalue.h
@@ -1,948 +1,708 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARVALUE_H
#define COLVARVALUE_H
#include "colvarmodule.h"
#include "colvartypes.h"
/// \brief Value of a collective variable: this is a metatype which
/// can be set at runtime. By default it is set to be a scalar
/// number, and can be treated as such in all operations (this is
/// done by most \link cvc \endlink implementations).
///
/// \link colvarvalue \endlink allows \link colvar \endlink to be
/// treat different data types. By default, a \link colvarvalue
/// \endlink variable is a scalar number. To use it as
/// another type, declare and initialize it as
/// \code colvarvalue x(colvarvalue::type_xxx)\endcode, use \link x.type
/// (colvarvalue::type_xxx) \endlink at a later stage, or if unset,
/// assign the type with \code x = y; \endcode, provided y is correctly set.
///
/// All operators (either unary or binary) on a \link
/// colvarvalue \endlink object performs one or more checks on the
/// \link Type \endlink, except when reading from a stream, when there is no way to
/// detect the \link Type \endlink. To use \code is >> x; \endcode x \b MUST
/// already have a type correcly set up for properly parsing the
/// stream. No problem of course with the output streams: \code os << x; \endcode
///
/// \em Note \em on \em performance: to avoid type checks in a long array of \link
/// colvarvalue \endlink objects, use one of the existing "_opt" functions or implement a new one
class colvarvalue {
public:
/// \brief Possible types of value
///
/// These three cover most possibilities of data type one can
/// devise. If you need to implement a new colvar with a very
/// complex data type, it's better to put an allocatable class here
enum Type {
/// Undefined type
type_notset,
/// Scalar number, implemented as \link colvarmodule::real \endlink (default)
type_scalar,
/// 3-dimensional vector, implemented as \link colvarmodule::rvector \endlink
type_3vector,
/// 3-dimensional unit vector, implemented as \link colvarmodule::rvector \endlink
type_unit3vector,
/// 3-dimensional vector that is a derivative of a unitvector
type_unit3vectorderiv,
/// 4-dimensional unit vector representing a rotation, implemented as \link colvarmodule::quaternion \endlink
type_quaternion,
/// 4-dimensional vector that is a derivative of a quaternion
type_quaternionderiv,
/// vector (arbitrary dimension)
type_vector,
/// Needed to iterate through enum
type_all
};
/// Current type of this colvarvalue object
Type value_type;
/// \brief Real data member
cvm::real real_value;
/// \brief 3-dimensional vector data member
cvm::rvector rvector_value;
/// \brief Quaternion data member
cvm::quaternion quaternion_value;
/// \brief Generic vector data member
cvm::vector1d<cvm::real> vector1d_value;
/// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues,
/// keep track of the individual types
std::vector<Type> elem_types;
/// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues,
/// these mark the initial components of each colvarvalue
std::vector<int> elem_indices;
/// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues,
/// these mark how many components for each colvarvalue
std::vector<int> elem_sizes;
/// \brief Whether or not the type check is enforced
static inline bool type_checking()
{
return true;
}
/// Runtime description of value types
static std::string const type_desc(Type t);
/// User keywords for specifying value types in the configuration
static std::string const type_keyword(Type t);
/// Number of degrees of freedom for each supported type
static size_t num_df(Type t);
/// Number of dimensions for each supported type (used to allocate vector1d_value)
static size_t num_dimensions(Type t);
/// Number of dimensions of this variable
size_t size() const;
/// \brief Default constructor: this class defaults to a scalar
/// number and always behaves like it unless you change its type
inline colvarvalue()
: value_type(type_scalar), real_value(0.0)
{}
/// Constructor from a type specification
inline colvarvalue(Type const &vti)
: value_type(vti)
{
reset();
}
/// Copy constructor from real base type
inline colvarvalue(cvm::real const &x)
: value_type(type_scalar), real_value(x)
{}
/// \brief Copy constructor from rvector base type (Note: this sets
/// by default a type \link type_3vector \endlink , if you want a
/// \link type_unit3vector \endlink you must set it explicitly)
inline colvarvalue(cvm::rvector const &v, Type vti = type_3vector)
: value_type(vti), rvector_value(v)
{}
/// \brief Copy constructor from quaternion base type
inline colvarvalue(cvm::quaternion const &q, Type vti = type_quaternion)
: value_type(vti), quaternion_value(q)
{}
/// Copy constructor from vector1d base type
colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti = type_vector);
/// Copy constructor from another \link colvarvalue \endlink
colvarvalue(colvarvalue const &x);
/// Set to the null value for the data type currently defined
void reset();
/// \brief If the variable has constraints (e.g. unitvector or
/// quaternion), transform it to satisfy them; this function needs
/// to be called only when the \link colvarvalue \endlink
/// is calculated outside of \link cvc \endlink objects
void apply_constraints();
/// Get the current type
inline Type type() const
{
return value_type;
}
/// Set the type explicitly
- inline void type(Type const &vti)
- {
- if (vti != value_type) {
- // reset the value based on the previous type
- reset();
- if ((value_type == type_vector) && (vti != type_vector)) {
- vector1d_value.resize(0);
- }
- value_type = vti;
- }
- }
+ void type(Type const &vti);
/// Set the type after another \link colvarvalue \endlink
- inline void type(colvarvalue const &x)
- {
- if (x.type() != value_type) {
- // reset the value based on the previous type
- reset();
- if (value_type == type_vector) {
- vector1d_value.resize(0);
- }
- value_type = x.type();
- }
-
- if (x.type() == type_vector) {
- vector1d_value.resize(x.vector1d_value.size());
- }
- }
+ void type(colvarvalue const &x);
/// Make the type a derivative of the original type
/// (so that its constraints do not apply)
- inline void is_derivative();
+ void is_derivative();
/// Square norm of this colvarvalue
cvm::real norm2() const;
/// Norm of this colvarvalue
inline cvm::real norm() const
{
return std::sqrt(this->norm2());
}
/// Square distance between this \link colvarvalue \endlink and another
cvm::real dist2(colvarvalue const &x2) const;
/// Derivative with respect to this \link colvarvalue \endlink of the square distance
colvarvalue dist2_grad(colvarvalue const &x2) const;
/// Assignment operator (type of x is checked)
colvarvalue & operator = (colvarvalue const &x);
void operator += (colvarvalue const &x);
void operator -= (colvarvalue const &x);
void operator *= (cvm::real const &a);
void operator /= (cvm::real const &a);
// Binary operators (return values)
friend colvarvalue operator + (colvarvalue const &x1, colvarvalue const &x2);
friend colvarvalue operator - (colvarvalue const &x1, colvarvalue const &x2);
friend colvarvalue operator * (colvarvalue const &x, cvm::real const &a);
friend colvarvalue operator * (cvm::real const &a, colvarvalue const &x);
friend colvarvalue operator / (colvarvalue const &x, cvm::real const &a);
/// Inner product
friend cvm::real operator * (colvarvalue const &x1, colvarvalue const &x2);
// Cast to scalar
inline operator cvm::real() const
{
if (value_type != type_scalar) {
cvm::error("Error: trying to use a variable of type \""+
type_desc(value_type)+"\" as one of type \""+
type_desc(type_scalar)+"\".\n");
}
return real_value;
}
// Cast to 3-vector
inline operator cvm::rvector() const
{
if ((value_type != type_3vector) &&
(value_type != type_unit3vector) &&
(value_type != type_unit3vectorderiv)) {
cvm::error("Error: trying to use a variable of type \""+
type_desc(value_type)+"\" as one of type \""+
type_desc(type_3vector)+"\".\n");
}
return rvector_value;
}
// Cast to quaternion
inline operator cvm::quaternion() const
{
if ((value_type != type_quaternion) &&
(value_type != type_quaternionderiv)) {
cvm::error("Error: trying to use a variable of type \""+
type_desc(value_type)+"\" as one of type \""+
type_desc(type_quaternion)+"\".\n");
}
return quaternion_value;
}
// Create a n-dimensional vector from one of the basic types, or return the existing vector
cvm::vector1d<cvm::real> const as_vector() const;
/// Whether this variable is a real number
inline bool is_scalar() const
{
return (value_type == type_scalar);
}
/// Add an element to the vector (requires that type_vector is already set).
/// This is only needed to use this object as a vector of "complex" colvar values.
/// To use it instead as a plain n-dimensional vector, access vector1d_value directly.
void add_elem(colvarvalue const &x);
/// Get a single colvarvalue out of elements of the vector
colvarvalue const get_elem(int const i_begin, int const i_end, Type const vt) const;
/// Set elements of the vector from a single colvarvalue
void set_elem(int const i_begin, int const i_end, colvarvalue const &x);
/// Make each element a random number in N(0,1)
void set_random();
/// Get a single colvarvalue out of elements of the vector
colvarvalue const get_elem(int const icv) const;
/// Set elements of the vector from a single colvarvalue
void set_elem(int const icv, colvarvalue const &x);
/// Get a scalar number out of an element of the vector
- inline cvm::real operator [] (int const i) const
- {
- if (vector1d_value.size() > 0) {
- return vector1d_value[i];
- } else {
- cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n");
- return 0.0;
- }
- }
+ cvm::real operator [] (int const i) const;
/// Use an element of the vector as a scalar number
- inline cvm::real & operator [] (int const i)
- {
- if (vector1d_value.size() > 0) {
- return vector1d_value[i];
- } else {
- cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n");
- real_value = 0.0;
- return real_value;
- }
- }
-
+ cvm::real & operator [] (int const i);
/// Ensure that the two types are the same within a binary operator
int static check_types(colvarvalue const &x1, colvarvalue const &x2);
/// Ensure that the two types are the same within an assignment, or that the left side is type_notset
int static check_types_assign(Type const &vt1, Type const &vt2);
/// Undefined operation
void undef_op() const;
/// \brief Formatted output operator
friend std::ostream & operator << (std::ostream &os, colvarvalue const &q);
/// \brief Formatted input operator
friend std::istream & operator >> (std::istream &is, colvarvalue &q);
/// Give the number of characters required to output this
/// colvarvalue, given the current type assigned and the number of
/// characters for a real number
size_t output_width(size_t const &real_width) const;
/// Formats value as a script-friendly string (space separated list)
std::string to_simple_string() const;
/// Parses value from a script-friendly string (space separated list)
int from_simple_string(std::string const &s);
// optimized routines for operations on arrays of colvar values;
// xv and result are assumed to have the same number of elements
/// \brief Optimized routine for the inner product of one collective
/// variable with an array
void static inner_opt(colvarvalue const &x,
std::vector<colvarvalue>::iterator &xv,
std::vector<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result);
/// \brief Optimized routine for the inner product of one collective
/// variable with an array
void static inner_opt(colvarvalue const &x,
std::list<colvarvalue>::iterator &xv,
std::list<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result);
/// \brief Optimized routine for the second order Legendre
/// polynomial, (3cos^2(w)-1)/2, of one collective variable with an
/// array
void static p2leg_opt(colvarvalue const &x,
std::vector<colvarvalue>::iterator &xv,
std::vector<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result);
/// \brief Optimized routine for the second order Legendre
/// polynomial of one collective variable with an array
void static p2leg_opt(colvarvalue const &x,
std::list<colvarvalue>::iterator &xv,
std::list<colvarvalue>::iterator const &xv_end,
std::vector<cvm::real>::iterator &result);
};
-
-inline std::string const colvarvalue::type_desc(Type t)
-{
- switch (t) {
- case colvarvalue::type_scalar:
- return "scalar number"; break;
- case colvarvalue::type_3vector:
- return "3-dimensional vector"; break;
- case colvarvalue::type_unit3vector:
- return "3-dimensional unit vector"; break;
- case colvarvalue::type_unit3vectorderiv:
- return "derivative of a 3-dimensional unit vector"; break;
- case colvarvalue::type_quaternion:
- return "4-dimensional unit quaternion"; break;
- case colvarvalue::type_quaternionderiv:
- return "4-dimensional tangent vector"; break;
- case colvarvalue::type_vector:
- return "n-dimensional vector"; break;
- case colvarvalue::type_notset:
- // fallthrough
- default:
- return "not set"; break;
- }
-}
-
-
-inline std::string const colvarvalue::type_keyword(Type t)
-{
- switch (t) {
- case colvarvalue::type_notset:
- default:
- return "not_set"; break;
- case colvarvalue::type_scalar:
- return "scalar"; break;
- case colvarvalue::type_3vector:
- return "vector3"; break;
- case colvarvalue::type_unit3vector:
- return "unit_vector3"; break;
- case colvarvalue::type_unit3vectorderiv:
- return ""; break;
- case colvarvalue::type_quaternion:
- return "unit_quaternion"; break;
- case colvarvalue::type_quaternionderiv:
- return ""; break;
- case colvarvalue::type_vector:
- return "vector"; break;
- }
-}
-
-
-inline size_t colvarvalue::num_df(Type t)
+inline size_t colvarvalue::size() const
{
- switch (t) {
+ switch (value_type) {
case colvarvalue::type_notset:
default:
return 0; break;
case colvarvalue::type_scalar:
return 1; break;
case colvarvalue::type_3vector:
- return 3; break;
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
- return 2; break;
+ return 3; break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
- return 3; break;
+ return 4; break;
case colvarvalue::type_vector:
- // the size of a vector is unknown without its object
- return 0; break;
+ return vector1d_value.size(); break;
}
}
-inline size_t colvarvalue::num_dimensions(Type t)
+inline cvm::real colvarvalue::operator [] (int const i) const
{
- switch (t) {
+ switch (value_type) {
case colvarvalue::type_notset:
default:
- return 0; break;
+ cvm::error("Error: trying to access a colvar value "
+ "that is not initialized.\n", BUG_ERROR);
+ return 0.0; break;
case colvarvalue::type_scalar:
- return 1; break;
+ return real_value; break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
- return 3; break;
+ return rvector_value[i]; break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
- return 4; break;
+ return quaternion_value[i]; break;
case colvarvalue::type_vector:
- // the size of a vector is unknown without its object
- return 0; break;
+ return vector1d_value[i]; break;
}
}
-inline size_t colvarvalue::size() const
+inline cvm::real & colvarvalue::operator [] (int const i)
{
switch (value_type) {
case colvarvalue::type_notset:
default:
- return 0; break;
+ cvm::error("Error: trying to access a colvar value "
+ "that is not initialized.\n", BUG_ERROR);
+ return real_value; break;
case colvarvalue::type_scalar:
- return 1; break;
+ return real_value; break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
- return 3; break;
+ return rvector_value[i]; break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
- return 4; break;
+ return quaternion_value[i]; break;
case colvarvalue::type_vector:
- return vector1d_value.size(); break;
- }
-}
-
-
-inline colvarvalue::colvarvalue(colvarvalue const &x)
- : value_type(x.type())
-{
- switch (x.type()) {
- case type_scalar:
- real_value = x.real_value;
- break;
- case type_3vector:
- case type_unit3vector:
- case type_unit3vectorderiv:
- rvector_value = x.rvector_value;
- break;
- case type_quaternion:
- case type_quaternionderiv:
- quaternion_value = x.quaternion_value;
- break;
- case type_vector:
- vector1d_value = x.vector1d_value;
- elem_types = x.elem_types;
- elem_indices = x.elem_indices;
- elem_sizes = x.elem_sizes;
- case type_notset:
- default:
- break;
- }
-}
-
-inline colvarvalue::colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti)
-{
- if ((vti != type_vector) && (v.size() != num_dimensions(vti))) {
- cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+
- "\" using a vector of size "+cvm::to_str(v.size())+
- ".\n");
- value_type = type_notset;
- } else {
- value_type = vti;
- switch (vti) {
- case type_scalar:
- real_value = v[0];
- break;
- case type_3vector:
- case type_unit3vector:
- case type_unit3vectorderiv:
- rvector_value = cvm::rvector(v);
- break;
- case type_quaternion:
- case type_quaternionderiv:
- quaternion_value = cvm::quaternion(v);
- break;
- case type_vector:
- vector1d_value = v;
- break;
- case type_notset:
- default:
- break;
- }
+ return vector1d_value[i]; break;
}
}
inline int colvarvalue::check_types(colvarvalue const &x1,
colvarvalue const &x2)
{
if (!colvarvalue::type_checking()) {
return COLVARS_OK;
}
if (x1.type() != x2.type()) {
if (((x1.type() == type_unit3vector) &&
(x2.type() == type_unit3vectorderiv)) ||
((x2.type() == type_unit3vector) &&
(x1.type() == type_unit3vectorderiv)) ||
((x1.type() == type_quaternion) &&
(x2.type() == type_quaternionderiv)) ||
((x2.type() == type_quaternion) &&
(x1.type() == type_quaternionderiv))) {
return COLVARS_OK;
} else {
cvm::error("Trying to perform an operation between two colvar "
"values with different types, \""+
colvarvalue::type_desc(x1.type())+
"\" and \""+
colvarvalue::type_desc(x2.type())+
"\".\n");
return COLVARS_ERROR;
}
}
if (x1.type() == type_vector) {
if (x1.vector1d_value.size() != x2.vector1d_value.size()) {
cvm::error("Trying to perform an operation between two vector colvar "
"values with different sizes, "+
cvm::to_str(x1.vector1d_value.size())+
" and "+
cvm::to_str(x2.vector1d_value.size())+
".\n");
return COLVARS_ERROR;
}
}
return COLVARS_OK;
}
inline int colvarvalue::check_types_assign(colvarvalue::Type const &vt1,
colvarvalue::Type const &vt2)
{
if (!colvarvalue::type_checking()) {
return COLVARS_OK;
}
if (vt1 != type_notset) {
if (((vt1 == type_unit3vector) &&
(vt2 == type_unit3vectorderiv)) ||
((vt2 == type_unit3vector) &&
(vt1 == type_unit3vectorderiv)) ||
((vt1 == type_quaternion) &&
(vt2 == type_quaternionderiv)) ||
((vt2 == type_quaternion) &&
(vt1 == type_quaternionderiv))) {
return COLVARS_OK;
} else {
if (vt1 != vt2) {
cvm::error("Trying to assign a colvar value with type \""+
type_desc(vt2)+"\" to one with type \""+
type_desc(vt1)+"\".\n");
return COLVARS_ERROR;
}
}
}
return COLVARS_OK;
}
-inline void colvarvalue::undef_op() const
-{
- cvm::error("Error: Undefined operation on a colvar of type \""+
- type_desc(this->type())+"\".\n");
-}
-
-
inline colvarvalue & colvarvalue::operator = (colvarvalue const &x)
{
check_types_assign(this->type(), x.type());
value_type = x.type();
switch (this->type()) {
case colvarvalue::type_scalar:
this->real_value = x.real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
this->rvector_value = x.rvector_value;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
this->quaternion_value = x.quaternion_value;
break;
case colvarvalue::type_vector:
vector1d_value = x.vector1d_value;
elem_types = x.elem_types;
elem_indices = x.elem_indices;
elem_sizes = x.elem_sizes;
break;
case colvarvalue::type_notset:
default:
undef_op();
break;
}
return *this;
}
inline void colvarvalue::operator += (colvarvalue const &x)
{
colvarvalue::check_types(*this, x);
switch (this->type()) {
case colvarvalue::type_scalar:
this->real_value += x.real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
this->rvector_value += x.rvector_value;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
this->quaternion_value += x.quaternion_value;
break;
case colvarvalue::type_vector:
this->vector1d_value += x.vector1d_value;
break;
case colvarvalue::type_notset:
default:
undef_op();
}
}
+
inline void colvarvalue::operator -= (colvarvalue const &x)
{
colvarvalue::check_types(*this, x);
switch (value_type) {
case colvarvalue::type_scalar:
real_value -= x.real_value;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
rvector_value -= x.rvector_value;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
quaternion_value -= x.quaternion_value;
break;
case colvarvalue::type_vector:
this->vector1d_value -= x.vector1d_value;
break;
case colvarvalue::type_notset:
default:
undef_op();
}
}
inline void colvarvalue::operator *= (cvm::real const &a)
{
switch (value_type) {
case colvarvalue::type_scalar:
real_value *= a;
break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vectorderiv:
rvector_value *= a;
break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
quaternion_value *= a;
break;
case colvarvalue::type_vector:
this->vector1d_value *= a;
break;
case colvarvalue::type_notset:
default:
undef_op();
}
}
inline void colvarvalue::operator /= (cvm::real const &a)
{
switch (value_type) {
case colvarvalue::type_scalar:
real_value /= a; break;
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
rvector_value /= a; break;
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
quaternion_value /= a; break;
case colvarvalue::type_vector:
this->vector1d_value /= a;
break;
case colvarvalue::type_notset:
default:
undef_op();
}
}
inline cvm::vector1d<cvm::real> const colvarvalue::as_vector() const
{
switch (value_type) {
case colvarvalue::type_scalar:
{
cvm::vector1d<cvm::real> v(1);
v[0] = real_value;
return v;
}
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return rvector_value.as_vector();
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return quaternion_value.as_vector();
case colvarvalue::type_vector:
return vector1d_value;
case colvarvalue::type_notset:
default:
return cvm::vector1d<cvm::real>(0);
}
}
-inline void colvarvalue::reset()
-{
- switch (value_type) {
- case colvarvalue::type_scalar:
- real_value = 0.0;
- break;
- case colvarvalue::type_3vector:
- case colvarvalue::type_unit3vector:
- case colvarvalue::type_unit3vectorderiv:
- rvector_value.reset();
- break;
- case colvarvalue::type_quaternion:
- case colvarvalue::type_quaternionderiv:
- quaternion_value.reset();
- break;
- case colvarvalue::type_vector:
- vector1d_value.reset();
- break;
- case colvarvalue::type_notset:
- default:
- break;
- }
-}
-
-
-inline void colvarvalue::apply_constraints()
-{
- switch (value_type) {
- case colvarvalue::type_scalar:
- case colvarvalue::type_3vector:
- case colvarvalue::type_unit3vectorderiv:
- case colvarvalue::type_quaternionderiv:
- break;
- case colvarvalue::type_unit3vector:
- rvector_value /= std::sqrt(rvector_value.norm2());
- break;
- case colvarvalue::type_quaternion:
- quaternion_value /= std::sqrt(quaternion_value.norm2());
- break;
- case colvarvalue::type_vector:
- if (elem_types.size() > 0) {
- // if we have information about non-scalar types, use it
- size_t i;
- for (i = 0; i < elem_types.size(); i++) {
- if (elem_sizes[i] == 1) continue; // TODO this can be optimized further
- colvarvalue cvtmp(vector1d_value.slice(elem_indices[i],
- elem_indices[i] + elem_sizes[i]), elem_types[i]);
- cvtmp.apply_constraints();
- set_elem(i, cvtmp);
- }
- }
- break;
- case colvarvalue::type_notset:
- default:
- break;
- }
-}
-
-
-inline void colvarvalue::is_derivative()
-{
- switch (value_type) {
- case colvarvalue::type_scalar:
- case colvarvalue::type_3vector:
- case colvarvalue::type_unit3vectorderiv:
- case colvarvalue::type_quaternionderiv:
- break;
- case colvarvalue::type_unit3vector:
- type(colvarvalue::type_unit3vectorderiv);
- break;
- case colvarvalue::type_quaternion:
- type(colvarvalue::type_quaternionderiv);
- break;
- case colvarvalue::type_vector:
- // TODO
- break;
- case colvarvalue::type_notset:
- default:
- break;
- }
-}
-
-
inline cvm::real colvarvalue::norm2() const
{
switch (value_type) {
case colvarvalue::type_scalar:
return (this->real_value)*(this->real_value);
case colvarvalue::type_3vector:
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
return (this->rvector_value).norm2();
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
return (this->quaternion_value).norm2();
case colvarvalue::type_vector:
if (elem_types.size() > 0) {
// if we have information about non-scalar types, use it
cvm::real result = 0.0;
size_t i;
for (i = 0; i < elem_types.size(); i++) {
result += (this->get_elem(i)).norm2();
}
return result;
} else {
return vector1d_value.norm2();
}
break;
case colvarvalue::type_notset:
default:
return 0.0;
}
}
inline cvm::real colvarvalue::dist2(colvarvalue const &x2) const
{
colvarvalue::check_types(*this, x2);
switch (this->type()) {
case colvarvalue::type_scalar:
return (this->real_value - x2.real_value)*(this->real_value - x2.real_value);
case colvarvalue::type_3vector:
return (this->rvector_value - x2.rvector_value).norm2();
case colvarvalue::type_unit3vector:
case colvarvalue::type_unit3vectorderiv:
// angle between (*this) and x2 is the distance
return std::acos(this->rvector_value * x2.rvector_value) * std::acos(this->rvector_value * x2.rvector_value);
case colvarvalue::type_quaternion:
case colvarvalue::type_quaternionderiv:
// angle between (*this) and x2 is the distance, the quaternion
// object has it implemented internally
return this->quaternion_value.dist2(x2.quaternion_value);
case colvarvalue::type_vector:
return (this->vector1d_value - x2.vector1d_value).norm2();
case colvarvalue::type_notset:
default:
this->undef_op();
return 0.0;
};
}
#endif
diff --git a/src/ASPHERE/pair_gayberne.cpp b/src/ASPHERE/pair_gayberne.cpp
index 25bdae14f..9ff87326e 100644
--- a/src/ASPHERE/pair_gayberne.cpp
+++ b/src/ASPHERE/pair_gayberne.cpp
@@ -1,953 +1,953 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Mike Brown (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_gayberne.h"
#include "math_extra.h"
#include "atom.h"
#include "atom_vec_ellipsoid.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "integrate.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
static const char cite_pair_gayberne[] =
"pair gayberne command:\n\n"
"@Article{Brown09,\n"
" author = {W. M. Brown, M. K. Petersen, S. J. Plimpton, and G. S. Grest},\n"
" title = {Liquid crystal nanodroplets in solution},\n"
" journal = {J.~Chem.~Phys.},\n"
" year = 2009,\n"
" volume = 130,\n"
" pages = {044901}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
PairGayBerne::PairGayBerne(LAMMPS *lmp) : Pair(lmp)
{
if (lmp->citeme) lmp->citeme->add(cite_pair_gayberne);
single_enable = 0;
writedata = 1;
}
/* ----------------------------------------------------------------------
free all arrays
------------------------------------------------------------------------- */
PairGayBerne::~PairGayBerne()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(form);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(shape1);
memory->destroy(shape2);
memory->destroy(well);
memory->destroy(cut);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
delete [] lshape;
delete [] setwell;
}
}
/* ---------------------------------------------------------------------- */
void PairGayBerne::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj;
double fforce[3],ttor[3],rtor[3],r12[3];
double a1[3][3],b1[3][3],g1[3][3],a2[3][3],b2[3][3],g2[3][3],temp[3][3];
int *ilist,*jlist,*numneigh,**firstneigh;
double *iquat,*jquat;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
AtomVecEllipsoid::Bonus *bonus = avec->bonus;
int *ellipsoid = atom->ellipsoid;
double **x = atom->x;
double **f = atom->f;
double **tor = atom->torque;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = type[i];
if (form[itype][itype] == ELLIPSE_ELLIPSE) {
iquat = bonus[ellipsoid[i]].quat;
MathExtra::quat_to_mat_trans(iquat,a1);
MathExtra::diag_times3(well[itype],a1,temp);
MathExtra::transpose_times3(a1,temp,b1);
MathExtra::diag_times3(shape2[itype],a1,temp);
MathExtra::transpose_times3(a1,temp,g1);
}
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
// r12 = center to center vector
r12[0] = x[j][0]-x[i][0];
r12[1] = x[j][1]-x[i][1];
r12[2] = x[j][2]-x[i][2];
rsq = MathExtra::dot3(r12,r12);
jtype = type[j];
// compute if less than cutoff
if (rsq < cutsq[itype][jtype]) {
switch (form[itype][jtype]) {
case SPHERE_SPHERE:
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
forcelj *= -r2inv;
if (eflag) one_eng =
r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) -
offset[itype][jtype];
fforce[0] = r12[0]*forcelj;
fforce[1] = r12[1]*forcelj;
fforce[2] = r12[2]*forcelj;
ttor[0] = ttor[1] = ttor[2] = 0.0;
rtor[0] = rtor[1] = rtor[2] = 0.0;
break;
case SPHERE_ELLIPSE:
jquat = bonus[ellipsoid[j]].quat;
MathExtra::quat_to_mat_trans(jquat,a2);
MathExtra::diag_times3(well[jtype],a2,temp);
MathExtra::transpose_times3(a2,temp,b2);
MathExtra::diag_times3(shape2[jtype],a2,temp);
MathExtra::transpose_times3(a2,temp,g2);
one_eng = gayberne_lj(j,i,a2,b2,g2,r12,rsq,fforce,rtor);
ttor[0] = ttor[1] = ttor[2] = 0.0;
break;
case ELLIPSE_SPHERE:
one_eng = gayberne_lj(i,j,a1,b1,g1,r12,rsq,fforce,ttor);
rtor[0] = rtor[1] = rtor[2] = 0.0;
break;
default:
jquat = bonus[ellipsoid[j]].quat;
MathExtra::quat_to_mat_trans(jquat,a2);
MathExtra::diag_times3(well[jtype],a2,temp);
MathExtra::transpose_times3(a2,temp,b2);
MathExtra::diag_times3(shape2[jtype],a2,temp);
MathExtra::transpose_times3(a2,temp,g2);
one_eng = gayberne_analytic(i,j,a1,a2,b1,b2,g1,g2,r12,rsq,
fforce,ttor,rtor);
break;
}
fforce[0] *= factor_lj;
fforce[1] *= factor_lj;
fforce[2] *= factor_lj;
ttor[0] *= factor_lj;
ttor[1] *= factor_lj;
ttor[2] *= factor_lj;
f[i][0] += fforce[0];
f[i][1] += fforce[1];
f[i][2] += fforce[2];
tor[i][0] += ttor[0];
tor[i][1] += ttor[1];
tor[i][2] += ttor[2];
if (newton_pair || j < nlocal) {
rtor[0] *= factor_lj;
rtor[1] *= factor_lj;
rtor[2] *= factor_lj;
f[j][0] -= fforce[0];
f[j][1] -= fforce[1];
f[j][2] -= fforce[2];
tor[j][0] += rtor[0];
tor[j][1] += rtor[1];
tor[j][2] += rtor[2];
}
if (eflag) evdwl = factor_lj*one_eng;
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
evdwl,0.0,fforce[0],fforce[1],fforce[2],
-r12[0],-r12[1],-r12[2]);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairGayBerne::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(form,n+1,n+1,"pair:form");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(shape1,n+1,3,"pair:shape1");
memory->create(shape2,n+1,3,"pair:shape2");
memory->create(well,n+1,3,"pair:well");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
lshape = new double[n+1];
setwell = new int[n+1];
for (int i = 1; i <= n; i++) setwell[i] = 0;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairGayBerne::settings(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Illegal pair_style command");
gamma = force->numeric(FLERR,arg[0]);
upsilon = force->numeric(FLERR,arg[1])/2.0;
mu = force->numeric(FLERR,arg[2]);
cut_global = force->numeric(FLERR,arg[3]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairGayBerne::coeff(int narg, char **arg)
{
if (narg < 10 || narg > 11)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double eia_one = force->numeric(FLERR,arg[4]);
double eib_one = force->numeric(FLERR,arg[5]);
double eic_one = force->numeric(FLERR,arg[6]);
double eja_one = force->numeric(FLERR,arg[7]);
double ejb_one = force->numeric(FLERR,arg[8]);
double ejc_one = force->numeric(FLERR,arg[9]);
double cut_one = cut_global;
if (narg == 11) cut_one = force->numeric(FLERR,arg[10]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
if (eia_one != 0.0 || eib_one != 0.0 || eic_one != 0.0) {
well[i][0] = pow(eia_one,-1.0/mu);
well[i][1] = pow(eib_one,-1.0/mu);
well[i][2] = pow(eic_one,-1.0/mu);
if (eia_one == eib_one && eib_one == eic_one) setwell[i] = 2;
else setwell[i] = 1;
}
if (eja_one != 0.0 || ejb_one != 0.0 || ejc_one != 0.0) {
well[j][0] = pow(eja_one,-1.0/mu);
well[j][1] = pow(ejb_one,-1.0/mu);
well[j][2] = pow(ejc_one,-1.0/mu);
if (eja_one == ejb_one && ejb_one == ejc_one) setwell[j] = 2;
else setwell[j] = 1;
}
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairGayBerne::init_style()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
if (!avec) error->all(FLERR,"Pair gayberne requires atom style ellipsoid");
neighbor->request(this,instance_me);
// per-type shape precalculations
// require that atom shapes are identical within each type
// if shape = 0 for point particle, set shape = 1 as required by Gay-Berne
for (int i = 1; i <= atom->ntypes; i++) {
if (!atom->shape_consistency(i,shape1[i][0],shape1[i][1],shape1[i][2]))
error->all(FLERR,
"Pair gayberne requires atoms with same type have same shape");
if (shape1[i][0] == 0.0)
shape1[i][0] = shape1[i][1] = shape1[i][2] = 1.0;
shape2[i][0] = shape1[i][0]*shape1[i][0];
shape2[i][1] = shape1[i][1]*shape1[i][1];
shape2[i][2] = shape1[i][2]*shape1[i][2];
lshape[i] = (shape1[i][0]*shape1[i][1]+shape1[i][2]*shape1[i][2]) *
sqrt(shape1[i][0]*shape1[i][1]);
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairGayBerne::init_one(int i, int j)
{
if (setwell[i] == 0 || setwell[j] == 0)
error->all(FLERR,"Pair gayberne epsilon a,b,c coeffs are not all set");
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
int ishape = 0;
if (shape1[i][0] != shape1[i][1] ||
shape1[i][0] != shape1[i][2] ||
shape1[i][1] != shape1[i][2]) ishape = 1;
if (setwell[i] == 1) ishape = 1;
int jshape = 0;
if (shape1[j][0] != shape1[j][1] ||
shape1[j][0] != shape1[j][2] ||
shape1[j][1] != shape1[j][2]) jshape = 1;
if (setwell[j] == 1) jshape = 1;
if (ishape == 0 && jshape == 0)
form[i][i] = form[j][j] = form[i][j] = form[j][i] = SPHERE_SPHERE;
else if (ishape == 0) {
form[i][i] = SPHERE_SPHERE; form[j][j] = ELLIPSE_ELLIPSE;
form[i][j] = SPHERE_ELLIPSE; form[j][i] = ELLIPSE_SPHERE;
} else if (jshape == 0) {
form[j][j] = SPHERE_SPHERE; form[i][i] = ELLIPSE_ELLIPSE;
form[j][i] = SPHERE_ELLIPSE; form[i][j] = ELLIPSE_SPHERE;
} else
form[i][i] = form[j][j] = form[i][j] = form[j][i] = ELLIPSE_ELLIPSE;
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairGayBerne::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++) {
fwrite(&setwell[i],sizeof(int),1,fp);
if (setwell[i]) fwrite(&well[i][0],sizeof(double),3,fp);
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairGayBerne::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++) {
if (me == 0) fread(&setwell[i],sizeof(int),1,fp);
MPI_Bcast(&setwell[i],1,MPI_INT,0,world);
if (setwell[i]) {
if (me == 0) fread(&well[i][0],sizeof(double),3,fp);
MPI_Bcast(&well[i][0],3,MPI_DOUBLE,0,world);
}
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairGayBerne::write_restart_settings(FILE *fp)
{
fwrite(&gamma,sizeof(double),1,fp);
fwrite(&upsilon,sizeof(double),1,fp);
fwrite(&mu,sizeof(double),1,fp);
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairGayBerne::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&gamma,sizeof(double),1,fp);
fread(&upsilon,sizeof(double),1,fp);
fread(&mu,sizeof(double),1,fp);
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&gamma,1,MPI_DOUBLE,0,world);
MPI_Bcast(&upsilon,1,MPI_DOUBLE,0,world);
MPI_Bcast(&mu,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairGayBerne::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i,
epsilon[i][i],sigma[i][i],
pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu),
pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu));
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairGayBerne::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g %g %g %g %g\n",i,j,
epsilon[i][i],sigma[i][i],
pow(well[i][0],-mu),pow(well[i][1],-mu),pow(well[i][2],-mu),
pow(well[j][0],-mu),pow(well[j][1],-mu),pow(well[j][2],-mu),
cut[i][j]);
}
/* ----------------------------------------------------------------------
compute analytic energy, force (fforce), and torque (ttor & rtor)
based on rotation matrices a and precomputed matrices b and g
if newton is off, rtor is not calculated for ghost atoms
------------------------------------------------------------------------- */
double PairGayBerne::gayberne_analytic(const int i,const int j,double a1[3][3],
double a2[3][3], double b1[3][3],
double b2[3][3], double g1[3][3],
double g2[3][3], double *r12,
const double rsq, double *fforce,
double *ttor, double *rtor)
{
double tempv[3], tempv2[3];
double temp[3][3];
double temp1,temp2,temp3;
int *type = atom->type;
int newton_pair = force->newton_pair;
int nlocal = atom->nlocal;
double r12hat[3];
MathExtra::normalize3(r12,r12hat);
double r = sqrt(rsq);
// compute distance of closest approach
double g12[3][3];
MathExtra::plus3(g1,g2,g12);
double kappa[3];
int ierror = MathExtra::mldivide3(g12,r12,kappa);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
// tempv = G12^-1*r12hat
tempv[0] = kappa[0]/r;
tempv[1] = kappa[1]/r;
tempv[2] = kappa[2]/r;
double sigma12 = MathExtra::dot3(r12hat,tempv);
sigma12 = pow(0.5*sigma12,-0.5);
double h12 = r-sigma12;
// energy
// compute u_r
double varrho = sigma[type[i]][type[j]]/(h12+gamma*sigma[type[i]][type[j]]);
double varrho6 = pow(varrho,6.0);
double varrho12 = varrho6*varrho6;
double u_r = 4.0*epsilon[type[i]][type[j]]*(varrho12-varrho6);
// compute eta_12
double eta = 2.0*lshape[type[i]]*lshape[type[j]];
double det_g12 = MathExtra::det3(g12);
eta = pow(eta/det_g12,upsilon);
// compute chi_12
double b12[3][3];
double iota[3];
MathExtra::plus3(b1,b2,b12);
ierror = MathExtra::mldivide3(b12,r12,iota);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
// tempv = G12^-1*r12hat
tempv[0] = iota[0]/r;
tempv[1] = iota[1]/r;
tempv[2] = iota[2]/r;
double chi = MathExtra::dot3(r12hat,tempv);
chi = pow(chi*2.0,mu);
// force
// compute dUr/dr
temp1 = (2.0*varrho12*varrho-varrho6*varrho)/sigma[type[i]][type[j]];
temp1 = temp1*24.0*epsilon[type[i]][type[j]];
double u_slj = temp1*pow(sigma12,3.0)/2.0;
double dUr[3];
temp2 = MathExtra::dot3(kappa,r12hat);
double uslj_rsq = u_slj/rsq;
dUr[0] = temp1*r12hat[0]+uslj_rsq*(kappa[0]-temp2*r12hat[0]);
dUr[1] = temp1*r12hat[1]+uslj_rsq*(kappa[1]-temp2*r12hat[1]);
dUr[2] = temp1*r12hat[2]+uslj_rsq*(kappa[2]-temp2*r12hat[2]);
// compute dChi_12/dr
double dchi[3];
temp1 = MathExtra::dot3(iota,r12hat);
temp2 = -4.0/rsq*mu*pow(chi,(mu-1.0)/mu);
dchi[0] = temp2*(iota[0]-temp1*r12hat[0]);
dchi[1] = temp2*(iota[1]-temp1*r12hat[1]);
dchi[2] = temp2*(iota[2]-temp1*r12hat[2]);
temp1 = -eta*u_r;
temp2 = eta*chi;
fforce[0] = temp1*dchi[0]-temp2*dUr[0];
fforce[1] = temp1*dchi[1]-temp2*dUr[1];
fforce[2] = temp1*dchi[2]-temp2*dUr[2];
// torque for particle 1 and 2
// compute dUr
tempv[0] = -uslj_rsq*kappa[0];
tempv[1] = -uslj_rsq*kappa[1];
tempv[2] = -uslj_rsq*kappa[2];
MathExtra::vecmat(kappa,g1,tempv2);
MathExtra::cross3(tempv,tempv2,dUr);
double dUr2[3];
if (newton_pair || j < nlocal) {
MathExtra::vecmat(kappa,g2,tempv2);
MathExtra::cross3(tempv,tempv2,dUr2);
}
// compute d_chi
MathExtra::vecmat(iota,b1,tempv);
MathExtra::cross3(tempv,iota,dchi);
temp1 = -4.0/rsq;
dchi[0] *= temp1;
dchi[1] *= temp1;
dchi[2] *= temp1;
double dchi2[3];
if (newton_pair || j < nlocal) {
MathExtra::vecmat(iota,b2,tempv);
MathExtra::cross3(tempv,iota,dchi2);
dchi2[0] *= temp1;
dchi2[1] *= temp1;
dchi2[2] *= temp1;
}
// compute d_eta
double deta[3];
deta[0] = deta[1] = deta[2] = 0.0;
compute_eta_torque(g12,a1,shape2[type[i]],temp);
temp1 = -eta*upsilon;
for (int m = 0; m < 3; m++) {
for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y];
MathExtra::cross3(a1[m],tempv,tempv2);
deta[0] += tempv2[0];
deta[1] += tempv2[1];
deta[2] += tempv2[2];
}
// compute d_eta for particle 2
double deta2[3];
if (newton_pair || j < nlocal) {
deta2[0] = deta2[1] = deta2[2] = 0.0;
compute_eta_torque(g12,a2,shape2[type[j]],temp);
for (int m = 0; m < 3; m++) {
for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y];
MathExtra::cross3(a2[m],tempv,tempv2);
deta2[0] += tempv2[0];
deta2[1] += tempv2[1];
deta2[2] += tempv2[2];
}
}
// torque
temp1 = u_r*eta;
temp2 = u_r*chi;
temp3 = chi*eta;
ttor[0] = (temp1*dchi[0]+temp2*deta[0]+temp3*dUr[0]) * -1.0;
ttor[1] = (temp1*dchi[1]+temp2*deta[1]+temp3*dUr[1]) * -1.0;
ttor[2] = (temp1*dchi[2]+temp2*deta[2]+temp3*dUr[2]) * -1.0;
if (newton_pair || j < nlocal) {
rtor[0] = (temp1*dchi2[0]+temp2*deta2[0]+temp3*dUr2[0]) * -1.0;
rtor[1] = (temp1*dchi2[1]+temp2*deta2[1]+temp3*dUr2[1]) * -1.0;
rtor[2] = (temp1*dchi2[2]+temp2*deta2[2]+temp3*dUr2[2]) * -1.0;
}
return temp1*chi;
}
/* ----------------------------------------------------------------------
compute analytic energy, force (fforce), and torque (ttor)
between ellipsoid and lj particle
------------------------------------------------------------------------- */
double PairGayBerne::gayberne_lj(const int i,const int j,double a1[3][3],
double b1[3][3],double g1[3][3],
double *r12,const double rsq,double *fforce,
double *ttor)
{
double tempv[3], tempv2[3];
double temp[3][3];
double temp1,temp2,temp3;
int *type = atom->type;
double r12hat[3];
MathExtra::normalize3(r12,r12hat);
double r = sqrt(rsq);
// compute distance of closest approach
double g12[3][3];
g12[0][0] = g1[0][0]+shape2[type[j]][0];
g12[1][1] = g1[1][1]+shape2[type[j]][0];
g12[2][2] = g1[2][2]+shape2[type[j]][0];
g12[0][1] = g1[0][1]; g12[1][0] = g1[1][0];
g12[0][2] = g1[0][2]; g12[2][0] = g1[2][0];
g12[1][2] = g1[1][2]; g12[2][1] = g1[2][1];
double kappa[3];
int ierror = MathExtra::mldivide3(g12,r12,kappa);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
// tempv = G12^-1*r12hat
tempv[0] = kappa[0]/r;
tempv[1] = kappa[1]/r;
tempv[2] = kappa[2]/r;
double sigma12 = MathExtra::dot3(r12hat,tempv);
sigma12 = pow(0.5*sigma12,-0.5);
double h12 = r-sigma12;
// energy
// compute u_r
double varrho = sigma[type[i]][type[j]]/(h12+gamma*sigma[type[i]][type[j]]);
double varrho6 = pow(varrho,6.0);
double varrho12 = varrho6*varrho6;
double u_r = 4.0*epsilon[type[i]][type[j]]*(varrho12-varrho6);
// compute eta_12
double eta = 2.0*lshape[type[i]]*lshape[type[j]];
double det_g12 = MathExtra::det3(g12);
eta = pow(eta/det_g12,upsilon);
// compute chi_12
double b12[3][3];
double iota[3];
b12[0][0] = b1[0][0] + well[type[j]][0];
b12[1][1] = b1[1][1] + well[type[j]][0];
b12[2][2] = b1[2][2] + well[type[j]][0];
b12[0][1] = b1[0][1]; b12[1][0] = b1[1][0];
b12[0][2] = b1[0][2]; b12[2][0] = b1[2][0];
b12[1][2] = b1[1][2]; b12[2][1] = b1[2][1];
ierror = MathExtra::mldivide3(b12,r12,iota);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
// tempv = G12^-1*r12hat
tempv[0] = iota[0]/r;
tempv[1] = iota[1]/r;
tempv[2] = iota[2]/r;
double chi = MathExtra::dot3(r12hat,tempv);
chi = pow(chi*2.0,mu);
// force
// compute dUr/dr
temp1 = (2.0*varrho12*varrho-varrho6*varrho)/sigma[type[i]][type[j]];
temp1 = temp1*24.0*epsilon[type[i]][type[j]];
double u_slj = temp1*pow(sigma12,3.0)/2.0;
double dUr[3];
temp2 = MathExtra::dot3(kappa,r12hat);
double uslj_rsq = u_slj/rsq;
dUr[0] = temp1*r12hat[0]+uslj_rsq*(kappa[0]-temp2*r12hat[0]);
dUr[1] = temp1*r12hat[1]+uslj_rsq*(kappa[1]-temp2*r12hat[1]);
dUr[2] = temp1*r12hat[2]+uslj_rsq*(kappa[2]-temp2*r12hat[2]);
// compute dChi_12/dr
double dchi[3];
temp1 = MathExtra::dot3(iota,r12hat);
temp2 = -4.0/rsq*mu*pow(chi,(mu-1.0)/mu);
dchi[0] = temp2*(iota[0]-temp1*r12hat[0]);
dchi[1] = temp2*(iota[1]-temp1*r12hat[1]);
dchi[2] = temp2*(iota[2]-temp1*r12hat[2]);
temp1 = -eta*u_r;
temp2 = eta*chi;
fforce[0] = temp1*dchi[0]-temp2*dUr[0];
fforce[1] = temp1*dchi[1]-temp2*dUr[1];
fforce[2] = temp1*dchi[2]-temp2*dUr[2];
// torque for particle 1 and 2
// compute dUr
tempv[0] = -uslj_rsq*kappa[0];
tempv[1] = -uslj_rsq*kappa[1];
tempv[2] = -uslj_rsq*kappa[2];
MathExtra::vecmat(kappa,g1,tempv2);
MathExtra::cross3(tempv,tempv2,dUr);
// compute d_chi
MathExtra::vecmat(iota,b1,tempv);
MathExtra::cross3(tempv,iota,dchi);
temp1 = -4.0/rsq;
dchi[0] *= temp1;
dchi[1] *= temp1;
dchi[2] *= temp1;
// compute d_eta
double deta[3];
deta[0] = deta[1] = deta[2] = 0.0;
compute_eta_torque(g12,a1,shape2[type[i]],temp);
temp1 = -eta*upsilon;
for (int m = 0; m < 3; m++) {
for (int y = 0; y < 3; y++) tempv[y] = temp1*temp[m][y];
MathExtra::cross3(a1[m],tempv,tempv2);
deta[0] += tempv2[0];
deta[1] += tempv2[1];
deta[2] += tempv2[2];
}
// torque
temp1 = u_r*eta;
temp2 = u_r*chi;
temp3 = chi*eta;
ttor[0] = (temp1*dchi[0]+temp2*deta[0]+temp3*dUr[0]) * -1.0;
ttor[1] = (temp1*dchi[1]+temp2*deta[1]+temp3*dUr[1]) * -1.0;
ttor[2] = (temp1*dchi[2]+temp2*deta[2]+temp3*dUr[2]) * -1.0;
return temp1*chi;
}
/* ----------------------------------------------------------------------
torque contribution from eta
computes trace in the last doc equation for the torque derivative
code comes from symbolic solver dump
m is g12, m2 is a_i, s is the shape for the particle
------------------------------------------------------------------------- */
void PairGayBerne::compute_eta_torque(double m[3][3], double m2[3][3],
double *s, double ans[3][3])
{
double den = m[1][0]*m[0][2]*m[2][1]-m[0][0]*m[1][2]*m[2][1]-
m[0][2]*m[2][0]*m[1][1]+m[0][1]*m[2][0]*m[1][2]-
m[1][0]*m[0][1]*m[2][2]+m[0][0]*m[1][1]*m[2][2];
ans[0][0] = s[0]*(m[1][2]*m[0][1]*m2[0][2]+2.0*m[1][1]*m[2][2]*m2[0][0]-
m[1][1]*m2[0][2]*m[0][2]-2.0*m[1][2]*m2[0][0]*m[2][1]+
m2[0][1]*m[0][2]*m[2][1]-m2[0][1]*m[0][1]*m[2][2]-
m[1][0]*m[2][2]*m2[0][1]+m[2][0]*m[1][2]*m2[0][1]+
m[1][0]*m2[0][2]*m[2][1]-m2[0][2]*m[2][0]*m[1][1])/den;
ans[0][1] = s[0]*(m[0][2]*m2[0][0]*m[2][1]-m[2][2]*m2[0][0]*m[0][1]+
2.0*m[0][0]*m[2][2]*m2[0][1]-m[0][0]*m2[0][2]*m[1][2]-
2.0*m[2][0]*m[0][2]*m2[0][1]+m2[0][2]*m[1][0]*m[0][2]-
m[2][2]*m[1][0]*m2[0][0]+m[2][0]*m2[0][0]*m[1][2]+
m[2][0]*m2[0][2]*m[0][1]-m2[0][2]*m[0][0]*m[2][1])/den;
ans[0][2] = s[0]*(m[0][1]*m[1][2]*m2[0][0]-m[0][2]*m2[0][0]*m[1][1]-
m[0][0]*m[1][2]*m2[0][1]+m[1][0]*m[0][2]*m2[0][1]-
m2[0][1]*m[0][0]*m[2][1]-m[2][0]*m[1][1]*m2[0][0]+
2.0*m[1][1]*m[0][0]*m2[0][2]-2.0*m[1][0]*m2[0][2]*m[0][1]+
m[1][0]*m[2][1]*m2[0][0]+m[2][0]*m2[0][1]*m[0][1])/den;
ans[1][0] = s[1]*(-m[1][1]*m2[1][2]*m[0][2]+2.0*m[1][1]*m[2][2]*m2[1][0]+
m[1][2]*m[0][1]*m2[1][2]-2.0*m[1][2]*m2[1][0]*m[2][1]+
m2[1][1]*m[0][2]*m[2][1]-m2[1][1]*m[0][1]*m[2][2]-
m[1][0]*m[2][2]*m2[1][1]+m[2][0]*m[1][2]*m2[1][1]-
m2[1][2]*m[2][0]*m[1][1]+m[1][0]*m2[1][2]*m[2][1])/den;
ans[1][1] = s[1]*(m[0][2]*m2[1][0]*m[2][1]-m[0][1]*m[2][2]*m2[1][0]+
2.0*m[2][2]*m[0][0]*m2[1][1]-m2[1][2]*m[0][0]*m[1][2]-
2.0*m[2][0]*m2[1][1]*m[0][2]-m[1][0]*m[2][2]*m2[1][0]+
m[2][0]*m[1][2]*m2[1][0]+m[1][0]*m2[1][2]*m[0][2]-
m[0][0]*m2[1][2]*m[2][1]+m2[1][2]*m[0][1]*m[2][0])/den;
ans[1][2] = s[1]*(m[0][1]*m[1][2]*m2[1][0]-m[0][2]*m2[1][0]*m[1][1]-
m[0][0]*m[1][2]*m2[1][1]+m[1][0]*m[0][2]*m2[1][1]+
2.0*m[1][1]*m[0][0]*m2[1][2]-m[0][0]*m2[1][1]*m[2][1]+
m[0][1]*m[2][0]*m2[1][1]-m2[1][0]*m[2][0]*m[1][1]-
2.0*m[1][0]*m[0][1]*m2[1][2]+m[1][0]*m2[1][0]*m[2][1])/den;
ans[2][0] = s[2]*(-m[1][1]*m[0][2]*m2[2][2]+m[0][1]*m[1][2]*m2[2][2]+
2.0*m[1][1]*m2[2][0]*m[2][2]-m[0][1]*m2[2][1]*m[2][2]+
m[0][2]*m[2][1]*m2[2][1]-2.0*m2[2][0]*m[2][1]*m[1][2]-
m[1][0]*m2[2][1]*m[2][2]+m[1][2]*m[2][0]*m2[2][1]-
m[1][1]*m[2][0]*m2[2][2]+m[2][1]*m[1][0]*m2[2][2])/den;
ans[2][1] = s[2]*-(m[0][1]*m[2][2]*m2[2][0]-m[0][2]*m2[2][0]*m[2][1]-
2.0*m2[2][1]*m[0][0]*m[2][2]+m[1][2]*m2[2][2]*m[0][0]+
2.0*m2[2][1]*m[0][2]*m[2][0]+m[1][0]*m2[2][0]*m[2][2]-
m[1][0]*m[0][2]*m2[2][2]-m[1][2]*m[2][0]*m2[2][0]+
m[0][0]*m2[2][2]*m[2][1]-m2[2][2]*m[0][1]*m[2][0])/den;
ans[2][2] = s[2]*(m[0][1]*m[1][2]*m2[2][0]-m[0][2]*m2[2][0]*m[1][1]-
m[0][0]*m[1][2]*m2[2][1]+m[1][0]*m[0][2]*m2[2][1]-
m[1][1]*m[2][0]*m2[2][0]-m[2][1]*m2[2][1]*m[0][0]+
2.0*m[1][1]*m2[2][2]*m[0][0]+m[2][1]*m[1][0]*m2[2][0]+
m[2][0]*m[0][1]*m2[2][1]-2.0*m2[2][2]*m[1][0]*m[0][1])/den;
}
diff --git a/src/ASPHERE/pair_resquared.cpp b/src/ASPHERE/pair_resquared.cpp
index ed9d9b36c..caa031a1e 100644
--- a/src/ASPHERE/pair_resquared.cpp
+++ b/src/ASPHERE/pair_resquared.cpp
@@ -1,990 +1,990 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Mike Brown (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_resquared.h"
#include "math_extra.h"
#include "atom.h"
#include "atom_vec_ellipsoid.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "integrate.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairRESquared::PairRESquared(LAMMPS *lmp) : Pair(lmp),
cr60(pow(60.0,1.0/3.0)),
b_alpha(45.0/56.0)
{
single_enable = 0;
cr60 = pow(60.0,1.0/3.0);
b_alpha = 45.0/56.0;
solv_f_a = 3.0/(16.0*atan(1.0)*-36.0);
solv_f_r = 3.0/(16.0*atan(1.0)*2025.0);
}
/* ----------------------------------------------------------------------
free all arrays
------------------------------------------------------------------------- */
PairRESquared::~PairRESquared()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(form);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(shape1);
memory->destroy(shape2);
memory->destroy(well);
memory->destroy(cut);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
delete [] lshape;
delete [] setwell;
}
}
/* ---------------------------------------------------------------------- */
void PairRESquared::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double evdwl,one_eng,rsq,r2inv,r6inv,forcelj,factor_lj;
double fforce[3],ttor[3],rtor[3],r12[3];
int *ilist,*jlist,*numneigh,**firstneigh;
RE2Vars wi,wj;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double **tor = atom->torque;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = type[i];
// not a LJ sphere
if (lshape[itype] != 0.0) precompute_i(i,wi);
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
// r12 = center to center vector
r12[0] = x[j][0]-x[i][0];
r12[1] = x[j][1]-x[i][1];
r12[2] = x[j][2]-x[i][2];
rsq = MathExtra::dot3(r12,r12);
jtype = type[j];
// compute if less than cutoff
if (rsq < cutsq[itype][jtype]) {
fforce[0] = fforce[1] = fforce[2] = 0.0;
switch (form[itype][jtype]) {
case SPHERE_SPHERE:
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
forcelj *= -r2inv;
if (eflag) one_eng =
r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) -
offset[itype][jtype];
fforce[0] = r12[0]*forcelj;
fforce[1] = r12[1]*forcelj;
fforce[2] = r12[2]*forcelj;
break;
case SPHERE_ELLIPSE:
precompute_i(j,wj);
if (newton_pair || j < nlocal) {
one_eng = resquared_lj(j,i,wj,r12,rsq,fforce,rtor,true);
tor[j][0] += rtor[0]*factor_lj;
tor[j][1] += rtor[1]*factor_lj;
tor[j][2] += rtor[2]*factor_lj;
} else
one_eng = resquared_lj(j,i,wj,r12,rsq,fforce,rtor,false);
break;
case ELLIPSE_SPHERE:
one_eng = resquared_lj(i,j,wi,r12,rsq,fforce,ttor,true);
tor[i][0] += ttor[0]*factor_lj;
tor[i][1] += ttor[1]*factor_lj;
tor[i][2] += ttor[2]*factor_lj;
break;
default:
precompute_i(j,wj);
one_eng = resquared_analytic(i,j,wi,wj,r12,rsq,fforce,ttor,rtor);
tor[i][0] += ttor[0]*factor_lj;
tor[i][1] += ttor[1]*factor_lj;
tor[i][2] += ttor[2]*factor_lj;
if (newton_pair || j < nlocal) {
tor[j][0] += rtor[0]*factor_lj;
tor[j][1] += rtor[1]*factor_lj;
tor[j][2] += rtor[2]*factor_lj;
}
break;
}
fforce[0] *= factor_lj;
fforce[1] *= factor_lj;
fforce[2] *= factor_lj;
f[i][0] += fforce[0];
f[i][1] += fforce[1];
f[i][2] += fforce[2];
if (newton_pair || j < nlocal) {
f[j][0] -= fforce[0];
f[j][1] -= fforce[1];
f[j][2] -= fforce[2];
}
if (eflag) evdwl = factor_lj*one_eng;
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
evdwl,0.0,fforce[0],fforce[1],fforce[2],
-r12[0],-r12[1],-r12[2]);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairRESquared::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(form,n+1,n+1,"pair:form");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(shape1,n+1,3,"pair:shape1");
memory->create(shape2,n+1,3,"pair:shape2");
memory->create(well,n+1,3,"pair:well");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
lshape = new double[n+1];
setwell = new int[n+1];
for (int i = 1; i <= n; i++) setwell[i] = 0;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairRESquared::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairRESquared::coeff(int narg, char **arg)
{
if (narg < 10 || narg > 11)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double eia_one = force->numeric(FLERR,arg[4]);
double eib_one = force->numeric(FLERR,arg[5]);
double eic_one = force->numeric(FLERR,arg[6]);
double eja_one = force->numeric(FLERR,arg[7]);
double ejb_one = force->numeric(FLERR,arg[8]);
double ejc_one = force->numeric(FLERR,arg[9]);
double cut_one = cut_global;
if (narg == 11) cut_one = force->numeric(FLERR,arg[10]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
if (eia_one != 0.0 || eib_one != 0.0 || eic_one != 0.0) {
well[i][0] = eia_one;
well[i][1] = eib_one;
well[i][2] = eic_one;
if (eia_one == 1.0 && eib_one == 1.0 && eic_one == 1.0) setwell[i] = 2;
else setwell[i] = 1;
}
if (eja_one != 0.0 || ejb_one != 0.0 || ejc_one != 0.0) {
well[j][0] = eja_one;
well[j][1] = ejb_one;
well[j][2] = ejc_one;
if (eja_one == 1.0 && ejb_one == 1.0 && ejc_one == 1.0) setwell[j] = 2;
else setwell[j] = 1;
}
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairRESquared::init_style()
{
avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
if (!avec) error->all(FLERR,"Pair resquared requires atom style ellipsoid");
neighbor->request(this,instance_me);
// per-type shape precalculations
// require that atom shapes are identical within each type
for (int i = 1; i <= atom->ntypes; i++) {
if (!atom->shape_consistency(i,shape1[i][0],shape1[i][1],shape1[i][2]))
error->all(FLERR,"Pair resquared requires atoms with same type have same shape");
if (setwell[i]) {
shape2[i][0] = shape1[i][0]*shape1[i][0];
shape2[i][1] = shape1[i][1]*shape1[i][1];
shape2[i][2] = shape1[i][2]*shape1[i][2];
lshape[i] = shape1[i][0]*shape1[i][1]*shape1[i][2];
}
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairRESquared::init_one(int i, int j)
{
if (setwell[i] == 0 || setwell[j] == 0)
error->all(FLERR,"Pair resquared epsilon a,b,c coeffs are not all set");
int ishape = 0;
if (shape1[i][0] != 0.0 && shape1[i][1] != 0.0 && shape1[i][2] != 0.0)
ishape = 1;
int jshape = 0;
if (shape1[j][0] != 0.0 && shape1[j][1] != 0.0 && shape1[j][2] != 0.0)
jshape = 1;
if (ishape == 0 && jshape == 0) {
form[i][j] = SPHERE_SPHERE;
form[j][i] = SPHERE_SPHERE;
} else if (ishape == 0) {
form[i][j] = SPHERE_ELLIPSE;
form[j][i] = ELLIPSE_SPHERE;
} else if (jshape == 0) {
form[i][j] = ELLIPSE_SPHERE;
form[j][i] = SPHERE_ELLIPSE;
} else {
form[i][j] = ELLIPSE_ELLIPSE;
form[j][i] = ELLIPSE_ELLIPSE;
}
// allow mixing only for LJ spheres
if (setflag[i][j] == 0) {
if (setflag[j][i] == 0) {
if (ishape == 0 && jshape == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
} else
error->all(FLERR,
"Pair resquared epsilon and sigma coeffs are not all set");
}
epsilon[i][j] = epsilon[j][i];
sigma[i][j] = sigma[j][i];
cut[i][j] = cut[j][i];
}
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairRESquared::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++) {
fwrite(&setwell[i],sizeof(int),1,fp);
if (setwell[i]) fwrite(&well[i][0],sizeof(double),3,fp);
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairRESquared::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++) {
if (me == 0) fread(&setwell[i],sizeof(int),1,fp);
MPI_Bcast(&setwell[i],1,MPI_INT,0,world);
if (setwell[i]) {
if (me == 0) fread(&well[i][0],sizeof(double),3,fp);
MPI_Bcast(&well[i][0],3,MPI_DOUBLE,0,world);
}
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairRESquared::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairRESquared::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
Precompute per-particle temporaries for RE-squared calculation
------------------------------------------------------------------------- */
void PairRESquared::precompute_i(const int i,RE2Vars &ws)
{
double aTs[3][3]; // A1'*S1^2
int *ellipsoid = atom->ellipsoid;
AtomVecEllipsoid::Bonus *bonus = avec->bonus;
MathExtra::quat_to_mat_trans(bonus[ellipsoid[i]].quat,ws.A);
MathExtra::transpose_diag3(ws.A,well[atom->type[i]],ws.aTe);
MathExtra::transpose_diag3(ws.A,shape2[atom->type[i]],aTs);
MathExtra::diag_times3(shape2[atom->type[i]],ws.A,ws.sa);
MathExtra::times3(aTs,ws.A,ws.gamma);
MathExtra::rotation_generator_x(ws.A,ws.lA[0]);
MathExtra::rotation_generator_y(ws.A,ws.lA[1]);
MathExtra::rotation_generator_z(ws.A,ws.lA[2]);
for (int i=0; i<3; i++) {
MathExtra::times3(aTs,ws.lA[i],ws.lAtwo[i]);
MathExtra::transpose_times3(ws.lA[i],ws.sa,ws.lAsa[i]);
MathExtra::plus3(ws.lAsa[i],ws.lAtwo[i],ws.lAsa[i]);
}
}
/* ----------------------------------------------------------------------
Compute the derivative of the determinant of m, using m and the
derivative of m (m2)
------------------------------------------------------------------------- */
double PairRESquared::det_prime(const double m[3][3], const double m2[3][3])
{
double ans;
ans = m2[0][0]*m[1][1]*m[2][2] - m2[0][0]*m[1][2]*m[2][1] -
m[1][0]*m2[0][1]*m[2][2] + m[1][0]*m2[0][2]*m[2][1] +
m[2][0]*m2[0][1]*m[1][2] - m[2][0]*m2[0][2]*m[1][1] +
m[0][0]*m2[1][1]*m[2][2] - m[0][0]*m2[1][2]*m[2][1] -
m2[1][0]*m[0][1]*m[2][2] + m2[1][0]*m[0][2]*m[2][1] +
m[2][0]*m[0][1]*m2[1][2] - m[2][0]*m[0][2]*m2[1][1] +
m[0][0]*m[1][1]*m2[2][2] - m[0][0]*m[1][2]*m2[2][1] -
m[1][0]*m[0][1]*m2[2][2] + m[1][0]*m[0][2]*m2[2][1] +
m2[2][0]*m[0][1]*m[1][2] - m2[2][0]*m[0][2]*m[1][1];
return ans;
}
/* ----------------------------------------------------------------------
Compute the energy, force, torque for a pair (INTEGRATED-INTEGRATED)
------------------------------------------------------------------------- */
double PairRESquared::resquared_analytic(const int i, const int j,
const RE2Vars &wi, const RE2Vars &wj,
const double *r, const double rsq,
double *fforce, double *ttor,
double *rtor)
{
int *type = atom->type;
// pair computations for energy, force, torque
double z1[3],z2[3]; // A1*rhat # don't need to store
double v1[3],v2[3]; // inv(S1^2)*z1 # don't need to store
double sigma1,sigma2; // 1/sqrt(z1'*v1)
double sigma1p2,sigma2p2; // sigma1^2
double rnorm; // L2 norm of r
double rhat[3]; // r/rnorm
double s[3]; // inv(gamma1+gamma2)*rhat
double sigma12; // 1/sqrt(0.5*s'*rhat)
double H12[3][3]; // gamma1/sigma1+gamma2/sigma2
double dH; // det(H12)
double lambda; // dS1/sigma1p2+dS2/sigma2p2
double nu; // sqrt(dH/(sigma1+sigma2))
double w[3]; // inv(A1'*E1*A1+A2'*E2*A2)*rhat
double h12; // rnorm-sigma12;
double eta; // lambda/nu
double chi; // 2*rhat'*w
double sprod; // dS1*dS2
double sigh; // sigma/h12
double tprod; // eta*chi*sigh
double Ua,Ur; // attractive/repulsive parts of potential
// pair computations for force, torque
double sec; // sigma*eta*chi
double sigma1p3, sigma2p3; // sigma1^3
double vsigma1[3], vsigma2[3]; // sigma1^3*v1;
double sigma12p3; // sigma12^3
double gsigma1[3][3], gsigma2[3][3]; // -gamma1/sigma1^2
double tsig1sig2; // eta/(2*(sigma1+sigma2))
double tdH; // eta/(2*dH)
double teta1,teta2; // 2*eta/lambda*dS1/sigma1p3
double fourw[3]; // 4*w;
double spr[3]; // 0.5*sigma12^3*s
double hsec; // h12+[3,b_alpha]*sec
double dspu; // 1/h12 - 1/hsec + temp
double pbsu; // 3*sigma/hsec
double dspr; // 7/h12-1/hsec+temp
double pbsr; // b_alpha*sigma/hsec;
double u[3]; // (-rhat(i)*rhat+eye(:,i))/rnorm
double u1[3],u2[3]; // A1*u
double dsigma1,dsigma2; // u1'*vsigma1 (force) p'*vsigma1 (tor)
double dH12[3][3]; // dsigma1*gsigma1 + dsigma2*gsigma2
double ddH; // derivative of det(H12)
double deta,dchi,dh12; // derivatives of eta,chi,h12
double dUr,dUa; // derivatives of Ua,Ur
// pair computations for torque
double fwae[3]; // -fourw'*aTe
double p[3]; // lA*rhat
rnorm = sqrt(rsq);
rhat[0] = r[0]/rnorm;
rhat[1] = r[1]/rnorm;
rhat[2] = r[2]/rnorm;
// energy
double temp[3][3];
MathExtra::plus3(wi.gamma,wj.gamma,temp);
int ierror = MathExtra::mldivide3(temp,rhat,s);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
sigma12 = 1.0/sqrt(0.5*MathExtra::dot3(s,rhat));
MathExtra::matvec(wi.A,rhat,z1);
MathExtra::matvec(wj.A,rhat,z2);
v1[0] = z1[0]/shape2[type[i]][0];
v1[1] = z1[1]/shape2[type[i]][1];
v1[2] = z1[2]/shape2[type[i]][2];
v2[0] = z2[0]/shape2[type[j]][0];
v2[1] = z2[1]/shape2[type[j]][1];
v2[2] = z2[2]/shape2[type[j]][2];
sigma1 = 1.0/sqrt(MathExtra::dot3(z1,v1));
sigma2 = 1.0/sqrt(MathExtra::dot3(z2,v2));
H12[0][0] = wi.gamma[0][0]/sigma1+wj.gamma[0][0]/sigma2;
H12[0][1] = wi.gamma[0][1]/sigma1+wj.gamma[0][1]/sigma2;
H12[0][2] = wi.gamma[0][2]/sigma1+wj.gamma[0][2]/sigma2;
H12[1][0] = wi.gamma[1][0]/sigma1+wj.gamma[1][0]/sigma2;
H12[1][1] = wi.gamma[1][1]/sigma1+wj.gamma[1][1]/sigma2;
H12[1][2] = wi.gamma[1][2]/sigma1+wj.gamma[1][2]/sigma2;
H12[2][0] = wi.gamma[2][0]/sigma1+wj.gamma[2][0]/sigma2;
H12[2][1] = wi.gamma[2][1]/sigma1+wj.gamma[2][1]/sigma2;
H12[2][2] = wi.gamma[2][2]/sigma1+wj.gamma[2][2]/sigma2;
dH=MathExtra::det3(H12);
sigma1p2 = sigma1*sigma1;
sigma2p2 = sigma2*sigma2;
lambda = lshape[type[i]]/sigma1p2 + lshape[type[j]]/sigma2p2;
nu = sqrt(dH/(sigma1+sigma2));
MathExtra::times3(wi.aTe,wi.A,temp);
double temp2[3][3];
MathExtra::times3(wj.aTe,wj.A,temp2);
MathExtra::plus3(temp,temp2,temp);
ierror = MathExtra::mldivide3(temp,rhat,w);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
h12 = rnorm-sigma12;
eta = lambda/nu;
chi = 2.0*MathExtra::dot3(rhat,w);
sprod = lshape[type[i]] * lshape[type[j]];
sigh = sigma[type[i]][type[j]]/h12;
tprod = eta*chi*sigh;
double stemp = h12/2.0;
Ua = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)*
(shape1[type[i]][2]+stemp)*(shape1[type[j]][0]+stemp)*
(shape1[type[j]][1]+stemp)*(shape1[type[j]][2]+stemp);
Ua = (1.0+3.0*tprod)*sprod/Ua;
Ua = epsilon[type[i]][type[j]]*Ua/-36.0;
stemp = h12/cr60;
Ur = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)*
(shape1[type[i]][2]+stemp)*(shape1[type[j]][0]+stemp)*
(shape1[type[j]][1]+stemp)*(shape1[type[j]][2]+stemp);
Ur = (1.0+b_alpha*tprod)*sprod/Ur;
Ur = epsilon[type[i]][type[j]]*Ur*pow(sigh,6.0)/2025.0;
// force
sec = sigma[type[i]][type[j]]*eta*chi;
sigma12p3 = pow(sigma12,3.0);
sigma1p3 = sigma1p2*sigma1;
sigma2p3 = sigma2p2*sigma2;
vsigma1[0] = -sigma1p3*v1[0];
vsigma1[1] = -sigma1p3*v1[1];
vsigma1[2] = -sigma1p3*v1[2];
vsigma2[0] = -sigma2p3*v2[0];
vsigma2[1] = -sigma2p3*v2[1];
vsigma2[2] = -sigma2p3*v2[2];
gsigma1[0][0] = -wi.gamma[0][0]/sigma1p2;
gsigma1[0][1] = -wi.gamma[0][1]/sigma1p2;
gsigma1[0][2] = -wi.gamma[0][2]/sigma1p2;
gsigma1[1][0] = -wi.gamma[1][0]/sigma1p2;
gsigma1[1][1] = -wi.gamma[1][1]/sigma1p2;
gsigma1[1][2] = -wi.gamma[1][2]/sigma1p2;
gsigma1[2][0] = -wi.gamma[2][0]/sigma1p2;
gsigma1[2][1] = -wi.gamma[2][1]/sigma1p2;
gsigma1[2][2] = -wi.gamma[2][2]/sigma1p2;
gsigma2[0][0] = -wj.gamma[0][0]/sigma2p2;
gsigma2[0][1] = -wj.gamma[0][1]/sigma2p2;
gsigma2[0][2] = -wj.gamma[0][2]/sigma2p2;
gsigma2[1][0] = -wj.gamma[1][0]/sigma2p2;
gsigma2[1][1] = -wj.gamma[1][1]/sigma2p2;
gsigma2[1][2] = -wj.gamma[1][2]/sigma2p2;
gsigma2[2][0] = -wj.gamma[2][0]/sigma2p2;
gsigma2[2][1] = -wj.gamma[2][1]/sigma2p2;
gsigma2[2][2] = -wj.gamma[2][2]/sigma2p2;
tsig1sig2 = eta/(2.0*(sigma1+sigma2));
tdH = eta/(2.0*dH);
teta1 = 2.0*eta/lambda;
teta2 = teta1*lshape[type[j]]/sigma2p3;
teta1 = teta1*lshape[type[i]]/sigma1p3;
fourw[0] = 4.0*w[0];
fourw[1] = 4.0*w[1];
fourw[2] = 4.0*w[2];
spr[0] = 0.5*sigma12p3*s[0];
spr[1] = 0.5*sigma12p3*s[1];
spr[2] = 0.5*sigma12p3*s[2];
stemp = 1.0/(shape1[type[i]][0]*2.0+h12)+
1.0/(shape1[type[i]][1]*2.0+h12)+
1.0/(shape1[type[i]][2]*2.0+h12)+
1.0/(shape1[type[j]][0]*2.0+h12)+
1.0/(shape1[type[j]][1]*2.0+h12)+
1.0/(shape1[type[j]][2]*2.0+h12);
hsec = h12+3.0*sec;
dspu = 1.0/h12-1.0/hsec+stemp;
pbsu = 3.0*sigma[type[i]][type[j]]/hsec;
stemp = 1.0/(shape1[type[i]][0]*cr60+h12)+
1.0/(shape1[type[i]][1]*cr60+h12)+
1.0/(shape1[type[i]][2]*cr60+h12)+
1.0/(shape1[type[j]][0]*cr60+h12)+
1.0/(shape1[type[j]][1]*cr60+h12)+
1.0/(shape1[type[j]][2]*cr60+h12);
hsec = h12+b_alpha*sec;
dspr = 7.0/h12-1.0/hsec+stemp;
pbsr = b_alpha*sigma[type[i]][type[j]]/hsec;
for (int i=0; i<3; i++) {
u[0] = -rhat[i]*rhat[0];
u[1] = -rhat[i]*rhat[1];
u[2] = -rhat[i]*rhat[2];
u[i] += 1.0;
u[0] /= rnorm;
u[1] /= rnorm;
u[2] /= rnorm;
MathExtra::matvec(wi.A,u,u1);
MathExtra::matvec(wj.A,u,u2);
dsigma1=MathExtra::dot3(u1,vsigma1);
dsigma2=MathExtra::dot3(u2,vsigma2);
dH12[0][0] = dsigma1*gsigma1[0][0]+dsigma2*gsigma2[0][0];
dH12[0][1] = dsigma1*gsigma1[0][1]+dsigma2*gsigma2[0][1];
dH12[0][2] = dsigma1*gsigma1[0][2]+dsigma2*gsigma2[0][2];
dH12[1][0] = dsigma1*gsigma1[1][0]+dsigma2*gsigma2[1][0];
dH12[1][1] = dsigma1*gsigma1[1][1]+dsigma2*gsigma2[1][1];
dH12[1][2] = dsigma1*gsigma1[1][2]+dsigma2*gsigma2[1][2];
dH12[2][0] = dsigma1*gsigma1[2][0]+dsigma2*gsigma2[2][0];
dH12[2][1] = dsigma1*gsigma1[2][1]+dsigma2*gsigma2[2][1];
dH12[2][2] = dsigma1*gsigma1[2][2]+dsigma2*gsigma2[2][2];
ddH = det_prime(H12,dH12);
deta = (dsigma1+dsigma2)*tsig1sig2;
deta -= ddH*tdH;
deta -= dsigma1*teta1+dsigma2*teta2;
dchi = MathExtra::dot3(u,fourw);
dh12 = rhat[i]+MathExtra::dot3(u,spr);
dUa = pbsu*(eta*dchi+deta*chi)-dh12*dspu;
dUr = pbsr*(eta*dchi+deta*chi)-dh12*dspr;
fforce[i]=dUr*Ur+dUa*Ua;
}
// torque on i
MathExtra::vecmat(fourw,wi.aTe,fwae);
for (int i=0; i<3; i++) {
MathExtra::matvec(wi.lA[i],rhat,p);
dsigma1 = MathExtra::dot3(p,vsigma1);
dH12[0][0] = wi.lAsa[i][0][0]/sigma1+dsigma1*gsigma1[0][0];
dH12[0][1] = wi.lAsa[i][0][1]/sigma1+dsigma1*gsigma1[0][1];
dH12[0][2] = wi.lAsa[i][0][2]/sigma1+dsigma1*gsigma1[0][2];
dH12[1][0] = wi.lAsa[i][1][0]/sigma1+dsigma1*gsigma1[1][0];
dH12[1][1] = wi.lAsa[i][1][1]/sigma1+dsigma1*gsigma1[1][1];
dH12[1][2] = wi.lAsa[i][1][2]/sigma1+dsigma1*gsigma1[1][2];
dH12[2][0] = wi.lAsa[i][2][0]/sigma1+dsigma1*gsigma1[2][0];
dH12[2][1] = wi.lAsa[i][2][1]/sigma1+dsigma1*gsigma1[2][1];
dH12[2][2] = wi.lAsa[i][2][2]/sigma1+dsigma1*gsigma1[2][2];
ddH = det_prime(H12,dH12);
deta = tsig1sig2*dsigma1-tdH*ddH;
deta -= teta1*dsigma1;
double tempv[3];
MathExtra::matvec(wi.lA[i],w,tempv);
dchi = -MathExtra::dot3(fwae,tempv);
MathExtra::matvec(wi.lAtwo[i],spr,tempv);
dh12 = -MathExtra::dot3(s,tempv);
dUa = pbsu*(eta*dchi + deta*chi)-dh12*dspu;
dUr = pbsr*(eta*dchi + deta*chi)-dh12*dspr;
ttor[i] = -(dUa*Ua+dUr*Ur);
}
// torque on j
if (!(force->newton_pair || j < atom->nlocal))
return Ua+Ur;
MathExtra::vecmat(fourw,wj.aTe,fwae);
for (int i=0; i<3; i++) {
MathExtra::matvec(wj.lA[i],rhat,p);
dsigma2 = MathExtra::dot3(p,vsigma2);
dH12[0][0] = wj.lAsa[i][0][0]/sigma2+dsigma2*gsigma2[0][0];
dH12[0][1] = wj.lAsa[i][0][1]/sigma2+dsigma2*gsigma2[0][1];
dH12[0][2] = wj.lAsa[i][0][2]/sigma2+dsigma2*gsigma2[0][2];
dH12[1][0] = wj.lAsa[i][1][0]/sigma2+dsigma2*gsigma2[1][0];
dH12[1][1] = wj.lAsa[i][1][1]/sigma2+dsigma2*gsigma2[1][1];
dH12[1][2] = wj.lAsa[i][1][2]/sigma2+dsigma2*gsigma2[1][2];
dH12[2][0] = wj.lAsa[i][2][0]/sigma2+dsigma2*gsigma2[2][0];
dH12[2][1] = wj.lAsa[i][2][1]/sigma2+dsigma2*gsigma2[2][1];
dH12[2][2] = wj.lAsa[i][2][2]/sigma2+dsigma2*gsigma2[2][2];
ddH = det_prime(H12,dH12);
deta = tsig1sig2*dsigma2-tdH*ddH;
deta -= teta2*dsigma2;
double tempv[3];
MathExtra::matvec(wj.lA[i],w,tempv);
dchi = -MathExtra::dot3(fwae,tempv);
MathExtra::matvec(wj.lAtwo[i],spr,tempv);
dh12 = -MathExtra::dot3(s,tempv);
dUa = pbsu*(eta*dchi + deta*chi)-dh12*dspu;
dUr = pbsr*(eta*dchi + deta*chi)-dh12*dspr;
rtor[i] = -(dUa*Ua+dUr*Ur);
}
return Ua+Ur;
}
/* ----------------------------------------------------------------------
Compute the energy, force, torque for a pair (INTEGRATED-LJ)
------------------------------------------------------------------------- */
double PairRESquared::resquared_lj(const int i, const int j,
const RE2Vars &wi, const double *r,
const double rsq, double *fforce,
double *ttor, bool calc_torque)
{
int *type = atom->type;
// pair computations for energy, force, torque
double rnorm; // L2 norm of r
double rhat[3]; // r/rnorm
double s[3]; // inv(gamma1)*rhat
double sigma12; // 1/sqrt(0.5*s'*rhat)
double w[3]; // inv(A1'*E1*A1+I)*rhat
double h12; // rnorm-sigma12;
double chi; // 2*rhat'*w
double sigh; // sigma/h12
double tprod; // chi*sigh
double Ua,Ur; // attractive/repulsive parts of potential
// pair computations for force, torque
double sec; // sigma*chi
double sigma12p3; // sigma12^3
double fourw[3]; // 4*w;
double spr[3]; // 0.5*sigma12^3*s
double hsec; // h12+[3,b_alpha]*sec
double dspu; // 1/h12 - 1/hsec + temp
double pbsu; // 3*sigma/hsec
double dspr; // 7/h12-1/hsec+temp
double pbsr; // b_alpha*sigma/hsec;
double u[3]; // (-rhat(i)*rhat+eye(:,i))/rnorm
double dchi,dh12; // derivatives of chi,h12
double dUr,dUa; // derivatives of Ua,Ur
double h12p3; // h12^3
// pair computations for torque
double fwae[3]; // -fourw'*aTe
double p[3]; // lA*rhat
// distance of closest approach correction
double aTs[3][3]; // A1'*S1^2
double gamma[3][3]; // A1'*S1^2*A
double lAtwo[3][3][3]; // A1'*S1^2*wi.lA
double scorrect[3];
double half_sigma=sigma[type[i]][type[j]] / 2.0;
scorrect[0] = shape1[type[i]][0]+half_sigma;
scorrect[1] = shape1[type[i]][1]+half_sigma;
scorrect[2] = shape1[type[i]][2]+half_sigma;
scorrect[0] = scorrect[0] * scorrect[0] / 2.0;
scorrect[1] = scorrect[1] * scorrect[1] / 2.0;
scorrect[2] = scorrect[2] * scorrect[2] / 2.0;
MathExtra::transpose_diag3(wi.A,scorrect,aTs);
MathExtra::times3(aTs,wi.A,gamma);
for (int ii=0; ii<3; ii++)
MathExtra::times3(aTs,wi.lA[ii],lAtwo[ii]);
rnorm=sqrt(rsq);
rhat[0] = r[0]/rnorm;
rhat[1] = r[1]/rnorm;
rhat[2] = r[2]/rnorm;
// energy
int ierror = MathExtra::mldivide3(gamma,rhat,s);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
sigma12 = 1.0/sqrt(0.5*MathExtra::dot3(s,rhat));
double temp[3][3];
MathExtra::times3(wi.aTe,wi.A,temp);
temp[0][0] += 1.0;
temp[1][1] += 1.0;
temp[2][2] += 1.0;
ierror = MathExtra::mldivide3(temp,rhat,w);
if (ierror) error->all(FLERR,"Bad matrix inversion in mldivide3");
h12 = rnorm-sigma12;
chi = 2.0*MathExtra::dot3(rhat,w);
sigh = sigma[type[i]][type[j]]/h12;
tprod = chi*sigh;
h12p3 = pow(h12,3.0);
double sigmap3 = pow(sigma[type[i]][type[j]],3.0);
double stemp = h12/2.0;
Ua = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)*
(shape1[type[i]][2]+stemp)*h12p3/8.0;
Ua = (1.0+3.0*tprod)*lshape[type[i]]/Ua;
Ua = epsilon[type[i]][type[j]]*Ua*sigmap3*solv_f_a;
stemp = h12/cr60;
Ur = (shape1[type[i]][0]+stemp)*(shape1[type[i]][1]+stemp)*
(shape1[type[i]][2]+stemp)*h12p3/60.0;
Ur = (1.0+b_alpha*tprod)*lshape[type[i]]/Ur;
Ur = epsilon[type[i]][type[j]]*Ur*sigmap3*pow(sigh,6.0)*solv_f_r;
// force
sec = sigma[type[i]][type[j]]*chi;
sigma12p3 = pow(sigma12,3.0);
fourw[0] = 4.0*w[0];
fourw[1] = 4.0*w[1];
fourw[2] = 4.0*w[2];
spr[0] = 0.5*sigma12p3*s[0];
spr[1] = 0.5*sigma12p3*s[1];
spr[2] = 0.5*sigma12p3*s[2];
stemp = 1.0/(shape1[type[i]][0]*2.0+h12)+
1.0/(shape1[type[i]][1]*2.0+h12)+
1.0/(shape1[type[i]][2]*2.0+h12)+
3.0/h12;
hsec = h12+3.0*sec;
dspu = 1.0/h12-1.0/hsec+stemp;
pbsu = 3.0*sigma[type[i]][type[j]]/hsec;
stemp = 1.0/(shape1[type[i]][0]*cr60+h12)+
1.0/(shape1[type[i]][1]*cr60+h12)+
1.0/(shape1[type[i]][2]*cr60+h12)+
3.0/h12;
hsec = h12+b_alpha*sec;
dspr = 7.0/h12-1.0/hsec+stemp;
pbsr = b_alpha*sigma[type[i]][type[j]]/hsec;
for (int i=0; i<3; i++) {
u[0] = -rhat[i]*rhat[0];
u[1] = -rhat[i]*rhat[1];
u[2] = -rhat[i]*rhat[2];
u[i] += 1.0;
u[0] /= rnorm;
u[1] /= rnorm;
u[2] /= rnorm;
dchi = MathExtra::dot3(u,fourw);
dh12 = rhat[i]+MathExtra::dot3(u,spr);
dUa = pbsu*dchi-dh12*dspu;
dUr = pbsr*dchi-dh12*dspr;
fforce[i]=dUr*Ur+dUa*Ua;
}
// torque on i
if (calc_torque) {
MathExtra::vecmat(fourw,wi.aTe,fwae);
for (int i=0; i<3; i++) {
MathExtra::matvec(wi.lA[i],rhat,p);
double tempv[3];
MathExtra::matvec(wi.lA[i],w,tempv);
dchi = -MathExtra::dot3(fwae,tempv);
MathExtra::matvec(lAtwo[i],spr,tempv);
dh12 = -MathExtra::dot3(s,tempv);
dUa = pbsu*dchi-dh12*dspu;
dUr = pbsr*dchi-dh12*dspr;
ttor[i] = -(dUa*Ua+dUr*Ur);
}
}
return Ua+Ur;
}
diff --git a/src/CLASS2/pair_lj_class2.cpp b/src/CLASS2/pair_lj_class2.cpp
index e79dc0c6d..0b90b2717 100644
--- a/src/CLASS2/pair_lj_class2.cpp
+++ b/src/CLASS2/pair_lj_class2.cpp
@@ -1,396 +1,396 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "pair_lj_class2.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJClass2::PairLJClass2(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJClass2::~PairLJClass2()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJClass2::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,rinv,r2inv,r3inv,r6inv,forcelj,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJClass2::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJClass2::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJClass2::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_one = cut_global;
if (narg == 5) cut_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJClass2::init_one(int i, int j)
{
// always mix epsilon,sigma via sixthpower rules
// mix distance via user-defined rule
if (setflag[i][j] == 0) {
epsilon[i][j] = 2.0 * sqrt(epsilon[i][i]*epsilon[j][j]) *
pow(sigma[i][i],3.0) * pow(sigma[j][j],3.0) /
(pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0));
sigma[i][j] =
pow((0.5 * (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0))),1.0/6.0);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
lj1[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj2[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0));
} else offset[i][j] = 0.0;
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j];
double sig6 = sig3*sig3;
double rc3 = cut[i][j]*cut[i][j]*cut[i][j];
double rc6 = rc3*rc3;
etail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 3.0*rc3) / (3.0*rc6);
ptail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 2.0*rc3) / rc6;
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJClass2::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJClass2::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJClass2::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,rinv,r3inv,r6inv,forcelj,philj;
r2inv = 1.0/rsq;
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fforce = factor_lj*forcelj*r2inv;
philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
return factor_lj*philj;
}
diff --git a/src/CLASS2/pair_lj_class2_coul_cut.cpp b/src/CLASS2/pair_lj_class2_coul_cut.cpp
index bec7f1da1..395953e0a 100644
--- a/src/CLASS2/pair_lj_class2_coul_cut.cpp
+++ b/src/CLASS2/pair_lj_class2_coul_cut.cpp
@@ -1,468 +1,468 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "pair_lj_class2_coul_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJClass2CoulCut::PairLJClass2CoulCut(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJClass2CoulCut::~PairLJClass2CoulCut()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJClass2CoulCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,rinv,r2inv,r3inv,r6inv,forcecoul,forcelj;
double factor_coul,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype])
ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv);
else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]);
if (narg == 6) cut_coul_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/class2/coul/cut requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJClass2CoulCut::init_one(int i, int j)
{
// always mix epsilon,sigma via sixthpower rules
// mix distance via user-defined rule
if (setflag[i][j] == 0) {
epsilon[i][j] = 2.0 * sqrt(epsilon[i][i]*epsilon[j][j]) *
pow(sigma[i][i],3.0) * pow(sigma[j][j],3.0) /
(pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0));
sigma[i][j] =
pow((0.5 * (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0))),1.0/6.0);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
lj1[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj2[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j];
double sig6 = sig3*sig3;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
etail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 3.0*rc3) / (3.0*rc6);
ptail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 2.0*rc3) / rc6;
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJClass2CoulCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJClass2CoulCut::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,rinv,r3inv,r6inv,forcecoul,forcelj,phicoul,philj;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fforce = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
eng += factor_coul*phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
diff --git a/src/CLASS2/pair_lj_class2_coul_long.cpp b/src/CLASS2/pair_lj_class2_coul_long.cpp
index 5f7d738e9..5d2ae891d 100644
--- a/src/CLASS2/pair_lj_class2_coul_long.cpp
+++ b/src/CLASS2/pair_lj_class2_coul_long.cpp
@@ -1,552 +1,552 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_class2_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJClass2CoulLong::PairLJClass2CoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
writedata = 1;
ftable = NULL;
}
/* ---------------------------------------------------------------------- */
PairLJClass2CoulLong::~PairLJClass2CoulLong()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJClass2CoulLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itable,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double rsq,r,rinv,r2inv,r3inv,r6inv,forcecoul,forcelj;
double grij,expm2,prefactor,t,erfc;
double factor_coul,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,
"Pair style lj/class2/coul/long requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
// setup force tables
if (ncoultablebits) init_tables(cut_coul,NULL);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJClass2CoulLong::init_one(int i, int j)
{
// always mix epsilon,sigma via sixthpower rules
// mix distance via user-defined rule
if (setflag[i][j] == 0) {
epsilon[i][j] = 2.0 * sqrt(epsilon[i][i]*epsilon[j][j]) *
pow(sigma[i][i],3.0) * pow(sigma[j][j],3.0) /
(pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0));
sigma[i][j] =
pow((0.5 * (pow(sigma[i][i],6.0) + pow(sigma[j][j],6.0))),1.0/6.0);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj2[i][j] = 18.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j];
double sig6 = sig3*sig3;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
etail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 3.0*rc3) / (3.0*rc6);
ptail_ij = 2.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 2.0*rc3) / rc6;
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJClass2CoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJClass2CoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,rinv,r3inv,r6inv,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forcelj,phicoul,philj;
int itable;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
rinv = sqrt(r2inv);
r3inv = r2inv*rinv;
r6inv = r3inv*r3inv;
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fforce = (forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJClass2CoulLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
diff --git a/src/COLLOID/pair_colloid.cpp b/src/COLLOID/pair_colloid.cpp
index 68150f6ef..983b973e0 100644
--- a/src/COLLOID/pair_colloid.cpp
+++ b/src/COLLOID/pair_colloid.cpp
@@ -1,545 +1,545 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pieter in 't Veld (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_colloid.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_special.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathSpecial;
/* ---------------------------------------------------------------------- */
PairColloid::PairColloid(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairColloid::~PairColloid()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(form);
memory->destroy(a12);
memory->destroy(sigma);
memory->destroy(d1);
memory->destroy(d2);
memory->destroy(a1);
memory->destroy(a2);
memory->destroy(diameter);
memory->destroy(cut);
memory->destroy(offset);
memory->destroy(sigma3);
memory->destroy(sigma6);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
}
}
/* ---------------------------------------------------------------------- */
void PairColloid::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r,forcelj,factor_lj;
double r2inv,r6inv,c1,c2,fR,dUR,dUA;
double K[9],h[4],g[4];
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq >= cutsq[itype][jtype]) continue;
switch (form[itype][jtype]) {
case SMALL_SMALL:
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (eflag) evdwl = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) -
offset[itype][jtype];
break;
case SMALL_LARGE:
c2 = a2[itype][jtype];
K[1] = c2*c2;
K[2] = rsq;
K[0] = K[1] - rsq;
K[4] = rsq*rsq;
K[3] = K[1] - K[2];
K[3] *= K[3]*K[3];
K[6] = K[3]*K[3];
fR = sigma3[itype][jtype]*a12[itype][jtype]*c2*K[1]/K[3];
fpair = 4.0/15.0*fR*factor_lj *
(2.0*(K[1]+K[2]) * (K[1]*(5.0*K[1]+22.0*K[2])+5.0*K[4]) *
sigma6[itype][jtype]/K[6]-5.0) / K[0];
if (eflag)
evdwl = 2.0/9.0*fR *
(1.0-(K[1]*(K[1]*(K[1]/3.0+3.0*K[2])+4.2*K[4])+K[2]*K[4]) *
sigma6[itype][jtype]/K[6]) - offset[itype][jtype];
if (rsq <= K[1])
error->one(FLERR,"Overlapping small/large in pair colloid");
break;
case LARGE_LARGE:
r = sqrt(rsq);
c1 = a1[itype][jtype];
c2 = a2[itype][jtype];
K[0] = c1*c2;
K[1] = c1+c2;
K[2] = c1-c2;
K[3] = K[1]+r;
K[4] = K[1]-r;
K[5] = K[2]+r;
K[6] = K[2]-r;
K[7] = 1.0/(K[3]*K[4]);
K[8] = 1.0/(K[5]*K[6]);
g[0] = powint(K[3],-7);
g[1] = powint(K[4],-7);
g[2] = powint(K[5],-7);
g[3] = powint(K[6],-7);
h[0] = ((K[3]+5.0*K[1])*K[3]+30.0*K[0])*g[0];
h[1] = ((K[4]+5.0*K[1])*K[4]+30.0*K[0])*g[1];
h[2] = ((K[5]+5.0*K[2])*K[5]-30.0*K[0])*g[2];
h[3] = ((K[6]+5.0*K[2])*K[6]-30.0*K[0])*g[3];
g[0] *= 42.0*K[0]/K[3]+6.0*K[1]+K[3];
g[1] *= 42.0*K[0]/K[4]+6.0*K[1]+K[4];
g[2] *= -42.0*K[0]/K[5]+6.0*K[2]+K[5];
g[3] *= -42.0*K[0]/K[6]+6.0*K[2]+K[6];
fR = a12[itype][jtype]*sigma6[itype][jtype]/r/37800.0;
evdwl = fR * (h[0]-h[1]-h[2]+h[3]);
dUR = evdwl/r + 5.0*fR*(g[0]+g[1]-g[2]-g[3]);
dUA = -a12[itype][jtype]/3.0*r*((2.0*K[0]*K[7]+1.0)*K[7] +
(2.0*K[0]*K[8]-1.0)*K[8]);
fpair = factor_lj * (dUR+dUA)/r;
if (eflag)
evdwl += a12[itype][jtype]/6.0 *
(2.0*K[0]*(K[7]+K[8])-log(K[8]/K[7])) - offset[itype][jtype];
if (r <= K[1])
error->one(FLERR,"Overlapping large/large in pair colloid");
break;
}
if (eflag) evdwl *= factor_lj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairColloid::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(form,n+1,n+1,"pair:form");
memory->create(a12,n+1,n+1,"pair:a12");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(d1,n+1,n+1,"pair:d1");
memory->create(d2,n+1,n+1,"pair:d2");
memory->create(a1,n+1,n+1,"pair:a1");
memory->create(a2,n+1,n+1,"pair:a2");
memory->create(diameter,n+1,n+1,"pair:diameter");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(offset,n+1,n+1,"pair:offset");
memory->create(sigma3,n+1,n+1,"pair:sigma3");
memory->create(sigma6,n+1,n+1,"pair:sigma6");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairColloid::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairColloid::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a12_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double d1_one = force->numeric(FLERR,arg[4]);
double d2_one = force->numeric(FLERR,arg[5]);
double cut_one = cut_global;
if (narg == 7) cut_one = force->numeric(FLERR,arg[6]);
if (d1_one < 0.0 || d2_one < 0.0)
error->all(FLERR,"Invalid d1 or d2 value for pair colloid coeff");
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a12[i][j] = a12_one;
sigma[i][j] = sigma_one;
if (i == j && d1_one != d2_one)
error->all(FLERR,"Invalid d1 or d2 value for pair colloid coeff");
d1[i][j] = d1_one;
d2[i][j] = d2_one;
diameter[i][j] = 0.5*(d1_one+d2_one);
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairColloid::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
a12[i][j] = mix_energy(a12[i][i],a12[j][j],sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
d1[i][j] = mix_distance(d1[i][i],d1[j][j]);
d2[i][j] = mix_distance(d2[i][i],d2[j][j]);
diameter[i][j] = 0.5 * (d1[i][j] + d2[i][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
sigma3[i][j] = sigma[i][j]*sigma[i][j]*sigma[i][j];
sigma6[i][j] = sigma3[i][j]*sigma3[i][j];
if (d1[i][j] == 0.0 && d2[i][j] == 0.0) form[i][j] = SMALL_SMALL;
else if (d1[i][j] == 0.0 || d2[i][j] == 0.0) form[i][j] = SMALL_LARGE;
else form[i][j] = LARGE_LARGE;
// for SMALL_SMALL, a1/a2 do not need to be set
// for SMALL_LARGE, a1 does not need to be set, a2 = radius for i,j and j,i
// for LARGE_LARGE, a1/a2 are radii, swap them for j,i
if (form[i][j] == SMALL_LARGE) {
if (d1[i][j] > 0.0) a2[i][j] = 0.5*d1[i][j];
else a2[i][j] = 0.5*d2[i][j];
a2[j][i] = a2[i][j];
} else if (form[i][j] == LARGE_LARGE) {
a2[j][i] = a1[i][j] = 0.5*d1[i][j];
a1[j][i] = a2[i][j] = 0.5*d2[i][j];
}
form[j][i] = form[i][j];
a12[j][i] = a12[i][j];
sigma[j][i] = sigma[i][j];
sigma3[j][i] = sigma3[i][j];
sigma6[j][i] = sigma6[i][j];
diameter[j][i] = diameter[i][j];
double epsilon = a12[i][j]/144.0;
lj1[j][i] = lj1[i][j] = 48.0 * epsilon * sigma6[i][j] * sigma6[i][j];
lj2[j][i] = lj2[i][j] = 24.0 * epsilon * sigma6[i][j];
lj3[j][i] = lj3[i][j] = 4.0 * epsilon * sigma6[i][j] * sigma6[i][j];
lj4[j][i] = lj4[i][j] = 4.0 * epsilon * sigma6[i][j];
offset[j][i] = offset[i][j] = 0.0;
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double tmp;
offset[j][i] = offset[i][j] =
single(0,0,i,j,cut[i][j]*cut[i][j],0.0,1.0,tmp);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairColloid::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a12[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&d1[i][j],sizeof(double),1,fp);
fwrite(&d2[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairColloid::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (comm->me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (comm->me == 0) {
fread(&a12[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&d1[i][j],sizeof(double),1,fp);
fread(&d2[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a12[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d1[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d2[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairColloid::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairColloid::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairColloid::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,a12[i][i],sigma[i][i],d1[i][i],d2[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairColloid::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %g %g %g %g %g\n",i,
a12[i][j],sigma[i][j],d1[i][j],d2[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairColloid::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double K[9],h[4],g[4];
double r,r2inv,r6inv,forcelj,c1,c2,phi,fR,dUR,dUA;
switch (form[itype][jtype]) {
case SMALL_SMALL:
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fforce = factor_lj*forcelj*r2inv;
phi = r6inv*(r6inv*lj3[itype][jtype]-lj4[itype][jtype]) -
offset[itype][jtype];
break;
case SMALL_LARGE:
c2 = a2[itype][jtype];
K[1] = c2*c2;
K[2] = rsq;
K[0] = K[1] - rsq;
K[4] = rsq*rsq;
K[3] = K[1] - K[2];
K[3] *= K[3]*K[3];
K[6] = K[3]*K[3];
fR = sigma3[itype][jtype]*a12[itype][jtype]*c2*K[1]/K[3];
fforce = 4.0/15.0*fR*factor_lj *
(2.0*(K[1]+K[2])*(K[1]*(5.0*K[1]+22.0*K[2])+5.0*K[4]) *
sigma6[itype][jtype]/K[6] - 5.0)/K[0];
phi = 2.0/9.0*fR *
(1.0-(K[1]*(K[1]*(K[1]/3.0+3.0*K[2])+4.2*K[4])+K[2]*K[4]) *
sigma6[itype][jtype]/K[6]) - offset[itype][jtype];
break;
case LARGE_LARGE:
r = sqrt(rsq);
c1 = a1[itype][jtype];
c2 = a2[itype][jtype];
K[0] = c1*c2;
K[1] = c1+c2;
K[2] = c1-c2;
K[3] = K[1]+r;
K[4] = K[1]-r;
K[5] = K[2]+r;
K[6] = K[2]-r;
K[7] = 1.0/(K[3]*K[4]);
K[8] = 1.0/(K[5]*K[6]);
g[0] = powint(K[3],-7);
g[1] = powint(K[4],-7);
g[2] = powint(K[5],-7);
g[3] = powint(K[6],-7);
h[0] = ((K[3]+5.0*K[1])*K[3]+30.0*K[0])*g[0];
h[1] = ((K[4]+5.0*K[1])*K[4]+30.0*K[0])*g[1];
h[2] = ((K[5]+5.0*K[2])*K[5]-30.0*K[0])*g[2];
h[3] = ((K[6]+5.0*K[2])*K[6]-30.0*K[0])*g[3];
g[0] *= 42.0*K[0]/K[3]+6.0*K[1]+K[3];
g[1] *= 42.0*K[0]/K[4]+6.0*K[1]+K[4];
g[2] *= -42.0*K[0]/K[5]+6.0*K[2]+K[5];
g[3] *= -42.0*K[0]/K[6]+6.0*K[2]+K[6];
fR = a12[itype][jtype]*sigma6[itype][jtype]/r/37800.0;
phi = fR * (h[0]-h[1]-h[2]+h[3]);
dUR = phi/r + 5.0*fR*(g[0]+g[1]-g[2]-g[3]);
dUA = -a12[itype][jtype]/3.0*r*((2.0*K[0]*K[7]+1.0)*K[7] +
(2.0*K[0]*K[8]-1.0)*K[8]);
fforce = factor_lj*(dUR+dUA)/r;
phi += a12[itype][jtype]/6.0*(2.0*K[0]*(K[7]+K[8])-log(K[8]/K[7])) -
offset[itype][jtype];
break;
}
return factor_lj*phi;
}
diff --git a/src/COLLOID/pair_yukawa_colloid.cpp b/src/COLLOID/pair_yukawa_colloid.cpp
index 9b8d0ecaa..87fa7f542 100644
--- a/src/COLLOID/pair_yukawa_colloid.cpp
+++ b/src/COLLOID/pair_yukawa_colloid.cpp
@@ -1,178 +1,178 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Randy Schunk (Sandia)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include "pair_yukawa_colloid.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairYukawaColloid::PairYukawaColloid(LAMMPS *lmp) : PairYukawa(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
void PairYukawaColloid::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair,radi,radj;
double rsq,r,rinv,screening,forceyukawa,factor;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
radi = radius[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
radj = radius[j];
if (rsq < cutsq[itype][jtype]) {
r = sqrt(rsq);
rinv = 1.0/r;
screening = exp(-kappa*(r-(radi+radj)));
forceyukawa = a[itype][jtype] * screening;
fpair = factor*forceyukawa * rinv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = a[itype][jtype]/kappa * screening - offset[itype][jtype];
evdwl *= factor;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairYukawaColloid::init_style()
{
if (!atom->sphere_flag)
error->all(FLERR,"Pair yukawa/colloid requires atom style sphere");
neighbor->request(this,instance_me);
// require that atom radii are identical within each type
for (int i = 1; i <= atom->ntypes; i++)
if (!atom->radius_consistency(i,rad[i]))
error->all(FLERR,"Pair yukawa/colloid requires atoms with same type "
"have same radius");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairYukawaColloid::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
a[i][j] = mix_energy(a[i][i],a[j][j],1.0,1.0);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
- if (offset_flag) {
+ if (offset_flag && (kappa != 0.0)) {
double screening = exp(-kappa * (cut[i][j] - (rad[i]+rad[j])));
offset[i][j] = a[i][j]/kappa * screening;
} else offset[i][j] = 0.0;
a[j][i] = a[i][j];
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ---------------------------------------------------------------------- */
double PairYukawaColloid::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r,rinv,screening,forceyukawa,phi;
r = sqrt(rsq);
rinv = 1.0/r;
screening = exp(-kappa*(r-(rad[itype]+rad[jtype])));
forceyukawa = a[itype][jtype] * screening;
fforce = factor_lj*forceyukawa * rinv;
phi = a[itype][jtype]/kappa * screening - offset[itype][jtype];
return factor_lj*phi;
}
diff --git a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp
index addd02e50..af987bf25 100644
--- a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp
+++ b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp
@@ -1,486 +1,486 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include "pair_lj_cut_dipole_cut.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "comm.h"
#include "force.h"
#include "memory.h"
#include "error.h"
#include "update.h"
#include <string.h>
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairLJCutDipoleCut::PairLJCutDipoleCut(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
}
/* ---------------------------------------------------------------------- */
PairLJCutDipoleCut::~PairLJCutDipoleCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutDipoleCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fx,fy,fz;
double rsq,rinv,r2inv,r6inv,r3inv,r5inv,r7inv;
double forcecoulx,forcecouly,forcecoulz,crossx,crossy,crossz;
double tixcoul,tiycoul,tizcoul,tjxcoul,tjycoul,tjzcoul;
double fq,pdotp,pidotr,pjdotr,pre1,pre2,pre3,pre4;
double forcelj,factor_coul,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
double **mu = atom->mu;
double **torque = atom->torque;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
rinv = sqrt(r2inv);
// atom can have both a charge and dipole
// i,j = charge-charge, dipole-dipole, dipole-charge, or charge-dipole
forcecoulx = forcecouly = forcecoulz = 0.0;
tixcoul = tiycoul = tizcoul = 0.0;
tjxcoul = tjycoul = tjzcoul = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
if (qtmp != 0.0 && q[j] != 0.0) {
r3inv = r2inv*rinv;
pre1 = qtmp*q[j]*r3inv;
forcecoulx += pre1*delx;
forcecouly += pre1*dely;
forcecoulz += pre1*delz;
}
if (mu[i][3] > 0.0 && mu[j][3] > 0.0) {
r3inv = r2inv*rinv;
r5inv = r3inv*r2inv;
r7inv = r5inv*r2inv;
pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2];
pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz;
pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz;
pre1 = 3.0*r5inv*pdotp - 15.0*r7inv*pidotr*pjdotr;
pre2 = 3.0*r5inv*pjdotr;
pre3 = 3.0*r5inv*pidotr;
pre4 = -1.0*r3inv;
forcecoulx += pre1*delx + pre2*mu[i][0] + pre3*mu[j][0];
forcecouly += pre1*dely + pre2*mu[i][1] + pre3*mu[j][1];
forcecoulz += pre1*delz + pre2*mu[i][2] + pre3*mu[j][2];
crossx = pre4 * (mu[i][1]*mu[j][2] - mu[i][2]*mu[j][1]);
crossy = pre4 * (mu[i][2]*mu[j][0] - mu[i][0]*mu[j][2]);
crossz = pre4 * (mu[i][0]*mu[j][1] - mu[i][1]*mu[j][0]);
tixcoul += crossx + pre2 * (mu[i][1]*delz - mu[i][2]*dely);
tiycoul += crossy + pre2 * (mu[i][2]*delx - mu[i][0]*delz);
tizcoul += crossz + pre2 * (mu[i][0]*dely - mu[i][1]*delx);
tjxcoul += -crossx + pre3 * (mu[j][1]*delz - mu[j][2]*dely);
tjycoul += -crossy + pre3 * (mu[j][2]*delx - mu[j][0]*delz);
tjzcoul += -crossz + pre3 * (mu[j][0]*dely - mu[j][1]*delx);
}
if (mu[i][3] > 0.0 && q[j] != 0.0) {
r3inv = r2inv*rinv;
r5inv = r3inv*r2inv;
pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz;
pre1 = 3.0*q[j]*r5inv * pidotr;
pre2 = q[j]*r3inv;
forcecoulx += pre2*mu[i][0] - pre1*delx;
forcecouly += pre2*mu[i][1] - pre1*dely;
forcecoulz += pre2*mu[i][2] - pre1*delz;
tixcoul += pre2 * (mu[i][1]*delz - mu[i][2]*dely);
tiycoul += pre2 * (mu[i][2]*delx - mu[i][0]*delz);
tizcoul += pre2 * (mu[i][0]*dely - mu[i][1]*delx);
}
if (mu[j][3] > 0.0 && qtmp != 0.0) {
r3inv = r2inv*rinv;
r5inv = r3inv*r2inv;
pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz;
pre1 = 3.0*qtmp*r5inv * pjdotr;
pre2 = qtmp*r3inv;
forcecoulx += pre1*delx - pre2*mu[j][0];
forcecouly += pre1*dely - pre2*mu[j][1];
forcecoulz += pre1*delz - pre2*mu[j][2];
tjxcoul += -pre2 * (mu[j][1]*delz - mu[j][2]*dely);
tjycoul += -pre2 * (mu[j][2]*delx - mu[j][0]*delz);
tjzcoul += -pre2 * (mu[j][0]*dely - mu[j][1]*delx);
}
}
// LJ interaction
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
forcelj *= factor_lj * r2inv;
} else forcelj = 0.0;
// total force
fq = factor_coul*qqrd2e;
fx = fq*forcecoulx + delx*forcelj;
fy = fq*forcecouly + dely*forcelj;
fz = fq*forcecoulz + delz*forcelj;
// force & torque accumulation
f[i][0] += fx;
f[i][1] += fy;
f[i][2] += fz;
torque[i][0] += fq*tixcoul;
torque[i][1] += fq*tiycoul;
torque[i][2] += fq*tizcoul;
if (newton_pair || j < nlocal) {
f[j][0] -= fx;
f[j][1] -= fy;
f[j][2] -= fz;
torque[j][0] += fq*tjxcoul;
torque[j][1] += fq*tjycoul;
torque[j][2] += fq*tjzcoul;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype]) {
ecoul = qtmp*q[j]*rinv;
if (mu[i][3] > 0.0 && mu[j][3] > 0.0)
ecoul += r3inv*pdotp - 3.0*r5inv*pidotr*pjdotr;
if (mu[i][3] > 0.0 && q[j] != 0.0)
ecoul += -q[j]*r3inv*pidotr;
if (mu[j][3] > 0.0 && qtmp != 0.0)
ecoul += qtmp*r3inv*pjdotr;
ecoul *= factor_coul*qqrd2e;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
evdwl,ecoul,fx,fy,fz,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2)
error->all(FLERR,"Incorrect args in pair_style command");
if (strcmp(update->unit_style,"electron") == 0)
error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]);
if (narg == 6) cut_coul_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::init_style()
{
if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag)
error->all(FLERR,"Pair dipole/cut requires atom attributes q, mu, torque");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutDipoleCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutDipoleCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
diff --git a/src/DIPOLE/pair_lj_cut_dipole_long.cpp b/src/DIPOLE/pair_lj_cut_dipole_long.cpp
index 78922e356..63f48bea8 100644
--- a/src/DIPOLE/pair_lj_cut_dipole_long.cpp
+++ b/src/DIPOLE/pair_lj_cut_dipole_long.cpp
@@ -1,559 +1,559 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
www.cs.sandia.gov/~sjplimp/lammps.html
Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_dipole_long.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "force.h"
#include "kspace.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include "update.h"
#include <string.h>
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJCutDipoleLong::PairLJCutDipoleLong(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
ewaldflag = dipoleflag = 1;
respa_enable = 0;
}
/* ----------------------------------------------------------------------
free all arrays
------------------------------------------------------------------------- */
PairLJCutDipoleLong::~PairLJCutDipoleLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutDipoleLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz;
double rsq,r,rinv,r2inv,r6inv;
double forcecoulx,forcecouly,forcecoulz,fforce;
double tixcoul,tiycoul,tizcoul,tjxcoul,tjycoul,tjzcoul;
double fx,fy,fz,fdx,fdy,fdz,fax,fay,faz;
double pdotp,pidotr,pjdotr,pre1,pre2,pre3;
double grij,expm2,t,erfc;
double g0,g1,g2,b0,b1,b2,b3,d0,d1,d2,d3;
double zdix,zdiy,zdiz,zdjx,zdjy,zdjz,zaix,zaiy,zaiz,zajx,zajy,zajz;
double g0b1_g1b2_g2b3,g0d1_g1d2_g2d3;
double forcelj,factor_coul,factor_lj,facm1;
double evdwl,ecoul;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
double **mu = atom->mu;
double **torque = atom->torque;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
pre1 = 2.0 * g_ewald / MY_PIS;
pre2 = 4.0 * pow(g_ewald,3.0) / MY_PIS;
pre3 = 8.0 * pow(g_ewald,5.0) / MY_PIS;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = atom->q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
rinv = sqrt(r2inv);
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
pdotp = mu[i][0]*mu[j][0] + mu[i][1]*mu[j][1] + mu[i][2]*mu[j][2];
pidotr = mu[i][0]*delx + mu[i][1]*dely + mu[i][2]*delz;
pjdotr = mu[j][0]*delx + mu[j][1]*dely + mu[j][2]*delz;
g0 = qtmp*q[j];
g1 = qtmp*pjdotr - q[j]*pidotr + pdotp;
g2 = -pidotr*pjdotr;
if (factor_coul > 0.0) {
b0 = erfc * rinv;
b1 = (b0 + pre1*expm2) * r2inv;
b2 = (3.0*b1 + pre2*expm2) * r2inv;
b3 = (5.0*b2 + pre3*expm2) * r2inv;
g0b1_g1b2_g2b3 = g0*b1 + g1*b2 + g2*b3;
fdx = delx * g0b1_g1b2_g2b3 -
b1 * (qtmp*mu[j][0] - q[j]*mu[i][0]) +
b2 * (pjdotr*mu[i][0] + pidotr*mu[j][0]);
fdy = dely * g0b1_g1b2_g2b3 -
b1 * (qtmp*mu[j][1] - q[j]*mu[i][1]) +
b2 * (pjdotr*mu[i][1] + pidotr*mu[j][1]);
fdz = delz * g0b1_g1b2_g2b3 -
b1 * (qtmp*mu[j][2] - q[j]*mu[i][2]) +
b2 * (pjdotr*mu[i][2] + pidotr*mu[j][2]);
zdix = delx * (q[j]*b1 + b2*pjdotr) - b1*mu[j][0];
zdiy = dely * (q[j]*b1 + b2*pjdotr) - b1*mu[j][1];
zdiz = delz * (q[j]*b1 + b2*pjdotr) - b1*mu[j][2];
zdjx = delx * (-qtmp*b1 + b2*pidotr) - b1*mu[i][0];
zdjy = dely * (-qtmp*b1 + b2*pidotr) - b1*mu[i][1];
zdjz = delz * (-qtmp*b1 + b2*pidotr) - b1*mu[i][2];
if (factor_coul < 1.0) {
fdx *= factor_coul;
fdy *= factor_coul;
fdz *= factor_coul;
zdix *= factor_coul;
zdiy *= factor_coul;
zdiz *= factor_coul;
zdjx *= factor_coul;
zdjy *= factor_coul;
zdjz *= factor_coul;
}
} else {
fdx = fdy = fdz = 0.0;
zdix = zdiy = zdiz = 0.0;
zdjx = zdjy = zdjz = 0.0;
}
if (factor_coul < 1.0) {
d0 = (erfc - 1.0) * rinv;
d1 = (d0 + pre1*expm2) * r2inv;
d2 = (3.0*d1 + pre2*expm2) * r2inv;
d3 = (5.0*d2 + pre3*expm2) * r2inv;
g0d1_g1d2_g2d3 = g0*d1 + g1*d2 + g2*d3;
fax = delx * g0d1_g1d2_g2d3 -
d1 * (qtmp*mu[j][0] - q[j]*mu[i][0]) +
d2 * (pjdotr*mu[i][0] + pidotr*mu[j][0]);
fay = dely * g0d1_g1d2_g2d3 -
d1 * (qtmp*mu[j][1] - q[j]*mu[i][1]) +
d2 * (pjdotr*mu[i][1] + pidotr*mu[j][1]);
faz = delz * g0d1_g1d2_g2d3 -
d1 * (qtmp*mu[j][2] - q[j]*mu[i][2]) +
d2 * (pjdotr*mu[i][2] + pidotr*mu[j][2]);
zaix = delx * (q[j]*d1 + d2*pjdotr) - d1*mu[j][0];
zaiy = dely * (q[j]*d1 + d2*pjdotr) - d1*mu[j][1];
zaiz = delz * (q[j]*d1 + d2*pjdotr) - d1*mu[j][2];
zajx = delx * (-qtmp*d1 + d2*pidotr) - d1*mu[i][0];
zajy = dely * (-qtmp*d1 + d2*pidotr) - d1*mu[i][1];
zajz = delz * (-qtmp*d1 + d2*pidotr) - d1*mu[i][2];
if (factor_coul > 0.0) {
facm1 = 1.0 - factor_coul;
fax *= facm1;
fay *= facm1;
faz *= facm1;
zaix *= facm1;
zaiy *= facm1;
zaiz *= facm1;
zajx *= facm1;
zajy *= facm1;
zajz *= facm1;
}
} else {
fax = fay = faz = 0.0;
zaix = zaiy = zaiz = 0.0;
zajx = zajy = zajz = 0.0;
}
forcecoulx = fdx + fax;
forcecouly = fdy + fay;
forcecoulz = fdz + faz;
tixcoul = mu[i][1]*(zdiz + zaiz) - mu[i][2]*(zdiy + zaiy);
tiycoul = mu[i][2]*(zdix + zaix) - mu[i][0]*(zdiz + zaiz);
tizcoul = mu[i][0]*(zdiy + zaiy) - mu[i][1]*(zdix + zaix);
tjxcoul = mu[j][1]*(zdjz + zajz) - mu[j][2]*(zdjy + zajy);
tjycoul = mu[j][2]*(zdjx + zajx) - mu[j][0]*(zdjz + zajz);
tjzcoul = mu[j][0]*(zdjy + zajy) - mu[j][1]*(zdjx + zajx);
} else {
forcecoulx = forcecouly = forcecoulz = 0.0;
tixcoul = tiycoul = tizcoul = 0.0;
tjxcoul = tjycoul = tjzcoul = 0.0;
}
// LJ interaction
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fforce = factor_lj * forcelj*r2inv;
} else fforce = 0.0;
// total force
fx = qqrd2e*forcecoulx + delx*fforce;
fy = qqrd2e*forcecouly + dely*fforce;
fz = qqrd2e*forcecoulz + delz*fforce;
// force & torque accumulation
f[i][0] += fx;
f[i][1] += fy;
f[i][2] += fz;
torque[i][0] += qqrd2e*tixcoul;
torque[i][1] += qqrd2e*tiycoul;
torque[i][2] += qqrd2e*tizcoul;
if (newton_pair || j < nlocal) {
f[j][0] -= fx;
f[j][1] -= fy;
f[j][2] -= fz;
torque[j][0] += qqrd2e*tjxcoul;
torque[j][1] += qqrd2e*tjycoul;
torque[j][2] += qqrd2e*tjzcoul;
}
if (eflag) {
if (rsq < cut_coulsq && factor_coul > 0.0) {
ecoul = qqrd2e*(b0*g0 + b1*g1 + b2*g2);
if (factor_coul < 1.0) {
ecoul *= factor_coul;
ecoul += (1-factor_coul) * qqrd2e * (d0*g0 + d1*g1 + d2*g2);
}
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
evdwl,ecoul,fx,fy,fz,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2)
error->all(FLERR,"Incorrect args in pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutDipoleLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::init_style()
{
if (!atom->q_flag || !atom->mu_flag || !atom->torque_flag)
error->all(FLERR,"Pair dipole/long requires atom attributes q, mu, torque");
if (strcmp(update->unit_style,"electron") == 0)
error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles");
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
cut_coulsq = cut_coul * cut_coul;
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutDipoleLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
void *PairLJCutDipoleLong::extract(const char *str, int &dim)
{
if (strcmp(str,"cut_coul") == 0) {
dim = 0;
return (void *) &cut_coul;
} else if (strcmp(str,"ewald_order") == 0) {
ewald_order = 0;
ewald_order |= 1<<1;
ewald_order |= 1<<3;
dim = 0;
return (void *) &ewald_order;
} else if (strcmp(str,"ewald_mix") == 0) {
dim = 0;
return (void *) &mix_flag;
}
return NULL;
}
diff --git a/src/DIPOLE/pair_lj_long_dipole_long.cpp b/src/DIPOLE/pair_lj_long_dipole_long.cpp
index 15ac2e788..b833b250d 100644
--- a/src/DIPOLE/pair_lj_long_dipole_long.cpp
+++ b/src/DIPOLE/pair_lj_long_dipole_long.cpp
@@ -1,682 +1,682 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pieter J. in 't Veld and Stan Moore (Sandia)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "math_const.h"
#include "math_vector.h"
#include "pair_lj_long_dipole_long.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
// ----------------------------------------------------------------------
PairLJLongDipoleLong::PairLJLongDipoleLong(LAMMPS *lmp) : Pair(lmp)
{
dispersionflag = ewaldflag = dipoleflag = 1;
respa_enable = 0;
single_enable = 0;
}
// ----------------------------------------------------------------------
// global settings
// ----------------------------------------------------------------------
void PairLJLongDipoleLong::options(char **arg, int order)
{
const char *option[] = {"long", "cut", "off", NULL};
int i;
if (!*arg) error->all(FLERR,"Illegal pair_style lj/long/dipole/long command");
for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i);
switch (i) {
default: error->all(FLERR,"Illegal pair_style lj/long/dipole/long command");
case 0: ewald_order |= 1<<order; break; // set kspace r^-order
case 2: ewald_off |= 1<<order; // turn r^-order off
case 1: break;
}
}
void PairLJLongDipoleLong::settings(int narg, char **arg)
{
if (narg != 3 && narg != 4) error->all(FLERR,"Illegal pair_style command");
ewald_off = 0;
ewald_order = 0;
options(arg, 6);
options(++arg, 3);
options(arg, 1);
if (!comm->me && ewald_order&(1<<6))
error->warning(FLERR,"Geometric mixing assumed for 1/r^6 coefficients");
if (!comm->me && ewald_order==((1<<3)|(1<<6)))
error->warning(FLERR,
"Using largest cut-off for lj/long/dipole/long long long");
if (!*(++arg))
error->all(FLERR,"Cut-offs missing in pair_style lj/long/dipole/long");
if (!((ewald_order^ewald_off)&(1<<3)))
error->all(FLERR,
"Coulombic cut not supported in pair_style lj/long/dipole/long");
cut_lj_global = force->numeric(FLERR,*(arg++));
if (narg == 4 && (ewald_order==74))
error->all(FLERR,"Only one cut-off allowed when requesting all long");
if (narg == 4) cut_coul = force->numeric(FLERR,*(arg++));
else cut_coul = cut_lj_global;
if (allocated) { // reset explicit cuts
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
// ----------------------------------------------------------------------
// free all arrays
// ----------------------------------------------------------------------
PairLJLongDipoleLong::~PairLJLongDipoleLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj_read);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon_read);
memory->destroy(epsilon);
memory->destroy(sigma_read);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
//if (ftable) free_tables();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj_read,n+1,n+1,"pair:cut_lj_read");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon_read,n+1,n+1,"pair:epsilon_read");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma_read,n+1,n+1,"pair:sigma_read");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
extract protected data from object
------------------------------------------------------------------------- */
void *PairLJLongDipoleLong::extract(const char *id, int &dim)
{
const char *ids[] = {
"B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix",
"cut_coul", "cut_vdwl", NULL};
void *ptrs[] = {
lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag, &cut_coul,
&cut_lj_global, NULL};
int i;
for (i=0; ids[i]&&strcmp(ids[i], id); ++i);
if (i <= 2) dim = 2;
else dim = 0;
return ptrs[i];
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon_read[i][j] = epsilon_one;
sigma_read[i][j] = sigma_one;
cut_lj_read[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::init_style()
{
const char *style3[] = {"ewald/disp", NULL};
const char *style6[] = {"ewald/disp", NULL};
int i;
if (strcmp(update->unit_style,"electron") == 0)
error->all(FLERR,"Cannot (yet) use 'electron' units with dipoles");
// require an atom style with charge defined
if (!atom->q_flag && (ewald_order&(1<<1)))
error->all(FLERR,
"Invoking coulombic in pair style lj/long/dipole/long requires atom attribute q");
if (!atom->mu && (ewald_order&(1<<3)))
error->all(FLERR,"Pair lj/long/dipole/long requires atom attributes mu, torque");
if (!atom->torque && (ewald_order&(1<<3)))
error->all(FLERR,"Pair lj/long/dipole/long requires atom attributes mu, torque");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// ensure use of KSpace long-range solver, set g_ewald
if (ewald_order&(1<<3)) { // r^-1 kspace
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
for (i=0; style3[i]&&strcmp(force->kspace_style, style3[i]); ++i);
if (!style3[i])
error->all(FLERR,"Pair style requires use of kspace_style ewald/disp");
}
if (ewald_order&(1<<6)) { // r^-6 kspace
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
for (i=0; style6[i]&&strcmp(force->kspace_style, style6[i]); ++i);
if (!style6[i])
error->all(FLERR,"Pair style requires use of kspace_style ewald/disp");
}
if (force->kspace) g_ewald = force->kspace->g_ewald;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
if (id)
error->all(FLERR,"Pair style lj/long/dipole/long does not currently support respa");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJLongDipoleLong::init_one(int i, int j)
{
if ((ewald_order&(1<<6))||(setflag[i][j] == 0)) {
epsilon[i][j] = mix_energy(epsilon_read[i][i],epsilon_read[j][j],
sigma_read[i][i],sigma_read[j][j]);
sigma[i][j] = mix_distance(sigma_read[i][i],sigma_read[j][j]);
if (ewald_order&(1<<6))
cut_lj[i][j] = cut_lj_global;
else
cut_lj[i][j] = mix_distance(cut_lj_read[i][i],cut_lj_read[j][j]);
}
else {
sigma[i][j] = sigma_read[i][j];
epsilon[i][j] = epsilon_read[i][j];
cut_lj[i][j] = cut_lj_read[i][j];
}
double cut = MAX(cut_lj[i][j], cut_coul);
cutsq[i][j] = cut*cut;
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
// check interior rRESPA cutoff
//if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3])
//error->all(FLERR,"Pair cutoff < Respa interior cutoff");
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cutsq[j][i] = cutsq[i][j];
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon_read[i][j],sizeof(double),1,fp);
fwrite(&sigma_read[i][j],sizeof(double),1,fp);
fwrite(&cut_lj_read[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon_read[i][j],sizeof(double),1,fp);
fread(&sigma_read[i][j],sizeof(double),1,fp);
fread(&cut_lj_read[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_read[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&ewald_order,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&ewald_order,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&ewald_order,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
compute pair interactions
------------------------------------------------------------------------- */
void PairLJLongDipoleLong::compute(int eflag, int vflag)
{
double evdwl,ecoul,fpair;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x, *x0 = x[0];
double **mu = atom->mu, *mu0 = mu[0], *imu, *jmu;
double **tq = atom->torque, *tq0 = tq[0], *tqi;
double **f = atom->f, *f0 = f[0], *fi = f0, fx, fy, fz;
double *q = atom->q, qi = 0, qj;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int i, j;
int order3 = ewald_order&(1<<3), order6 = ewald_order&(1<<6);
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double rsq, r2inv, force_coul, force_lj;
double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2;
double B0, B1, B2, B3, G0, G1, G2, mudi, mudj, muij;
vector force_d = VECTOR_NULL, ti = VECTOR_NULL, tj = VECTOR_NULL;
vector mui, muj, xi, d;
double C1 = 2.0 * g_ewald / MY_PIS;
double C2 = 2.0 * g2 * C1;
double C3 = 2.0 * g2 * C2;
ineighn = (ineigh = list->ilist)+list->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over all neighs
i = *ineigh; fi = f0+3*i; tqi = tq0+3*i;
qi = q[i]; // initialize constants
offseti = offset[typei = type[i]];
lj1i = lj1[typei]; lj2i = lj2[typei]; lj3i = lj3[typei]; lj4i = lj4[typei];
cutsqi = cutsq[typei]; cut_ljsqi = cut_ljsq[typei];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
memcpy(mui, imu = mu0+(i<<2), sizeof(vector));
jneighn = (jneigh = list->firstneigh[i])+list->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j); // special index
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cutsqi[typej = type[j]]) continue;
r2inv = 1.0/rsq;
if (order3 && (rsq < cut_coulsq)) { // dipole
memcpy(muj, jmu = mu0+(j<<2), sizeof(vector));
{ // series real space
register double r = sqrt(rsq);
register double x = g_ewald*r;
register double f = exp(-x*x)*qqrd2e;
B0 = 1.0/(1.0+EWALD_P*x); // eqn 2.8
B0 *= ((((A5*B0+A4)*B0+A3)*B0+A2)*B0+A1)*f/r;
B1 = (B0 + C1 * f) * r2inv;
B2 = (3.0*B1 + C2 * f) * r2inv;
B3 = (5.0*B2 + C3 * f) * r2inv;
mudi = mui[0]*d[0]+mui[1]*d[1]+mui[2]*d[2];
mudj = muj[0]*d[0]+muj[1]*d[1]+muj[2]*d[2];
muij = mui[0]*muj[0]+mui[1]*muj[1]+mui[2]*muj[2];
G0 = qi*(qj = q[j]); // eqn 2.10
G1 = qi*mudj-qj*mudi+muij;
G2 = -mudi*mudj;
force_coul = G0*B1+G1*B2+G2*B3;
mudi *= B2; mudj *= B2; // torque contribs
ti[0] = mudj*d[0]+(qj*d[0]-muj[0])*B1;
ti[1] = mudj*d[1]+(qj*d[1]-muj[1])*B1;
ti[2] = mudj*d[2]+(qj*d[2]-muj[2])*B1;
if (newton_pair || j < nlocal) {
tj[0] = mudi*d[0]-(qi*d[0]+mui[0])*B1;
tj[1] = mudi*d[1]-(qi*d[1]+mui[1])*B1;
tj[2] = mudi*d[2]-(qi*d[2]+mui[2])*B1;
}
if (eflag) ecoul = G0*B0+G1*B1+G2*B2;
if (ni > 0) { // adj part, eqn 2.13
force_coul -= (f = qqrd2e*(1.0-special_coul[ni])/r)*(
(3.0*G1+15.0*G2*r2inv)*r2inv+G0)*r2inv;
if (eflag)
ecoul -= f*((G1+3.0*G2*r2inv)*r2inv+G0);
B1 -= f*r2inv;
}
B0 = mudj+qj*B1; B3 = -qi*B1+mudi; // position independent
if (ni > 0) B0 -= f*3.0*mudj*r2inv*r2inv/B2;
if (ni > 0) B3 -= f*3.0*mudi*r2inv*r2inv/B2;
force_d[0] = B0*mui[0]+B3*muj[0]; // force contribs
force_d[1] = B0*mui[1]+B3*muj[1];
force_d[2] = B0*mui[2]+B3*muj[2];
if (ni > 0) {
ti[0] -= f*(3.0*mudj*r2inv*r2inv*d[0]/B2+(qj*r2inv*d[0]-muj[0]*r2inv));
ti[1] -= f*(3.0*mudj*r2inv*r2inv*d[1]/B2+(qj*r2inv*d[1]-muj[1]*r2inv));
ti[2] -= f*(3.0*mudj*r2inv*r2inv*d[2]/B2+(qj*r2inv*d[2]-muj[2]*r2inv));
if (newton_pair || j < nlocal) {
tj[0] -= f*(3.0*mudi*r2inv*r2inv*d[0]/B2-(qi*r2inv*d[0]+mui[0]*r2inv));
tj[1] -= f*(3.0*mudi*r2inv*r2inv*d[1]/B2-(qi*r2inv*d[1]+mui[1]*r2inv));
tj[2] -= f*(3.0*mudi*r2inv*r2inv*d[2]/B2-(qi*r2inv*d[2]+mui[2]*r2inv));
}
}
} // table real space
} else {
force_coul = ecoul = 0.0;
memset(force_d, 0, 3*sizeof(double));
}
if (rsq < cut_ljsqi[typej]) { // lj
if (order6) { // long-range lj
register double rn = r2inv*r2inv*r2inv;
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*lj4i[typej];
if (ni < 0) {
force_lj =
(rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
if (eflag) evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_lj = f*(rn *= rn)*lj1i[typej]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej];
if (eflag) evdwl =
f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej];
}
}
else { // cut lj
register double rn = r2inv*r2inv*r2inv;
if (ni < 0) {
force_lj = rn*(rn*lj1i[typej]-lj2i[typej]);
if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej];
}
else { // special case
register double f = special_lj[ni];
force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]);
if (eflag) evdwl = f*(
rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]);
}
}
force_lj *= r2inv;
}
else force_lj = evdwl = 0.0;
fpair = force_coul+force_lj; // force
if (newton_pair || j < nlocal) {
register double *fj = f0+(j+(j<<1));
fi[0] += fx = d[0]*fpair+force_d[0]; fj[0] -= fx;
fi[1] += fy = d[1]*fpair+force_d[1]; fj[1] -= fy;
fi[2] += fz = d[2]*fpair+force_d[2]; fj[2] -= fz;
tqi[0] += mui[1]*ti[2]-mui[2]*ti[1]; // torque
tqi[1] += mui[2]*ti[0]-mui[0]*ti[2];
tqi[2] += mui[0]*ti[1]-mui[1]*ti[0];
register double *tqj = tq0+(j+(j<<1));
tqj[0] += muj[1]*tj[2]-muj[2]*tj[1];
tqj[1] += muj[2]*tj[0]-muj[0]*tj[2];
tqj[2] += muj[0]*tj[1]-muj[1]*tj[0];
}
else {
fi[0] += fx = d[0]*fpair+force_d[0]; // force
fi[1] += fy = d[1]*fpair+force_d[1];
fi[2] += fz = d[2]*fpair+force_d[2];
tqi[0] += mui[1]*ti[2]-mui[2]*ti[1]; // torque
tqi[1] += mui[2]*ti[0]-mui[0]*ti[2];
tqi[2] += mui[0]*ti[1]-mui[1]*ti[0];
}
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
evdwl,ecoul,fx,fy,fz,d[0],d[1],d[2]);
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
/*
double PairLJLongDipoleLong::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r6inv, force_coul, force_lj;
double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q;
double eng = 0.0;
double r2inv = 1.0/rsq;
if ((ewald_order&(1<<3)) && (rsq < cut_coulsq)) { // coulombic
double *mui = atom->mu[i], *muj = atom->mu[j];
double *xi = atom->x[i], *xj = atom->x[j];
double qi = q[i], qj = q[j];
double G0, G1, G2, B0, B1, B2, B3, mudi, mudj, muij;
vector d = {xi[0]-xj[0], xi[1]-xj[1], xi[2]-xj[2]};
{ // series real space
register double r = sqrt(rsq);
register double x = g_ewald*r;
register double f = exp(-x*x)*qqrd2e;
B0 = 1.0/(1.0+EWALD_P*x); // eqn 2.8
B0 *= ((((A5*B0+A4)*B0+A3)*B0+A2)*B0+A1)*f/r;
B1 = (B0 + C1 * f) * r2inv;
B2 = (3.0*B1 + C2 * f) * r2inv;
B3 = (5.0*B2 + C3 * f) * r2inv;
mudi = mui[0]*d[0]+mui[1]*d[1]+mui[2]*d[2];
mudj = muj[0]*d[0]+muj[1]*d[1]+muj[2]*d[2];
muij = mui[0]*muj[0]+mui[1]*muj[1]+mui[2]*muj[2];
G0 = qi*(qj = q[j]); // eqn 2.10
G1 = qi*mudj-qj*mudi+muij;
G2 = -mudi*mudj;
force_coul = G0*B1+G1*B2+G2*B3;
eng += G0*B0+G1*B1+G2*B2;
if (factor_coul < 1.0) { // adj part, eqn 2.13
force_coul -= (f = force->qqrd2e*(1.0-factor_coul)/r)*(
(3.0*G1+6.0*muij+15.0*G2*r2inv)*r2inv+G0);
eng -= f*((G1+3.0*G2*r2inv)*r2inv+G0);
B1 -= f*r2inv;
}
B0 = mudj*B2-qj*B1; B3 = qi*B1+mudi*B2; // position independent
//force_d[0] = B0*mui[0]+B3*muj[0]; // force contributions
//force_d[1] = B0*mui[1]+B3*muj[1];
//force_d[2] = B0*mui[2]+B3*muj[2];
} // table real space
}
else force_coul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) { // lennard-jones
r6inv = r2inv*r2inv*r2inv;
if (ewald_order&0x40) { // long-range
register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_lj);
x2 = a2*exp(-x2)*lj4[itype][jtype];
force_lj = factor_lj*(r6inv *= r6inv)*lj1[itype][jtype]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*lj2[itype][jtype];
eng += factor_lj*r6inv*lj3[itype][jtype]-
g6*((a2+1.0)*a2+0.5)*x2+t*lj4[itype][jtype];
}
else { // cut
force_lj = factor_lj*r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]);
eng += factor_lj*(r6inv*(r6inv*lj3[itype][jtype]-
lj4[itype][jtype])-offset[itype][jtype]);
}
}
else force_lj = 0.0;
fforce = (force_coul+force_lj)*r2inv;
return eng;
}
*/
diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp
index 43559bde0..d95cd8f8a 100644
--- a/src/KOKKOS/pair_reaxc_kokkos.cpp
+++ b/src/KOKKOS/pair_reaxc_kokkos.cpp
@@ -1,4162 +1,4163 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Ray Shan (SNL), Stan Moore (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_reaxc_kokkos.h"
#include "kokkos.h"
#include "atom_kokkos.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "neigh_list_kokkos.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "math_const.h"
#include "math_special.h"
#include "memory.h"
#include "error.h"
#include "atom_masks.h"
#include "reaxc_defs.h"
#include "reaxc_lookup.h"
#include "reaxc_tool_box.h"
#define TEAMSIZE 128
/* ---------------------------------------------------------------------- */
namespace LAMMPS_NS {
using namespace MathConst;
using namespace MathSpecial;
template<class DeviceType>
PairReaxCKokkos<DeviceType>::PairReaxCKokkos(LAMMPS *lmp) : PairReaxC(lmp)
{
respa_enable = 0;
cut_nbsq = cut_hbsq = cut_bosq = 0.0;
atomKK = (AtomKokkos *) atom;
execution_space = ExecutionSpaceFromDevice<DeviceType>::space;
datamask_read = X_MASK | Q_MASK | F_MASK | TYPE_MASK | ENERGY_MASK | VIRIAL_MASK;
datamask_modify = F_MASK | ENERGY_MASK | VIRIAL_MASK;
k_resize_bo = DAT::tdual_int_scalar("pair:resize_bo");
d_resize_bo = k_resize_bo.view<DeviceType>();
k_resize_hb = DAT::tdual_int_scalar("pair:resize_hb");
d_resize_hb = k_resize_hb.view<DeviceType>();
nmax = 0;
maxbo = 1;
maxhb = 1;
k_error_flag = DAT::tdual_int_scalar("pair:error_flag");
k_nbuf_local = DAT::tdual_int_scalar("pair:nbuf_local");
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
PairReaxCKokkos<DeviceType>::~PairReaxCKokkos()
{
if (copymode) return;
memory->destroy_kokkos(k_eatom,eatom);
memory->destroy_kokkos(k_vatom,vatom);
memory->destroy_kokkos(k_tmpid,tmpid);
tmpid = NULL;
memory->destroy_kokkos(k_tmpbo,tmpbo);
tmpbo = NULL;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::allocate()
{
int n = atom->ntypes;
k_params_sing = Kokkos::DualView<params_sing*,typename DeviceType::array_layout,DeviceType>
("PairReaxC::params_sing",n+1);
paramssing = k_params_sing.template view<DeviceType>();
k_params_twbp = Kokkos::DualView<params_twbp**,typename DeviceType::array_layout,DeviceType>
("PairReaxC::params_twbp",n+1,n+1);
paramstwbp = k_params_twbp.template view<DeviceType>();
k_params_thbp = Kokkos::DualView<params_thbp***,typename DeviceType::array_layout,DeviceType>
("PairReaxC::params_thbp",n+1,n+1,n+1);
paramsthbp = k_params_thbp.template view<DeviceType>();
k_params_fbp = Kokkos::DualView<params_fbp****,typename DeviceType::array_layout,DeviceType>
("PairReaxC::params_fbp",n+1,n+1,n+1,n+1);
paramsfbp = k_params_fbp.template view<DeviceType>();
k_params_hbp = Kokkos::DualView<params_hbp***,typename DeviceType::array_layout,DeviceType>
("PairReaxC::params_hbp",n+1,n+1,n+1);
paramshbp = k_params_hbp.template view<DeviceType>();
k_tap = DAT::tdual_ffloat_1d("pair:tap",8);
d_tap = k_tap.template view<DeviceType>();
h_tap = k_tap.h_view;
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::init_style()
{
PairReaxC::init_style();
// irequest = neigh request made by parent class
neighflag = lmp->kokkos->neighflag;
int irequest = neighbor->nrequest - 1;
neighbor->requests[irequest]->
kokkos_host = Kokkos::Impl::is_same<DeviceType,LMPHostType>::value &&
!Kokkos::Impl::is_same<DeviceType,LMPDeviceType>::value;
neighbor->requests[irequest]->
kokkos_device = Kokkos::Impl::is_same<DeviceType,LMPDeviceType>::value;
if (neighflag == FULL) {
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->ghost = 1;
} else if (neighflag == HALF || neighflag == HALFTHREAD) {
neighbor->requests[irequest]->full = 0;
neighbor->requests[irequest]->half = 1;
neighbor->requests[irequest]->ghost = 1;
} else {
error->all(FLERR,"Cannot use chosen neighbor list style with reax/c/kk");
}
allocate();
setup();
init_md();
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::setup()
{
int i,j,k,m;
int n = atom->ntypes;
// general parameters
for (i = 0; i < 39; i ++)
gp[i] = system->reax_param.gp.l[i];
p_boc1 = gp[0];
p_boc2 = gp[1];
// vdw parameters
vdwflag = system->reax_param.gp.vdw_type;
lgflag = control->lgflag;
// atom, bond, angle, dihedral, H-bond specific parameters
two_body_parameters *twbp;
// valence angle (3-body) parameters
three_body_header *thbh;
three_body_parameters *thbp;
// torsion angle (4-body) parameters
four_body_header *fbh;
four_body_parameters *fbp;
// hydrogen bond parameters
hbond_parameters *hbp;
for (i = 1; i <= n; i++) {
// general
k_params_sing.h_view(i).mass = system->reax_param.sbp[map[i]].mass;
// polarization
k_params_sing.h_view(i).chi = system->reax_param.sbp[map[i]].chi;
k_params_sing.h_view(i).eta = system->reax_param.sbp[map[i]].eta;
// bond order
k_params_sing.h_view(i).r_s = system->reax_param.sbp[map[i]].r_s;
k_params_sing.h_view(i).r_pi = system->reax_param.sbp[map[i]].r_pi;
k_params_sing.h_view(i).r_pi2 = system->reax_param.sbp[map[i]].r_pi_pi;
k_params_sing.h_view(i).valency = system->reax_param.sbp[map[i]].valency;
k_params_sing.h_view(i).valency_val = system->reax_param.sbp[map[i]].valency_val;
k_params_sing.h_view(i).valency_boc = system->reax_param.sbp[map[i]].valency_boc;
k_params_sing.h_view(i).valency_e = system->reax_param.sbp[map[i]].valency_e;
k_params_sing.h_view(i).nlp_opt = system->reax_param.sbp[map[i]].nlp_opt;
// multibody
k_params_sing.h_view(i).p_lp2 = system->reax_param.sbp[map[i]].p_lp2;
k_params_sing.h_view(i).p_ovun2 = system->reax_param.sbp[map[i]].p_ovun2;
k_params_sing.h_view(i).p_ovun5 = system->reax_param.sbp[map[i]].p_ovun5;
// angular
k_params_sing.h_view(i).p_val3 = system->reax_param.sbp[map[i]].p_val3;
k_params_sing.h_view(i).p_val5 = system->reax_param.sbp[map[i]].p_val5;
// hydrogen bond
k_params_sing.h_view(i).p_hbond = system->reax_param.sbp[map[i]].p_hbond;
for (j = 1; j <= n; j++) {
twbp = &(system->reax_param.tbp[map[i]][map[j]]);
// vdW
k_params_twbp.h_view(i,j).gamma = twbp->gamma;
k_params_twbp.h_view(i,j).gamma_w = twbp->gamma_w;
k_params_twbp.h_view(i,j).alpha = twbp->alpha;
k_params_twbp.h_view(i,j).r_vdw = twbp->r_vdW;
k_params_twbp.h_view(i,j).epsilon = twbp->D;
k_params_twbp.h_view(i,j).acore = twbp->acore;
k_params_twbp.h_view(i,j).ecore = twbp->ecore;
k_params_twbp.h_view(i,j).rcore = twbp->rcore;
k_params_twbp.h_view(i,j).lgre = twbp->lgre;
k_params_twbp.h_view(i,j).lgcij = twbp->lgcij;
// bond order
k_params_twbp.h_view(i,j).r_s = twbp->r_s;
k_params_twbp.h_view(i,j).r_pi = twbp->r_p;
k_params_twbp.h_view(i,j).r_pi2 = twbp->r_pp;
k_params_twbp.h_view(i,j).p_bo1 = twbp->p_bo1;
k_params_twbp.h_view(i,j).p_bo2 = twbp->p_bo2;
k_params_twbp.h_view(i,j).p_bo3 = twbp->p_bo3;
k_params_twbp.h_view(i,j).p_bo4 = twbp->p_bo4;
k_params_twbp.h_view(i,j).p_bo5 = twbp->p_bo5;
k_params_twbp.h_view(i,j).p_bo6 = twbp->p_bo6;
k_params_twbp.h_view(i,j).p_boc3 = twbp->p_boc3;
k_params_twbp.h_view(i,j).p_boc4 = twbp->p_boc4;
k_params_twbp.h_view(i,j).p_boc5 = twbp->p_boc5;
k_params_twbp.h_view(i,j).ovc = twbp->ovc;
k_params_twbp.h_view(i,j).v13cor = twbp->v13cor;
// bond energy
k_params_twbp.h_view(i,j).p_be1 = twbp->p_be1;
k_params_twbp.h_view(i,j).p_be2 = twbp->p_be2;
k_params_twbp.h_view(i,j).De_s = twbp->De_s;
k_params_twbp.h_view(i,j).De_p = twbp->De_p;
k_params_twbp.h_view(i,j).De_pp = twbp->De_pp;
// multibody
k_params_twbp.h_view(i,j).p_ovun1 = twbp->p_ovun1;
for (k = 1; k <= n; k++) {
// Angular
thbh = &(system->reax_param.thbp[map[i]][map[j]][map[k]]);
thbp = &(thbh->prm[0]);
k_params_thbp.h_view(i,j,k).cnt = thbh->cnt;
k_params_thbp.h_view(i,j,k).theta_00 = thbp->theta_00;
k_params_thbp.h_view(i,j,k).p_val1 = thbp->p_val1;
k_params_thbp.h_view(i,j,k).p_val2 = thbp->p_val2;
k_params_thbp.h_view(i,j,k).p_val4 = thbp->p_val4;
k_params_thbp.h_view(i,j,k).p_val7 = thbp->p_val7;
k_params_thbp.h_view(i,j,k).p_pen1 = thbp->p_pen1;
k_params_thbp.h_view(i,j,k).p_coa1 = thbp->p_coa1;
// Hydrogen Bond
hbp = &(system->reax_param.hbp[map[i]][map[j]][map[k]]);
k_params_hbp.h_view(i,j,k).p_hb1 = hbp->p_hb1;
k_params_hbp.h_view(i,j,k).p_hb2 = hbp->p_hb2;
k_params_hbp.h_view(i,j,k).p_hb3 = hbp->p_hb3;
k_params_hbp.h_view(i,j,k).r0_hb = hbp->r0_hb;
for (m = 1; m <= n; m++) {
// Torsion
fbh = &(system->reax_param.fbp[map[i]][map[j]][map[k]][map[m]]);
fbp = &(fbh->prm[0]);
k_params_fbp.h_view(i,j,k,m).p_tor1 = fbp->p_tor1;
k_params_fbp.h_view(i,j,k,m).p_cot1 = fbp->p_cot1;
k_params_fbp.h_view(i,j,k,m).V1 = fbp->V1;
k_params_fbp.h_view(i,j,k,m).V2 = fbp->V2;
k_params_fbp.h_view(i,j,k,m).V3 = fbp->V3;
}
}
}
}
k_params_sing.template modify<LMPHostType>();
k_params_twbp.template modify<LMPHostType>();
k_params_thbp.template modify<LMPHostType>();
k_params_fbp.template modify<LMPHostType>();
k_params_hbp.template modify<LMPHostType>();
// cutoffs
cut_nbsq = control->nonb_cut * control->nonb_cut;
cut_hbsq = control->hbond_cut * control->hbond_cut;
cut_bosq = control->bond_cut * control->bond_cut;
// bond order cutoffs
bo_cut = 0.01 * gp[29];
thb_cut = control->thb_cut;
thb_cutsq = 0.000010; //thb_cut*thb_cut;
if (atom->nmax > nmax) {
nmax = atom->nmax;
allocate_array();
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::init_md()
{
// init_taper()
F_FLOAT d1, d7, swa, swa2, swa3, swb, swb2, swb3;
swa = control->nonb_low;
swb = control->nonb_cut;
if (fabs(swa) > 0.01 )
error->warning(FLERR,"Warning: non-zero lower Taper-radius cutoff");
if (swb < 0)
error->one(FLERR,"Negative upper Taper-radius cutoff");
else if (swb < 5) {
char str[128];
sprintf(str,"Warning: very low Taper-radius cutoff: %f\n", swb);
error->one(FLERR,str);
}
d1 = swb - swa;
d7 = powint(d1,7);
swa2 = swa * swa;
swa3 = swa * swa2;
swb2 = swb * swb;
swb3 = swb * swb2;
k_tap.h_view(7) = 20.0/d7;
k_tap.h_view(6) = -70.0 * (swa + swb) / d7;
k_tap.h_view(5) = 84.0 * (swa2 + 3.0*swa*swb + swb2) / d7;
k_tap.h_view(4) = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7;
k_tap.h_view(3) = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7;
k_tap.h_view(2) =-210.0 * (swa3*swb2 + swa2*swb3) / d7;
k_tap.h_view(1) = 140.0 * swa3 * swb3 / d7;
k_tap.h_view(0) = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 +
7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7;
k_tap.template modify<LMPHostType>();
k_tap.template sync<DeviceType>();
if ( control->tabulate ) {
int ntypes = atom->ntypes;
Init_Lookup_Tables();
k_LR = tdual_LR_lookup_table_kk_2d("lookup:LR",ntypes+1,ntypes+1);
d_LR = k_LR.template view<DeviceType>();
for (int i = 1; i <= ntypes; ++i) {
for (int j = i; j <= ntypes; ++j) {
int n = LR[i][j].n;
if (n == 0) continue;
k_LR.h_view(i,j).xmin = LR[i][j].xmin;
k_LR.h_view(i,j).xmax = LR[i][j].xmax;
k_LR.h_view(i,j).n = LR[i][j].n;
k_LR.h_view(i,j).dx = LR[i][j].dx;
k_LR.h_view(i,j).inv_dx = LR[i][j].inv_dx;
k_LR.h_view(i,j).a = LR[i][j].a;
k_LR.h_view(i,j).m = LR[i][j].m;
k_LR.h_view(i,j).c = LR[i][j].c;
typename LR_lookup_table_kk<DeviceType>::tdual_LR_data_1d k_y = typename LR_lookup_table_kk<DeviceType>::tdual_LR_data_1d("lookup:LR[i,j].y",n);
typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d k_H = typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d("lookup:LR[i,j].H",n);
typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d k_vdW = typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d("lookup:LR[i,j].vdW",n);
typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d k_CEvd = typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d("lookup:LR[i,j].CEvd",n);
typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d k_ele = typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d("lookup:LR[i,j].ele",n);
typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d k_CEclmb = typename LR_lookup_table_kk<DeviceType>::tdual_cubic_spline_coef_1d("lookup:LR[i,j].CEclmb",n);
k_LR.h_view(i,j).d_y = k_y.template view<DeviceType>();
k_LR.h_view(i,j).d_H = k_H.template view<DeviceType>();
k_LR.h_view(i,j).d_vdW = k_vdW.template view<DeviceType>();
k_LR.h_view(i,j).d_CEvd = k_CEvd.template view<DeviceType>();
k_LR.h_view(i,j).d_ele = k_ele.template view<DeviceType>();
k_LR.h_view(i,j).d_CEclmb = k_CEclmb.template view<DeviceType>();
for (int k = 0; k < n; k++) {
k_y.h_view(k) = LR[i][j].y[k];
k_H.h_view(k) = LR[i][j].H[k];
k_vdW.h_view(k) = LR[i][j].vdW[k];
k_CEvd.h_view(k) = LR[i][j].CEvd[k];
k_ele.h_view(k) = LR[i][j].ele[k];
k_CEclmb.h_view(k) = LR[i][j].CEclmb[k];
}
k_y.template modify<LMPHostType>();
k_H.template modify<LMPHostType>();
k_vdW.template modify<LMPHostType>();
k_CEvd.template modify<LMPHostType>();
k_ele.template modify<LMPHostType>();
k_CEclmb.template modify<LMPHostType>();
k_y.template sync<DeviceType>();
k_H.template sync<DeviceType>();
k_vdW.template sync<DeviceType>();
k_CEvd.template sync<DeviceType>();
k_ele.template sync<DeviceType>();
k_CEclmb.template sync<DeviceType>();
}
}
k_LR.template modify<LMPHostType>();
k_LR.template sync<DeviceType>();
Deallocate_Lookup_Tables();
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
int PairReaxCKokkos<DeviceType>::Init_Lookup_Tables()
{
int i, j, r;
int num_atom_types;
double dr;
double *h, *fh, *fvdw, *fele, *fCEvd, *fCEclmb;
double v0_vdw, v0_ele, vlast_vdw, vlast_ele;
/* initializations */
v0_vdw = 0;
v0_ele = 0;
vlast_vdw = 0;
vlast_ele = 0;
num_atom_types = atom->ntypes;
dr = control->nonb_cut / control->tabulate;
h = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:h", world );
fh = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:fh", world );
fvdw = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:fvdw", world );
fCEvd = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:fCEvd", world );
fele = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:fele", world );
fCEclmb = (double*)
smalloc( (control->tabulate+2) * sizeof(double), "lookup:fCEclmb", world );
LR = (LR_lookup_table**)
scalloc( num_atom_types+1, sizeof(LR_lookup_table*), "lookup:LR", world );
for( i = 0; i < num_atom_types+1; ++i )
LR[i] = (LR_lookup_table*)
scalloc( num_atom_types+1, sizeof(LR_lookup_table), "lookup:LR[i]", world );
for( i = 1; i <= num_atom_types; ++i ) {
for( j = i; j <= num_atom_types; ++j ) {
LR[i][j].xmin = 0;
LR[i][j].xmax = control->nonb_cut;
LR[i][j].n = control->tabulate + 2;
LR[i][j].dx = dr;
LR[i][j].inv_dx = control->tabulate / control->nonb_cut;
LR[i][j].y = (LR_data*)
smalloc( LR[i][j].n * sizeof(LR_data), "lookup:LR[i,j].y", world );
LR[i][j].H = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].H" ,
world );
LR[i][j].vdW = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].vdW",
world);
LR[i][j].CEvd = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].CEvd",
world);
LR[i][j].ele = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),"lookup:LR[i,j].ele",
world );
LR[i][j].CEclmb = (cubic_spline_coef*)
smalloc( LR[i][j].n*sizeof(cubic_spline_coef),
"lookup:LR[i,j].CEclmb", world );
for( r = 1; r <= control->tabulate; ++r ) {
LR_vdW_Coulomb(i, j, r * dr, &(LR[i][j].y[r]) );
h[r] = LR[i][j].dx;
fh[r] = LR[i][j].y[r].H;
fvdw[r] = LR[i][j].y[r].e_vdW;
fCEvd[r] = LR[i][j].y[r].CEvd;
fele[r] = LR[i][j].y[r].e_ele;
fCEclmb[r] = LR[i][j].y[r].CEclmb;
}
// init the start-end points
h[r] = LR[i][j].dx;
v0_vdw = LR[i][j].y[1].CEvd;
v0_ele = LR[i][j].y[1].CEclmb;
fh[r] = fh[r-1];
fvdw[r] = fvdw[r-1];
fCEvd[r] = fCEvd[r-1];
fele[r] = fele[r-1];
fCEclmb[r] = fCEclmb[r-1];
vlast_vdw = fCEvd[r-1];
vlast_ele = fele[r-1];
Natural_Cubic_Spline( &h[1], &fh[1],
&(LR[i][j].H[1]), control->tabulate+1, world );
Complete_Cubic_Spline( &h[1], &fvdw[1], v0_vdw, vlast_vdw,
&(LR[i][j].vdW[1]), control->tabulate+1,
world );
Natural_Cubic_Spline( &h[1], &fCEvd[1],
&(LR[i][j].CEvd[1]), control->tabulate+1,
world );
Complete_Cubic_Spline( &h[1], &fele[1], v0_ele, vlast_ele,
&(LR[i][j].ele[1]), control->tabulate+1,
world );
Natural_Cubic_Spline( &h[1], &fCEclmb[1],
&(LR[i][j].CEclmb[1]), control->tabulate+1,
world );
}// else{
// LR[i][j].n = 0;
//}//
}
free(h);
free(fh);
free(fvdw);
free(fCEvd);
free(fele);
free(fCEclmb);
return 1;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::Deallocate_Lookup_Tables()
{
int i, j;
int ntypes;
ntypes = atom->ntypes;
for( i = 0; i < ntypes; ++i ) {
for( j = i; j < ntypes; ++j )
if( LR[i][j].n ) {
sfree( LR[i][j].y, "LR[i,j].y" );
sfree( LR[i][j].H, "LR[i,j].H" );
sfree( LR[i][j].vdW, "LR[i,j].vdW" );
sfree( LR[i][j].CEvd, "LR[i,j].CEvd" );
sfree( LR[i][j].ele, "LR[i,j].ele" );
sfree( LR[i][j].CEclmb, "LR[i,j].CEclmb" );
}
sfree( LR[i], "LR[i]" );
}
sfree( LR, "LR" );
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::LR_vdW_Coulomb( int i, int j, double r_ij, LR_data *lr )
{
double p_vdW1 = system->reax_param.gp.l[28];
double p_vdW1i = 1.0 / p_vdW1;
double powr_vdW1, powgi_vdW1;
double tmp, fn13, exp1, exp2;
double Tap, dTap, dfn13;
double dr3gamij_1, dr3gamij_3;
double e_core, de_core;
double e_lg, de_lg, r_ij5, r_ij6, re6;
two_body_parameters *twbp;
twbp = &(system->reax_param.tbp[map[i]][map[j]]);
e_core = 0;
de_core = 0;
e_lg = de_lg = 0.0;
/* calculate taper and its derivative */
Tap = k_tap.h_view[7] * r_ij + k_tap.h_view[6];
Tap = Tap * r_ij + k_tap.h_view[5];
Tap = Tap * r_ij + k_tap.h_view[4];
Tap = Tap * r_ij + k_tap.h_view[3];
Tap = Tap * r_ij + k_tap.h_view[2];
Tap = Tap * r_ij + k_tap.h_view[1];
Tap = Tap * r_ij + k_tap.h_view[0];
dTap = 7*k_tap.h_view[7] * r_ij + 6*k_tap.h_view[6];
dTap = dTap * r_ij + 5*k_tap.h_view[5];
dTap = dTap * r_ij + 4*k_tap.h_view[4];
dTap = dTap * r_ij + 3*k_tap.h_view[3];
dTap = dTap * r_ij + 2*k_tap.h_view[2];
dTap += k_tap.h_view[1]/r_ij;
/*vdWaals Calculations*/
if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
{ // shielding
powr_vdW1 = pow(r_ij, p_vdW1);
powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1);
fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i );
exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i-1.0) * pow(r_ij, p_vdW1-2.0);
lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
}
else{ // no shielding
exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) / r_ij;
}
if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
{ // inner wall
e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
lr->e_vdW += Tap * e_core;
de_core = -(twbp->acore/twbp->rcore) * e_core;
lr->CEvd += dTap * e_core + Tap * de_core / r_ij;
// lg correction, only if lgvdw is yes
if (control->lgflag) {
r_ij5 = powint( r_ij, 5 );
r_ij6 = powint( r_ij, 6 );
re6 = powint( twbp->lgre, 6 );
e_lg = -(twbp->lgcij/( r_ij6 + re6 ));
lr->e_vdW += Tap * e_lg;
de_lg = -6.0 * e_lg * r_ij5 / ( r_ij6 + re6 ) ;
lr->CEvd += dTap * e_lg + Tap * de_lg/r_ij;
}
}
/* Coulomb calculations */
dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 );
tmp = Tap / dr3gamij_3;
lr->H = EV_to_KCALpMOL * tmp;
lr->e_ele = C_ele * tmp;
lr->CEclmb = C_ele * ( dTap - Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::compute(int eflag_in, int vflag_in)
{
copymode = 1;
bocnt = hbcnt = 0;
eflag = eflag_in;
vflag = vflag_in;
if (neighflag == FULL) no_virial_fdotr_compute = 1;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
atomKK->sync(execution_space,datamask_read);
k_params_sing.template sync<DeviceType>();
k_params_twbp.template sync<DeviceType>();
k_params_thbp.template sync<DeviceType>();
k_params_fbp.template sync<DeviceType>();
k_params_hbp.template sync<DeviceType>();
if (eflag || vflag) atomKK->modified(execution_space,datamask_modify);
else atomKK->modified(execution_space,F_MASK);
x = atomKK->k_x.view<DeviceType>();
f = atomKK->k_f.view<DeviceType>();
q = atomKK->k_q.view<DeviceType>();
tag = atomKK->k_tag.view<DeviceType>();
type = atomKK->k_type.view<DeviceType>();
nlocal = atomKK->nlocal;
nall = atom->nlocal + atom->nghost;
newton_pair = force->newton_pair;
const int inum = list->inum;
const int ignum = inum + list->gnum;
NeighListKokkos<DeviceType>* k_list = static_cast<NeighListKokkos<DeviceType>*>(list);
d_numneigh = k_list->d_numneigh;
d_neighbors = k_list->d_neighbors;
d_ilist = k_list->d_ilist;
if (eflag_global) {
for (int i = 0; i < 14; i++)
pvector[i] = 0.0;
}
EV_FLOAT_REAX ev;
EV_FLOAT_REAX ev_all;
// Polarization (self)
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputePolar<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputePolar<HALF,0> >(0,inum),*this);
} else { //if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputePolar<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputePolar<HALFTHREAD,0> >(0,inum),*this);
}
ev_all += ev;
pvector[13] = ev.ecoul;
// LJ + Coulomb
if (control->tabulate) {
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<HALF,0> >(0,inum),*this);
} else if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<HALFTHREAD,0> >(0,inum),*this);
} else if (neighflag == FULL) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<FULL,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeTabulatedLJCoulomb<FULL,0> >(0,inum),*this);
}
} else {
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<HALF,0> >(0,inum),*this);
} else if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<HALFTHREAD,0> >(0,inum),*this);
} else if (neighflag == FULL) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<FULL,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeLJCoulomb<FULL,0> >(0,inum),*this);
}
}
ev_all += ev;
pvector[10] = ev.evdwl;
pvector[11] = ev.ecoul;
if (atom->nmax > nmax) {
nmax = atom->nmax;
allocate_array();
}
// Neighbor lists for bond and hbond
// try, resize if necessary
int resize = 1;
while (resize) {
resize = 0;
k_resize_bo.h_view() = 0;
k_resize_bo.modify<LMPHostType>();
k_resize_bo.sync<DeviceType>();
k_resize_hb.h_view() = 0;
k_resize_hb.modify<LMPHostType>();
k_resize_hb.sync<DeviceType>();
// zero
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxZero>(0,nmax),*this);
if (neighflag == HALF)
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBuildListsHalf<HALF> >(0,ignum),*this);
else if (neighflag == HALFTHREAD)
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBuildListsHalf_LessAtomics<HALFTHREAD> >(0,ignum),*this);
else //(neighflag == FULL)
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBuildListsFull>(0,ignum),*this);
k_resize_bo.modify<DeviceType>();
k_resize_bo.sync<LMPHostType>();
int resize_bo = k_resize_bo.h_view();
if (resize_bo) maxbo++;
k_resize_hb.modify<DeviceType>();
k_resize_hb.sync<LMPHostType>();
int resize_hb = k_resize_hb.h_view();
if (resize_hb) maxhb++;
resize = resize_bo || resize_hb;
if (resize) allocate_array();
}
// Bond order
if (neighflag == HALF) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBondOrder1>(0,ignum),*this);
} else if (neighflag == HALFTHREAD) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBondOrder1_LessAtomics>(0,ignum),*this);
}
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBondOrder2>(0,ignum),*this);
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxBondOrder3>(0,ignum),*this);
// Bond energy
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond1<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond1<HALF,0> >(0,inum),*this);
ev_all += ev;
pvector[0] = ev.evdwl;
} else { //if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond1<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond1<HALFTHREAD,0> >(0,inum),*this);
ev_all += ev;
pvector[0] = ev.evdwl;
}
// Multi-body corrections
if (neighflag == HALF) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti1<HALF,0> >(0,inum),*this);
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti2<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti2<HALF,0> >(0,inum),*this);
ev_all += ev;
} else { //if (neighflag == HALFTHREAD) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti1<HALFTHREAD,0> >(0,inum),*this);
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti2<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeMulti2<HALFTHREAD,0> >(0,inum),*this);
ev_all += ev;
}
pvector[2] = ev.ereax[0];
pvector[1] = ev.ereax[1]+ev.ereax[2];
pvector[3] = 0.0;
ev_all.evdwl += ev.ereax[0] + ev.ereax[1] + ev.ereax[2];
// Angular
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeAngular<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeAngular<HALF,0> >(0,inum),*this);
ev_all += ev;
} else { //if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeAngular<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeAngular<HALFTHREAD,0> >(0,inum),*this);
ev_all += ev;
}
pvector[4] = ev.ereax[3];
pvector[5] = ev.ereax[4];
pvector[6] = ev.ereax[5];
ev_all.evdwl += ev.ereax[3] + ev.ereax[4] + ev.ereax[5];
// Torsion
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeTorsion<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeTorsion<HALF,0> >(0,inum),*this);
ev_all += ev;
} else { //if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeTorsion<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeTorsion<HALFTHREAD,0> >(0,inum),*this);
ev_all += ev;
}
pvector[8] = ev.ereax[6];
pvector[9] = ev.ereax[7];
ev_all.evdwl += ev.ereax[6] + ev.ereax[7];
// Hydrogen Bond
if (cut_hbsq > 0.0) {
if (neighflag == HALF) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeHydrogen<HALF,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeHydrogen<HALF,0> >(0,inum),*this);
ev_all += ev;
} else { //if (neighflag == HALFTHREAD) {
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeHydrogen<HALFTHREAD,1> >(0,inum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeHydrogen<HALFTHREAD,0> >(0,inum),*this);
ev_all += ev;
}
}
pvector[7] = ev.ereax[8];
ev_all.evdwl += ev.ereax[8];
// Bond force
if (neighflag == HALF) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxUpdateBond<HALF> >(0,ignum),*this);
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond2<HALF,1> >(0,ignum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond2<HALF,0> >(0,ignum),*this);
ev_all += ev;
pvector[0] += ev.evdwl;
} else { //if (neighflag == HALFTHREAD) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxUpdateBond<HALFTHREAD> >(0,ignum),*this);
if (evflag)
Kokkos::parallel_reduce(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond2<HALFTHREAD,1> >(0,ignum),*this,ev);
else
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxComputeBond2<HALFTHREAD,0> >(0,ignum),*this);
ev_all += ev;
pvector[0] += ev.evdwl;
}
if (eflag_global) {
eng_vdwl += ev_all.evdwl;
eng_coul += ev_all.ecoul;
}
if (vflag_global) {
virial[0] += ev_all.v[0];
virial[1] += ev_all.v[1];
virial[2] += ev_all.v[2];
virial[3] += ev_all.v[3];
virial[4] += ev_all.v[4];
virial[5] += ev_all.v[5];
}
if (vflag_fdotr) pair_virial_fdotr_compute(this);
if (eflag_atom) {
k_eatom.template modify<DeviceType>();
k_eatom.template sync<LMPHostType>();
}
if (vflag_atom) {
k_vatom.template modify<DeviceType>();
k_vatom.template sync<LMPHostType>();
}
if (fixspecies_flag)
FindBondSpecies();
copymode = 0;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputePolar<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
const int i = d_ilist[ii];
const int itype = type(i);
const F_FLOAT qi = q(i);
const F_FLOAT chi = paramssing(itype).chi;
const F_FLOAT eta = paramssing(itype).eta;
const F_FLOAT epol = KCALpMOL_to_EV*(chi*qi+(eta/2.0)*qi*qi);
if (eflag) ev.ecoul += epol;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,i,epol,0.0,0.0,0.0,0.0);
if (eflag_atom) this->template e_tally_single<NEIGHFLAG>(ev,i,epol);
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputePolar<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputePolar<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeLJCoulomb<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
// The f array is atomic for Half/Thread neighbor style
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
F_FLOAT powr_vdw, powgi_vdw, fn13, dfn13, exp1, exp2, etmp;
F_FLOAT evdwl, fvdwl;
evdwl = fvdwl = 0.0;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const F_FLOAT qi = q(i);
const int itype = type(i);
const tagint itag = tag(i);
const int jnum = d_numneigh[i];
F_FLOAT fxtmp, fytmp, fztmp;
fxtmp = fytmp = fztmp = 0.0;
for (int jj = 0; jj < jnum; jj++) {
int j = d_neighbors(i,jj);
j &= NEIGHMASK;
const int jtype = type(j);
const tagint jtag = tag(j);
const F_FLOAT qj = q(j);
if (NEIGHFLAG != FULL) {
// skip half of the interactions
if (j >= nlocal) {
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x(j,2) < ztmp) continue;
if (x(j,2) == ztmp && x(j,1) < ytmp) continue;
if (x(j,2) == ztmp && x(j,1) == ytmp && x(j,0) < xtmp) continue;
}
}
}
const X_FLOAT delx = x(j,0) - xtmp;
const X_FLOAT dely = x(j,1) - ytmp;
const X_FLOAT delz = x(j,2) - ztmp;
const F_FLOAT rsq = delx*delx + dely*dely + delz*delz;
if (rsq > cut_nbsq) continue;
const F_FLOAT rij = sqrt(rsq);
// LJ energy/force
F_FLOAT Tap = d_tap[7] * rij + d_tap[6];
Tap = Tap * rij + d_tap[5];
Tap = Tap * rij + d_tap[4];
Tap = Tap * rij + d_tap[3];
Tap = Tap * rij + d_tap[2];
Tap = Tap * rij + d_tap[1];
Tap = Tap * rij + d_tap[0];
F_FLOAT dTap = 7*d_tap[7] * rij + 6*d_tap[6];
dTap = dTap * rij + 5*d_tap[5];
dTap = dTap * rij + 4*d_tap[4];
dTap = dTap * rij + 3*d_tap[3];
dTap = dTap * rij + 2*d_tap[2];
dTap += d_tap[1]/rij;
const F_FLOAT gamma_w = paramstwbp(itype,jtype).gamma_w;
const F_FLOAT alpha = paramstwbp(itype,jtype).alpha;
const F_FLOAT r_vdw = paramstwbp(itype,jtype).r_vdw;
const F_FLOAT epsilon = paramstwbp(itype,jtype).epsilon;
// shielding
if (vdwflag == 1 || vdwflag == 3) {
powr_vdw = pow(rij,gp[28]);
powgi_vdw = pow(1.0/gamma_w,gp[28]);
fn13 = pow(powr_vdw+powgi_vdw,1.0/gp[28]);
exp1 = exp(alpha*(1.0-fn13/r_vdw));
exp2 = exp(0.5*alpha*(1.0-fn13/r_vdw));
dfn13 = pow(powr_vdw+powgi_vdw,1.0/gp[28]-1.0)*pow(rij,gp[28]-2.0);
etmp = epsilon*(exp1-2.0*exp2);
evdwl = Tap*etmp;
fvdwl = dTap*etmp-Tap*epsilon*(alpha/r_vdw)*(exp1-exp2)*dfn13;
} else {
exp1 = exp(alpha*(1.0-rij/r_vdw));
exp2 = exp(0.5*alpha*(1.0-rij/r_vdw));
etmp = epsilon*(exp1-2.0*exp2);
evdwl = Tap*etmp;
fvdwl = dTap*etmp-Tap*epsilon*(alpha/r_vdw)*(exp1-exp2)*rij;
}
// inner wall
if (vdwflag == 2 || vdwflag == 3) {
const F_FLOAT ecore = paramstwbp(itype,jtype).ecore;
const F_FLOAT acore = paramstwbp(itype,jtype).acore;
const F_FLOAT rcore = paramstwbp(itype,jtype).rcore;
const F_FLOAT e_core = ecore*exp(acore*(1.0-(rij/rcore)));
const F_FLOAT de_core = -(acore/rcore)*e_core;
evdwl += Tap*e_core;
fvdwl += dTap*e_core+Tap*de_core/rij;
if (lgflag) {
const F_FLOAT lgre = paramstwbp(itype,jtype).lgre;
const F_FLOAT lgcij = paramstwbp(itype,jtype).lgcij;
const F_FLOAT rij5 = rsq*rsq*rij;
const F_FLOAT rij6 = rij5*rij;
const F_FLOAT re6 = lgre*lgre*lgre*lgre*lgre*lgre;
const F_FLOAT elg = -lgcij/(rij6+re6);
const F_FLOAT delg = -6.0*elg*rij5/(rij6+re6);
evdwl += Tap*elg;
fvdwl += dTap*elg+Tap*delg/rij;
}
}
// Coulomb energy/force
const F_FLOAT shld = paramstwbp(itype,jtype).gamma;
const F_FLOAT denom1 = rij * rij * rij + shld;
const F_FLOAT denom3 = pow(denom1,0.3333333333333);
const F_FLOAT ecoul = C_ele * qi*qj*Tap/denom3;
const F_FLOAT fcoul = C_ele * qi*qj*(dTap-Tap*rij/denom1)/denom3;
const F_FLOAT ftotal = fvdwl + fcoul;
fxtmp += delx*ftotal;
fytmp += dely*ftotal;
fztmp += delz*ftotal;
if (NEIGHFLAG != FULL) {
a_f(j,0) -= delx*ftotal;
a_f(j,1) -= dely*ftotal;
a_f(j,2) -= delz*ftotal;
}
if (NEIGHFLAG == FULL) {
if (eflag) ev.evdwl += 0.5*evdwl;
if (eflag) ev.ecoul += 0.5*ecoul;
} else {
if (eflag) ev.evdwl += evdwl;
if (eflag) ev.ecoul += ecoul;
}
if (vflag_either || eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,evdwl+ecoul,-ftotal,delx,dely,delz);
}
a_f(i,0) += fxtmp;
a_f(i,1) += fytmp;
a_f(i,2) += fztmp;
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeLJCoulomb<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeLJCoulomb<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeTabulatedLJCoulomb<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
// The f array is atomic for Half/Thread neighbor style
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const F_FLOAT qi = q(i);
const int itype = type(i);
const tagint itag = tag(i);
const int jnum = d_numneigh[i];
F_FLOAT fxtmp, fytmp, fztmp;
fxtmp = fytmp = fztmp = 0.0;
for (int jj = 0; jj < jnum; jj++) {
int j = d_neighbors(i,jj);
j &= NEIGHMASK;
const int jtype = type(j);
const tagint jtag = tag(j);
const F_FLOAT qj = q(j);
if (NEIGHFLAG != FULL) {
// skip half of the interactions
if (j >= nlocal) {
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x(j,2) < ztmp) continue;
if (x(j,2) == ztmp && x(j,1) < ytmp) continue;
if (x(j,2) == ztmp && x(j,1) == ytmp && x(j,0) < xtmp) continue;
}
}
}
const X_FLOAT delx = x(j,0) - xtmp;
const X_FLOAT dely = x(j,1) - ytmp;
const X_FLOAT delz = x(j,2) - ztmp;
const F_FLOAT rsq = delx*delx + dely*dely + delz*delz;
if (rsq > cut_nbsq) continue;
const F_FLOAT rij = sqrt(rsq);
const int tmin = MIN( itype, jtype );
const int tmax = MAX( itype, jtype );
const LR_lookup_table_kk<DeviceType> t = d_LR(tmin,tmax);
/* Cubic Spline Interpolation */
int r = (int)(rij * t.inv_dx);
if( r == 0 ) ++r;
const F_FLOAT base = (double)(r+1) * t.dx;
const F_FLOAT dif = rij - base;
const cubic_spline_coef vdW = t.d_vdW[r];
const cubic_spline_coef ele = t.d_ele[r];
const cubic_spline_coef CEvd = t.d_CEvd[r];
const cubic_spline_coef CEclmb = t.d_CEclmb[r];
const F_FLOAT evdwl = ((vdW.d*dif + vdW.c)*dif + vdW.b)*dif +
vdW.a;
const F_FLOAT ecoul = (((ele.d*dif + ele.c)*dif + ele.b)*dif +
ele.a)*qi*qj;
const F_FLOAT fvdwl = ((CEvd.d*dif + CEvd.c)*dif + CEvd.b)*dif +
CEvd.a;
const F_FLOAT fcoul = (((CEclmb.d*dif+CEclmb.c)*dif+CEclmb.b)*dif +
CEclmb.a)*qi*qj;
const F_FLOAT ftotal = fvdwl + fcoul;
fxtmp += delx*ftotal;
fytmp += dely*ftotal;
fztmp += delz*ftotal;
if (NEIGHFLAG != FULL) {
a_f(j,0) -= delx*ftotal;
a_f(j,1) -= dely*ftotal;
a_f(j,2) -= delz*ftotal;
}
if (NEIGHFLAG == FULL) {
if (eflag) ev.evdwl += 0.5*evdwl;
if (eflag) ev.ecoul += 0.5*ecoul;
} else {
if (eflag) ev.evdwl += evdwl;
if (eflag) ev.ecoul += ecoul;
}
if (vflag_either || eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,evdwl+ecoul,-ftotal,delx,dely,delz);
}
a_f(i,0) += fxtmp;
a_f(i,1) += fytmp;
a_f(i,2) += fztmp;
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeTabulatedLJCoulomb<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeTabulatedLJCoulomb<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::allocate_array()
{
if (cut_hbsq > 0.0) {
d_hb_first = typename AT::t_int_1d("reax/c/kk:hb_first",nmax);
d_hb_num = typename AT::t_int_1d("reax/c/kk:hb_num",nmax);
d_hb_list = typename AT::t_int_1d("reax/c/kk:hb_list",nmax*maxhb);
}
d_bo_first = typename AT::t_int_1d("reax/c/kk:bo_first",nmax);
d_bo_num = typename AT::t_int_1d("reax/c/kk:bo_num",nmax);
d_bo_list = typename AT::t_int_1d("reax/c/kk:bo_list",nmax*maxbo);
d_BO = typename AT::t_ffloat_2d_dl("reax/c/kk:BO",nmax,maxbo);
d_BO_s = typename AT::t_ffloat_2d_dl("reax/c/kk:BO",nmax,maxbo);
d_BO_pi = typename AT::t_ffloat_2d_dl("reax/c/kk:BO_pi",nmax,maxbo);
d_BO_pi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:BO_pi2",nmax,maxbo);
d_dln_BOp_pix = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_pix",nmax,maxbo);
d_dln_BOp_piy = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_piy",nmax,maxbo);
d_dln_BOp_piz = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_piz",nmax,maxbo);
d_dln_BOp_pi2x = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_pi2x",nmax,maxbo);
d_dln_BOp_pi2y = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_pi2y",nmax,maxbo);
d_dln_BOp_pi2z = typename AT::t_ffloat_2d_dl("reax/c/kk:d_dln_BOp_pi2z",nmax,maxbo);
d_C1dbo = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C1dbo",nmax,maxbo);
d_C2dbo = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C2dbo",nmax,maxbo);
d_C3dbo = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C3dbo",nmax,maxbo);
d_C1dbopi = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C1dbopi",nmax,maxbo);
d_C2dbopi = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C2dbopi",nmax,maxbo);
d_C3dbopi = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C3dbopi",nmax,maxbo);
d_C4dbopi = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C4dbopi",nmax,maxbo);
d_C1dbopi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C1dbopi2",nmax,maxbo);
d_C2dbopi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C2dbopi2",nmax,maxbo);
d_C3dbopi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C3dbopi2",nmax,maxbo);
d_C4dbopi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:d_C4dbopi2",nmax,maxbo);
d_dBOpx = typename AT::t_ffloat_2d_dl("reax/c/kk:dBOpx",nmax,maxbo);
d_dBOpy = typename AT::t_ffloat_2d_dl("reax/c/kk:dBOpy",nmax,maxbo);
d_dBOpz = typename AT::t_ffloat_2d_dl("reax/c/kk:dBOpz",nmax,maxbo);
d_dDeltap_self = typename AT::t_ffloat_2d_dl("reax/c/kk:dDeltap_self",nmax,3);
d_Deltap_boc = typename AT::t_ffloat_1d("reax/c/kk:Deltap_boc",nmax);
d_Deltap = typename AT::t_ffloat_1d("reax/c/kk:Deltap",nmax);
d_total_bo = typename AT::t_ffloat_1d("reax/c/kk:total_bo",nmax);
d_Cdbo = typename AT::t_ffloat_2d_dl("reax/c/kk:Cdbo",nmax,3*maxbo);
d_Cdbopi = typename AT::t_ffloat_2d_dl("reax/c/kk:Cdbopi",nmax,3*maxbo);
d_Cdbopi2 = typename AT::t_ffloat_2d_dl("reax/c/kk:Cdbopi2",nmax,3*maxbo);
d_Delta = typename AT::t_ffloat_1d("reax/c/kk:Delta",nmax);
d_Delta_boc = typename AT::t_ffloat_1d("reax/c/kk:Delta_boc",nmax);
d_dDelta_lp = typename AT::t_ffloat_1d("reax/c/kk:dDelta_lp",nmax);
d_Delta_lp = typename AT::t_ffloat_1d("reax/c/kk:Delta_lp",nmax);
d_Delta_lp_temp = typename AT::t_ffloat_1d("reax/c/kk:Delta_lp_temp",nmax);
d_CdDelta = typename AT::t_ffloat_1d("reax/c/kk:CdDelta",nmax);
d_sum_ovun = typename AT::t_ffloat_2d_dl("reax/c/kk:sum_ovun",nmax,3);
// FixReaxCSpecies
if (fixspecies_flag) {
memory->destroy_kokkos(k_tmpid,tmpid);
memory->destroy_kokkos(k_tmpbo,tmpbo);
memory->create_kokkos(k_tmpid,tmpid,nmax,MAXSPECBOND,"pair:tmpid");
memory->create_kokkos(k_tmpbo,tmpbo,nmax,MAXSPECBOND,"pair:tmpbo");
}
// FixReaxCBonds
d_abo = typename AT::t_ffloat_2d("reax/c/kk:abo",nmax,maxbo);
d_neighid = typename AT::t_tagint_2d("reax/c/kk:neighid",nmax,maxbo);
d_numneigh_bonds = typename AT::t_int_1d("reax/c/kk:numneigh_bonds",nmax);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxZero, const int &n) const {
d_total_bo(n) = 0.0;
d_CdDelta(n) = 0.0;
if (neighflag != FULL) {
d_bo_num(n) = 0.0;
d_hb_num(n) = 0.0;
}
for (int j = 0; j < 3; j++)
d_dDeltap_self(n,j) = 0.0;
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxZeroEAtom, const int &i) const {
v_eatom(i) = 0.0;
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxZeroVAtom, const int &i) const {
v_vatom(i,0) = 0.0;
v_vatom(i,1) = 0.0;
v_vatom(i,2) = 0.0;
v_vatom(i,3) = 0.0;
v_vatom(i,4) = 0.0;
v_vatom(i,5) = 0.0;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBuildListsFull, const int &ii) const {
if (d_resize_bo() || d_resize_hb())
return;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const int jnum = d_numneigh[i];
F_FLOAT C12, C34, C56, BO_s, BO_pi, BO_pi2, BO, delij[3], dBOp_i[3], dln_BOp_pi_i[3], dln_BOp_pi2_i[3];
F_FLOAT total_bo = 0.0;
int j_index = i*maxbo;
d_bo_first[i] = j_index;
const int bo_first_i = j_index;
int ihb = -1;
int jhb = -1;
int hb_index = i*maxhb;
int hb_first_i;
if (cut_hbsq > 0.0) {
ihb = paramssing(itype).p_hbond;
if (ihb == 1) {
d_hb_first[i] = hb_index;
hb_first_i = hb_index;
}
}
for (int jj = 0; jj < jnum; jj++) {
int j = d_neighbors(i,jj);
j &= NEIGHMASK;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
double cutoffsq;
if(i < nlocal) cutoffsq = MAX(cut_bosq,cut_hbsq);
else cutoffsq = cut_bosq;
if (rsq > cutoffsq) continue;
const int jtype = type(j);
// hbond list
if (i < nlocal && cut_hbsq > 0.0 && (ihb == 1 || ihb == 2) && rsq <= cut_hbsq) {
jhb = paramssing(jtype).p_hbond;
if( ihb == 1 && jhb == 2) {
const int jj_index = hb_index - hb_first_i;
if (jj_index >= maxhb) {
d_resize_hb() = 1;
return;
}
d_hb_list[hb_index] = j;
hb_index++;
}
}
// bond_list
const F_FLOAT rij = sqrt(rsq);
const F_FLOAT p_bo1 = paramstwbp(itype,jtype).p_bo1;
const F_FLOAT p_bo2 = paramstwbp(itype,jtype).p_bo2;
const F_FLOAT p_bo3 = paramstwbp(itype,jtype).p_bo3;
const F_FLOAT p_bo4 = paramstwbp(itype,jtype).p_bo4;
const F_FLOAT p_bo5 = paramstwbp(itype,jtype).p_bo5;
const F_FLOAT p_bo6 = paramstwbp(itype,jtype).p_bo6;
const F_FLOAT r_s = paramstwbp(itype,jtype).r_s;
const F_FLOAT r_pi = paramstwbp(itype,jtype).r_pi;
const F_FLOAT r_pi2 = paramstwbp(itype,jtype).r_pi2;
if (paramssing(itype).r_s > 0.0 && paramssing(jtype).r_s > 0.0) {
C12 = p_bo1*pow(rij/r_s,p_bo2);
BO_s = (1.0+bo_cut)*exp(C12);
}
else BO_s = C12 = 0.0;
if (paramssing(itype).r_pi > 0.0 && paramssing(jtype).r_pi > 0.0) {
C34 = p_bo3*pow(rij/r_pi,p_bo4);
BO_pi = exp(C34);
}
else BO_pi = C34 = 0.0;
if (paramssing(itype).r_pi2 > 0.0 && paramssing(jtype).r_pi2 > 0.0) {
C56 = p_bo5*pow(rij/r_pi2,p_bo6);
BO_pi2 = exp(C56);
}
else BO_pi2 = C56 = 0.0;
BO = BO_s + BO_pi + BO_pi2;
if (BO < bo_cut) continue;
const int jj_index = j_index - bo_first_i;
if (jj_index >= maxbo) {
d_resize_bo() = 1;
return;
}
d_bo_list[j_index] = j;
// from BondOrder1
d_BO(i,jj_index) = BO;
d_BO_s(i,jj_index) = BO_s;
d_BO_pi(i,jj_index) = BO_pi;
d_BO_pi2(i,jj_index) = BO_pi2;
F_FLOAT Cln_BOp_s = p_bo2 * C12 / rij / rij;
F_FLOAT Cln_BOp_pi = p_bo4 * C34 / rij / rij;
F_FLOAT Cln_BOp_pi2 = p_bo6 * C56 / rij / rij;
if (nlocal == 0)
Cln_BOp_s = Cln_BOp_pi = Cln_BOp_pi2 = 0.0;
for (int d = 0; d < 3; d++) dln_BOp_pi_i[d] = -(BO_pi*Cln_BOp_pi)*delij[d];
for (int d = 0; d < 3; d++) dln_BOp_pi2_i[d] = -(BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) dBOp_i[d] = -(BO_s*Cln_BOp_s+BO_pi*Cln_BOp_pi+BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) d_dDeltap_self(i,d) += dBOp_i[d];
d_dln_BOp_pix(i,jj_index) = dln_BOp_pi_i[0];
d_dln_BOp_piy(i,jj_index) = dln_BOp_pi_i[1];
d_dln_BOp_piz(i,jj_index) = dln_BOp_pi_i[2];
d_dln_BOp_pi2x(i,jj_index) = dln_BOp_pi2_i[0];
d_dln_BOp_pi2y(i,jj_index) = dln_BOp_pi2_i[1];
d_dln_BOp_pi2z(i,jj_index) = dln_BOp_pi2_i[2];
d_dBOpx(i,jj_index) = dBOp_i[0];
d_dBOpy(i,jj_index) = dBOp_i[1];
d_dBOpz(i,jj_index) = dBOp_i[2];
d_BO(i,jj_index) -= bo_cut;
d_BO_s(i,jj_index) -= bo_cut;
total_bo += d_BO(i,jj_index);
j_index++;
}
d_bo_num[i] = j_index - d_bo_first[i];
if (cut_hbsq > 0.0 && ihb == 1) d_hb_num[i] = hb_index - d_hb_first[i];
d_total_bo[i] += total_bo;
const F_FLOAT val_i = paramssing(itype).valency;
d_Deltap[i] = d_total_bo[i] - val_i;
d_Deltap_boc[i] = d_total_bo[i] - paramssing(itype).valency_val;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBuildListsHalf<NEIGHFLAG>, const int &ii) const {
if (d_resize_bo() || d_resize_hb())
return;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_dDeltap_self = d_dDeltap_self;
Kokkos::View<F_FLOAT*, typename DAT::t_float_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_total_bo = d_total_bo;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const tagint itag = tag(i);
const int jnum = d_numneigh[i];
F_FLOAT C12, C34, C56, BO_s, BO_pi, BO_pi2, BO, delij[3], dBOp_i[3], dln_BOp_pi_i[3], dln_BOp_pi2_i[3];
F_FLOAT total_bo = 0.0;
int j_index,i_index;
d_bo_first[i] = i*maxbo;
const int bo_first_i = d_bo_first[i];
int ihb = -1;
int jhb = -1;
int hb_first_i;
if (cut_hbsq > 0.0) {
ihb = paramssing(itype).p_hbond;
if (ihb == 1) {
d_hb_first[i] = i*maxhb;
hb_first_i = d_hb_first[i];
}
}
for (int jj = 0; jj < jnum; jj++) {
int j = d_neighbors(i,jj);
j &= NEIGHMASK;
const tagint jtag = tag(j);
d_bo_first[j] = j*maxbo;
d_hb_first[j] = j*maxhb;
const int jtype = type(j);
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
double cutoffsq;
if(i < nlocal) cutoffsq = MAX(cut_bosq,cut_hbsq);
else cutoffsq = cut_bosq;
if (rsq > cutoffsq) continue;
// hbond list
if (i < nlocal && cut_hbsq > 0.0 && (ihb == 1 || ihb == 2) && rsq <= cut_hbsq) {
jhb = paramssing(jtype).p_hbond;
if( ihb == 1 && jhb == 2) {
if (NEIGHFLAG == HALF) {
j_index = hb_first_i + d_hb_num[i];
d_hb_num[i]++;
} else {
j_index = hb_first_i + Kokkos::atomic_fetch_add(&d_hb_num[i],1);
}
const int jj_index = j_index - hb_first_i;
if (jj_index >= maxhb) {
d_resize_hb() = 1;
return;
}
d_hb_list[j_index] = j;
} else if ( j < nlocal && ihb == 2 && jhb == 1) {
if (NEIGHFLAG == HALF) {
i_index = d_hb_first[j] + d_hb_num[j];
d_hb_num[j]++;
} else {
i_index = d_hb_first[j] + Kokkos::atomic_fetch_add(&d_hb_num[j],1);
}
const int ii_index = i_index - d_hb_first[j];
if (ii_index >= maxhb) {
d_resize_hb() = 1;
return;
}
d_hb_list[i_index] = i;
}
}
// bond_list
const F_FLOAT rij = sqrt(rsq);
const F_FLOAT p_bo1 = paramstwbp(itype,jtype).p_bo1;
const F_FLOAT p_bo2 = paramstwbp(itype,jtype).p_bo2;
const F_FLOAT p_bo3 = paramstwbp(itype,jtype).p_bo3;
const F_FLOAT p_bo4 = paramstwbp(itype,jtype).p_bo4;
const F_FLOAT p_bo5 = paramstwbp(itype,jtype).p_bo5;
const F_FLOAT p_bo6 = paramstwbp(itype,jtype).p_bo6;
const F_FLOAT r_s = paramstwbp(itype,jtype).r_s;
const F_FLOAT r_pi = paramstwbp(itype,jtype).r_pi;
const F_FLOAT r_pi2 = paramstwbp(itype,jtype).r_pi2;
if (paramssing(itype).r_s > 0.0 && paramssing(jtype).r_s > 0.0) {
C12 = p_bo1*pow(rij/r_s,p_bo2);
BO_s = (1.0+bo_cut)*exp(C12);
}
else BO_s = C12 = 0.0;
if (paramssing(itype).r_pi > 0.0 && paramssing(jtype).r_pi > 0.0) {
C34 = p_bo3*pow(rij/r_pi,p_bo4);
BO_pi = exp(C34);
}
else BO_pi = C34 = 0.0;
if (paramssing(itype).r_pi2 > 0.0 && paramssing(jtype).r_pi2 > 0.0) {
C56 = p_bo5*pow(rij/r_pi2,p_bo6);
BO_pi2 = exp(C56);
}
else BO_pi2 = C56 = 0.0;
BO = BO_s + BO_pi + BO_pi2;
if (BO < bo_cut) continue;
if (NEIGHFLAG == HALF) {
j_index = bo_first_i + d_bo_num[i];
i_index = d_bo_first[j] + d_bo_num[j];
d_bo_num[i]++;
d_bo_num[j]++;
} else {
j_index = bo_first_i + Kokkos::atomic_fetch_add(&d_bo_num[i],1);
i_index = d_bo_first[j] + Kokkos::atomic_fetch_add(&d_bo_num[j],1);
}
const int jj_index = j_index - bo_first_i;
const int ii_index = i_index - d_bo_first[j];
if (jj_index >= maxbo || ii_index >= maxbo) {
d_resize_bo() = 1;
return;
}
d_bo_list[j_index] = j;
d_bo_list[i_index] = i;
// from BondOrder1
d_BO(i,jj_index) = BO;
d_BO_s(i,jj_index) = BO_s;
d_BO_pi(i,jj_index) = BO_pi;
d_BO_pi2(i,jj_index) = BO_pi2;
d_BO(j,ii_index) = BO;
d_BO_s(j,ii_index) = BO_s;
d_BO_pi(j,ii_index) = BO_pi;
d_BO_pi2(j,ii_index) = BO_pi2;
F_FLOAT Cln_BOp_s = p_bo2 * C12 / rij / rij;
F_FLOAT Cln_BOp_pi = p_bo4 * C34 / rij / rij;
F_FLOAT Cln_BOp_pi2 = p_bo6 * C56 / rij / rij;
if (nlocal == 0)
Cln_BOp_s = Cln_BOp_pi = Cln_BOp_pi2 = 0.0;
for (int d = 0; d < 3; d++) dln_BOp_pi_i[d] = -(BO_pi*Cln_BOp_pi)*delij[d];
for (int d = 0; d < 3; d++) dln_BOp_pi2_i[d] = -(BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) dBOp_i[d] = -(BO_s*Cln_BOp_s+BO_pi*Cln_BOp_pi+BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) a_dDeltap_self(i,d) += dBOp_i[d];
for (int d = 0; d < 3; d++) a_dDeltap_self(j,d) += -dBOp_i[d];
d_dln_BOp_pix(i,jj_index) = dln_BOp_pi_i[0];
d_dln_BOp_piy(i,jj_index) = dln_BOp_pi_i[1];
d_dln_BOp_piz(i,jj_index) = dln_BOp_pi_i[2];
d_dln_BOp_pix(j,ii_index) = -dln_BOp_pi_i[0];
d_dln_BOp_piy(j,ii_index) = -dln_BOp_pi_i[1];
d_dln_BOp_piz(j,ii_index) = -dln_BOp_pi_i[2];
d_dln_BOp_pi2x(i,jj_index) = dln_BOp_pi2_i[0];
d_dln_BOp_pi2y(i,jj_index) = dln_BOp_pi2_i[1];
d_dln_BOp_pi2z(i,jj_index) = dln_BOp_pi2_i[2];
d_dln_BOp_pi2x(j,ii_index) = -dln_BOp_pi2_i[0];
d_dln_BOp_pi2y(j,ii_index) = -dln_BOp_pi2_i[1];
d_dln_BOp_pi2z(j,ii_index) = -dln_BOp_pi2_i[2];
d_dBOpx(i,jj_index) = dBOp_i[0];
d_dBOpy(i,jj_index) = dBOp_i[1];
d_dBOpz(i,jj_index) = dBOp_i[2];
d_dBOpx(j,ii_index) = -dBOp_i[0];
d_dBOpy(j,ii_index) = -dBOp_i[1];
d_dBOpz(j,ii_index) = -dBOp_i[2];
d_BO(i,jj_index) -= bo_cut;
d_BO(j,ii_index) -= bo_cut;
d_BO_s(i,jj_index) -= bo_cut;
d_BO_s(j,ii_index) -= bo_cut;
total_bo += d_BO(i,jj_index);
a_total_bo[j] += d_BO(j,ii_index);
}
a_total_bo[i] += total_bo;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBondOrder1, const int &ii) const {
const int i = d_ilist[ii];
const int itype = type(i);
const F_FLOAT val_i = paramssing(itype).valency;
d_Deltap[i] = d_total_bo[i] - val_i;
d_Deltap_boc[i] = d_total_bo[i] - paramssing(itype).valency_val;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBuildListsHalf_LessAtomics<NEIGHFLAG>, const int &ii) const {
if (d_resize_bo() || d_resize_hb())
return;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const tagint itag = tag(i);
const int jnum = d_numneigh[i];
F_FLOAT C12, C34, C56, BO_s, BO_pi, BO_pi2, BO, delij[3];
int j_index,i_index;
d_bo_first[i] = i*maxbo;
const int bo_first_i = d_bo_first[i];
int ihb = -1;
int jhb = -1;
int hb_first_i;
if (cut_hbsq > 0.0) {
ihb = paramssing(itype).p_hbond;
if (ihb == 1) {
d_hb_first[i] = i*maxhb;
hb_first_i = d_hb_first[i];
}
}
for (int jj = 0; jj < jnum; jj++) {
int j = d_neighbors(i,jj);
j &= NEIGHMASK;
const tagint jtag = tag(j);
d_bo_first[j] = j*maxbo;
d_hb_first[j] = j*maxhb;
const int jtype = type(j);
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
double cutoffsq;
if(i < nlocal) cutoffsq = MAX(cut_bosq,cut_hbsq);
else cutoffsq = cut_bosq;
if (rsq > cutoffsq) continue;
// hbond list
if (i < nlocal && cut_hbsq > 0.0 && (ihb == 1 || ihb == 2) && rsq <= cut_hbsq) {
jhb = paramssing(jtype).p_hbond;
if( ihb == 1 && jhb == 2) {
if (NEIGHFLAG == HALF) {
j_index = hb_first_i + d_hb_num[i];
d_hb_num[i]++;
} else {
j_index = hb_first_i + Kokkos::atomic_fetch_add(&d_hb_num[i],1);
}
const int jj_index = j_index - hb_first_i;
if (jj_index >= maxhb) {
d_resize_hb() = 1;
return;
}
d_hb_list[j_index] = j;
} else if ( j < nlocal && ihb == 2 && jhb == 1) {
if (NEIGHFLAG == HALF) {
i_index = d_hb_first[j] + d_hb_num[j];
d_hb_num[j]++;
} else {
i_index = d_hb_first[j] + Kokkos::atomic_fetch_add(&d_hb_num[j],1);
}
const int ii_index = i_index - d_hb_first[j];
if (ii_index >= maxhb) {
d_resize_hb() = 1;
return;
}
d_hb_list[i_index] = i;
}
}
// bond_list
const F_FLOAT rij = sqrt(rsq);
const F_FLOAT p_bo1 = paramstwbp(itype,jtype).p_bo1;
const F_FLOAT p_bo2 = paramstwbp(itype,jtype).p_bo2;
const F_FLOAT p_bo3 = paramstwbp(itype,jtype).p_bo3;
const F_FLOAT p_bo4 = paramstwbp(itype,jtype).p_bo4;
const F_FLOAT p_bo5 = paramstwbp(itype,jtype).p_bo5;
const F_FLOAT p_bo6 = paramstwbp(itype,jtype).p_bo6;
const F_FLOAT r_s = paramstwbp(itype,jtype).r_s;
const F_FLOAT r_pi = paramstwbp(itype,jtype).r_pi;
const F_FLOAT r_pi2 = paramstwbp(itype,jtype).r_pi2;
if (paramssing(itype).r_s > 0.0 && paramssing(jtype).r_s > 0.0) {
C12 = p_bo1*pow(rij/r_s,p_bo2);
BO_s = (1.0+bo_cut)*exp(C12);
}
else BO_s = C12 = 0.0;
if (paramssing(itype).r_pi > 0.0 && paramssing(jtype).r_pi > 0.0) {
C34 = p_bo3*pow(rij/r_pi,p_bo4);
BO_pi = exp(C34);
}
else BO_pi = C34 = 0.0;
if (paramssing(itype).r_pi2 > 0.0 && paramssing(jtype).r_pi2 > 0.0) {
C56 = p_bo5*pow(rij/r_pi2,p_bo6);
BO_pi2 = exp(C56);
}
else BO_pi2 = C56 = 0.0;
BO = BO_s + BO_pi + BO_pi2;
if (BO < bo_cut) continue;
if (NEIGHFLAG == HALF) {
j_index = bo_first_i + d_bo_num[i];
i_index = d_bo_first[j] + d_bo_num[j];
d_bo_num[i]++;
d_bo_num[j]++;
} else {
j_index = bo_first_i + Kokkos::atomic_fetch_add(&d_bo_num[i],1);
i_index = d_bo_first[j] + Kokkos::atomic_fetch_add(&d_bo_num[j],1);
}
const int jj_index = j_index - bo_first_i;
const int ii_index = i_index - d_bo_first[j];
if (jj_index >= maxbo || ii_index >= maxbo) {
d_resize_bo() = 1;
return;
}
d_bo_list[j_index] = j;
d_bo_list[i_index] = i;
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBondOrder1_LessAtomics, const int &ii) const {
F_FLOAT C12, C34, C56, BO_s, BO_pi, BO_pi2, BO, delij[3], dBOp_i[3], dln_BOp_pi_i[3], dln_BOp_pi2_i[3];
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT total_bo = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsq);
const int jtype = type(j);
const int j_index = jj - j_start;
// calculate uncorrected BO and total bond order
const F_FLOAT p_bo1 = paramstwbp(itype,jtype).p_bo1;
const F_FLOAT p_bo2 = paramstwbp(itype,jtype).p_bo2;
const F_FLOAT p_bo3 = paramstwbp(itype,jtype).p_bo3;
const F_FLOAT p_bo4 = paramstwbp(itype,jtype).p_bo4;
const F_FLOAT p_bo5 = paramstwbp(itype,jtype).p_bo5;
const F_FLOAT p_bo6 = paramstwbp(itype,jtype).p_bo6;
const F_FLOAT r_s = paramstwbp(itype,jtype).r_s;
const F_FLOAT r_pi = paramstwbp(itype,jtype).r_pi;
const F_FLOAT r_pi2 = paramstwbp(itype,jtype).r_pi2;
if (paramssing(itype).r_s > 0.0 && paramssing(jtype).r_s > 0.0) {
C12 = p_bo1*pow(rij/r_s,p_bo2);
BO_s = (1.0+bo_cut)*exp(C12);
}
else BO_s = C12 = 0.0;
if (paramssing(itype).r_pi > 0.0 && paramssing(jtype).r_pi > 0.0) {
C34 = p_bo3*pow(rij/r_pi,p_bo4);
BO_pi = exp(C34);
}
else BO_pi = C34 = 0.0;
if (paramssing(itype).r_pi2 > 0.0 && paramssing(jtype).r_pi2 > 0.0) {
C56 = p_bo5*pow(rij/r_pi2,p_bo6);
BO_pi2 = exp(C56);
}
else BO_pi2 = C56 = 0.0;
BO = BO_s + BO_pi + BO_pi2;
if (BO < bo_cut) continue;
d_BO(i,j_index) = BO;
d_BO_s(i,j_index) = BO;
d_BO_pi(i,j_index) = BO_pi;
d_BO_pi2(i,j_index) = BO_pi2;
F_FLOAT Cln_BOp_s = p_bo2 * C12 / rij / rij;
F_FLOAT Cln_BOp_pi = p_bo4 * C34 / rij / rij;
F_FLOAT Cln_BOp_pi2 = p_bo6 * C56 / rij / rij;
if (nlocal == 0)
Cln_BOp_s = Cln_BOp_pi = Cln_BOp_pi2 = 0.0;
for (int d = 0; d < 3; d++) dln_BOp_pi_i[d] = -(BO_pi*Cln_BOp_pi)*delij[d];
for (int d = 0; d < 3; d++) dln_BOp_pi2_i[d] = -(BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) dBOp_i[d] = -(BO_s*Cln_BOp_s+BO_pi*Cln_BOp_pi+BO_pi2*Cln_BOp_pi2)*delij[d];
for (int d = 0; d < 3; d++) d_dDeltap_self(i,d) += dBOp_i[d];
d_dln_BOp_pix(i,j_index) = dln_BOp_pi_i[0];
d_dln_BOp_piy(i,j_index) = dln_BOp_pi_i[1];
d_dln_BOp_piz(i,j_index) = dln_BOp_pi_i[2];
d_dln_BOp_pi2x(i,j_index) = dln_BOp_pi2_i[0];
d_dln_BOp_pi2y(i,j_index) = dln_BOp_pi2_i[1];
d_dln_BOp_pi2z(i,j_index) = dln_BOp_pi2_i[2];
d_dBOpx(i,j_index) = dBOp_i[0];
d_dBOpy(i,j_index) = dBOp_i[1];
d_dBOpz(i,j_index) = dBOp_i[2];
d_BO(i,j_index) -= bo_cut;
d_BO_s(i,j_index) -= bo_cut;
total_bo += d_BO(i,j_index);
}
d_total_bo[i] += total_bo;
const F_FLOAT val_i = paramssing(itype).valency;
d_Deltap[i] = d_total_bo[i] - val_i;
d_Deltap_boc[i] = d_total_bo[i] - paramssing(itype).valency_val;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBondOrder2, const int &ii) const {
F_FLOAT delij[3];
F_FLOAT exp_p1i, exp_p2i, exp_p1j, exp_p2j, f1, f2, f3, u1_ij, u1_ji, Cf1A_ij, Cf1B_ij, Cf1_ij, Cf1_ji;
F_FLOAT f4, f5, exp_f4, exp_f5, f4f5, Cf45_ij, Cf45_ji;
F_FLOAT A0_ij, A1_ij, A2_ij, A3_ij, A2_ji, A3_ji;
const int i = d_ilist[ii];
const int itype = type(i);
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const F_FLOAT val_i = paramssing(itype).valency;
d_total_bo[i] = 0.0;
F_FLOAT total_bo = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsq);
const int jtype = type(j);
const int j_index = jj - j_start;
const int i_index = maxbo+j_index;
// calculate corrected BO and total bond order
const F_FLOAT val_j = paramssing(jtype).valency;
const F_FLOAT ovc = paramstwbp(itype,jtype).ovc;
const F_FLOAT v13cor = paramstwbp(itype,jtype).v13cor;
const F_FLOAT p_boc3 = paramstwbp(itype,jtype).p_boc3;
const F_FLOAT p_boc4 = paramstwbp(itype,jtype).p_boc4;
const F_FLOAT p_boc5 = paramstwbp(itype,jtype).p_boc5;
if (ovc < 0.001 && v13cor < 0.001) {
d_C1dbo(i,j_index) = 1.0;
d_C2dbo(i,j_index) = 0.0;
d_C3dbo(i,j_index) = 0.0;
d_C1dbopi(i,j_index) = d_BO_pi(i,j_index);
d_C2dbopi(i,j_index) = 0.0;
d_C3dbopi(i,j_index) = 0.0;
d_C4dbopi(i,j_index) = 0.0;
d_C1dbopi2(i,j_index) = d_BO_pi(i,j_index);
d_C2dbopi2(i,j_index) = 0.0;
d_C3dbopi2(i,j_index) = 0.0;
d_C4dbopi2(i,j_index) = 0.0;
} else {
if (ovc >= 0.001) {
exp_p1i = exp(-p_boc1 * d_Deltap[i]);
exp_p2i = exp(-p_boc2 * d_Deltap[i]);
exp_p1j = exp(-p_boc1 * d_Deltap[j]);
exp_p2j = exp(-p_boc2 * d_Deltap[j]);
f2 = exp_p1i + exp_p1j;
f3 = -1.0/p_boc2*log(0.5*(exp_p2i+exp_p2j));
f1 = 0.5 * ((val_i + f2)/(val_i + f2 + f3) + (val_j + f2)/(val_j + f2 + f3));
u1_ij = val_i + f2 + f3;
u1_ji = val_j + f2 + f3;
Cf1A_ij = 0.5 * f3 * (1.0/(u1_ij*u1_ij)+1.0/(u1_ji*u1_ji));
Cf1B_ij = -0.5 * ((u1_ij - f3)/(u1_ij*u1_ij)+(u1_ji - f3)/(u1_ji*u1_ji));
Cf1_ij = 0.5 * (-p_boc1 * exp_p1i / u1_ij - ((val_i+f2) / (u1_ij*u1_ij)) *
(-p_boc1 * exp_p1i + exp_p2i / (exp_p2i + exp_p2j)) +
-p_boc1 * exp_p1i / u1_ji - ((val_j+f2) / (u1_ji*u1_ji)) *
(-p_boc1 * exp_p1i + exp_p2i / (exp_p2i + exp_p2j)));
Cf1_ji = -Cf1A_ij * p_boc1 * exp_p1j + Cf1B_ij * exp_p2j / ( exp_p2i + exp_p2j );
} else {
f1 = 1.0;
Cf1_ij = Cf1_ji = 0.0;
}
if (v13cor >= 0.001) {
exp_f4 =exp(-(p_boc4*(d_BO(i,j_index)*d_BO(i,j_index))-d_Deltap_boc[i])*p_boc3+p_boc5);
exp_f5 =exp(-(p_boc4*(d_BO(i,j_index)*d_BO(i,j_index))-d_Deltap_boc[j])*p_boc3+p_boc5);
f4 = 1. / (1. + exp_f4);
f5 = 1. / (1. + exp_f5);
f4f5 = f4 * f5;
Cf45_ij = -f4 * exp_f4;
Cf45_ji = -f5 * exp_f5;
} else {
f4 = f5 = f4f5 = 1.0;
Cf45_ij = Cf45_ji = 0.0;
}
A0_ij = f1 * f4f5;
A1_ij = -2 * p_boc3 * p_boc4 * d_BO(i,j_index) * (Cf45_ij + Cf45_ji);
A2_ij = Cf1_ij / f1 + p_boc3 * Cf45_ij;
A2_ji = Cf1_ji / f1 + p_boc3 * Cf45_ji;
A3_ij = A2_ij + Cf1_ij / f1;
A3_ji = A2_ji + Cf1_ji / f1;
d_BO(i,j_index) = d_BO(i,j_index) * A0_ij;
d_BO_pi(i,j_index) = d_BO_pi(i,j_index) * A0_ij * f1;
d_BO_pi2(i,j_index) = d_BO_pi2(i,j_index) * A0_ij * f1;
d_BO_s(i,j_index) = d_BO(i,j_index)-(d_BO_pi(i,j_index)+d_BO_pi2(i,j_index));
d_C1dbo(i,j_index) = A0_ij + d_BO(i,j_index) * A1_ij;
d_C2dbo(i,j_index) = d_BO(i,j_index) * A2_ij;
d_C3dbo(i,j_index) = d_BO(i,j_index) * A2_ji;
d_C1dbopi(i,j_index) = f1*f1*f4*f5;
d_C2dbopi(i,j_index) = d_BO_pi(i,j_index) * A1_ij;
d_C3dbopi(i,j_index) = d_BO_pi(i,j_index) * A3_ij;
d_C4dbopi(i,j_index) = d_BO_pi(i,j_index) * A3_ji;
d_C1dbopi2(i,j_index) = f1*f1*f4*f5;
d_C2dbopi2(i,j_index) = d_BO_pi2(i,j_index) * A1_ij;
d_C3dbopi2(i,j_index) = d_BO_pi2(i,j_index) * A3_ij;
d_C4dbopi2(i,j_index) = d_BO_pi2(i,j_index) * A3_ji;
}
if(d_BO(i,j_index) < 1e-10) d_BO(i,j_index) = 0.0;
if(d_BO_s(i,j_index) < 1e-10) d_BO_s(i,j_index) = 0.0;
if(d_BO_pi(i,j_index) < 1e-10) d_BO_pi(i,j_index) = 0.0;
if(d_BO_pi2(i,j_index) < 1e-10) d_BO_pi2(i,j_index) = 0.0;
total_bo += d_BO(i,j_index);
d_Cdbo(i,j_index) = 0.0;
d_Cdbopi(i,j_index) = 0.0;
d_Cdbopi2(i,j_index) = 0.0;
d_Cdbo(j,i_index) = 0.0;
d_Cdbopi(j,i_index) = 0.0;
d_Cdbopi2(j,i_index) = 0.0;
d_CdDelta[j] = 0.0;
}
d_CdDelta[i] = 0.0;
d_total_bo[i] += total_bo;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxBondOrder3, const int &ii) const {
// bot part of BO()
const int i = d_ilist[ii];
const int itype = type(i);
F_FLOAT nlp_temp;
d_Delta[i] = d_total_bo[i] - paramssing(itype).valency;
const F_FLOAT Delta_e = d_total_bo[i] - paramssing(itype).valency_e;
d_Delta_boc[i] = d_total_bo[i] - paramssing(itype).valency_boc;
const F_FLOAT vlpex = Delta_e - 2.0 * (int)(Delta_e/2.0);
const F_FLOAT explp1 = exp(-gp[15] * SQR(2.0 + vlpex));
const F_FLOAT nlp = explp1 - (int)(Delta_e / 2.0);
d_Delta_lp[i] = paramssing(itype).nlp_opt - nlp;
const F_FLOAT Clp = 2.0 * gp[15] * explp1 * (2.0 + vlpex);
d_dDelta_lp[i] = Clp;
if( paramssing(itype).mass > 21.0 ) {
nlp_temp = 0.5 * (paramssing(itype).valency_e - paramssing(itype).valency);
d_Delta_lp_temp[i] = paramssing(itype).nlp_opt - nlp_temp;
} else {
nlp_temp = nlp;
d_Delta_lp_temp[i] = paramssing(itype).nlp_opt - nlp_temp;
}
d_sum_ovun(i,1) = 0.0;
d_sum_ovun(i,2) = 0.0;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeMulti1<NEIGHFLAG,EVFLAG>, const int &ii) const {
const int i = d_ilist[ii];
const int itype = type(i);
const F_FLOAT imass = paramssing(itype).mass;
F_FLOAT dfvl;
if (imass > 21.0) dfvl = 0.0;
else dfvl = 1.0;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT sum_ovun1 = 0.0;
F_FLOAT sum_ovun2 = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const int jtype = type(j);
const int j_index = jj - j_start;
sum_ovun1 += paramstwbp(itype,jtype).p_ovun1 * paramstwbp(itype,jtype).De_s * d_BO(i,j_index);
sum_ovun2 += (d_Delta[j] - dfvl * d_Delta_lp_temp[j]) * (d_BO_pi(i,j_index) + d_BO_pi2(i,j_index));
}
d_sum_ovun(i,1) += sum_ovun1;
d_sum_ovun(i,2) += sum_ovun2;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeMulti2<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*, typename DAT::t_float_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_CdDelta = d_CdDelta;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbo = d_Cdbo;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbopi = d_Cdbopi;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbopi2 = d_Cdbopi2;
const int i = d_ilist[ii];
const int itype = type(i);
const F_FLOAT imass = paramssing(itype).mass;
const F_FLOAT val_i = paramssing(itype).valency;
F_FLOAT dfvl;
if (imass > 21.0) dfvl = 0.0;
else dfvl = 1.0;
F_FLOAT e_lp, e_ov, e_un;
F_FLOAT CEover1, CEover2, CEover3, CEover4;
F_FLOAT CEunder1, CEunder2, CEunder3, CEunder4;
const F_FLOAT p_lp3 = gp[5];
const F_FLOAT p_ovun2 = paramssing(itype).p_ovun2;
const F_FLOAT p_ovun3 = gp[32];
const F_FLOAT p_ovun4 = gp[31];
const F_FLOAT p_ovun5 = paramssing(itype).p_ovun5;
const F_FLOAT p_ovun6 = gp[6];
const F_FLOAT p_ovun7 = gp[8];
const F_FLOAT p_ovun8 = gp[9];
// lone pair
const F_FLOAT p_lp2 = paramssing(itype).p_lp2;
const F_FLOAT expvd2 = exp( -75 * d_Delta_lp[i]);
const F_FLOAT inv_expvd2 = 1.0 / (1.0+expvd2);
int numbonds = d_bo_num[i];
e_lp = 0.0;
if (numbonds > 0 || control->enobondsflag)
e_lp = p_lp2 * d_Delta_lp[i] * inv_expvd2;
const F_FLOAT dElp = p_lp2 * inv_expvd2 + 75.0 * p_lp2 * d_Delta_lp[i] * expvd2 * inv_expvd2*inv_expvd2;
const F_FLOAT CElp = dElp * d_dDelta_lp[i];
if (numbonds > 0 || control->enobondsflag)
a_CdDelta[i] += CElp;
if (eflag) ev.ereax[0] += e_lp;
//if (vflag_either || eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,i,e_lp,0.0,0.0,0.0,0.0);
//if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,i,e_lp);
// over coordination
const F_FLOAT exp_ovun1 = p_ovun3 * exp( p_ovun4 * d_sum_ovun(i,2) );
const F_FLOAT inv_exp_ovun1 = 1.0 / (1 + exp_ovun1);
const F_FLOAT Delta_lpcorr = d_Delta[i] - (dfvl * d_Delta_lp_temp[i]) * inv_exp_ovun1;
const F_FLOAT exp_ovun2 = exp( p_ovun2 * Delta_lpcorr );
const F_FLOAT inv_exp_ovun2 = 1.0 / (1.0 + exp_ovun2);
const F_FLOAT DlpVi = 1.0 / (Delta_lpcorr + val_i + 1e-8);
CEover1 = Delta_lpcorr * DlpVi * inv_exp_ovun2;
e_ov = d_sum_ovun(i,1) * CEover1;
if (eflag) ev.ereax[1] += e_ov;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,i,e_ov,0.0,0.0,0.0,0.0);
//if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,i,e_ov);
CEover2 = d_sum_ovun(i,1) * DlpVi * inv_exp_ovun2 *
(1.0 - Delta_lpcorr * ( DlpVi + p_ovun2 * exp_ovun2 * inv_exp_ovun2 ));
CEover3 = CEover2 * (1.0 - dfvl * d_dDelta_lp[i] * inv_exp_ovun1 );
CEover4 = CEover2 * (dfvl * d_Delta_lp_temp[i]) * p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1);
// under coordination
const F_FLOAT exp_ovun2n = 1.0 / exp_ovun2;
const F_FLOAT exp_ovun6 = exp( p_ovun6 * Delta_lpcorr );
const F_FLOAT exp_ovun8 = p_ovun7 * exp(p_ovun8 * d_sum_ovun(i,2));
const F_FLOAT inv_exp_ovun2n = 1.0 / (1.0 + exp_ovun2n);
const F_FLOAT inv_exp_ovun8 = 1.0 / (1.0 + exp_ovun8);
e_un = 0;
if (numbonds > 0 || control->enobondsflag)
e_un = -p_ovun5 * (1.0 - exp_ovun6) * inv_exp_ovun2n * inv_exp_ovun8;
if (eflag) ev.ereax[2] += e_un;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,i,e_un,0.0,0.0,0.0,0.0);
//if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,i,e_un);
CEunder1 = inv_exp_ovun2n *
( p_ovun5 * p_ovun6 * exp_ovun6 * inv_exp_ovun8 + p_ovun2 * e_un * exp_ovun2n );
CEunder2 = -e_un * p_ovun8 * exp_ovun8 * inv_exp_ovun8;
CEunder3 = CEunder1 * (1.0 - dfvl * d_dDelta_lp[i] * inv_exp_ovun1);
CEunder4 = CEunder1 * (dfvl * d_Delta_lp_temp[i]) *
p_ovun4 * exp_ovun1 * inv_exp_ovun1 * inv_exp_ovun1 + CEunder2;
const F_FLOAT eng_tmp = e_lp + e_ov + e_un;
if (eflag_atom) this->template e_tally_single<NEIGHFLAG>(ev,i,eng_tmp);
// multibody forces
a_CdDelta[i] += CEover3;
if (numbonds > 0 || control->enobondsflag)
a_CdDelta[i] += CEunder3;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT CdDelta_i = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const int jtype = type(j);
const F_FLOAT jmass = paramssing(jtype).mass;
const int j_index = jj - j_start;
const F_FLOAT De_s = paramstwbp(itype,jtype).De_s;
// multibody lone pair: correction for C2
if (p_lp3 > 0.001 && imass == 12.0 && jmass == 12.0) {
const F_FLOAT Di = d_Delta[i];
const F_FLOAT vov3 = d_BO(i,j_index) - Di - 0.040*pow(Di,4.0);
if (vov3 > 3.0) {
const F_FLOAT e_lph = p_lp3 * (vov3-3.0)*(vov3-3.0);
const F_FLOAT deahu2dbo = 2.0 * p_lp3 * (vov3 - 3.0);
const F_FLOAT deahu2dsbo = 2.0 * p_lp3 * (vov3 - 3.0) * (-1.0 - 0.16 * pow(Di,3.0));
d_Cdbo(i,j_index) += deahu2dbo;
CdDelta_i += deahu2dsbo;
if (eflag) ev.ereax[0] += e_lph;
if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,e_lph);
}
}
// over/under coordination forces merged together
const F_FLOAT p_ovun1 = paramstwbp(itype,jtype).p_ovun1;
a_CdDelta[j] += (CEover4 + CEunder4) * (1.0 - dfvl * d_dDelta_lp[j]) * (d_BO_pi(i,j_index) + d_BO_pi2(i,j_index));
d_Cdbo(i,j_index) += CEover1 * p_ovun1 * De_s;
d_Cdbopi(i,j_index) += (CEover4 + CEunder4) * (d_Delta[j] - dfvl*d_Delta_lp_temp[j]);
d_Cdbopi2(i,j_index) += (CEover4 + CEunder4) * (d_Delta[j] - dfvl*d_Delta_lp_temp[j]);
}
a_CdDelta[i] += CdDelta_i;
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeMulti2<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeMulti2<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeAngular<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbo = d_Cdbo;
Kokkos::View<F_FLOAT*, typename DAT::t_float_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_CdDelta = d_CdDelta;
const int i = d_ilist[ii];
const int itype = type(i);
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
F_FLOAT temp, temp_bo_jt, pBOjt7;
F_FLOAT p_val1, p_val2, p_val3, p_val4, p_val5;
F_FLOAT p_val6, p_val7, p_val8, p_val9, p_val10;
F_FLOAT p_pen1, p_pen2, p_pen3, p_pen4;
F_FLOAT p_coa1, p_coa2, p_coa3, p_coa4;
F_FLOAT trm8, expval6, expval7, expval2theta, expval12theta, exp3ij, exp3jk;
F_FLOAT exp_pen2ij, exp_pen2jk, exp_pen3, exp_pen4, trm_pen34, exp_coa2;
F_FLOAT dSBO1, dSBO2, SBO, SBO2, CSBO2, SBOp, prod_SBO, vlpadj;
F_FLOAT CEval1, CEval2, CEval3, CEval4, CEval5, CEval6, CEval7, CEval8;
F_FLOAT CEpen1, CEpen2, CEpen3;
F_FLOAT e_ang, e_coa, e_pen;
F_FLOAT CEcoa1, CEcoa2, CEcoa3, CEcoa4, CEcoa5;
F_FLOAT Cf7ij, Cf7jk, Cf8j, Cf9j;
F_FLOAT f7_ij, f7_jk, f8_Dj, f9_Dj;
F_FLOAT Ctheta_0, theta_0, theta_00, theta, cos_theta, sin_theta;
F_FLOAT BOA_ij, BOA_ik, rij, bo_ij, bo_ik;
F_FLOAT dcos_theta_di[3], dcos_theta_dj[3], dcos_theta_dk[3];
F_FLOAT eng_tmp, fi_tmp[3], fj_tmp[3], fk_tmp[3];
F_FLOAT delij[3], delik[3], delji[3], delki[3];
p_val6 = gp[14];
p_val8 = gp[33];
p_val9 = gp[16];
p_val10 = gp[17];
p_pen2 = gp[19];
p_pen3 = gp[20];
p_pen4 = gp[21];
p_coa2 = gp[2];
p_coa3 = gp[38];
p_coa4 = gp[30];
p_val3 = paramssing(itype).p_val3;
p_val5 = paramssing(itype).p_val5;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
const F_FLOAT Delta_val = d_total_bo[i] - paramssing(itype).valency_val;
SBOp = 0.0, prod_SBO = 1.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const int j_index = jj - j_start;
bo_ij = d_BO(i,j_index);
SBOp += (d_BO_pi(i,j_index) + d_BO_pi2(i,j_index));
temp = SQR(bo_ij);
temp *= temp;
temp *= temp;
prod_SBO *= exp( -temp );
}
const F_FLOAT Delta_e = d_total_bo[i] - paramssing(itype).valency_e;
const F_FLOAT vlpex = Delta_e - 2.0 * (int)(Delta_e/2.0);
const F_FLOAT explp1 = exp(-gp[15] * SQR(2.0 + vlpex));
const F_FLOAT nlp = explp1 - (int)(Delta_e / 2.0);
if( vlpex >= 0.0 ){
vlpadj = 0.0;
dSBO2 = prod_SBO - 1.0;
} else{
vlpadj = nlp;
dSBO2 = (prod_SBO - 1.0) * (1.0 - p_val8 * d_dDelta_lp[i]);
}
SBO = SBOp + (1.0 - prod_SBO) * (-d_Delta_boc[i] - p_val8 * vlpadj);
dSBO1 = -8.0 * prod_SBO * ( d_Delta_boc[i] + p_val8 * vlpadj );
if( SBO <= 0.0 ) {
SBO2 = 0.0;
CSBO2 = 0.0;
} else if( SBO > 0.0 && SBO <= 1.0 ) {
SBO2 = pow( SBO, p_val9 );
CSBO2 = p_val9 * pow( SBO, p_val9 - 1.0 );
} else if( SBO > 1.0 && SBO < 2.0 ) {
SBO2 = 2.0 - pow( 2.0-SBO, p_val9 );
CSBO2 = p_val9 * pow( 2.0 - SBO, p_val9 - 1.0 );
} else {
SBO2 = 2.0;
CSBO2 = 0.0;
}
expval6 = exp( p_val6 * d_Delta_boc[i] );
F_FLOAT CdDelta_i = 0.0;
F_FLOAT fitmp[3],fjtmp[3];
for (int j = 0; j < 3; j++) fitmp[j] = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const int j_index = jj - j_start;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsqij = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
rij = sqrt(rsqij);
bo_ij = d_BO(i,j_index);
const int i_index = maxbo+j_index;
BOA_ij = bo_ij - thb_cut;
if (BOA_ij <= 0.0) continue;
if (i >= nlocal && j >= nlocal) continue;
const int jtype = type(j);
F_FLOAT CdDelta_j = 0.0;
for (int k = 0; k < 3; k++) fjtmp[k] = 0.0;
for (int kk = jj+1; kk < j_end; kk++ ) {
//for (int kk = j_start; kk < j_end; kk++ ) {
int k = d_bo_list[kk];
k &= NEIGHMASK;
if (k == j) continue;
const int k_index = kk - j_start;
delik[0] = x(k,0) - xtmp;
delik[1] = x(k,1) - ytmp;
delik[2] = x(k,2) - ztmp;
const F_FLOAT rsqik = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
const F_FLOAT rik = sqrt(rsqik);
bo_ik = d_BO(i,k_index);
BOA_ik = bo_ik - thb_cut;
if (BOA_ik <= 0.0 || bo_ij <= thb_cut || bo_ik <= thb_cut || bo_ij * bo_ik <= thb_cutsq) continue;
const int ktype = type(k);
// theta and derivatives
cos_theta = (delij[0]*delik[0]+delij[1]*delik[1]+delij[2]*delik[2])/(rij*rik);
if( cos_theta > 1.0 ) cos_theta = 1.0;
if( cos_theta < -1.0 ) cos_theta = -1.0;
theta = acos(cos_theta);
const F_FLOAT inv_dists = 1.0 / (rij * rik);
const F_FLOAT Cdot_inv3 = cos_theta * inv_dists * inv_dists;
for( int t = 0; t < 3; t++ ) {
dcos_theta_di[t] = -(delik[t] + delij[t]) * inv_dists + Cdot_inv3 * (rsqik * delij[t] + rsqij * delik[t]);
dcos_theta_dj[t] = delik[t] * inv_dists - Cdot_inv3 * rsqik * delij[t];
dcos_theta_dk[t] = delij[t] * inv_dists - Cdot_inv3 * rsqij * delik[t];
}
sin_theta = sin(theta);
if (sin_theta < 1.0e-5) sin_theta = 1.0e-5;
p_val1 = paramsthbp(jtype,itype,ktype).p_val1;
if (fabs(p_val1) <= 0.001) continue;
// ANGLE ENERGY
p_val1 = paramsthbp(jtype,itype,ktype).p_val1;
p_val2 = paramsthbp(jtype,itype,ktype).p_val2;
p_val4 = paramsthbp(jtype,itype,ktype).p_val4;
p_val7 = paramsthbp(jtype,itype,ktype).p_val7;
theta_00 = paramsthbp(jtype,itype,ktype).theta_00;
exp3ij = exp( -p_val3 * pow( BOA_ij, p_val4 ) );
f7_ij = 1.0 - exp3ij;
Cf7ij = p_val3 * p_val4 * pow( BOA_ij, p_val4 - 1.0 ) * exp3ij;
exp3jk = exp( -p_val3 * pow( BOA_ik, p_val4 ) );
f7_jk = 1.0 - exp3jk;
Cf7jk = p_val3 * p_val4 * pow( BOA_ik, p_val4 - 1.0 ) * exp3jk;
expval7 = exp( -p_val7 * d_Delta_boc[i] );
trm8 = 1.0 + expval6 + expval7;
f8_Dj = p_val5 - ( (p_val5 - 1.0) * (2.0 + expval6) / trm8 );
Cf8j = ((1.0 - p_val5) / (trm8*trm8)) *
(p_val6 * expval6 * trm8 - (2.0 + expval6) * ( p_val6*expval6 - p_val7*expval7));
theta_0 = 180.0 - theta_00 * (1.0 - exp(-p_val10 * (2.0 - SBO2)));
theta_0 = theta_0*constPI/180.0;
expval2theta = exp( -p_val2 * (theta_0-theta)*(theta_0-theta) );
if( p_val1 >= 0 )
expval12theta = p_val1 * (1.0 - expval2theta);
else // To avoid linear Me-H-Me angles (6/6/06)
expval12theta = p_val1 * -expval2theta;
CEval1 = Cf7ij * f7_jk * f8_Dj * expval12theta;
CEval2 = Cf7jk * f7_ij * f8_Dj * expval12theta;
CEval3 = Cf8j * f7_ij * f7_jk * expval12theta;
CEval4 = -2.0 * p_val1 * p_val2 * f7_ij * f7_jk * f8_Dj * expval2theta * (theta_0 - theta);
Ctheta_0 = p_val10 * theta_00*constPI/180.0 * exp( -p_val10 * (2.0 - SBO2) );
CEval5 = -CEval4 * Ctheta_0 * CSBO2;
CEval6 = CEval5 * dSBO1;
CEval7 = CEval5 * dSBO2;
CEval8 = -CEval4 / sin_theta;
e_ang = f7_ij * f7_jk * f8_Dj * expval12theta;
if (eflag) ev.ereax[3] += e_ang;
// Penalty energy
p_pen1 = paramsthbp(jtype,itype,ktype).p_pen1;
exp_pen2ij = exp( -p_pen2 * (BOA_ij - 2.0)*(BOA_ij - 2.0) );
exp_pen2jk = exp( -p_pen2 * (BOA_ik - 2.0)*(BOA_ik - 2.0) );
exp_pen3 = exp( -p_pen3 * d_Delta[i] );
exp_pen4 = exp( p_pen4 * d_Delta[i] );
trm_pen34 = 1.0 + exp_pen3 + exp_pen4;
f9_Dj = (2.0 + exp_pen3 ) / trm_pen34;
Cf9j = (-p_pen3 * exp_pen3 * trm_pen34 - (2.0 + exp_pen3) *
(-p_pen3 * exp_pen3 + p_pen4 * exp_pen4 ) )/(trm_pen34*trm_pen34);
e_pen = p_pen1 * f9_Dj * exp_pen2ij * exp_pen2jk;
if (eflag) ev.ereax[4] += e_pen;
CEpen1 = e_pen * Cf9j / f9_Dj;
temp = -2.0 * p_pen2 * e_pen;
CEpen2 = temp * (BOA_ij - 2.0);
CEpen3 = temp * (BOA_ik - 2.0);
// ConjAngle energy
p_coa1 = paramsthbp(jtype,itype,ktype).p_coa1;
exp_coa2 = exp( p_coa2 * Delta_val );
e_coa = p_coa1 / (1. + exp_coa2) *
exp( -p_coa3 * SQR(d_total_bo[j]-BOA_ij) ) *
exp( -p_coa3 * SQR(d_total_bo[k]-BOA_ik) ) *
exp( -p_coa4 * SQR(BOA_ij - 1.5) ) *
exp( -p_coa4 * SQR(BOA_ik - 1.5) );
CEcoa1 = -2 * p_coa4 * (BOA_ij - 1.5) * e_coa;
CEcoa2 = -2 * p_coa4 * (BOA_ik - 1.5) * e_coa;
CEcoa3 = -p_coa2 * exp_coa2 * e_coa / (1 + exp_coa2);
CEcoa4 = -2 * p_coa3 * (d_total_bo[j]-BOA_ij) * e_coa;
CEcoa5 = -2 * p_coa3 * (d_total_bo[k]-BOA_ik) * e_coa;
if (eflag) ev.ereax[5] += e_coa;
// Forces
a_Cdbo(i,j_index) += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4));
a_Cdbo(j,i_index) += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4));
a_Cdbo(i,k_index) += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5));
a_Cdbo(k,i_index) += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5));
CdDelta_i += ((CEval3 + CEval7) + CEpen1 + CEcoa3);
CdDelta_j += CEcoa4;
a_CdDelta[k] += CEcoa5;
for (int ll = j_start; ll < j_end; ll++) {
int l = d_bo_list[ll];
l &= NEIGHMASK;
const int l_index = ll - j_start;
temp_bo_jt = d_BO(i,l_index);
temp = temp_bo_jt * temp_bo_jt * temp_bo_jt;
pBOjt7 = temp * temp * temp_bo_jt;
a_Cdbo(i,l_index) += (CEval6 * pBOjt7);
d_Cdbopi(i,l_index) += CEval5;
d_Cdbopi2(i,l_index) += CEval5;
}
for (int d = 0; d < 3; d++) fi_tmp[d] = CEval8 * dcos_theta_di[d];
for (int d = 0; d < 3; d++) fj_tmp[d] = CEval8 * dcos_theta_dj[d];
for (int d = 0; d < 3; d++) fk_tmp[d] = CEval8 * dcos_theta_dk[d];
for (int d = 0; d < 3; d++) fitmp[d] -= fi_tmp[d];
for (int d = 0; d < 3; d++) fjtmp[d] -= fj_tmp[d];
for (int d = 0; d < 3; d++) a_f(k,d) -= fk_tmp[d];
// energy/virial tally
if (EVFLAG) {
eng_tmp = e_ang + e_pen + e_coa;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,eng_tmp,0.0,0.0,0.0,0.0);
for (int d = 0; d < 3; d++) delki[d] = -1.0 * delik[d];
for (int d = 0; d < 3; d++) delji[d] = -1.0 * delij[d];
if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,eng_tmp);
if (vflag_either) this->template v_tally3<NEIGHFLAG>(ev,i,j,k,fj_tmp,fk_tmp,delji,delki);
}
}
a_CdDelta[j] += CdDelta_j;
for (int d = 0; d < 3; d++) a_f(j,d) += fjtmp[d];
}
a_CdDelta[i] += CdDelta_i;
for (int d = 0; d < 3; d++) a_f(i,d) += fitmp[d];
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeAngular<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeAngular<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeTorsion<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
Kokkos::View<F_FLOAT*, typename DAT::t_float_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_CdDelta = d_CdDelta;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbo = d_Cdbo;
// in reaxc_torsion_angles: j = i, k = j, i = k;
F_FLOAT Delta_i, Delta_j, bo_ij, bo_ik, bo_jl, BOA_ij, BOA_ik, BOA_jl;
F_FLOAT p_tor1, p_cot1, V1, V2, V3;
F_FLOAT exp_tor2_ij, exp_tor2_ik, exp_tor2_jl, exp_tor1, exp_tor3_DiDj, exp_tor4_DiDj, exp_tor34_inv;
F_FLOAT exp_cot2_ij, exp_cot2_ik, exp_cot2_jl, fn10, f11_DiDj, dfn11, fn12;
F_FLOAT theta_ijk, theta_jil, sin_ijk, sin_jil, cos_ijk, cos_jil, tan_ijk_i, tan_jil_i;
F_FLOAT cos_omega, cos2omega, cos3omega;
F_FLOAT CV, cmn, CEtors1, CEtors2, CEtors3, CEtors4;
F_FLOAT CEtors5, CEtors6, CEtors7, CEtors8, CEtors9;
F_FLOAT Cconj, CEconj1, CEconj2, CEconj3, CEconj4, CEconj5, CEconj6;
F_FLOAT e_tor, e_con, eng_tmp;
F_FLOAT delij[3], delik[3], deljl[3], dellk[3], delil[3], delkl[3];
F_FLOAT fi_tmp[3], fj_tmp[3], fk_tmp[3], fl_tmp[3];
F_FLOAT dcos_omega_di[3], dcos_omega_dj[3], dcos_omega_dk[3], dcos_omega_dl[3];
F_FLOAT dcos_ijk_di[3], dcos_ijk_dj[3], dcos_ijk_dk[3], dcos_jil_di[3], dcos_jil_dj[3], dcos_jil_dk[3];
F_FLOAT p_tor2 = gp[23];
F_FLOAT p_tor3 = gp[24];
F_FLOAT p_tor4 = gp[25];
F_FLOAT p_cot2 = gp[27];
const int i = d_ilist[ii];
const int itype = type(i);
const tagint itag = tag(i);
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
Delta_i = d_Delta_boc[i];
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT fitmp[3], fjtmp[3], fktmp[3];
for(int j = 0; j < 3; j++) fitmp[j] = 0.0;
F_FLOAT CdDelta_i = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag(j);
const int jtype = type(j);
const int j_index = jj - j_start;
// skip half of the interactions
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x(j,2) < ztmp) continue;
if (x(j,2) == ztmp && x(j,1) < ytmp) continue;
if (x(j,2) == ztmp && x(j,1) == ytmp && x(j,0) < xtmp) continue;
}
bo_ij = d_BO(i,j_index);
if (bo_ij < thb_cut) continue;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsqij = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsqij);
BOA_ij = bo_ij - thb_cut;
Delta_j = d_Delta_boc[j];
exp_tor2_ij = exp( -p_tor2 * BOA_ij );
exp_cot2_ij = exp( -p_cot2 * SQR(BOA_ij - 1.5) );
exp_tor3_DiDj = exp( -p_tor3 * (Delta_i + Delta_j) );
exp_tor4_DiDj = exp( p_tor4 * (Delta_i + Delta_j) );
exp_tor34_inv = 1.0 / (1.0 + exp_tor3_DiDj + exp_tor4_DiDj);
f11_DiDj = (2.0 + exp_tor3_DiDj) * exp_tor34_inv;
const int l_start = d_bo_first[j];
const int l_end = l_start + d_bo_num[j];
for(int k = 0; k < 3; k++) fjtmp[k] = 0.0;
F_FLOAT CdDelta_j = 0.0;
for (int kk = j_start; kk < j_end; kk++) {
int k = d_bo_list[kk];
k &= NEIGHMASK;
if (k == j) continue;
const int ktype = type(k);
const int k_index = kk - j_start;
bo_ik = d_BO(i,k_index);
if (bo_ik < thb_cut) continue;
BOA_ik = bo_ik - thb_cut;
for (int d = 0; d < 3; d ++) delik[d] = x(k,d) - x(i,d);
const F_FLOAT rsqik = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
const F_FLOAT rik = sqrt(rsqik);
cos_ijk = (delij[0]*delik[0]+delij[1]*delik[1]+delij[2]*delik[2])/(rij*rik);
if( cos_ijk > 1.0 ) cos_ijk = 1.0;
if( cos_ijk < -1.0 ) cos_ijk = -1.0;
theta_ijk = acos(cos_ijk);
// dcos_ijk
const F_FLOAT inv_dists = 1.0 / (rij * rik);
const F_FLOAT cos_ijk_tmp = cos_ijk / ((rij*rik)*(rij*rik));
for( int d = 0; d < 3; d++ ) {
dcos_ijk_di[d] = -(delik[d] + delij[d]) * inv_dists + cos_ijk_tmp * (rsqik * delij[d] + rsqij * delik[d]);
dcos_ijk_dj[d] = delik[d] * inv_dists - cos_ijk_tmp * rsqik * delij[d];
dcos_ijk_dk[d] = delij[d] * inv_dists - cos_ijk_tmp * rsqij * delik[d];
}
sin_ijk = sin( theta_ijk );
if( sin_ijk >= 0 && sin_ijk <= 1e-10 )
tan_ijk_i = cos_ijk / 1e-10;
else if( sin_ijk <= 0 && sin_ijk >= -1e-10 )
tan_ijk_i = -cos_ijk / 1e-10;
else tan_ijk_i = cos_ijk / sin_ijk;
exp_tor2_ik = exp( -p_tor2 * BOA_ik );
exp_cot2_ik = exp( -p_cot2 * SQR(BOA_ik -1.5) );
for(int l = 0; l < 3; l++) fktmp[l] = 0.0;
for (int ll = l_start; ll < l_end; ll++) {
int l = d_bo_list[ll];
l &= NEIGHMASK;
if (l == i) continue;
const int ltype = type(l);
const int l_index = ll - l_start;
bo_jl = d_BO(j,l_index);
if (l == k || bo_jl < thb_cut || bo_ij*bo_ik*bo_jl < thb_cut) continue;
for (int d = 0; d < 3; d ++) deljl[d] = x(l,d) - x(j,d);
const F_FLOAT rsqjl = deljl[0]*deljl[0] + deljl[1]*deljl[1] + deljl[2]*deljl[2];
const F_FLOAT rjl = sqrt(rsqjl);
BOA_jl = bo_jl - thb_cut;
cos_jil = -(delij[0]*deljl[0]+delij[1]*deljl[1]+delij[2]*deljl[2])/(rij*rjl);
if( cos_jil > 1.0 ) cos_jil = 1.0;
if( cos_jil < -1.0 ) cos_jil = -1.0;
theta_jil = acos(cos_jil);
// dcos_jil
const F_FLOAT inv_distjl = 1.0 / (rij * rjl);
const F_FLOAT inv_distjl3 = pow( inv_distjl, 3.0 );
const F_FLOAT cos_jil_tmp = cos_jil / ((rij*rjl)*(rij*rjl));
for( int d = 0; d < 3; d++ ) {
dcos_jil_di[d] = deljl[d] * inv_distjl - cos_jil_tmp * rsqjl * -delij[d];
dcos_jil_dj[d] = (-deljl[d] + delij[d]) * inv_distjl - cos_jil_tmp * (rsqjl * delij[d] + rsqij * -deljl[d]);
dcos_jil_dk[d] = -delij[d] * inv_distjl - cos_jil_tmp * rsqij * deljl[d];
}
sin_jil = sin( theta_jil );
if( sin_jil >= 0 && sin_jil <= 1e-10 )
tan_jil_i = cos_jil / 1e-10;
else if( sin_jil <= 0 && sin_jil >= -1e-10 )
tan_jil_i = -cos_jil / 1e-10;
else tan_jil_i = cos_jil / sin_jil;
for (int d = 0; d < 3; d ++) dellk[d] = x(k,d) - x(l,d);
const F_FLOAT rsqlk = dellk[0]*dellk[0] + dellk[1]*dellk[1] + dellk[2]*dellk[2];
const F_FLOAT rlk = sqrt(rsqlk);
F_FLOAT unnorm_cos_omega, unnorm_sin_omega, omega;
F_FLOAT htra, htrb, htrc, hthd, hthe, hnra, hnrc, hnhd, hnhe;
F_FLOAT arg, poem, tel;
F_FLOAT cross_ij_jl[3];
// omega
F_FLOAT dot_ij_jk = -(delij[0]*delik[0]+delij[1]*delik[1]+delij[2]*delik[2]);
F_FLOAT dot_ij_lj = delij[0]*deljl[0]+delij[1]*deljl[1]+delij[2]*deljl[2];
F_FLOAT dot_ik_jl = delik[0]*deljl[0]+delik[1]*deljl[1]+delik[2]*deljl[2];
unnorm_cos_omega = dot_ij_jk * dot_ij_lj + rsqij * dot_ik_jl;
cross_ij_jl[0] = delij[1]*deljl[2] - delij[2]*deljl[1];
cross_ij_jl[1] = delij[2]*deljl[0] - delij[0]*deljl[2];
cross_ij_jl[2] = delij[0]*deljl[1] - delij[1]*deljl[0];
unnorm_sin_omega = -rij*(delik[0]*cross_ij_jl[0]+delik[1]*cross_ij_jl[1]+delik[2]*cross_ij_jl[2]);
omega = atan2( unnorm_sin_omega, unnorm_cos_omega );
htra = rik + cos_ijk * ( rjl * cos_jil - rij );
htrb = rij - rik * cos_ijk - rjl * cos_jil;
htrc = rjl + cos_jil * ( rik * cos_ijk - rij );
hthd = rik * sin_ijk * ( rij - rjl * cos_jil );
hthe = rjl * sin_jil * ( rij - rik * cos_ijk );
hnra = rjl * sin_ijk * sin_jil;
hnrc = rik * sin_ijk * sin_jil;
hnhd = rik * rjl * cos_ijk * sin_jil;
hnhe = rik * rjl * sin_ijk * cos_jil;
poem = 2.0 * rik * rjl * sin_ijk * sin_jil;
if( poem < 1e-20 ) poem = 1e-20;
tel = SQR(rik) + SQR(rij) + SQR(rjl) - SQR(rlk) -
2.0 * (rik * rij * cos_ijk - rik * rjl * cos_ijk * cos_jil + rij * rjl * cos_jil);
arg = tel / poem;
if( arg > 1.0 ) arg = 1.0;
if( arg < -1.0 ) arg = -1.0;
F_FLOAT sin_ijk_rnd = sin_ijk;
F_FLOAT sin_jil_rnd = sin_jil;
if( sin_ijk >= 0 && sin_ijk <= 1e-10 ) sin_ijk_rnd = 1e-10;
else if( sin_ijk <= 0 && sin_ijk >= -1e-10 ) sin_ijk_rnd = -1e-10;
if( sin_jil >= 0 && sin_jil <= 1e-10 ) sin_jil_rnd = 1e-10;
else if( sin_jil <= 0 && sin_jil >= -1e-10 ) sin_jil_rnd = -1e-10;
// dcos_omega_di
for (int d = 0; d < 3; d++) dcos_omega_dk[d] = ((htra-arg*hnra)/rik) * delik[d] - dellk[d];
for (int d = 0; d < 3; d++) dcos_omega_dk[d] += (hthd-arg*hnhd)/sin_ijk_rnd * -dcos_ijk_dk[d];
for (int d = 0; d < 3; d++) dcos_omega_dk[d] *= 2.0/poem;
// dcos_omega_dj
for (int d = 0; d < 3; d++) dcos_omega_di[d] = -((htra-arg*hnra)/rik) * delik[d] - htrb/rij * delij[d];
for (int d = 0; d < 3; d++) dcos_omega_di[d] += -(hthd-arg*hnhd)/sin_ijk_rnd * dcos_ijk_di[d];
for (int d = 0; d < 3; d++) dcos_omega_di[d] += -(hthe-arg*hnhe)/sin_jil_rnd * dcos_jil_di[d];
for (int d = 0; d < 3; d++) dcos_omega_di[d] *= 2.0/poem;
// dcos_omega_dk
for (int d = 0; d < 3; d++) dcos_omega_dj[d] = -((htrc-arg*hnrc)/rjl) * deljl[d] + htrb/rij * delij[d];
for (int d = 0; d < 3; d++) dcos_omega_dj[d] += -(hthd-arg*hnhd)/sin_ijk_rnd * dcos_ijk_dj[d];
for (int d = 0; d < 3; d++) dcos_omega_dj[d] += -(hthe-arg*hnhe)/sin_jil_rnd * dcos_jil_dj[d];
for (int d = 0; d < 3; d++) dcos_omega_dj[d] *= 2.0/poem;
// dcos_omega_dl
for (int d = 0; d < 3; d++) dcos_omega_dl[d] = ((htrc-arg*hnrc)/rjl) * deljl[d] + dellk[d];
for (int d = 0; d < 3; d++) dcos_omega_dl[d] += (hthe-arg*hnhe)/sin_jil_rnd * -dcos_jil_dk[d];
for (int d = 0; d < 3; d++) dcos_omega_dl[d] *= 2.0/poem;
cos_omega = cos( omega );
cos2omega = cos( 2. * omega );
cos3omega = cos( 3. * omega );
// torsion energy
p_tor1 = paramsfbp(ktype,itype,jtype,ltype).p_tor1;
p_cot1 = paramsfbp(ktype,itype,jtype,ltype).p_cot1;
V1 = paramsfbp(ktype,itype,jtype,ltype).V1;
V2 = paramsfbp(ktype,itype,jtype,ltype).V2;
V3 = paramsfbp(ktype,itype,jtype,ltype).V3;
exp_tor1 = exp(p_tor1 * SQR(2.0 - d_BO_pi(i,j_index) - f11_DiDj));
exp_tor2_jl = exp(-p_tor2 * BOA_jl);
exp_cot2_jl = exp(-p_cot2 * SQR(BOA_jl - 1.5) );
fn10 = (1.0 - exp_tor2_ik) * (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jl);
CV = 0.5 * (V1 * (1.0 + cos_omega) + V2 * exp_tor1 * (1.0 - cos2omega) + V3 * (1.0 + cos3omega) );
e_tor = fn10 * sin_ijk * sin_jil * CV;
if (eflag) ev.ereax[6] += e_tor;
dfn11 = (-p_tor3 * exp_tor3_DiDj + (p_tor3 * exp_tor3_DiDj - p_tor4 * exp_tor4_DiDj) *
(2.0 + exp_tor3_DiDj) * exp_tor34_inv) * exp_tor34_inv;
CEtors1 = sin_ijk * sin_jil * CV;
CEtors2 = -fn10 * 2.0 * p_tor1 * V2 * exp_tor1 * (2.0 - d_BO_pi(i,j_index) - f11_DiDj) *
(1.0 - SQR(cos_omega)) * sin_ijk * sin_jil;
CEtors3 = CEtors2 * dfn11;
CEtors4 = CEtors1 * p_tor2 * exp_tor2_ik * (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jl);
CEtors5 = CEtors1 * p_tor2 * (1.0 - exp_tor2_ik) * exp_tor2_ij * (1.0 - exp_tor2_jl);
CEtors6 = CEtors1 * p_tor2 * (1.0 - exp_tor2_ik) * (1.0 - exp_tor2_ij) * exp_tor2_jl;
cmn = -fn10 * CV;
CEtors7 = cmn * sin_jil * tan_ijk_i;
CEtors8 = cmn * sin_ijk * tan_jil_i;
CEtors9 = fn10 * sin_ijk * sin_jil *
(0.5 * V1 - 2.0 * V2 * exp_tor1 * cos_omega + 1.5 * V3 * (cos2omega + 2.0 * SQR(cos_omega)));
// 4-body conjugation energy
fn12 = exp_cot2_ik * exp_cot2_ij * exp_cot2_jl;
e_con = p_cot1 * fn12 * (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jil);
if (eflag) ev.ereax[7] += e_con;
Cconj = -2.0 * fn12 * p_cot1 * p_cot2 * (1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jil);
CEconj1 = Cconj * (BOA_ik - 1.5e0);
CEconj2 = Cconj * (BOA_ij - 1.5e0);
CEconj3 = Cconj * (BOA_jl - 1.5e0);
CEconj4 = -p_cot1 * fn12 * (SQR(cos_omega) - 1.0) * sin_jil * tan_ijk_i;
CEconj5 = -p_cot1 * fn12 * (SQR(cos_omega) - 1.0) * sin_ijk * tan_jil_i;
CEconj6 = 2.0 * p_cot1 * fn12 * cos_omega * sin_ijk * sin_jil;
// forces
// contribution to bond order
d_Cdbopi(i,j_index) += CEtors2;
CdDelta_i += CEtors3;
CdDelta_j += CEtors3;
a_Cdbo(i,k_index) += CEtors4 + CEconj1;
a_Cdbo(i,j_index) += CEtors5 + CEconj2;
a_Cdbo(j,l_index) += CEtors6 + CEconj3; // trouble
// dcos_theta_ijk
const F_FLOAT coeff74 = CEtors7 + CEconj4;
for (int d = 0; d < 3; d++) fi_tmp[d] = (coeff74) * dcos_ijk_di[d];
for (int d = 0; d < 3; d++) fj_tmp[d] = (coeff74) * dcos_ijk_dj[d];
for (int d = 0; d < 3; d++) fk_tmp[d] = (coeff74) * dcos_ijk_dk[d];
const F_FLOAT coeff85 = CEtors8 + CEconj5;
// dcos_theta_jil
for (int d = 0; d < 3; d++) fi_tmp[d] += (coeff85) * dcos_jil_di[d];
for (int d = 0; d < 3; d++) fj_tmp[d] += (coeff85) * dcos_jil_dj[d];
for (int d = 0; d < 3; d++) fl_tmp[d] = (coeff85) * dcos_jil_dk[d];
// dcos_omega
const F_FLOAT coeff96 = CEtors9 + CEconj6;
for (int d = 0; d < 3; d++) fi_tmp[d] += (coeff96) * dcos_omega_di[d];
for (int d = 0; d < 3; d++) fj_tmp[d] += (coeff96) * dcos_omega_dj[d];
for (int d = 0; d < 3; d++) fk_tmp[d] += (coeff96) * dcos_omega_dk[d];
for (int d = 0; d < 3; d++) fl_tmp[d] += (coeff96) * dcos_omega_dl[d];
// total forces
for (int d = 0; d < 3; d++) fitmp[d] -= fi_tmp[d];
for (int d = 0; d < 3; d++) fjtmp[d] -= fj_tmp[d];
for (int d = 0; d < 3; d++) fktmp[d] -= fk_tmp[d];
for (int d = 0; d < 3; d++) a_f(l,d) -= fl_tmp[d];
// per-atom energy/virial tally
if (EVFLAG) {
eng_tmp = e_tor + e_con;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,eng_tmp,0.0,0.0,0.0,0.0);
if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,eng_tmp);
if (vflag_either) {
for (int d = 0; d < 3; d ++) delil[d] = x(l,d) - x(i,d);
for (int d = 0; d < 3; d ++) delkl[d] = x(l,d) - x(k,d);
this->template v_tally4<NEIGHFLAG>(ev,k,i,j,l,fk_tmp,fi_tmp,fj_tmp,delkl,delil,deljl);
}
}
}
for (int d = 0; d < 3; d++) a_f(k,d) += fktmp[d];
}
a_CdDelta[j] += CdDelta_j;
for (int d = 0; d < 3; d++) a_f(j,d) += fjtmp[d];
}
a_CdDelta[i] += CdDelta_i;
for (int d = 0; d < 3; d++) a_f(i,d) += fitmp[d];
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeTorsion<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeTorsion<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeHydrogen<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
int hblist[MAX_BONDS];
F_FLOAT theta, cos_theta, sin_xhz4, cos_xhz1, sin_theta2;
F_FLOAT e_hb, exp_hb2, exp_hb3, CEhb1, CEhb2, CEhb3;
F_FLOAT dcos_theta_di[3], dcos_theta_dj[3], dcos_theta_dk[3];
// tally variables
F_FLOAT fi_tmp[3], fj_tmp[3], fk_tmp[3], delij[3], delji[3], delik[3], delki[3];
for (int d = 0; d < 3; d++) fi_tmp[d] = fj_tmp[d] = fk_tmp[d] = 0.0;
const int i = d_ilist[ii];
const int itype = type(i);
if( paramssing(itype).p_hbond != 1 ) return;
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const tagint itag = tag(i);
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
const int k_start = d_hb_first[i];
const int k_end = k_start + d_hb_num[i];
int top = 0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const int jtype = type(j);
const int j_index = jj - j_start;
const F_FLOAT bo_ij = d_BO(i,j_index);
if( paramssing(jtype).p_hbond == 2 && bo_ij >= HB_THRESHOLD ) {
hblist[top] = jj;
top ++;
}
}
F_FLOAT fitmp[3];
for (int d = 0; d < 3; d++) fitmp[d] = 0.0;
for (int kk = k_start; kk < k_end; kk++) {
int k = d_hb_list[kk];
k &= NEIGHMASK;
const tagint ktag = tag(k);
const int ktype = type(k);
delik[0] = x(k,0) - xtmp;
delik[1] = x(k,1) - ytmp;
delik[2] = x(k,2) - ztmp;
const F_FLOAT rsqik = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
const F_FLOAT rik = sqrt(rsqik);
for (int itr = 0; itr < top; itr++) {
const int jj = hblist[itr];
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag(j);
if (jtag == ktag) continue;
const int jtype = type(j);
const int j_index = jj - j_start;
const F_FLOAT bo_ij = d_BO(i,j_index);
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsqij = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsqij);
// theta and derivatives
cos_theta = (delij[0]*delik[0]+delij[1]*delik[1]+delij[2]*delik[2])/(rij*rik);
if( cos_theta > 1.0 ) cos_theta = 1.0;
if( cos_theta < -1.0 ) cos_theta = -1.0;
theta = acos(cos_theta);
const F_FLOAT inv_dists = 1.0 / (rij * rik);
const F_FLOAT Cdot_inv3 = cos_theta * inv_dists * inv_dists;
for( int d = 0; d < 3; d++ ) {
dcos_theta_di[d] = -(delik[d] + delij[d]) * inv_dists + Cdot_inv3 * (rsqik * delij[d] + rsqij * delik[d]);
dcos_theta_dj[d] = delik[d] * inv_dists - Cdot_inv3 * rsqik * delij[d];
dcos_theta_dk[d] = delij[d] * inv_dists - Cdot_inv3 * rsqij * delik[d];
}
// hydrogen bond energy
const F_FLOAT p_hb1 = paramshbp(jtype,itype,ktype).p_hb1;
const F_FLOAT p_hb2 = paramshbp(jtype,itype,ktype).p_hb2;
const F_FLOAT p_hb3 = paramshbp(jtype,itype,ktype).p_hb3;
const F_FLOAT r0_hb = paramshbp(jtype,itype,ktype).r0_hb;
sin_theta2 = sin(theta/2.0);
sin_xhz4 = SQR(sin_theta2);
sin_xhz4 *= sin_xhz4;
cos_xhz1 = (1.0 - cos_theta);
exp_hb2 = exp(-p_hb2 * bo_ij);
exp_hb3 = exp(-p_hb3 * (r0_hb/rik + rik/r0_hb - 2.0));
e_hb = p_hb1 * (1.0 - exp_hb2) * exp_hb3 * sin_xhz4;
if (eflag) ev.ereax[8] += e_hb;
// hydrogen bond forces
CEhb1 = p_hb1 * p_hb2 * exp_hb2 * exp_hb3 * sin_xhz4;
CEhb2 = -p_hb1/2.0 * (1.0 - exp_hb2) * exp_hb3 * cos_xhz1;
CEhb3 = -p_hb3 * (-r0_hb/SQR(rik) + 1.0/r0_hb) * e_hb;
d_Cdbo(i,j_index) += CEhb1; // dbo term
// dcos terms
for (int d = 0; d < 3; d++) fi_tmp[d] = CEhb2 * dcos_theta_di[d];
for (int d = 0; d < 3; d++) fj_tmp[d] = CEhb2 * dcos_theta_dj[d];
for (int d = 0; d < 3; d++) fk_tmp[d] = CEhb2 * dcos_theta_dk[d];
// dr terms
for (int d = 0; d < 3; d++) fi_tmp[d] -= CEhb3/rik * delik[d];
for (int d = 0; d < 3; d++) fk_tmp[d] += CEhb3/rik * delik[d];
for (int d = 0; d < 3; d++) fitmp[d] -= fi_tmp[d];
for (int d = 0; d < 3; d++) a_f(j,d) -= fj_tmp[d];
for (int d = 0; d < 3; d++) a_f(k,d) -= fk_tmp[d];
for (int d = 0; d < 3; d++) delki[d] = -1.0 * delik[d];
for (int d = 0; d < 3; d++) delji[d] = -1.0 * delij[d];
if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,e_hb);
if (vflag_either) this->template v_tally3<NEIGHFLAG>(ev,i,j,k,fj_tmp,fk_tmp,delji,delki);
}
}
for (int d = 0; d < 3; d++) a_f(i,d) += fitmp[d];
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeHydrogen<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeHydrogen<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxUpdateBond<NEIGHFLAG>, const int &ii) const {
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbo = d_Cdbo;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbopi = d_Cdbopi;
Kokkos::View<F_FLOAT**, typename DAT::t_ffloat_2d_dl::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_Cdbopi2 = d_Cdbopi2;
const int i = d_ilist[ii];
const tagint itag = tag(i);
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag(j);
const int j_index = jj - j_start;
const F_FLOAT Cdbo_i = d_Cdbo(i,j_index);
const F_FLOAT Cdbopi_i = d_Cdbopi(i,j_index);
const F_FLOAT Cdbopi2_i = d_Cdbopi2(i,j_index);
const int k_start = d_bo_first[j];
const int k_end = k_start + d_bo_num[j];
for (int kk = k_start; kk < k_end; kk++) {
int k = d_bo_list[kk];
k &= NEIGHMASK;
if (k != i) continue;
const int k_index = kk - k_start;
int flag = 0;
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) flag = 1;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) flag = 1;
}
if (flag) {
a_Cdbo(j,k_index) += Cdbo_i;
a_Cdbopi(j,k_index) += Cdbopi_i;
a_Cdbopi2(j,k_index) += Cdbopi2_i;
}
}
}
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeBond1<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
Kokkos::View<F_FLOAT*, typename DAT::t_ffloat_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_CdDelta = d_CdDelta;
F_FLOAT delij[3];
F_FLOAT p_be1, p_be2, De_s, De_p, De_pp, pow_BOs_be2, exp_be12, CEbo, ebond;
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const tagint itag = tag(i);
const F_FLOAT imass = paramssing(itype).mass;
const F_FLOAT val_i = paramssing(itype).valency;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT CdDelta_i = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag(j);
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x(j,2) < ztmp) continue;
if (x(j,2) == ztmp && x(j,1) < ytmp) continue;
if (x(j,2) == ztmp && x(j,1) == ytmp && x(j,0) < xtmp) continue;
}
const int jtype = type(j);
const int j_index = jj - j_start;
const F_FLOAT jmass = paramssing(jtype).mass;
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsq);
const int k_start = d_bo_first[j];
const int k_end = k_start + d_bo_num[j];
const F_FLOAT p_bo1 = paramstwbp(itype,jtype).p_bo1;
const F_FLOAT p_bo2 = paramstwbp(itype,jtype).p_bo2;
const F_FLOAT p_bo3 = paramstwbp(itype,jtype).p_bo3;
const F_FLOAT p_bo4 = paramstwbp(itype,jtype).p_bo4;
const F_FLOAT p_bo5 = paramstwbp(itype,jtype).p_bo5;
const F_FLOAT p_bo6 = paramstwbp(itype,jtype).p_bo6;
const F_FLOAT r_s = paramstwbp(itype,jtype).r_s;
const F_FLOAT r_pi = paramstwbp(itype,jtype).r_pi;
const F_FLOAT r_pi2 = paramstwbp(itype,jtype).r_pi2;
// bond energy (nlocal only)
p_be1 = paramstwbp(itype,jtype).p_be1;
p_be2 = paramstwbp(itype,jtype).p_be2;
De_s = paramstwbp(itype,jtype).De_s;
De_p = paramstwbp(itype,jtype).De_p;
De_pp = paramstwbp(itype,jtype).De_pp;
const F_FLOAT BO_i = d_BO(i,j_index);
const F_FLOAT BO_s_i = d_BO_s(i,j_index);
const F_FLOAT BO_pi_i = d_BO_pi(i,j_index);
const F_FLOAT BO_pi2_i = d_BO_pi2(i,j_index);
- pow_BOs_be2 = pow(BO_s_i,p_be2);
+ if (BO_s_i == 0.0) pow_BOs_be2 = 0.0;
+ else pow_BOs_be2 = pow(BO_s_i,p_be2);
exp_be12 = exp(p_be1*(1.0-pow_BOs_be2));
CEbo = -De_s*exp_be12*(1.0-p_be1*p_be2*pow_BOs_be2);
ebond = -De_s*BO_s_i*exp_be12
-De_p*BO_pi_i
-De_pp*BO_pi2_i;
if (eflag) ev.evdwl += ebond;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,ebond,0.0,0.0,0.0,0.0);
//if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,ebond);
// calculate derivatives of Bond Orders
d_Cdbo(i,j_index) += CEbo;
d_Cdbopi(i,j_index) -= (CEbo + De_p);
d_Cdbopi2(i,j_index) -= (CEbo + De_pp);
// Stabilisation terminal triple bond
F_FLOAT estriph = 0.0;
if( BO_i >= 1.00 ) {
if( gp[37] == 2 || (imass == 12.0000 && jmass == 15.9990) ||
(jmass == 12.0000 && imass == 15.9990) ) {
const F_FLOAT exphu = exp(-gp[7] * SQR(BO_i - 2.50) );
const F_FLOAT exphua1 = exp(-gp[3] * (d_total_bo[i]-BO_i));
const F_FLOAT exphub1 = exp(-gp[3] * (d_total_bo[j]-BO_i));
const F_FLOAT exphuov = exp(gp[4] * (d_Delta[i] + d_Delta[j]));
const F_FLOAT hulpov = 1.0 / (1.0 + 25.0 * exphuov);
estriph = gp[10] * exphu * hulpov * (exphua1 + exphub1);
if (eflag) ev.evdwl += estriph;
//if (eflag_atom) this->template ev_tally<NEIGHFLAG>(ev,i,j,estriph,0.0,0.0,0.0,0.0);
//if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,estriph);
const F_FLOAT decobdbo = gp[10] * exphu * hulpov * (exphua1 + exphub1) *
( gp[3] - 2.0 * gp[7] * (BO_i-2.50) );
const F_FLOAT decobdboua = -gp[10] * exphu * hulpov *
(gp[3]*exphua1 + 25.0*gp[4]*exphuov*hulpov*(exphua1+exphub1));
const F_FLOAT decobdboub = -gp[10] * exphu * hulpov *
(gp[3]*exphub1 + 25.0*gp[4]*exphuov*hulpov*(exphua1+exphub1));
d_Cdbo(i,j_index) += decobdbo;
CdDelta_i += decobdboua;
a_CdDelta[j] += decobdboub;
}
}
const F_FLOAT eng_tmp = ebond + estriph;
if (eflag_atom) this->template e_tally<NEIGHFLAG>(ev,i,j,eng_tmp);
}
a_CdDelta[i] += CdDelta_i;
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeBond1<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeBond1<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeBond2<NEIGHFLAG,EVFLAG>, const int &ii, EV_FLOAT_REAX& ev) const {
Kokkos::View<F_FLOAT*[3], typename DAT::t_f_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_f = f;
F_FLOAT delij[3], delik[3], deljk[3], tmpvec[3];
F_FLOAT dBOp_i[3], dBOp_k[3], dln_BOp_pi[3], dln_BOp_pi2[3];
const int i = d_ilist[ii];
const X_FLOAT xtmp = x(i,0);
const X_FLOAT ytmp = x(i,1);
const X_FLOAT ztmp = x(i,2);
const int itype = type(i);
const tagint itag = tag(i);
const F_FLOAT imass = paramssing(itype).mass;
const F_FLOAT val_i = paramssing(itype).valency;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
F_FLOAT CdDelta_i = d_CdDelta[i];
F_FLOAT fitmp[3];
for (int j = 0; j < 3; j++) fitmp[j] = 0.0;
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag(j);
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x(j,2) < ztmp) continue;
if (x(j,2) == ztmp && x(j,1) < ytmp) continue;
if (x(j,2) == ztmp && x(j,1) == ytmp && x(j,0) < xtmp) continue;
}
const int jtype = type(j);
const int j_index = jj - j_start;
const F_FLOAT jmass = paramssing(jtype).mass;
F_FLOAT CdDelta_j = d_CdDelta[j];
delij[0] = x(j,0) - xtmp;
delij[1] = x(j,1) - ytmp;
delij[2] = x(j,2) - ztmp;
const F_FLOAT rsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
const F_FLOAT rij = sqrt(rsq);
const int k_start = d_bo_first[j];
const int k_end = k_start + d_bo_num[j];
F_FLOAT coef_C1dbo, coef_C2dbo, coef_C3dbo, coef_C1dbopi, coef_C2dbopi, coef_C3dbopi, coef_C4dbopi;
F_FLOAT coef_C1dbopi2, coef_C2dbopi2, coef_C3dbopi2, coef_C4dbopi2, coef_C1dDelta, coef_C2dDelta, coef_C3dDelta;
coef_C1dbo = coef_C2dbo = coef_C3dbo = 0.0;
coef_C1dbopi = coef_C2dbopi = coef_C3dbopi = coef_C4dbopi = 0.0;
coef_C1dbopi2 = coef_C2dbopi2 = coef_C3dbopi2 = coef_C4dbopi2 = 0.0;
coef_C1dDelta = coef_C2dDelta = coef_C3dDelta = 0.0;
// total forces on i, j, k (nlocal + nghost, from Add_dBond_to_Forces))
const F_FLOAT Cdbo_ij = d_Cdbo(i,j_index);
coef_C1dbo = d_C1dbo(i,j_index) * (Cdbo_ij);
coef_C2dbo = d_C2dbo(i,j_index) * (Cdbo_ij);
coef_C3dbo = d_C3dbo(i,j_index) * (Cdbo_ij);
const F_FLOAT Cdbopi_ij = d_Cdbopi(i,j_index);
coef_C1dbopi = d_C1dbopi(i,j_index) * (Cdbopi_ij);
coef_C2dbopi = d_C2dbopi(i,j_index) * (Cdbopi_ij);
coef_C3dbopi = d_C3dbopi(i,j_index) * (Cdbopi_ij);
coef_C4dbopi = d_C4dbopi(i,j_index) * (Cdbopi_ij);
const F_FLOAT Cdbopi2_ij = d_Cdbopi2(i,j_index);
coef_C1dbopi2 = d_C1dbopi2(i,j_index) * (Cdbopi2_ij);
coef_C2dbopi2 = d_C2dbopi2(i,j_index) * (Cdbopi2_ij);
coef_C3dbopi2 = d_C3dbopi2(i,j_index) * (Cdbopi2_ij);
coef_C4dbopi2 = d_C4dbopi2(i,j_index) * (Cdbopi2_ij);
const F_FLOAT coeff_CdDelta_ij = CdDelta_i + CdDelta_j;
coef_C1dDelta = d_C1dbo(i,j_index) * (coeff_CdDelta_ij);
coef_C2dDelta = d_C2dbo(i,j_index) * (coeff_CdDelta_ij);
coef_C3dDelta = d_C3dbo(i,j_index) * (coeff_CdDelta_ij);
F_FLOAT temp[3];
dln_BOp_pi[0] = d_dln_BOp_pix(i,j_index);
dln_BOp_pi[1] = d_dln_BOp_piy(i,j_index);
dln_BOp_pi[2] = d_dln_BOp_piz(i,j_index);
dln_BOp_pi2[0] = d_dln_BOp_pi2x(i,j_index);
dln_BOp_pi2[1] = d_dln_BOp_pi2y(i,j_index);
dln_BOp_pi2[2] = d_dln_BOp_pi2z(i,j_index);
dBOp_i[0] = d_dBOpx(i,j_index);
dBOp_i[1] = d_dBOpy(i,j_index);
dBOp_i[2] = d_dBOpz(i,j_index);
// forces on i
for (int d = 0; d < 3; d++) temp[d] = coef_C1dbo * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C2dbo * d_dDeltap_self(i,d);
for (int d = 0; d < 3; d++) temp[d] += coef_C1dDelta * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C2dDelta * d_dDeltap_self(i,d);
for (int d = 0; d < 3; d++) temp[d] += coef_C1dbopi * dln_BOp_pi[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C2dbopi * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C3dbopi * d_dDeltap_self(i,d);
for (int d = 0; d < 3; d++) temp[d] += coef_C1dbopi2 * dln_BOp_pi2[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C2dbopi2 * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C3dbopi2 * d_dDeltap_self(i,d);
if (EVFLAG)
if (vflag_either) this->template v_tally<NEIGHFLAG>(ev,i,temp,delij);
fitmp[0] -= temp[0];
fitmp[1] -= temp[1];
fitmp[2] -= temp[2];
// forces on j
for (int d = 0; d < 3; d++) temp[d] = -coef_C1dbo * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C3dbo * d_dDeltap_self(j,d);
for (int d = 0; d < 3; d++) temp[d] -= coef_C1dDelta * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C3dDelta * d_dDeltap_self(j,d);
for (int d = 0; d < 3; d++) temp[d] -= coef_C1dbopi * dln_BOp_pi[d];
for (int d = 0; d < 3; d++) temp[d] -= coef_C2dbopi * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C4dbopi * d_dDeltap_self(j,d);
for (int d = 0; d < 3; d++) temp[d] -= coef_C1dbopi2 * dln_BOp_pi2[d];
for (int d = 0; d < 3; d++) temp[d] -= coef_C2dbopi2 * dBOp_i[d];
for (int d = 0; d < 3; d++) temp[d] += coef_C4dbopi2 * d_dDeltap_self(j,d);
a_f(j,0) -= temp[0];
a_f(j,1) -= temp[1];
a_f(j,2) -= temp[2];
if (EVFLAG)
if (vflag_either) {
for (int d = 0; d < 3; d++) tmpvec[d] = -delij[d];
this->template v_tally<NEIGHFLAG>(ev,j,temp,tmpvec);
}
// forces on k: i neighbor
for (int kk = j_start; kk < j_end; kk++) {
int k = d_bo_list[kk];
k &= NEIGHMASK;
const int k_index = kk - j_start;
dBOp_k[0] = d_dBOpx(i,k_index);
dBOp_k[1] = d_dBOpy(i,k_index);
dBOp_k[2] = d_dBOpz(i,k_index);
const F_FLOAT coef_all = -coef_C2dbo - coef_C2dDelta - coef_C3dbopi - coef_C3dbopi2;
for (int d = 0; d < 3; d++) temp[d] = coef_all * dBOp_k[d];
a_f(k,0) -= temp[0];
a_f(k,1) -= temp[1];
a_f(k,2) -= temp[2];
if (EVFLAG)
if (vflag_either) {
delik[0] = x(k,0) - xtmp;
delik[1] = x(k,1) - ytmp;
delik[2] = x(k,2) - ztmp;
for (int d = 0; d < 3; d++) tmpvec[d] = x(j,d) - x(k,d) - delik[d];
this->template v_tally<NEIGHFLAG>(ev,k,temp,tmpvec);
}
}
// forces on k: j neighbor
for (int kk = k_start; kk < k_end; kk++) {
int k = d_bo_list[kk];
k &= NEIGHMASK;
const int k_index = kk - k_start;
dBOp_k[0] = d_dBOpx(j,k_index);
dBOp_k[1] = d_dBOpy(j,k_index);
dBOp_k[2] = d_dBOpz(j,k_index);
const F_FLOAT coef_all = -coef_C3dbo - coef_C3dDelta - coef_C4dbopi - coef_C4dbopi2;
for (int d = 0; d < 3; d++) temp[d] = coef_all * dBOp_k[d];
a_f(k,0) -= temp[0];
a_f(k,1) -= temp[1];
a_f(k,2) -= temp[2];
if (EVFLAG) {
if (vflag_either) {
for (int d = 0; d < 3; d++) deljk[d] = x(k,d) - x(j,d);
for (int d = 0; d < 3; d++) tmpvec[d] = x(i,d) - x(k,d) - deljk[d];
this->template v_tally<NEIGHFLAG>(ev,k,temp,tmpvec);
}
}
}
}
for (int d = 0; d < 3; d++) a_f(i,d) += fitmp[d];
}
template<class DeviceType>
template<int NEIGHFLAG, int EVFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxComputeBond2<NEIGHFLAG,EVFLAG>, const int &ii) const {
EV_FLOAT_REAX ev;
this->template operator()<NEIGHFLAG,EVFLAG>(PairReaxComputeBond2<NEIGHFLAG,EVFLAG>(), ii, ev);
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::ev_tally(EV_FLOAT_REAX &ev, const int &i, const int &j,
const F_FLOAT &epair, const F_FLOAT &fpair, const F_FLOAT &delx,
const F_FLOAT &dely, const F_FLOAT &delz) const
{
const int VFLAG = vflag_either;
// The eatom and vatom arrays are atomic for Half/Thread neighbor style
Kokkos::View<E_FLOAT*, typename DAT::t_efloat_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_eatom = v_eatom;
Kokkos::View<F_FLOAT*[6], typename DAT::t_virial_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_vatom = v_vatom;
if (eflag_atom) {
const E_FLOAT epairhalf = 0.5 * epair;
a_eatom[i] += epairhalf;
if (NEIGHFLAG != FULL) a_eatom[j] += epairhalf;
}
if (VFLAG) {
const E_FLOAT v0 = delx*delx*fpair;
const E_FLOAT v1 = dely*dely*fpair;
const E_FLOAT v2 = delz*delz*fpair;
const E_FLOAT v3 = delx*dely*fpair;
const E_FLOAT v4 = delx*delz*fpair;
const E_FLOAT v5 = dely*delz*fpair;
if (vflag_global) {
if (NEIGHFLAG != FULL) {
ev.v[0] += v0;
ev.v[1] += v1;
ev.v[2] += v2;
ev.v[3] += v3;
ev.v[4] += v4;
ev.v[5] += v5;
} else {
ev.v[0] += 0.5*v0;
ev.v[1] += 0.5*v1;
ev.v[2] += 0.5*v2;
ev.v[3] += 0.5*v3;
ev.v[4] += 0.5*v4;
ev.v[5] += 0.5*v5;
}
}
if (vflag_atom) {
a_vatom(i,0) += 0.5*v0;
a_vatom(i,1) += 0.5*v1;
a_vatom(i,2) += 0.5*v2;
a_vatom(i,3) += 0.5*v3;
a_vatom(i,4) += 0.5*v4;
a_vatom(i,5) += 0.5*v5;
if (NEIGHFLAG != FULL) {
a_vatom(j,0) += 0.5*v0;
a_vatom(j,1) += 0.5*v1;
a_vatom(j,2) += 0.5*v2;
a_vatom(j,3) += 0.5*v3;
a_vatom(j,4) += 0.5*v4;
a_vatom(j,5) += 0.5*v5;
}
}
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::e_tally(EV_FLOAT_REAX &ev, const int &i, const int &j,
const F_FLOAT &epair) const
{
// The eatom array is atomic for Half/Thread neighbor style
if (eflag_atom) {
Kokkos::View<E_FLOAT*, typename DAT::t_efloat_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_eatom = v_eatom;
const E_FLOAT epairhalf = 0.5 * epair;
a_eatom[i] += epairhalf;
a_eatom[j] += epairhalf;
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::e_tally_single(EV_FLOAT_REAX &ev, const int &i,
const F_FLOAT &epair) const
{
// The eatom array is atomic for Half/Thread neighbor style
Kokkos::View<E_FLOAT*, typename DAT::t_efloat_1d::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_eatom = v_eatom;
a_eatom[i] += epair;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::v_tally(EV_FLOAT_REAX &ev, const int &i,
F_FLOAT *fi, F_FLOAT *drij) const
{
F_FLOAT v[6];
v[0] = 0.5*drij[0]*fi[0];
v[1] = 0.5*drij[1]*fi[1];
v[2] = 0.5*drij[2]*fi[2];
v[3] = 0.5*drij[0]*fi[1];
v[4] = 0.5*drij[0]*fi[2];
v[5] = 0.5*drij[1]*fi[2];
if (vflag_global) {
ev.v[0] += v[0];
ev.v[1] += v[1];
ev.v[2] += v[2];
ev.v[3] += v[3];
ev.v[4] += v[4];
ev.v[5] += v[5];
}
if (vflag_atom) {
Kokkos::View<F_FLOAT*[6], typename DAT::t_virial_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_vatom = v_vatom;
a_vatom(i,0) += v[0]; a_vatom(i,1) += v[1]; a_vatom(i,2) += v[2];
a_vatom(i,3) += v[3]; a_vatom(i,4) += v[4]; a_vatom(i,5) += v[5];
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::v_tally3(EV_FLOAT_REAX &ev, const int &i, const int &j, const int &k,
F_FLOAT *fj, F_FLOAT *fk, F_FLOAT *drij, F_FLOAT *drik) const
{
// The eatom and vatom arrays are atomic for Half/Thread neighbor style
Kokkos::View<F_FLOAT*[6], typename DAT::t_virial_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_vatom = v_vatom;
F_FLOAT v[6];
v[0] = drij[0]*fj[0] + drik[0]*fk[0];
v[1] = drij[1]*fj[1] + drik[1]*fk[1];
v[2] = drij[2]*fj[2] + drik[2]*fk[2];
v[3] = drij[0]*fj[1] + drik[0]*fk[1];
v[4] = drij[0]*fj[2] + drik[0]*fk[2];
v[5] = drij[1]*fj[2] + drik[1]*fk[2];
if (vflag_global) {
ev.v[0] += v[0];
ev.v[1] += v[1];
ev.v[2] += v[2];
ev.v[3] += v[3];
ev.v[4] += v[4];
ev.v[5] += v[5];
}
if (vflag_atom) {
a_vatom(i,0) += THIRD * v[0]; a_vatom(i,1) += THIRD * v[1]; a_vatom(i,2) += THIRD * v[2];
a_vatom(i,3) += THIRD * v[3]; a_vatom(i,4) += THIRD * v[4]; a_vatom(i,5) += THIRD * v[5];
a_vatom(j,0) += THIRD * v[0]; a_vatom(j,1) += THIRD * v[1]; a_vatom(j,2) += THIRD * v[2];
a_vatom(j,3) += THIRD * v[3]; a_vatom(j,4) += THIRD * v[4]; a_vatom(j,5) += THIRD * v[5];
a_vatom(k,0) += THIRD * v[0]; a_vatom(k,1) += THIRD * v[1]; a_vatom(k,2) += THIRD * v[2];
a_vatom(k,3) += THIRD * v[3]; a_vatom(k,4) += THIRD * v[4]; a_vatom(k,5) += THIRD * v[5];
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
template<int NEIGHFLAG>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::v_tally4(EV_FLOAT_REAX &ev, const int &i, const int &j, const int &k,
const int &l, F_FLOAT *fi, F_FLOAT *fj, F_FLOAT *fk, F_FLOAT *dril, F_FLOAT *drjl, F_FLOAT *drkl) const
{
// The vatom array is atomic for Half/Thread neighbor style
F_FLOAT v[6];
v[0] = dril[0]*fi[0] + drjl[0]*fj[0] + drkl[0]*fk[0];
v[1] = dril[1]*fi[1] + drjl[1]*fj[1] + drkl[1]*fk[1];
v[2] = dril[2]*fi[2] + drjl[2]*fj[2] + drkl[2]*fk[2];
v[3] = dril[0]*fi[1] + drjl[0]*fj[1] + drkl[0]*fk[1];
v[4] = dril[0]*fi[2] + drjl[0]*fj[2] + drkl[0]*fk[2];
v[5] = dril[1]*fi[2] + drjl[1]*fj[2] + drkl[1]*fk[2];
if (vflag_global) {
ev.v[0] += v[0];
ev.v[1] += v[1];
ev.v[2] += v[2];
ev.v[3] += v[3];
ev.v[4] += v[4];
ev.v[5] += v[5];
}
if (vflag_atom) {
Kokkos::View<F_FLOAT*[6], typename DAT::t_virial_array::array_layout,DeviceType,Kokkos::MemoryTraits<AtomicF<NEIGHFLAG>::value> > a_vatom = v_vatom;
a_vatom(i,0) += 0.25 * v[0]; a_vatom(i,1) += 0.25 * v[1]; a_vatom(i,2) += 0.25 * v[2];
a_vatom(i,3) += 0.25 * v[3]; a_vatom(i,4) += 0.25 * v[4]; a_vatom(i,5) += 0.25 * v[5];
a_vatom(j,0) += 0.25 * v[0]; a_vatom(j,1) += 0.25 * v[1]; a_vatom(j,2) += 0.25 * v[2];
a_vatom(j,3) += 0.25 * v[3]; a_vatom(j,4) += 0.25 * v[4]; a_vatom(j,5) += 0.25 * v[5];
a_vatom(k,0) += 0.25 * v[0]; a_vatom(k,1) += 0.25 * v[1]; a_vatom(k,2) += 0.25 * v[2];
a_vatom(k,3) += 0.25 * v[3]; a_vatom(k,4) += 0.25 * v[4]; a_vatom(k,5) += 0.25 * v[5];
a_vatom(l,0) += 0.25 * v[0]; a_vatom(l,1) += 0.25 * v[1]; a_vatom(l,2) += 0.25 * v[2];
a_vatom(l,3) += 0.25 * v[3]; a_vatom(l,4) += 0.25 * v[4]; a_vatom(l,5) += 0.25 * v[5];
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::v_tally3_atom(EV_FLOAT_REAX &ev, const int &i, const int &j, const int &k,
F_FLOAT *fj, F_FLOAT *fk, F_FLOAT *drji, F_FLOAT *drjk) const
{
F_FLOAT v[6];
v[0] = THIRD * (drji[0]*fj[0] + drjk[0]*fk[0]);
v[1] = THIRD * (drji[1]*fj[1] + drjk[1]*fk[1]);
v[2] = THIRD * (drji[2]*fj[2] + drjk[2]*fk[2]);
v[3] = THIRD * (drji[0]*fj[1] + drjk[0]*fk[1]);
v[4] = THIRD * (drji[0]*fj[2] + drjk[0]*fk[2]);
v[5] = THIRD * (drji[1]*fj[2] + drjk[1]*fk[2]);
if (vflag_global) {
ev.v[0] += v[0];
ev.v[1] += v[1];
ev.v[2] += v[2];
ev.v[3] += v[3];
ev.v[4] += v[4];
ev.v[5] += v[5];
}
if (vflag_atom) {
d_vatom(i,0) += v[0]; d_vatom(i,1) += v[1]; d_vatom(i,2) += v[2];
d_vatom(i,3) += v[3]; d_vatom(i,4) += v[4]; d_vatom(i,5) += v[5];
}
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void *PairReaxCKokkos<DeviceType>::extract(const char *str, int &dim)
{
dim = 1;
if (strcmp(str,"chi") == 0 && chi) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) chi[i] = system->reax_param.sbp[map[i]].chi;
else chi[i] = 0.0;
return (void *) chi;
}
if (strcmp(str,"eta") == 0 && eta) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) eta[i] = system->reax_param.sbp[map[i]].eta;
else eta[i] = 0.0;
return (void *) eta;
}
if (strcmp(str,"gamma") == 0 && gamma) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) gamma[i] = system->reax_param.sbp[map[i]].gamma;
else gamma[i] = 0.0;
return (void *) gamma;
}
return NULL;
}
/* ----------------------------------------------------------------------
setup for energy, virial computation
see integrate::ev_set() for values of eflag (0-3) and vflag (0-6)
------------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::ev_setup(int eflag, int vflag)
{
int i;
evflag = 1;
eflag_either = eflag;
eflag_global = eflag % 2;
eflag_atom = eflag / 2;
vflag_either = vflag;
vflag_global = vflag % 4;
vflag_atom = vflag / 4;
// reallocate per-atom arrays if necessary
if (eflag_atom && atom->nmax > maxeatom) {
maxeatom = atom->nmax;
memory->destroy_kokkos(k_eatom,eatom);
memory->create_kokkos(k_eatom,eatom,maxeatom,"pair:eatom");
v_eatom = k_eatom.view<DeviceType>();
}
if (vflag_atom && atom->nmax > maxvatom) {
maxvatom = atom->nmax;
memory->destroy_kokkos(k_vatom,vatom);
memory->create_kokkos(k_vatom,vatom,maxvatom,6,"pair:vatom");
v_vatom = k_vatom.view<DeviceType>();
}
// zero accumulators
if (eflag_global) eng_vdwl = eng_coul = 0.0;
if (vflag_global) for (i = 0; i < 6; i++) virial[i] = 0.0;
if (eflag_atom) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxZeroEAtom>(0,maxeatom),*this);
}
if (vflag_atom) {
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxZeroVAtom>(0,maxvatom),*this);
}
// if vflag_global = 2 and pair::compute() calls virial_fdotr_compute()
// compute global virial via (F dot r) instead of via pairwise summation
// unset other flags as appropriate
if (vflag_global == 2 && no_virial_fdotr_compute == 0) {
vflag_fdotr = 1;
vflag_global = 0;
if (vflag_atom == 0) vflag_either = 0;
if (vflag_either == 0 && eflag_either == 0) evflag = 0;
} else vflag_fdotr = 0;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
double PairReaxCKokkos<DeviceType>::memory_usage()
{
double bytes = 0.0;
if (cut_hbsq > 0.0) {
bytes += nmax*3*sizeof(int);
bytes += maxhb*nmax*sizeof(int);
}
bytes += nmax*2*sizeof(int);
bytes += maxbo*nmax*sizeof(int);
bytes += nmax*17*sizeof(F_FLOAT);
bytes += maxbo*nmax*34*sizeof(F_FLOAT);
// FixReaxCSpecies
if (fixspecies_flag) {
bytes += MAXSPECBOND*nmax*sizeof(tagint);
bytes += MAXSPECBOND*nmax*sizeof(F_FLOAT);
}
// FixReaxCBonds
bytes += maxbo*nmax*sizeof(tagint);
bytes += maxbo*nmax*sizeof(F_FLOAT);
bytes += nmax*sizeof(int);
return bytes;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::FindBond(int &numbonds)
{
copymode = 1;
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxFindBondZero>(0,nmax),*this);
bo_cut_bond = control->bg_cut;
atomKK->sync(execution_space,TAG_MASK);
tag = atomKK->k_tag.view<DeviceType>();
const int inum = list->inum;
NeighListKokkos<DeviceType>* k_list = static_cast<NeighListKokkos<DeviceType>*>(list);
d_ilist = k_list->d_ilist;
numbonds = 0;
PairReaxCKokkosFindBondFunctor<DeviceType> find_bond_functor(this);
Kokkos::parallel_reduce(inum,find_bond_functor,numbonds);
copymode = 0;
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxFindBondZero, const int &i) const {
d_numneigh_bonds[i] = 0;
for (int j = 0; j < maxbo; j++) {
d_neighid(i,j) = 0;
d_abo(i,j) = 0.0;
}
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::calculate_find_bond_item(int ii, int &numbonds) const
{
const int i = d_ilist[ii];
int nj = 0;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
const tagint jtag = tag[j];
const int j_index = jj - j_start;
double bo_tmp = d_BO(i,j_index);
if (bo_tmp > bo_cut_bond) {
d_neighid(i,nj) = jtag;
d_abo(i,nj) = bo_tmp;
nj++;
}
}
d_numneigh_bonds[i] = nj;
if (nj > numbonds) numbonds = nj;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::PackBondBuffer(DAT::tdual_ffloat_1d k_buf, int &nbuf_local)
{
d_buf = k_buf.view<DeviceType>();
k_params_sing.template sync<DeviceType>();
atomKK->sync(execution_space,TAG_MASK|TYPE_MASK|Q_MASK|MOLECULE_MASK);
tag = atomKK->k_tag.view<DeviceType>();
type = atomKK->k_type.view<DeviceType>();
q = atomKK->k_q.view<DeviceType>();
if (atom->molecule)
molecule = atomKK->k_molecule.view<DeviceType>();
copymode = 1;
nlocal = atomKK->nlocal;
PairReaxCKokkosPackBondBufferFunctor<DeviceType> pack_bond_buffer_functor(this);
Kokkos::parallel_scan(nlocal,pack_bond_buffer_functor);
copymode = 0;
k_buf.modify<DeviceType>();
k_nbuf_local.modify<DeviceType>();
k_buf.sync<LMPHostType>();
k_nbuf_local.sync<LMPHostType>();
nbuf_local = k_nbuf_local.h_view();
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::pack_bond_buffer_item(int i, int &j, const bool &final) const
{
if (i == 0)
j += 2;
if (final) {
d_buf[j-1] = tag[i];
d_buf[j+0] = type[i];
d_buf[j+1] = d_total_bo[i];
d_buf[j+2] = paramssing(type[i]).nlp_opt - d_Delta_lp[i];
d_buf[j+3] = q[i];
d_buf[j+4] = d_numneigh_bonds[i];
}
const int numbonds = d_numneigh_bonds[i];
if (final) {
for (int k = 5; k < 5+numbonds; k++) {
d_buf[j+k] = d_neighid(i,k-5);
}
}
j += (5+numbonds);
if (final) {
if (!molecule.data()) d_buf[j] = 0.0;
else d_buf[j] = molecule[i];
}
j++;
if (final) {
for (int k = 0; k < numbonds; k++) {
d_buf[j+k] = d_abo(i,k);
}
}
j += (1+numbonds);
if (final && i == nlocal-1)
k_nbuf_local.view<DeviceType>()() = j - 1;
}
/* ---------------------------------------------------------------------- */
template<class DeviceType>
void PairReaxCKokkos<DeviceType>::FindBondSpecies()
{
copymode = 1;
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxFindBondSpeciesZero>(0,nmax),*this);
nlocal = atomKK->nlocal;
Kokkos::parallel_for(Kokkos::RangePolicy<DeviceType, PairReaxFindBondSpecies>(0,nlocal),*this);
copymode = 0;
// NOTE: Could improve performance if a Kokkos version of ComputeSpecAtom is added
k_tmpbo.modify<DeviceType>();
k_tmpid.modify<DeviceType>();
k_error_flag.modify<DeviceType>();
k_tmpbo.sync<LMPHostType>();
k_tmpid.sync<LMPHostType>();
k_error_flag.sync<LMPHostType>();
if (k_error_flag.h_view())
error->all(FLERR,"Increase MAXSPECBOND in reaxc_defs.h");
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxFindBondSpeciesZero, const int &i) const {
for (int j = 0; j < MAXSPECBOND; j++) {
k_tmpbo.view<DeviceType>()(i,j) = 0.0;
k_tmpid.view<DeviceType>()(i,j) = 0;
}
}
template<class DeviceType>
KOKKOS_INLINE_FUNCTION
void PairReaxCKokkos<DeviceType>::operator()(PairReaxFindBondSpecies, const int &i) const {
int nj = 0;
const int j_start = d_bo_first[i];
const int j_end = j_start + d_bo_num[i];
for (int jj = j_start; jj < j_end; jj++) {
int j = d_bo_list[jj];
j &= NEIGHMASK;
if (j < i) continue;
const int j_index = jj - j_start;
double bo_tmp = d_BO(i,j_index);
if (bo_tmp >= 0.10 ) { // Why is this a hardcoded value?
k_tmpid.view<DeviceType>()(i,nj) = j;
k_tmpbo.view<DeviceType>()(i,nj) = bo_tmp;
nj++;
if (nj > MAXSPECBOND) k_error_flag.view<DeviceType>()() = 1;
}
}
}
template class PairReaxCKokkos<LMPDeviceType>;
#ifdef KOKKOS_HAVE_CUDA
template class PairReaxCKokkos<LMPHostType>;
#endif
}
diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp
index e588a30b5..479128ef2 100644
--- a/src/KSPACE/pair_born_coul_long.cpp
+++ b/src/KSPACE/pair_born_coul_long.cpp
@@ -1,582 +1,582 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Ahmed Ismail (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_born_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairBornCoulLong::PairBornCoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
ftable = NULL;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairBornCoulLong::~PairBornCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(sigma);
memory->destroy(c);
memory->destroy(d);
memory->destroy(rhoinv);
memory->destroy(born1);
memory->destroy(born2);
memory->destroy(born3);
memory->destroy(offset);
}
if (ftable) free_tables();
}
/* ---------------------------------------------------------------------- */
void PairBornCoulLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itable,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double rsq,r2inv,r6inv,forcecoul,forceborn,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
r6inv = r2inv*r2inv*r2inv;
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fpair = (forcecoul + factor_lj*forceborn) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv
+ d[itype][jtype]*r6inv*r2inv - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBornCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(c,n+1,n+1,"pair:c");
memory->create(d,n+1,n+1,"pair:d");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(born1,n+1,n+1,"pair:born1");
memory->create(born2,n+1,n+1,"pair:born2");
memory->create(born3,n+1,n+1,"pair:born3");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBornCoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBornCoulLong::coeff(int narg, char **arg)
{
if (narg < 7 || narg > 8) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[5]);
double d_one = force->numeric(FLERR,arg[6]);
double cut_lj_one = cut_lj_global;
if (narg == 8) cut_lj_one = force->numeric(FLERR,arg[7]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
sigma[i][j] = sigma_one;
c[i][j] = c_one;
d[i][j] = d_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBornCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
rhoinv[i][j] = 1.0/rho[i][j];
born1[i][j] = a[i][j]/rho[i][j];
born2[i][j] = 6.0*c[i][j];
born3[i][j] = 8.0*d[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) +
d[i][j]/pow(cut_lj[i][j],8.0);
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
d[j][i] = d[i][j];
rhoinv[j][i] = rhoinv[i][j];
sigma[j][i] = sigma[i][j];
born1[j][i] = born1[i][j];
born2[j][i] = born2[i][j];
born3[j][i] = born3[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut_lj[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
double rc5 = rc3*rc2;
etail_ij = 2.0*MY_PI*all[0]*all[1] *
(a[i][j]*exp((sigma[i][j]-rc)/rho1)*rho1*
(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3) + d[i][j]/(5.0*rc5));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1] *
(-a[i][j]*exp((sigma[i][j]-rc)/rho1) *
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) +
2.0*c[i][j]/rc3 - 8.0*d[i][j]/(5.0*rc5));
}
return cut;
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBornCoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style born/coul/long requires atom attribute q");
cut_coulsq = cut_coul * cut_coul;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
neighbor->request(this,instance_me);
// setup force tables
if (ncoultablebits) init_tables(cut_coul,NULL);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&d[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&d[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBornCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,
a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBornCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j,
a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairBornCoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forceborn,phicoul,phiborn;
int itable;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv +
born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fforce = (forcecoul + factor_lj*forceborn) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv +
d[itype][jtype]*r2inv*r6inv - offset[itype][jtype];
eng += factor_lj*phiborn;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairBornCoulLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
diff --git a/src/KSPACE/pair_buck_coul_long.cpp b/src/KSPACE/pair_buck_coul_long.cpp
index 476e3c716..95496409b 100644
--- a/src/KSPACE/pair_buck_coul_long.cpp
+++ b/src/KSPACE/pair_buck_coul_long.cpp
@@ -1,553 +1,553 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_buck_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairBuckCoulLong::PairBuckCoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
writedata = 1;
ftable = NULL;
}
/* ---------------------------------------------------------------------- */
PairBuckCoulLong::~PairBuckCoulLong()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(c);
memory->destroy(rhoinv);
memory->destroy(buck1);
memory->destroy(buck2);
memory->destroy(offset);
}
if (ftable) free_tables();
}
}
/* ---------------------------------------------------------------------- */
void PairBuckCoulLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itable,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double rsq,r2inv,r6inv,forcecoul,forcebuck,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
r6inv = r2inv*r2inv*r2inv;
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
} else forcebuck = 0.0;
fpair = (forcecoul + factor_lj*forcebuck) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBuckCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(c,n+1,n+1,"pair:c");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(buck1,n+1,n+1,"pair:buck1");
memory->create(buck2,n+1,n+1,"pair:buck2");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBuckCoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBuckCoulLong::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[4]);
double cut_lj_one = cut_lj_global;
if (narg == 6) cut_lj_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
c[i][j] = c_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBuckCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
rhoinv[i][j] = 1.0/rho[i][j];
buck1[i][j] = a[i][j]/rho[i][j];
buck2[i][j] = 6.0*c[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double rexp = exp(-cut_lj[i][j]/rho[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0);
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
rhoinv[j][i] = rhoinv[i][j];
buck1[j][i] = buck1[i][j];
buck2[j][i] = buck2[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut_lj[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
etail_ij = 2.0*MY_PI*all[0]*all[1]*
(a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]*
(-a[i][j]*exp(-rc/rho1)*
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3);
}
return cut;
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBuckCoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style buck/coul/long requires atom attribute q");
cut_coulsq = cut_coul * cut_coul;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
neighbor->request(this,instance_me);
// setup force tables
if (ncoultablebits) init_tables(cut_coul,NULL);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBuckCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBuckCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,
a[i][j],rho[i][j],c[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairBuckCoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forcebuck,phicoul,phibuck;
int itable;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
} else forcebuck = 0.0;
fforce = (forcecoul + factor_lj*forcebuck) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
eng += factor_lj*phibuck;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairBuckCoulLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
diff --git a/src/KSPACE/pair_buck_long_coul_long.cpp b/src/KSPACE/pair_buck_long_coul_long.cpp
index 8aa4d7208..4cfb9b726 100644
--- a/src/KSPACE/pair_buck_long_coul_long.cpp
+++ b/src/KSPACE/pair_buck_long_coul_long.cpp
@@ -1,1051 +1,1051 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pieter J. in 't Veld (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "math_vector.h"
#include "pair_buck_long_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairBuckLongCoulLong::PairBuckLongCoulLong(LAMMPS *lmp) : Pair(lmp)
{
dispersionflag = ewaldflag = pppmflag = 1;
respa_enable = 1;
writedata = 1;
ftable = NULL;
fdisptable = NULL;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::options(char **arg, int order)
{
const char *option[] = {"long", "cut", "off", NULL};
int i;
if (!*arg) error->all(FLERR,"Illegal pair_style buck/long/coul/long command");
for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i);
switch (i) {
default: error->all(FLERR,"Illegal pair_style buck/long/coul/long command");
case 0: ewald_order |= 1<<order; break;
case 2: ewald_off |= 1<<order;
case 1: break;
}
}
/* ---------------------------------------------------------------------- */
void PairBuckLongCoulLong::settings(int narg, char **arg)
{
if (narg != 3 && narg != 4) error->all(FLERR,"Illegal pair_style command");
ewald_order = 0;
ewald_off = 0;
options(arg,6);
options(++arg,1);
if (!comm->me && ewald_order == ((1<<1) | (1<<6)))
error->warning(FLERR,"Using largest cutoff for buck/long/coul/long");
if (!*(++arg))
error->all(FLERR,"Cutoffs missing in pair_style buck/long/coul/long");
if (ewald_off & (1<<6))
error->all(FLERR,"LJ6 off not supported in pair_style buck/long/coul/long");
if (!((ewald_order^ewald_off) & (1<<1)))
error->all(FLERR,
"Coulomb cut not supported in pair_style buck/long/coul/coul");
cut_buck_global = force->numeric(FLERR,*(arg++));
if (narg == 4 && ((ewald_order & 0x42) == 0x42))
error->all(FLERR,"Only one cutoff allowed when requesting all long");
if (narg == 4) cut_coul = force->numeric(FLERR,*arg);
else cut_coul = cut_buck_global;
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_buck[i][j] = cut_buck_global;
}
}
/* ----------------------------------------------------------------------
free all arrays
------------------------------------------------------------------------- */
PairBuckLongCoulLong::~PairBuckLongCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_buck_read);
memory->destroy(cut_buck);
memory->destroy(cut_bucksq);
memory->destroy(buck_a_read);
memory->destroy(buck_a);
memory->destroy(buck_c_read);
memory->destroy(buck_c);
memory->destroy(buck_rho_read);
memory->destroy(buck_rho);
memory->destroy(buck1);
memory->destroy(buck2);
memory->destroy(rhoinv);
memory->destroy(offset);
}
if (ftable) free_tables();
if (fdisptable) free_disp_tables();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_buck_read,n+1,n+1,"pair:cut_buck_read");
memory->create(cut_buck,n+1,n+1,"pair:cut_buck");
memory->create(cut_bucksq,n+1,n+1,"pair:cut_bucksq");
memory->create(buck_a_read,n+1,n+1,"pair:buck_a_read");
memory->create(buck_a,n+1,n+1,"pair:buck_a");
memory->create(buck_c_read,n+1,n+1,"pair:buck_c_read");
memory->create(buck_c,n+1,n+1,"pair:buck_c");
memory->create(buck_rho_read,n+1,n+1,"pair:buck_rho_read");
memory->create(buck_rho,n+1,n+1,"pair:buck_rho");
memory->create(buck1,n+1,n+1,"pair:buck1");
memory->create(buck2,n+1,n+1,"pair:buck2");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
extract protected data from object
------------------------------------------------------------------------- */
void *PairBuckLongCoulLong::extract(const char *id, int &dim)
{
const char *ids[] = {
"B", "ewald_order", "ewald_cut", "ewald_mix", "cut_coul", "cut_LJ", NULL};
void *ptrs[] = {
buck_c, &ewald_order, &cut_coul, &mix_flag, &cut_coul, &cut_buck_global,
NULL};
int i;
for (i=0; ids[i]&&strcmp(ids[i], id); ++i);
if (i == 0) dim = 2;
else dim = 0;
return ptrs[i];
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,*(arg++),atom->ntypes,ilo,ihi);
force->bounds(FLERR,*(arg++),atom->ntypes,jlo,jhi);
double buck_a_one = force->numeric(FLERR,*(arg++));
double buck_rho_one = force->numeric(FLERR,*(arg++));
double buck_c_one = force->numeric(FLERR,*(arg++));
double cut_buck_one = cut_buck_global;
if (narg == 6) cut_buck_one = force->numeric(FLERR,*(arg++));
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
buck_a_read[i][j] = buck_a_one;
buck_c_read[i][j] = buck_c_one;
buck_rho_read[i][j] = buck_rho_one;
cut_buck_read[i][j] = cut_buck_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::init_style()
{
// require an atom style with charge defined
if (!atom->q_flag && (ewald_order&(1<<1)))
error->all(FLERR,
"Invoking coulombic in pair style buck/long/coul/long requires atom attribute q");
// ensure use of KSpace long-range solver, set two g_ewalds
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
if (ewald_order&(1<<1)) g_ewald = force->kspace->g_ewald;
if (ewald_order&(1<<6)) g_ewald_6 = force->kspace->g_ewald_6;
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
// setup force tables
if (ncoultablebits && (ewald_order&(1<<1))) init_tables(cut_coul,cut_respa);
if (ndisptablebits && (ewald_order&(1<<6))) init_tables_disp(cut_buck_global);
// request regular or rRESPA neighbor lists if neighrequest_flag != 0
if (force->kspace->neighrequest_flag) {
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
}
cut_coulsq = cut_coul * cut_coul;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBuckLongCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
if (ewald_order&(1<<6)) cut_buck[i][j] = cut_buck_global;
else cut_buck[i][j] = cut_buck_read[i][j];
buck_a[i][j] = buck_a_read[i][j];
buck_c[i][j] = buck_c_read[i][j];
buck_rho[i][j] = buck_rho_read[i][j];
double cut = MAX(cut_buck[i][j],cut_coul);
cutsq[i][j] = cut*cut;
cut_bucksq[i][j] = cut_buck[i][j] * cut_buck[i][j];
buck1[i][j] = buck_a[i][j]/buck_rho[i][j];
buck2[i][j] = 6.0*buck_c[i][j];
rhoinv[i][j] = 1.0/buck_rho[i][j];
// check interior rRESPA cutoff
if (cut_respa && MIN(cut_buck[i][j],cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
- if (offset_flag) {
+ if (offset_flag && (cut_buck[i][j] > 0.0)) {
double rexp = exp(-cut_buck[i][j]/buck_rho[i][j]);
offset[i][j] = buck_a[i][j]*rexp - buck_c[i][j]/pow(cut_buck[i][j],6.0);
} else offset[i][j] = 0.0;
cutsq[j][i] = cutsq[i][j];
cut_bucksq[j][i] = cut_bucksq[i][j];
buck_a[j][i] = buck_a[i][j];
buck_c[j][i] = buck_c[i][j];
rhoinv[j][i] = rhoinv[i][j];
buck1[j][i] = buck1[i][j];
buck2[j][i] = buck2[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&buck_a_read[i][j],sizeof(double),1,fp);
fwrite(&buck_rho_read[i][j],sizeof(double),1,fp);
fwrite(&buck_c_read[i][j],sizeof(double),1,fp);
fwrite(&cut_buck_read[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&buck_a_read[i][j],sizeof(double),1,fp);
fread(&buck_rho_read[i][j],sizeof(double),1,fp);
fread(&buck_c_read[i][j],sizeof(double),1,fp);
fread(&cut_buck_read[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&buck_a_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&buck_rho_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&buck_c_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_buck_read[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_buck_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
fwrite(&ewald_order,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_buck_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
fread(&ewald_order,sizeof(int),1,fp);
}
MPI_Bcast(&cut_buck_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
MPI_Bcast(&ewald_order,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,
buck_a_read[i][i],buck_rho_read[i][i],buck_c_read[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,
buck_a_read[i][j],buck_rho_read[i][j],buck_c_read[i][j]);
}
/* ----------------------------------------------------------------------
compute pair interactions
------------------------------------------------------------------------- */
void PairBuckLongCoulLong::compute(int eflag, int vflag)
{
double evdwl,ecoul,fpair;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x, *x0 = x[0];
double **f = atom->f, *f0 = f[0], *fi = f0;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
double qi = 0.0, qri = 0.0, *cutsqi, *cut_bucksqi,
*buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti;
double r, rsq, r2inv, force_coul, force_buck;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
vector xi, d;
ineighn = (ineigh = list->ilist)+list->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = (qi = q[i])*qqrd2e; // initialize constants
offseti = offset[typei = type[i]];
buck1i = buck1[typei]; buck2i = buck2[typei];
buckai = buck_a[typei]; buckci = buck_c[typei], rhoinvi = rhoinv[typei];
cutsqi = cutsq[typei]; cut_bucksqi = cut_bucksq[typei];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
jneighn = (jneigh = list->firstneigh[i])+list->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cutsqi[typej = type[j]]) continue;
r2inv = 1.0/rsq;
r = sqrt(rsq);
if (order1 && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double x = g_ewald*r;
register double s = qri*q[j], t = 1.0/(1.0+EWALD_P*x);
if (ni == 0) {
s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s;
if (eflag) ecoul = t;
}
else { // special case
register double f = s*(1.0-special_coul[ni])/r;
s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-f;
if (eflag) ecoul = t-f;
}
} // table real space
else {
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask) >> ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j];
if (ni == 0) {
force_coul = qiqj*(ftable[k]+f*dftable[k]);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]);
}
else { // special case
t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]-t.f);
}
}
}
else force_coul = ecoul = 0.0;
if (rsq < cut_bucksqi[typej]) { // buckingham
register double rn = r2inv*r2inv*r2inv,
expr = exp(-r*rhoinvi[typej]);
if (order6) { // long-range
if (!ndisptablebits || rsq <= tabinnerdispsq) {
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*buckci[typej];
if (ni == 0) {
force_buck =
r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
if (eflag) evdwl = expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_buck = f*r*expr*buck1i[typej]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej];
if (eflag) evdwl = f*expr*buckai[typej] -
g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej];
}
}
else { //table real space
register union_int_float_t disp_t;
disp_t.f = rsq;
register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits;
register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k];
if (ni == 0) {
force_buck = r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej];
if (eflag) evdwl = expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej];
}
else { //speial case
register double f = special_lj[ni], t = rn*(1.0-f);
force_buck = f*r*expr*buck1i[typej] -(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej] +t*buck2i[typej];
if (eflag) evdwl = f*expr*buckai[typej] -(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]+t*buckci[typej];
}
}
}
else { // cut
if (ni == 0) {
force_buck = r*expr*buck1i[typej]-rn*buck2i[typej];
if (eflag) evdwl = expr*buckai[typej] -
rn*buckci[typej]-offseti[typej];
}
else { // special case
register double f = special_lj[ni];
force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej]);
if (eflag)
evdwl = f*(expr*buckai[typej]-rn*buckci[typej]-offseti[typej]);
}
}
}
else force_buck = evdwl = 0.0;
fpair = (force_coul+force_buck)*r2inv;
if (newton_pair || j < nlocal) {
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,d[0],d[1],d[2]);
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairBuckLongCoulLong::compute_inner()
{
double r, rsq, r2inv, force_coul = 0.0, force_buck, fpair;
int *type = atom->type;
int nlocal = atom->nlocal;
double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1);
double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi;
vector xi, d;
ineighn = (ineigh = listinner->ilist) + listinner->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = qqrd2e*q[i];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
cut_bucksqi = cut_bucksq[typei = type[i]];
buck1i = buck1[typei]; buck2i = buck2[typei]; rhoinvi = rhoinv[typei];
jneighn = (jneigh = listinner->firstneigh[i])+listinner->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cut_out_off_sq) continue;
r2inv = 1.0/rsq;
r = sqrt(rsq);
if (order1 && (rsq < cut_coulsq)) // coulombic
force_coul = ni == 0 ?
qri*q[j]/r : qri*q[j]/r*special_coul[ni];
if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham
register double rn = r2inv*r2inv*r2inv,
expr = exp(-r*rhoinvi[typej]);
force_buck = ni == 0 ?
(r*expr*buck1i[typej]-rn*buck2i[typej]) :
(r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni];
}
else force_buck = 0.0;
fpair = (force_coul + force_buck) * r2inv;
if (rsq > cut_out_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
if (newton_pair || j < nlocal) { // force update
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairBuckLongCoulLong::compute_middle()
{
double r, rsq, r2inv, force_coul = 0.0, force_buck, fpair;
int *type = atom->type;
int nlocal = atom->nlocal;
double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1);
double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi;
vector xi, d;
ineighn = (ineigh = listmiddle->ilist)+listmiddle->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = qqrd2e*q[i];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
cut_bucksqi = cut_bucksq[typei = type[i]];
buck1i = buck1[typei]; buck2i = buck2[typei]; rhoinvi = rhoinv[typei];
jneighn = (jneigh = listmiddle->firstneigh[i])+listmiddle->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cut_out_off_sq) continue;
if (rsq <= cut_in_off_sq) continue;
r2inv = 1.0/rsq;
r = sqrt(rsq);
if (order1 && (rsq < cut_coulsq)) // coulombic
force_coul = ni == 0 ?
qri*q[j]/r : qri*q[j]/r*special_coul[ni];
if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham
register double rn = r2inv*r2inv*r2inv,
expr = exp(-r*rhoinvi[typej]);
force_buck = ni == 0 ?
(r*expr*buck1i[typej]-rn*buck2i[typej]) :
(r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni];
}
else force_buck = 0.0;
fpair = (force_coul + force_buck) * r2inv;
if (rsq < cut_in_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
if (newton_pair || j < nlocal) { // force update
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairBuckLongCoulLong::compute_outer(int eflag, int vflag)
{
double evdwl,ecoul,fpair,fvirial;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x, *x0 = x[0];
double **f = atom->f, *f0 = f[0], *fi = f0;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag;
double qi = 0.0, qri = 0.0, *cutsqi, *cut_bucksqi,
*buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti;
double r, rsq, r2inv, force_coul, force_buck;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
double respa_buck = 0.0, respa_coul = 0.0, frespa = 0.0;
vector xi, d;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
ineighn = (ineigh = listouter->ilist)+listouter->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = (qi = q[i])*qqrd2e; // initialize constants
offseti = offset[typei = type[i]];
buck1i = buck1[typei]; buck2i = buck2[typei];
buckai = buck_a[typei]; buckci = buck_c[typei]; rhoinvi = rhoinv[typei];
cutsqi = cutsq[typei]; cut_bucksqi = cut_bucksq[typei];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
jneighn = (jneigh = listouter->firstneigh[i])+listouter->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cutsqi[typej = type[j]]) continue;
r2inv = 1.0/rsq;
r = sqrt(rsq);
frespa = 1.0; //check whether and how to compute respa corrections
respa_coul = 0.0;
respa_buck = 0.0;
respa_flag = rsq < cut_in_on_sq ? 1 : 0;
if (respa_flag && (rsq > cut_in_off_sq)) {
register double rsw = (r-cut_in_off)/cut_in_diff;
frespa = 1-rsw*rsw*(3.0-2.0*rsw);
}
if (order1 && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double s = qri*q[j];
if (respa_flag) // correct for respa
respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni];
register double x = g_ewald*r, t = 1.0/(1.0+EWALD_P*x);
if (ni == 0) {
s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-respa_coul;
if (eflag) ecoul = t;
}
else { // correct for special
register double ri = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-ri-respa_coul;
if (eflag) ecoul = t-ri;
}
} // table real space
else {
if (respa_flag) {
register double s = qri*q[j];
respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni];
}
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask) >> ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j];
if (ni == 0) {
force_coul = qiqj*(ftable[k]+f*dftable[k]);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]);
}
else { // correct for special
t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
if (eflag) {
t.f = (1.0-special_coul[ni])*(ptable[k]+f*dptable[k]);
ecoul = qiqj*(etable[k]+f*detable[k]-t.f);
}
}
}
}
else force_coul = respa_coul = ecoul = 0.0;
if (rsq < cut_bucksqi[typej]) { // buckingham
register double rn = r2inv*r2inv*r2inv,
expr = exp(-r*rhoinvi[typej]);
if (respa_flag) respa_buck = ni == 0 ? // correct for respa
frespa*(r*expr*buck1i[typej]-rn*buck2i[typej]) :
frespa*(r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni];
if (order6) { // long-range form
if (!ndisptablebits || rsq <= tabinnerdispsq) {
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*buckci[typej];
if (ni == 0) {
force_buck =
r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq-respa_buck;
if (eflag) evdwl = expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // correct for special
register double f = special_lj[ni], t = rn*(1.0-f);
force_buck = f*r*expr*buck1i[typej]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej]-respa_buck;
if (eflag) evdwl = f*expr*buckai[typej] -
g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej];
}
}
else { // table real space
register union_int_float_t disp_t;
disp_t.f = rsq;
register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits;
register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k];
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) {
force_buck = r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej]-respa_buck;
if (eflag) evdwl = expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej];
}
else { //special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_buck = f*r*expr*buck1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*buckci[typej]+t*buck2i[typej]-respa_buck;
if (eflag) evdwl = f*expr*buckai[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*buckci[typej]+t*buckci[typej];
}
}
}
else { // cut form
if (ni == 0) {
force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]-respa_buck;
if (eflag)
evdwl = expr*buckai[typej]-rn*buckci[typej]-offseti[typej];
}
else { // correct for special
register double f = special_lj[ni];
force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej])-respa_buck;
if (eflag)
evdwl = f*(expr*buckai[typej]-rn*buckci[typej]-offseti[typej]);
}
}
}
else force_buck = respa_buck = evdwl = 0.0;
fpair = (force_coul+force_buck)*r2inv;
if (newton_pair || j < nlocal) {
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
if (evflag) {
fvirial = (force_coul + force_buck + respa_coul + respa_buck)*r2inv;
ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fvirial,d[0],d[1],d[2]);
}
}
}
}
/* ---------------------------------------------------------------------- */
double PairBuckLongCoulLong::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_buck,
double &fforce)
{
double f, r, r2inv, r6inv, force_coul, force_buck;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q;
r = sqrt(rsq);
r2inv = 1.0/rsq;
double eng = 0.0;
if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double x = g_ewald*r;
register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x);
f = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-f;
eng += t-f;
}
else { // table real space
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask) >> ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j];
t.f = (1.0-factor_coul)*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
eng += qiqj*(etable[k]+f*detable[k]-t.f);
}
} else force_coul = 0.0;
if (rsq < cut_bucksq[itype][jtype]) { // buckingham
register double expr = factor_buck*exp(-sqrt(rsq)*rhoinv[itype][jtype]);
r6inv = r2inv*r2inv*r2inv;
if (ewald_order&64) { // long-range
register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_buck);
x2 = a2*exp(-x2)*buck_c[itype][jtype];
force_buck = buck1[itype][jtype]*r*expr-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*buck2[itype][jtype];
eng += buck_a[itype][jtype]*expr-
g6*((a2+1.0)*a2+0.5)*x2+t*buck_c[itype][jtype];
}
else { // cut
force_buck =
buck1[itype][jtype]*r*expr-factor_buck*buck_c[itype][jtype]*r6inv;
eng += buck_a[itype][jtype]*expr-
factor_buck*(buck_c[itype][jtype]*r6inv-offset[itype][jtype]);
}
} else force_buck = 0.0;
fforce = (force_coul+force_buck)*r2inv;
return eng;
}
diff --git a/src/KSPACE/pair_lj_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp
index e9799843f..f8be9fdb7 100644
--- a/src/KSPACE/pair_lj_cut_coul_long.cpp
+++ b/src/KSPACE/pair_lj_cut_coul_long.cpp
@@ -1,978 +1,978 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJCutCoulLong::PairLJCutCoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
respa_enable = 1;
writedata = 1;
ftable = NULL;
qdist = 0.0;
}
/* ---------------------------------------------------------------------- */
PairLJCutCoulLong::~PairLJCutCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
if (ftable) free_tables();
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLong::compute(int eflag, int vflag)
{
int i,ii,j,jj,inum,jnum,itype,jtype,itable;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLong::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
double rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
r2inv = 1.0/rsq;
forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
jtype = type[j];
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLong::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
double rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
jtype = type[j];
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLong::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double r,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2 - 1.0);
if (rsq > cut_in_off_sq) {
if (rsq < cut_in_on_sq) {
rsw = (r - cut_in_off)/cut_in_diff;
forcecoul += prefactor*rsw*rsw*(3.0 - 2.0*rsw);
if (factor_coul < 1.0)
forcecoul -=
(1.0-factor_coul)*prefactor*rsw*rsw*(3.0 - 2.0*rsw);
} else {
forcecoul += prefactor;
if (factor_coul < 1.0)
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype] && rsq > cut_in_off_sq) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
forcelj *= rsw*rsw*(3.0 - 2.0*rsw);
}
} else forcelj = 0.0;
fpair = (forcecoul + forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
ecoul = prefactor*erfc;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ptable[itable] + fraction*dptable[itable];
prefactor = qtmp*q[j] * table;
ecoul -= (1.0-factor_coul)*prefactor;
}
}
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (vflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
table = vtable[itable] + fraction*dvtable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ptable[itable] + fraction*dptable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq <= cut_in_off_sq) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else if (rsq <= cut_in_on_sq) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
}
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutCoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutCoulLong::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutCoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q");
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
// setup force tables
if (ncoultablebits) init_tables(cut_coul,cut_respa);
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCutCoulLong::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutCoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forcelj,phicoul,philj;
int itable;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup_single;
rsq_lookup_single.f = rsq;
itable = rsq_lookup_single.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fforce = (forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutCoulLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
return NULL;
}
diff --git a/src/KSPACE/pair_lj_long_coul_long.cpp b/src/KSPACE/pair_lj_long_coul_long.cpp
index 44256a9fb..7c6adfcb4 100644
--- a/src/KSPACE/pair_lj_long_coul_long.cpp
+++ b/src/KSPACE/pair_lj_long_coul_long.cpp
@@ -1,1039 +1,1039 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pieter J. in 't Veld (SNL)
Tabulation for long-range dispersion added by Wayne Mitchell (Loyola
University New Orleans)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "math_vector.h"
#include "pair_lj_long_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJLongCoulLong::PairLJLongCoulLong(LAMMPS *lmp) : Pair(lmp)
{
dispersionflag = ewaldflag = pppmflag = 1;
respa_enable = 1;
writedata = 1;
ftable = NULL;
fdisptable = NULL;
qdist = 0.0;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJLongCoulLong::options(char **arg, int order)
{
const char *option[] = {"long", "cut", "off", NULL};
int i;
if (!*arg) error->all(FLERR,"Illegal pair_style lj/long/coul/long command");
for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i);
switch (i) {
default: error->all(FLERR,"Illegal pair_style lj/long/coul/long command");
case 0: ewald_order |= 1<<order; break;
case 2: ewald_off |= 1<<order;
case 1: break;
}
}
void PairLJLongCoulLong::settings(int narg, char **arg)
{
if (narg != 3 && narg != 4) error->all(FLERR,"Illegal pair_style command");
ewald_order = 0;
ewald_off = 0;
options(arg,6);
options(++arg,1);
if (!comm->me && ewald_order == ((1<<1) | (1<<6)))
error->warning(FLERR,"Using largest cutoff for lj/long/coul/long");
if (!*(++arg))
error->all(FLERR,"Cutoffs missing in pair_style lj/long/coul/long");
if (!((ewald_order^ewald_off) & (1<<1)))
error->all(FLERR,
"Coulomb cut not supported in pair_style lj/long/coul/long");
cut_lj_global = force->numeric(FLERR,*(arg++));
if (narg == 4 && ((ewald_order & 0x42) == 0x42))
error->all(FLERR,"Only one cutoff allowed when requesting all long");
if (narg == 4) cut_coul = force->numeric(FLERR,*arg);
else cut_coul = cut_lj_global;
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
free all arrays
------------------------------------------------------------------------- */
PairLJLongCoulLong::~PairLJLongCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj_read);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon_read);
memory->destroy(epsilon);
memory->destroy(sigma_read);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
if (ftable) free_tables();
if (fdisptable) free_disp_tables();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJLongCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj_read,n+1,n+1,"pair:cut_lj_read");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon_read,n+1,n+1,"pair:epsilon_read");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma_read,n+1,n+1,"pair:sigma_read");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
extract protected data from object
------------------------------------------------------------------------- */
void *PairLJLongCoulLong::extract(const char *id, int &dim)
{
const char *ids[] = {
"B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix",
"cut_coul", "cut_LJ", NULL};
void *ptrs[] = {
lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag,
&cut_coul, &cut_lj_global, NULL};
int i;
for (i=0; ids[i]&&strcmp(ids[i], id); ++i);
if (i <= 2) dim = 2;
else dim = 0;
return ptrs[i];
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJLongCoulLong::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon_read[i][j] = epsilon_one;
sigma_read[i][j] = sigma_one;
cut_lj_read[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJLongCoulLong::init_style()
{
// require an atom style with charge defined
if (!atom->q_flag && (ewald_order&(1<<1)))
error->all(FLERR,
"Invoking coulombic in pair style lj/long/coul/long requires atom attribute q");
// ensure use of KSpace long-range solver, set two g_ewalds
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
if (ewald_order&(1<<1)) g_ewald = force->kspace->g_ewald;
if (ewald_order&(1<<6)) g_ewald_6 = force->kspace->g_ewald_6;
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
// setup force tables
if (ncoultablebits && (ewald_order&(1<<1))) init_tables(cut_coul,cut_respa);
if (ndisptablebits && (ewald_order&(1<<6))) init_tables_disp(cut_lj_global);
// request regular or rRESPA neighbor lists if neighrequest_flag != 0
if (force->kspace->neighrequest_flag) {
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
}
cut_coulsq = cut_coul * cut_coul;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJLongCoulLong::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJLongCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon_read[i][i],epsilon_read[j][j],
sigma_read[i][i],sigma_read[j][j]);
sigma[i][j] = mix_distance(sigma_read[i][i],sigma_read[j][j]);
if (ewald_order&(1<<6))
cut_lj[i][j] = cut_lj_global;
else
cut_lj[i][j] = mix_distance(cut_lj_read[i][i],cut_lj_read[j][j]);
}
else {
sigma[i][j] = sigma_read[i][j];
epsilon[i][j] = epsilon_read[i][j];
cut_lj[i][j] = cut_lj_read[i][j];
}
double cut = MAX(cut_lj[i][j], cut_coul + 2.0*qdist);
cutsq[i][j] = cut*cut;
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
// check interior rRESPA cutoff
if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cutsq[j][i] = cutsq[i][j];
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJLongCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon_read[i][j],sizeof(double),1,fp);
fwrite(&sigma_read[i][j],sizeof(double),1,fp);
fwrite(&cut_lj_read[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJLongCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon_read[i][j],sizeof(double),1,fp);
fread(&sigma_read[i][j],sizeof(double),1,fp);
fread(&cut_lj_read[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_read[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_read[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJLongCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
fwrite(&ewald_order,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJLongCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
fread(&ewald_order,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
MPI_Bcast(&ewald_order,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJLongCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon_read[i][i],sigma_read[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJLongCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,
epsilon_read[i][j],sigma_read[i][j],cut_lj_read[i][j]);
}
/* ----------------------------------------------------------------------
compute pair interactions
------------------------------------------------------------------------- */
void PairLJLongCoulLong::compute(int eflag, int vflag)
{
double evdwl,ecoul,fpair;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x, *x0 = x[0];
double **f = atom->f, *f0 = f[0], *fi = f0;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
double qi = 0.0, qri = 0.0;
double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double rsq, r2inv, force_coul, force_lj;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
vector xi, d;
ineighn = (ineigh = list->ilist)+list->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = (qi = q[i])*qqrd2e; // initialize constants
offseti = offset[typei = type[i]];
lj1i = lj1[typei]; lj2i = lj2[typei]; lj3i = lj3[typei]; lj4i = lj4[typei];
cutsqi = cutsq[typei]; cut_ljsqi = cut_ljsq[typei];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
jneighn = (jneigh = list->firstneigh[i])+list->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cutsqi[typej = type[j]]) continue;
r2inv = 1.0/rsq;
if (order1 && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double r = sqrt(rsq), x = g_ewald*r;
register double s = qri*q[j], t = 1.0/(1.0+EWALD_P*x);
if (ni == 0) {
s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s;
if (eflag) ecoul = t;
}
else { // special case
r = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r;
if (eflag) ecoul = t-r;
}
} // table real space
else {
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask)>>ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j];
if (ni == 0) {
force_coul = qiqj*(ftable[k]+f*dftable[k]);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]);
}
else { // special case
t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]-t.f);
}
}
}
else force_coul = ecoul = 0.0;
if (rsq < cut_ljsqi[typej]) { // lj
if (order6) { // long-range lj
if(!ndisptablebits || rsq <= tabinnerdispsq) { // series real space
register double rn = r2inv*r2inv*r2inv;
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*lj4i[typej];
if (ni == 0) {
force_lj =
(rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
if (eflag)
evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_lj = f*(rn *= rn)*lj1i[typej]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej];
if (eflag)
evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej];
}
}
else { // table real space
register union_int_float_t disp_t;
disp_t.f = rsq;
register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits;
register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k];
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) {
force_lj = (rn*=rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej];
if (eflag) evdwl = rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej];
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_lj = f*(rn *= rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]+t*lj2i[typej];
if (eflag) evdwl = f*rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]+t*lj4i[typej];
}
}
}
else { // cut lj
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) {
force_lj = rn*(rn*lj1i[typej]-lj2i[typej]);
if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej];
}
else { // special case
register double f = special_lj[ni];
force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]);
if (eflag)
evdwl = f * (rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]);
}
}
}
else force_lj = evdwl = 0.0;
fpair = (force_coul+force_lj)*r2inv;
if (newton_pair || j < nlocal) {
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,d[0],d[1],d[2]);
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJLongCoulLong::compute_inner()
{
double rsq, r2inv, force_coul = 0.0, force_lj, fpair;
int *type = atom->type;
int nlocal = atom->nlocal;
double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1);
double qri, *cut_ljsqi, *lj1i, *lj2i;
vector xi, d;
ineighn = (ineigh = listinner->ilist)+listinner->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
cut_ljsqi = cut_ljsq[typei = type[i]];
lj1i = lj1[typei]; lj2i = lj2[typei];
jneighn = (jneigh = listinner->firstneigh[i])+listinner->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cut_out_off_sq) continue;
r2inv = 1.0/rsq;
if (order1 && (rsq < cut_coulsq)) { // coulombic
qri = qqrd2e*q[i];
force_coul = ni == 0 ?
qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni];
}
if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones
register double rn = r2inv*r2inv*r2inv;
force_lj = ni == 0 ?
rn*(rn*lj1i[typej]-lj2i[typej]) :
rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni];
}
else force_lj = 0.0;
fpair = (force_coul + force_lj) * r2inv;
if (rsq > cut_out_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
if (newton_pair || j < nlocal) { // force update
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJLongCoulLong::compute_middle()
{
double rsq, r2inv, force_coul = 0.0, force_lj, fpair;
int *type = atom->type;
int nlocal = atom->nlocal;
double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni;
int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1);
double qri, *cut_ljsqi, *lj1i, *lj2i;
vector xi, d;
ineighn = (ineigh = listmiddle->ilist)+listmiddle->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = qqrd2e*q[i];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
cut_ljsqi = cut_ljsq[typei = type[i]];
lj1i = lj1[typei]; lj2i = lj2[typei];
jneighn = (jneigh = listmiddle->firstneigh[i])+listmiddle->numneigh[i];
for (; jneigh<jneighn; ++jneigh) {
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cut_out_off_sq) continue;
if (rsq <= cut_in_off_sq) continue;
r2inv = 1.0/rsq;
if (order1 && (rsq < cut_coulsq)) // coulombic
force_coul = ni == 0 ?
qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni];
if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones
register double rn = r2inv*r2inv*r2inv;
force_lj = ni == 0 ?
rn*(rn*lj1i[typej]-lj2i[typej]) :
rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni];
}
else force_lj = 0.0;
fpair = (force_coul + force_lj) * r2inv;
if (rsq < cut_in_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
if (newton_pair || j < nlocal) { // force update
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJLongCoulLong::compute_outer(int eflag, int vflag)
{
double evdwl,ecoul,fvirial,fpair;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x, *x0 = x[0];
double **f = atom->f, *f0 = f[0], *fi = f0;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag;
double qi = 0.0, qri = 0.0;
double *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double rsq, r2inv, force_coul, force_lj;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
double respa_lj = 0.0, respa_coul = 0.0, frespa = 0.0;
vector xi, d;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
ineighn = (ineigh = listouter->ilist)+listouter->inum;
for (; ineigh<ineighn; ++ineigh) { // loop over my atoms
i = *ineigh; fi = f0+3*i;
if (order1) qri = (qi = q[i])*qqrd2e; // initialize constants
offseti = offset[typei = type[i]];
lj1i = lj1[typei]; lj2i = lj2[typei]; lj3i = lj3[typei]; lj4i = lj4[typei];
cutsqi = cutsq[typei]; cut_ljsqi = cut_ljsq[typei];
memcpy(xi, x0+(i+(i<<1)), sizeof(vector));
jneighn = (jneigh = listouter->firstneigh[i])+listouter->numneigh[i];
for (; jneigh<jneighn; ++jneigh) { // loop over neighbors
j = *jneigh;
ni = sbmask(j);
j &= NEIGHMASK;
{ register double *xj = x0+(j+(j<<1));
d[0] = xi[0] - xj[0]; // pair vector
d[1] = xi[1] - xj[1];
d[2] = xi[2] - xj[2]; }
if ((rsq = vec_dot(d, d)) >= cutsqi[typej = type[j]]) continue;
r2inv = 1.0/rsq;
frespa = 1.0; // check whether and how to compute respa corrections
respa_coul = 0;
respa_lj = 0;
respa_flag = rsq < cut_in_on_sq ? 1 : 0;
if (respa_flag && (rsq > cut_in_off_sq)) {
register double rsw = (sqrt(rsq)-cut_in_off)/cut_in_diff;
frespa = 1-rsw*rsw*(3.0-2.0*rsw);
}
if (order1 && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double r = sqrt(rsq), s = qri*q[j];
if (respa_flag) // correct for respa
respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni];
register double x = g_ewald*r, t = 1.0/(1.0+EWALD_P*x);
if (ni == 0) {
s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-respa_coul;
if (eflag) ecoul = t;
}
else { // correct for special
r = s*(1.0-special_coul[ni])/r; s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r-respa_coul;
if (eflag) ecoul = t-r;
}
} // table real space
else {
if (respa_flag) {
register double r = sqrt(rsq), s = qri*q[j];
respa_coul = ni == 0 ? frespa*s/r : frespa*s/r*special_coul[ni];
}
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask) >> ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j];
if (ni == 0) {
force_coul = qiqj*(ftable[k]+f*dftable[k]);
if (eflag) ecoul = qiqj*(etable[k]+f*detable[k]);
}
else { // correct for special
t.f = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
if (eflag) {
t.f = (1.0-special_coul[ni])*(ptable[k]+f*dptable[k]);
ecoul = qiqj*(etable[k]+f*detable[k]-t.f);
}
}
}
}
else force_coul = respa_coul = ecoul = 0.0;
if (rsq < cut_ljsqi[typej]) { // lennard-jones
register double rn = r2inv*r2inv*r2inv;
if (respa_flag) respa_lj = ni == 0 ? // correct for respa
frespa*rn*(rn*lj1i[typej]-lj2i[typej]) :
frespa*rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni];
if (order6) { // long-range form
if (!ndisptablebits || rsq <= tabinnerdispsq) {
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*lj4i[typej];
if (ni == 0) {
force_lj =
(rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq-respa_lj;
if (eflag) evdwl = rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // correct for special
register double f = special_lj[ni], t = rn*(1.0-f);
force_lj = f*(rn *= rn)*lj1i[typej]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]-respa_lj;
if (eflag)
evdwl = f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej];
}
}
else { // table real space
register union_int_float_t disp_t;
disp_t.f = rsq;
register const int disp_k = (disp_t.i & ndispmask)>>ndispshiftbits;
register double f_disp = (rsq-rdisptable[disp_k])*drdisptable[disp_k];
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) {
force_lj = (rn*=rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]-respa_lj;
if (eflag) evdwl = rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej];
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
force_lj = f*(rn *= rn)*lj1i[typej]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[typej]+t*lj2i[typej]-respa_lj;
if (eflag) evdwl = f*rn*lj3i[typej]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[typej]+t*lj4i[typej];
}
}
}
else { // cut form
if (ni == 0) {
force_lj = rn*(rn*lj1i[typej]-lj2i[typej])-respa_lj;
if (eflag) evdwl = rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej];
}
else { // correct for special
register double f = special_lj[ni];
force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej])-respa_lj;
if (eflag)
evdwl = f*(rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]);
}
}
}
else force_lj = respa_lj = evdwl = 0.0;
fpair = (force_coul+force_lj)*r2inv;
if (newton_pair || j < nlocal) {
register double *fj = f0+(j+(j<<1)), f;
fi[0] += f = d[0]*fpair; fj[0] -= f;
fi[1] += f = d[1]*fpair; fj[1] -= f;
fi[2] += f = d[2]*fpair; fj[2] -= f;
}
else {
fi[0] += d[0]*fpair;
fi[1] += d[1]*fpair;
fi[2] += d[2]*fpair;
}
if (evflag) {
fvirial = (force_coul + force_lj + respa_coul + respa_lj)*r2inv;
ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fvirial,d[0],d[1],d[2]);
}
}
}
}
/* ---------------------------------------------------------------------- */
double PairLJLongCoulLong::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r2inv, r6inv, force_coul, force_lj;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q;
double eng = 0.0;
r2inv = 1.0/rsq;
if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic
if (!ncoultablebits || rsq <= tabinnersq) { // series real space
register double r = sqrt(rsq), x = g_ewald*r;
register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x);
r = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x);
force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r;
eng += t-r;
}
else { // table real space
register union_int_float_t t;
t.f = rsq;
register const int k = (t.i & ncoulmask) >> ncoulshiftbits;
register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j];
t.f = (1.0-factor_coul)*(ctable[k]+f*dctable[k]);
force_coul = qiqj*(ftable[k]+f*dftable[k]-t.f);
eng += qiqj*(etable[k]+f*detable[k]-t.f);
}
} else force_coul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) { // lennard-jones
r6inv = r2inv*r2inv*r2inv;
if (ewald_order&64) { // long-range
register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_lj);
x2 = a2*exp(-x2)*lj4[itype][jtype];
force_lj = factor_lj*(r6inv *= r6inv)*lj1[itype][jtype]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*lj2[itype][jtype];
eng += factor_lj*r6inv*lj3[itype][jtype]-
g6*((a2+1.0)*a2+0.5)*x2+t*lj4[itype][jtype];
}
else { // cut
force_lj = factor_lj*r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]);
eng += factor_lj*(r6inv*(r6inv*lj3[itype][jtype]-
lj4[itype][jtype])-offset[itype][jtype]);
}
} else force_lj = 0.0;
fforce = (force_coul+force_lj)*r2inv;
return eng;
}
diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp
index d05558eb1..b363ad147 100644
--- a/src/MANYBODY/pair_airebo.cpp
+++ b/src/MANYBODY/pair_airebo.cpp
@@ -1,4626 +1,4626 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Ase Henry (MIT)
Bugfixes and optimizations:
Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U),
Markus Hoehnerbach (RWTH Aachen), Cyril Falvo (Universite Paris Sud)
AIREBO-M modification to optionally replace LJ with Morse potentials.
Thomas C. O'Connor (JHU) 2014
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
#include "pair_airebo.h"
#include "atom.h"
#include "neighbor.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "my_page.h"
#include "math_const.h"
#include "math_special.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace MathSpecial;
#define MAXLINE 1024
#define TOL 1.0e-9
#define PGDELTA 1
/* ---------------------------------------------------------------------- */
PairAIREBO::PairAIREBO(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
ghostneigh = 1;
ljflag = torflag = 1;
morseflag = 0;
nextra = 3;
pvector = new double[nextra];
maxlocal = 0;
REBO_numneigh = NULL;
REBO_firstneigh = NULL;
ipage = NULL;
pgsize = oneatom = 0;
nC = nH = NULL;
map = NULL;
manybody_flag = 1;
sigwid = 0.84;
sigcut = 3.0;
sigmin = sigcut - sigwid;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairAIREBO::~PairAIREBO()
{
memory->destroy(REBO_numneigh);
memory->sfree(REBO_firstneigh);
delete [] ipage;
memory->destroy(nC);
memory->destroy(nH);
delete [] pvector;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
memory->destroy(cutljsq);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairAIREBO::compute(int eflag, int vflag)
{
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = vflag_atom = 0;
pvector[0] = pvector[1] = pvector[2] = 0.0;
REBO_neigh();
FREBO(eflag,vflag);
if (ljflag) FLJ(eflag,vflag);
if (torflag) TORSION(eflag,vflag);
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairAIREBO::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cutghost,n+1,n+1,"pair:cutghost");
// only sized by C,H = 2 types
memory->create(cutljsq,2,2,"pair:cutljsq");
memory->create(lj1,2,2,"pair:lj1");
memory->create(lj2,2,2,"pair:lj2");
memory->create(lj3,2,2,"pair:lj3");
memory->create(lj4,2,2,"pair:lj4");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairAIREBO::settings(int narg, char **arg)
{
if (narg != 1 && narg != 3 && narg != 4)
error->all(FLERR,"Illegal pair_style command");
cutlj = force->numeric(FLERR,arg[0]);
if (narg >= 3) {
ljflag = force->inumeric(FLERR,arg[1]);
torflag = force->inumeric(FLERR,arg[2]);
}
if (narg == 4) {
sigcut = cutlj;
sigmin = force->numeric(FLERR,arg[3]);
sigwid = sigcut - sigmin;
}
// this one parameter for C-C interactions is different in AIREBO vs REBO
// see Favata, Micheletti, Ryu, Pugno, Comp Phys Comm (2016)
PCCf_2_0 = -0.0276030;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairAIREBO::coeff(int narg, char **arg)
{
if (!allocated) allocate();
if (narg != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// insure I,J args are * *
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read args that map atom types to C and H
// map[i] = which element (0,1) the Ith atom type is, -1 if NULL
for (int i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
} else if (strcmp(arg[i],"C") == 0) {
map[i-2] = 0;
} else if (strcmp(arg[i],"H") == 0) {
map[i-2] = 1;
} else error->all(FLERR,"Incorrect args for pair coefficients");
}
// read potential file and initialize fitting splines
read_file(arg[2]);
spline_init();
// clear setflag since coeff() called once with I,J = * *
int n = atom->ntypes;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
// set setflag i,j for type pairs where both are mapped to elements
int count = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
if (map[i] >= 0 && map[j] >= 0) {
setflag[i][j] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairAIREBO::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style AIREBO requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style AIREBO requires newton pair on");
// need a full neighbor list, including neighbors of ghosts
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->ghost = 1;
// local REBO neighbor list
// create pages if first time or if neighbor pgsize/oneatom has changed
int create = 0;
if (ipage == NULL) create = 1;
if (pgsize != neighbor->pgsize) create = 1;
if (oneatom != neighbor->oneatom) create = 1;
if (create) {
delete [] ipage;
pgsize = neighbor->pgsize;
oneatom = neighbor->oneatom;
int nmypage= comm->nthreads;
ipage = new MyPage<int>[nmypage];
for (int i = 0; i < nmypage; i++)
ipage[i].init(oneatom,pgsize,PGDELTA);
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairAIREBO::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
// convert to C,H types
int ii = map[i];
int jj = map[j];
// use C-C values for these cutoffs since C atoms are biggest
// cut3rebo = 3 REBO distances
cut3rebo = 3.0 * rcmax[0][0];
// cutljrebosq = furthest distance from an owned atom a ghost atom can be
// to need its REBO neighs computed
// interaction = M-K-I-J-L-N with I = owned and J = ghost
// this insures N is in the REBO neigh list of L
// since I-J < rcLJmax and J-L < rmax
double cutljrebo = rcLJmax[0][0] + rcmax[0][0];
cutljrebosq = cutljrebo * cutljrebo;
// cutmax = furthest distance from an owned atom
// at which another atom will feel force, i.e. the ghost cutoff
// for REBO term in potential:
// interaction = M-K-I-J-L-N with I = owned and J = ghost
// I to N is max distance = 3 REBO distances
// for LJ term in potential:
// short interaction = M-K-I-J-L-N with I = owned, J = ghost, I-J < rcLJmax
// rcLJmax + 2*rcmax, since I-J < rcLJmax and J-L,L-N = REBO distances
// long interaction = I-J with I = owned and J = ghost
// cutlj*sigma, since I-J < LJ cutoff
// cutghost = REBO cutoff used in REBO_neigh() for neighbors of ghosts
double cutmax = cut3rebo;
if (ljflag) {
cutmax = MAX(cutmax,rcLJmax[0][0] + 2.0*rcmax[0][0]);
cutmax = MAX(cutmax,cutlj*sigma[0][0]);
}
cutghost[i][j] = rcmax[ii][jj];
cutljsq[ii][jj] = cutlj*sigma[ii][jj] * cutlj*sigma[ii][jj];
if (morseflag) {
// using LJ precomputed parameter arrays to store values for Morse potential
lj1[ii][jj] = epsilonM[ii][jj] * exp(alphaM[ii][jj]*reqM[ii][jj]);
lj2[ii][jj] = exp(alphaM[ii][jj]*reqM[ii][jj]);
lj3[ii][jj] = 2*epsilonM[ii][jj]*alphaM[ii][jj]*exp(alphaM[ii][jj]*reqM[ii][jj]);
lj4[ii][jj] = alphaM[ii][jj];
} else {
lj1[ii][jj] = 48.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0);
lj2[ii][jj] = 24.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0);
lj3[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],12.0);
lj4[ii][jj] = 4.0 * epsilon[ii][jj] * pow(sigma[ii][jj],6.0);
}
cutghost[j][i] = cutghost[i][j];
cutljsq[jj][ii] = cutljsq[ii][jj];
lj1[jj][ii] = lj1[ii][jj];
lj2[jj][ii] = lj2[ii][jj];
lj3[jj][ii] = lj3[ii][jj];
lj4[jj][ii] = lj4[ii][jj];
return cutmax;
}
/* ----------------------------------------------------------------------
create REBO neighbor list from main neighbor list
REBO neighbor list stores neighbors of ghost atoms
------------------------------------------------------------------------- */
void PairAIREBO::REBO_neigh()
{
int i,j,ii,jj,n,allnum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
int *ilist,*jlist,*numneigh,**firstneigh;
int *neighptr;
double **x = atom->x;
int *type = atom->type;
if (atom->nmax > maxlocal) {
maxlocal = atom->nmax;
memory->destroy(REBO_numneigh);
memory->sfree(REBO_firstneigh);
memory->destroy(nC);
memory->destroy(nH);
memory->create(REBO_numneigh,maxlocal,"AIREBO:numneigh");
REBO_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
"AIREBO:firstneigh");
memory->create(nC,maxlocal,"AIREBO:nC");
memory->create(nH,maxlocal,"AIREBO:nH");
}
allnum = list->inum + list->gnum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// store all REBO neighs of owned and ghost atoms
// scan full neighbor list of I
ipage->reset();
for (ii = 0; ii < allnum; ii++) {
i = ilist[ii];
n = 0;
neighptr = ipage->vget();
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = map[type[i]];
nC[i] = nH[i] = 0.0;
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = map[type[j]];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < rcmaxsq[itype][jtype]) {
neighptr[n++] = j;
if (jtype == 0)
nC[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
else
nH[i] += Sp(sqrt(rsq),rcmin[itype][jtype],rcmax[itype][jtype],dS);
}
}
REBO_firstneigh[i] = neighptr;
REBO_numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
}
/* ----------------------------------------------------------------------
REBO forces and energy
------------------------------------------------------------------------- */
void PairAIREBO::FREBO(int eflag, int vflag)
{
int i,j,k,m,ii,inum,itype,jtype;
tagint itag,jtag;
double delx,dely,delz,evdwl,fpair,xtmp,ytmp,ztmp;
double rsq,rij,wij;
double Qij,Aij,alphaij,VR,pre,dVRdi,VA,term,bij,dVAdi,dVA;
double dwij,del[3];
int *ilist,*REBO_neighs;
evdwl = 0.0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
// two-body interactions from REBO neighbor list, skip half of them
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
j = REBO_neighs[k];
jtag = tag[j];
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
jtype = map[type[j]];
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
rij = sqrt(rsq);
wij = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
if (wij <= TOL) continue;
Qij = Q[itype][jtype];
Aij = A[itype][jtype];
alphaij = alpha[itype][jtype];
VR = wij*(1.0+(Qij/rij)) * Aij*exp(-alphaij*rij);
pre = wij*Aij * exp(-alphaij*rij);
dVRdi = pre * ((-alphaij)-(Qij/rsq)-(Qij*alphaij/rij));
dVRdi += VR/wij * dwij;
VA = dVA = 0.0;
for (m = 0; m < 3; m++) {
term = -wij * BIJc[itype][jtype][m] * exp(-Beta[itype][jtype][m]*rij);
VA += term;
dVA += -Beta[itype][jtype][m] * term;
}
dVA += VA/wij * dwij;
del[0] = delx;
del[1] = dely;
del[2] = delz;
bij = bondorder(i,j,del,rij,VA,f,vflag_atom);
dVAdi = bij*dVA;
fpair = -(dVRdi+dVAdi) / rij;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
if (eflag) pvector[0] += evdwl = VR + bij*VA;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
/* ----------------------------------------------------------------------
compute LJ forces and energy
find 3- and 4-step paths between atoms I,J via REBO neighbor lists
------------------------------------------------------------------------- */
void PairAIREBO::FLJ(int eflag, int vflag)
{
int i,j,k,m,ii,jj,kk,mm,inum,jnum,itype,jtype,ktype,mtype;
int atomi,atomj,atomk,atomm;
int testpath,npath,done;
tagint itag,jtag;
double evdwl,fpair,xtmp,ytmp,ztmp;
double rsq,best,wik,wkm,cij,rij,dwij,dwik,dwkj,dwkm,dwmj;
double delij[3],rijsq,delik[3],rik,deljk[3];
double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb;
double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2;
double rljmin,rljmax;
double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3];
int *ilist,*jlist,*numneigh,**firstneigh;
int *REBO_neighs_i,*REBO_neighs_k;
double delikS[3],deljkS[3],delkmS[3],deljmS[3],delimS[3];
double rikS,rkjS,rkmS,rmjS,wikS,dwikS;
double wkjS,dwkjS,wkmS,dwkmS,wmjS,dwmjS;
double fpair1,fpair2,fpair3;
double fi[3],fj[3],fk[3],fm[3];
// I-J interaction from full neighbor list
// skip 1/2 of interactions since only consider each pair once
evdwl = 0.0;
rljmin = 0.0;
rljmax = 0.0;
double **x = atom->x;
double **f = atom->f;
tagint *tag = atom->tag;
int *type = atom->type;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
itype = map[type[i]];
atomi = i;
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtag = tag[j];
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
jtype = map[type[j]];
atomj = j;
delij[0] = xtmp - x[j][0];
delij[1] = ytmp - x[j][1];
delij[2] = ztmp - x[j][2];
rijsq = delij[0]*delij[0] + delij[1]*delij[1] + delij[2]*delij[2];
// if outside of LJ cutoff, skip
// if outside of 4-path cutoff, best = 0.0, no need to test paths
// if outside of 2-path cutoff but inside 4-path cutoff,
// best = 0.0, test 3-,4-paths
// if inside 2-path cutoff, best = wij, only test 3-,4-paths if best < 1
npath = testpath = done = 0;
best = 0.0;
if (rijsq >= cutljsq[itype][jtype]) continue;
rij = sqrt(rijsq);
if (rij >= cut3rebo) {
best = 0.0;
testpath = 0;
} else if (rij >= rcmax[itype][jtype]) {
best = 0.0;
testpath = 1;
} else {
best = Sp(rij,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
npath = 2;
if (best < 1.0) testpath = 1;
else testpath = 0;
}
if (testpath) {
// test all 3-body paths = I-K-J
// I-K interactions come from atom I's REBO neighbors
// if wik > current best, compute wkj
// if best = 1.0, done
REBO_neighs_i = REBO_firstneigh[i];
for (kk = 0; kk < REBO_numneigh[i] && done==0; kk++) {
k = REBO_neighs_i[kk];
if (k == j) continue;
ktype = map[type[k]];
delik[0] = x[i][0] - x[k][0];
delik[1] = x[i][1] - x[k][1];
delik[2] = x[i][2] - x[k][2];
rsq = delik[0]*delik[0] + delik[1]*delik[1] + delik[2]*delik[2];
if (rsq < rcmaxsq[itype][ktype]) {
rik = sqrt(rsq);
wik = Sp(rik,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
} else { dwik = wik = 0.0; rikS = rik = 1.0; }
if (wik > best) {
deljk[0] = x[j][0] - x[k][0];
deljk[1] = x[j][1] - x[k][1];
deljk[2] = x[j][2] - x[k][2];
rsq = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
if (rsq < rcmaxsq[ktype][jtype]) {
rkj = sqrt(rsq);
wkj = Sp(rkj,rcmin[ktype][jtype],rcmax[ktype][jtype],dwkj);
if (wik*wkj > best) {
best = wik*wkj;
npath = 3;
atomk = k;
delikS[0] = delik[0];
delikS[1] = delik[1];
delikS[2] = delik[2];
rikS = rik;
wikS = wik;
dwikS = dwik;
deljkS[0] = deljk[0];
deljkS[1] = deljk[1];
deljkS[2] = deljk[2];
rkjS = rkj;
wkjS = wkj;
dwkjS = dwkj;
if (best == 1.0) {
done = 1;
break;
}
}
}
// test all 4-body paths = I-K-M-J
// K-M interactions come from atom K's REBO neighbors
// if wik*wkm > current best, compute wmj
// if best = 1.0, done
REBO_neighs_k = REBO_firstneigh[k];
for (mm = 0; mm < REBO_numneigh[k] && done==0; mm++) {
m = REBO_neighs_k[mm];
if (m == i || m == j) continue;
mtype = map[type[m]];
delkm[0] = x[k][0] - x[m][0];
delkm[1] = x[k][1] - x[m][1];
delkm[2] = x[k][2] - x[m][2];
rsq = delkm[0]*delkm[0] + delkm[1]*delkm[1] + delkm[2]*delkm[2];
if (rsq < rcmaxsq[ktype][mtype]) {
rkm = sqrt(rsq);
wkm = Sp(rkm,rcmin[ktype][mtype],rcmax[ktype][mtype],dwkm);
} else { dwkm = wkm = 0.0; rkmS = rkm = 1.0; }
if (wik*wkm > best) {
deljm[0] = x[j][0] - x[m][0];
deljm[1] = x[j][1] - x[m][1];
deljm[2] = x[j][2] - x[m][2];
rsq = deljm[0]*deljm[0] + deljm[1]*deljm[1] +
deljm[2]*deljm[2];
if (rsq < rcmaxsq[mtype][jtype]) {
rmj = sqrt(rsq);
wmj = Sp(rmj,rcmin[mtype][jtype],rcmax[mtype][jtype],dwmj);
if (wik*wkm*wmj > best) {
best = wik*wkm*wmj;
npath = 4;
atomk = k;
delikS[0] = delik[0];
delikS[1] = delik[1];
delikS[2] = delik[2];
rikS = rik;
wikS = wik;
dwikS = dwik;
atomm = m;
delkmS[0] = delkm[0];
delkmS[1] = delkm[1];
delkmS[2] = delkm[2];
rkmS = rkm;
wkmS = wkm;
dwkmS = dwkm;
deljmS[0] = deljm[0];
deljmS[1] = deljm[1];
deljmS[2] = deljm[2];
rmjS = rmj;
wmjS = wmj;
dwmjS = dwmj;
if (best == 1.0) {
done = 1;
break;
}
}
}
}
}
}
}
}
cij = 1.0 - best;
if (cij == 0.0) continue;
// compute LJ forces and energy
rljmin = sigma[itype][jtype];
rljmax = sigcut * rljmin;
rljmin = sigmin * rljmin;
if (rij > rljmax) {
slw = 0.0;
dslw = 0.0;
} else if (rij > rljmin) {
drij = rij - rljmin;
swidth = rljmax - rljmin;
tee = drij / swidth;
tee2 = tee*tee;
slw = 1.0 - tee2 * (3.0 - 2.0 * tee);
dslw = -6.0 * tee * (1.0 - tee) / swidth;
} else {
slw = 1.0;
dslw = 0.0;
}
if (morseflag) {
const double exr = exp(-rij*lj4[itype][jtype]);
vdw = lj1[itype][jtype]*exr*(lj2[itype][jtype]*exr - 2);
dvdw = lj3[itype][jtype]*exr*(1-lj2[itype][jtype]*exr);
} else {
r2inv = 1.0/rijsq;
r6inv = r2inv*r2inv*r2inv;
vdw = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]);
dvdw = -r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]) / rij;
}
// VLJ now becomes vdw * slw, derivaties, etc.
VLJ = vdw * slw;
dVLJ = dvdw * slw + vdw * dslw;
Str = Sp2(rij,rcLJmin[itype][jtype],rcLJmax[itype][jtype],dStr);
VA = Str*cij*VLJ;
if (Str > 0.0) {
scale = rcmin[itype][jtype] / rij;
delscale[0] = scale * delij[0];
delscale[1] = scale * delij[1];
delscale[2] = scale * delij[2];
Stb = bondorderLJ(i,j,delscale,rcmin[itype][jtype],VA,
delij,rij,f,vflag_atom);
} else Stb = 0.0;
fpair = -(dStr * (Stb*cij*VLJ - cij*VLJ) +
dVLJ * (Str*Stb*cij + cij - Str*cij)) / rij;
f[i][0] += delij[0]*fpair;
f[i][1] += delij[1]*fpair;
f[i][2] += delij[2]*fpair;
f[j][0] -= delij[0]*fpair;
f[j][1] -= delij[1]*fpair;
f[j][2] -= delij[2]*fpair;
if (eflag) pvector[1] += evdwl = VA*Stb + (1.0-Str)*cij*VLJ;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delij[0],delij[1],delij[2]);
if (cij < 1.0) {
dC = Str*Stb*VLJ + (1.0-Str)*VLJ;
if (npath == 2) {
fpair = dC*dwij / rij;
f[atomi][0] += delij[0]*fpair;
f[atomi][1] += delij[1]*fpair;
f[atomi][2] += delij[2]*fpair;
f[atomj][0] -= delij[0]*fpair;
f[atomj][1] -= delij[1]*fpair;
f[atomj][2] -= delij[2]*fpair;
if (vflag_atom) v_tally2(atomi,atomj,fpair,delij);
} else if (npath == 3) {
fpair1 = dC*dwikS*wkjS / rikS;
fi[0] = delikS[0]*fpair1;
fi[1] = delikS[1]*fpair1;
fi[2] = delikS[2]*fpair1;
fpair2 = dC*wikS*dwkjS / rkjS;
fj[0] = deljkS[0]*fpair2;
fj[1] = deljkS[1]*fpair2;
fj[2] = deljkS[2]*fpair2;
f[atomi][0] += fi[0];
f[atomi][1] += fi[1];
f[atomi][2] += fi[2];
f[atomj][0] += fj[0];
f[atomj][1] += fj[1];
f[atomj][2] += fj[2];
f[atomk][0] -= fi[0] + fj[0];
f[atomk][1] -= fi[1] + fj[1];
f[atomk][2] -= fi[2] + fj[2];
if (vflag_atom)
v_tally3(atomi,atomj,atomk,fi,fj,delikS,deljkS);
} else if (npath == 4) {
fpair1 = dC*dwikS*wkmS*wmjS / rikS;
fi[0] = delikS[0]*fpair1;
fi[1] = delikS[1]*fpair1;
fi[2] = delikS[2]*fpair1;
fpair2 = dC*wikS*dwkmS*wmjS / rkmS;
fk[0] = delkmS[0]*fpair2 - fi[0];
fk[1] = delkmS[1]*fpair2 - fi[1];
fk[2] = delkmS[2]*fpair2 - fi[2];
fpair3 = dC*wikS*wkmS*dwmjS / rmjS;
fj[0] = deljmS[0]*fpair3;
fj[1] = deljmS[1]*fpair3;
fj[2] = deljmS[2]*fpair3;
fm[0] = -delkmS[0]*fpair2 - fj[0];
fm[1] = -delkmS[1]*fpair2 - fj[1];
fm[2] = -delkmS[2]*fpair2 - fj[2];
f[atomi][0] += fi[0];
f[atomi][1] += fi[1];
f[atomi][2] += fi[2];
f[atomj][0] += fj[0];
f[atomj][1] += fj[1];
f[atomj][2] += fj[2];
f[atomk][0] += fk[0];
f[atomk][1] += fk[1];
f[atomk][2] += fk[2];
f[atomm][0] += fm[0];
f[atomm][1] += fm[1];
f[atomm][2] += fm[2];
if (vflag_atom) {
delimS[0] = delikS[0] + delkmS[0];
delimS[1] = delikS[1] + delkmS[1];
delimS[2] = delikS[2] + delkmS[2];
v_tally4(atomi,atomj,atomk,atomm,fi,fj,fk,delimS,deljmS,delkmS);
}
}
}
}
}
}
/* ----------------------------------------------------------------------
torsional forces and energy
------------------------------------------------------------------------- */
void PairAIREBO::TORSION(int eflag, int vflag)
{
int i,j,k,l,ii,inum;
tagint itag,jtag;
double evdwl,fpair,xtmp,ytmp,ztmp;
double cos321;
double w21,dw21,cos234,w34,dw34;
double cross321[3],cross321mag,cross234[3],cross234mag;
double w23,dw23,cw2,ekijl,Ec;
double cw,cwnum,cwnom;
double rij,rij2,rik,rjl,tspjik,dtsjik,tspijl,dtsijl,costmp,fcpc;
double sin321,sin234,rjk2,rik2,ril2,rjl2;
double rjk,ril;
double Vtors;
double dndij[3],tmpvec[3],dndik[3],dndjl[3];
double dcidij,dcidik,dcidjk,dcjdji,dcjdjl,dcjdil;
double dsidij,dsidik,dsidjk,dsjdji,dsjdjl,dsjdil;
double dxidij,dxidik,dxidjk,dxjdji,dxjdjl,dxjdil;
double ddndij,ddndik,ddndjk,ddndjl,ddndil,dcwddn,dcwdn,dvpdcw,Ftmp[3];
double del32[3],rsq,r32,del23[3],del21[3],r21;
double deljk[3],del34[3],delil[3],delkl[3],r23,r34;
double fi[3],fj[3],fk[3],fl[3];
int itype,jtype,ktype,ltype,kk,ll,jj;
int *ilist,*REBO_neighs_i,*REBO_neighs_j;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
tagint *tag = atom->tag;
inum = list->inum;
ilist = list->ilist;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
itype = map[type[i]];
if (itype != 0) continue;
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
REBO_neighs_i = REBO_firstneigh[i];
for (jj = 0; jj < REBO_numneigh[i]; jj++) {
j = REBO_neighs_i[jj];
jtag = tag[j];
if (itag > jtag) {
if ((itag+jtag) % 2 == 0) continue;
} else if (itag < jtag) {
if ((itag+jtag) % 2 == 1) continue;
} else {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
jtype = map[type[j]];
if (jtype != 0) continue;
del32[0] = x[j][0]-x[i][0];
del32[1] = x[j][1]-x[i][1];
del32[2] = x[j][2]-x[i][2];
rsq = del32[0]*del32[0] + del32[1]*del32[1] + del32[2]*del32[2];
r32 = sqrt(rsq);
del23[0] = -del32[0];
del23[1] = -del32[1];
del23[2] = -del32[2];
r23 = r32;
w23 = Sp(r23,rcmin[itype][jtype],rcmax[itype][jtype],dw23);
for (kk = 0; kk < REBO_numneigh[i]; kk++) {
k = REBO_neighs_i[kk];
ktype = map[type[k]];
if (k == j) continue;
del21[0] = x[i][0]-x[k][0];
del21[1] = x[i][1]-x[k][1];
del21[2] = x[i][2]-x[k][2];
rsq = del21[0]*del21[0] + del21[1]*del21[1] + del21[2]*del21[2];
r21 = sqrt(rsq);
cos321 = - ((del21[0]*del32[0]) + (del21[1]*del32[1]) +
(del21[2]*del32[2])) / (r21*r32);
cos321 = MIN(cos321,1.0);
cos321 = MAX(cos321,-1.0);
sin321 = sqrt(1.0 - cos321*cos321);
if (sin321 < TOL) continue;
deljk[0] = del21[0]-del23[0];
deljk[1] = del21[1]-del23[1];
deljk[2] = del21[2]-del23[2];
rjk2 = deljk[0]*deljk[0] + deljk[1]*deljk[1] + deljk[2]*deljk[2];
rjk=sqrt(rjk2);
rik2 = r21*r21;
w21 = Sp(r21,rcmin[itype][ktype],rcmax[itype][ktype],dw21);
rij = r32;
rik = r21;
rij2 = r32*r32;
rik2 = r21*r21;
costmp = 0.5*(rij2+rik2-rjk2)/rij/rik;
tspjik = Sp2(costmp,thmin,thmax,dtsjik);
dtsjik = -dtsjik;
REBO_neighs_j = REBO_firstneigh[j];
for (ll = 0; ll < REBO_numneigh[j]; ll++) {
l = REBO_neighs_j[ll];
ltype = map[type[l]];
if (l == i || l == k) continue;
del34[0] = x[j][0]-x[l][0];
del34[1] = x[j][1]-x[l][1];
del34[2] = x[j][2]-x[l][2];
rsq = del34[0]*del34[0] + del34[1]*del34[1] + del34[2]*del34[2];
r34 = sqrt(rsq);
cos234 = (del32[0]*del34[0] + del32[1]*del34[1] +
del32[2]*del34[2]) / (r32*r34);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
sin234 = sqrt(1.0 - cos234*cos234);
if (sin234 < TOL) continue;
w34 = Sp(r34,rcmin[jtype][ltype],rcmax[jtype][ltype],dw34);
delil[0] = del23[0] + del34[0];
delil[1] = del23[1] + del34[1];
delil[2] = del23[2] + del34[2];
ril2 = delil[0]*delil[0] + delil[1]*delil[1] + delil[2]*delil[2];
ril=sqrt(ril2);
rjl2 = r34*r34;
rjl = r34;
rjl2 = r34*r34;
costmp = 0.5*(rij2+rjl2-ril2)/rij/rjl;
tspijl = Sp2(costmp,thmin,thmax,dtsijl);
dtsijl = -dtsijl; //need minus sign
cross321[0] = (del32[1]*del21[2])-(del32[2]*del21[1]);
cross321[1] = (del32[2]*del21[0])-(del32[0]*del21[2]);
cross321[2] = (del32[0]*del21[1])-(del32[1]*del21[0]);
cross321mag = sqrt(cross321[0]*cross321[0]+
cross321[1]*cross321[1]+
cross321[2]*cross321[2]);
cross234[0] = (del23[1]*del34[2])-(del23[2]*del34[1]);
cross234[1] = (del23[2]*del34[0])-(del23[0]*del34[2]);
cross234[2] = (del23[0]*del34[1])-(del23[1]*del34[0]);
cross234mag = sqrt(cross234[0]*cross234[0]+
cross234[1]*cross234[1]+
cross234[2]*cross234[2]);
cwnum = (cross321[0]*cross234[0]) +
(cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
cwnom = r21*r34*r32*r32*sin321*sin234;
cw = cwnum/cwnom;
cw2 = (.5*(1.0-cw));
ekijl = epsilonT[ktype][ltype];
Ec = 256.0*ekijl/405.0;
Vtors = (Ec*(powint(cw2,5)))-(ekijl/10.0);
if (eflag) pvector[2] += evdwl = Vtors*w21*w23*w34*(1.0-tspjik)*(1.0-tspijl);
dndij[0] = (cross234[1]*del21[2])-(cross234[2]*del21[1]);
dndij[1] = (cross234[2]*del21[0])-(cross234[0]*del21[2]);
dndij[2] = (cross234[0]*del21[1])-(cross234[1]*del21[0]);
tmpvec[0] = (del34[1]*cross321[2])-(del34[2]*cross321[1]);
tmpvec[1] = (del34[2]*cross321[0])-(del34[0]*cross321[2]);
tmpvec[2] = (del34[0]*cross321[1])-(del34[1]*cross321[0]);
dndij[0] = dndij[0]+tmpvec[0];
dndij[1] = dndij[1]+tmpvec[1];
dndij[2] = dndij[2]+tmpvec[2];
dndik[0] = (del23[1]*cross234[2])-(del23[2]*cross234[1]);
dndik[1] = (del23[2]*cross234[0])-(del23[0]*cross234[2]);
dndik[2] = (del23[0]*cross234[1])-(del23[1]*cross234[0]);
dndjl[0] = (cross321[1]*del23[2])-(cross321[2]*del23[1]);
dndjl[1] = (cross321[2]*del23[0])-(cross321[0]*del23[2]);
dndjl[2] = (cross321[0]*del23[1])-(cross321[1]*del23[0]);
dcidij = ((r23*r23)-(r21*r21)+(rjk*rjk))/(2.0*r23*r23*r21);
dcidik = ((r21*r21)-(r23*r23)+(rjk*rjk))/(2.0*r23*r21*r21);
dcidjk = (-rjk)/(r23*r21);
dcjdji = ((r23*r23)-(r34*r34)+(ril*ril))/(2.0*r23*r23*r34);
dcjdjl = ((r34*r34)-(r23*r23)+(ril*ril))/(2.0*r23*r34*r34);
dcjdil = (-ril)/(r23*r34);
dsidij = (-cos321/sin321)*dcidij;
dsidik = (-cos321/sin321)*dcidik;
dsidjk = (-cos321/sin321)*dcidjk;
dsjdji = (-cos234/sin234)*dcjdji;
dsjdjl = (-cos234/sin234)*dcjdjl;
dsjdil = (-cos234/sin234)*dcjdil;
dxidij = (r21*sin321)+(r23*r21*dsidij);
dxidik = (r23*sin321)+(r23*r21*dsidik);
dxidjk = (r23*r21*dsidjk);
dxjdji = (r34*sin234)+(r23*r34*dsjdji);
dxjdjl = (r23*sin234)+(r23*r34*dsjdjl);
dxjdil = (r23*r34*dsjdil);
ddndij = (dxidij*cross234mag)+(cross321mag*dxjdji);
ddndik = dxidik*cross234mag;
ddndjk = dxidjk*cross234mag;
ddndjl = cross321mag*dxjdjl;
ddndil = cross321mag*dxjdil;
dcwddn = -cwnum/(cwnom*cwnom);
dcwdn = 1.0/cwnom;
dvpdcw = (-1.0)*Ec*(-.5)*5.0*powint(cw2,4) *
w23*w21*w34*(1.0-tspjik)*(1.0-tspijl);
Ftmp[0] = dvpdcw*((dcwdn*dndij[0])+(dcwddn*ddndij*del23[0]/r23));
Ftmp[1] = dvpdcw*((dcwdn*dndij[1])+(dcwddn*ddndij*del23[1]/r23));
Ftmp[2] = dvpdcw*((dcwdn*dndij[2])+(dcwddn*ddndij*del23[2]/r23));
fi[0] = Ftmp[0];
fi[1] = Ftmp[1];
fi[2] = Ftmp[2];
fj[0] = -Ftmp[0];
fj[1] = -Ftmp[1];
fj[2] = -Ftmp[2];
Ftmp[0] = dvpdcw*((dcwdn*dndik[0])+(dcwddn*ddndik*del21[0]/r21));
Ftmp[1] = dvpdcw*((dcwdn*dndik[1])+(dcwddn*ddndik*del21[1]/r21));
Ftmp[2] = dvpdcw*((dcwdn*dndik[2])+(dcwddn*ddndik*del21[2]/r21));
fi[0] += Ftmp[0];
fi[1] += Ftmp[1];
fi[2] += Ftmp[2];
fk[0] = -Ftmp[0];
fk[1] = -Ftmp[1];
fk[2] = -Ftmp[2];
Ftmp[0] = (dvpdcw*dcwddn*ddndjk*deljk[0])/rjk;
Ftmp[1] = (dvpdcw*dcwddn*ddndjk*deljk[1])/rjk;
Ftmp[2] = (dvpdcw*dcwddn*ddndjk*deljk[2])/rjk;
fj[0] += Ftmp[0];
fj[1] += Ftmp[1];
fj[2] += Ftmp[2];
fk[0] -= Ftmp[0];
fk[1] -= Ftmp[1];
fk[2] -= Ftmp[2];
Ftmp[0] = dvpdcw*((dcwdn*dndjl[0])+(dcwddn*ddndjl*del34[0]/r34));
Ftmp[1] = dvpdcw*((dcwdn*dndjl[1])+(dcwddn*ddndjl*del34[1]/r34));
Ftmp[2] = dvpdcw*((dcwdn*dndjl[2])+(dcwddn*ddndjl*del34[2]/r34));
fj[0] += Ftmp[0];
fj[1] += Ftmp[1];
fj[2] += Ftmp[2];
fl[0] = -Ftmp[0];
fl[1] = -Ftmp[1];
fl[2] = -Ftmp[2];
Ftmp[0] = (dvpdcw*dcwddn*ddndil*delil[0])/ril;
Ftmp[1] = (dvpdcw*dcwddn*ddndil*delil[1])/ril;
Ftmp[2] = (dvpdcw*dcwddn*ddndil*delil[2])/ril;
fi[0] += Ftmp[0];
fi[1] += Ftmp[1];
fi[2] += Ftmp[2];
fl[0] -= Ftmp[0];
fl[1] -= Ftmp[1];
fl[2] -= Ftmp[2];
// coordination forces
fpair = Vtors*dw21*w23*w34*(1.0-tspjik)*(1.0-tspijl) / r21;
fi[0] -= del21[0]*fpair;
fi[1] -= del21[1]*fpair;
fi[2] -= del21[2]*fpair;
fk[0] += del21[0]*fpair;
fk[1] += del21[1]*fpair;
fk[2] += del21[2]*fpair;
fpair = Vtors*w21*dw23*w34*(1.0-tspjik)*(1.0-tspijl) / r23;
fi[0] -= del23[0]*fpair;
fi[1] -= del23[1]*fpair;
fi[2] -= del23[2]*fpair;
fj[0] += del23[0]*fpair;
fj[1] += del23[1]*fpair;
fj[2] += del23[2]*fpair;
fpair = Vtors*w21*w23*dw34*(1.0-tspjik)*(1.0-tspijl) / r34;
fj[0] -= del34[0]*fpair;
fj[1] -= del34[1]*fpair;
fj[2] -= del34[2]*fpair;
fl[0] += del34[0]*fpair;
fl[1] += del34[1]*fpair;
fl[2] += del34[2]*fpair;
// additional cut off function forces
fcpc = -Vtors*w21*w23*w34*dtsjik*(1.0-tspijl);
fpair = fcpc*dcidij/rij;
fi[0] += fpair*del23[0];
fi[1] += fpair*del23[1];
fi[2] += fpair*del23[2];
fj[0] -= fpair*del23[0];
fj[1] -= fpair*del23[1];
fj[2] -= fpair*del23[2];
fpair = fcpc*dcidik/rik;
fi[0] += fpair*del21[0];
fi[1] += fpair*del21[1];
fi[2] += fpair*del21[2];
fk[0] -= fpair*del21[0];
fk[1] -= fpair*del21[1];
fk[2] -= fpair*del21[2];
fpair = fcpc*dcidjk/rjk;
fj[0] += fpair*deljk[0];
fj[1] += fpair*deljk[1];
fj[2] += fpair*deljk[2];
fk[0] -= fpair*deljk[0];
fk[1] -= fpair*deljk[1];
fk[2] -= fpair*deljk[2];
fcpc = -Vtors*w21*w23*w34*(1.0-tspjik)*dtsijl;
fpair = fcpc*dcjdji/rij;
fi[0] += fpair*del23[0];
fi[1] += fpair*del23[1];
fi[2] += fpair*del23[2];
fj[0] -= fpair*del23[0];
fj[1] -= fpair*del23[1];
fj[2] -= fpair*del23[2];
fpair = fcpc*dcjdjl/rjl;
fj[0] += fpair*del34[0];
fj[1] += fpair*del34[1];
fj[2] += fpair*del34[2];
fl[0] -= fpair*del34[0];
fl[1] -= fpair*del34[1];
fl[2] -= fpair*del34[2];
fpair = fcpc*dcjdil/ril;
fi[0] += fpair*delil[0];
fi[1] += fpair*delil[1];
fi[2] += fpair*delil[2];
fl[0] -= fpair*delil[0];
fl[1] -= fpair*delil[1];
fl[2] -= fpair*delil[2];
// sum per-atom forces into atom force array
f[i][0] += fi[0]; f[i][1] += fi[1]; f[i][2] += fi[2];
f[j][0] += fj[0]; f[j][1] += fj[1]; f[j][2] += fj[2];
f[k][0] += fk[0]; f[k][1] += fk[1]; f[k][2] += fk[2];
f[l][0] += fl[0]; f[l][1] += fl[1]; f[l][2] += fl[2];
if (evflag) {
delkl[0] = delil[0] - del21[0];
delkl[1] = delil[1] - del21[1];
delkl[2] = delil[2] - del21[2];
ev_tally4(i,j,k,l,evdwl,fi,fj,fk,delil,del34,delkl);
}
}
}
}
}
}
/* ----------------------------------------------------------------------
Bij function
------------------------------------------------------------------------- */
double PairAIREBO::bondorder(int i, int j, double rij[3],
double rijmag, double VA,
double **f, int vflag_atom)
{
int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
int itype,jtype,ktype,ltype,ntype;
double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij;
double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS;
double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
double dN2[2],dN3[3];
double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3];
double Tij;
double r32[3],r32mag,cos321,r43[3],r13[3];
double dNlj;
double om1234,rln[3];
double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
double cross321[3],cross234[3],prefactor,SpN;
double fcijpc,fcikpc,fcjlpc,fcjkpc,fcilpc;
double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa2,at2,cw,cwnum,cwnom;
double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3];
double f1[3],f2[3],f3[3],f4[4];
double dcut321,PijS,PjiS;
double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
double **x = atom->x;
int *type = atom->type;
atomi = i;
atomj = j;
itype = map[type[i]];
jtype = map[type[j]];
wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
NijC = nC[i]-(wij*kronecker(jtype,0));
NijH = nH[i]-(wij*kronecker(jtype,1));
NjiC = nC[j]-(wij*kronecker(itype,0));
NjiH = nH[j]-(wij*kronecker(itype,1));
bij = 0.0;
tmp = 0.0;
tmp2 = 0.0;
tmp3 = 0.0;
dgdc = 0.0;
dgdN = 0.0;
NconjtmpI = 0.0;
NconjtmpJ = 0.0;
Etmp = 0.0;
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
lamdajik = 4.0*kronecker(itype,1) *
((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
(wik*kronecker(itype,1));
cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
(rijmag*rikmag);
cosjik = MIN(cosjik,1.0);
cosjik = MAX(cosjik,-1.0);
// evaluate splines g and derivatives dg
g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
Etmp = Etmp+(wik*g*exp(lamdajik));
tmp3 = tmp3+(wik*dgdN*exp(lamdajik));
NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
}
}
PijS = 0.0;
dN2[0] = 0.0;
dN2[1] = 0.0;
PijS = PijSpline(NijC,NijH,itype,jtype,dN2);
pij = 1.0/sqrt(1.0+Etmp+PijS);
tmp = -0.5*cube(pij);
// pij forces
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
lamdajik = 4.0*kronecker(itype,1) *
((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) /
(rijmag*rikmag);
cosjik = MIN(cosjik,1.0);
cosjik = MAX(cosjik,-1.0);
dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) -
(cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag))));
dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) -
(cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag))));
dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) -
(cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag))));
dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) +
(cosjik*(rik[0]/(rikmag*rikmag)));
dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) +
(cosjik*(rik[1]/(rikmag*rikmag)));
dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) +
(cosjik*(rik[2]/(rikmag*rikmag)));
dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) +
(cosjik*(rij[0]/(rijmag*rijmag)));
dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) +
(cosjik*(rij[1]/(rijmag*rijmag)));
dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) +
(cosjik*(rij[2]/(rijmag*rijmag)));
g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
fj[0] = -tmp2*dcosjikdrj[0];
fj[1] = -tmp2*dcosjikdrj[1];
fj[2] = -tmp2*dcosjikdrj[2];
fi[0] = -tmp2*dcosjikdri[0];
fi[1] = -tmp2*dcosjikdri[1];
fi[2] = -tmp2*dcosjikdri[2];
fk[0] = -tmp2*dcosjikdrk[0];
fk[1] = -tmp2*dcosjikdrk[1];
fk[2] = -tmp2*dcosjikdrk[2];
tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
fj[0] -= tmp2*(-rij[0]/rijmag);
fj[1] -= tmp2*(-rij[1]/rijmag);
fj[2] -= tmp2*(-rij[2]/rijmag);
fi[0] -= tmp2*((-rik[0]/rikmag)+(rij[0]/rijmag));
fi[1] -= tmp2*((-rik[1]/rikmag)+(rij[1]/rijmag));
fi[2] -= tmp2*((-rik[2]/rikmag)+(rij[2]/rijmag));
fk[0] -= tmp2*(rik[0]/rikmag);
fk[1] -= tmp2*(rik[1]/rikmag);
fk[2] -= tmp2*(rik[2]/rikmag);
// coordination forces
// dwik forces
tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
// PIJ forces
tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
// dgdN forces
tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
if (vflag_atom) {
rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
v_tally3(atomi,atomj,atomk,fj,fk,rji,rki);
}
}
}
tmp = 0.0;
tmp2 = 0.0;
tmp3 = 0.0;
Etmp = 0.0;
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
lamdaijl = 4.0*kronecker(jtype,1) *
((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0)) +
nH[atoml]-(wjl*kronecker(jtype,1));
cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
(rijmag*rjlmag);
cosijl = MIN(cosijl,1.0);
cosijl = MAX(cosijl,-1.0);
// evaluate splines g and derivatives dg
g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
Etmp = Etmp+(wjl*g*exp(lamdaijl));
tmp3 = tmp3+(wjl*dgdN*exp(lamdaijl));
NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
}
}
PjiS = 0.0;
dN2[0] = 0.0;
dN2[1] = 0.0;
PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2);
pji = 1.0/sqrt(1.0+Etmp+PjiS);
tmp = -0.5*cube(pji);
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
lamdaijl = 4.0*kronecker(jtype,1) *
((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) /
(rijmag*rjlmag);
cosijl = MIN(cosijl,1.0);
cosijl = MAX(cosijl,-1.0);
dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) -
(cosijl*rij[0]/(rijmag*rijmag));
dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) -
(cosijl*rij[1]/(rijmag*rijmag));
dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) -
(cosijl*rij[2]/(rijmag*rijmag));
dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) +
(cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag))));
dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) +
(cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag))));
dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) +
(cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag))));
dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag));
dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag));
dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag));
// evaluate splines g and derivatives dg
g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
fi[0] = -tmp2*dcosijldri[0];
fi[1] = -tmp2*dcosijldri[1];
fi[2] = -tmp2*dcosijldri[2];
fj[0] = -tmp2*dcosijldrj[0];
fj[1] = -tmp2*dcosijldrj[1];
fj[2] = -tmp2*dcosijldrj[2];
fl[0] = -tmp2*dcosijldrl[0];
fl[1] = -tmp2*dcosijldrl[1];
fl[2] = -tmp2*dcosijldrl[2];
tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
fi[0] -= tmp2*(rij[0]/rijmag);
fi[1] -= tmp2*(rij[1]/rijmag);
fi[2] -= tmp2*(rij[2]/rijmag);
fj[0] -= tmp2*((-rjl[0]/rjlmag)-(rij[0]/rijmag));
fj[1] -= tmp2*((-rjl[1]/rjlmag)-(rij[1]/rijmag));
fj[2] -= tmp2*((-rjl[2]/rjlmag)-(rij[2]/rijmag));
fl[0] -= tmp2*(rjl[0]/rjlmag);
fl[1] -= tmp2*(rjl[1]/rjlmag);
fl[2] -= tmp2*(rjl[2]/rjlmag);
// coordination forces
// dwik forces
tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
// PIJ forces
tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
// dgdN forces
tmp2 = VA*.5*(tmp*tmp3*dwjl)/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
if (vflag_atom) {
rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj);
}
}
}
// evaluate Nij conj
Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3);
// piRC forces
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
if (atomk !=atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
(wik*kronecker(itype,1));
SpN = Sp(Nki,Nmin,Nmax,dNki);
tmp2 = VA*dN3[0]*dwik/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
// due to kronecker(ktype, 0) term in contribution
// to NconjtmpI and later Nijconj
if (ktype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
if (fabs(dNki) > TOL) {
REBO_neighs_k = REBO_firstneigh[atomk];
for (n = 0; n < REBO_numneigh[atomk]; n++) {
atomn = REBO_neighs_k[n];
if (atomn != atomi) {
ntype = map[type[atomn]];
rkn[0] = x[atomk][0]-x[atomn][0];
rkn[1] = x[atomk][1]-x[atomn][1];
rkn[2] = x[atomk][2]-x[atomn][2];
rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
f[atomk][0] -= tmp2*rkn[0];
f[atomk][1] -= tmp2*rkn[1];
f[atomk][2] -= tmp2*rkn[2];
f[atomn][0] += tmp2*rkn[0];
f[atomn][1] += tmp2*rkn[1];
f[atomn][2] += tmp2*rkn[2];
if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
}
}
}
}
}
// piRC forces
REBO_neighs = REBO_firstneigh[atomj];
for (l = 0; l < REBO_numneigh[atomj]; l++) {
atoml = REBO_neighs[l];
if (atoml !=atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
(wjl*kronecker(jtype,1));
SpN = Sp(Nlj,Nmin,Nmax,dNlj);
tmp2 = VA*dN3[1]*dwjl/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
// due to kronecker(ltype, 0) term in contribution
// to NconjtmpJ and later Nijconj
if (ltype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
if (fabs(dNlj) > TOL) {
REBO_neighs_l = REBO_firstneigh[atoml];
for (n = 0; n < REBO_numneigh[atoml]; n++) {
atomn = REBO_neighs_l[n];
if (atomn != atomj) {
ntype = map[type[atomn]];
rln[0] = x[atoml][0]-x[atomn][0];
rln[1] = x[atoml][1]-x[atomn][1];
rln[2] = x[atoml][2]-x[atomn][2];
rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
f[atoml][0] -= tmp2*rln[0];
f[atoml][1] -= tmp2*rln[1];
f[atoml][2] -= tmp2*rln[2];
f[atomn][0] += tmp2*rln[0];
f[atomn][1] += tmp2*rln[1];
f[atomn][2] += tmp2*rln[2];
if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
}
}
}
}
}
Tij = 0.0;
dN3[0] = 0.0;
dN3[1] = 0.0;
dN3[2] = 0.0;
if (itype == 0 && jtype == 0)
Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3);
Etmp = 0.0;
if (fabs(Tij) > TOL) {
atom2 = atomi;
atom3 = atomj;
r32[0] = x[atom3][0]-x[atom2][0];
r32[1] = x[atom3][1]-x[atom2][1];
r32[2] = x[atom3][2]-x[atom2][2];
r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
r23[0] = -r32[0];
r23[1] = -r32[1];
r23[2] = -r32[2];
r23mag = r32mag;
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
atom1 = atomk;
ktype = map[type[atomk]];
if (atomk != atomj) {
r21[0] = x[atom2][0]-x[atom1][0];
r21[1] = x[atom2][1]-x[atom1][1];
r21[2] = x[atom2][2]-x[atom1][2];
r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) /
(r21mag*r32mag);
cos321 = MIN(cos321,1.0);
cos321 = MAX(cos321,-1.0);
Sp2(cos321,thmin,thmax,dcut321);
sin321 = sqrt(1.0 - cos321*cos321);
if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0
sink2i = 1.0/(sin321*sin321);
rik2i = 1.0/(r21mag*r21mag);
rr = (r23mag*r23mag)-(r21mag*r21mag);
rjk[0] = r21[0]-r23[0];
rjk[1] = r21[1]-r23[1];
rjk[2] = r21[2]-r23[2];
rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
rijrik = 2.0*r23mag*r21mag;
rik2 = r21mag*r21mag;
dctik = (-rr+rjk2)/(rijrik*rik2);
dctij = (rr+rjk2)/(rijrik*r23mag*r23mag);
dctjk = -2.0/rijrik;
w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
rijmag = r32mag;
rikmag = r21mag;
rij2 = r32mag*r32mag;
rik2 = r21mag*r21mag;
costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
tspjik = Sp2(costmp,thmin,thmax,dtsjik);
dtsjik = -dtsjik;
REBO_neighs_j = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs_j[l];
atom4 = atoml;
ltype = map[type[atoml]];
if (!(atoml == atomi || atoml == atomk)) {
r34[0] = x[atom3][0]-x[atom4][0];
r34[1] = x[atom3][1]-x[atom4][1];
r34[2] = x[atom3][2]-x[atom4][2];
r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2]));
cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) /
(r32mag*r34mag);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
sin234 = sqrt(1.0 - cos234*cos234);
if ((sin234 > TOL) && (r34mag > TOL)) { // XXX was sin234 != 0.0
sinl2i = 1.0/(sin234*sin234);
rjl2i = 1.0/(r34mag*r34mag);
w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34);
rr = (r23mag*r23mag)-(r34mag*r34mag);
ril[0] = r23[0]+r34[0];
ril[1] = r23[1]+r34[1];
ril[2] = r23[2]+r34[2];
ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
rijrjl = 2.0*r23mag*r34mag;
rjl2 = r34mag*r34mag;
dctjl = (-rr+ril2)/(rijrjl*rjl2);
dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
dctil = -2.0/rijrjl;
rjlmag = r34mag;
rjl2 = r34mag*r34mag;
costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
tspijl = Sp2(costmp,thmin,thmax,dtsijl);
dtsijl = -dtsijl;
prefactor = VA*Tij;
cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
cwnum = (cross321[0]*cross234[0]) +
(cross321[1]*cross234[1]) + (cross321[2]*cross234[2]);
cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
om1234 = cwnum/cwnom;
cw = om1234;
Etmp += ((1.0-square(om1234))*w21*w34) *
(1.0-tspjik)*(1.0-tspijl);
dt1dik = (rik2i)-(dctik*sink2i*cos321);
dt1djk = (-dctjk*sink2i*cos321);
dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
dt1dil = (-dctil*sinl2i*cos234);
dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) -
(dctji*sinl2i*cos234);
dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) -
(r21[1]*cross234[2])+(r34[1]*cross321[2]);
dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) -
(r21[2]*cross234[0])+(r34[2]*cross321[0]);
dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) -
(r21[0]*cross234[1])+(r34[0]*cross321[1]);
aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
(1.0-tspjik)*(1.0-tspijl);
aaa2 = -prefactor*(1.0-square(om1234)) * w21*w34;
at2 = aa*cwnum;
fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
(aaa2*dtsijl*dctji*(1.0-tspjik));
fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
F31[0] = (fcjkpc*rjk[0]);
F31[1] = (fcjkpc*rjk[1]);
F31[2] = (fcjkpc*rjk[2]);
F24[0] = (fcilpc*ril[0]);
F24[1] = (fcilpc*ril[1]);
F24[2] = (fcilpc*ril[2]);
f1[0] = -F12[0]-F31[0];
f1[1] = -F12[1]-F31[1];
f1[2] = -F12[2]-F31[2];
f2[0] = F23[0]+F12[0]+F24[0];
f2[1] = F23[1]+F12[1]+F24[1];
f2[2] = F23[2]+F12[2]+F24[2];
f3[0] = -F23[0]+F34[0]+F31[0];
f3[1] = -F23[1]+F34[1]+F31[1];
f3[2] = -F23[2]+F34[2]+F31[2];
f4[0] = -F34[0]-F24[0];
f4[1] = -F34[1]-F24[1];
f4[2] = -F34[2]-F24[2];
// coordination forces
tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
(1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
f2[0] -= tmp2*r21[0];
f2[1] -= tmp2*r21[1];
f2[2] -= tmp2*r21[2];
f1[0] += tmp2*r21[0];
f1[1] += tmp2*r21[1];
f1[2] += tmp2*r21[2];
tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
(1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
f3[0] -= tmp2*r34[0];
f3[1] -= tmp2*r34[1];
f3[2] -= tmp2*r34[2];
f4[0] += tmp2*r34[0];
f4[1] += tmp2*r34[1];
f4[2] += tmp2*r34[2];
f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
f[atom1][2] += f1[2];
f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
f[atom2][2] += f2[2];
f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
f[atom3][2] += f3[2];
f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
f[atom4][2] += f4[2];
if (vflag_atom) {
r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43);
}
}
}
}
}
}
}
// Tij forces now that we have Etmp
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
(wik*kronecker(itype,1));
SpN = Sp(Nki,Nmin,Nmax,dNki);
tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
// due to kronecker(ktype, 0) term in contribution
// to NconjtmpI and later Nijconj
if (ktype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
if (fabs(dNki) > TOL) {
REBO_neighs_k = REBO_firstneigh[atomk];
for (n = 0; n < REBO_numneigh[atomk]; n++) {
atomn = REBO_neighs_k[n];
ntype = map[type[atomn]];
if (atomn != atomi) {
rkn[0] = x[atomk][0]-x[atomn][0];
rkn[1] = x[atomk][1]-x[atomn][1];
rkn[2] = x[atomk][2]-x[atomn][2];
rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
f[atomk][0] -= tmp2*rkn[0];
f[atomk][1] -= tmp2*rkn[1];
f[atomk][2] -= tmp2*rkn[2];
f[atomn][0] += tmp2*rkn[0];
f[atomn][1] += tmp2*rkn[1];
f[atomn][2] += tmp2*rkn[2];
if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
}
}
}
}
}
// Tij forces
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
(wjl*kronecker(jtype,1));
SpN = Sp(Nlj,Nmin,Nmax,dNlj);
tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
// due to kronecker(ltype, 0) term in contribution
// to NconjtmpJ and later Nijconj
if (ltype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
if (fabs(dNlj) > TOL) {
REBO_neighs_l = REBO_firstneigh[atoml];
for (n = 0; n < REBO_numneigh[atoml]; n++) {
atomn = REBO_neighs_l[n];
ntype = map[type[atomn]];
if (atomn !=atomj) {
rln[0] = x[atoml][0]-x[atomn][0];
rln[1] = x[atoml][1]-x[atomn][1];
rln[2] = x[atoml][2]-x[atomn][2];
rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
f[atoml][0] -= tmp2*rln[0];
f[atoml][1] -= tmp2*rln[1];
f[atoml][2] -= tmp2*rln[2];
f[atomn][0] += tmp2*rln[0];
f[atomn][1] += tmp2*rln[1];
f[atomn][2] += tmp2*rln[2];
if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
}
}
}
}
}
}
bij = (0.5*(pij+pji))+piRC+(Tij*Etmp);
return bij;
}
/* ----------------------------------------------------------------------
Bij* function
-------------------------------------------------------------------------
This function calculates S(t_b(b_ij*)) as specified in the AIREBO paper.
To do so, it needs to compute b_ij*, i.e. the bondorder given that the
atoms i and j are placed a ficticious distance rijmag_mod apart.
Now there are two approaches to calculate the resulting forces:
1. Carry through the ficticious distance and corresponding vector
rij_mod, correcting afterwards using the derivative of r/|r|.
2. Perform all the calculations using the real distance, and do not
use a correction, only using rijmag_mod where necessary.
This code opts for (2). Mathematically, the approaches are equivalent
if implemented correctly, since in terms where only the normalized
vector is used, both calculations necessarily lead to the same result
since if f(x) = g(x/|x|) then for x = y/|y| f(x) = g(y/|y|/1).
The actual modified distance is only used in the lamda terms.
Note that these do not contribute to the forces between i and j, since
rijmag_mod is a constant and the corresponding derivatives are
accordingly zero.
This function should be kept in sync with bondorder(), i.e. changes
there probably also need to be performed here.
The OpenKIM Fortran implementation chooses option (1) instead, which
means that the internal values computed by the two codes are not
directly comparable.
Note that of 7/2017 the OpenKIM code contains an issue where the it
assumes dt2dij[] to be zero (since it is a r_ij derivative). This is
incorrect since dt2dij is not a derivative of the scalar distance r_ij,
but of the vector r_ij.
*/
double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mod,
double VA, double rij[3], double rijmag,
double **f, int vflag_atom)
{
int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
int itype,jtype,ktype,ltype,ntype;
double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij;
double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl;
double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3;
double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS;
double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
double dN2[2],dN3[3];
double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3];
double Tij;
double r32[3],r32mag,cos321,r43[3],r13[3];
double dNlj;
double om1234,rln[3];
double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag;
double w21,dw21,r34[3],r34mag,cos234,w34,dw34;
double cross321[3],cross234[3],prefactor,SpN;
double fcikpc,fcjlpc,fcjkpc,fcilpc,fcijpc;
double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa2,at2,cw,cwnum,cwnom;
double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2;
double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i;
double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij;
double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3];
double f1[3],f2[3],f3[3],f4[4];
double PijS,PjiS;
double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp;
int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l;
double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3];
double tmp3pij,tmp3pji,Stb,dStb;
double **x = atom->x;
int *type = atom->type;
atomi = i;
atomj = j;
itype = map[type[atomi]];
jtype = map[type[atomj]];
wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij);
NijC = nC[atomi]-(wij*kronecker(jtype,0));
NijH = nH[atomi]-(wij*kronecker(jtype,1));
NjiC = nC[atomj]-(wij*kronecker(itype,0));
NjiH = nH[atomj]-(wij*kronecker(itype,1));
bij = 0.0;
tmp = 0.0;
tmp2 = 0.0;
tmp3 = 0.0;
dgdc = 0.0;
dgdN = 0.0;
NconjtmpI = 0.0;
NconjtmpJ = 0.0;
Etmp = 0.0;
Stb = 0.0;
dStb = 0.0;
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
lamdajik = 4.0*kronecker(itype,1) *
((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS);
Nki = nC[atomk]-(wik*kronecker(itype,0))+
nH[atomk]-(wik*kronecker(itype,1));
cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
(rijmag*rikmag);
cosjik = MIN(cosjik,1.0);
cosjik = MAX(cosjik,-1.0);
// evaluate splines g and derivatives dg
g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
Etmp += (wik*g*exp(lamdajik));
tmp3 += (wik*dgdN*exp(lamdajik));
NconjtmpI = NconjtmpI+(kronecker(ktype,0)*wik*Sp(Nki,Nmin,Nmax,dS));
}
}
PijS = 0.0;
dN2PIJ[0] = 0.0;
dN2PIJ[1] = 0.0;
PijS = PijSpline(NijC,NijH,itype,jtype,dN2PIJ);
pij = 1.0/sqrt(1.0+Etmp+PijS);
tmppij = -.5*cube(pij);
tmp3pij = tmp3;
tmp = 0.0;
tmp2 = 0.0;
tmp3 = 0.0;
Etmp = 0.0;
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
lamdaijl = 4.0*kronecker(jtype,1) *
((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
(wjl*kronecker(jtype,1));
cosijl = -1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
(rijmag*rjlmag);
cosijl = MIN(cosijl,1.0);
cosijl = MAX(cosijl,-1.0);
// evaluate splines g and derivatives dg
g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
Etmp += (wjl*g*exp(lamdaijl));
tmp3 += (wjl*dgdN*exp(lamdaijl));
NconjtmpJ = NconjtmpJ+(kronecker(ltype,0)*wjl*Sp(Nlj,Nmin,Nmax,dS));
}
}
PjiS = 0.0;
dN2PJI[0] = 0.0;
dN2PJI[1] = 0.0;
PjiS = PijSpline(NjiC,NjiH,jtype,itype,dN2PJI);
pji = 1.0/sqrt(1.0+Etmp+PjiS);
tmppji = -.5*cube(pji);
tmp3pji = tmp3;
// evaluate Nij conj
Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ);
piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC);
Tij = 0.0;
dN3Tij[0] = 0.0;
dN3Tij[1] = 0.0;
dN3Tij[2] = 0.0;
if (itype == 0 && jtype == 0)
Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij);
Etmp = 0.0;
if (fabs(Tij) > TOL) {
atom2 = atomi;
atom3 = atomj;
r32[0] = x[atom3][0]-x[atom2][0];
r32[1] = x[atom3][1]-x[atom2][1];
r32[2] = x[atom3][2]-x[atom2][2];
r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
r23[0] = -r32[0];
r23[1] = -r32[1];
r23[2] = -r32[2];
r23mag = r32mag;
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
atom1 = atomk;
ktype = map[type[atomk]];
if (atomk != atomj) {
r21[0] = x[atom2][0]-x[atom1][0];
r21[1] = x[atom2][1]-x[atom1][1];
r21[2] = x[atom2][2]-x[atom1][2];
r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) /
(r21mag*r32mag);
cos321 = MIN(cos321,1.0);
cos321 = MAX(cos321,-1.0);
sin321 = sqrt(1.0 - cos321*cos321);
if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0
w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
tspjik = Sp2(cos321,thmin,thmax,dtsjik);
REBO_neighs_j = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs_j[l];
atom4 = atoml;
ltype = map[type[atoml]];
if (!(atoml == atomi || atoml == atomk)) {
r34[0] = x[atom3][0]-x[atom4][0];
r34[1] = x[atom3][1]-x[atom4][1];
r34[2] = x[atom3][2]-x[atom4][2];
r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2]));
cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) /
(r32mag*r34mag);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
sin234 = sqrt(1.0 - cos234*cos234);
if ((sin234 > TOL) && (r34mag > TOL)) { // XXX was sin234 != 0.0
w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34);
tspijl = Sp2(cos234,thmin,thmax,dtsijl);
cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
cwnum = (cross321[0]*cross234[0]) +
(cross321[1]*cross234[1]) + (cross321[2]*cross234[2]);
cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
om1234 = cwnum/cwnom;
cw = om1234;
Etmp += ((1.0-square(om1234))*w21*w34) *
(1.0-tspjik)*(1.0-tspijl);
}
}
}
}
}
}
}
bij = (.5*(pij+pji))+piRC+(Tij*Etmp);
Stb = Sp2(bij,bLJmin[itype][jtype],bLJmax[itype][jtype],dStb);
VA = VA*dStb;
if (dStb != 0.0) {
tmp = tmppij;
dN2[0] = dN2PIJ[0];
dN2[1] = dN2PIJ[1];
tmp3 = tmp3pij;
// pij forces
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
ktype = map[type[atomk]];
if (atomk != atomj) {
lamdajik = 0.0;
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]);
lamdajik = 4.0*kronecker(itype,1) *
((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) /
(rijmag*rikmag);
cosjik = MIN(cosjik,1.0);
cosjik = MAX(cosjik,-1.0);
dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) -
(cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag))));
dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) -
(cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag))));
dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) -
(cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag))));
dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) +
(cosjik*(rik[0]/(rikmag*rikmag)));
dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) +
(cosjik*(rik[1]/(rikmag*rikmag)));
dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) +
(cosjik*(rik[2]/(rikmag*rikmag)));
dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) +
(cosjik*(rij[0]/(rijmag*rijmag)));
dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) +
(cosjik*(rij[1]/(rijmag*rijmag)));
dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) +
(cosjik*(rij[2]/(rijmag*rijmag)));
g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN);
tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik));
fj[0] = -tmp2*dcosjikdrj[0];
fj[1] = -tmp2*dcosjikdrj[1];
fj[2] = -tmp2*dcosjikdrj[2];
fi[0] = -tmp2*dcosjikdri[0];
fi[1] = -tmp2*dcosjikdri[1];
fi[2] = -tmp2*dcosjikdri[2];
fk[0] = -tmp2*dcosjikdrk[0];
fk[1] = -tmp2*dcosjikdrk[1];
fk[2] = -tmp2*dcosjikdrk[2];
tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1));
fi[0] += tmp2*(rik[0]/rikmag);
fi[1] += tmp2*(rik[1]/rikmag);
fi[2] += tmp2*(rik[2]/rikmag);
fk[0] -= tmp2*(rik[0]/rikmag);
fk[1] -= tmp2*(rik[1]/rikmag);
fk[2] -= tmp2*(rik[2]/rikmag);
// coordination forces
// dwik forces
tmp2 = VA*.5*(tmp*dwik*g*exp(lamdajik))/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
// PIJ forces
tmp2 = VA*.5*(tmp*dN2[ktype]*dwik)/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
// dgdN forces
tmp2 = VA*.5*(tmp*tmp3*dwik)/rikmag;
fi[0] -= tmp2*rik[0];
fi[1] -= tmp2*rik[1];
fi[2] -= tmp2*rik[2];
fk[0] += tmp2*rik[0];
fk[1] += tmp2*rik[1];
fk[2] += tmp2*rik[2];
f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
f[atomk][0] += fk[0]; f[atomk][1] += fk[1]; f[atomk][2] += fk[2];
if (vflag_atom) {
rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
rki[0] = -rik[0]; rki[1] = -rik[1]; rki[2] = -rik[2];
v_tally3(atomi,atomj,atomk,fj,fk,rji,rki);
}
}
}
tmp = tmppji;
tmp3 = tmp3pji;
dN2[0] = dN2PJI[0];
dN2[1] = dN2PJI[1];
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml !=atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
lamdaijl = 4.0*kronecker(jtype,1) *
((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) /
(rijmag*rjlmag);
cosijl = MIN(cosijl,1.0);
cosijl = MAX(cosijl,-1.0);
dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) -
(cosijl*rij[0]/(rijmag*rijmag));
dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) -
(cosijl*rij[1]/(rijmag*rijmag));
dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) -
(cosijl*rij[2]/(rijmag*rijmag));
dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) +
(cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag))));
dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) +
(cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag))));
dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) +
(cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag))));
dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag));
dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag));
dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag));
// evaluate splines g and derivatives dg
g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN);
tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl));
fi[0] = -tmp2*dcosijldri[0];
fi[1] = -tmp2*dcosijldri[1];
fi[2] = -tmp2*dcosijldri[2];
fj[0] = -tmp2*dcosijldrj[0];
fj[1] = -tmp2*dcosijldrj[1];
fj[2] = -tmp2*dcosijldrj[2];
fl[0] = -tmp2*dcosijldrl[0];
fl[1] = -tmp2*dcosijldrl[1];
fl[2] = -tmp2*dcosijldrl[2];
tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1));
fj[0] += tmp2*(rjl[0]/rjlmag);
fj[1] += tmp2*(rjl[1]/rjlmag);
fj[2] += tmp2*(rjl[2]/rjlmag);
fl[0] -= tmp2*(rjl[0]/rjlmag);
fl[1] -= tmp2*(rjl[1]/rjlmag);
fl[2] -= tmp2*(rjl[2]/rjlmag);
// coordination forces
// dwik forces
tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
// PIJ forces
tmp2 = VA*.5*(tmp*dN2[ltype]*dwjl)/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
// dgdN forces
tmp2=VA*.5*(tmp*tmp3*dwjl)/rjlmag;
fj[0] -= tmp2*rjl[0];
fj[1] -= tmp2*rjl[1];
fj[2] -= tmp2*rjl[2];
fl[0] += tmp2*rjl[0];
fl[1] += tmp2*rjl[1];
fl[2] += tmp2*rjl[2];
f[atomi][0] += fi[0]; f[atomi][1] += fi[1]; f[atomi][2] += fi[2];
f[atomj][0] += fj[0]; f[atomj][1] += fj[1]; f[atomj][2] += fj[2];
f[atoml][0] += fl[0]; f[atoml][1] += fl[1]; f[atoml][2] += fl[2];
if (vflag_atom) {
rlj[0] = -rjl[0]; rlj[1] = -rjl[1]; rlj[2] = -rjl[2];
v_tally3(atomi,atomj,atoml,fi,fl,rij,rlj);
}
}
}
// piRC forces
dN3[0] = dN3piRC[0];
dN3[1] = dN3piRC[1];
dN3[2] = dN3piRC[2];
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
(wik*kronecker(itype,1));
SpN = Sp(Nki,Nmin,Nmax,dNki);
tmp2 = VA*dN3[0]*dwik/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
// due to kronecker(ktype, 0) term in contribution
// to NconjtmpI and later Nijconj
if (ktype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
if (fabs(dNki) > TOL) {
REBO_neighs_k = REBO_firstneigh[atomk];
for (n = 0; n < REBO_numneigh[atomk]; n++) {
atomn = REBO_neighs_k[n];
if (atomn != atomi) {
ntype = map[type[atomn]];
rkn[0] = x[atomk][0]-x[atomn][0];
rkn[1] = x[atomk][1]-x[atomn][1];
rkn[2] = x[atomk][2]-x[atomn][2];
rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)/rknmag;
f[atomk][0] -= tmp2*rkn[0];
f[atomk][1] -= tmp2*rkn[1];
f[atomk][2] -= tmp2*rkn[2];
f[atomn][0] += tmp2*rkn[0];
f[atomn][1] += tmp2*rkn[1];
f[atomn][2] += tmp2*rkn[2];
if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
}
}
}
}
}
// piRC forces to J side
REBO_neighs = REBO_firstneigh[atomj];
for (l = 0; l < REBO_numneigh[atomj]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
(wjl*kronecker(jtype,1));
SpN = Sp(Nlj,Nmin,Nmax,dNlj);
tmp2 = VA*dN3[1]*dwjl/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
// due to kronecker(ltype, 0) term in contribution
// to NconjtmpJ and later Nijconj
if (ltype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
if (fabs(dNlj) > TOL) {
REBO_neighs_l = REBO_firstneigh[atoml];
for (n = 0; n < REBO_numneigh[atoml]; n++) {
atomn = REBO_neighs_l[n];
if (atomn != atomj) {
ntype = map[type[atomn]];
rln[0] = x[atoml][0]-x[atomn][0];
rln[1] = x[atoml][1]-x[atomn][1];
rln[2] = x[atoml][2]-x[atomn][2];
rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)/rlnmag;
f[atoml][0] -= tmp2*rln[0];
f[atoml][1] -= tmp2*rln[1];
f[atoml][2] -= tmp2*rln[2];
f[atomn][0] += tmp2*rln[0];
f[atomn][1] += tmp2*rln[1];
f[atomn][2] += tmp2*rln[2];
if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
}
}
}
}
}
if (fabs(Tij) > TOL) {
dN3[0] = dN3Tij[0];
dN3[1] = dN3Tij[1];
dN3[2] = dN3Tij[2];
atom2 = atomi;
atom3 = atomj;
r32[0] = x[atom3][0]-x[atom2][0];
r32[1] = x[atom3][1]-x[atom2][1];
r32[2] = x[atom3][2]-x[atom2][2];
r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2]));
r23[0] = -r32[0];
r23[1] = -r32[1];
r23[2] = -r32[2];
r23mag = r32mag;
REBO_neighs_i = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs_i[k];
atom1 = atomk;
ktype = map[type[atomk]];
if (atomk != atomj) {
r21[0] = x[atom2][0]-x[atom1][0];
r21[1] = x[atom2][1]-x[atom1][1];
r21[2] = x[atom2][2]-x[atom1][2];
r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]);
cos321 = ((r21[0]*rij[0])+(r21[1]*rij[1])+(r21[2]*rij[2])) /
(r21mag*rijmag);
cos321 = MIN(cos321,1.0);
cos321 = MAX(cos321,-1.0);
sin321 = sqrt(1.0 - cos321*cos321);
if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0
sink2i = 1.0/(sin321*sin321);
rik2i = 1.0/(r21mag*r21mag);
rr = (rijmag*rijmag)-(r21mag*r21mag);
rjk[0] = r21[0]-r23[0];
rjk[1] = r21[1]-r23[1];
rjk[2] = r21[2]-r23[2];
rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
rijrik = 2.0*r23mag*r21mag;
rik2 = r21mag*r21mag;
dctik = (-rr+rjk2)/(rijrik*rik2);
dctij = (rr+rjk2)/(rijrik*r23mag*r23mag);
dctjk = -2.0/rijrik;
w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
rijmag = r32mag;
rikmag = r21mag;
rij2 = r32mag*r32mag;
rik2 = r21mag*r21mag;
costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
tspjik = Sp2(costmp,thmin,thmax,dtsjik);
dtsjik = -dtsjik;
REBO_neighs_j = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs_j[l];
atom4 = atoml;
ltype = map[type[atoml]];
if (!(atoml == atomi || atoml == atomk)) {
r34[0] = x[atom3][0]-x[atom4][0];
r34[1] = x[atom3][1]-x[atom4][1];
r34[2] = x[atom3][2]-x[atom4][2];
r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]);
cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) /
(r32mag*r34mag);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
sin234 = sqrt(1.0 - cos234*cos234);
if ((sin234 > TOL) && (r34mag > TOL)) { // XXX was sin234 != 0.0
sinl2i = 1.0/(sin234*sin234);
rjl2i = 1.0/(r34mag*r34mag);
w34 = Sp(r34mag,rcmin[jtype][ltype],
rcmaxp[jtype][ltype],dw34);
rr = (r23mag*r23mag)-(r34mag*r34mag);
ril[0] = r23[0]+r34[0];
ril[1] = r23[1]+r34[1];
ril[2] = r23[2]+r34[2];
ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
rijrjl = 2.0*r23mag*r34mag;
rjl2 = r34mag*r34mag;
dctjl = (-rr+ril2)/(rijrjl*rjl2);
dctji = (rr+ril2)/(rijrjl*r23mag*r23mag);
dctil = -2.0/rijrjl;
rjlmag = r34mag;
rjl2 = r34mag*r34mag;
costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
tspijl = Sp2(costmp,thmin,thmax,dtsijl);
dtsijl = -dtsijl; //need minus sign
prefactor = VA*Tij;
cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]);
cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]);
cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]);
cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]);
cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]);
cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]);
cwnum = (cross321[0]*cross234[0]) +
(cross321[1]*cross234[1])+(cross321[2]*cross234[2]);
cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234;
om1234 = cwnum/cwnom;
cw = om1234;
dt1dik = (rik2i)-(dctik*sink2i*cos321);
dt1djk = (-dctjk*sink2i*cos321);
dt1djl = (rjl2i)-(dctjl*sinl2i*cos234);
dt1dil = (-dctil*sinl2i*cos234);
dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) -
(dctji*sinl2i*cos234);
dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]);
dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]);
dt2dik[2] = (-r23[1]*cross234[0])+(r23[0]*cross234[1]);
dt2djl[0] = (-r23[1]*cross321[2])+(r23[2]*cross321[1]);
dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]);
dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]);
dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) -
(r21[1]*cross234[2])+(r34[1]*cross321[2]);
dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) -
(r21[2]*cross234[0])+(r34[2]*cross321[0]);
dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) -
(r21[0]*cross234[1])+(r34[0]*cross321[1]);
aa = (prefactor*2.0*cw/cwnom)*w21*w34 *
(1.0-tspjik)*(1.0-tspijl);
aaa2 = -prefactor*(1.0-square(om1234)) * w21*w34;
at2 = aa*cwnum;
fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) +
(aaa2*dtsijl*dctji*(1.0-tspjik));
fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl));
fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik));
fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl));
fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik));
F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]);
F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]);
F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]);
F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]);
F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]);
F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]);
F34[0] = (fcjlpc*r34[0])+(aa*dt2djl[0]);
F34[1] = (fcjlpc*r34[1])+(aa*dt2djl[1]);
F34[2] = (fcjlpc*r34[2])+(aa*dt2djl[2]);
F31[0] = (fcjkpc*rjk[0]);
F31[1] = (fcjkpc*rjk[1]);
F31[2] = (fcjkpc*rjk[2]);
F24[0] = (fcilpc*ril[0]);
F24[1] = (fcilpc*ril[1]);
F24[2] = (fcilpc*ril[2]);
f1[0] = -F12[0]-F31[0];
f1[1] = -F12[1]-F31[1];
f1[2] = -F12[2]-F31[2];
f2[0] = F23[0]+F12[0]+F24[0];
f2[1] = F23[1]+F12[1]+F24[1];
f2[2] = F23[2]+F12[2]+F24[2];
f3[0] = -F23[0]+F34[0]+F31[0];
f3[1] = -F23[1]+F34[1]+F31[1];
f3[2] = -F23[2]+F34[2]+F31[2];
f4[0] = -F34[0]-F24[0];
f4[1] = -F34[1]-F24[1];
f4[2] = -F34[2]-F24[2];
// coordination forces
tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
(1.0-tspjik)*(1.0-tspijl)*dw21*w34/r21mag;
f2[0] -= tmp2*r21[0];
f2[1] -= tmp2*r21[1];
f2[2] -= tmp2*r21[2];
f1[0] += tmp2*r21[0];
f1[1] += tmp2*r21[1];
f1[2] += tmp2*r21[2];
tmp2 = VA*Tij*((1.0-(om1234*om1234))) *
(1.0-tspjik)*(1.0-tspijl)*w21*dw34/r34mag;
f3[0] -= tmp2*r34[0];
f3[1] -= tmp2*r34[1];
f3[2] -= tmp2*r34[2];
f4[0] += tmp2*r34[0];
f4[1] += tmp2*r34[1];
f4[2] += tmp2*r34[2];
f[atom1][0] += f1[0]; f[atom1][1] += f1[1];
f[atom1][2] += f1[2];
f[atom2][0] += f2[0]; f[atom2][1] += f2[1];
f[atom2][2] += f2[2];
f[atom3][0] += f3[0]; f[atom3][1] += f3[1];
f[atom3][2] += f3[2];
f[atom4][0] += f4[0]; f[atom4][1] += f4[1];
f[atom4][2] += f4[2];
if (vflag_atom) {
r13[0] = -rjk[0]; r13[1] = -rjk[1]; r13[2] = -rjk[2];
r43[0] = -r34[0]; r43[1] = -r34[1]; r43[2] = -r34[2];
v_tally4(atom1,atom2,atom3,atom4,f1,f2,f4,r13,r23,r43);
}
}
}
}
}
}
}
REBO_neighs = REBO_firstneigh[i];
for (k = 0; k < REBO_numneigh[i]; k++) {
atomk = REBO_neighs[k];
if (atomk != atomj) {
ktype = map[type[atomk]];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik);
Nki = nC[atomk]-(wik*kronecker(itype,0))+nH[atomk] -
(wik*kronecker(itype,1));
SpN = Sp(Nki,Nmin,Nmax,dNki);
tmp2 = VA*dN3[0]*dwik*Etmp/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
// due to kronecker(ktype, 0) term in contribution
// to NconjtmpI and later Nijconj
if (ktype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*dwik*SpN)*Etmp/rikmag;
f[atomi][0] -= tmp2*rik[0];
f[atomi][1] -= tmp2*rik[1];
f[atomi][2] -= tmp2*rik[2];
f[atomk][0] += tmp2*rik[0];
f[atomk][1] += tmp2*rik[1];
f[atomk][2] += tmp2*rik[2];
if (vflag_atom) v_tally2(atomi,atomk,-tmp2,rik);
if (fabs(dNki) > TOL) {
REBO_neighs_k = REBO_firstneigh[atomk];
for (n = 0; n < REBO_numneigh[atomk]; n++) {
atomn = REBO_neighs_k[n];
ntype = map[type[atomn]];
if (atomn !=atomi) {
rkn[0] = x[atomk][0]-x[atomn][0];
rkn[1] = x[atomk][1]-x[atomn][1];
rkn[2] = x[atomk][2]-x[atomn][2];
rknmag = sqrt((rkn[0]*rkn[0])+(rkn[1]*rkn[1])+(rkn[2]*rkn[2]));
Sp(rknmag,rcmin[ktype][ntype],rcmax[ktype][ntype],dwkn);
tmp2 = VA*dN3[2]*(2.0*NconjtmpI*wik*dNki*dwkn)*Etmp/rknmag;
f[atomk][0] -= tmp2*rkn[0];
f[atomk][1] -= tmp2*rkn[1];
f[atomk][2] -= tmp2*rkn[2];
f[atomn][0] += tmp2*rkn[0];
f[atomn][1] += tmp2*rkn[1];
f[atomn][2] += tmp2*rkn[2];
if (vflag_atom) v_tally2(atomk,atomn,-tmp2,rkn);
}
}
}
}
}
// Tij forces
REBO_neighs = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs[l];
if (atoml != atomi) {
ltype = map[type[atoml]];
rjl[0] = x[atomj][0]-x[atoml][0];
rjl[1] = x[atomj][1]-x[atoml][1];
rjl[2] = x[atomj][2]-x[atoml][2];
rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2]));
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl);
Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] -
(wjl*kronecker(jtype,1));
SpN = Sp(Nlj,Nmin,Nmax,dNlj);
tmp2 = VA*dN3[1]*dwjl*Etmp/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
// due to kronecker(ltype, 0) term in contribution
// to NconjtmpJ and later Nijconj
if (ltype != 0) continue;
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*dwjl*SpN)*Etmp/rjlmag;
f[atomj][0] -= tmp2*rjl[0];
f[atomj][1] -= tmp2*rjl[1];
f[atomj][2] -= tmp2*rjl[2];
f[atoml][0] += tmp2*rjl[0];
f[atoml][1] += tmp2*rjl[1];
f[atoml][2] += tmp2*rjl[2];
if (vflag_atom) v_tally2(atomj,atoml,-tmp2,rjl);
if (fabs(dNlj) > TOL) {
REBO_neighs_l = REBO_firstneigh[atoml];
for (n = 0; n < REBO_numneigh[atoml]; n++) {
atomn = REBO_neighs_l[n];
ntype = map[type[atomn]];
if (atomn != atomj) {
rln[0] = x[atoml][0]-x[atomn][0];
rln[1] = x[atoml][1]-x[atomn][1];
rln[2] = x[atoml][2]-x[atomn][2];
rlnmag = sqrt((rln[0]*rln[0])+(rln[1]*rln[1])+(rln[2]*rln[2]));
Sp(rlnmag,rcmin[ltype][ntype],rcmax[ltype][ntype],dwln);
tmp2 = VA*dN3[2]*(2.0*NconjtmpJ*wjl*dNlj*dwln)*Etmp/rlnmag;
f[atoml][0] -= tmp2*rln[0];
f[atoml][1] -= tmp2*rln[1];
f[atoml][2] -= tmp2*rln[2];
f[atomn][0] += tmp2*rln[0];
f[atomn][1] += tmp2*rln[1];
f[atomn][2] += tmp2*rln[2];
if (vflag_atom) v_tally2(atoml,atomn,-tmp2,rln);
}
}
}
}
}
}
}
return Stb;
}
/* ----------------------------------------------------------------------
G spline
------------------------------------------------------------------------- */
double PairAIREBO::gSpline(double costh, double Nij, int typei,
double *dgdc, double *dgdN)
{
double coeffs[6],dS,g1,g2,dg1,dg2,cut,g;
int i,j;
i = 0;
j = 0;
g = 0.0;
cut = 0.0;
dS = 0.0;
dg1 = 0.0;
dg2 = 0.0;
*dgdc = 0.0;
*dgdN = 0.0;
// central atom is Carbon
if (typei == 0) {
if (costh < gCdom[0]) costh = gCdom[0];
if (costh > gCdom[4]) costh = gCdom[4];
if (Nij >= NCmax) {
for (i = 0; i < 4; i++) {
if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j];
}
}
g2 = Sp5th(costh,coeffs,&dg2);
g = g2;
*dgdc = dg2;
*dgdN = 0.0;
}
if (Nij <= NCmin) {
for (i = 0; i < 4; i++) {
if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j];
}
}
g1 = Sp5th(costh,coeffs,&dg1);
g = g1;
*dgdc = dg1;
*dgdN = 0.0;
}
if (Nij > NCmin && Nij < NCmax) {
for (i = 0; i < 4; i++) {
if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
for (j = 0; j < 6; j++) coeffs[j] = gC1[i][j];
}
}
g1 = Sp5th(costh,coeffs,&dg1);
for (i = 0; i < 4; i++) {
if (costh >= gCdom[i] && costh <= gCdom[i+1]) {
for (j = 0; j < 6; j++) coeffs[j] = gC2[i][j];
}
}
g2 = Sp5th(costh,coeffs,&dg2);
cut = Sp(Nij,NCmin,NCmax,dS);
g = g2+cut*(g1-g2);
*dgdc = dg2+(cut*(dg1-dg2));
*dgdN = dS*(g1-g2);
}
}
// central atom is Hydrogen
if (typei == 1) {
if (costh < gHdom[0]) costh = gHdom[0];
if (costh > gHdom[3]) costh = gHdom[3];
for (i = 0; i < 3; i++) {
if (costh >= gHdom[i] && costh <= gHdom[i+1]) {
for (j = 0; j < 6; j++) coeffs[j] = gH[i][j];
}
}
g = Sp5th(costh,coeffs,&dg1);
*dgdN = 0.0;
*dgdc = dg1;
}
return g;
}
/* ----------------------------------------------------------------------
Pij spline
------------------------------------------------------------------------- */
double PairAIREBO::PijSpline(double NijC, double NijH, int typei, int typej,
double dN2[2])
{
int x,y;
double Pij;
x = 0;
y = 0;
dN2[0] = 0.0;
dN2[1] = 0.0;
Pij = 0.0;
if (typei == 1) return Pij;
if (typej == 0) {
// if inputs are out of bounds set them back to a point in bounds
if (NijC < pCCdom[0][0]) NijC=pCCdom[0][0];
if (NijC > pCCdom[0][1]) NijC=pCCdom[0][1];
if (NijH < pCCdom[1][0]) NijH=pCCdom[1][0];
if (NijH > pCCdom[1][1]) NijH=pCCdom[1][1];
x = (int) floor(NijC);
y = (int) floor(NijH);
if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
Pij = PCCf[x][y];
dN2[0] = PCCdfdx[x][y];
dN2[1] = PCCdfdy[x][y];
} else {
if (NijC == pCCdom[0][1]) --x;
if (NijH == pCCdom[1][1]) --y;
Pij = Spbicubic(NijC,NijH,pCC[x][y],dN2);
}
} else if (typej == 1) {
// if inputs are out of bounds set them back to a point in bounds
if (NijC < pCHdom[0][0]) NijC=pCHdom[0][0];
if (NijC > pCHdom[0][1]) NijC=pCHdom[0][1];
if (NijH < pCHdom[1][0]) NijH=pCHdom[1][0];
if (NijH > pCHdom[1][1]) NijH=pCHdom[1][1];
x = (int) floor(NijC);
y = (int) floor(NijH);
if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
Pij = PCHf[x][y];
dN2[0] = PCHdfdx[x][y];
dN2[1] = PCHdfdy[x][y];
} else {
if (NijC == pCHdom[0][1]) --x;
if (NijH == pCHdom[1][1]) --y;
Pij = Spbicubic(NijC,NijH,pCH[x][y],dN2);
}
}
return Pij;
}
/* ----------------------------------------------------------------------
PiRC spline
------------------------------------------------------------------------- */
double PairAIREBO::piRCSpline(double Nij, double Nji, double Nijconj,
int typei, int typej, double dN3[3])
{
int x,y,z;
double piRC;
x=0;
y=0;
z=0;
dN3[0]=0.0;
dN3[1]=0.0;
dN3[2]=0.0;
if (typei==0 && typej==0) {
// CC interaction
// if the inputs are out of bounds set them back to a point in bounds
if (Nij < piCCdom[0][0]) Nij=piCCdom[0][0];
if (Nij > piCCdom[0][1]) Nij=piCCdom[0][1];
if (Nji < piCCdom[1][0]) Nji=piCCdom[1][0];
if (Nji > piCCdom[1][1]) Nji=piCCdom[1][1];
if (Nijconj < piCCdom[2][0]) Nijconj=piCCdom[2][0];
if (Nijconj > piCCdom[2][1]) Nijconj=piCCdom[2][1];
x = (int) floor(Nij);
y = (int) floor(Nji);
z = (int) floor(Nijconj);
if (fabs(Nij-floor(Nij)) < TOL && fabs(Nji-floor(Nji)) < TOL
&& fabs(Nijconj-floor(Nijconj)) < TOL) {
piRC=piCCf[x][y][z];
dN3[0]=piCCdfdx[x][y][z];
dN3[1]=piCCdfdy[x][y][z];
dN3[2]=piCCdfdz[x][y][z];
} else {
if (Nij == piCCdom[0][1]) --x;
if (Nji == piCCdom[1][1]) --y;
if (Nijconj == piCCdom[2][1]) --z;
piRC=Sptricubic(Nij,Nji,Nijconj,piCC[x][y][z],dN3);
}
} else if ((typei==0 && typej==1) || (typei==1 && typej==0)) {
// CH interaction
// if the inputs are out of bounds set them back to a point in bounds
if (Nij < piCHdom[0][0]) Nij=piCHdom[0][0];
if (Nij > piCHdom[0][1]) Nij=piCHdom[0][1];
if (Nji < piCHdom[1][0]) Nji=piCHdom[1][0];
if (Nji > piCHdom[1][1]) Nji=piCHdom[1][1];
if (Nijconj < piCHdom[2][0]) Nijconj=piCHdom[2][0];
if (Nijconj > piCHdom[2][1]) Nijconj=piCHdom[2][1];
x = (int) floor(Nij);
y = (int) floor(Nji);
z = (int) floor(Nijconj);
if (fabs(Nij-floor(Nij)) < TOL && fabs(Nji-floor(Nji)) < TOL
&& fabs(Nijconj-floor(Nijconj)) < TOL) {
piRC=piCHf[x][y][z];
dN3[0]=piCHdfdx[x][y][z];
dN3[1]=piCHdfdy[x][y][z];
dN3[2]=piCHdfdz[x][y][z];
} else {
if (Nij == piCHdom[0][1]) --x;
if (Nji == piCHdom[1][1]) --y;
if (Nijconj == piCHdom[2][1]) --z;
piRC=Sptricubic(Nij,Nji,Nijconj,piCH[x][y][z],dN3);
}
} else if (typei==1 && typej==1) {
if (Nij < piHHdom[0][0]) Nij=piHHdom[0][0];
if (Nij > piHHdom[0][1]) Nij=piHHdom[0][1];
if (Nji < piHHdom[1][0]) Nji=piHHdom[1][0];
if (Nji > piHHdom[1][1]) Nji=piHHdom[1][1];
if (Nijconj < piHHdom[2][0]) Nijconj=piHHdom[2][0];
if (Nijconj > piHHdom[2][1]) Nijconj=piHHdom[2][1];
x = (int) floor(Nij);
y = (int) floor(Nji);
z = (int) floor(Nijconj);
if (fabs(Nij-floor(Nij)) < TOL && fabs(Nji-floor(Nji)) < TOL
&& fabs(Nijconj-floor(Nijconj)) < TOL) {
piRC=piHHf[x][y][z];
dN3[0]=piHHdfdx[x][y][z];
dN3[1]=piHHdfdy[x][y][z];
dN3[2]=piHHdfdz[x][y][z];
} else {
if (Nij == piHHdom[0][1]) --x;
if (Nji == piHHdom[1][1]) --y;
if (Nijconj == piHHdom[2][1]) --z;
piRC=Sptricubic(Nij,Nji,Nijconj,piHH[x][y][z],dN3);
}
}
return piRC;
}
/* ----------------------------------------------------------------------
Tij spline
------------------------------------------------------------------------- */
double PairAIREBO::TijSpline(double Nij, double Nji,
double Nijconj, double dN3[3])
{
int x,y,z;
double Tijf;
x=0;
y=0;
z=0;
Tijf=0.0;
dN3[0]=0.0;
dN3[1]=0.0;
dN3[2]=0.0;
//if the inputs are out of bounds set them back to a point in bounds
if (Nij < Tijdom[0][0]) Nij=Tijdom[0][0];
if (Nij > Tijdom[0][1]) Nij=Tijdom[0][1];
if (Nji < Tijdom[1][0]) Nji=Tijdom[1][0];
if (Nji > Tijdom[1][1]) Nji=Tijdom[1][1];
if (Nijconj < Tijdom[2][0]) Nijconj=Tijdom[2][0];
if (Nijconj > Tijdom[2][1]) Nijconj=Tijdom[2][1];
x = (int) floor(Nij);
y = (int) floor(Nji);
z = (int) floor(Nijconj);
if (fabs(Nij-floor(Nij)) < TOL && fabs(Nji-floor(Nji)) < TOL
&& fabs(Nijconj-floor(Nijconj)) < TOL) {
Tijf=Tf[x][y][z];
dN3[0]=Tdfdx[x][y][z];
dN3[1]=Tdfdy[x][y][z];
dN3[2]=Tdfdz[x][y][z];
} else {
if (Nij == Tijdom[0][1]) --x;
if (Nji == Tijdom[1][1]) --y;
if (Nijconj == Tijdom[2][1]) --z;
Tijf=Sptricubic(Nij,Nji,Nijconj,Tijc[x][y][z],dN3);
}
return Tijf;
}
/* ----------------------------------------------------------------------
read AIREBO potential file
------------------------------------------------------------------------- */
void PairAIREBO::read_file(char *filename)
{
int i,j,k,l,limit;
char s[MAXLINE];
// REBO Parameters (AIREBO)
double rcmin_CC,rcmin_CH,rcmin_HH,rcmax_CC,rcmax_CH,
rcmax_HH,rcmaxp_CC,rcmaxp_CH,rcmaxp_HH;
double Q_CC,Q_CH,Q_HH,alpha_CC,alpha_CH,alpha_HH,A_CC,A_CH,A_HH;
double BIJc_CC1,BIJc_CC2,BIJc_CC3,BIJc_CH1,BIJc_CH2,BIJc_CH3,
BIJc_HH1,BIJc_HH2,BIJc_HH3;
double Beta_CC1,Beta_CC2,Beta_CC3,Beta_CH1,Beta_CH2,Beta_CH3,
Beta_HH1,Beta_HH2,Beta_HH3;
double rho_CC,rho_CH,rho_HH;
// LJ Parameters (AIREBO)
double rcLJmin_CC,rcLJmin_CH,rcLJmin_HH,rcLJmax_CC,rcLJmax_CH,
rcLJmax_HH,bLJmin_CC;
double bLJmin_CH,bLJmin_HH,bLJmax_CC,bLJmax_CH,bLJmax_HH,
epsilon_CC,epsilon_CH,epsilon_HH;
double sigma_CC,sigma_CH,sigma_HH,epsilonT_CCCC,epsilonT_CCCH,epsilonT_HCCH;
// additional parameters for Morse potential.
double epsilonM_CC,epsilonM_CH,epsilonM_HH,alphaM_CC,alphaM_CH,alphaM_HH;
double reqM_CC,reqM_CH,reqM_HH;
MPI_Comm_rank(world,&me);
// read file on proc 0
if (me == 0) {
FILE *fp = force->open_potential(filename);
if (fp == NULL) {
char str[128];
if (morseflag)
sprintf(str,"Cannot open AIREBO-M potential file %s",filename);
else
sprintf(str,"Cannot open AIREBO potential file %s",filename);
error->one(FLERR,str);
}
// skip initial comment lines
while (1) {
fgets(s,MAXLINE,fp);
if (s[0] != '#') break;
}
// read parameters
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmin_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmin_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmin_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmax_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmax_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmax_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmaxp_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmaxp_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcmaxp_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&smin);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Nmin);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Nmax);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&NCmin);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&NCmax);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Q_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Q_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Q_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alpha_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alpha_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alpha_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&A_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&A_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&A_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CC1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CC2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CC3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CH1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CH2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_CH3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_HH1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_HH2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&BIJc_HH3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CC1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CC2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CC3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CH1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CH2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_CH3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_HH1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_HH2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Beta_HH3);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rho_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rho_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rho_HH);
// LJ parameters
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmin_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmin_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmin_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmax_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmax_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&rcLJmax_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmin_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmin_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmin_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmax_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmax_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&bLJmax_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilon_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilon_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilon_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&sigma_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&sigma_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&sigma_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonT_CCCC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonT_CCCH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonT_HCCH);
if (morseflag) {
// lines for reading in MORSE parameters from CH.airebo_m file
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonM_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonM_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&epsilonM_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alphaM_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alphaM_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&alphaM_HH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&reqM_CC);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&reqM_CH);
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&reqM_HH);
}
// gC spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
// number-1 = # of domains for the spline
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit; i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&gCdom[i]);
}
fgets(s,MAXLINE,fp);
for (i = 0; i < limit-1; i++) {
for (j = 0; j < 6; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&gC1[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < limit-1; i++) {
for (j = 0; j < 6; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&gC2[i][j]);
}
}
// gH spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit; i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&gHdom[i]);
}
fgets(s,MAXLINE,fp);
for (i = 0; i < limit-1; i++) {
for (j = 0; j < 6; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&gH[i][j]);
}
}
// pCC spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/2; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&pCCdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) pCCdom[0][1]; i++) {
for (j = 0; j < (int) pCCdom[1][1]; j++) {
for (k = 0; k < 16; k++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&pCC[i][j][k]);
}
}
}
// pCH spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/2; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&pCHdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) pCHdom[0][1]; i++) {
for (j = 0; j < (int) pCHdom[1][1]; j++) {
for (k = 0; k < 16; k++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&pCH[i][j][k]);
}
}
}
// piCC cpline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/3; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piCCdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) piCCdom[0][1]; i++) {
for (j = 0; j < (int) piCCdom[1][1]; j++) {
for (k = 0; k < (int) piCCdom[2][1]; k++) {
for (l = 0; l < 64; l = l+1) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piCC[i][j][k][l]);
}
}
}
}
// piCH spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/3; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piCHdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) piCHdom[0][1]; i++) {
for (j = 0; j < (int) piCHdom[1][1]; j++) {
for (k = 0; k < (int) piCHdom[2][1]; k++) {
for (l = 0; l < 64; l = l+1) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piCH[i][j][k][l]);
}
}
}
}
// piHH spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/3; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piHHdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) piHHdom[0][1]; i++) {
for (j = 0; j < (int) piHHdom[1][1]; j++) {
for (k = 0; k < (int) piHHdom[2][1]; k++) {
for (l = 0; l < 64; l = l+1) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&piHH[i][j][k][l]);
}
}
}
}
// Tij spline
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&limit);
for (i = 0; i < limit/2; i++) {
for (j = 0; j < limit/3; j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Tijdom[i][j]);
}
}
fgets(s,MAXLINE,fp);
for (i = 0; i < (int) Tijdom[0][1]; i++) {
for (j = 0; j < (int) Tijdom[1][1]; j++) {
for (k = 0; k < (int) Tijdom[2][1]; k++) {
for (l = 0; l < 64; l = l+1) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lg",&Tijc[i][j][k][l]);
}
}
}
}
fclose(fp);
}
// store read-in values in arrays
if (me == 0) {
// REBO
rcmin[0][0] = rcmin_CC;
rcmin[0][1] = rcmin_CH;
rcmin[1][0] = rcmin[0][1];
rcmin[1][1] = rcmin_HH;
rcmax[0][0] = rcmax_CC;
rcmax[0][1] = rcmax_CH;
rcmax[1][0] = rcmax[0][1];
rcmax[1][1] = rcmax_HH;
rcmaxsq[0][0] = rcmax[0][0]*rcmax[0][0];
rcmaxsq[1][0] = rcmax[1][0]*rcmax[1][0];
rcmaxsq[0][1] = rcmax[0][1]*rcmax[0][1];
rcmaxsq[1][1] = rcmax[1][1]*rcmax[1][1];
rcmaxp[0][0] = rcmaxp_CC;
rcmaxp[0][1] = rcmaxp_CH;
rcmaxp[1][0] = rcmaxp[0][1];
rcmaxp[1][1] = rcmaxp_HH;
Q[0][0] = Q_CC;
Q[0][1] = Q_CH;
Q[1][0] = Q[0][1];
Q[1][1] = Q_HH;
alpha[0][0] = alpha_CC;
alpha[0][1] = alpha_CH;
alpha[1][0] = alpha[0][1];
alpha[1][1] = alpha_HH;
A[0][0] = A_CC;
A[0][1] = A_CH;
A[1][0] = A[0][1];
A[1][1] = A_HH;
rho[0][0] = rho_CC;
rho[0][1] = rho_CH;
rho[1][0] = rho[0][1];
rho[1][1] = rho_HH;
BIJc[0][0][0] = BIJc_CC1;
BIJc[0][0][1] = BIJc_CC2;
BIJc[0][0][2] = BIJc_CC3;
BIJc[0][1][0] = BIJc_CH1;
BIJc[0][1][1] = BIJc_CH2;
BIJc[0][1][2] = BIJc_CH3;
BIJc[1][0][0] = BIJc_CH1;
BIJc[1][0][1] = BIJc_CH2;
BIJc[1][0][2] = BIJc_CH3;
BIJc[1][1][0] = BIJc_HH1;
BIJc[1][1][1] = BIJc_HH2;
BIJc[1][1][2] = BIJc_HH3;
Beta[0][0][0] = Beta_CC1;
Beta[0][0][1] = Beta_CC2;
Beta[0][0][2] = Beta_CC3;
Beta[0][1][0] = Beta_CH1;
Beta[0][1][1] = Beta_CH2;
Beta[0][1][2] = Beta_CH3;
Beta[1][0][0] = Beta_CH1;
Beta[1][0][1] = Beta_CH2;
Beta[1][0][2] = Beta_CH3;
Beta[1][1][0] = Beta_HH1;
Beta[1][1][1] = Beta_HH2;
Beta[1][1][2] = Beta_HH3;
// LJ
rcLJmin[0][0] = rcLJmin_CC;
rcLJmin[0][1] = rcLJmin_CH;
rcLJmin[1][0] = rcLJmin[0][1];
rcLJmin[1][1] = rcLJmin_HH;
rcLJmax[0][0] = rcLJmax_CC;
rcLJmax[0][1] = rcLJmax_CH;
rcLJmax[1][0] = rcLJmax[0][1];
rcLJmax[1][1] = rcLJmax_HH;
rcLJmaxsq[0][0] = rcLJmax[0][0]*rcLJmax[0][0];
rcLJmaxsq[1][0] = rcLJmax[1][0]*rcLJmax[1][0];
rcLJmaxsq[0][1] = rcLJmax[0][1]*rcLJmax[0][1];
rcLJmaxsq[1][1] = rcLJmax[1][1]*rcLJmax[1][1];
bLJmin[0][0] = bLJmin_CC;
bLJmin[0][1] = bLJmin_CH;
bLJmin[1][0] = bLJmin[0][1];
bLJmin[1][1] = bLJmin_HH;
bLJmax[0][0] = bLJmax_CC;
bLJmax[0][1] = bLJmax_CH;
bLJmax[1][0] = bLJmax[0][1];
bLJmax[1][1] = bLJmax_HH;
epsilon[0][0] = epsilon_CC;
epsilon[0][1] = epsilon_CH;
epsilon[1][0] = epsilon[0][1];
epsilon[1][1] = epsilon_HH;
sigma[0][0] = sigma_CC;
sigma[0][1] = sigma_CH;
sigma[1][0] = sigma[0][1];
sigma[1][1] = sigma_HH;
if (morseflag) {
// Morse parameter assignments
epsilonM[0][0] = epsilonM_CC;
epsilonM[0][1] = epsilonM_CH;
epsilonM[1][0] = epsilonM[0][1];
epsilonM[1][1] = epsilonM_HH;
alphaM[0][0] = alphaM_CC;
alphaM[0][1] = alphaM_CH;
alphaM[1][0] = alphaM[0][1];
alphaM[1][1] = alphaM_HH;
reqM[0][0] = reqM_CC;
reqM[0][1] = reqM_CH;
reqM[1][0] = reqM[0][1];
reqM[1][1] = reqM_HH;
}
// torsional
thmin = -1.0;
thmax = -0.995;
epsilonT[0][0] = epsilonT_CCCC;
epsilonT[0][1] = epsilonT_CCCH;
epsilonT[1][0] = epsilonT[0][1];
epsilonT[1][1] = epsilonT_HCCH;
}
// broadcast read-in and setup values
MPI_Bcast(&thmin,1,MPI_DOUBLE,0,world);
MPI_Bcast(&thmax,1,MPI_DOUBLE,0,world);
MPI_Bcast(&smin,1,MPI_DOUBLE,0,world);
MPI_Bcast(&Nmin,1,MPI_DOUBLE,0,world);
MPI_Bcast(&Nmax,1,MPI_DOUBLE,0,world);
MPI_Bcast(&NCmin,1,MPI_DOUBLE,0,world);
MPI_Bcast(&NCmax,1,MPI_DOUBLE,0,world);
MPI_Bcast(&rcmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcmax[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcmaxsq[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcmaxp[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&Q[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&A[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&BIJc[0][0][0],12,MPI_DOUBLE,0,world);
MPI_Bcast(&Beta[0][0][0],12,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmaxsq[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&rcLJmax[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&bLJmin[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&bLJmax[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&epsilon[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&epsilonT[0][0],4,MPI_DOUBLE,0,world);
if (morseflag) {
// Morse parameter broadcast
MPI_Bcast(&epsilonM[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&alphaM[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&reqM[0][0],4,MPI_DOUBLE,0,world);
}
MPI_Bcast(&gCdom[0],5,MPI_DOUBLE,0,world);
MPI_Bcast(&gC1[0][0],24,MPI_DOUBLE,0,world);
MPI_Bcast(&gC2[0][0],24,MPI_DOUBLE,0,world);
MPI_Bcast(&gHdom[0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&gH[0][0],18,MPI_DOUBLE,0,world);
MPI_Bcast(&pCCdom[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&pCHdom[0][0],4,MPI_DOUBLE,0,world);
MPI_Bcast(&pCC[0][0][0],256,MPI_DOUBLE,0,world);
MPI_Bcast(&pCH[0][0][0],256,MPI_DOUBLE,0,world);
MPI_Bcast(&piCCdom[0][0],6,MPI_DOUBLE,0,world);
MPI_Bcast(&piCHdom[0][0],6,MPI_DOUBLE,0,world);
MPI_Bcast(&piHHdom[0][0],6,MPI_DOUBLE,0,world);
MPI_Bcast(&piCC[0][0][0][0],9216,MPI_DOUBLE,0,world);
MPI_Bcast(&piCH[0][0][0][0],9216,MPI_DOUBLE,0,world);
MPI_Bcast(&piHH[0][0][0][0],9216,MPI_DOUBLE,0,world);
MPI_Bcast(&Tijdom[0][0],6,MPI_DOUBLE,0,world);
MPI_Bcast(&Tijc[0][0][0][0],9216,MPI_DOUBLE,0,world);
}
// ----------------------------------------------------------------------
// generic Spline functions
// ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
fifth order spline evaluation
------------------------------------------------------------------------- */
double PairAIREBO::Sp5th(double x, double coeffs[6], double *df)
{
double f, d;
const double x2 = x*x;
const double x3 = x2*x;
f = coeffs[0];
f += coeffs[1]*x;
d = coeffs[1];
f += coeffs[2]*x2;
d += 2.0*coeffs[2]*x;
f += coeffs[3]*x3;
d += 3.0*coeffs[3]*x2;
f += coeffs[4]*x2*x2;
d += 4.0*coeffs[4]*x3;
f += coeffs[5]*x2*x3;
d += 5.0*coeffs[5]*x2*x2;
*df = d;
return f;
}
/* ----------------------------------------------------------------------
bicubic spline evaluation
------------------------------------------------------------------------- */
double PairAIREBO::Spbicubic(double x, double y,
double coeffs[16], double df[2])
{
double f,xn,yn,xn1,yn1,c;
int i,j;
f = 0.0;
df[0] = 0.0;
df[1] = 0.0;
xn = 1.0;
for (i = 0; i < 4; i++) {
yn = 1.0;
for (j = 0; j < 4; j++) {
c = coeffs[i*4+j];
f += c*xn*yn;
if (i > 0) df[0] += c * ((double) i) * xn1 * yn;
if (j > 0) df[1] += c * ((double) j) * xn * yn1;
yn1 = yn;
yn *= y;
}
xn1 = xn;
xn *= x;
}
return f;
}
/* ----------------------------------------------------------------------
tricubic spline evaluation
------------------------------------------------------------------------- */
double PairAIREBO::Sptricubic(double x, double y, double z,
double coeffs[64], double df[3])
{
double f,ir,jr,kr,xn,yn,zn,xn1,yn1,zn1,c;
int i,j,k;
f = 0.0;
df[0] = 0.0;
df[1] = 0.0;
df[2] = 0.0;
xn = 1.0;
for (i = 0; i < 4; i++) {
ir = (double) i;
yn = 1.0;
for (j = 0; j < 4; j++) {
jr = (double) j;
zn = 1.0;
for (k = 0; k < 4; k++) {
kr = (double) k;
c = coeffs[16*i+4*j+k];
f += c*xn*yn*zn;
if (i > 0) df[0] += c * ir * xn1 * yn * zn;
if (j > 0) df[1] += c * jr * xn * yn1 * zn;
if (k > 0) df[2] += c * kr * xn * yn * zn1;
zn1 = zn;
zn *= z;
}
yn1 = yn;
yn *= y;
}
xn1 = xn;
xn *= x;
}
return f;
}
/* ----------------------------------------------------------------------
spline coefficient matrix python script
-------------------------------------------------------------------------
import numpy as np
import numpy.linalg as lin
# Generate all the derivatives that are spline conditions
# Ordered such that df / dx_i / d_xj i < j.
# Gives the derivatives at which the spline's values are prescribed.
def generate_derivs(n):
def generate_derivs_order(n, m):
if m == 0:
return [tuple()]
if m == 1:
return [tuple([i]) for i in range(n)]
rec = generate_derivs_order(n, m - 1)
return [tuple([i]+list(j)) for i in range(n) for j in rec if j[0] > i]
ret = []
m = 0
while m <= n:
ret += generate_derivs_order(n, m)
m += 1
return ret
# Generate all the points in an n-dimensional unit cube.
# Gives the points at which the spline's values are prescribed.
def generate_points(n):
if n == 1:
return [(0,), (1,)]
rec = generate_points(n - 1)
return [tuple([j]+list(i)) for j in range(2) for i in rec]
# Generate all the coefficients in the order later expected.
def generate_coeffs(n):
if n == 1:
return [tuple([i]) for i in range(4)] # cubic
rec = generate_coeffs(n-1)
return [tuple([i]+list(j)) for i in range(4) for j in rec]
# Evaluate the `deriv`'s derivative at `point` symbolically
# with respect to the coefficients `coeffs`.
def eval_at(n, coeffs, deriv, point):
def eval_single(order, value, the_deriv):
if the_deriv:
if order == 0:
return 0
if order == 1:
return 1
return order * value
else:
if order == 0:
return 1
else:
return value
result = {}
for c in coeffs:
result[c] = 1
for i in range(n):
result[c] *= eval_single(c[i], point[i], i in deriv)
return result
# Build the matrix transforming prescribed values to coefficients.
def get_matrix(n):
coeffs = generate_coeffs(n)
points = generate_points(n)
derivs = generate_derivs(n)
assert(len(coeffs) == len(points)*len(derivs))
i = 0
A = np.zeros((len(coeffs), len(points)*len(derivs)))
for d in derivs:
for p in points:
coeff = eval_at(n, coeffs, d, p)
for j, c in enumerate(coeffs):
A[i, j] = coeff[c]
i += 1
return lin.inv(A)
# Output the first k values with padding n from A.
def output_matrix(n, k, A):
print('\n'.join([''.join([("%{}d,".format(n+1)) % i for i in j[:k]]) for j in A]))
*/
/* ----------------------------------------------------------------------
tricubic spline coefficient calculation
------------------------------------------------------------------------- */
void PairAIREBO::Sptricubic_patch_adjust(double * dl, double wid, double lo,
char dir) {
- int rowOuterL = 16, rowInnerL = 1, colL;
+ int rowOuterL = 16, rowInnerL = 1, colL = 4;
if (dir == 'R') {
rowOuterL = 4;
colL = 16;
} else if (dir == 'M') {
colL = 4;
} else if (dir == 'L') {
rowInnerL = 4;
colL = 1;
}
double binomial[5] = {1, 1, 2, 6};
for (int rowOuter = 0; rowOuter < 4; rowOuter++) {
for (int rowInner = 0; rowInner < 4; rowInner++) {
for (int col = 0; col < 4; col++) {
double acc = 0;
for (int k = col; k < 4; k++) {
acc += dl[rowOuterL * rowOuter + rowInnerL * rowInner + colL * k]
* pow(wid, -k) * pow(-lo, k - col) * binomial[k] / binomial[col]
/ binomial[k - col];
}
dl[rowOuterL * rowOuter + rowInnerL * rowInner + colL * col] = acc;
}
}
}
}
void PairAIREBO::Sptricubic_patch_coeffs(
double xmin, double xmax, double ymin, double ymax, double zmin, double zmax,
double * y, double * y1, double * y2, double * y3, double * dl
) {
const double C_inv[64][32] = {
// output_matrix(2, 8*4, get_matrix(3))
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0,
2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0,
9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0,
-6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0,
2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0,
-6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0,
4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-3, 0, 0, 0, 3, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0,
9, -9, 0, 0, -9, 9, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0,
-6, 6, 0, 0, 6, -6, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 0, -9, 0, -9, 0, 9, 0, 6, 0, -6, 0, 3, 0, -3, 0, 6, 0, 3, 0, -6, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, -9, 0, -9, 0, 9, 0,
-27, 27, 27,-27, 27,-27,-27, 27,-18, 18, 18,-18, -9, 9, 9, -9,-18, 18, -9, 9, 18,-18, 9, -9,-18, -9, 18, 9, 18, 9,-18, -9,
18,-18,-18, 18,-18, 18, 18,-18, 12,-12,-12, 12, 6, -6, -6, 6, 12,-12, 6, -6,-12, 12, -6, 6, 9, 9, -9, -9, -9, -9, 9, 9,
-6, 0, 6, 0, 6, 0, -6, 0, -4, 0, 4, 0, -2, 0, 2, 0, -3, 0, -3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0,
18,-18,-18, 18,-18, 18, 18,-18, 12,-12,-12, 12, 6, -6, -6, 6, 9, -9, 9, -9, -9, 9, -9, 9, 12, 6,-12, -6,-12, -6, 12, 6,
-12, 12, 12,-12, 12,-12,-12, 12, -8, 8, 8, -8, -4, 4, 4, -4, -6, 6, -6, 6, 6, -6, 6, -6, -6, -6, 6, 6, 6, 6, -6, -6,
2, 0, 0, 0, -2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0,
-6, 6, 0, 0, 6, -6, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0,
4, -4, 0, 0, -4, 4, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-6, 0, 6, 0, 6, 0, -6, 0, -3, 0, 3, 0, -3, 0, 3, 0, -4, 0, -2, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0,
18,-18,-18, 18,-18, 18, 18,-18, 9, -9, -9, 9, 9, -9, -9, 9, 12,-12, 6, -6,-12, 12, -6, 6, 12, 6,-12, -6,-12, -6, 12, 6,
-12, 12, 12,-12, 12,-12,-12, 12, -6, 6, 6, -6, -6, 6, 6, -6, -8, 8, -4, 4, 8, -8, 4, -4, -6, -6, 6, 6, 6, 6, -6, -6,
4, 0, -4, 0, -4, 0, 4, 0, 2, 0, -2, 0, 2, 0, -2, 0, 2, 0, 2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, -4, 0, 4, 0,
-12, 12, 12,-12, 12,-12,-12, 12, -6, 6, 6, -6, -6, 6, 6, -6, -6, 6, -6, 6, 6, -6, 6, -6, -8, -4, 8, 4, 8, 4, -8, -4,
8, -8, -8, 8, -8, 8, 8, -8, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, 4, -4, -4, 4, -4, 4, 4, 4, -4, -4, -4, -4, 4, 4,
};
double dx = xmax - xmin;
double dy = ymax - ymin;
double dz = zmax - zmin;
double x[32];
for (int i = 0; i < 8; i++) {
x[i+0*8] = y[i];
x[i+1*8] = y1[i] * dx;
x[i+2*8] = y2[i] * dy;
x[i+3*8] = y3[i] * dz;
}
for (int i = 0; i < 64; i++) {
dl[i] = 0;
for (int k = 0; k < 32; k++) {
dl[i] += x[k] * C_inv[i][k];
}
}
Sptricubic_patch_adjust(dl, dx, xmin, 'R');
Sptricubic_patch_adjust(dl, dy, ymin, 'M');
Sptricubic_patch_adjust(dl, dz, zmin, 'L');
}
/* ----------------------------------------------------------------------
bicubic spline coefficient calculation
------------------------------------------------------------------------- */
void PairAIREBO::Spbicubic_patch_adjust(double * dl, double wid, double lo,
char dir) {
int rowL = dir == 'R' ? 1 : 4;
int colL = dir == 'L' ? 1 : 4;
double binomial[5] = {1, 1, 2, 6};
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
double acc = 0;
for (int k = col; k < 4; k++) {
acc += dl[rowL * row + colL * k] * pow(wid, -k) * pow(-lo, k - col)
* binomial[k] / binomial[col] / binomial[k - col];
}
dl[rowL * row + colL * col] = acc;
}
}
}
void PairAIREBO::Spbicubic_patch_coeffs(
double xmin, double xmax, double ymin, double ymax, double * y,
double * y1, double * y2, double * dl
) {
const double C_inv[16][12] = {
// output_matrix(1, 4*3, get_matrix(2))
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,
2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0,
-3, 0, 3, 0,-2, 0,-1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0,
9,-9,-9, 9, 6,-6, 3,-3, 6, 3,-6,-3,
-6, 6, 6,-6,-4, 4,-2, 2,-3,-3, 3, 3,
2, 0,-2, 0, 1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0,
-6, 6, 6,-6,-3, 3,-3, 3,-4,-2, 4, 2,
4,-4,-4, 4, 2,-2, 2,-2, 2, 2,-2,-2,
};
double dx = xmax - xmin;
double dy = ymax - ymin;
double x[12];
for (int i = 0; i < 4; i++) {
x[i+0*4] = y[i];
x[i+1*4] = y1[i] * dx;
x[i+2*4] = y2[i] * dy;
}
for (int i = 0; i < 16; i++) {
dl[i] = 0;
for (int k = 0; k < 12; k++) {
dl[i] += x[k] * C_inv[i][k];
}
}
Spbicubic_patch_adjust(dl, dx, xmin, 'R');
Spbicubic_patch_adjust(dl, dy, ymin, 'L');
}
/* ----------------------------------------------------------------------
initialize spline knot values
------------------------------------------------------------------------- */
void PairAIREBO::spline_init()
{
int i,j,k;
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
PCCf[i][j] = 0.0;
PCCdfdx[i][j] = 0.0;
PCCdfdy[i][j] = 0.0;
PCHf[i][j] = 0.0;
PCHdfdx[i][j] = 0.0;
PCHdfdy[i][j] = 0.0;
}
}
PCCf[0][2] = -0.00050;
PCCf[0][3] = 0.0161253646;
PCCf[1][1] = -0.010960;
PCCf[1][2] = 0.00632624824;
// this one parameter for C-C interactions is different in REBO vs AIREBO
// see Favata, Micheletti, Ryu, Pugno, Comp Phys Comm (2016)
PCCf[2][0] = PCCf_2_0;
PCCf[2][1] = 0.00317953083;
PCHf[0][1] = 0.209336733;
PCHf[0][2] = -0.0644496154;
PCHf[0][3] = -0.303927546;
PCHf[1][0] = 0.010;
PCHf[1][1] = -0.125123401;
PCHf[1][2] = -0.298905246;
PCHf[2][0] = -0.122042146;
PCHf[2][1] = -0.300529172;
PCHf[3][0] = -0.307584705;
for (int nH = 0; nH < 4; nH++) {
for (int nC = 0; nC < 4; nC++) {
double y[4] = {0}, y1[4] = {0}, y2[4] = {0};
y[0] = PCCf[nC][nH];
y[1] = PCCf[nC][nH+1];
y[2] = PCCf[nC+1][nH];
y[3] = PCCf[nC+1][nH+1];
Spbicubic_patch_coeffs(nC, nC+1, nH, nH+1, y, y1, y2, &pCC[nC][nH][0]);
y[0] = PCHf[nC][nH];
y[1] = PCHf[nC][nH+1];
y[2] = PCHf[nC+1][nH];
y[3] = PCHf[nC+1][nH+1];
Spbicubic_patch_coeffs(nC, nC+1, nH, nH+1, y, y1, y2, &pCH[nC][nH][0]);
}
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
for (k = 0; k < 10; k++) {
piCCf[i][j][k] = 0.0;
piCCdfdx[i][j][k] = 0.0;
piCCdfdy[i][j][k] = 0.0;
piCCdfdz[i][j][k] = 0.0;
piCHf[i][j][k] = 0.0;
piCHdfdx[i][j][k] = 0.0;
piCHdfdy[i][j][k] = 0.0;
piCHdfdz[i][j][k] = 0.0;
piHHf[i][j][k] = 0.0;
piHHdfdx[i][j][k] = 0.0;
piHHdfdy[i][j][k] = 0.0;
piHHdfdz[i][j][k] = 0.0;
Tf[i][j][k] = 0.0;
Tdfdx[i][j][k] = 0.0;
Tdfdy[i][j][k] = 0.0;
Tdfdz[i][j][k] = 0.0;
}
}
}
for (i = 3; i < 10; i++) piCCf[0][0][i] = 0.0049586079;
piCCf[1][0][1] = 0.021693495;
piCCf[0][1][1] = 0.021693495;
for (i = 2; i < 10; i++) piCCf[1][0][i] = 0.0049586079;
for (i = 2; i < 10; i++) piCCf[0][1][i] = 0.0049586079;
piCCf[1][1][1] = 0.05250;
piCCf[1][1][2] = -0.002088750;
for (i = 3; i < 10; i++) piCCf[1][1][i] = -0.00804280;
piCCf[2][0][1] = 0.024698831850;
piCCf[0][2][1] = 0.024698831850;
piCCf[2][0][2] = -0.00597133450;
piCCf[0][2][2] = -0.00597133450;
for (i = 3; i < 10; i++) piCCf[2][0][i] = 0.0049586079;
for (i = 3; i < 10; i++) piCCf[0][2][i] = 0.0049586079;
piCCf[2][1][1] = 0.00482478490;
piCCf[1][2][1] = 0.00482478490;
piCCf[2][1][2] = 0.0150;
piCCf[1][2][2] = 0.0150;
piCCf[2][1][3] = -0.010;
piCCf[1][2][3] = -0.010;
piCCf[2][1][4] = -0.01168893870;
piCCf[1][2][4] = -0.01168893870;
piCCf[2][1][5] = -0.013377877400;
piCCf[1][2][5] = -0.013377877400;
piCCf[2][1][6] = -0.015066816000;
piCCf[1][2][6] = -0.015066816000;
for (i = 7; i < 10; i++) piCCf[2][1][i] = -0.015066816000;
for (i = 7; i < 10; i++) piCCf[1][2][i] = -0.015066816000;
piCCf[2][2][1] = 0.0472247850;
piCCf[2][2][2] = 0.0110;
piCCf[2][2][3] = 0.0198529350;
piCCf[2][2][4] = 0.01654411250;
piCCf[2][2][5] = 0.013235290;
piCCf[2][2][6] = 0.00992646749999 ;
piCCf[2][2][7] = 0.006617644999;
piCCf[2][2][8] = 0.00330882250;
piCCf[3][0][1] = -0.05989946750;
piCCf[0][3][1] = -0.05989946750;
piCCf[3][0][2] = -0.05989946750;
piCCf[0][3][2] = -0.05989946750;
for (i = 3; i < 10; i++) piCCf[3][0][i] = 0.0049586079;
for (i = 3; i < 10; i++) piCCf[0][3][i] = 0.0049586079;
piCCf[3][1][2] = -0.0624183760;
piCCf[1][3][2] = -0.0624183760;
for (i = 3; i < 10; i++) piCCf[3][1][i] = -0.0624183760;
for (i = 3; i < 10; i++) piCCf[1][3][i] = -0.0624183760;
piCCf[3][2][1] = -0.02235469150;
piCCf[2][3][1] = -0.02235469150;
for (i = 2; i < 10; i++) piCCf[3][2][i] = -0.02235469150;
for (i = 2; i < 10; i++) piCCf[2][3][i] = -0.02235469150;
piCCdfdx[2][1][1] = -0.026250;
piCCdfdx[2][1][5] = -0.0271880;
piCCdfdx[2][1][6] = -0.0271880;
for (i = 7; i < 10; i++) piCCdfdx[2][1][i] = -0.0271880;
piCCdfdx[1][3][2] = 0.0187723882;
for (i = 2; i < 10; i++) piCCdfdx[2][3][i] = 0.031209;
piCCdfdy[1][2][1] = -0.026250;
piCCdfdy[1][2][5] = -0.0271880;
piCCdfdy[1][2][6] = -0.0271880;
for (i = 7; i < 10; i++) piCCdfdy[1][2][i] = -0.0271880;
piCCdfdy[3][1][2] = 0.0187723882;
for (i = 2; i < 10; i++) piCCdfdy[3][2][i] = 0.031209;
piCCdfdz[1][1][2] = -0.0302715;
piCCdfdz[2][1][4] = -0.0100220;
piCCdfdz[1][2][4] = -0.0100220;
piCCdfdz[2][1][5] = -0.0100220;
piCCdfdz[1][2][5] = -0.0100220;
for (i = 4; i < 9; i++) piCCdfdz[2][2][i] = -0.0033090;
// make top end of piCC flat instead of zero
i = 4;
for (j = 0; j < 4; j++){
for (k = 1; k < 11; k++){
piCCf[i][j][k] = piCCf[i-1][j][k];
}
}
for (i = 0; i < 4; i++){ // also enforces some symmetry
for (j = i+1; j < 5; j++){
for (k = 1; k < 11; k++){
piCCf[i][j][k] = piCCf[j][i][k];
}
}
}
for (k = 1; k < 11; k++) piCCf[4][4][k] = piCCf[3][4][k];
k = 10;
for (i = 0; i < 5; i++){
for (j = 0; j < 5; j++){
piCCf[i][j][k] = piCCf[i][j][k-1];
}
}
piCHf[1][1][1] = -0.050;
piCHf[1][1][2] = -0.050;
piCHf[1][1][3] = -0.30;
for (i = 4; i < 10; i++) piCHf[1][1][i] = -0.050;
for (i = 5; i < 10; i++) piCHf[2][0][i] = -0.004523893758064;
for (i = 5; i < 10; i++) piCHf[0][2][i] = -0.004523893758064;
piCHf[2][1][2] = -0.250;
piCHf[1][2][2] = -0.250;
piCHf[2][1][3] = -0.250;
piCHf[1][2][3] = -0.250;
piCHf[3][1][1] = -0.10;
piCHf[1][3][1] = -0.10;
piCHf[3][1][2] = -0.125;
piCHf[1][3][2] = -0.125;
piCHf[3][1][3] = -0.125;
piCHf[1][3][3] = -0.125;
for (i = 4; i < 10; i++) piCHf[3][1][i] = -0.10;
for (i = 4; i < 10; i++) piCHf[1][3][i] = -0.10;
// make top end of piCH flat instead of zero
// also enforces some symmetry
i = 4;
for (j = 0; j < 4; j++){
for (k = 1; k < 11; k++){
piCHf[i][j][k] = piCHf[i-1][j][k];
}
}
for (i = 0; i < 4; i++){
for (j = i+1; j < 5; j++){
for (k = 1; k < 11; k++){
piCHf[i][j][k] = piCHf[j][i][k];
}
}
}
for (k = 1; k < 11; k++) piCHf[4][4][k] = piCHf[3][4][k];
k = 10;
for (i = 0; i < 5; i++){
for (j = 0; j < 5; j++){
piCHf[i][j][k] = piCHf[i][j][k-1];
}
}
piHHf[1][1][1] = 0.124915958;
Tf[2][2][1] = -0.035140;
for (i = 2; i < 10; i++) Tf[2][2][i] = -0.0040480;
for (int nH = 0; nH < 4; nH++) {
for (int nC = 0; nC < 4; nC++) {
// Note: Spline knot values exist up to "10", but are never used because
// they are clamped down to 9.
for (int nConj = 0; nConj < 9; nConj++) {
double y[8] = {0}, y1[8] = {0}, y2[8] = {0}, y3[8] = {0};
#define FILL_KNOTS_TRI(dest, src) \
dest[0] = src[nC+0][nH+0][nConj+0]; \
dest[1] = src[nC+0][nH+0][nConj+1]; \
dest[2] = src[nC+0][nH+1][nConj+0]; \
dest[3] = src[nC+0][nH+1][nConj+1]; \
dest[4] = src[nC+1][nH+0][nConj+0]; \
dest[5] = src[nC+1][nH+0][nConj+1]; \
dest[6] = src[nC+1][nH+1][nConj+0]; \
dest[7] = src[nC+1][nH+1][nConj+1];
FILL_KNOTS_TRI(y, piCCf)
FILL_KNOTS_TRI(y1, piCCdfdx)
FILL_KNOTS_TRI(y2, piCCdfdy)
FILL_KNOTS_TRI(y3, piCCdfdz)
Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piCC[nC][nH][nConj][0]);
FILL_KNOTS_TRI(y, piCHf)
FILL_KNOTS_TRI(y1, piCHdfdx)
FILL_KNOTS_TRI(y2, piCHdfdy)
FILL_KNOTS_TRI(y3, piCHdfdz)
Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piCH[nC][nH][nConj][0]);
FILL_KNOTS_TRI(y, piHHf)
FILL_KNOTS_TRI(y1, piHHdfdx)
FILL_KNOTS_TRI(y2, piHHdfdy)
FILL_KNOTS_TRI(y3, piHHdfdz)
Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piHH[nC][nH][nConj][0]);
FILL_KNOTS_TRI(y, Tf)
FILL_KNOTS_TRI(y1, Tdfdx)
FILL_KNOTS_TRI(y2, Tdfdy)
FILL_KNOTS_TRI(y3, Tdfdz)
Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &Tijc[nC][nH][nConj][0]);
#undef FILL_KNOTS_TRI
}
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairAIREBO::memory_usage()
{
double bytes = 0.0;
bytes += maxlocal * sizeof(int);
bytes += maxlocal * sizeof(int *);
for (int i = 0; i < comm->nthreads; i++)
bytes += ipage[i].size();
bytes += 2*maxlocal * sizeof(double);
return bytes;
}
diff --git a/src/MANYBODY/pair_eam.cpp b/src/MANYBODY/pair_eam.cpp
index d3ac3951b..29a627e1d 100644
--- a/src/MANYBODY/pair_eam.cpp
+++ b/src/MANYBODY/pair_eam.cpp
@@ -1,906 +1,910 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Stephen Foiles (SNL), Murray Daw (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_eam.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
/* ---------------------------------------------------------------------- */
PairEAM::PairEAM(LAMMPS *lmp) : Pair(lmp)
{
restartinfo = 0;
manybody_flag = 1;
nmax = 0;
rho = NULL;
fp = NULL;
map = NULL;
type2frho = NULL;
nfuncfl = 0;
funcfl = NULL;
setfl = NULL;
fs = NULL;
frho = NULL;
rhor = NULL;
z2r = NULL;
scale = NULL;
frho_spline = NULL;
rhor_spline = NULL;
z2r_spline = NULL;
// set comm size needed by this Pair
comm_forward = 1;
comm_reverse = 1;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairEAM::~PairEAM()
{
if (copymode) return;
memory->destroy(rho);
memory->destroy(fp);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
delete [] type2frho;
map = NULL;
type2frho = NULL;
memory->destroy(type2rhor);
memory->destroy(type2z2r);
memory->destroy(scale);
}
if (funcfl) {
for (int i = 0; i < nfuncfl; i++) {
delete [] funcfl[i].file;
memory->destroy(funcfl[i].frho);
memory->destroy(funcfl[i].rhor);
memory->destroy(funcfl[i].zr);
}
memory->sfree(funcfl);
funcfl = NULL;
}
if (setfl) {
for (int i = 0; i < setfl->nelements; i++) delete [] setfl->elements[i];
delete [] setfl->elements;
delete [] setfl->mass;
memory->destroy(setfl->frho);
memory->destroy(setfl->rhor);
memory->destroy(setfl->z2r);
delete setfl;
setfl = NULL;
}
if (fs) {
for (int i = 0; i < fs->nelements; i++) delete [] fs->elements[i];
delete [] fs->elements;
delete [] fs->mass;
memory->destroy(fs->frho);
memory->destroy(fs->rhor);
memory->destroy(fs->z2r);
delete fs;
fs = NULL;
}
memory->destroy(frho);
memory->destroy(rhor);
memory->destroy(z2r);
memory->destroy(frho_spline);
memory->destroy(rhor_spline);
memory->destroy(z2r_spline);
}
/* ---------------------------------------------------------------------- */
void PairEAM::compute(int eflag, int vflag)
{
int i,j,ii,jj,m,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r,p,rhoip,rhojp,z2,z2p,recip,phip,psip,phi;
double *coeff;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = eflag_global = eflag_atom = 0;
// grow energy and fp arrays if necessary
// need to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(rho);
memory->destroy(fp);
nmax = atom->nmax;
memory->create(rho,nmax,"pair:rho");
memory->create(fp,nmax,"pair:fp");
}
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// zero out density
if (newton_pair) {
for (i = 0; i < nall; i++) rho[i] = 0.0;
} else for (i = 0; i < nlocal; i++) rho[i] = 0.0;
// rho = density at each atom
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cutforcesq) {
jtype = type[j];
p = sqrt(rsq)*rdr + 1.0;
m = static_cast<int> (p);
m = MIN(m,nr-1);
p -= m;
p = MIN(p,1.0);
coeff = rhor_spline[type2rhor[jtype][itype]][m];
rho[i] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
if (newton_pair || j < nlocal) {
coeff = rhor_spline[type2rhor[itype][jtype]][m];
rho[j] += ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
}
}
}
}
// communicate and sum densities
if (newton_pair) comm->reverse_comm_pair(this);
// fp = derivative of embedding energy at each atom
// phi = embedding energy at each atom
// if rho > rhomax (e.g. due to close approach of two atoms),
// will exceed table, so add linear term to conserve energy
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
p = rho[i]*rdrho + 1.0;
m = static_cast<int> (p);
m = MAX(1,MIN(m,nrho-1));
p -= m;
p = MIN(p,1.0);
coeff = frho_spline[type2frho[type[i]]][m];
fp[i] = (coeff[0]*p + coeff[1])*p + coeff[2];
if (eflag) {
phi = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
if (rho[i] > rhomax) phi += fp[i] * (rho[i]-rhomax);
phi *= scale[type[i]][type[i]];
if (eflag_global) eng_vdwl += phi;
if (eflag_atom) eatom[i] += phi;
}
}
// communicate derivative of embedding function
comm->forward_comm_pair(this);
// compute forces on each atom
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cutforcesq) {
jtype = type[j];
r = sqrt(rsq);
p = r*rdr + 1.0;
m = static_cast<int> (p);
m = MIN(m,nr-1);
p -= m;
p = MIN(p,1.0);
// rhoip = derivative of (density at atom j due to atom i)
// rhojp = derivative of (density at atom i due to atom j)
// phi = pair potential energy
// phip = phi'
// z2 = phi * r
// z2p = (phi * r)' = (phi' r) + phi
// psip needs both fp[i] and fp[j] terms since r_ij appears in two
// terms of embed eng: Fi(sum rho_ij) and Fj(sum rho_ji)
// hence embed' = Fi(sum rho_ij) rhojp + Fj(sum rho_ji) rhoip
// scale factor can be applied by thermodynamic integration
coeff = rhor_spline[type2rhor[itype][jtype]][m];
rhoip = (coeff[0]*p + coeff[1])*p + coeff[2];
coeff = rhor_spline[type2rhor[jtype][itype]][m];
rhojp = (coeff[0]*p + coeff[1])*p + coeff[2];
coeff = z2r_spline[type2z2r[itype][jtype]][m];
z2p = (coeff[0]*p + coeff[1])*p + coeff[2];
z2 = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
recip = 1.0/r;
phi = z2*recip;
phip = z2p*recip - phi*recip;
psip = fp[i]*rhojp + fp[j]*rhoip + phip;
fpair = -scale[itype][jtype]*psip*recip;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) evdwl = scale[itype][jtype]*phi;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairEAM::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
map = new int[n+1];
for (int i = 1; i <= n; i++) map[i] = -1;
type2frho = new int[n+1];
memory->create(type2rhor,n+1,n+1,"pair:type2rhor");
memory->create(type2z2r,n+1,n+1,"pair:type2z2r");
memory->create(scale,n+1,n+1,"pair:scale");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairEAM::settings(int narg, char **arg)
{
if (narg > 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
read DYNAMO funcfl file
------------------------------------------------------------------------- */
void PairEAM::coeff(int narg, char **arg)
{
if (!allocated) allocate();
if (narg != 3) error->all(FLERR,"Incorrect args for pair coefficients");
// parse pair of atom types
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
// read funcfl file if hasn't already been read
// store filename in Funcfl data struct
int ifuncfl;
for (ifuncfl = 0; ifuncfl < nfuncfl; ifuncfl++)
if (strcmp(arg[2],funcfl[ifuncfl].file) == 0) break;
if (ifuncfl == nfuncfl) {
nfuncfl++;
funcfl = (Funcfl *)
memory->srealloc(funcfl,nfuncfl*sizeof(Funcfl),"pair:funcfl");
read_file(arg[2]);
int n = strlen(arg[2]) + 1;
funcfl[ifuncfl].file = new char[n];
strcpy(funcfl[ifuncfl].file,arg[2]);
}
// set setflag and map only for i,i type pairs
// set mass of atom type if i = j
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
if (i == j) {
setflag[i][i] = 1;
map[i] = ifuncfl;
atom->set_mass(FLERR,i,funcfl[ifuncfl].mass);
count++;
}
scale[i][j] = 1.0;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairEAM::init_style()
{
// convert read-in file(s) to arrays and spline them
file2array();
array2spline();
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairEAM::init_one(int i, int j)
{
// single global cutoff = max of cut from all files read in
// for funcfl could be multiple files
// for setfl or fs, just one file
if (setflag[i][j] == 0) scale[i][j] = 1.0;
scale[j][i] = scale[i][j];
if (funcfl) {
cutmax = 0.0;
for (int m = 0; m < nfuncfl; m++)
cutmax = MAX(cutmax,funcfl[m].cut);
} else if (setfl) cutmax = setfl->cut;
else if (fs) cutmax = fs->cut;
cutforcesq = cutmax*cutmax;
return cutmax;
}
/* ----------------------------------------------------------------------
read potential values from a DYNAMO single element funcfl file
------------------------------------------------------------------------- */
void PairEAM::read_file(char *filename)
{
Funcfl *file = &funcfl[nfuncfl-1];
int me = comm->me;
FILE *fptr;
char line[MAXLINE];
if (me == 0) {
fptr = force->open_potential(filename);
if (fptr == NULL) {
char str[128];
sprintf(str,"Cannot open EAM potential file %s",filename);
error->one(FLERR,str);
}
}
- int tmp;
+ int tmp,nwords;
if (me == 0) {
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
sscanf(line,"%d %lg",&tmp,&file->mass);
fgets(line,MAXLINE,fptr);
- sscanf(line,"%d %lg %d %lg %lg",
+ nwords = sscanf(line,"%d %lg %d %lg %lg",
&file->nrho,&file->drho,&file->nr,&file->dr,&file->cut);
}
+ MPI_Bcast(&nwords,1,MPI_INT,0,world);
MPI_Bcast(&file->mass,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->nrho,1,MPI_INT,0,world);
MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->nr,1,MPI_INT,0,world);
MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world);
+ if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0))
+ error->all(FLERR,"Invalid EAM potential file");
+
memory->create(file->frho,(file->nrho+1),"pair:frho");
memory->create(file->rhor,(file->nr+1),"pair:rhor");
memory->create(file->zr,(file->nr+1),"pair:zr");
if (me == 0) grab(fptr,file->nrho,&file->frho[1]);
MPI_Bcast(&file->frho[1],file->nrho,MPI_DOUBLE,0,world);
if (me == 0) grab(fptr,file->nr,&file->zr[1]);
MPI_Bcast(&file->zr[1],file->nr,MPI_DOUBLE,0,world);
if (me == 0) grab(fptr,file->nr,&file->rhor[1]);
MPI_Bcast(&file->rhor[1],file->nr,MPI_DOUBLE,0,world);
if (me == 0) fclose(fptr);
}
/* ----------------------------------------------------------------------
convert read-in funcfl potential(s) to standard array format
interpolate all file values to a single grid and cutoff
------------------------------------------------------------------------- */
void PairEAM::file2array()
{
int i,j,k,m,n;
int ntypes = atom->ntypes;
double sixth = 1.0/6.0;
// determine max function params from all active funcfl files
// active means some element is pointing at it via map
int active;
double rmax;
dr = drho = rmax = rhomax = 0.0;
for (int i = 0; i < nfuncfl; i++) {
active = 0;
for (j = 1; j <= ntypes; j++)
if (map[j] == i) active = 1;
if (active == 0) continue;
Funcfl *file = &funcfl[i];
dr = MAX(dr,file->dr);
drho = MAX(drho,file->drho);
rmax = MAX(rmax,(file->nr-1) * file->dr);
rhomax = MAX(rhomax,(file->nrho-1) * file->drho);
}
// set nr,nrho from cutoff and spacings
// 0.5 is for round-off in divide
nr = static_cast<int> (rmax/dr + 0.5);
nrho = static_cast<int> (rhomax/drho + 0.5);
// ------------------------------------------------------------------
// setup frho arrays
// ------------------------------------------------------------------
// allocate frho arrays
// nfrho = # of funcfl files + 1 for zero array
nfrho = nfuncfl + 1;
memory->destroy(frho);
memory->create(frho,nfrho,nrho+1,"pair:frho");
// interpolate each file's frho to a single grid and cutoff
double r,p,cof1,cof2,cof3,cof4;
n = 0;
for (i = 0; i < nfuncfl; i++) {
Funcfl *file = &funcfl[i];
for (m = 1; m <= nrho; m++) {
r = (m-1)*drho;
p = r/file->drho + 1.0;
k = static_cast<int> (p);
k = MIN(k,file->nrho-2);
k = MAX(k,2);
p -= k;
p = MIN(p,2.0);
cof1 = -sixth*p*(p-1.0)*(p-2.0);
cof2 = 0.5*(p*p-1.0)*(p-2.0);
cof3 = -0.5*p*(p+1.0)*(p-2.0);
cof4 = sixth*p*(p*p-1.0);
frho[n][m] = cof1*file->frho[k-1] + cof2*file->frho[k] +
cof3*file->frho[k+1] + cof4*file->frho[k+2];
}
n++;
}
// add extra frho of zeroes for non-EAM types to point to (pair hybrid)
// this is necessary b/c fp is still computed for non-EAM atoms
for (m = 1; m <= nrho; m++) frho[nfrho-1][m] = 0.0;
// type2frho[i] = which frho array (0 to nfrho-1) each atom type maps to
// if atom type doesn't point to file (non-EAM atom in pair hybrid)
// then map it to last frho array of zeroes
for (i = 1; i <= ntypes; i++)
if (map[i] >= 0) type2frho[i] = map[i];
else type2frho[i] = nfrho-1;
// ------------------------------------------------------------------
// setup rhor arrays
// ------------------------------------------------------------------
// allocate rhor arrays
// nrhor = # of funcfl files
nrhor = nfuncfl;
memory->destroy(rhor);
memory->create(rhor,nrhor,nr+1,"pair:rhor");
// interpolate each file's rhor to a single grid and cutoff
n = 0;
for (i = 0; i < nfuncfl; i++) {
Funcfl *file = &funcfl[i];
for (m = 1; m <= nr; m++) {
r = (m-1)*dr;
p = r/file->dr + 1.0;
k = static_cast<int> (p);
k = MIN(k,file->nr-2);
k = MAX(k,2);
p -= k;
p = MIN(p,2.0);
cof1 = -sixth*p*(p-1.0)*(p-2.0);
cof2 = 0.5*(p*p-1.0)*(p-2.0);
cof3 = -0.5*p*(p+1.0)*(p-2.0);
cof4 = sixth*p*(p*p-1.0);
rhor[n][m] = cof1*file->rhor[k-1] + cof2*file->rhor[k] +
cof3*file->rhor[k+1] + cof4*file->rhor[k+2];
}
n++;
}
// type2rhor[i][j] = which rhor array (0 to nrhor-1) each type pair maps to
// for funcfl files, I,J mapping only depends on I
// OK if map = -1 (non-EAM atom in pair hybrid) b/c type2rhor not used
for (i = 1; i <= ntypes; i++)
for (j = 1; j <= ntypes; j++)
type2rhor[i][j] = map[i];
// ------------------------------------------------------------------
// setup z2r arrays
// ------------------------------------------------------------------
// allocate z2r arrays
// nz2r = N*(N+1)/2 where N = # of funcfl files
nz2r = nfuncfl*(nfuncfl+1)/2;
memory->destroy(z2r);
memory->create(z2r,nz2r,nr+1,"pair:z2r");
// create a z2r array for each file against other files, only for I >= J
// interpolate zri and zrj to a single grid and cutoff
double zri,zrj;
n = 0;
for (i = 0; i < nfuncfl; i++) {
Funcfl *ifile = &funcfl[i];
for (j = 0; j <= i; j++) {
Funcfl *jfile = &funcfl[j];
for (m = 1; m <= nr; m++) {
r = (m-1)*dr;
p = r/ifile->dr + 1.0;
k = static_cast<int> (p);
k = MIN(k,ifile->nr-2);
k = MAX(k,2);
p -= k;
p = MIN(p,2.0);
cof1 = -sixth*p*(p-1.0)*(p-2.0);
cof2 = 0.5*(p*p-1.0)*(p-2.0);
cof3 = -0.5*p*(p+1.0)*(p-2.0);
cof4 = sixth*p*(p*p-1.0);
zri = cof1*ifile->zr[k-1] + cof2*ifile->zr[k] +
cof3*ifile->zr[k+1] + cof4*ifile->zr[k+2];
p = r/jfile->dr + 1.0;
k = static_cast<int> (p);
k = MIN(k,jfile->nr-2);
k = MAX(k,2);
p -= k;
p = MIN(p,2.0);
cof1 = -sixth*p*(p-1.0)*(p-2.0);
cof2 = 0.5*(p*p-1.0)*(p-2.0);
cof3 = -0.5*p*(p+1.0)*(p-2.0);
cof4 = sixth*p*(p*p-1.0);
zrj = cof1*jfile->zr[k-1] + cof2*jfile->zr[k] +
cof3*jfile->zr[k+1] + cof4*jfile->zr[k+2];
z2r[n][m] = 27.2*0.529 * zri*zrj;
}
n++;
}
}
// type2z2r[i][j] = which z2r array (0 to nz2r-1) each type pair maps to
// set of z2r arrays only fill lower triangular Nelement matrix
// value = n = sum over rows of lower-triangular matrix until reach irow,icol
// swap indices when irow < icol to stay lower triangular
// if map = -1 (non-EAM atom in pair hybrid):
// type2z2r is not used by non-opt
// but set type2z2r to 0 since accessed by opt
int irow,icol;
for (i = 1; i <= ntypes; i++) {
for (j = 1; j <= ntypes; j++) {
irow = map[i];
icol = map[j];
if (irow == -1 || icol == -1) {
type2z2r[i][j] = 0;
continue;
}
if (irow < icol) {
irow = map[j];
icol = map[i];
}
n = 0;
for (m = 0; m < irow; m++) n += m + 1;
n += icol;
type2z2r[i][j] = n;
}
}
}
/* ---------------------------------------------------------------------- */
void PairEAM::array2spline()
{
rdr = 1.0/dr;
rdrho = 1.0/drho;
memory->destroy(frho_spline);
memory->destroy(rhor_spline);
memory->destroy(z2r_spline);
memory->create(frho_spline,nfrho,nrho+1,7,"pair:frho");
memory->create(rhor_spline,nrhor,nr+1,7,"pair:rhor");
memory->create(z2r_spline,nz2r,nr+1,7,"pair:z2r");
for (int i = 0; i < nfrho; i++)
interpolate(nrho,drho,frho[i],frho_spline[i]);
for (int i = 0; i < nrhor; i++)
interpolate(nr,dr,rhor[i],rhor_spline[i]);
for (int i = 0; i < nz2r; i++)
interpolate(nr,dr,z2r[i],z2r_spline[i]);
}
/* ---------------------------------------------------------------------- */
void PairEAM::interpolate(int n, double delta, double *f, double **spline)
{
for (int m = 1; m <= n; m++) spline[m][6] = f[m];
spline[1][5] = spline[2][6] - spline[1][6];
spline[2][5] = 0.5 * (spline[3][6]-spline[1][6]);
spline[n-1][5] = 0.5 * (spline[n][6]-spline[n-2][6]);
spline[n][5] = spline[n][6] - spline[n-1][6];
for (int m = 3; m <= n-2; m++)
spline[m][5] = ((spline[m-2][6]-spline[m+2][6]) +
8.0*(spline[m+1][6]-spline[m-1][6])) / 12.0;
for (int m = 1; m <= n-1; m++) {
spline[m][4] = 3.0*(spline[m+1][6]-spline[m][6]) -
2.0*spline[m][5] - spline[m+1][5];
spline[m][3] = spline[m][5] + spline[m+1][5] -
2.0*(spline[m+1][6]-spline[m][6]);
}
spline[n][4] = 0.0;
spline[n][3] = 0.0;
for (int m = 1; m <= n; m++) {
spline[m][2] = spline[m][5]/delta;
spline[m][1] = 2.0*spline[m][4]/delta;
spline[m][0] = 3.0*spline[m][3]/delta;
}
}
/* ----------------------------------------------------------------------
grab n values from file fp and put them in list
values can be several to a line
only called by proc 0
------------------------------------------------------------------------- */
void PairEAM::grab(FILE *fptr, int n, double *list)
{
char *ptr;
char line[MAXLINE];
int i = 0;
while (i < n) {
fgets(line,MAXLINE,fptr);
ptr = strtok(line," \t\n\r\f");
list[i++] = atof(ptr);
while ((ptr = strtok(NULL," \t\n\r\f"))) list[i++] = atof(ptr);
}
}
/* ---------------------------------------------------------------------- */
double PairEAM::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
int m;
double r,p,rhoip,rhojp,z2,z2p,recip,phi,phip,psip;
double *coeff;
r = sqrt(rsq);
p = r*rdr + 1.0;
m = static_cast<int> (p);
m = MIN(m,nr-1);
p -= m;
p = MIN(p,1.0);
coeff = rhor_spline[type2rhor[itype][jtype]][m];
rhoip = (coeff[0]*p + coeff[1])*p + coeff[2];
coeff = rhor_spline[type2rhor[jtype][itype]][m];
rhojp = (coeff[0]*p + coeff[1])*p + coeff[2];
coeff = z2r_spline[type2z2r[itype][jtype]][m];
z2p = (coeff[0]*p + coeff[1])*p + coeff[2];
z2 = ((coeff[3]*p + coeff[4])*p + coeff[5])*p + coeff[6];
recip = 1.0/r;
phi = z2*recip;
phip = z2p*recip - phi*recip;
psip = fp[i]*rhojp + fp[j]*rhoip + phip;
fforce = -psip*recip;
return phi;
}
/* ---------------------------------------------------------------------- */
int PairEAM::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = fp[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void PairEAM::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) fp[i] = buf[m++];
}
/* ---------------------------------------------------------------------- */
int PairEAM::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) buf[m++] = rho[i];
return m;
}
/* ---------------------------------------------------------------------- */
void PairEAM::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
rho[j] += buf[m++];
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairEAM::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
swap fp array with one passed in by caller
------------------------------------------------------------------------- */
void PairEAM::swap_eam(double *fp_caller, double **fp_caller_hold)
{
double *tmp = fp;
fp = fp_caller;
*fp_caller_hold = tmp;
}
/* ---------------------------------------------------------------------- */
void *PairEAM::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"scale") == 0) return (void *) scale;
return NULL;
}
diff --git a/src/MANYBODY/pair_eam_alloy.cpp b/src/MANYBODY/pair_eam_alloy.cpp
index d3ed404a0..e22b4642a 100644
--- a/src/MANYBODY/pair_eam_alloy.cpp
+++ b/src/MANYBODY/pair_eam_alloy.cpp
@@ -1,327 +1,331 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Stephen Foiles (SNL), Murray Daw (SNL)
------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_eam_alloy.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
/* ---------------------------------------------------------------------- */
PairEAMAlloy::PairEAMAlloy(LAMMPS *lmp) : PairEAM(lmp)
{
one_coeff = 1;
manybody_flag = 1;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
read DYNAMO setfl file
------------------------------------------------------------------------- */
void PairEAMAlloy::coeff(int narg, char **arg)
{
int i,j;
if (!allocated) allocate();
if (narg != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// insure I,J args are * *
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read EAM setfl file
if (setfl) {
for (i = 0; i < setfl->nelements; i++) delete [] setfl->elements[i];
delete [] setfl->elements;
delete [] setfl->mass;
memory->destroy(setfl->frho);
memory->destroy(setfl->rhor);
memory->destroy(setfl->z2r);
delete setfl;
}
setfl = new Setfl();
read_file(arg[2]);
// read args that map atom types to elements in potential file
// map[i] = which element the Ith atom type is, -1 if NULL
for (i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
}
for (j = 0; j < setfl->nelements; j++)
if (strcmp(arg[i],setfl->elements[j]) == 0) break;
if (j < setfl->nelements) map[i-2] = j;
else error->all(FLERR,"No matching element in EAM potential file");
}
// clear setflag since coeff() called once with I,J = * *
int n = atom->ntypes;
for (i = 1; i <= n; i++)
for (j = i; j <= n; j++)
setflag[i][j] = 0;
// set setflag i,j for type pairs where both are mapped to elements
// set mass of atom type if i = j
int count = 0;
for (i = 1; i <= n; i++) {
for (j = i; j <= n; j++) {
if (map[i] >= 0 && map[j] >= 0) {
setflag[i][j] = 1;
if (i == j) atom->set_mass(FLERR,i,setfl->mass[map[i]]);
count++;
}
scale[i][j] = 1.0;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
read a multi-element DYNAMO setfl file
------------------------------------------------------------------------- */
void PairEAMAlloy::read_file(char *filename)
{
Setfl *file = setfl;
// open potential file
int me = comm->me;
FILE *fptr;
char line[MAXLINE];
if (me == 0) {
fptr = force->open_potential(filename);
if (fptr == NULL) {
char str[128];
sprintf(str,"Cannot open EAM potential file %s",filename);
error->one(FLERR,str);
}
}
// read and broadcast header
// extract element names from nelements line
int n;
if (me == 0) {
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
n = strlen(line) + 1;
}
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
sscanf(line,"%d",&file->nelements);
int nwords = atom->count_words(line);
if (nwords != file->nelements + 1)
error->all(FLERR,"Incorrect element names in EAM potential file");
char **words = new char*[file->nelements+1];
nwords = 0;
strtok(line," \t\n\r\f");
while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
file->elements = new char*[file->nelements];
for (int i = 0; i < file->nelements; i++) {
n = strlen(words[i]) + 1;
file->elements[i] = new char[n];
strcpy(file->elements[i],words[i]);
}
delete [] words;
if (me == 0) {
fgets(line,MAXLINE,fptr);
- sscanf(line,"%d %lg %d %lg %lg",
+ nwords = sscanf(line,"%d %lg %d %lg %lg",
&file->nrho,&file->drho,&file->nr,&file->dr,&file->cut);
}
+ MPI_Bcast(&nwords,1,MPI_INT,0,world);
MPI_Bcast(&file->nrho,1,MPI_INT,0,world);
MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->nr,1,MPI_INT,0,world);
MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world);
+ if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0))
+ error->all(FLERR,"Invalid EAM potential file");
+
file->mass = new double[file->nelements];
memory->create(file->frho,file->nelements,file->nrho+1,"pair:frho");
memory->create(file->rhor,file->nelements,file->nr+1,"pair:rhor");
memory->create(file->z2r,file->nelements,file->nelements,file->nr+1,
"pair:z2r");
int i,j,tmp;
for (i = 0; i < file->nelements; i++) {
if (me == 0) {
fgets(line,MAXLINE,fptr);
sscanf(line,"%d %lg",&tmp,&file->mass[i]);
}
MPI_Bcast(&file->mass[i],1,MPI_DOUBLE,0,world);
if (me == 0) grab(fptr,file->nrho,&file->frho[i][1]);
MPI_Bcast(&file->frho[i][1],file->nrho,MPI_DOUBLE,0,world);
if (me == 0) grab(fptr,file->nr,&file->rhor[i][1]);
MPI_Bcast(&file->rhor[i][1],file->nr,MPI_DOUBLE,0,world);
}
for (i = 0; i < file->nelements; i++)
for (j = 0; j <= i; j++) {
if (me == 0) grab(fptr,file->nr,&file->z2r[i][j][1]);
MPI_Bcast(&file->z2r[i][j][1],file->nr,MPI_DOUBLE,0,world);
}
// close the potential file
if (me == 0) fclose(fptr);
}
/* ----------------------------------------------------------------------
copy read-in setfl potential to standard array format
------------------------------------------------------------------------- */
void PairEAMAlloy::file2array()
{
int i,j,m,n;
int ntypes = atom->ntypes;
// set function params directly from setfl file
nrho = setfl->nrho;
nr = setfl->nr;
drho = setfl->drho;
dr = setfl->dr;
rhomax = (nrho-1) * drho;
// ------------------------------------------------------------------
// setup frho arrays
// ------------------------------------------------------------------
// allocate frho arrays
// nfrho = # of setfl elements + 1 for zero array
nfrho = setfl->nelements + 1;
memory->destroy(frho);
memory->create(frho,nfrho,nrho+1,"pair:frho");
// copy each element's frho to global frho
for (i = 0; i < setfl->nelements; i++)
for (m = 1; m <= nrho; m++) frho[i][m] = setfl->frho[i][m];
// add extra frho of zeroes for non-EAM types to point to (pair hybrid)
// this is necessary b/c fp is still computed for non-EAM atoms
for (m = 1; m <= nrho; m++) frho[nfrho-1][m] = 0.0;
// type2frho[i] = which frho array (0 to nfrho-1) each atom type maps to
// if atom type doesn't point to element (non-EAM atom in pair hybrid)
// then map it to last frho array of zeroes
for (i = 1; i <= ntypes; i++)
if (map[i] >= 0) type2frho[i] = map[i];
else type2frho[i] = nfrho-1;
// ------------------------------------------------------------------
// setup rhor arrays
// ------------------------------------------------------------------
// allocate rhor arrays
// nrhor = # of setfl elements
nrhor = setfl->nelements;
memory->destroy(rhor);
memory->create(rhor,nrhor,nr+1,"pair:rhor");
// copy each element's rhor to global rhor
for (i = 0; i < setfl->nelements; i++)
for (m = 1; m <= nr; m++) rhor[i][m] = setfl->rhor[i][m];
// type2rhor[i][j] = which rhor array (0 to nrhor-1) each type pair maps to
// for setfl files, I,J mapping only depends on I
// OK if map = -1 (non-EAM atom in pair hybrid) b/c type2rhor not used
for (i = 1; i <= ntypes; i++)
for (j = 1; j <= ntypes; j++)
type2rhor[i][j] = map[i];
// ------------------------------------------------------------------
// setup z2r arrays
// ------------------------------------------------------------------
// allocate z2r arrays
// nz2r = N*(N+1)/2 where N = # of setfl elements
nz2r = setfl->nelements * (setfl->nelements+1) / 2;
memory->destroy(z2r);
memory->create(z2r,nz2r,nr+1,"pair:z2r");
// copy each element pair z2r to global z2r, only for I >= J
n = 0;
for (i = 0; i < setfl->nelements; i++)
for (j = 0; j <= i; j++) {
for (m = 1; m <= nr; m++) z2r[n][m] = setfl->z2r[i][j][m];
n++;
}
// type2z2r[i][j] = which z2r array (0 to nz2r-1) each type pair maps to
// set of z2r arrays only fill lower triangular Nelement matrix
// value = n = sum over rows of lower-triangular matrix until reach irow,icol
// swap indices when irow < icol to stay lower triangular
// if map = -1 (non-EAM atom in pair hybrid):
// type2z2r is not used by non-opt
// but set type2z2r to 0 since accessed by opt
int irow,icol;
for (i = 1; i <= ntypes; i++) {
for (j = 1; j <= ntypes; j++) {
irow = map[i];
icol = map[j];
if (irow == -1 || icol == -1) {
type2z2r[i][j] = 0;
continue;
}
if (irow < icol) {
irow = map[j];
icol = map[i];
}
n = 0;
for (m = 0; m < irow; m++) n += m + 1;
n += icol;
type2z2r[i][j] = n;
}
}
}
diff --git a/src/MANYBODY/pair_eam_fs.cpp b/src/MANYBODY/pair_eam_fs.cpp
index f0f1814dc..2817e13f8 100644
--- a/src/MANYBODY/pair_eam_fs.cpp
+++ b/src/MANYBODY/pair_eam_fs.cpp
@@ -1,336 +1,340 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Tim Lau (MIT)
------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_eam_fs.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
/* ---------------------------------------------------------------------- */
PairEAMFS::PairEAMFS(LAMMPS *lmp) : PairEAM(lmp)
{
one_coeff = 1;
manybody_flag = 1;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
read EAM Finnis-Sinclair file
------------------------------------------------------------------------- */
void PairEAMFS::coeff(int narg, char **arg)
{
int i,j;
if (!allocated) allocate();
if (narg != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// insure I,J args are * *
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read EAM Finnis-Sinclair file
if (fs) {
for (i = 0; i < fs->nelements; i++) delete [] fs->elements[i];
delete [] fs->elements;
delete [] fs->mass;
memory->destroy(fs->frho);
memory->destroy(fs->rhor);
memory->destroy(fs->z2r);
delete fs;
}
fs = new Fs();
read_file(arg[2]);
// read args that map atom types to elements in potential file
// map[i] = which element the Ith atom type is, -1 if NULL
for (i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
}
for (j = 0; j < fs->nelements; j++)
if (strcmp(arg[i],fs->elements[j]) == 0) break;
if (j < fs->nelements) map[i-2] = j;
else error->all(FLERR,"No matching element in EAM potential file");
}
// clear setflag since coeff() called once with I,J = * *
int n = atom->ntypes;
for (i = 1; i <= n; i++)
for (j = i; j <= n; j++)
setflag[i][j] = 0;
// set setflag i,j for type pairs where both are mapped to elements
// set mass of atom type if i = j
int count = 0;
for (i = 1; i <= n; i++) {
for (j = i; j <= n; j++) {
if (map[i] >= 0 && map[j] >= 0) {
setflag[i][j] = 1;
if (i == j) atom->set_mass(FLERR,i,fs->mass[map[i]]);
count++;
}
scale[i][j] = 1.0;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
read a multi-element DYNAMO setfl file
------------------------------------------------------------------------- */
void PairEAMFS::read_file(char *filename)
{
Fs *file = fs;
// open potential file
int me = comm->me;
FILE *fptr;
char line[MAXLINE];
if (me == 0) {
fptr = force->open_potential(filename);
if (fptr == NULL) {
char str[128];
sprintf(str,"Cannot open EAM potential file %s",filename);
error->one(FLERR,str);
}
}
// read and broadcast header
// extract element names from nelements line
int n;
if (me == 0) {
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
fgets(line,MAXLINE,fptr);
n = strlen(line) + 1;
}
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
sscanf(line,"%d",&file->nelements);
int nwords = atom->count_words(line);
if (nwords != file->nelements + 1)
error->all(FLERR,"Incorrect element names in EAM potential file");
char **words = new char*[file->nelements+1];
nwords = 0;
strtok(line," \t\n\r\f");
while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
file->elements = new char*[file->nelements];
for (int i = 0; i < file->nelements; i++) {
n = strlen(words[i]) + 1;
file->elements[i] = new char[n];
strcpy(file->elements[i],words[i]);
}
delete [] words;
if (me == 0) {
fgets(line,MAXLINE,fptr);
- sscanf(line,"%d %lg %d %lg %lg",
+ nwords = sscanf(line,"%d %lg %d %lg %lg",
&file->nrho,&file->drho,&file->nr,&file->dr,&file->cut);
}
+ MPI_Bcast(&nwords,1,MPI_INT,0,world);
MPI_Bcast(&file->nrho,1,MPI_INT,0,world);
MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->nr,1,MPI_INT,0,world);
MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world);
MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world);
+ if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0))
+ error->all(FLERR,"Invalid EAM potential file");
+
file->mass = new double[file->nelements];
memory->create(file->frho,file->nelements,file->nrho+1,
"pair:frho");
memory->create(file->rhor,file->nelements,file->nelements,
file->nr+1,"pair:rhor");
memory->create(file->z2r,file->nelements,file->nelements,
file->nr+1,"pair:z2r");
int i,j,tmp;
for (i = 0; i < file->nelements; i++) {
if (me == 0) {
fgets(line,MAXLINE,fptr);
sscanf(line,"%d %lg",&tmp,&file->mass[i]);
}
MPI_Bcast(&file->mass[i],1,MPI_DOUBLE,0,world);
if (me == 0) grab(fptr,file->nrho,&file->frho[i][1]);
MPI_Bcast(&file->frho[i][1],file->nrho,MPI_DOUBLE,0,world);
for (j = 0; j < file->nelements; j++) {
if (me == 0) grab(fptr,file->nr,&file->rhor[i][j][1]);
MPI_Bcast(&file->rhor[i][j][1],file->nr,MPI_DOUBLE,0,world);
}
}
for (i = 0; i < file->nelements; i++)
for (j = 0; j <= i; j++) {
if (me == 0) grab(fptr,file->nr,&file->z2r[i][j][1]);
MPI_Bcast(&file->z2r[i][j][1],file->nr,MPI_DOUBLE,0,world);
}
// close the potential file
if (me == 0) fclose(fptr);
}
/* ----------------------------------------------------------------------
copy read-in setfl potential to standard array format
------------------------------------------------------------------------- */
void PairEAMFS::file2array()
{
int i,j,m,n;
int ntypes = atom->ntypes;
// set function params directly from fs file
nrho = fs->nrho;
nr = fs->nr;
drho = fs->drho;
dr = fs->dr;
rhomax = (nrho-1) * drho;
// ------------------------------------------------------------------
// setup frho arrays
// ------------------------------------------------------------------
// allocate frho arrays
// nfrho = # of fs elements + 1 for zero array
nfrho = fs->nelements + 1;
memory->destroy(frho);
memory->create(frho,nfrho,nrho+1,"pair:frho");
// copy each element's frho to global frho
for (i = 0; i < fs->nelements; i++)
for (m = 1; m <= nrho; m++) frho[i][m] = fs->frho[i][m];
// add extra frho of zeroes for non-EAM types to point to (pair hybrid)
// this is necessary b/c fp is still computed for non-EAM atoms
for (m = 1; m <= nrho; m++) frho[nfrho-1][m] = 0.0;
// type2frho[i] = which frho array (0 to nfrho-1) each atom type maps to
// if atom type doesn't point to element (non-EAM atom in pair hybrid)
// then map it to last frho array of zeroes
for (i = 1; i <= ntypes; i++)
if (map[i] >= 0) type2frho[i] = map[i];
else type2frho[i] = nfrho-1;
// ------------------------------------------------------------------
// setup rhor arrays
// ------------------------------------------------------------------
// allocate rhor arrays
// nrhor = square of # of fs elements
nrhor = fs->nelements * fs->nelements;
memory->destroy(rhor);
memory->create(rhor,nrhor,nr+1,"pair:rhor");
// copy each element pair rhor to global rhor
n = 0;
for (i = 0; i < fs->nelements; i++)
for (j = 0; j < fs->nelements; j++) {
for (m = 1; m <= nr; m++) rhor[n][m] = fs->rhor[i][j][m];
n++;
}
// type2rhor[i][j] = which rhor array (0 to nrhor-1) each type pair maps to
// for fs files, there is a full NxN set of rhor arrays
// OK if map = -1 (non-EAM atom in pair hybrid) b/c type2rhor not used
for (i = 1; i <= ntypes; i++)
for (j = 1; j <= ntypes; j++)
type2rhor[i][j] = map[i] * fs->nelements + map[j];
// ------------------------------------------------------------------
// setup z2r arrays
// ------------------------------------------------------------------
// allocate z2r arrays
// nz2r = N*(N+1)/2 where N = # of fs elements
nz2r = fs->nelements * (fs->nelements+1) / 2;
memory->destroy(z2r);
memory->create(z2r,nz2r,nr+1,"pair:z2r");
// copy each element pair z2r to global z2r, only for I >= J
n = 0;
for (i = 0; i < fs->nelements; i++)
for (j = 0; j <= i; j++) {
for (m = 1; m <= nr; m++) z2r[n][m] = fs->z2r[i][j][m];
n++;
}
// type2z2r[i][j] = which z2r array (0 to nz2r-1) each type pair maps to
// set of z2r arrays only fill lower triangular Nelement matrix
// value = n = sum over rows of lower-triangular matrix until reach irow,icol
// swap indices when irow < icol to stay lower triangular
// if map = -1 (non-EAM atom in pair hybrid):
// type2z2r is not used by non-opt
// but set type2z2r to 0 since accessed by opt
int irow,icol;
for (i = 1; i <= ntypes; i++) {
for (j = 1; j <= ntypes; j++) {
irow = map[i];
icol = map[j];
if (irow == -1 || icol == -1) {
type2z2r[i][j] = 0;
continue;
}
if (irow < icol) {
irow = map[j];
icol = map[i];
}
n = 0;
for (m = 0; m < irow; m++) n += m + 1;
n += icol;
type2z2r[i][j] = n;
}
}
}
diff --git a/src/MISC/pair_nm_cut.cpp b/src/MISC/pair_nm_cut.cpp
index 0163cdcf5..b9bf6ac47 100644
--- a/src/MISC/pair_nm_cut.cpp
+++ b/src/MISC/pair_nm_cut.cpp
@@ -1,433 +1,433 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing Author: Julien Devemy (ICCF)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_nm_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairNMCut::PairNMCut(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairNMCut::~PairNMCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(e0);
memory->destroy(r0);
memory->destroy(nn);
memory->destroy(mm);
memory->destroy(nm);
memory->destroy(e0nm);
memory->destroy(r0n);
memory->destroy(r0m);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairNMCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,factor_lj;
double r,forcenm,rminv,rninv;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r = sqrt(rsq);
rminv = pow(r2inv,mm[itype][jtype]/2.0);
rninv = pow(r2inv,nn[itype][jtype]/2.0);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
fpair = factor_lj*forcenm*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = e0nm[itype][jtype] *
(mm[itype][jtype]*r0n[itype][jtype]*rninv -
nn[itype][jtype]*r0m[itype][jtype]*rminv) - offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairNMCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(e0,n+1,n+1,"pair:e0");
memory->create(r0,n+1,n+1,"pair:r0");
memory->create(nn,n+1,n+1,"pair:nn");
memory->create(mm,n+1,n+1,"pair:mm");
memory->create(nm,n+1,n+1,"pair:nm");
memory->create(e0nm,n+1,n+1,"pair:e0nm");
memory->create(r0n,n+1,n+1,"pair:r0n");
memory->create(r0m,n+1,n+1,"pair:r0m");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairNMCut::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairNMCut::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double e0_one = force->numeric(FLERR,arg[2]);
double r0_one = force->numeric(FLERR,arg[3]);
double nn_one = force->numeric(FLERR,arg[4]);
double mm_one = force->numeric(FLERR,arg[5]);
double cut_one = cut_global;
if (narg == 7) cut_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
e0[i][j] = e0_one;
r0[i][j] = r0_one;
nn[i][j] = nn_one;
mm[i][j] = mm_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairNMCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
nm[i][j] = nn[i][j]*mm[i][j];
e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]);
r0n[i][j] = pow(r0[i][j],nn[i][j]);
r0m[i][j] = pow(r0[i][j],mm[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
offset[i][j] = e0nm[i][j] *
((mm[i][j]*r0n[i][j] / pow(cut[i][j],nn[i][j])) -
(nn[i][j]*r0m[i][j] / pow(cut[i][j],mm[i][j])));
} else offset[i][j] = 0.0;
e0[j][i] = e0[i][j];
nn[j][i] = nn[i][j];
mm[j][i] = mm[i][j];
nm[j][i] = nm[i][j];
r0[j][i] = r0[i][j];
e0nm[j][i] = e0nm[i][j];
r0n[j][i] = r0n[i][j];
r0m[j][i] = r0m[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]);
double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]);
double p1 = 1-nn[i][j];
double p2 = 1-mm[i][j];
double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]);
double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]);
etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] *
(rr1*pow(cut[i][j],p1)-rr2*pow(cut[i][j],p2));
ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] *
nn[i][j]*mm[i][j]*(rrr1*pow(cut[i][j],p1)-rrr2*pow(cut[i][j],p2));
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&e0[i][j],sizeof(double),1,fp);
fwrite(&r0[i][j],sizeof(double),1,fp);
fwrite(&nn[i][j],sizeof(double),1,fp);
fwrite(&mm[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&e0[i][j],sizeof(double),1,fp);
fread(&r0[i][j],sizeof(double),1,fp);
fread(&nn[i][j],sizeof(double),1,fp);
fread(&mm[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&mm[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairNMCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairNMCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,
e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairNMCut::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,forcenm,phinm;
r2inv = 1.0/rsq;
r = sqrt(rsq);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
fforce = factor_lj*forcenm*r2inv;
phinm = e0nm[itype][jtype] *
(mm[itype][jtype] * r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
nn[itype][jtype]*r0m[itype][jtype] /pow(r,mm[itype][jtype])) -
offset[itype][jtype];
return factor_lj*phinm;
}
/* ---------------------------------------------------------------------- */
void *PairNMCut::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"e0") == 0) return (void *) e0;
if (strcmp(str,"r0") == 0) return (void *) r0;
if (strcmp(str,"nn") == 0) return (void *) nn;
if (strcmp(str,"mm") == 0) return (void *) mm;
return NULL;
}
diff --git a/src/MISC/pair_nm_cut_coul_cut.cpp b/src/MISC/pair_nm_cut_coul_cut.cpp
index 5cb245290..78c77a648 100644
--- a/src/MISC/pair_nm_cut_coul_cut.cpp
+++ b/src/MISC/pair_nm_cut_coul_cut.cpp
@@ -1,506 +1,506 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing Author: Julien Devemy (ICCF)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_nm_cut_coul_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairNMCutCoulCut::PairNMCutCoulCut(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairNMCutCoulCut::~PairNMCutCoulCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(e0);
memory->destroy(r0);
memory->destroy(nn);
memory->destroy(mm);
memory->destroy(nm);
memory->destroy(e0nm);
memory->destroy(r0n);
memory->destroy(r0m);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairNMCutCoulCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,r2inv,factor_coul,factor_lj;
double r,forcecoul,forcenm,rminv,rninv;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
rminv = pow(r2inv,mm[itype][jtype]/2.0);
rninv = pow(r2inv,nn[itype][jtype]/2.0);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
} else forcenm = 0.0;
fpair = (factor_coul*forcecoul + factor_lj*forcenm) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype])
ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv);
else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = e0nm[itype][jtype]*(mm[itype][jtype] *
r0n[itype][jtype]*rninv -
nn[itype][jtype] *
r0m[itype][jtype]*rminv) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairNMCutCoulCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(e0,n+1,n+1,"pair:e0");
memory->create(r0,n+1,n+1,"pair:r0");
memory->create(nn,n+1,n+1,"pair:nn");
memory->create(mm,n+1,n+1,"pair:mm");
memory->create(nm,n+1,n+1,"pair:nm");
memory->create(e0nm,n+1,n+1,"pair:e0nm");
memory->create(r0n,n+1,n+1,"pair:r0n");
memory->create(r0m,n+1,n+1,"pair:r0m");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairNMCutCoulCut::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairNMCutCoulCut::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 8)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double e0_one = force->numeric(FLERR,arg[2]);
double r0_one = force->numeric(FLERR,arg[3]);
double nn_one = force->numeric(FLERR,arg[4]);
double mm_one = force->numeric(FLERR,arg[5]);
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 7) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]);
if (narg == 8) cut_coul_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
e0[i][j] = e0_one;
r0[i][j] = r0_one;
nn[i][j] = nn_one;
mm[i][j] = mm_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairNMCutCoulCut::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style nm/cut/coul/cut requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairNMCutCoulCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
nm[i][j] = nn[i][j]*mm[i][j];
e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]);
r0n[i][j] = pow(r0[i][j],nn[i][j]);
r0m[i][j] = pow(r0[i][j],mm[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
offset[i][j] = e0nm[i][j] *
((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) -
(nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j])));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
e0[j][i] = e0[i][j];
nn[j][i] = nn[i][j];
mm[j][i] = mm[i][j];
nm[j][i] = nm[i][j];
r0[j][i] = r0[i][j];
e0nm[j][i] = e0nm[i][j];
r0n[j][i] = r0n[i][j];
r0m[j][i] = r0m[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]);
double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]);
double p1 = 1-nn[i][j];
double p2 = 1-mm[i][j];
double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]);
double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]);
etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] *
(rr1*pow(cut_lj[i][j],p1)-rr2*pow(cut_lj[i][j],p2));
ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] *
nn[i][j]*mm[i][j]*(rrr1*pow(cut_lj[i][j],p1)-rrr2*pow(cut_lj[i][j],p2));
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCutCoulCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&e0[i][j],sizeof(double),1,fp);
fwrite(&r0[i][j],sizeof(double),1,fp);
fwrite(&nn[i][j],sizeof(double),1,fp);
fwrite(&mm[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCutCoulCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&e0[i][j],sizeof(double),1,fp);
fread(&r0[i][j],sizeof(double),1,fp);
fread(&nn[i][j],sizeof(double),1,fp);
fread(&mm[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&mm[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCutCoulCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCutCoulCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairNMCutCoulCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairNMCutCoulCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,
e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairNMCutCoulCut::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,forcecoul,forcenm,phicoul,phinm;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
} else forcenm = 0.0;
fforce = (factor_coul*forcecoul + factor_lj*forcenm) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
eng += factor_coul*phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phinm = e0nm[itype][jtype] *
(mm[itype][jtype]*r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
nn[itype][jtype]*r0m[itype][jtype]/pow(r,mm[itype][jtype])) -
offset[itype][jtype];
eng += factor_lj*phinm;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairNMCutCoulCut::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"e0") == 0) return (void *) e0;
if (strcmp(str,"r0") == 0) return (void *) r0;
if (strcmp(str,"nn") == 0) return (void *) nn;
if (strcmp(str,"mm") == 0) return (void *) mm;
return NULL;
}
diff --git a/src/MISC/pair_nm_cut_coul_long.cpp b/src/MISC/pair_nm_cut_coul_long.cpp
index 15d5d0375..8e0da40ea 100644
--- a/src/MISC/pair_nm_cut_coul_long.cpp
+++ b/src/MISC/pair_nm_cut_coul_long.cpp
@@ -1,590 +1,590 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing Author: Julien Devemy (ICCF)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_nm_cut_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairNMCutCoulLong::PairNMCutCoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
ftable = NULL;
qdist = 0.0;
}
/* ---------------------------------------------------------------------- */
PairNMCutCoulLong::~PairNMCutCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(e0);
memory->destroy(r0);
memory->destroy(nn);
memory->destroy(mm);
memory->destroy(nm);
memory->destroy(e0nm);
memory->destroy(r0n);
memory->destroy(r0m);
memory->destroy(offset);
}
if (ftable) free_tables();
}
/* ---------------------------------------------------------------------- */
void PairNMCutCoulLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double r,r2inv,factor_coul,factor_lj;
double forcecoul,forcenm,rminv,rninv;
double grij,expm2,prefactor,t,erfc;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
rminv = pow(r2inv,mm[itype][jtype]/2.0);
rninv = pow(r2inv,nn[itype][jtype]/2.0);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
} else forcenm = 0.0;
fpair = (forcecoul + factor_lj*forcenm) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qtmp*q[j] * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = e0nm[itype][jtype] *
(mm[itype][jtype]*r0n[itype][jtype]*rninv -
nn[itype][jtype]*r0m[itype][jtype]*rminv) - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairNMCutCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(e0,n+1,n+1,"pair:e0");
memory->create(r0,n+1,n+1,"pair:r0");
memory->create(nn,n+1,n+1,"pair:nn");
memory->create(mm,n+1,n+1,"pair:mm");
memory->create(nm,n+1,n+1,"pair:nm");
memory->create(e0nm,n+1,n+1,"pair:e0nm");
memory->create(r0n,n+1,n+1,"pair:r0n");
memory->create(r0m,n+1,n+1,"pair:r0m");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairNMCutCoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairNMCutCoulLong::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double e0_one = force->numeric(FLERR,arg[2]);
double r0_one = force->numeric(FLERR,arg[3]);
double nn_one = force->numeric(FLERR,arg[4]);
double mm_one = force->numeric(FLERR,arg[5]);
double cut_lj_one = cut_lj_global;
if (narg == 7) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
e0[i][j] = e0_one;
r0[i][j] = r0_one;
nn[i][j] = nn_one;
mm[i][j] = mm_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairNMCutCoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style nm/cut/coul/long requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
// setup force tables
if (ncoultablebits) init_tables(cut_coul,NULL);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairNMCutCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
nm[i][j] = nn[i][j]*mm[i][j];
e0nm[i][j] = e0[i][j]/(nn[i][j]-mm[i][j]);
r0n[i][j] = pow(r0[i][j],nn[i][j]);
r0m[i][j] = pow(r0[i][j],mm[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
offset[i][j] = e0nm[i][j] *
((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) -
(nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j])));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
e0[j][i] = e0[i][j];
nn[j][i] = nn[i][j];
mm[j][i] = mm[i][j];
nm[j][i] = nm[i][j];
r0[j][i] = r0[i][j];
e0nm[j][i] = e0nm[i][j];
r0n[j][i] = r0n[i][j];
r0m[j][i] = r0m[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rr1 = mm[i][j]*(nn[i][j]-1)*pow(r0[i][j],nn[i][j]);
double rr2 = nn[i][j]*(mm[i][j]-1)*pow(r0[i][j],mm[i][j]);
double p1 = 1-nn[i][j];
double p2 = 1-mm[i][j];
double rrr1 = pow(r0[i][j],nn[i][j])*(1-nn[i][j]);
double rrr2 = pow(r0[i][j],mm[i][j])*(1-mm[i][j]);
etail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j] *
(rr1*pow(cut_lj[i][j],p1)-rr2*pow(cut_lj[i][j],p2));
ptail_ij = 2.0*MY_PI*all[0]*all[1]*e0nm[i][j]*nn[i][j]*mm[i][j] *
(rrr1*pow(cut_lj[i][j],p1)-rrr2*pow(cut_lj[i][j],p2));
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCutCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&e0[i][j],sizeof(double),1,fp);
fwrite(&r0[i][j],sizeof(double),1,fp);
fwrite(&nn[i][j],sizeof(double),1,fp);
fwrite(&mm[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCutCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&e0[i][j],sizeof(double),1,fp);
fread(&r0[i][j],sizeof(double),1,fp);
fread(&nn[i][j],sizeof(double),1,fp);
fread(&mm[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&e0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&nn[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&mm[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairNMCutCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairNMCutCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairNMCutCoulLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,e0[i][i],r0[i][i],nn[i][i],mm[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairNMCutCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,
e0[i][j],r0[i][j],nn[i][j],mm[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairNMCutCoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forcenm,phicoul,phinm;
int itable;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup_single;
rsq_lookup_single.f = rsq;
itable = rsq_lookup_single.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r = sqrt(rsq);
forcenm = e0nm[itype][jtype]*nm[itype][jtype] *
(r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
r0m[itype][jtype]/pow(r,mm[itype][jtype]));
} else forcenm = 0.0;
fforce = (forcecoul + factor_lj*forcenm) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phinm = e0nm[itype][jtype] *
(mm[itype][jtype]*r0n[itype][jtype]/pow(r,nn[itype][jtype]) -
nn[itype][jtype]*r0m[itype][jtype]/pow(r,mm[itype][jtype])) -
offset[itype][jtype];
eng += factor_lj*phinm;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairNMCutCoulLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"e0") == 0) return (void *) e0;
if (strcmp(str,"r0") == 0) return (void *) r0;
if (strcmp(str,"nn") == 0) return (void *) nn;
if (strcmp(str,"mm") == 0) return (void *) mm;
return NULL;
}
diff --git a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
index e3093e4d1..c616a9fa8 100644
--- a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
+++ b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
@@ -1,755 +1,755 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pavel Elkind (Gothenburg University)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_tip4p_cut.h"
#include "atom.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "domain.h"
#include "angle.h"
#include "bond.h"
#include "comm.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJCutTIP4PCut::PairLJCutTIP4PCut(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
writedata = 1;
nmax = 0;
hneigh = NULL;
newsite = NULL;
// TIP4P cannot compute virial as F dot r
// due to finding bonded H atoms which are not near O atom
no_virial_fdotr_compute = 1;
}
/* ---------------------------------------------------------------------- */
PairLJCutTIP4PCut::~PairLJCutTIP4PCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
memory->destroy(hneigh);
memory->destroy(newsite);
}
/* ---------------------------------------------------------------------- */
void PairLJCutTIP4PCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double rsq,r2inv,r6inv,forcecoul,forcelj,factor_lj,factor_coul;
int *ilist,*jlist,*numneigh,**firstneigh;
int key;
int n,vlist[6];
int iH1,iH2,jH1,jH2;
double cforce;
double fO[3],fH[3],fd[3],v[6];
double *x1,*x2,*xH1,*xH2;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
// reallocate hneigh & newsite if necessary
// initialize hneigh[0] to -1 on steps when reneighboring occurred
// initialize hneigh[2] to 0 every step
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if (atom->nmax > nmax) {
nmax = atom->nmax;
memory->destroy(hneigh);
memory->create(hneigh,nmax,3,"pair:hneigh");
memory->destroy(newsite);
memory->create(newsite,nmax,3,"pair:newsite");
}
if (neighbor->ago == 0)
for (i = 0; i < nall; i++) hneigh[i][0] = -1;
for (i = 0; i < nall; i++) hneigh[i][2] = 0;
double **f = atom->f;
double **x = atom->x;
double *q = atom->q;
tagint *tag = atom->tag;
int *type = atom->type;
double *special_lj = force->special_lj;
double *special_coul = force->special_coul;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
if (itype == typeO) {
if (hneigh[i][0] < 0) {
iH1 = atom->map(tag[i] + 1);
iH2 = atom->map(tag[i] + 2);
if (iH1 == -1 || iH2 == -1)
error->one(FLERR,"TIP4P hydrogen is missing");
if (atom->type[iH1] != typeH || atom->type[iH2] != typeH)
error->one(FLERR,"TIP4P hydrogen has incorrect atom type");
// set iH1,iH2 to index of closest image to O
iH1 = domain->closest_image(i,iH1);
iH2 = domain->closest_image(i,iH2);
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
hneigh[i][0] = iH1;
hneigh[i][1] = iH2;
hneigh[i][2] = 1;
} else {
iH1 = hneigh[i][0];
iH2 = hneigh[i][1];
if (hneigh[i][2] == 0) {
hneigh[i][2] = 1;
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
}
}
x1 = newsite[i];
} else x1 = x[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
// LJ interaction based on true rsq
if (rsq < cut_ljsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
forcelj *= factor_lj * r2inv;
f[i][0] += delx*forcelj;
f[i][1] += dely*forcelj;
f[i][2] += delz*forcelj;
f[j][0] -= delx*forcelj;
f[j][1] -= dely*forcelj;
f[j][2] -= delz*forcelj;
if (eflag) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,forcelj,delx,dely,delz);
}
// adjust rsq and delxyz for off-site O charge(s) if necessary
// but only if they are within reach
if (rsq < cut_coulsqplus) {
if (itype == typeO || jtype == typeO) {
// if atom J = water O, set x2 = offset charge site
// else x2 = x of atom J
if (jtype == typeO) {
if (hneigh[j][0] < 0) {
jH1 = atom->map(tag[j] + 1);
jH2 = atom->map(tag[j] + 2);
if (jH1 == -1 || jH2 == -1)
error->one(FLERR,"TIP4P hydrogen is missing");
if (atom->type[jH1] != typeH || atom->type[jH2] != typeH)
error->one(FLERR,"TIP4P hydrogen has incorrect atom type");
// set jH1,jH2 to closest image to O
jH1 = domain->closest_image(j,jH1);
jH2 = domain->closest_image(j,jH2);
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
hneigh[j][0] = jH1;
hneigh[j][1] = jH2;
hneigh[j][2] = 1;
} else {
jH1 = hneigh[j][0];
jH2 = hneigh[j][1];
if (hneigh[j][2] == 0) {
hneigh[j][2] = 1;
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
}
}
x2 = newsite[j];
} else x2 = x[j];
delx = x1[0] - x2[0];
dely = x1[1] - x2[1];
delz = x1[2] - x2[2];
rsq = delx*delx + dely*dely + delz*delz;
}
// Coulombic interaction based on modified rsq
if (rsq < cut_coulsq) {
r2inv = 1.0 / rsq;
forcecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv);
cforce = factor_coul * forcecoul * r2inv;
// if i,j are not O atoms, force is applied directly;
// if i or j are O atoms, force is on fictitious atom & partitioned
// force partitioning due to Feenstra, J Comp Chem, 20, 786 (1999)
// f_f = fictitious force, fO = f_f (1 - 2 alpha), fH = alpha f_f
// preserves total force and torque on water molecule
// virial = sum(r x F) where each water's atoms are near xi and xj
// vlist stores 2,4,6 atoms whose forces contribute to virial
n = 0;
key = 0;
if (itype != typeO) {
f[i][0] += delx * cforce;
f[i][1] += dely * cforce;
f[i][2] += delz * cforce;
if (vflag) {
v[0] = x[i][0] * delx * cforce;
v[1] = x[i][1] * dely * cforce;
v[2] = x[i][2] * delz * cforce;
v[3] = x[i][0] * dely * cforce;
v[4] = x[i][0] * delz * cforce;
v[5] = x[i][1] * delz * cforce;
}
vlist[n++] = i;
} else {
key++;
fd[0] = delx*cforce;
fd[1] = dely*cforce;
fd[2] = delz*cforce;
fO[0] = fd[0]*(1.0 - alpha);
fO[1] = fd[1]*(1.0 - alpha);
fO[2] = fd[2]*(1.0 - alpha);
fH[0] = 0.5 * alpha * fd[0];
fH[1] = 0.5 * alpha * fd[1];
fH[2] = 0.5 * alpha * fd[2];
f[i][0] += fO[0];
f[i][1] += fO[1];
f[i][2] += fO[2];
f[iH1][0] += fH[0];
f[iH1][1] += fH[1];
f[iH1][2] += fH[2];
f[iH2][0] += fH[0];
f[iH2][1] += fH[1];
f[iH2][2] += fH[2];
if (vflag) {
xH1 = x[iH1];
xH2 = x[iH2];
v[0] = x[i][0]*fO[0] + xH1[0]*fH[0] + xH2[0]*fH[0];
v[1] = x[i][1]*fO[1] + xH1[1]*fH[1] + xH2[1]*fH[1];
v[2] = x[i][2]*fO[2] + xH1[2]*fH[2] + xH2[2]*fH[2];
v[3] = x[i][0]*fO[1] + xH1[0]*fH[1] + xH2[0]*fH[1];
v[4] = x[i][0]*fO[2] + xH1[0]*fH[2] + xH2[0]*fH[2];
v[5] = x[i][1]*fO[2] + xH1[1]*fH[2] + xH2[1]*fH[2];
}
vlist[n++] = i;
vlist[n++] = iH1;
vlist[n++] = iH2;
}
if (jtype != typeO) {
f[j][0] -= delx * cforce;
f[j][1] -= dely * cforce;
f[j][2] -= delz * cforce;
if (vflag) {
v[0] -= x[j][0] * delx * cforce;
v[1] -= x[j][1] * dely * cforce;
v[2] -= x[j][2] * delz * cforce;
v[3] -= x[j][0] * dely * cforce;
v[4] -= x[j][0] * delz * cforce;
v[5] -= x[j][1] * delz * cforce;
}
vlist[n++] = j;
} else {
key += 2;
fd[0] = -delx*cforce;
fd[1] = -dely*cforce;
fd[2] = -delz*cforce;
fO[0] = fd[0]*(1 - alpha);
fO[1] = fd[1]*(1 - alpha);
fO[2] = fd[2]*(1 - alpha);
fH[0] = 0.5 * alpha * fd[0];
fH[1] = 0.5 * alpha * fd[1];
fH[2] = 0.5 * alpha * fd[2];
f[j][0] += fO[0];
f[j][1] += fO[1];
f[j][2] += fO[2];
f[jH1][0] += fH[0];
f[jH1][1] += fH[1];
f[jH1][2] += fH[2];
f[jH2][0] += fH[0];
f[jH2][1] += fH[1];
f[jH2][2] += fH[2];
if (vflag) {
xH1 = x[jH1];
xH2 = x[jH2];
v[0] += x[j][0]*fO[0] + xH1[0]*fH[0] + xH2[0]*fH[0];
v[1] += x[j][1]*fO[1] + xH1[1]*fH[1] + xH2[1]*fH[1];
v[2] += x[j][2]*fO[2] + xH1[2]*fH[2] + xH2[2]*fH[2];
v[3] += x[j][0]*fO[1] + xH1[0]*fH[1] + xH2[0]*fH[1];
v[4] += x[j][0]*fO[2] + xH1[0]*fH[2] + xH2[0]*fH[2];
v[5] += x[j][1]*fO[2] + xH1[1]*fH[2] + xH2[1]*fH[2];
}
vlist[n++] = j;
vlist[n++] = jH1;
vlist[n++] = jH2;
}
if (eflag) {
ecoul = qqrd2e * qtmp * q[j] * sqrt(r2inv);
ecoul *= factor_coul;
} else ecoul = 0.0;
if (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::settings(int narg, char **arg)
{
if (narg < 6 || narg > 7) error->all(FLERR,"Illegal pair_style command");
typeO = force->inumeric(FLERR,arg[0]);
typeH = force->inumeric(FLERR,arg[1]);
typeB = force->inumeric(FLERR,arg[2]);
typeA = force->inumeric(FLERR,arg[3]);
qdist = force->numeric(FLERR,arg[4]);
cut_lj_global = force->numeric(FLERR,arg[5]);
if (narg == 6) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[6]);
cut_coulsq = cut_coul * cut_coul;
cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist);
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style lj/cut/tip4p/cut requires atom IDs");
if (!force->newton_pair)
error->all(FLERR,
"Pair style lj/cut/tip4p/cut requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,
"Pair style lj/cut/tip4p/cut requires atom attribute q");
if (force->bond == NULL)
error->all(FLERR,"Must use a bond style with TIP4P potential");
if (force->angle == NULL)
error->all(FLERR,"Must use an angle style with TIP4P potential");
neighbor->request(this,instance_me);
// set alpha parameter
double theta = force->angle->equilibrium_angle(typeA);
double blen = force->bond->equilibrium_distance(typeB);
alpha = qdist / (cos(0.5*theta) * blen);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutTIP4PCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
// check that LJ epsilon = 0.0 for water H
// set LJ cutoff to 0.0 for any interaction involving water H
// so LJ term isn't calculated in compute()
if ((i == typeH && epsilon[i][i] != 0.0) ||
(j == typeH && epsilon[j][j] != 0.0))
error->all(FLERR,"Water H epsilon must be 0.0 for "
"pair style lj/cut/tip4p/cut");
if (i == typeH || j == typeH)
cut_ljsq[j][i] = cut_ljsq[i][j] = 0.0;
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++) {
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++) {
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::write_restart_settings(FILE *fp)
{
fwrite(&typeO,sizeof(int),1,fp);
fwrite(&typeH,sizeof(int),1,fp);
fwrite(&typeB,sizeof(int),1,fp);
fwrite(&typeA,sizeof(int),1,fp);
fwrite(&qdist,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&typeO,sizeof(int),1,fp);
fread(&typeH,sizeof(int),1,fp);
fread(&typeB,sizeof(int),1,fp);
fread(&typeA,sizeof(int),1,fp);
fread(&qdist,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&typeO,1,MPI_INT,0,world);
MPI_Bcast(&typeH,1,MPI_INT,0,world);
MPI_Bcast(&typeB,1,MPI_INT,0,world);
MPI_Bcast(&typeA,1,MPI_INT,0,world);
MPI_Bcast(&qdist,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
cut_coulsq = cut_coul * cut_coul;
cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairLJCutTIP4PCut::compute_newsite(double *xO, double *xH1,
double *xH2, double *xM)
{
double delx1 = xH1[0] - xO[0];
double dely1 = xH1[1] - xO[1];
double delz1 = xH1[2] - xO[2];
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
xM[0] = xO[0] + alpha * 0.5 * (delx1 + delx2);
xM[1] = xO[1] + alpha * 0.5 * (dely1 + dely2);
xM[2] = xO[2] + alpha * 0.5 * (delz1 + delz2);
}
/* ---------------------------------------------------------------------- */
void *PairLJCutTIP4PCut::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
return NULL;
}
/* ----------------------------------------------------------------------
memory usage of hneigh
------------------------------------------------------------------------- */
double PairLJCutTIP4PCut::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/Make.py b/src/Make.py
deleted file mode 100755
index 3030183e1..000000000
--- a/src/Make.py
+++ /dev/null
@@ -1,2378 +0,0 @@
-#!/usr/bin/env python2
-
-# Make.py tool for managing packages and their auxiliary libs,
-# auto-editing machine Makefiles, and building LAMMPS
-# Syntax: Make.py -h (for help)
-# Notes: should be compatible with python 2.7 and 3.x thanks to 'futurize'
-
-from __future__ import print_function
-import sys,os,re,copy,subprocess,platform
-
-# switch abbrevs
-# switch classes = created class for each switch
-# lib classes = auxiliary package libs
-# build classes = build options with defaults
-# make classes = makefile options with no defaults
-# setargs = makefile settings
-# actionargs = allowed actions (also lib-dir and machine)
-# lib build flags are set if lib is built, for use with zoutput
-
-abbrevs = "adhjmoprsvz"
-
-switchclasses = ("actions","dir","help","jmake","makefile",
- "output","packages","redo","settings","verbose","zoutput")
-libclasses = ("atc","awpmd","colvars","cuda","gpu","h5md",
- "meam","poems","python","qmmm","reax","voronoi")
-buildclasses = ("intel","kokkos")
-makeclasses = ("cc","flags","mpi","fft","jpg","png")
-
-setargs = ("gzip","#gzip","ffmpeg","#ffmpeg","smallbig","bigbig",
- "smallsmall","exceptions","#exceptions")
-actionargs = ("lib-all","file","clean","exe")
-
-gpubuildflag = 0
-
-# ----------------------------------------------------------------
-# functions
-# ----------------------------------------------------------------
-
-# if flag = 1, print txt and exit
-# if flag = 0, print txt as warning and do not exit
-
-def error(txt,flag=1):
- if flag:
- print("ERROR:",txt)
- sys.exit()
- else:
- print("WARNING:",txt)
-
-# store command-line args as sw = dict of key/value
-# key = switch word, value = list of following args
-# order = list of switches in order specified
-# enforce no switch more than once
-
-def parse_args(args):
- narg = len(args)
- sw = {}
- order = []
- iarg = 0
- while iarg < narg:
- if args[iarg][0] != '-': error("Arg %s is not a switch" % args[iarg])
- switch = args[iarg][1:]
- if switch in sw: error("Duplicate switch %s" % args[iarg])
- order.append(switch)
- first = iarg+1
- last = first
- while last < narg and args[last][0] != '-': last += 1
- sw[switch] = args[first:last]
- iarg = last
- return sw,order
-
-# convert info in switches dict back to a string, in switch_order
-
-def switch2str(switches,switch_order):
- txt = ""
- for switch in switch_order:
- if txt: txt += ' '
- txt += "-%s" % switch
- txt += ' ' + ' '.join(switches[switch])
- return txt
-
-# check if compiler works with ccflags on dummy one-line tmpauto.cpp file
-# return 1 if successful, else 0
-# warn = 1 = print warning if not successful, warn = 0 = no warning
-# NOTE: unrecognized -override-limits can leave verride-limits file
-
-def compile_check(compiler,ccflags,warn):
- open("tmpauto.cpp",'w').write("int main(int, char **) {}\n")
- tmp = "%s %s -c tmpauto.cpp" % (compiler,ccflags)
- try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT,
- shell=True).decode()
- except subprocess.CalledProcessError as e: txt = e.output
- flag = 1
- if txt or not os.path.isfile("tmpauto.o"):
- flag = 0
- if warn:
- print(tmp)
- if txt: print(txt)
- else: print("compile produced no output")
- os.remove("tmpauto.cpp")
- if os.path.isfile("tmpauto.o"): os.remove("tmpauto.o")
- return flag
-
-# check if linker works with linkflags and libs on tmpauto.o file
-# return 1 if successful, else 0
-# warn = 1 = print warning if not successful, warn = 0 = no warning
-
-def link_check(linker,linkflags,libs,warn):
- open("tmpauto.cpp",'w').write("int main(int, char **) {}\n")
- tmp = "%s %s -o tmpauto tmpauto.cpp %s" % (linker,linkflags,libs)
- try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT,
- shell=True).decode()
- except subprocess.CalledProcessError as e: txt = e.output
- flag = 1
- if txt or not os.path.isfile("tmpauto"):
- flag = 0
- if warn:
- print(tmp)
- if txt: print(txt)
- else: print("link produced no output")
- os.remove("tmpauto.cpp")
- if os.path.isfile("tmpauto"): os.remove("tmpauto")
- return flag
-
-# ----------------------------------------------------------------
-# switch classes, one per single-letter switch
-# ----------------------------------------------------------------
-
-# actions
-
-class Actions(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--a action1 action2 ...
- possible actions = lib-all, lib-dir, file, clean, exe or machine
- machine is a Makefile.machine suffix
- actions can be specified in any order
- each action can appear only once
- lib-dir can appear multiple times for different dirs
- some actions depend on installed packages
- installed packages = currently installed + result of -p switch
- actions are invoked in this order, independent of specified order
- (1) lib-all or lib-dir = build auxiliary libraries
- lib-all builds all auxiliary libs needed by installed packages
- lib-dir builds a specific lib whether package installed or not
- dir is any dir in lib directory (atc, cuda, meam, etc) except linalg
- (2) file = create a new src/MAKE/MINE/Makefile.auto
- if file not specified, existing Makefile.auto is NOT changed
- except by -m switch, which will copy Makefile.machine to Makefile.auto
- note that exe action can add an -m switch, as described below
- if file is specified, new Makefile.auto is created
- if "-m machine" specified (or added by exe),
- start with existing Makefile.machine, else existing Makefile.auto
- if "-m none" specified, start Makefile.auto from scratch
- must use -cc and -mpi switches to specify compiler and MPI
- settings for these switches will alter Makefile.auto
- -s, -intel, -kokkos, -cc, -mpi, -fft, -jpg, -png
- if these accelerator packages are installed, they induce settings
- that will alter Makefile.auto: opt, user-omp, user-intel, kokkos
- use -z switch to copy final Makefile.auto to new filename
- (3) clean = invoke "make clean-auto" to insure clean build on current files
- useful if compiler flags have changed
- (4) exe or machine = build LAMMPS
- machine can be any existing Makefile.machine suffix
- machine is converted to "exe" action, and additionally:
- "-m machine" is added if -m switch is not specified
- "-o machine" is added if -o switch is not specified
- if either "-m" or "-o" are specified, they are not overridden
- does not invoke any lib builds, since libs could be previously built
- exe ALWAYS builds using src/MAKE/MINE/Makefile.auto
- if file action also specified, it creates a new Makefile.auto
- else if -m switch specified,
- existing Makefile.machine is copied to create Makefile.auto
- else Makefile.auto must already exist and is not changed
- build produces src/lmp_auto, or error message if unsuccessful
- use -o switch to copy src/lmp_auto to new filename
- use -z switch to copy src/MAKE/MINE/Makefile.auto to new filename
-"""
-
- def check(self):
- if not self.inlist: error("-a args are invalid")
- libs = []
- cleans = []
- files = []
- exes = []
- for one in self.inlist:
- if one.startswith("lib-"):
- lib = one[4:]
- if lib != "all" and lib not in libclasses: error("Actions are invalid")
- libs.append(one)
- elif one == "file":
- files.append(one)
- elif one == "clean":
- cleans.append(one)
- elif one == "exe":
- exes.append(one)
- # one action can be unknown, must be a machine (checked in setup)
- else:
- exes.append(one)
- if len(set(libs)) != len(libs) or \
- len(cleans) > 1 or len(files) > 1 or len(exes) > 1:
- error("Actions are invalid")
- self.alist = [action for actions in [libs,cleans,files,exes] \
- for action in actions]
-
- # dedup list of actions concatenated from two lists
- # current self.inlist = specified -a switch + redo command -a switch
- # specified exe/machine action replaces redo exe/machine action
- # operates on and replaces self.inlist
-
- def dedup(self):
- alist = []
- exemachine = 0
- for one in self.inlist:
- if one == "exe" or (one not in actionargs and not one.startswith("lib-")):
- if exemachine: continue
- exemachine = 1
- if one not in alist: alist.append(one)
- self.inlist = alist
-
- # if last action is unknown, assume machine and convert to exe
- # only done if action is a suffix for an existing Makefile.machine
- # return machine if conversion done, else None
-
- def setup(self):
- machine = self.alist[-1]
- if machine in actionargs or machine.startswith("lib-"): return None
- make = MakeReader(machine,2)
- self.alist[-1] = "exe"
- return machine
-
- # build one or more auxiliary package libraries
-
- def lib(self,suffix):
- if suffix != "all":
- print("building",suffix,"library ...")
- txt = "%s.build()" % suffix
- exec(txt)
- else:
- final = packages.final
- for one in packages.lib:
- if final[one]:
- if "user" in one: pkg = one[5:]
- else: pkg = one
- print("building",pkg,"library ...")
- txt = "%s.build()" % pkg
- exec(txt)
-
- # read Makefile.machine
- # if caller = "file", edit via switches
- # if caller = "exe", just read
- # write out new Makefile.auto
-
- def file(self,caller):
-
- # if caller="file", create from mpi or read from Makefile.machine or auto
- # if caller="exe" and "file" action already invoked, read from auto
- # if caller="exe" and no "file" action, read from Makefile.machine or auto
-
- if caller == "file":
- if makefile and makefile.machine == "none":
- if cc and mpi: machine = "mpi"
- else: error("Cannot create makefile unless -cc and -mpi are used")
- elif makefile: machine = makefile.machine
- else: machine = "auto"
- elif caller == "exe" and "file" in self.alist:
- machine = "auto"
- elif caller == "exe" and "file" not in self.alist:
- if makefile and makefile.machine == "none":
- error("Cannot build with makefile = none")
- elif makefile: machine = makefile.machine
- else: machine = "auto"
-
- make = MakeReader(machine,1)
-
- # change makefile settings to user specifications
-
- precompiler = ""
- if caller == "file":
-
- # add compiler/linker and default CCFLAGS,LINKFLAGS
- # if cc.wrap, add wrapper setting for mpi = ompi/mpich
- # precompiler = env variable setting for OpenMPI wrapper compiler
-
- if cc:
- make.setvar("CC",cc.compiler)
- make.setvar("LINK",cc.compiler)
- if cc.wrap:
- if cc.wrap == "nvcc":
- wrapper = os.path.abspath("../lib/kokkos/config/nvcc_wrapper")
- else: wrapper = cc.wrap
- abbrev = cc.abbrev
- if abbrev == "mpi":
- if cc.parent == "mpich":
- make.addvar("CC","-cxx=%s" % wrapper)
- make.addvar("LINK","-cxx=%s" % wrapper)
- elif cc.parent == "openmpi":
- make.addvar("export OMPI_CXX",wrapper,"cc")
- precompiler = "env OMPI_CXX=%s " % wrapper
- else: error("Could not add MPI wrapper compiler, " +
- "did not recognize OpenMPI or MPICH")
- make.setvar("CCFLAGS","-g")
- make.addvar("CCFLAGS","-O3")
- make.setvar("LINKFLAGS","-g")
- make.addvar("LINKFLAGS","-O")
-
- # add MPI settings
-
- if mpi:
- make.delvar("MPI_INC","*")
- make.delvar("MPI_PATH","*")
- make.delvar("MPI_LIB","*")
- if mpi.style == "mpi":
- make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX")
- make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1")
- elif mpi.style == "mpich":
- make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX")
- make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1")
- if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir)
- if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir)
- make.addvar("MPI_LIB","-lmpich")
- make.addvar("MPI_LIB","-lmpl")
- make.addvar("MPI_LIB","-lpthread")
- elif mpi.style == "ompi":
- make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX")
- make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1")
- if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir)
- if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir)
- make.addvar("MPI_LIB","-lmpi")
- make.addvar("MPI_LIB","-lmpi_cxx")
- elif mpi.style == "serial":
- make.addvar("MPI_INC","-I../STUBS")
- make.addvar("MPI_PATH","-L../STUBS")
- make.addvar("MPI_LIB","-lmpi_stubs")
-
- # add accelerator package CCFLAGS and LINKFLAGS and variables
-
- compiler = precompiler + ' '.join(make.getvar("CC"))
- linker = precompiler + ' '.join(make.getvar("LINK"))
-
- final = packages.final
- if final["opt"]:
- if compile_check(compiler,"-restrict",0):
- make.addvar("CCFLAGS","-restrict")
-
- if final["user-omp"]:
- if compile_check(compiler,"-fopenmp",1):
- make.addvar("CCFLAGS","-fopenmp")
- make.addvar("LINKFLAGS","-fopenmp")
- if compile_check(compiler,"-restrict",0):
- make.addvar("CCFLAGS","-restrict")
-
- if final["user-intel"]:
- if intel.mode == "cpu":
- make.delvar("CCFLAGS","-O*")
- make.addvar("CCFLAGS","-O2")
- if compile_check(compiler,"-openmp",1):
- make.addvar("CCFLAGS","-openmp")
- if compile_check(compiler,"-restrict",1):
- make.addvar("CCFLAGS","-restrict")
- if compile_check(compiler,"-no-offload",1):
- make.addvar("CCFLAGS","-no-offload")
- if compile_check(compiler,"-fno-alias",1):
- make.addvar("CCFLAGS","-fno-alias")
- if compile_check(compiler,"-ansi-alias",1):
- make.addvar("CCFLAGS","-ansi-alias")
- if compile_check(compiler,"-xAVX",1):
- make.addvar("CCFLAGS","-xAVX")
- if compile_check(compiler,"-fp-model fast=2",1):
- make.addvar("CCFLAGS","-fp-model fast=2")
- if compile_check(compiler,"-no-prec-div",1):
- make.addvar("CCFLAGS","-no-prec-div")
- if compile_check(compiler,"-override-limits",1):
- make.addvar("CCFLAGS","-override-limits")
- make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64")
- make.delvar("CCFLAGS","-DLMP_INTEL_OFFLOAD")
-
- make.delvar("LINKFLAGS","-O*")
- make.addvar("LINKFLAGS","-O2")
- if link_check(linker,"-openmp","",1):
- make.addvar("LINKFLAGS","-openmp")
- if link_check(linker,"-xAVX","",1):
- make.addvar("LINKFLAGS","-xAVX")
- if link_check(linker,"-fpmodel fast=2","",1):
- make.addvar("LINKFLAGS","-fpmodel fast=2")
- if link_check(linker,"-no-prec-div","",1):
- make.addvar("LINKFLAGS","-no-prec-div")
- if link_check(linker,"-override-limits","",1):
- make.addvar("LINKFLAGS","-override-limits")
- make.delvar("LINKFLAGS","-offload")
-
- if link_check(linker,"","-ltbbmalloc",1):
- make.addvar("LIB","-ltbbmalloc")
- if link_check(linker,"","-ltbbmalloc_proxy",1):
- make.addvar("LIB","-ltbbmalloc_proxy")
-
- elif intel.mode == "phi":
- if compile_check(compiler,"-fopenmp",1):
- make.addvar("CCFLAGS","-fopenmp")
- make.addvar("LINKFLAGS","-fopenmp")
- make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64")
- if compile_check(compiler,"-restrict",1):
- make.addvar("CCFLAGS","-restrict")
- if compile_check(compiler,"-xHost",1):
- make.addvar("CCFLAGS","-xHost")
- make.addvar("CCFLAGS","-DLMP_INTEL_OFFLOAD")
- if compile_check(compiler,"-fno-alias",1):
- make.addvar("CCFLAGS","-fno-alias")
- if compile_check(compiler,"-ansi-alias",1):
- make.addvar("CCFLAGS","-ansi-alias")
- if compile_check(compiler,"-override-limits",1):
- make.addvar("CCFLAGS","-override-limits")
- if compile_check(compiler,'-offload-option,mic,compiler,' +
- '"-fp-model fast=2 -mGLOB_default_function_attrs=' +
- '\\"gather_scatter_loop_unroll=4\\""',1):
- make.addvar("CCFLAGS",'-offload-option,mic,compiler,' +
- '"-fp-model fast=2 -mGLOB_default_function_attrs=' +
- '\\"gather_scatter_loop_unroll=4\\""')
- if link_check(linker,"-offload","",1):
- make.addvar("LINKFLAGS","-offload")
-
- if final["kokkos"]:
- if kokkos.mode == "omp":
- make.delvar("KOKKOS_DEVICES","*")
- make.delvar("KOKKOS_ARCH","*")
- make.addvar("KOKKOS_DEVICES","OpenMP","lmp")
- if kokkos.archcpu:
- make.addvar("KOKKOS_ARCH",kokkos.archcpu,"lmp")
- elif kokkos.mode == "cuda":
- make.delvar("KOKKOS_DEVICES","*")
- make.delvar("KOKKOS_ARCH","*")
- make.addvar("KOKKOS_DEVICES","Cuda, OpenMP","lmp")
- if kokkos.archgpu:
- if kokkos.archgpu[0] == "3": value = "Kepler" + kokkos.archgpu
- elif kokkos.archgpu[0] == "2": value = "Fermi" + kokkos.archgpu
- else: error("Unrecognized Kokkos archgpu setting")
- if kokkos.archcpu: value += ", %s" % kokkos.archcpu
- make.addvar("KOKKOS_ARCH",value,"lmp")
- elif kokkos.mode == "phi":
- make.delvar("KOKKOS_DEVICES","*")
- make.delvar("KOKKOS_ARCH","*")
- make.addvar("KOKKOS_DEVICES","OpenMP","lmp")
- make.addvar("KOKKOS_ARCH","KNC","lmp")
-
- # add LMP_INC ifdef settings
-
- if settings:
- list = settings.inlist
- for one in list:
- if one == "gzip": make.addvar("LMP_INC","-DLAMMPS_GZIP")
- elif one == "#gzip": make.delvar("LMP_INC","-DLAMMPS_GZIP")
- elif one == "ffmpeg": make.addvar("LMP_INC","-DLAMMPS_FFMPEG")
- elif one == "#ffmpeg": make.delvar("LMP_INC","-DLAMMPS_FFMPEG")
- elif one == "smallbig":
- make.delvar("LMP_INC","-DLAMMPS_BIGBIG")
- make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL")
- elif one == "bigbig":
- make.delvar("LMP_INC","-DLAMMPS_SMALLBIG")
- make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL")
- make.addvar("LMP_INC","-DLAMMPS_BIGBIG")
- elif one == "smallsmall":
- make.delvar("LMP_INC","-DLAMMPS_SMALLBIG")
- make.delvar("LMP_INC","-DLAMMPS_BIGBIG")
- make.addvar("LMP_INC","-DLAMMPS_SMALLSMALL")
- elif one == "exceptions": make.addvar("LMP_INC","-DLAMMPS_EXCEPTIONS")
- elif one == "#exception": make.delvar("LMP_INC","-DLAMMPS_EXCEPTIONS")
-
- # add FFT, JPG, PNG settings
-
- if fft:
- make.delvar("FFT_INC","*")
- make.delvar("FFT_PATH","*")
- make.delvar("FFT_LIB","*")
- if fft.mode == "none": make.addvar("FFT_INC","-DFFT_NONE")
- else:
- make.addvar("FFT_INC","-DFFT_%s" % fft.mode.upper())
- make.addvar("FFT_LIB",fft.lib)
- if fft.dir:
- make.addvar("FFT_INC","-I%s/include" % fft.dir)
- make.addvar("FFT_PATH","-L%s/lib" % fft.dir)
- else:
- if fft.incdir: make.addvar("FFT_INC","-I%s" % fft.incdir)
- if fft.libdir: make.addvar("FFT_PATH","-L%s" % fft.libdir)
-
- if jpg:
- if jpg.on == 0:
- make.delvar("LMP_INC","-DLAMMPS_JPEG")
- make.delvar("JPG_LIB","-ljpeg")
- else:
- make.addvar("LMP_INC","-DLAMMPS_JPEG")
- make.addvar("JPG_LIB","-ljpeg")
- if jpg.dir:
- make.addvar("JPG_INC","-I%s/include" % jpg.dir)
- make.addvar("JPG_PATH","-L%s/lib" % jpg.dir)
- else:
- if jpg.incdir: make.addvar("JPG_INC","-I%s" % jpg.incdir)
- if jpg.libdir: make.addvar("JPG_PATH","-L%s" % jpg.libdir)
-
- if png:
- if png.on == 0:
- make.delvar("LMP_INC","-DLAMMPS_PNG")
- make.delvar("JPG_LIB","-lpng")
- else:
- make.addvar("LMP_INC","-DLAMMPS_PNG")
- make.addvar("JPG_LIB","-lpng")
- if png.dir:
- make.addvar("JPG_INC","-I%s/include" % png.dir)
- make.addvar("JPG_PATH","-L%s/lib" % png.dir)
- else:
- if png.incdir: make.addvar("JPG_INC","-I%s" % png.incdir)
- if png.libdir: make.addvar("JPG_PATH","-L%s" % png.libdir)
-
- # finally after all other settings, add explicit flags
-
- if flags:
- for var,action,flist in flags.flags:
- values = make.getvar(var)
- if values == None:
- error("Flags for a non-existent Makefile.auto variable")
- for flag in flist:
- flag = "-" + flag
- if action == "add": make.addvar(var,flag)
- elif action == "del": make.delvar(var,flag)
-
- # set self.stubs if Makefile.auto uses STUBS lib in MPI settings
-
- if make.getvar("MPI_LIB") and "-lmpi_stubs" in make.getvar("MPI_LIB"):
- self.stubs = 1
- else: self.stubs = 0
-
- # write out Makefile.auto
- # unless caller = "exe" and "file" action already invoked
-
- if caller == "file" or "file" not in self.alist:
- # make certain that 'MAKE/MINE' folder exists.
- subprocess.check_output("mkdir -p %s/MAKE/MINE" % dir.src,
- stderr=subprocess.STDOUT,shell=True)
- make.write("%s/MAKE/MINE/Makefile.auto" % dir.src,1)
- print("Created src/MAKE/MINE/Makefile.auto")
-
- # test full compile and link
- # unless caller = "file" and "exe" action will be invoked later
-
- if caller == "file" and "exe" in self.alist: return
- compiler = precompiler + ' '.join(make.getvar("CC"))
- ccflags = ' '.join(make.getvar("CCFLAGS"))
- linker = precompiler + ' '.join(make.getvar("LINK"))
- linkflags = ' '.join(make.getvar("LINKFLAGS"))
- libs = ' '.join(make.getvar("LIB"))
- if not compile_check(compiler,ccflags,1):
- error("Test of compilation failed")
- if not link_check(linker,linkflags,libs,1): error("Test of link failed")
-
- # invoke "make clean-auto" to force clean before build
-
- def clean(self):
- txt = "cd %s; make clean-auto" % dir.src
- subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- print("Performed make clean-auto")
-
- # build LAMMPS using Makefile.auto and -j setting
- # invoke self.file() first, to test makefile compile/link
- # delete existing lmp_auto, so can detect if build fails
- # build STUBS lib (if unbuilt) if Makefile.auto MPI settings need it
-
- def exe(self):
- self.file("exe")
- subprocess.check_output("cd %s; rm -f lmp_auto" % dir.src,stderr=subprocess.STDOUT,shell=True)
- if self.stubs and not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src):
- print("building serial STUBS library ...")
- tmp = "cd %s/STUBS; make clean; make" % dir.src
- txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode()
- if not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src):
- print(txt)
- error('Unsuccessful "make stubs"')
- print("Created src/STUBS/libmpi_stubs.a")
-
- # special hack for shannon GPU cluster
- # must use "srun make" if on it and building w/ GPU package, else just make
- # this is b/c Cuda libs are not all available on host
-
- make = "make"
- if "shannon" == platform.node() and packages.final["gpu"]:
- make = "srun make"
-
- if jmake: tmp = "cd %s; %s -j %d auto" % (dir.src,make,jmake.n)
- else: tmp = "cd %s; %s auto" % (dir.src,make)
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(tmp,shell=True)
- else:
- print(tmp)
- try: subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/lmp_auto" % dir.src):
- error('Unsuccessful "make auto"')
- elif not output: print("Created src/lmp_auto")
-
-# dir switch
-
-class Dir(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--d dir
- dir = LAMMPS home dir
- if -d not specified, working dir must be lammps/src
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) != 1:
- error("-d args are invalid")
-
- # if inlist = None, check that cwd = lammps/src
- # store cwd and lammps dir
- # derive src,make,lib dirs from lammps dir
- # check that they all exist
-
- def setup(self):
- self.cwd = os.getcwd()
- if self.inlist == None: self.lammps = ".."
- else: self.lammps = self.inlist[0]
- self.lammps = os.path.realpath(self.lammps)
- self.src = self.lammps + "/src"
- self.make = self.lammps + "/src/MAKE"
- self.lib = self.lammps + "/lib"
- if not os.path.isdir(self.lammps): error("LAMMPS home dir is invalid")
- if not os.path.isdir(self.src): error("LAMMPS src dir is invalid")
- if not os.path.isdir(self.lib): error("LAMMPS lib dir is invalid")
-
-# help switch
-
-class Help(object):
- def __init__(self,list): pass
-
- def help(self):
- return """
-Syntax: Make.py switch args ...
- switches can be listed in any order
- help switch:
- -h prints help and syntax for all other specified switches
- switch for actions:
- -a lib-all, lib-dir, clean, file, exe or machine
- list one or more actions, in any order
- machine is a Makefile.machine suffix
- one-letter switches:
- -d (dir), -j (jmake), -m (makefile), -o (output), -p (packages),
- -r (redo), -s (settings), -v (verbose), -z (makefile output)
- switches for libs:
- -atc, -awpmd, -colvars, -cuda, -gpu, -h5md,
- -meam, -poems, -python, -qmmm, -reax, -voronoi
- switches for build and makefile options:
- -intel, -kokkos, -cc, -flags, -mpi, -fft, -jpg, -png
-"""
-
-# jmake switch
-
-class Jmake(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--j N
- use N procs for performing parallel make commands
- used when building a lib or LAMMPS itself
- if -j not specified, serial make commands run on single core
-"""
-
- def check(self):
- if len(self.inlist) != 1: error("-j args are invalid")
- if not self.inlist[0].isdigit(): error("-j args are invalid")
- n = int(self.inlist[0])
- if n <= 0: error("-j args are invalid")
- self.n = n
-
-# makefile switch
-
-class Makefile(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--m machine
- use Makefile.machine under src/MAKE as starting point to create Makefile.auto
- if machine = "none", file action will create Makefile.auto from scratch
- must use -cc and -mpi switches to specify compiler and MPI
- if -m not specified, file/exe actions alter existing Makefile.auto
-"""
-
- def check(self):
- if len(self.inlist) != 1: error("-m args are invalid")
- self.machine = self.inlist[0]
-
-# output switch
-
-class Output(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--o machine
- copy final src/lmp_auto to lmp_machine in working dir
- if -o not specified, exe action only produces src/lmp_auto
-"""
-
- def check(self):
- if len(self.inlist) != 1: error("-o args are invalid")
- self.machine = self.inlist[0]
-
-# packages switch
-
-class Packages(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--p = package1 package2 ...
- list of packages to install or uninstall in order specified
- operates on set of packages currently installed
- valid package names:
- any LAMMPS standard or user package (type "make package" to see list)
- prefix by yes/no to install/uninstall (see abbrevs)
- yes-molecule, yes-user-atc, no-molecule, no-user-atc
- can use LAMMPS categories (type "make package" to see list)
- all = all standard and user packages (also none = no-all)
- std (or standard) = all standard packages
- user = all user packages
- lib = all standard and user packages with auxiliary libs
- can abbreviate package names and yes/no
- omp = user-omp = yes-user-omp
- ^omp = ^user-omp = no-user-omp
- user = yes-user, ^user = no-user
- all = yes-all, ^all = none = no-all
- when action performed, list is processed in order,
- as if typed "make yes/no" for each
- if "orig" or "original" is last package in list,
- set of installed packages will be restored to original (current) list
- after "build" action is performed
- if -p not specified, currently installed packages are not changed
-"""
-
- def check(self):
- if self.inlist != None and not self.inlist: error("-p args are invalid")
-
- def setup(self):
-
- # extract package lists from src/Makefile
- # remove names from lib that there are not Make.py lib-classes for
- # most don't actually have libs, so nothing to control from Make.py
-
- make = MakeReader("%s/Makefile" % dir.src)
- std = make.getvar("PACKAGE")
- user = make.getvar("PACKUSER")
- lib = make.getvar("PACKLIB")
- lib.remove("kim")
- lib.remove("kokkos")
- lib.remove("user-molfile")
- lib.remove("python")
- lib.remove("user-quip")
- all = std + user
-
- # plist = command line args expanded to yes-package or no-package
-
- plist = []
- if self.inlist:
- for one in self.inlist:
- if one in std:
- plist.append("yes-%s" % one)
- elif one in user:
- plist.append("yes-%s" % one)
- elif "user-"+one in user:
- plist.append("yes-user-%s" % one)
- elif one == "std" or one == "standard" or one == "user" or \
- one == "lib" or one == "all": plist.append("yes-%s" % one)
- elif one.startswith("yes-"):
- if one[4:] in std: plist.append("yes-%s" % one[4:])
- elif one[4:] in user: plist.append("yes-%s" % one[4:])
- elif "user-"+one[4:] in user: plist.append("yes-user-%s" % one[4:])
- elif one == "yes-std" or one == "yes-standard" or \
- one == "yes-user" or one == "yes-lib" or one == "yes-all":
- plist.append("yes-%s" % one[4:])
- else: error("Invalid package name %s" % one)
- elif one.startswith("no-"):
- if one[3:] in std: plist.append("no-%s" % one[3:])
- elif one[3:] in user: plist.append("no-%s" % one[3:])
- elif "user-"+one[3:] in user: plist.append("no-user-%s" % one[3:])
- elif one == "no-std" or one == "no-standard" or one == "no-user" or \
- one == "no-lib" or one == "no-all":
- plist.append("no-%s" % one[3:])
- else: error("Invalid package name %s" % one)
- elif one.startswith('^'):
- if one[1:] in std: plist.append("no-%s" % one[1:])
- elif one[1:] in user: plist.append("no-%s" % one[1:])
- elif "user-"+one[1:] in user: plist.append("no-user-%s" % one[1:])
- elif one == "^std" or one == "^standard" or one == "^user" or \
- one == "^lib" or one == "^all": plist.append("no-%s" % one[1:])
- else: error("Invalid package name %s" % one)
- elif one == "none": plist.append("no-all")
- elif one == "orig": plist.append(one)
- else: error("Invalid package name %s" % one)
- if "orig" in plist and plist.index("orig") != len(plist)-1:
- error('-p orig arg must be last')
- if plist.count("orig") > 1: error('-p orig arg must be last')
-
- # original = dict of all packages
- # key = package name, value = 1 if currently installed, else 0
-
- original = {}
- tmp = "cd %s; make ps" % dir.src
- output = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode().split('\n')
- pattern = "Installed\s+(\w+): package (\S+)"
- for line in output:
- m = re.search(pattern,line)
- if not m: continue
- pkg = m.group(2).lower()
- if pkg not in all: error('Package list does not match "make ps" results')
- if m.group(1) == "NO": original[pkg] = 0
- elif m.group(1) == "YES": original[pkg] = 1
-
- # final = dict of all packages after plist applied to original
- # key = package name, value = 1 if installed, else 0
-
- final = copy.deepcopy(original)
- for i,one in enumerate(plist):
- if "yes" in one:
- pkg = one[4:]
- yes = 1
- else:
- pkg = one[3:]
- yes = 0
- if pkg in all:
- final[pkg] = yes
- elif pkg == "std" or pkg == "standard":
- for pkg in std: final[pkg] = yes
- elif pkg == "user":
- for pkg in user: final[pkg] = yes
- elif pkg == "lib":
- for pkg in lib: final[pkg] = yes
- elif pkg == "all":
- for pkg in all: final[pkg] = yes
-
- self.std = std
- self.user = user
- self.lib = lib
- self.all = all
- self.plist = plist
- self.original = original
- self.final = final
-
- # install packages in plist
-
- def install(self):
- if self.plist: print("Installing packages ...")
- for one in self.plist:
- if one == "orig": continue
- subprocess.check_output("cd %s; make %s" % (dir.src,one),
- stderr=subprocess.STDOUT,shell=True)
- if self.plist and verbose:
- txt = subprocess.check_output("cd %s; make ps" % dir.src,
- stderr=subprocess.STDOUT,
- shell=True).decode()
- print("Package status after installation:")
- print(txt)
-
- # restore packages to original list if requested
- # order of re-install should not matter matter b/c of Depend.sh
-
- def uninstall(self):
- if not self.plist or self.plist[-1] != "orig": return
- print("Restoring packages to original state ...")
- subprocess.check_output("cd %s; make no-all" % dir.src,
- stderr=subprocess.STDOUT,shell=True)
- for one in self.all:
- if self.original[one]:
- subprocess.check_output("cd %s; make yes-%s" % (dir.src,one),
- stderr=subprocess.STDOUT,shell=True)
- if verbose:
- txt = subprocess.check_output("cd %s; make ps" % dir.src,
- stderr=subprocess.STDOUT,
- shell=True).decode()
- print("Restored package status:")
- print(txt)
-
-# redo switch
-
-class Redo(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--r file label1 label2 ...
- all args are optional
- invoke Make.py commands from a file
- other specified switches are merged with file commands (see below)
- redo file format:
- blank lines and lines starting with "#" are skipped
- other lines are treated as commands
- each command is a list of Make.py args, as if typed at command-line
- commands can have leading label, followed by ":"
- commands cannot contain a "-r" switch
- if no args, execute previous command, which is stored in src/Make.py.last
- if one arg, execute all commands from specified file
- unlabeled or labeled commands are all executed
- if multiple args, execute only matching labeled commands from file
- if other switches are specified,
- if file command does not have the switch, it is added
- if file command has the switch, the specified switch replaces it
- except if -a (action) switch is both specified and in the file command,
- two sets of actions are merged and duplicates removed
- if both switches have "exe or machine" action,
- the specified exe/machine overrides the file exe/machine
-"""
-
- def check(self):
- if len(self.inlist) == 0:
- self.dir = 1
- self.file = "Make.py.last"
- self.labels = []
- else:
- self.dir = 0
- self.file = self.inlist[0]
- self.labels = self.inlist[1:]
-
- # read redo file
- # self.commands = list of commands to execute
-
- def setup(self):
- file = self.file
- if not os.path.isfile(file): error("Redo file %s does not exist" % file)
- lines = open(file,'r').readlines()
-
- cmdlines = []
- for line in lines:
- line = line.strip()
- if not line or line[0] == '#' : continue
- cmdlines.append(line)
-
- # if no labels, add all file commands to command list
- # if labels, make a dict with key = label, value = command
- # and discard unlabeled commands
-
- dict = {}
- commands = []
- for line in cmdlines:
- words = line.split()
- if "-r" in words: error("Redo command cannot contain -r switch")
- if words[0][-1] == ':': label = words[0][:-1]
- else: label = None
- if not self.labels:
- if label: subprocess.append(' '.join(words[1:]))
- else: subprocess.append(line)
- else:
- if not label: continue
- dict[label] = ' '.join(words[1:])
-
- # extract labeled commands from dict and add to command list
-
- for label in self.labels:
- if label not in dict: error("Redo label not in redo file")
- subprocess.append(dict[label])
-
- self.commands = commands
-
-# settings switch
-
-class Settings(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--s set1 set2 ...
- possible settings = gzip #gzip ffmpeg #ffmpeg
- smallbig bigbig smallsmall exceptions #exceptions
- alter LAMMPS ifdef settings in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- gzip and #gzip turn on/off LAMMPS_GZIP setting
- ffmpeg and #ffmpeg turn on/off LAMMPS_FFMPEG setting
- smallbig, bigbig, smallsmall turn on LAMMPS_SMALLBIG, etc
- and turn off other two
- exceptions and #exceptions turn on/off LAMMPS_EXCEPTIONS setting
-"""
-
- def check(self):
- if not self.inlist: error("-s args are invalid")
- for one in self.inlist:
- if one not in setargs: error("-s args are invalid")
-
-# verbose switch
-
-class Verbose(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--v (no arguments)
- produce verbose output as Make.py executes
- if -v not specified, minimal output is produced
-"""
-
- def check(self):
- if len(self.inlist): error("-v args are invalid")
-
-# zoutput switch for making copy of final Makefile.auto
-
-class Zoutput(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
-
- def help(self):
- return """
--z machine
- copy created/used src/MAKE/MINE/Makefile.auto to Makefile.machine in same dir
- copy created/used lib/*/Makefile.auto and lib/*/Makefile.lammps to
- Makefile_lib.machine and Makefile_lib_lammps.machine in same dir
- this can be used to preserve the machine Makefile and lib Makefiles
-"""
-
- def check(self):
- if len(self.inlist) != 1: error("-z args are invalid")
- self.machine = self.inlist[0]
-
-# ----------------------------------------------------------------
-# lib classes, one per LAMMPS auxiliary lib
-# ----------------------------------------------------------------
-
-# ATC lib
-
-class ATC(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "g++"
- self.lammpsflag = 0
-
- def help(self):
- return """
--atc make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = g++)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-atc args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-atc args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-atc args are invalid")
-
- def build(self):
- libdir = dir.lib + "/atc"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" %
- libdir,stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libatc.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/atc library")
- else: print("Created lib/atc library")
-
-# AWPMD lib
-
-class AWPMD(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "mpicc"
- self.lammpsflag = 0
-
- def help(self):
- return """
--awpmd make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = mpicc)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-awpmd args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-awpmd args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-awpmd args are invalid")
-
- def build(self):
- libdir = dir.lib + "/awpmd"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" %
- libdir,stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libawpmd.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/awpmd library")
- else: print("Created lib/awpmd library")
-
-# COLVARS lib
-
-class COLVARS(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "g++"
- self.lammpsflag = 0
-
- def help(self):
- return """
--colvars make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = g++)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-colvars args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-colvars args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-colvars args are invalid")
-
- def build(self):
- libdir = dir.lib + "/colvars"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" %
- libdir,stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libcolvars.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/colvars library")
- else: print("Created lib/colvars library")
-
-# CUDA lib
-
-class CUDA(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.mode = "double"
- self.arch = "35"
-
- def help(self):
- return """
--cuda mode=double arch=35
- all args are optional and can be in any order
- mode = double or mixed or single (def = double)
- arch = M (def = 35)
- M = 31,35,37,etc for Kepler
- M = 20 for CC2.0 (GF100/110, e.g. C2050,GTX580,GTX470)
- M = 21 for CC2.1 (GF104/114, e.g. GTX560, GTX460, GTX450)
- M = 13 for CC1.3 (GF200, e.g. C1060, GTX285)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-cuda args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-cuda args are invalid")
- if words[0] == "mode": self.mode = words[1]
- elif words[0] == "arch": self.arch = words[1]
- else: error("-cuda args are invalid")
- if self.mode != "double" and self.mode != "mixed" and \
- self.mode != "single":
- error("-cuda args are invalid")
- if not self.arch.isdigit(): error("-cuda args are invalid")
-
- def build(self):
- libdir = dir.lib + "/cuda"
- subprocess.check_output("cd %s; make clean" % libdir,
- stderr=subprocess.STDOUT,shell=True)
- if self.mode == "double": n = 2
- elif self.mode == "mixed": n = 3
- elif self.mode == "single": n = 1
- if jmake: txt = "cd %s; make -j %d precision=%d arch=%s" % \
- (libdir,jmake.n,n,self.arch)
- else: txt = "cd %s; make precision=%d arch=%s" % \
- (libdir,n,self.arch)
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/liblammpscuda.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/cuda library")
- else: print("Created lib/cuda library")
-
-# GPU lib
-
-class GPU(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "linux.double"
- self.lammpsflag = self.modeflag = self.archflag = self.homeflag = 0
-
- def help(self):
- return """
--gpu make=suffix lammps=suffix2 mode=double arch=N home=path
- all args are optional and can be in any order
- make = use Makefile.suffix (def = linux.double)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
- mode = double or mixed or single (def = CUDA_PREC in makefile)
- arch = 3x (x = digit for Kepler) or 2x (x = digit for Fermi)
- (def = CUDA_ARCH in makefile)
- home = path to Cuda, e.g. /usr/local/cuda (def = CUDA_HOME in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-gpu args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-gpu args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- elif words[0] == "mode":
- self.mode = words[1]
- self.modeflag = 1
- elif words[0] == "arch":
- self.arch = words[1]
- self.archflag = 1
- elif words[0] == "home":
- self.home = words[1]
- self.homeflag = 1
- else: error("-gpu args are invalid")
- if self.modeflag and (self.mode != "double" and
- self.mode != "mixed" and
- self.mode != "single"):
- error("-gpu args are invalid")
- if self.archflag and not self.arch.isdigit():
- error("-gpu args are invalid")
-
- def build(self):
- global gpubuildflag
- gpubuildflag = 1
- libdir = dir.lib + "/gpu"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.modeflag:
- if self.mode == "double":
- make.setvar("CUDA_PRECISION","-D_DOUBLE_DOUBLE")
- elif self.mode == "mixed":
- make.setvar("CUDA_PRECISION","-D_SINGLE_DOUBLE")
- elif self.mode == "single":
- make.setvar("CUDA_PRECISION","-D_SINGLE_SINGLE")
- if self.archflag:
- make.setvar("CUDA_ARCH","-arch=sm_%s" % self.arch)
- if self.homeflag:
- make.setvar("CUDA_HOME",self.home)
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- # special hack for shannon GPU cluster
- # must use "srun make" if on it, else just make
- # this is b/c Cuda libs are not all available on host
-
- make = "make"
- if "shannon" == platform.node(): make = "srun make"
-
- subprocess.check_output("cd %s; %s -f Makefile.auto clean" %
- (libdir,make),stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; %s -j %d -f Makefile.auto" % (libdir,make,jmake.n)
- else: txt = "cd %s; %s -f Makefile.auto" % (libdir,make)
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libgpu.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/gpu library")
- else: print("Created lib/gpu library")
-
-# H5MD lib
-
-class H5MD(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "h5cc"
- self.lammpsflag = 0
-
- def help(self):
- return """
--h5md make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = h5cc)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-h5md args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-h5md args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-h5md args are invalid")
-
- def build(self):
- libdir = dir.lib + "/h5md"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make clean" % libdir,
- stderr=subprocess.STDOUT,shell=True)
- txt = "cd %s; make" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libch5md.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/h5md library")
- else: print("Created lib/h5md library")
-
-# MEAM lib
-
-class MEAM(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "gfortran"
- self.lammpsflag = 0
-
- def help(self):
- return """
--meam make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = gfortran)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-meam args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-meam args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-meam args are invalid")
-
- def build(self):
- libdir = dir.lib + "/meam"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" %
- libdir,stderr=subprocess.STDOUT,shell=True)
- # do not use -j for MEAM build, parallel build does not work
- txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libmeam.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/meam library")
- else: print("Created lib/meam library")
-
-# POEMS lib
-
-class POEMS(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "g++"
- self.lammpsflag = 0
-
- def help(self):
- return """
--poems make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = g++)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-poems args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-poems args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-poems args are invalid")
-
- def build(self):
- libdir = dir.lib + "/poems"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" % libdir,
- stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libpoems.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/poems library")
- else: print("Created lib/poems library")
-
-# PYTHON lib
-
-class PYTHON(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "g++"
- self.lammpsflag = 0
-
- def help(self):
- return """
--python lammps=suffix
- arg is optional, use Makefile.lammps if not specified
- lammps = use Makefile.lammps.suffix
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-python args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-python args are invalid")
- if words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-python args are invalid")
-
- def build(self):
- libdir = dir.lib + "/python"
- if self.lammpsflag:
- subprocess.check_output("cd %s; cp Makefile.lammps.%s Makefile.lammps" %
- (libdir,self.lammps))
- if not os.path.isfile("%s/Makefile.lammps.%s" % (libdir,self.lammps)):
- error("Unsuccessful creation of lib/python/Makefile.lammps.%s file" %
- self.lammps)
- else: print("Created lib/python/Makefile.lammps file")
-
-# QMMM lib
-
-class QMMM(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "gfortran"
- self.lammpsflag = 0
-
- def help(self):
- return """
--qmmm make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = gfortran)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-qmmm args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-qmmm args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-qmmm args are invalid")
-
- def build(self):
- libdir = dir.lib + "/qmmm"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- subprocess.check_output("cd %s; make -f Makefile.auto clean" %
- libdir,stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libqmmm.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/qmmm library")
- else: print("Created lib/qmmm library")
-
-# REAX lib
-
-class REAX(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.make = "gfortran"
- self.lammpsflag = 0
-
- def help(self):
- return """
--reax make=suffix lammps=suffix2
- all args are optional and can be in any order
- make = use Makefile.suffix (def = gfortran)
- lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile)
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-reax args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-reax args are invalid")
- if words[0] == "make": self.make = words[1]
- elif words[0] == "lammps":
- self.lammps = words[1]
- self.lammpsflag = 1
- else: error("-reax args are invalid")
-
- def build(self):
- libdir = dir.lib + "/reax"
- make = MakeReader("%s/Makefile.%s" % (libdir,self.make))
- if self.lammpsflag:
- make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps)
- make.write("%s/Makefile.auto" % libdir)
-
- cmd = "cd %s; make -f Makefile.auto clean" % libdir
- subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)
- if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n)
- else: txt = "cd %s; make -f Makefile.auto" % libdir
-
- # if verbose, print output as build proceeds, else only print if fails
-
- if verbose: subprocess.call(txt,shell=True)
- else:
- try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- except subprocess.CalledProcessError as e: print(e.output)
-
- if not os.path.isfile("%s/libreax.a" % libdir) or \
- not os.path.isfile("%s/Makefile.lammps" % libdir):
- error("Unsuccessful build of lib/reax library")
- else: print("Created lib/reax library")
-
-# VORONOI lib
-
-class VORONOI(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.install = ""
-
- def help(self):
- return """
--voronoi install="-d dir -v version -g -b -i installdir -l incdir libdir"
- arg is optional, only needed if want to run install.py script
- install = args to use with lib/voronoi/install.py script
- must enclose in quotes since install.py args have switches
- install.py can download, build, install, setup links to the Voro++ library
- see lib/voronoi/README for details on Voro++ and using install.py
-"""
-
- def check(self):
- if self.inlist != None and len(self.inlist) == 0:
- error("-voronoi args are invalid")
- for one in self.inlist:
- words = one.split('=')
- if len(words) != 2: error("-voronoi args are invalid")
- if words[0] == "install": self.install = words[1]
- else: error("-voronoi args are invalid")
-
- def build(self):
- if not self.install: return
- libdir = dir.lib + "/voronoi"
- cmd = "cd %s; python install.py %s" % (libdir,self.install)
- txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,
- shell=True).decode()
- if verbose: print(txt)
- print("Created lib/voronoi library")
-
-# ----------------------------------------------------------------
-# build classes for intel, kokkos build options
-# ----------------------------------------------------------------
-
-# Intel class
-
-class Intel(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.mode = "cpu"
-
- def help(self):
- return """
--intel mode
- mode = cpu or phi (def = cpu)
- build Intel package for CPU or Xeon Phi
-"""
-
- def check(self):
- if self.inlist == None: return
- if len(self.inlist) != 1: error("-intel args are invalid")
- self.mode = self.inlist[0]
- if self.mode != "cpu" and self.mode != "phi":
- error("-intel args are invalid")
-
-# Kokkos class
-
-class Kokkos(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.mode = ""
- self.archgpu = None
- self.archcpu = None
-
- def help(self):
- return """
--kokkos mode archgpu=N archcpu=SNB
- mode is not optional, arch is optional
- mode = omp or cuda or phi (def = KOKKOS_DEVICES setting in Makefile )
- build Kokkos package for omp or cuda or phi
- sets KOKKOS_DEVICES to "OpenMP" (omp, phi) or "Cuda, OpenMP" (cuda)
- archgpu = number like 35 (Kepler) or 21 (Fermi) (def = none)
- sets KOKKOS_ARCH for GPU to appropriate value
- archcpu = SNB or HSW or BGQ or Power7 or Power8 (def = none)
- for CPU = SandyBridge, Haswell, BGQ, Power7, Power8
- sets KOKKOS_ARCH for GPU to appropriate value
-"""
-
- def check(self):
- print(self.inlist)
- if self.inlist != None and len(self.inlist) == 0:
- error("-kokkos args are invalid")
-
- if self.inlist == None: return
- if len(self.inlist) < 1: error("-kokkos args are invalid")
- self.mode = self.inlist[0]
- if self.mode != "omp" and self.mode != "cuda" and self.mode != "phi":
- error("-kokkos args are invalid")
- for one in self.inlist[1:]:
- words = one.split('=')
- if len(words) != 2: error("-kokkos args are invalid")
- if words[0] == "archgpu": self.archgpu = words[1]
- elif words[0] == "archcpu": self.archcpu = words[1]
- else: error("-kokkos args are invalid")
-
-# ----------------------------------------------------------------
-# makefile classes for CC, FLAGS, MPI, JPG, PNG, FFT settings
-# ----------------------------------------------------------------
-
-# Cc class
-
-class Cc(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.compiler = self.abbrev = ""
- self.wrap = ""
- self.parent = ""
-
- def help(self):
- return """
--cc compiler wrap=wcompiler,parent
- alter CC setting in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- compiler is required, all other args are optional
- compiler = any string with g++ or icc or icpc
- or mpi (or mpicxx, mpiCC, mpiicpc, etc)
- can be compiler name or full path to compiler
- mpi by itself is changed to mpicxx
- wcompiler = compiler for mpi wrapper to use
- use nvcc for building for Kokkos/cuda with provided nvcc_wrapper
- parent = openmpi or mpich
- parent style determines syntax for setting low-level compiler
-"""
-
- def check(self):
- if len(self.inlist) < 1: error("-cc args are invalid")
- self.compiler = self.inlist[0]
- if self.compiler == "mpi":
- self.compiler = "mpicxx"
- self.abbrev = "mpi"
- elif self.compiler.startswith("mpi"):
- self.abbrev = "mpi"
- elif self.compiler == "g++" or self.compiler == "icc" or \
- self.compiler == "icpc":
- self.abbrev = self.compiler
- elif "mpi" in self.compiler: self.abbrev = "mpi"
- elif "g++" in self.compiler: self.abbrev = "g++"
- elif "icc" in self.compiler: self.abbrev = "icc"
- elif "icpc" in self.compiler: self.abbrev = "icpc"
- else: error("-cc args are invalid")
- for one in self.inlist[1:]:
- words = one.split('=')
- if len(words) != 2: error("-cc args are invalid")
- args = words[1].split(',')
- if len(args) != 2: error("-cc args are invalid")
- if words[0] == "wrap":
- if self.abbrev != "mpi": error("-cc compiler is not a wrapper")
- self.wrap = args[0]
- self.parent = args[1]
- else: error("-cc args are invalid")
-
-# Flags class
-
-class Flags(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.flags = []
-
- def help(self):
- return """
--flags var action N f1 f2 ... var action N f1 f2 ...
- alter variable settings (flags) in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- var = CCFLAGS, LINKFLAGS, LIB, etc
- any variable in Makefile.auto, must already exist
- action = add or del
- N = # of flags to follow
- f1,f2,etc = flag to add or delete
- "-" char will be prepended to each flag
- for example: add 4 g O3 xHost "fp-model fast=2"
- will add: -g -O3 -xHost -fp-model fast=2
- for add: if flag already exists, no change is made
- for delete: flag of form "-O*", will delete any wildcard match
- for -O,-O2,-O3,etc: existing -O* will first be removed
-"""
-
- def check(self):
- if len(self.inlist) < 1: error("-flags args are invalid")
- narg = len(self.inlist)
- i = 0
- while i < narg:
- if i+3 > narg: error("-flags args are invalid")
- var = self.inlist[i]
- action = self.inlist[i+1]
- if action != "add" and action != "del": error("-flags args are invalid")
- nflag = int(self.inlist[i+2])
- i += 3
- if i+nflag > narg: error("-flags args are invalid")
- flags = self.inlist[i:i+nflag]
- self.flags.append([var,action,flags])
- i += nflag
-
-# Mpi class
-
-class Mpi(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.style = self.dir = ""
-
- def help(self):
- return """
--mpi style dir=path
- alter MPI settings in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- style is required, all other args are optional
- style = mpi or mpich or ompi or serial
- mpi = no MPI settings (assume compiler is MPI wrapper)
- mpich = use explicit settings for MPICH
- ompi = use explicit settings for OpenMPI
- serial = use settings for src/STUBS library
- dir = path for MPICH or OpenMPI directory
- add -I and -L settings for include and lib sub-dirs
-"""
-
- def check(self):
- if len(self.inlist) < 1: error("-mpi args are invalid")
- self.style = self.inlist[0]
- if self.style != "mpi" and self.style != "mpich" and \
- self.style != "ompi" and self.style != "serial":
- error("-mpi args are invalid")
- for one in self.inlist[1:]:
- words = one.split('=')
- if len(words) != 2: error("-mpi args are invalid")
- if words[0] == "dir": self.dir = words[1]
- else: error("-mpi args are invalid")
-
-# Fft class
-
-class Fft(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.dir = self.incdir = self.libdir = ""
-
- def help(self):
- return """
--fft mode lib=libname dir=homedir idir=incdir ldir=libdir
- alter FFT settings in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- mode is required, all other args are optional
- first removes all current FFT variable settings
- mode = none or fftw or fftw3 or ...
- adds -DFFT_MODE setting
- lib = name of FFT library to link with (def is libname = mode)
- adds -llib{libname} setting, e.g. -llibfftw3
- dir = home dir for include and library files (def = none)
- adds -Idir/include and -Ldir/lib settings
- if set, overrides idir and ldir args
- idir = dir for include file (def = none)
- adds -Iidir setting
- ldir = dir for library file (def = none)
- adds -Lldir setting
-"""
-
- def check(self):
- if not len(self.inlist): error("-fft args are invalid")
- self.mode = self.inlist[0]
- self.lib = "-l%s" % self.mode
- for one in self.inlist[1:]:
- words = one.split('=')
- if len(words) != 2: error("-fft args are invalid")
- if words[0] == "lib": self.lib = "-l%s" % words[1]
- elif words[0] == "dir": self.dir = words[1]
- elif words[0] == "idir": self.incdir = words[1]
- elif words[0] == "ldir": self.libdir = words[1]
- else: error("-fft args are invalid")
-
-# Jpg class
-
-class Jpg(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.on = 1
- self.dir = self.incdir = self.libdir = ""
-
- def help(self):
- return """
--jpg flag dir=homedir idir=incdir ldir=libdir
- alter JPG settings in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- change JPG settings in makefile
- all args are optional, flag must come first if specified
- flag = yes or no (def = yes)
- include or exclude JPEG support
- adds/removes -DLAMMPS_JPEG and -ljpeg settings
- dir = home dir for include and library files (def = none)
- adds -Idir/include and -Ldir/lib settings
- if set, overrides idir and ldir args
- idir = dir for include file (def = none)
- adds -Iidir setting
- ldir = dir for library file (def = none)
- adds -Lldir setting
-"""
-
- def check(self):
- for i,one in enumerate(self.inlist):
- if one == "no" and i == 0: self.on = 0
- elif one == "yes" and i == 0: self.on = 1
- else:
- words = one.split('=')
- if len(words) != 2: error("-jpeg args are invalid")
- if words[0] == "dir": self.dir = words[1]
- elif words[0] == "idir": self.incdir = words[1]
- elif words[0] == "ldir": self.libdir = words[1]
- else: error("-jpeg args are invalid")
-
-# Png class
-
-class Png(object):
- def __init__(self,list):
- self.inlist = copy.copy(list)
- self.on = 1
- self.dir = self.incdir = self.libdir = ""
-
- def help(self):
- return """
--png flag dir=homedir idir=incdir ldir=libdir
- alter PNG settings in Makefile.auto
- only happens if new Makefile.auto is created by use of "file" action
- all args are optional, flag must come first if specified
- flag = yes or no (def = yes)
- include or exclude PNG support
- adds/removes -DLAMMPS_PNG and -lpng settings
- dir = home dir for include and library files (def = none)
- adds -Idir/include and -Ldir/lib settings
- if set, overrides idir and ldir args
- idir = dir for include file (def = none)
- adds -Iidir setting
- ldir = dir for library file (def = none)
- adds -Lldir setting
-"""
-
- def check(self):
- for i,one in enumerate(self.inlist):
- if one == "no" and i == 0: self.on = 0
- elif one == "yes" and i == 0: self.on = 1
- else:
- words = one.split('=')
- if len(words) != 2: error("-png args are invalid")
- if words[0] == "dir": self.dir = words[1]
- elif words[0] == "idir": self.incdir = words[1]
- elif words[0] == "ldir": self.libdir = words[1]
- else: error("-png args are invalid")
-
-# ----------------------------------------------------------------
-# auxiliary classes
-# ----------------------------------------------------------------
-
-# read, tweak, and write a Makefile
-
-class MakeReader(object):
-
- # read a makefile
- # flag = 0 if file is full path name
- # flag = 1,2 if file is suffix for any Makefile.machine under src/MAKE
- # look for this file in same order that src/Makefile does
- # if flag = 1, read the file
- # if flag = 2, just check if file exists
-
- def __init__(self,file,flag=0):
- if flag == 0:
- if not os.path.isfile(file): error("Makefile %s does not exist" % file)
- lines = open(file,'r').readlines()
- else:
- mfile = "%s/MAKE/MINE/Makefile.%s" % (dir.src,file)
- if not os.path.isfile(mfile):
- mfile = "%s/MAKE/Makefile.%s" % (dir.src,file)
- if not os.path.isfile(mfile):
- mfile = "%s/MAKE/OPTIONS/Makefile.%s" % (dir.src,file)
- if not os.path.isfile(mfile):
- mfile = "%s/MAKE/MACHINES/Makefile.%s" % (dir.src,file)
- if not os.path.isfile(mfile):
- error("Makefile.%s does not exist" % file)
- if flag == 1: lines = open(mfile,'r').readlines()
- else: return
-
- # scan lines of makefile
- # if not a variable line, just copy to newlines
- # if a variable line, concatenate any continuation lines
- # convert variable to var dict entry: key = name, value = list of words
- # discard any portion of value string with a comment char
- # varinfo = list of variable info: (name, name with whitespace for print)
- # add index into varinfo to newlines
- # ccindex = index of "CC =" line, to add OMPI var before it
- # lmpindex = index of "LAMMPS-specific settings"
- # line to add KOKKOS vars before it
-
- var = {}
- varinfo = []
- newlines = []
- pattern = "(\S+\s+=\s+)(.*)"
- conditional = 0
- multiline = 0
- self.ccindex = self.lmpindex = 0
-
- for line in lines:
- line = line[:-1]
- if "CC =" in line: self.ccindex = len(newlines)
- if "LAMMPS-specific settings" in line: self.lmpindex = len(newlines)
- if "ifeq" in line:
- conditional = 1
- continue
- if conditional:
- if "endif" in line:
- conditional = 0
- continue
- if multiline:
- if '#' in line: line = line[:line.find('#')]
- morevalues = line.split()
- values = values[:-1] + morevalues
- if values[-1] != '\\':
- var[name] = values
- multiline = 0
- newlines.append(str(len(varinfo)))
- varinfo.append((name,namewhite))
- continue
- varflag = 1
- if len(line.strip()) == 0: varflag = 0
- elif line.lstrip()[0] == '#': varflag = 0
- else:
- m = re.match(pattern,line)
- if not m: varflag = 0
- if varflag:
- namewhite = m.group(1)
- name = namewhite.split()[0]
- if name in var:
- error("Makefile variable %s appears more than once" % name)
- remainder = m.group(2)
- if '#' in remainder: remainder = remainder[:remainder.find('#')]
- values = remainder.split()
- if values and values[-1] == '\\': multiline = 1
- else:
- var[name] = values
- newlines.append(str(len(varinfo)))
- varinfo.append((name,namewhite))
- else:
- newlines.append(line)
-
- self.var = var
- self.varinfo = varinfo
- self.lines = newlines
-
- # return list of values associated with var
- # return None if var not defined
-
- def getvar(self,var):
- if var in self.var: return self.var[var]
- else: return None
-
- # set var to single value
- # if var not defined, error
-
- def setvar(self,var,value):
- if var not in self.var: error("Variable %s not in makefile" % var)
- self.var[var] = [value]
-
- # add value to var
- # do not add if value already defined by var
- # if var not defined,
- # create new variable using "where"
- # where="cc", line before "CC =" line, use ":="
- # where="lmp", 2 lines before "LAMMPS-specific settings" line, use "="
-
- def addvar(self,var,value,where=""):
- if var in self.var:
- if value not in self.var[var]: self.var[var].append(value)
- else:
- if not where:
- error("Variable %s with value %s is not in makefile" % (var,value))
- if where == "cc":
- if not self.ccindex: error("No 'CC =' line in makefile to add variable")
- index = self.ccindex
- varwhite = "%s :=\t\t" % var
- elif where == "lmp":
- if not self.lmpindex: error("No 'LAMMPS-specific settings line' " +
- "in makefile to add variable")
- index = self.lmpindex - 2
- varwhite = "%s =\t\t" % var
- self.var[var] = [value]
- varwhite = "%s =\t\t" % var
- self.lines.insert(index,str(len(self.varinfo)))
- self.varinfo.append((var,varwhite))
-
- # if value = None, remove entire var
- # no need to update lines or varinfo, write() will ignore deleted vars
- # else remove value from var
- # value can have trailing '*' to remove wildcard match
- # if var or value not defined, ignore it
-
- def delvar(self,var,value=None):
- #if var == "KOKKOS_DEVICES":
- # print self.var,value
- if var not in self.var: return
- if not value:
- del self.var[var]
- #print "AGAIN",self.var
- elif value and value[-1] != '*':
- if value not in self.var[var]: return
- self.var[var].remove(value)
- else:
- value = value[:-1]
- values = self.var[var]
- dellist = []
- for i,one in enumerate(values):
- if one.startswith(value): dellist.append(i)
- while dellist: values.pop(dellist.pop())
- self.var[var] = values
-
- # write stored makefile lines to file, using vars that may have been updated
- # do not write var if not in dict, since has been deleted
- # wrap var values into multiple lines if needed
- # file = 1 if this is Makefile.auto, change 1st line to use "auto"
-
- def write(self,file,flag=0):
- fp = open(file,'w')
- for i,line in enumerate(self.lines):
- if not line.isdigit():
- if flag and i == 0:
- line = "# auto = makefile auto-generated by Make.py"
- print(line, file=fp)
- else:
- index = int(line)
- name = self.varinfo[index][0]
- txt = self.varinfo[index][1]
- if name not in self.var: continue
- values = self.var[name]
- print("%s%s" % (txt,' '.join(values)), file=fp)
-
-# ----------------------------------------------------------------
-# main program
-# ----------------------------------------------------------------
-
-# parse command-line args
-# switches dict: key = switch letter, value = list of args
-# switch_order = list of switches in order
-# will possibly be merged with redo file args below
-
-cmd_switches,cmd_switch_order = parse_args(sys.argv[1:])
-
-if "v" in cmd_switches:
- # debug
- #print "Command-line parsing:"
- #for switch in cmd_switch_order:
- # print " %s: %s" % (switch,' '.join(cmd_switches[switch]))
- pass
-
-# check for redo switch, process redo file
-# redolist = list of commands to execute
-
-redoflag = 0
-redolist = []
-
-if 'r' in cmd_switches and 'h' not in cmd_switches:
- redoflag = 1
- redo = Redo(cmd_switches['r'])
- redo.check()
- redo.setup()
- redolist = redo.commands
- redoindex = 0
- del redo
- if not redolist: error("No commands to execute from redo file")
-
-# loop over Make.py commands
-# if no redo switch, loop once for command-line command
-# if redo, loop over one or more commands from redo file
-
-while 1:
-
- # if redo:
- # parse next command from redo file
- # use command-line switches to add/replace file command switches
- # do not add -r, since already processed
- # and don't want -r swtich to appear in Make.py.last file
- # if -a in both: concatenate, de-dup,
- # specified exe/machine action replaces file exe/machine action
- # print resulting new command
- # else just use command-line switches
-
- if redoflag:
- if redoindex == len(redolist): break
- args = redolist[redoindex].split()
- switches,switch_order = parse_args(args)
- redoindex += 1
-
- for switch in cmd_switches:
- if switch == 'r': continue
- if switch == 'a' and switch in switches:
- tmp = Actions(cmd_switches[switch] + switches[switch])
- tmp.dedup()
- switches[switch] = tmp.inlist
- continue
- if switch not in switches: switch_order.append(switch)
- switches[switch] = cmd_switches[switch]
-
- argstr = switch2str(switches,switch_order)
- print("Redo command: Make.py",argstr)
- else:
- switches = cmd_switches
- switch_order = cmd_switch_order
-
- # initialize all class variables to None
-
- for one in switchclasses: exec("%s = None" % one)
- for one in libclasses: exec("%s = None" % one)
- for one in buildclasses: exec("%s = None" % one)
- for one in makeclasses: exec("%s = None" % one)
-
- # classes = dictionary of created classes
- # key = switch, value = class instance
-
- classes = {}
- for switch in switches:
- if len(switch) == 1 and switch in abbrevs:
- i = abbrevs.index(switch)
- txt = '%s = classes["%s"] = %s(switches["%s"])' % \
- (switchclasses[i],switch,switchclasses[i].capitalize(),switch)
- exec(txt)
- elif switch in libclasses:
- i = libclasses.index(switch)
- txt = '%s = classes["%s"] = %s(switches["%s"])' % \
- (libclasses[i],switch,libclasses[i].upper(),switch)
- exec(txt)
- elif switch in buildclasses:
- i = buildclasses.index(switch)
- txt = '%s = classes["%s"] = %s(switches["%s"])' % \
- (buildclasses[i],switch,buildclasses[i].capitalize(),switch)
- exec(txt)
- elif switch in makeclasses:
- i = makeclasses.index(switch)
- txt = '%s = classes["%s"] = %s(switches["%s"])' % \
- (makeclasses[i],switch,makeclasses[i].capitalize(),switch)
- exec(txt)
- else: error("Unknown command-line switch -%s" % switch)
-
- # print help messages and exit
-
- if help or (actions and "-h" in actions.inlist) or not switches:
- if not help: help = Help(None)
- print(help.help())
- for switch in switch_order:
- if switch == "h": continue
- print(classes[switch].help()[1:])
- sys.exit()
-
- # create needed default classes if not specified with switch
- # dir and packages plus lib and build classes so defaults are set
-
- if not dir: dir = Dir(None)
- if not packages: packages = Packages(None)
-
- for one in libclasses:
- txt = "if not %s: %s = %s(None)" % (one,one,one.upper())
- exec(txt)
-
- for one in buildclasses:
- txt = "if not %s: %s = %s(None)" % (one,one,one.capitalize())
- exec(txt)
-
- # error check on args for all classes
-
- for switch in classes: classes[switch].check()
-
- # prep for action
- # actions.setup() detects if last action = machine
- # if yes, induce addition of "-m" and "-o" switches
-
- dir.setup()
- packages.setup()
-
- if actions:
- machine = actions.setup()
- if machine:
- switches['a'][-1] = "exe"
- if 'm' not in switches:
- switches['m'] = [machine]
- switch_order.insert(-1,'m')
- makefile = classes['m'] = Makefile(switches['m'])
- makefile.check()
- if 'o' not in switches:
- switches['o'] = [machine]
- switch_order.insert(-1,'o')
- output = classes['o'] = Output(switches['o'])
- output.check()
-
- # perform actions
-
- packages.install()
-
- if actions:
- for action in actions.alist:
- print("Action %s ..." % action)
- if action.startswith("lib-"): actions.lib(action[4:])
- elif action == "file": actions.file("file")
- elif action == "clean": actions.clean()
- elif action == "exe": actions.exe()
-
- packages.uninstall()
-
- # create copy of executable if requested, and exe action performed
-
- if output and actions and "exe" in actions.alist:
- txt = "cp %s/lmp_auto %s/lmp_%s" % (dir.src,dir.cwd,output.machine)
- subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- print("Created lmp_%s in %s" % (output.machine,dir.cwd))
-
- # create copy of Makefile.auto if requested, and file or exe action performed
- # ditto for library Makefile.auto and Makefile.lammps files
-
- if zoutput and actions and \
- ("file" in actions.alist or "exe" in actions.alist):
- txt = "cp %s/MAKE/MINE/Makefile.auto %s/MAKE/MINE/Makefile.%s" % \
- (dir.src,dir.src,zoutput.machine)
- subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- print("Created Makefile.%s in %s/MAKE/MINE" % (zoutput.machine,dir.src))
- if gpubuildflag:
- txt = "cp %s/gpu/Makefile.auto %s/MAKE/MINE/Makefile_gpu.%s" % \
- (dir.lib,dir.src,zoutput.machine)
- subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- print("Created Makefile_gpu.%s in %s/MAKE/MINE" % \
- (zoutput.machine,dir.src))
- txt = "cp %s/gpu/Makefile.lammps %s/MAKE/MINE/Makefile_gpu_lammps.%s" % \
- (dir.lib,dir.src,zoutput.machine)
- subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True)
- print("Created Makefile_gpu_lammps.%s in %s/MAKE/MINE" % \
- (zoutput.machine,dir.src))
-
- # write current Make.py command to src/Make.py.last
-
- fp = open("%s/Make.py.last" % dir.src,'w')
- print("# last invoked Make.py command", file=fp)
- print(switch2str(switches,switch_order), file=fp)
- fp.close()
-
- # if not redoflag, done
-
- if not redoflag: break
diff --git a/src/PERI/fix_peri_neigh.cpp b/src/PERI/fix_peri_neigh.cpp
index a84ce3160..d92f355c5 100644
--- a/src/PERI/fix_peri_neigh.cpp
+++ b/src/PERI/fix_peri_neigh.cpp
@@ -1,646 +1,652 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Mike Parks (SNL), Ezwanur Rahman, J.T. Foster (UTSA)
------------------------------------------------------------------------- */
#include <math.h>
#include "fix_peri_neigh.h"
#include "pair_peri_pmb.h"
#include "pair_peri_lps.h"
#include "pair_peri_ves.h"
#include "pair_peri_eps.h"
#include "atom.h"
#include "domain.h"
#include "force.h"
#include "comm.h"
#include "update.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "pair.h"
#include "lattice.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixPeriNeigh::FixPeriNeigh(LAMMPS *lmp,int narg, char **arg) :
Fix(lmp, narg, arg)
{
isPMB = isLPS = isVES = isEPS = 0;
if (force->pair_match("peri/pmb",1)) isPMB = 1;
if (force->pair_match("peri/lps",1)) isLPS = 1;
if (force->pair_match("peri/ves",1)) isVES = 1;
if (force->pair_match("peri/eps",1)) isEPS = 1;
restart_global = 1;
restart_peratom = 1;
first = 1;
// perform initial allocation of atom-based arrays
// register with atom class
// set maxpartner = 1 as placeholder
maxpartner = 1;
npartner = NULL;
partner = NULL;
deviatorextention = NULL;
deviatorBackextention = NULL;
deviatorPlasticextension = NULL;
lambdaValue = NULL;
r0 = NULL;
vinter = NULL;
wvolume = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
atom->add_callback(1);
// initialize npartner to 0 so atom migration is OK the 1st time
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) npartner[i] = 0;
// set comm sizes needed by this fix
comm_forward = 1;
}
/* ---------------------------------------------------------------------- */
FixPeriNeigh::~FixPeriNeigh()
{
// unregister this fix so atom class doesn't invoke it any more
atom->delete_callback(id,0);
atom->delete_callback(id,1);
// delete locally stored arrays
memory->destroy(npartner);
memory->destroy(partner);
memory->destroy(deviatorextention);
memory->destroy(deviatorBackextention);
memory->destroy(deviatorPlasticextension);
memory->destroy(lambdaValue);
memory->destroy(r0);
memory->destroy(vinter);
memory->destroy(wvolume);
}
/* ---------------------------------------------------------------------- */
int FixPeriNeigh::setmask()
{
int mask = 0;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixPeriNeigh::init()
{
if (!first) return;
// need a full neighbor list once
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->occasional = 1;
// compute PD scale factor, stored in Atom class, used by DumpCFG
int nlocal = atom->nlocal;
double vone = 0.0;
for (int i = 0; i < nlocal; i++) vone += atom->vfrac[i];
double vave;
MPI_Allreduce(&vone,&vave,1,MPI_DOUBLE,MPI_SUM,world);
if (atom->natoms) vave /= atom->natoms;
if (vave > 0.0) atom->pdscale = 1.44 / pow(vave,1.0/3.0);
else atom->pdscale = 1.0;
}
/* ---------------------------------------------------------------------- */
void FixPeriNeigh::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ----------------------------------------------------------------------
For minimization: setup as with dynamics
------------------------------------------------------------------------- */
void FixPeriNeigh::min_setup(int vflag)
{
setup(vflag);
}
/* ----------------------------------------------------------------------
create initial list of neighbor partners via call to neighbor->build()
must be done in setup (not init) since fix init comes before neigh init
------------------------------------------------------------------------- */
void FixPeriNeigh::setup(int vflag)
{
int i,j,ii,jj,itype,jtype,inum,jnum;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *ilist,*jlist,*numneigh;
int **firstneigh;
double **x = atom->x;
double *vfrac = atom->vfrac;
int *type = atom->type;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
// only build list of bonds on very first run
if (!first) return;
first = 0;
// build full neighbor list, will copy or build as necessary
neighbor->build_one(list);
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// scan neighbor list to set maxpartner
Pair *anypair = force->pair_match("peri",0);
double **cutsq = anypair->cutsq;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq <= cutsq[itype][jtype]) npartner[i]++;
}
}
maxpartner = 0;
for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]);
int maxall;
MPI_Allreduce(&maxpartner,&maxall,1,MPI_INT,MPI_MAX,world);
maxpartner = maxall;
// realloc arrays with correct value for maxpartner
memory->destroy(partner);
memory->destroy(deviatorextention);
memory->destroy(deviatorBackextention);
memory->destroy(deviatorPlasticextension);
memory->destroy(lambdaValue);
memory->destroy(r0);
memory->destroy(npartner);
npartner = NULL;
partner = NULL;
deviatorextention = NULL;
deviatorBackextention = NULL;
deviatorPlasticextension = NULL;
lambdaValue = NULL;
r0 = NULL;
grow_arrays(atom->nmax);
// create partner list and r0 values from neighbor list
// compute vinter for each atom
for (i = 0; i < nlocal; i++) {
npartner[i] = 0;
vinter[i] = 0.0;
wvolume[i] = 0.0;
if (isEPS) lambdaValue[i] = 0.0;
}
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq <= cutsq[itype][jtype]) {
partner[i][npartner[i]] = tag[j];
if (isVES)
deviatorextention[i][npartner[i]] =
deviatorBackextention[i][npartner[i]] = 0.0;
if (isEPS)
deviatorPlasticextension[i][npartner[i]] = 0.0;
r0[i][npartner[i]] = sqrt(rsq);
npartner[i]++;
vinter[i] += vfrac[j];
}
}
}
// sanity check: does any atom appear twice in any neigborlist?
// should only be possible if using pbc and domain < 2*delta
if (domain->xperiodic || domain->yperiodic || domain->zperiodic) {
for (i = 0; i < nlocal; i++) {
jnum = npartner[i];
for (jj = 0; jj < jnum; jj++) {
for (int kk = jj+1; kk < jnum; kk++) {
if (partner[i][jj] == partner[i][kk])
error->one(FLERR,"Duplicate particle in PeriDynamic bond - "
"simulation box is too small");
}
}
}
}
// compute wvolume for each atom
double **x0 = atom->x0;
double half_lc = 0.5*(domain->lattice->xlattice);
double vfrac_scale;
- PairPeriLPS *pairlps = static_cast<PairPeriLPS*>(anypair);
- PairPeriVES *pairves = static_cast<PairPeriVES*>(anypair);
- PairPeriEPS *paireps = static_cast<PairPeriEPS*>(anypair);
+ PairPeriLPS *pairlps = NULL;
+ PairPeriVES *pairves = NULL;
+ PairPeriEPS *paireps = NULL;
+ if (isLPS)
+ pairlps = static_cast<PairPeriLPS*>(anypair);
+ else if (isVES)
+ pairves = static_cast<PairPeriVES*>(anypair);
+ else if (isEPS)
+ paireps = static_cast<PairPeriEPS*>(anypair);
for (i = 0; i < nlocal; i++) {
double xtmp0 = x0[i][0];
double ytmp0 = x0[i][1];
double ztmp0 = x0[i][2];
jnum = npartner[i];
itype = type[i];
// loop over partners of particle i
for (jj = 0; jj < jnum; jj++) {
// if bond already broken, skip this partner
if (partner[i][jj] == 0) continue;
// lookup local index of partner particle
j = atom->map(partner[i][jj]);
// skip if particle is "lost"
if (j < 0) continue;
double delx0 = xtmp0 - x0[j][0];
double dely0 = ytmp0 - x0[j][1];
double delz0 = ztmp0 - x0[j][2];
double rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0;
jtype = type[j];
double delta = sqrt(cutsq[itype][jtype]);
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
// for PMB, influence = 1.0, otherwise invoke influence function
if (isPMB)
wvolume[i] += 1.0 * rsq0 * vfrac[j] * vfrac_scale;
else if (isLPS)
wvolume[i] += pairlps->influence_function(delx0,dely0,delz0) *
rsq0 * vfrac[j] * vfrac_scale;
else if (isVES)
wvolume[i] += pairves->influence_function(delx0,dely0,delz0) *
rsq0 * vfrac[j] * vfrac_scale;
else if (isEPS)
wvolume[i] += paireps->influence_function(delx0,dely0,delz0) *
rsq0 * vfrac[j] * vfrac_scale;
}
}
// communicate wvolume to ghosts
comm->forward_comm_fix(this);
// bond statistics
int n = 0;
for (i = 0; i < nlocal; i++) n += npartner[i];
int nall;
MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world);
if (comm->me == 0) {
if (screen) {
fprintf(screen,"Peridynamic bonds:\n");
fprintf(screen," total # of bonds = %d\n",nall);
fprintf(screen," bonds/atom = %g\n",(double)nall/atom->natoms);
}
if (logfile) {
fprintf(logfile,"Peridynamic bonds:\n");
fprintf(logfile," total # of bonds = %d\n",nall);
fprintf(logfile," bonds/atom = %g\n",(double)nall/atom->natoms);
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixPeriNeigh::memory_usage()
{
int nmax = atom->nmax;
int bytes = nmax * sizeof(int);
bytes += nmax*maxpartner * sizeof(tagint);
bytes += nmax*maxpartner * sizeof(double);
if (isVES) {
bytes += nmax*maxpartner * sizeof(double);
bytes += nmax*maxpartner * sizeof(double);
}
if (isEPS) {
bytes += nmax*maxpartner * sizeof(double);
bytes += nmax * sizeof(double);
}
bytes += nmax * sizeof(double);
bytes += nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixPeriNeigh::grow_arrays(int nmax)
{
memory->grow(npartner,nmax,"peri_neigh:npartner");
memory->grow(partner,nmax,maxpartner,"peri_neigh:partner");
if (isVES) {
memory->grow(deviatorextention,nmax,maxpartner,
"peri_neigh:deviatorextention");
memory->grow(deviatorBackextention,nmax,maxpartner,
"peri_neigh:deviatorBackextention");
}
if (isEPS) memory->grow(deviatorPlasticextension,nmax,maxpartner,
"peri_neigh:deviatorPlasticextension");
memory->grow(r0,nmax,maxpartner,"peri_neigh:r0");
if (isEPS) memory->grow(lambdaValue,nmax,"peri_neigh:lambdaValue");
memory->grow(vinter,nmax,"peri_neigh:vinter");
memory->grow(wvolume,nmax,"peri_neigh:wvolume");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixPeriNeigh::copy_arrays(int i, int j, int delflag)
{
npartner[j] = npartner[i];
for (int m = 0; m < npartner[j]; m++) {
partner[j][m] = partner[i][m];
if (isVES) {
deviatorextention[j][m] = deviatorextention[i][m];
deviatorBackextention[j][m] = deviatorBackextention[i][m];
}
if (isEPS)
deviatorPlasticextension[j][m] = deviatorPlasticextension[i][m];
r0[j][m] = r0[i][m];
}
if (isEPS) lambdaValue[j] = lambdaValue[i];
vinter[j] = vinter[i];
wvolume[j] = wvolume[i];
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixPeriNeigh::pack_exchange(int i, double *buf)
{
// compact list by eliminating partner = 0 entries
// set buf[0] after compaction
int m = 1;
for (int n = 0; n < npartner[i]; n++) {
if (partner[i][n] == 0) continue;
buf[m++] = partner[i][n];
if (isVES) {
buf[m++] = deviatorextention[i][n];
buf[m++] = deviatorBackextention[i][n];
}
if (isEPS) buf[m++] = deviatorPlasticextension[i][n];
buf[m++] = r0[i][n];
}
if (isVES) buf[0] = m/4;
else if (isEPS) buf[0] = m/3;
else buf[0] = m/2;
if (isEPS) buf[m++] = lambdaValue[i];
buf[m++] = vinter[i];
buf[m++] = wvolume[i];
return m;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixPeriNeigh::unpack_exchange(int nlocal, double *buf)
{
int m = 0;
npartner[nlocal] = static_cast<int> (buf[m++]);
for (int n = 0; n < npartner[nlocal]; n++) {
partner[nlocal][n] = static_cast<tagint> (buf[m++]);
if (isVES) {
deviatorextention[nlocal][n] = buf[m++];
deviatorBackextention[nlocal][n] = buf[m++];
}
if (isEPS) deviatorPlasticextension[nlocal][n] = buf[m++];
r0[nlocal][n] = buf[m++];
}
if (isEPS) lambdaValue[nlocal] = buf[m++];
vinter[nlocal] = buf[m++];
wvolume[nlocal] = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
int FixPeriNeigh::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = wvolume[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void FixPeriNeigh::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
wvolume[i] = buf[m++];
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixPeriNeigh::write_restart(FILE *fp)
{
int n = 0;
double list[2];
list[n++] = first;
list[n++] = maxpartner;
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size,sizeof(int),1,fp);
fwrite(list,sizeof(double),n,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixPeriNeigh::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
first = static_cast<int> (list[n++]);
maxpartner = static_cast<int> (list[n++]);
// grow 2D arrays now, cannot change size of 2nd array index later
grow_arrays(atom->nmax);
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixPeriNeigh::pack_restart(int i, double *buf)
{
int m = 0;
if (isVES) buf[m++] = 4*npartner[i] + 4;
else if (isEPS) buf[m++] = 3*npartner[i] + 5;
else buf[m++] = 2*npartner[i] + 4;
buf[m++] = npartner[i];
for (int n = 0; n < npartner[i]; n++) {
buf[m++] = partner[i][n];
if (isVES) {
buf[m++] = deviatorextention[i][n];
buf[m++] = deviatorBackextention[i][n];
}
if (isEPS) buf[m++] = deviatorPlasticextension[i][n];
buf[m++] = r0[i][n];
}
if (isEPS) buf[m++] = lambdaValue[i];
buf[m++] = vinter[i];
buf[m++] = wvolume[i];
return m;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixPeriNeigh::unpack_restart(int nlocal, int nth)
{
double **extra = atom->extra;
// skip to Nth set of extra values
int m = 0;
for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]);
m++;
npartner[nlocal] = static_cast<int> (extra[nlocal][m++]);
for (int n = 0; n < npartner[nlocal]; n++) {
partner[nlocal][n] = static_cast<tagint> (extra[nlocal][m++]);
if (isVES) {
deviatorextention[nlocal][n] = extra[nlocal][m++];
deviatorBackextention[nlocal][n] = extra[nlocal][m++];
}
if (isEPS) deviatorPlasticextension[nlocal][n] = extra[nlocal][m++];
r0[nlocal][n] = extra[nlocal][m++];
}
if (isEPS) lambdaValue[nlocal] = extra[nlocal][m++];
vinter[nlocal] = extra[nlocal][m++];
wvolume[nlocal] = extra[nlocal][m++];
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixPeriNeigh::maxsize_restart()
{
if (isVES) return 4*maxpartner + 4;
if (isEPS) return 3*maxpartner + 5;
return 2*maxpartner + 4;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixPeriNeigh::size_restart(int nlocal)
{
if (isVES) return 4*npartner[nlocal] + 4;
if (isEPS) return 3*npartner[nlocal] + 5;
return 2*npartner[nlocal] + 4;
}
diff --git a/src/PERI/pair_peri_eps.cpp b/src/PERI/pair_peri_eps.cpp
index b5807c0e3..670e1d693 100644
--- a/src/PERI/pair_peri_eps.cpp
+++ b/src/PERI/pair_peri_eps.cpp
@@ -1,826 +1,825 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Rezwanur Rahman, John Foster (UTSA)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "pair_peri_eps.h"
#include "atom.h"
#include "domain.h"
#include "lattice.h"
#include "force.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "fix_peri_neigh.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
#include "update.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairPeriEPS::PairPeriEPS(LAMMPS *lmp) : Pair(lmp)
{
for (int i = 0; i < 6; i++) virial[i] = 0.0;
no_virial_fdotr_compute = 1;
single_enable = 0;
ifix_peri = -1;
- nmax = 0;
+ nmax = -1;
s0_new = NULL;
theta = NULL;
bulkmodulus = NULL;
shearmodulus = NULL;
s00 = alpha = NULL;
cut = NULL;
m_yieldstress = NULL;
// set comm size needed by this Pair
// comm_reverse not needed
comm_forward = 1;
}
/* ---------------------------------------------------------------------- */
PairPeriEPS::~PairPeriEPS()
{
if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH");
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(bulkmodulus);
memory->destroy(shearmodulus);
memory->destroy(s00);
memory->destroy(alpha);
memory->destroy(cut);
memory->destroy(m_yieldstress);
memory->destroy(theta);
memory->destroy(s0_new);
}
}
/* ---------------------------------------------------------------------- */
void PairPeriEPS::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0;
double rsq,r,dr,rk,rkNew,evdwl,fpair,fbond;
double fbondElastoPlastic,fbondFinal;
double deltalambda,edpNp1;
int *ilist,*jlist,*numneigh,**firstneigh;
double d_ij,delta,stretch;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = eflag_global = eflag_atom = 0;
double **f = atom->f;
double **x = atom->x;
int *type = atom->type;
int nlocal = atom->nlocal;
double *vfrac = atom->vfrac;
double *s0 = atom->s0;
double **x0 = atom->x0;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
double **deviatorPlasticextension =
((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorPlasticextension;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
double *lambdaValue = ((FixPeriNeigh *) modify->fix[ifix_peri])->lambdaValue;
// lc = lattice constant
// init_style guarantees it's the same in x, y, and z
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double vfrac_scale = 1.0;
// short-range forces
int newton_pair = force->newton_pair;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
// need minimg() for x0 difference since not ghosted
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0;
jtype = type[j];
r = sqrt(rsq);
// short-range interaction distance based on initial particle position
// 0.9 and 1.35 are constants
d_ij = MIN(0.9*sqrt(rsq0),1.35*lc);
// short-range contact forces
// 15 is constant taken from the EMU Theory Manual
// Silling, 12 May 2005, p 18
if (r < d_ij) {
dr = r - d_ij;
// kshort based upon short-range force constant
// of the bond-based theory used in PMB model
double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) /
(3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]);
rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]);
if (r > 0.0) fpair = -(rk/r);
else fpair = 0.0;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) evdwl = 0.5*rk*dr;
if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,
fpair*vfrac[i],delx,dely,delz);
}
}
}
// grow bond forces array if necessary
int maxpartner = 0;
for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]);
- if (atom->nmax > nmax) {
+ if (nlocal > nmax) {
memory->destroy(s0_new);
memory->destroy(theta);
nmax = atom->nmax;
memory->create(s0_new,nmax,"pair:s0_new");
memory->create(theta,nmax,"pair:theta");
}
// ******** temp array to store Plastic extension *********** ///
// create on heap to reduce stack use and to allow for faster zeroing
- double **deviatorPlasticExtTemp;
- memory->create(deviatorPlasticExtTemp,nlocal,maxpartner,"pair:plastext");
- memset(&(deviatorPlasticExtTemp[0][0]),0,sizeof(double)*nlocal*maxpartner);
+ double **deviatorPlasticExtTemp = NULL;
+ if (nlocal*maxpartner > 0) {
+ memory->create(deviatorPlasticExtTemp,nlocal,maxpartner,"pair:plastext");
+ memset(&(deviatorPlasticExtTemp[0][0]),0,sizeof(double)*nlocal*maxpartner);
+ }
// ******** temp array to store Plastic extension *********** ///
-
-
// compute the dilatation on each particle
compute_dilatation();
// communicate dilatation (theta) of each particle
comm->forward_comm_pair(this);
// communicate weighted volume (wvolume) upon every reneighbor
if (neighbor->ago == 0)
comm->forward_comm_fix(modify->fix[ifix_peri]);
// volume-dependent part of the energy
if (eflag) {
for (i = 0; i < nlocal; i++) {
itype = type[i];
if (eflag_global)
eng_vdwl += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]);
if (eflag_atom)
eatom[i] += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]);
}
}
// loop over my particles and their partners
// partner list contains all bond partners, so I-J appears twice
// if bond already broken, skip this partner
// first = true if this is first neighbor of particle i
bool first;
double omega_minus, omega_plus;
for (i = 0; i < nlocal; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jnum = npartner[i];
first = true;
double yieldStress = m_yieldstress[itype][itype];
double horizon = cut[itype][itype];
double tdnorm = compute_DeviatoricForceStateNorm(i);
double pointwiseYieldvalue = 25.0 * yieldStress *
yieldStress / 8 / M_PI / pow(horizon,5);
double fsurf = (tdnorm * tdnorm)/2 - pointwiseYieldvalue;
bool elastic = true;
- double alphavalue = (15 * shearmodulus[itype][itype]) /wvolume[i];
-
-
- if (fsurf>0) {
+ if (fsurf > 0) {
elastic = false;
- deltalambda = ((tdnorm /sqrt(2.0 * pointwiseYieldvalue)) - 1.0) / alphavalue;
+ deltalambda = ((tdnorm /sqrt(2.0 * pointwiseYieldvalue)) - 1.0) * wvolume[i]
+ / (15 * shearmodulus[itype][itype]);
double templambda = lambdaValue[i];
lambdaValue[i] = templambda + deltalambda;
}
for (jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
j = atom->map(partner[i][jj]);
// check if lost a partner without first breaking bond
if (j < 0) {
partner[i][jj] = 0;
continue;
}
// compute force density, add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
jtype = type[j];
delta = cut[itype][jtype];
r = sqrt(rsq);
dr = r - r0[i][jj];
// avoid roundoff errors
if (fabs(dr) < 2.2204e-016) {
dr = 0.0;
}
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0);
omega_minus = influence_function(delx0,dely0,delz0);
//Elastic Part
rk = ((3.0 * bulkmodulus[itype][itype]) * ( (omega_plus * theta[i] / wvolume[i]) +
( omega_minus * theta[j] / wvolume[j] ) ) ) * r0[i][jj];
if (r > 0.0) fbond = -((rk/r) * vfrac[j] * vfrac_scale);
else fbond = 0.0;
//Plastic part
double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0);
edpNp1 = deviatorPlasticextension[i][jj];
double tdtrialValue = ( 15 * shearmodulus[itype][itype]) *
( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) *
(deviatoric_extension - edpNp1);
- if(elastic) {
+ if (elastic) {
rkNew = tdtrialValue;
- }
- else {
+ } else {
rkNew = (sqrt(2.0*pointwiseYieldvalue) * tdtrialValue) / tdnorm;
deviatorPlasticExtTemp[i][jj] = edpNp1 + rkNew * deltalambda;
}
if (r > 0.0) fbondElastoPlastic = -((rkNew/r) * vfrac[j] * vfrac_scale);
else fbondElastoPlastic = 0.0;
// total Force state: elastic + plastic
fbondFinal=fbond+fbondElastoPlastic;
fbond=fbondFinal;
f[i][0] += delx*fbond;
f[i][1] += dely*fbond;
f[i][2] += delz*fbond;
// since I-J is double counted, set newton off & use 1/2 factor and I,I
if (eflag) evdwl = (0.5 * 15 * shearmodulus[itype][itype]/wvolume[i] *
omega_plus * (deviatoric_extension - edpNp1) *
(deviatoric_extension-edpNp1)) * vfrac[j] * vfrac_scale;
if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0,
0.5*fbond*vfrac[i],delx,dely,delz);
// find stretch in bond I-J and break if necessary
// use s0 from previous timestep
stretch = dr / r0[i][jj];
if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0;
// update s0 for next timestep
if (first)
s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch);
else
s0_new[i] = MAX(s0_new[i],s00[itype][jtype] -
(alpha[itype][jtype] * stretch));
first = false;
}
}
// store new s0
memcpy(s0,s0_new,sizeof(double)*nlocal);
- memcpy(&(deviatorPlasticextension[0][0]),
- &(deviatorPlasticExtTemp[0][0]),
- sizeof(double)*nlocal*maxpartner);
- memory->destroy(deviatorPlasticExtTemp);
+ if (nlocal*maxpartner > 0) {
+ memcpy(&(deviatorPlasticextension[0][0]),
+ &(deviatorPlasticExtTemp[0][0]),
+ sizeof(double)*nlocal*maxpartner);
+ memory->destroy(deviatorPlasticExtTemp);
+ }
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairPeriEPS::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(bulkmodulus,n+1,n+1,"pair:bulkmodulus");
memory->create(shearmodulus,n+1,n+1,"pair:shearmodulus");
memory->create(s00,n+1,n+1,"pair:s00");
memory->create(alpha,n+1,n+1,"pair:alpha");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(m_yieldstress,n+1,n+1,"pair:m_yieldstress");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairPeriEPS::settings(int narg, char **arg)
{
if (narg) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairPeriEPS::coeff(int narg, char **arg)
{
if (narg != 8) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double bulkmodulus_one = atof(arg[2]);
double shearmodulus_one = atof(arg[3]);
double cut_one = atof(arg[4]);
double s00_one = atof(arg[5]);
double alpha_one = atof(arg[6]);
double myieldstress_one = atof(arg[7]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
bulkmodulus[i][j] = bulkmodulus_one;
shearmodulus[i][j] = shearmodulus_one;
cut[i][j] = cut_one;
s00[i][j] = s00_one;
alpha[i][j] = alpha_one;
m_yieldstress[i][j] = myieldstress_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairPeriEPS::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
bulkmodulus[j][i] = bulkmodulus[i][j];
shearmodulus[j][i] = shearmodulus[i][j];
s00[j][i] = s00[i][j];
alpha[j][i] = alpha[i][j];
cut[j][i] = cut[i][j];
m_yieldstress[j][i] = m_yieldstress[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairPeriEPS::init_style()
{
// error checks
if (!atom->peri_flag)
error->all(FLERR,"Pair style peri requires atom style peri");
if (atom->map_style == 0)
error->all(FLERR,"Pair peri requires an atom map, see atom_modify");
if (domain->lattice == NULL)
error->all(FLERR,"Pair peri requires a lattice be defined");
if (domain->lattice->xlattice != domain->lattice->ylattice ||
domain->lattice->xlattice != domain->lattice->zlattice ||
domain->lattice->ylattice != domain->lattice->zlattice)
error->all(FLERR,"Pair peri lattice is not identical in x, y, and z");
// if first init, create Fix needed for storing fixed neighbors
if (ifix_peri == -1) {
char **fixarg = new char*[3];
fixarg[0] = (char *) "PERI_NEIGH";
fixarg[1] = (char *) "all";
fixarg[2] = (char *) "PERI_NEIGH";
modify->add_fix(3,fixarg);
delete [] fixarg;
}
// find associated PERI_NEIGH fix that must exist
// could have changed locations in fix list since created
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i;
if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairPeriEPS::write_restart(FILE *fp)
{
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&bulkmodulus[i][j],sizeof(double),1,fp);
fwrite(&shearmodulus[i][j],sizeof(double),1,fp);
fwrite(&s00[i][j],sizeof(double),1,fp);
fwrite(&alpha[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
fwrite(&m_yieldstress[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairPeriEPS::read_restart(FILE *fp)
{
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&bulkmodulus[i][j],sizeof(double),1,fp);
fread(&shearmodulus[i][j],sizeof(double),1,fp);
fread(&s00[i][j],sizeof(double),1,fp);
fread(&alpha[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
fread(&m_yieldstress[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&bulkmodulus[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&shearmodulus[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&m_yieldstress[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairPeriEPS::memory_usage()
{
double bytes = 2 * nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
influence function definition
------------------------------------------------------------------------- */
double PairPeriEPS::influence_function(double xi_x, double xi_y, double xi_z)
{
double r = sqrt(xi_x*xi_x + xi_y*xi_y + xi_z*xi_z);
double omega;
if (fabs(r) < 2.2204e-016)
error->one(FLERR,"Divide by 0 in influence function");
omega = 1.0/r;
return omega;
}
/* ---------------------------------------------------------------------- */
void PairPeriEPS::compute_dilatation()
{
int i,j,jj,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0;
double rsq,r,dr;
double delta;
double **x = atom->x;
int *type = atom->type;
double **x0 = atom->x0;
int nlocal = atom->nlocal;
double *vfrac = atom->vfrac;
double vfrac_scale = 1.0;
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
// compute the dilatation theta
for (i = 0; i < nlocal; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
jnum = npartner[i];
theta[i] = 0.0;
itype = type[i];
for (jj = 0; jj < jnum; jj++) {
// if bond already broken, skip this partner
if (partner[i][jj] == 0) continue;
// look up local index of this partner particle
j = atom->map(partner[i][jj]);
// skip if particle is "lost"
if (j < 0) continue;
// compute force density and add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
r = sqrt(rsq);
dr = r - r0[i][jj];
if (fabs(dr) < 2.2204e-016) dr = 0.0;
jtype = type[j];
delta = cut[itype][jtype];
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr *
vfrac[j] * vfrac_scale;
}
// if wvolume[i] is zero, then particle i has no bonds
// therefore, the dilatation is set to
if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i];
else theta[i] = 0;
}
}
/* ---------------------------------------------------------------------- */
double PairPeriEPS::compute_DeviatoricForceStateNorm(int i)
{
int j,jj,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0;
double rsq,r,dr;
double tdtrial;
double norm = 0.0;
double **x = atom->x;
int *type = atom->type;
double **x0 = atom->x0;
double *vfrac = atom->vfrac;
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
double **deviatorPlasticextension =
((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorPlasticextension;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
// compute the dilatation theta
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
jnum = npartner[i];
itype = type[i];
for (jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
j = atom->map(partner[i][jj]);
// check if lost a partner without first breaking bond
if (j < 0) {
partner[i][jj] = 0;
continue;
}
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
r = sqrt(rsq);
dr = r - r0[i][jj];
if (fabs(dr) < 2.2204e-016) dr = 0.0;
// scale vfrac[j] if particle j near the horizon
double vfrac_scale;
jtype = type[j];
double delta = cut[itype][jtype];
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
double ed = dr - (theta[i] * r0[i][jj])/3;
double edPNP1 = deviatorPlasticextension[i][jj];
jtype = type[j];
delta = cut[itype][jtype];
double omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0);
double omega_minus = influence_function(delx0,dely0,delz0);
tdtrial = ( 15 * shearmodulus[itype][itype]) *
((omega_plus * theta[i] / wvolume[i]) +
( omega_minus * theta[j] / wvolume[j] ) ) * (ed - edPNP1);
norm += tdtrial * tdtrial * vfrac[j] * vfrac_scale;
}
return sqrt(norm);
}
/* ----------------------------------------------------------------------
communication routines
---------------------------------------------------------------------- */
int PairPeriEPS::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = theta[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void PairPeriEPS::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
theta[i] = buf[m++];
}
}
diff --git a/src/PERI/pair_peri_lps.cpp b/src/PERI/pair_peri_lps.cpp
index cd88b4182..0fe8f29f3 100644
--- a/src/PERI/pair_peri_lps.cpp
+++ b/src/PERI/pair_peri_lps.cpp
@@ -1,653 +1,657 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Mike Parks (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "pair_peri_lps.h"
#include "atom.h"
#include "domain.h"
#include "lattice.h"
#include "force.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "fix_peri_neigh.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
#include "update.h"
+#include "math_const.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairPeriLPS::PairPeriLPS(LAMMPS *lmp) : Pair(lmp)
{
for (int i = 0; i < 6; i++) virial[i] = 0.0;
no_virial_fdotr_compute = 1;
single_enable = 0;
ifix_peri = -1;
nmax = 0;
s0_new = NULL;
theta = NULL;
bulkmodulus = NULL;
shearmodulus = NULL;
s00 = alpha = NULL;
cut = NULL;
// set comm size needed by this Pair
// comm_reverse not needed
comm_forward = 1; // for passing dilatation (theta)
}
/* ---------------------------------------------------------------------- */
PairPeriLPS::~PairPeriLPS()
{
if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH");
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(bulkmodulus);
memory->destroy(shearmodulus);
memory->destroy(s00);
memory->destroy(alpha);
memory->destroy(cut);
memory->destroy(theta);
memory->destroy(s0_new);
}
}
/* ---------------------------------------------------------------------- */
void PairPeriLPS::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0;
double rsq,r,dr,rk,evdwl,fpair,fbond;
int *ilist,*jlist,*numneigh,**firstneigh;
double d_ij,delta,stretch;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = eflag_global = eflag_atom = 0;
double **f = atom->f;
double **x = atom->x;
int *type = atom->type;
int nlocal = atom->nlocal;
double *vfrac = atom->vfrac;
double *s0 = atom->s0;
double **x0 = atom->x0;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
// lc = lattice constant
// init_style guarantees it's the same in x, y, and z
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double vfrac_scale = 1.0;
// short-range forces
int newton_pair = force->newton_pair;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
// need minimg() for x0 difference since not ghosted
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0;
jtype = type[j];
r = sqrt(rsq);
// short-range interaction distance based on initial particle position
// 0.9 and 1.35 are constants
d_ij = MIN(0.9*sqrt(rsq0),1.35*lc);
// short-range contact forces
// 15 is constant taken from the EMU Theory Manual
// Silling, 12 May 2005, p 18
if (r < d_ij) {
dr = r - d_ij;
// kshort based upon short-range force constant
// of the bond-based theory used in PMB model
double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) /
- (3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]);
+ (MathConst::MY_PI * cutsq[itype][jtype] * cutsq[itype][jtype]);
rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]);
if (r > 0.0) fpair = -(rk/r);
else fpair = 0.0;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) evdwl = 0.5*rk*dr;
if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,
fpair*vfrac[i],delx,dely,delz);
}
}
}
// grow bond forces array if necessary
if (atom->nmax > nmax) {
memory->destroy(s0_new);
memory->destroy(theta);
nmax = atom->nmax;
memory->create(s0_new,nmax,"pair:s0_new");
memory->create(theta,nmax,"pair:theta");
}
// Compute the dilatation on each particle
compute_dilatation();
// communicate dilatation (theta) of each particle
comm->forward_comm_pair(this);
// communicate wighted volume (wvolume) upon every reneighbor
if (neighbor->ago == 0)
comm->forward_comm_fix(modify->fix[ifix_peri]);
// Volume-dependent part of the energy
if (eflag) {
for (i = 0; i < nlocal; i++) {
itype = type[i];
if (eflag_global)
eng_vdwl += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]);
if (eflag_atom)
eatom[i] += 0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]);
}
}
// loop over my particles and their partners
// partner list contains all bond partners, so I-J appears twice
// if bond already broken, skip this partner
// first = true if this is first neighbor of particle i
bool first;
double omega_minus, omega_plus;
for (i = 0; i < nlocal; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jnum = npartner[i];
first = true;
for (jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
j = atom->map(partner[i][jj]);
// check if lost a partner without first breaking bond
if (j < 0) {
partner[i][jj] = 0;
continue;
}
// compute force density, add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
jtype = type[j];
delta = cut[itype][jtype];
r = sqrt(rsq);
dr = r - r0[i][jj];
// avoid roundoff errors
if (fabs(dr) < 2.2204e-016) dr = 0.0;
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0);
omega_minus = influence_function(delx0,dely0,delz0);
-
- rk = ( (3.0 * bulkmodulus[itype][itype]) -
- (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale *
- ( (omega_plus * theta[i] / wvolume[i]) +
- ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj];
- rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
- ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr;
+ if ((wvolume[i] > 0.0) && (wvolume[j] > 0.0)) {
+ rk = ( (3.0 * bulkmodulus[itype][itype]) -
+ (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale *
+ ( (omega_plus * theta[i] / wvolume[i]) +
+ ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj];
+ rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
+ ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr;
+ } else rk = 0.0;
if (r > 0.0) fbond = -(rk/r);
else fbond = 0.0;
f[i][0] += delx*fbond;
f[i][1] += dely*fbond;
f[i][2] += delz*fbond;
// since I-J is double counted, set newton off & use 1/2 factor and I,I
double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0);
- if (eflag) evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) *
+ if (eflag && (wvolume[i] > 0.0))
+ evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) *
omega_plus*(deviatoric_extension * deviatoric_extension) *
vfrac[j] * vfrac_scale;
+ else evdwl = 0.0;
if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0,
0.5*fbond*vfrac[i],delx,dely,delz);
// find stretch in bond I-J and break if necessary
// use s0 from previous timestep
stretch = dr / r0[i][jj];
if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0;
// update s0 for next timestep
if (first)
s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch);
else
s0_new[i] = MAX(s0_new[i],s00[itype][jtype] -
(alpha[itype][jtype] * stretch));
first = false;
}
}
// store new s0
for (i = 0; i < nlocal; i++) s0[i] = s0_new[i];
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairPeriLPS::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(bulkmodulus,n+1,n+1,"pair:bulkmodulus");
memory->create(shearmodulus,n+1,n+1,"pair:shearmodulus");
memory->create(s00,n+1,n+1,"pair:s00");
memory->create(alpha,n+1,n+1,"pair:alpha");
memory->create(cut,n+1,n+1,"pair:cut");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairPeriLPS::settings(int narg, char **arg)
{
if (narg) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairPeriLPS::coeff(int narg, char **arg)
{
if (narg != 7) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double bulkmodulus_one = force->numeric(FLERR,arg[2]);
double shearmodulus_one = force->numeric(FLERR,arg[3]);
double cut_one = force->numeric(FLERR,arg[4]);
double s00_one = force->numeric(FLERR,arg[5]);
double alpha_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
bulkmodulus[i][j] = bulkmodulus_one;
shearmodulus[i][j] = shearmodulus_one;
cut[i][j] = cut_one;
s00[i][j] = s00_one;
alpha[i][j] = alpha_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairPeriLPS::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
bulkmodulus[j][i] = bulkmodulus[i][j];
shearmodulus[j][i] = shearmodulus[i][j];
s00[j][i] = s00[i][j];
alpha[j][i] = alpha[i][j];
cut[j][i] = cut[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairPeriLPS::init_style()
{
// error checks
if (!atom->peri_flag)
error->all(FLERR,"Pair style peri requires atom style peri");
if (atom->map_style == 0)
error->all(FLERR,"Pair peri requires an atom map, see atom_modify");
if (domain->lattice->xlattice != domain->lattice->ylattice ||
domain->lattice->xlattice != domain->lattice->zlattice ||
domain->lattice->ylattice != domain->lattice->zlattice)
error->all(FLERR,"Pair peri lattice is not identical in x, y, and z");
// if first init, create Fix needed for storing fixed neighbors
if (ifix_peri == -1) {
char **fixarg = new char*[3];
fixarg[0] = (char *) "PERI_NEIGH";
fixarg[1] = (char *) "all";
fixarg[2] = (char *) "PERI_NEIGH";
modify->add_fix(3,fixarg);
delete [] fixarg;
}
// find associated PERI_NEIGH fix that must exist
// could have changed locations in fix list since created
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"PERI_NEIGH") == 0) ifix_peri = i;
if (ifix_peri == -1) error->all(FLERR,"Fix peri neigh does not exist");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairPeriLPS::write_restart(FILE *fp)
{
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&bulkmodulus[i][j],sizeof(double),1,fp);
fwrite(&shearmodulus[i][j],sizeof(double),1,fp);
fwrite(&s00[i][j],sizeof(double),1,fp);
fwrite(&alpha[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairPeriLPS::read_restart(FILE *fp)
{
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&bulkmodulus[i][j],sizeof(double),1,fp);
fread(&shearmodulus[i][j],sizeof(double),1,fp);
fread(&s00[i][j],sizeof(double),1,fp);
fread(&alpha[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&bulkmodulus[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&shearmodulus[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&s00[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairPeriLPS::memory_usage()
{
double bytes = 2 * nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
influence function definition
------------------------------------------------------------------------- */
double PairPeriLPS::influence_function(double xi_x, double xi_y, double xi_z)
{
double r = sqrt(xi_x*xi_x + xi_y*xi_y + xi_z*xi_z);
double omega;
if (fabs(r) < 2.2204e-016)
error->one(FLERR,"Divide by 0 in influence function of pair peri/lps");
omega = 1.0/r;
return omega;
}
/* ---------------------------------------------------------------------- */
void PairPeriLPS::compute_dilatation()
{
int i,j,jj,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0;
double rsq,r,dr;
double delta;
double **x = atom->x;
int *type = atom->type;
double **x0 = atom->x0;
int nlocal = atom->nlocal;
double *vfrac = atom->vfrac;
double vfrac_scale = 1.0;
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
// compute the dilatation theta
for (i = 0; i < nlocal; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
jnum = npartner[i];
theta[i] = 0.0;
itype = type[i];
for (jj = 0; jj < jnum; jj++) {
// if bond already broken, skip this partner
if (partner[i][jj] == 0) continue;
// Look up local index of this partner particle
j = atom->map(partner[i][jj]);
// Skip if particle is "lost"
if (j < 0) continue;
// Compute force density and add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
r = sqrt(rsq);
dr = r - r0[i][jj];
if (fabs(dr) < 2.2204e-016) dr = 0.0;
jtype = type[j];
delta = cut[itype][jtype];
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr *
vfrac[j] * vfrac_scale;
}
// if wvolume[i] is zero, then particle i has no bonds
// therefore, the dilatation is set to
if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i];
else theta[i] = 0;
}
}
/* ----------------------------------------------------------------------
communication routines
---------------------------------------------------------------------- */
int PairPeriLPS::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = theta[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void PairPeriLPS::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
theta[i] = buf[m++];
}
}
diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp
index 36f56aa29..f08228f3d 100644
--- a/src/RIGID/fix_shake.cpp
+++ b/src/RIGID/fix_shake.cpp
@@ -1,2816 +1,2836 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <mpi.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "fix_shake.h"
#include "fix_rattle.h"
#include "atom.h"
#include "atom_vec.h"
#include "molecule.h"
#include "update.h"
#include "respa.h"
#include "modify.h"
#include "domain.h"
#include "force.h"
#include "bond.h"
#include "angle.h"
#include "comm.h"
#include "group.h"
#include "fix_respa.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
#define BIG 1.0e20
#define MASSDELTA 0.1
/* ---------------------------------------------------------------------- */
FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg), bond_flag(NULL), angle_flag(NULL),
type_flag(NULL), mass_list(NULL), bond_distance(NULL), angle_distance(NULL),
loop_respa(NULL), step_respa(NULL), x(NULL), v(NULL), f(NULL), ftmp(NULL),
vtmp(NULL), mass(NULL), rmass(NULL), type(NULL), shake_flag(NULL),
shake_atom(NULL), shake_type(NULL), xshake(NULL), nshake(NULL),
list(NULL), b_count(NULL), b_count_all(NULL), b_ave(NULL), b_max(NULL),
b_min(NULL), b_ave_all(NULL), b_max_all(NULL), b_min_all(NULL),
a_count(NULL), a_count_all(NULL), a_ave(NULL), a_max(NULL), a_min(NULL),
a_ave_all(NULL), a_max_all(NULL), a_min_all(NULL), atommols(NULL),
onemols(NULL)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
virial_flag = 1;
create_attribute = 1;
dof_flag = 1;
// error check
molecular = atom->molecular;
if (molecular == 0)
error->all(FLERR,"Cannot use fix shake with non-molecular system");
// perform initial allocation of atom-based arrays
// register with Atom class
shake_flag = NULL;
shake_atom = NULL;
shake_type = NULL;
xshake = NULL;
ftmp = NULL;
vtmp = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
// set comm size needed by this fix
comm_forward = 3;
// parse SHAKE args
if (narg < 8) error->all(FLERR,"Illegal fix shake command");
tolerance = force->numeric(FLERR,arg[3]);
max_iter = force->inumeric(FLERR,arg[4]);
output_every = force->inumeric(FLERR,arg[5]);
// parse SHAKE args for bond and angle types
// will be used by find_clusters
// store args for "b" "a" "t" as flags in (1:n) list for fast access
// store args for "m" in list of length nmass for looping over
// for "m" verify that atom masses have been set
bond_flag = new int[atom->nbondtypes+1];
for (int i = 1; i <= atom->nbondtypes; i++) bond_flag[i] = 0;
angle_flag = new int[atom->nangletypes+1];
for (int i = 1; i <= atom->nangletypes; i++) angle_flag[i] = 0;
type_flag = new int[atom->ntypes+1];
for (int i = 1; i <= atom->ntypes; i++) type_flag[i] = 0;
mass_list = new double[atom->ntypes];
nmass = 0;
char mode = '\0';
int next = 6;
while (next < narg) {
if (strcmp(arg[next],"b") == 0) mode = 'b';
else if (strcmp(arg[next],"a") == 0) mode = 'a';
else if (strcmp(arg[next],"t") == 0) mode = 't';
else if (strcmp(arg[next],"m") == 0) {
mode = 'm';
atom->check_mass(FLERR);
// break if keyword that is not b,a,t,m
} else if (isalpha(arg[next][0])) break;
// read numeric args of b,a,t,m
else if (mode == 'b') {
int i = force->inumeric(FLERR,arg[next]);
if (i < 1 || i > atom->nbondtypes)
error->all(FLERR,"Invalid bond type index for fix shake");
bond_flag[i] = 1;
} else if (mode == 'a') {
int i = force->inumeric(FLERR,arg[next]);
if (i < 1 || i > atom->nangletypes)
error->all(FLERR,"Invalid angle type index for fix shake");
angle_flag[i] = 1;
} else if (mode == 't') {
int i = force->inumeric(FLERR,arg[next]);
if (i < 1 || i > atom->ntypes)
error->all(FLERR,"Invalid atom type index for fix shake");
type_flag[i] = 1;
} else if (mode == 'm') {
double massone = force->numeric(FLERR,arg[next]);
if (massone == 0.0) error->all(FLERR,"Invalid atom mass for fix shake");
if (nmass == atom->ntypes)
error->all(FLERR,"Too many masses for fix shake");
mass_list[nmass++] = massone;
} else error->all(FLERR,"Illegal fix shake command");
next++;
}
// parse optional args
onemols = NULL;
int iarg = next;
while (iarg < narg) {
if (strcmp(arg[next],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix shake command");
int imol = atom->find_molecule(arg[iarg+1]);
if (imol == -1)
error->all(FLERR,"Molecule template ID for fix shake does not exist");
if (atom->molecules[imol]->nset > 1 && comm->me == 0)
error->warning(FLERR,"Molecule template for "
"fix shake has multiple molecules");
onemols = &atom->molecules[imol];
nmol = onemols[0]->nset;
iarg += 2;
} else error->all(FLERR,"Illegal fix shake command");
}
// error check for Molecule template
if (onemols) {
for (int i = 0; i < nmol; i++)
if (onemols[i]->shakeflag == 0)
error->all(FLERR,"Fix shake molecule template must have shake info");
}
// allocate bond and angle distance arrays, indexed from 1 to n
bond_distance = new double[atom->nbondtypes+1];
angle_distance = new double[atom->nangletypes+1];
// allocate statistics arrays
if (output_every) {
int nb = atom->nbondtypes + 1;
b_count = new int[nb];
b_count_all = new int[nb];
b_ave = new double[nb];
b_ave_all = new double[nb];
b_max = new double[nb];
b_max_all = new double[nb];
b_min = new double[nb];
b_min_all = new double[nb];
int na = atom->nangletypes + 1;
a_count = new int[na];
a_count_all = new int[na];
a_ave = new double[na];
a_ave_all = new double[na];
a_max = new double[na];
a_max_all = new double[na];
a_min = new double[na];
a_min_all = new double[na];
}
// SHAKE vs RATTLE
rattle = 0;
// identify all SHAKE clusters
find_clusters();
// initialize list of SHAKE clusters to constrain
maxlist = 0;
list = NULL;
}
/* ---------------------------------------------------------------------- */
FixShake::~FixShake()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
// set bond_type and angle_type back to positive for SHAKE clusters
// must set for all SHAKE bonds and angles stored by each atom
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
else if (shake_flag[i] == 1) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],1);
angletype_findset(i,shake_atom[i][1],shake_atom[i][2],1);
} else if (shake_flag[i] == 2) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],1);
} else if (shake_flag[i] == 3) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],1);
} else if (shake_flag[i] == 4) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][3],1);
}
}
// delete locally stored arrays
memory->destroy(shake_flag);
memory->destroy(shake_atom);
memory->destroy(shake_type);
memory->destroy(xshake);
memory->destroy(ftmp);
memory->destroy(vtmp);
delete [] bond_flag;
delete [] angle_flag;
delete [] type_flag;
delete [] mass_list;
delete [] bond_distance;
delete [] angle_distance;
if (output_every) {
delete [] b_count;
delete [] b_count_all;
delete [] b_ave;
delete [] b_ave_all;
delete [] b_max;
delete [] b_max_all;
delete [] b_min;
delete [] b_min_all;
delete [] a_count;
delete [] a_count_all;
delete [] a_ave;
delete [] a_ave_all;
delete [] a_max;
delete [] a_max_all;
delete [] a_min;
delete [] a_min_all;
}
memory->destroy(list);
}
/* ---------------------------------------------------------------------- */
int FixShake::setmask()
{
int mask = 0;
mask |= PRE_NEIGHBOR;
mask |= POST_FORCE;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ----------------------------------------------------------------------
set bond and angle distances
this init must happen after force->bond and force->angle inits
------------------------------------------------------------------------- */
void FixShake::init()
{
int i,m,flag,flag_all,type1,type2,bond1_type,bond2_type;
double rsq,angle;
// error if more than one shake fix
int count = 0;
for (i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"shake") == 0) count++;
if (count > 1) error->all(FLERR,"More than one fix shake");
// cannot use with minimization since SHAKE turns off bonds
// that should contribute to potential energy
if (update->whichflag == 2)
error->all(FLERR,"Fix shake cannot be used with minimization");
// error if npt,nph fix comes before shake fix
for (i = 0; i < modify->nfix; i++) {
if (strcmp(modify->fix[i]->style,"npt") == 0) break;
if (strcmp(modify->fix[i]->style,"nph") == 0) break;
}
if (i < modify->nfix) {
for (int j = i; j < modify->nfix; j++)
if (strcmp(modify->fix[j]->style,"shake") == 0)
error->all(FLERR,"Shake fix must come before NPT/NPH fix");
}
// if rRESPA, find associated fix that must exist
// could have changed locations in fix list since created
// set ptrs to rRESPA variables
if (strstr(update->integrate_style,"respa")) {
for (i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"RESPA") == 0) ifix_respa = i;
nlevels_respa = ((Respa *) update->integrate)->nlevels;
loop_respa = ((Respa *) update->integrate)->loop;
step_respa = ((Respa *) update->integrate)->step;
}
// set equilibrium bond distances
if (force->bond == NULL)
error->all(FLERR,"Bond potential must be defined for SHAKE");
for (i = 1; i <= atom->nbondtypes; i++)
bond_distance[i] = force->bond->equilibrium_distance(i);
// set equilibrium angle distances
int nlocal = atom->nlocal;
for (i = 1; i <= atom->nangletypes; i++) {
if (angle_flag[i] == 0) continue;
if (force->angle == NULL)
error->all(FLERR,"Angle potential must be defined for SHAKE");
// scan all atoms for a SHAKE angle cluster
// extract bond types for the 2 bonds in the cluster
// bond types must be same in all clusters of this angle type,
// else set error flag
flag = 0;
bond1_type = bond2_type = 0;
for (m = 0; m < nlocal; m++) {
if (shake_flag[m] != 1) continue;
if (shake_type[m][2] != i) continue;
type1 = MIN(shake_type[m][0],shake_type[m][1]);
type2 = MAX(shake_type[m][0],shake_type[m][1]);
if (bond1_type > 0) {
if (type1 != bond1_type || type2 != bond2_type) {
flag = 1;
break;
}
}
bond1_type = type1;
bond2_type = type2;
}
// error check for any bond types that are not the same
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world);
if (flag_all) error->all(FLERR,"Shake angles have different bond types");
// insure all procs have bond types
MPI_Allreduce(&bond1_type,&flag_all,1,MPI_INT,MPI_MAX,world);
bond1_type = flag_all;
MPI_Allreduce(&bond2_type,&flag_all,1,MPI_INT,MPI_MAX,world);
bond2_type = flag_all;
// if bond types are 0, no SHAKE angles of this type exist
// just skip this angle
if (bond1_type == 0) {
angle_distance[i] = 0.0;
continue;
}
// compute the angle distance as a function of 2 bond distances
// formula is now correct for bonds of same or different lengths (Oct15)
angle = force->angle->equilibrium_angle(i);
const double b1 = bond_distance[bond1_type];
const double b2 = bond_distance[bond2_type];
rsq = b1*b1 + b2*b2 - 2.0*b1*b2*cos(angle);
angle_distance[i] = sqrt(rsq);
}
}
/* ----------------------------------------------------------------------
SHAKE as pre-integrator constraint
------------------------------------------------------------------------- */
void FixShake::setup(int vflag)
{
pre_neighbor();
if (output_every) stats();
// setup SHAKE output
bigint ntimestep = update->ntimestep;
if (output_every) {
next_output = ntimestep + output_every;
if (ntimestep % output_every != 0)
next_output = (ntimestep/output_every)*output_every + output_every;
} else next_output = -1;
// set respa to 0 if verlet is used and to 1 otherwise
if (strstr(update->integrate_style,"verlet"))
respa = 0;
else
respa = 1;
if (!respa) {
dtv = update->dt;
dtfsq = 0.5 * update->dt * update->dt * force->ftm2v;
if (!rattle) dtfsq = update->dt * update->dt * force->ftm2v;
} else {
dtv = step_respa[0];
dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v;
dtf_inner = dtf_innerhalf;
}
// correct geometry of cluster if necessary
correct_coordinates(vflag);
// remove velocities along any bonds
correct_velocities();
// precalculate constraining forces for first integration step
shake_end_of_step(vflag);
}
/* ----------------------------------------------------------------------
build list of SHAKE clusters to constrain
if one or more atoms in cluster are on this proc,
this proc lists the cluster exactly once
------------------------------------------------------------------------- */
void FixShake::pre_neighbor()
{
int atom1,atom2,atom3,atom4;
// local copies of atom quantities
// used by SHAKE until next re-neighboring
x = atom->x;
v = atom->v;
f = atom->f;
mass = atom->mass;
rmass = atom->rmass;
type = atom->type;
nlocal = atom->nlocal;
// extend size of SHAKE list if necessary
if (nlocal > maxlist) {
maxlist = nlocal;
memory->destroy(list);
memory->create(list,maxlist,"shake:list");
}
// build list of SHAKE clusters I compute
nlist = 0;
for (int i = 0; i < nlocal; i++)
if (shake_flag[i]) {
if (shake_flag[i] == 2) {
atom1 = atom->map(shake_atom[i][0]);
atom2 = atom->map(shake_atom[i][1]);
if (atom1 == -1 || atom2 == -1) {
char str[128];
sprintf(str,"Shake atoms " TAGINT_FORMAT " " TAGINT_FORMAT
" missing on proc %d at step " BIGINT_FORMAT,
shake_atom[i][0],shake_atom[i][1],me,update->ntimestep);
error->one(FLERR,str);
}
if (i <= atom1 && i <= atom2) list[nlist++] = i;
} else if (shake_flag[i] % 2 == 1) {
atom1 = atom->map(shake_atom[i][0]);
atom2 = atom->map(shake_atom[i][1]);
atom3 = atom->map(shake_atom[i][2]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1) {
char str[128];
sprintf(str,"Shake atoms "
TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT
" missing on proc %d at step " BIGINT_FORMAT,
shake_atom[i][0],shake_atom[i][1],shake_atom[i][2],
me,update->ntimestep);
error->one(FLERR,str);
}
if (i <= atom1 && i <= atom2 && i <= atom3) list[nlist++] = i;
} else {
atom1 = atom->map(shake_atom[i][0]);
atom2 = atom->map(shake_atom[i][1]);
atom3 = atom->map(shake_atom[i][2]);
atom4 = atom->map(shake_atom[i][3]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) {
char str[128];
sprintf(str,"Shake atoms "
TAGINT_FORMAT " " TAGINT_FORMAT " "
TAGINT_FORMAT " " TAGINT_FORMAT
" missing on proc %d at step " BIGINT_FORMAT,
shake_atom[i][0],shake_atom[i][1],
shake_atom[i][2],shake_atom[i][3],
me,update->ntimestep);
error->one(FLERR,str);
}
if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)
list[nlist++] = i;
}
}
}
/* ----------------------------------------------------------------------
compute the force adjustment for SHAKE constraint
------------------------------------------------------------------------- */
void FixShake::post_force(int vflag)
{
if (update->ntimestep == next_output) stats();
// xshake = unconstrained move with current v,f
// communicate results if necessary
unconstrained_update();
if (nprocs > 1) comm->forward_comm_fix(this);
// virial setup
if (vflag) v_setup(vflag);
else evflag = 0;
// loop over clusters to add constraint forces
int m;
for (int i = 0; i < nlist; i++) {
m = list[i];
if (shake_flag[m] == 2) shake(m);
else if (shake_flag[m] == 3) shake3(m);
else if (shake_flag[m] == 4) shake4(m);
else shake3angle(m);
}
// store vflag for coordinate_constraints_end_of_step()
vflag_post_force = vflag;
}
/* ----------------------------------------------------------------------
enforce SHAKE constraints from rRESPA
xshake prediction portion is different than Verlet
------------------------------------------------------------------------- */
void FixShake::post_force_respa(int vflag, int ilevel, int iloop)
{
// call stats only on outermost level
if (ilevel == nlevels_respa-1 && update->ntimestep == next_output) stats();
// might be OK to skip enforcing SHAKE constraings
// on last iteration of inner levels if pressure not requested
// however, leads to slightly different trajectories
//if (ilevel < nlevels_respa-1 && iloop == loop_respa[ilevel]-1 && !vflag)
// return;
// xshake = unconstrained move with current v,f as function of level
// communicate results if necessary
unconstrained_update_respa(ilevel);
if (nprocs > 1) comm->forward_comm_fix(this);
// virial setup only needed on last iteration of innermost level
// and if pressure is requested
// virial accumulation happens via evflag at last iteration of each level
if (ilevel == 0 && iloop == loop_respa[ilevel]-1 && vflag) v_setup(vflag);
if (iloop == loop_respa[ilevel]-1) evflag = 1;
else evflag = 0;
// loop over clusters to add constraint forces
int m;
for (int i = 0; i < nlist; i++) {
m = list[i];
if (shake_flag[m] == 2) shake(m);
else if (shake_flag[m] == 3) shake3(m);
else if (shake_flag[m] == 4) shake4(m);
else shake3angle(m);
}
// store vflag for coordinate_constraints_end_of_step()
vflag_post_force = vflag;
}
/* ----------------------------------------------------------------------
count # of degrees-of-freedom removed by SHAKE for atoms in igroup
------------------------------------------------------------------------- */
int FixShake::dof(int igroup)
{
int groupbit = group->bitmask[igroup];
int *mask = atom->mask;
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
// count dof in a cluster if and only if
// the central atom is in group and atom i is the central atom
int n = 0;
for (int i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
if (shake_flag[i] == 0) continue;
if (shake_atom[i][0] != tag[i]) continue;
if (shake_flag[i] == 1) n += 3;
else if (shake_flag[i] == 2) n += 1;
else if (shake_flag[i] == 3) n += 2;
else if (shake_flag[i] == 4) n += 3;
}
int nall;
MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world);
return nall;
}
/* ----------------------------------------------------------------------
identify whether each atom is in a SHAKE cluster
only include atoms in fix group and those bonds/angles specified in input
test whether all clusters are valid
set shake_flag, shake_atom, shake_type values
set bond,angle types negative so will be ignored in neighbor lists
------------------------------------------------------------------------- */
void FixShake::find_clusters()
{
int i,j,m,n,imol,iatom;
int flag,flag_all,nbuf,size;
tagint tagprev;
double massone;
tagint *buf;
if (me == 0 && screen) {
if (!rattle) fprintf(screen,"Finding SHAKE clusters ...\n");
else fprintf(screen,"Finding RATTLE clusters ...\n");
}
atommols = atom->avec->onemols;
tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double *mass = atom->mass;
double *rmass = atom->rmass;
int **nspecial = atom->nspecial;
tagint **special = atom->special;
int *molindex = atom->molindex;
int *molatom = atom->molatom;
int nlocal = atom->nlocal;
int angles_allow = atom->avec->angles_allow;
// setup ring of procs
int next = me + 1;
int prev = me -1;
if (next == nprocs) next = 0;
if (prev < 0) prev = nprocs - 1;
// -----------------------------------------------------
// allocate arrays for self (1d) and bond partners (2d)
// max = max # of bond partners for owned atoms = 2nd dim of partner arrays
// npartner[i] = # of bonds attached to atom i
// nshake[i] = # of SHAKE bonds attached to atom i
// partner_tag[i][] = global IDs of each partner
// partner_mask[i][] = mask of each partner
// partner_type[i][] = type of each partner
// partner_massflag[i][] = 1 if partner meets mass criterion, 0 if not
// partner_bondtype[i][] = type of bond attached to each partner
// partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not
// partner_nshake[i][] = nshake value for each partner
// -----------------------------------------------------
int max = 0;
if (molecular == 1) {
for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]);
} else {
for (i = 0; i < nlocal; i++) {
imol = molindex[i];
if (imol < 0) continue;
iatom = molatom[i];
max = MAX(max,atommols[imol]->nspecial[iatom][0]);
}
}
int *npartner;
memory->create(npartner,nlocal,"shake:npartner");
memory->create(nshake,nlocal,"shake:nshake");
tagint **partner_tag;
int **partner_mask,**partner_type,**partner_massflag;
int **partner_bondtype,**partner_shake,**partner_nshake;
memory->create(partner_tag,nlocal,max,"shake:partner_tag");
memory->create(partner_mask,nlocal,max,"shake:partner_mask");
memory->create(partner_type,nlocal,max,"shake:partner_type");
memory->create(partner_massflag,nlocal,max,"shake:partner_massflag");
memory->create(partner_bondtype,nlocal,max,"shake:partner_bondtype");
memory->create(partner_shake,nlocal,max,"shake:partner_shake");
memory->create(partner_nshake,nlocal,max,"shake:partner_nshake");
// -----------------------------------------------------
// set npartner and partner_tag from special arrays
// -----------------------------------------------------
if (molecular == 1) {
for (i = 0; i < nlocal; i++) {
npartner[i] = nspecial[i][0];
for (j = 0; j < npartner[i]; j++)
partner_tag[i][j] = special[i][j];
}
} else {
for (i = 0; i < nlocal; i++) {
imol = molindex[i];
if (imol < 0) continue;
iatom = molatom[i];
tagprev = tag[i] - iatom - 1;
npartner[i] = atommols[imol]->nspecial[iatom][0];
for (j = 0; j < npartner[i]; j++)
partner_tag[i][j] = atommols[imol]->special[iatom][j] + tagprev;;
}
}
// -----------------------------------------------------
// set partner_mask, partner_type, partner_massflag, partner_bondtype
// for bonded partners
// requires communication for off-proc partners
// -----------------------------------------------------
// fill in mask, type, massflag, bondtype if own bond partner
// info to store in buf for each off-proc bond = nper = 6
// 2 atoms IDs in bond, space for mask, type, massflag, bondtype
// nbufmax = largest buffer needed to hold info from any proc
int nper = 6;
nbuf = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
partner_mask[i][j] = 0;
partner_type[i][j] = 0;
partner_massflag[i][j] = 0;
partner_bondtype[i][j] = 0;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
partner_mask[i][j] = mask[m];
partner_type[i][j] = type[m];
if (nmass) {
if (rmass) massone = rmass[m];
else massone = mass[type[m]];
partner_massflag[i][j] = masscheck(massone);
}
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
else {
n = bondtype_findset(m,tag[i],partner_tag[i][j],0);
if (n) partner_bondtype[i][j] = n;
}
} else nbuf += nper;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = tag[i];
buf[size+1] = partner_tag[i][j];
buf[size+2] = 0;
buf[size+3] = 0;
buf[size+4] = 0;
n = bondtype_findset(i,tag[i],partner_tag[i][j],0);
if (n) buf[size+5] = n;
else buf[size+5] = 0;
size += nper;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,1,ring_bonds,buf,(void *)this);
// store partner info returned to me
m = 0;
while (m < size) {
i = atom->map(buf[m]);
for (j = 0; j < npartner[i]; j++)
if (buf[m+1] == partner_tag[i][j]) break;
partner_mask[i][j] = buf[m+2];
partner_type[i][j] = buf[m+3];
partner_massflag[i][j] = buf[m+4];
partner_bondtype[i][j] = buf[m+5];
m += nper;
}
memory->destroy(buf);
// error check for unfilled partner info
// if partner_type not set, is an error
// partner_bondtype may not be set if special list is not consistent
// with bondatom (e.g. due to delete_bonds command)
// this is OK if one or both atoms are not in fix group, since
// bond won't be SHAKEn anyway
// else it's an error
flag = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < npartner[i]; j++) {
if (partner_type[i][j] == 0) flag = 1;
if (!(mask[i] & groupbit)) continue;
if (!(partner_mask[i][j] & groupbit)) continue;
if (partner_bondtype[i][j] == 0) flag = 1;
}
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Did not find fix shake partner info");
// -----------------------------------------------------
// identify SHAKEable bonds
// set nshake[i] = # of SHAKE bonds attached to atom i
// set partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not
// both atoms must be in group, bondtype must be > 0
// check if bondtype is in input bond_flag
// check if type of either atom is in input type_flag
// check if mass of either atom is in input mass_list
// -----------------------------------------------------
int np;
for (i = 0; i < nlocal; i++) {
nshake[i] = 0;
np = npartner[i];
for (j = 0; j < np; j++) {
partner_shake[i][j] = 0;
if (!(mask[i] & groupbit)) continue;
if (!(partner_mask[i][j] & groupbit)) continue;
if (partner_bondtype[i][j] <= 0) continue;
if (bond_flag[partner_bondtype[i][j]]) {
partner_shake[i][j] = 1;
nshake[i]++;
continue;
}
if (type_flag[type[i]] || type_flag[partner_type[i][j]]) {
partner_shake[i][j] = 1;
nshake[i]++;
continue;
}
if (nmass) {
if (partner_massflag[i][j]) {
partner_shake[i][j] = 1;
nshake[i]++;
continue;
} else {
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (masscheck(massone)) {
partner_shake[i][j] = 1;
nshake[i]++;
continue;
}
}
}
}
}
// -----------------------------------------------------
// set partner_nshake for bonded partners
// requires communication for off-proc partners
// -----------------------------------------------------
// fill in partner_nshake if own bond partner
// info to store in buf for each off-proc bond =
// 2 atoms IDs in bond, space for nshake value
// nbufmax = largest buffer needed to hold info from any proc
nbuf = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) partner_nshake[i][j] = nshake[m];
else nbuf += 3;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
for (j = 0; j < npartner[i]; j++) {
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = tag[i];
buf[size+1] = partner_tag[i][j];
size += 3;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,2,ring_nshake,buf,(void *)this);
// store partner info returned to me
m = 0;
while (m < size) {
i = atom->map(buf[m]);
for (j = 0; j < npartner[i]; j++)
if (buf[m+1] == partner_tag[i][j]) break;
partner_nshake[i][j] = buf[m+2];
m += 3;
}
memory->destroy(buf);
// -----------------------------------------------------
// error checks
// no atom with nshake > 3
// no connected atoms which both have nshake > 1
// -----------------------------------------------------
flag = 0;
for (i = 0; i < nlocal; i++) if (nshake[i] > 3) flag = 1;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Shake cluster of more than 4 atoms");
flag = 0;
for (i = 0; i < nlocal; i++) {
if (nshake[i] <= 1) continue;
for (j = 0; j < npartner[i]; j++)
if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag = 1;
}
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Shake clusters are connected");
// -----------------------------------------------------
// set SHAKE arrays that are stored with atoms & add angle constraints
// zero shake arrays for all owned atoms
// if I am central atom set shake_flag & shake_atom & shake_type
// for 2-atom clusters, I am central atom if my atom ID < partner ID
// for 3-atom clusters, test for angle constraint
// angle will be stored by this atom if it exists
// if angle type matches angle_flag, then it is angle-constrained
// shake_flag[] = 0 if atom not in SHAKE cluster
// 2,3,4 = size of bond-only cluster
// 1 = 3-atom angle cluster
// shake_atom[][] = global IDs of 2,3,4 atoms in cluster
// central atom is 1st
// for 2-atom cluster, lowest ID is 1st
// shake_type[][] = bondtype of each bond in cluster
// for 3-atom angle cluster, 3rd value is angletype
// -----------------------------------------------------
for (i = 0; i < nlocal; i++) {
shake_flag[i] = 0;
shake_atom[i][0] = 0;
shake_atom[i][1] = 0;
shake_atom[i][2] = 0;
shake_atom[i][3] = 0;
shake_type[i][0] = 0;
shake_type[i][1] = 0;
shake_type[i][2] = 0;
if (nshake[i] == 1) {
for (j = 0; j < npartner[i]; j++)
if (partner_shake[i][j]) break;
if (partner_nshake[i][j] == 1 && tag[i] < partner_tag[i][j]) {
shake_flag[i] = 2;
shake_atom[i][0] = tag[i];
shake_atom[i][1] = partner_tag[i][j];
shake_type[i][0] = partner_bondtype[i][j];
}
}
if (nshake[i] > 1) {
shake_flag[i] = 1;
shake_atom[i][0] = tag[i];
for (j = 0; j < npartner[i]; j++)
if (partner_shake[i][j]) {
m = shake_flag[i];
shake_atom[i][m] = partner_tag[i][j];
shake_type[i][m-1] = partner_bondtype[i][j];
shake_flag[i]++;
}
}
if (nshake[i] == 2 && angles_allow) {
n = angletype_findset(i,shake_atom[i][1],shake_atom[i][2],0);
if (n <= 0) continue;
if (angle_flag[n]) {
shake_flag[i] = 1;
shake_type[i][2] = n;
}
}
}
// -----------------------------------------------------
// set shake_flag,shake_atom,shake_type for non-central atoms
// requires communication for off-proc atoms
// -----------------------------------------------------
// fill in shake arrays for each bond partner I own
// info to store in buf for each off-proc bond =
// all values from shake_flag, shake_atom, shake_type
// nbufmax = largest buffer needed to hold info from any proc
nbuf = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
for (j = 0; j < npartner[i]; j++) {
if (partner_shake[i][j] == 0) continue;
m = atom->map(partner_tag[i][j]);
if (m >= 0 && m < nlocal) {
shake_flag[m] = shake_flag[i];
shake_atom[m][0] = shake_atom[i][0];
shake_atom[m][1] = shake_atom[i][1];
shake_atom[m][2] = shake_atom[i][2];
shake_atom[m][3] = shake_atom[i][3];
shake_type[m][0] = shake_type[i][0];
shake_type[m][1] = shake_type[i][1];
shake_type[m][2] = shake_type[i][2];
} else nbuf += 9;
}
}
memory->create(buf,nbuf,"shake:buf");
// fill buffer with info
size = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
for (j = 0; j < npartner[i]; j++) {
if (partner_shake[i][j] == 0) continue;
m = atom->map(partner_tag[i][j]);
if (m < 0 || m >= nlocal) {
buf[size] = partner_tag[i][j];
buf[size+1] = shake_flag[i];
buf[size+2] = shake_atom[i][0];
buf[size+3] = shake_atom[i][1];
buf[size+4] = shake_atom[i][2];
buf[size+5] = shake_atom[i][3];
buf[size+6] = shake_type[i][0];
buf[size+7] = shake_type[i][1];
buf[size+8] = shake_type[i][2];
size += 9;
}
}
}
// cycle buffer around ring of procs back to self
comm->ring(size,sizeof(tagint),buf,3,ring_shake,NULL,(void *)this);
memory->destroy(buf);
// -----------------------------------------------------
// free local memory
// -----------------------------------------------------
memory->destroy(npartner);
memory->destroy(nshake);
memory->destroy(partner_tag);
memory->destroy(partner_mask);
memory->destroy(partner_type);
memory->destroy(partner_massflag);
memory->destroy(partner_bondtype);
memory->destroy(partner_shake);
memory->destroy(partner_nshake);
// -----------------------------------------------------
// set bond_type and angle_type negative for SHAKE clusters
// must set for all SHAKE bonds and angles stored by each atom
// -----------------------------------------------------
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
else if (shake_flag[i] == 1) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1);
angletype_findset(i,shake_atom[i][1],shake_atom[i][2],-1);
} else if (shake_flag[i] == 2) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1);
} else if (shake_flag[i] == 3) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1);
} else if (shake_flag[i] == 4) {
bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1);
bondtype_findset(i,shake_atom[i][0],shake_atom[i][3],-1);
}
}
// -----------------------------------------------------
// print info on SHAKE clusters
// -----------------------------------------------------
int count1,count2,count3,count4;
count1 = count2 = count3 = count4 = 0;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 1) count1++;
else if (shake_flag[i] == 2) count2++;
else if (shake_flag[i] == 3) count3++;
else if (shake_flag[i] == 4) count4++;
}
int tmp;
tmp = count1;
MPI_Allreduce(&tmp,&count1,1,MPI_INT,MPI_SUM,world);
tmp = count2;
MPI_Allreduce(&tmp,&count2,1,MPI_INT,MPI_SUM,world);
tmp = count3;
MPI_Allreduce(&tmp,&count3,1,MPI_INT,MPI_SUM,world);
tmp = count4;
MPI_Allreduce(&tmp,&count4,1,MPI_INT,MPI_SUM,world);
if (me == 0) {
if (screen) {
fprintf(screen," %d = # of size 2 clusters\n",count2/2);
fprintf(screen," %d = # of size 3 clusters\n",count3/3);
fprintf(screen," %d = # of size 4 clusters\n",count4/4);
fprintf(screen," %d = # of frozen angles\n",count1/3);
}
if (logfile) {
fprintf(logfile," %d = # of size 2 clusters\n",count2/2);
fprintf(logfile," %d = # of size 3 clusters\n",count3/3);
fprintf(logfile," %d = # of size 4 clusters\n",count4/4);
fprintf(logfile," %d = # of frozen angles\n",count1/3);
}
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner:
fill in mask and type and massflag
search for bond with 1st atom and fill in bondtype
------------------------------------------------------------------------- */
void FixShake::ring_bonds(int ndatum, char *cbuf, void *ptr)
{
FixShake *fsptr = (FixShake *)ptr;
Atom *atom = fsptr->atom;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *mask = atom->mask;
int *type = atom->type;
int nlocal = atom->nlocal;
int nmass = fsptr->nmass;
tagint *buf = (tagint *) cbuf;
int m,n;
double massone;
for (int i = 0; i < ndatum; i += 6) {
m = atom->map(buf[i+1]);
if (m >= 0 && m < nlocal) {
buf[i+2] = mask[m];
buf[i+3] = type[m];
if (nmass) {
if (rmass) massone = rmass[m];
else massone = mass[type[m]];
buf[i+4] = fsptr->masscheck(massone);
}
if (buf[i+5] == 0) {
n = fsptr->bondtype_findset(m,buf[i],buf[i+1],0);
if (n) buf[i+5] = n;
}
}
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner, fill in nshake value
------------------------------------------------------------------------- */
void FixShake::ring_nshake(int ndatum, char *cbuf, void *ptr)
{
FixShake *fsptr = (FixShake *)ptr;
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
int *nshake = fsptr->nshake;
tagint *buf = (tagint *) cbuf;
int m;
for (int i = 0; i < ndatum; i += 3) {
m = atom->map(buf[i+1]);
if (m >= 0 && m < nlocal) buf[i+2] = nshake[m];
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan bond partner IDs for atoms I own
if I own partner, fill in nshake value
------------------------------------------------------------------------- */
void FixShake::ring_shake(int ndatum, char *cbuf, void *ptr)
{
FixShake *fsptr = (FixShake *)ptr;
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
int *shake_flag = fsptr->shake_flag;
tagint **shake_atom = fsptr->shake_atom;
int **shake_type = fsptr->shake_type;
tagint *buf = (tagint *) cbuf;
int m;
for (int i = 0; i < ndatum; i += 9) {
m = atom->map(buf[i]);
if (m >= 0 && m < nlocal) {
shake_flag[m] = buf[i+1];
shake_atom[m][0] = buf[i+2];
shake_atom[m][1] = buf[i+3];
shake_atom[m][2] = buf[i+4];
shake_atom[m][3] = buf[i+5];
shake_type[m][0] = buf[i+6];
shake_type[m][1] = buf[i+7];
shake_type[m][2] = buf[i+8];
}
}
}
/* ----------------------------------------------------------------------
check if massone is within MASSDELTA of any mass in mass_list
return 1 if yes, 0 if not
------------------------------------------------------------------------- */
int FixShake::masscheck(double massone)
{
for (int i = 0; i < nmass; i++)
if (fabs(mass_list[i]-massone) <= MASSDELTA) return 1;
return 0;
}
/* ----------------------------------------------------------------------
update the unconstrained position of each atom
only for SHAKE clusters, else set to 0.0
assumes NVE update, seems to be accurate enough for NVT,NPT,NPH as well
------------------------------------------------------------------------- */
void FixShake::unconstrained_update()
{
double dtfmsq;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i]) {
dtfmsq = dtfsq / rmass[i];
xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0];
xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1];
xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2];
} else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0;
}
} else {
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i]) {
dtfmsq = dtfsq / mass[type[i]];
xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0];
xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1];
xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2];
} else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0;
}
}
}
/* ----------------------------------------------------------------------
update the unconstrained position of each atom in a rRESPA step
only for SHAKE clusters, else set to 0.0
assumes NVE update, seems to be accurate enough for NVT,NPT,NPH as well
------------------------------------------------------------------------- */
void FixShake::unconstrained_update_respa(int ilevel)
{
// xshake = atom coords after next x update in innermost loop
// depends on rRESPA level
// for levels > 0 this includes more than one velocity update
// xshake = predicted position from call to this routine at level N =
// x + dt0 (v + dtN/m fN + 1/2 dt(N-1)/m f(N-1) + ... + 1/2 dt0/m f0)
// also set dtfsq = dt0*dtN so that shake,shake3,etc can use it
double ***f_level = ((FixRespa *) modify->fix[ifix_respa])->f_level;
dtfsq = dtf_inner * step_respa[ilevel];
double invmass,dtfmsq;
int jlevel;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i]) {
invmass = 1.0 / rmass[i];
dtfmsq = dtfsq * invmass;
xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0];
xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1];
xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2];
for (jlevel = 0; jlevel < ilevel; jlevel++) {
dtfmsq = dtf_innerhalf * step_respa[jlevel] * invmass;
xshake[i][0] += dtfmsq*f_level[i][jlevel][0];
xshake[i][1] += dtfmsq*f_level[i][jlevel][1];
xshake[i][2] += dtfmsq*f_level[i][jlevel][2];
}
} else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0;
}
} else {
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i]) {
invmass = 1.0 / mass[type[i]];
dtfmsq = dtfsq * invmass;
xshake[i][0] = x[i][0] + dtv*v[i][0] + dtfmsq*f[i][0];
xshake[i][1] = x[i][1] + dtv*v[i][1] + dtfmsq*f[i][1];
xshake[i][2] = x[i][2] + dtv*v[i][2] + dtfmsq*f[i][2];
for (jlevel = 0; jlevel < ilevel; jlevel++) {
dtfmsq = dtf_innerhalf * step_respa[jlevel] * invmass;
xshake[i][0] += dtfmsq*f_level[i][jlevel][0];
xshake[i][1] += dtfmsq*f_level[i][jlevel][1];
xshake[i][2] += dtfmsq*f_level[i][jlevel][2];
}
} else xshake[i][2] = xshake[i][1] = xshake[i][0] = 0.0;
}
}
}
/* ---------------------------------------------------------------------- */
void FixShake::shake(int m)
{
int nlist,list[2];
double v[6];
double invmass0,invmass1;
// local atom IDs and constraint distances
int i0 = atom->map(shake_atom[m][0]);
int i1 = atom->map(shake_atom[m][1]);
double bond1 = bond_distance[shake_type[m][0]];
// r01 = distance vec between atoms, with PBC
double r01[3];
r01[0] = x[i0][0] - x[i1][0];
r01[1] = x[i0][1] - x[i1][1];
r01[2] = x[i0][2] - x[i1][2];
domain->minimum_image(r01);
// s01 = distance vec after unconstrained update, with PBC
// use Domain::minimum_image_once(), not minimum_image()
// b/c xshake values might be huge, due to e.g. fix gcmc
double s01[3];
s01[0] = xshake[i0][0] - xshake[i1][0];
s01[1] = xshake[i0][1] - xshake[i1][1];
s01[2] = xshake[i0][2] - xshake[i1][2];
domain->minimum_image_once(s01);
// scalar distances between atoms
double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2];
double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2];
// a,b,c = coeffs in quadratic equation for lamda
if (rmass) {
invmass0 = 1.0/rmass[i0];
invmass1 = 1.0/rmass[i1];
} else {
invmass0 = 1.0/mass[type[i0]];
invmass1 = 1.0/mass[type[i1]];
}
double a = (invmass0+invmass1)*(invmass0+invmass1) * r01sq;
double b = 2.0 * (invmass0+invmass1) *
(s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]);
double c = s01sq - bond1*bond1;
// error check
double determ = b*b - 4.0*a*c;
if (determ < 0.0) {
error->warning(FLERR,"Shake determinant < 0.0",0);
determ = 0.0;
}
// exact quadratic solution for lamda
double lamda,lamda1,lamda2;
lamda1 = (-b+sqrt(determ)) / (2.0*a);
lamda2 = (-b-sqrt(determ)) / (2.0*a);
if (fabs(lamda1) <= fabs(lamda2)) lamda = lamda1;
else lamda = lamda2;
// update forces if atom is owned by this processor
lamda /= dtfsq;
if (i0 < nlocal) {
f[i0][0] += lamda*r01[0];
f[i0][1] += lamda*r01[1];
f[i0][2] += lamda*r01[2];
}
if (i1 < nlocal) {
f[i1][0] -= lamda*r01[0];
f[i1][1] -= lamda*r01[1];
f[i1][2] -= lamda*r01[2];
}
if (evflag) {
nlist = 0;
if (i0 < nlocal) list[nlist++] = i0;
if (i1 < nlocal) list[nlist++] = i1;
v[0] = lamda*r01[0]*r01[0];
v[1] = lamda*r01[1]*r01[1];
v[2] = lamda*r01[2]*r01[2];
v[3] = lamda*r01[0]*r01[1];
v[4] = lamda*r01[0]*r01[2];
v[5] = lamda*r01[1]*r01[2];
v_tally(nlist,list,2.0,v);
}
}
/* ---------------------------------------------------------------------- */
void FixShake::shake3(int m)
{
int nlist,list[3];
double v[6];
double invmass0,invmass1,invmass2;
// local atom IDs and constraint distances
int i0 = atom->map(shake_atom[m][0]);
int i1 = atom->map(shake_atom[m][1]);
int i2 = atom->map(shake_atom[m][2]);
double bond1 = bond_distance[shake_type[m][0]];
double bond2 = bond_distance[shake_type[m][1]];
// r01,r02 = distance vec between atoms, with PBC
double r01[3];
r01[0] = x[i0][0] - x[i1][0];
r01[1] = x[i0][1] - x[i1][1];
r01[2] = x[i0][2] - x[i1][2];
domain->minimum_image(r01);
double r02[3];
r02[0] = x[i0][0] - x[i2][0];
r02[1] = x[i0][1] - x[i2][1];
r02[2] = x[i0][2] - x[i2][2];
domain->minimum_image(r02);
// s01,s02 = distance vec after unconstrained update, with PBC
// use Domain::minimum_image_once(), not minimum_image()
// b/c xshake values might be huge, due to e.g. fix gcmc
double s01[3];
s01[0] = xshake[i0][0] - xshake[i1][0];
s01[1] = xshake[i0][1] - xshake[i1][1];
s01[2] = xshake[i0][2] - xshake[i1][2];
domain->minimum_image_once(s01);
double s02[3];
s02[0] = xshake[i0][0] - xshake[i2][0];
s02[1] = xshake[i0][1] - xshake[i2][1];
s02[2] = xshake[i0][2] - xshake[i2][2];
domain->minimum_image_once(s02);
// scalar distances between atoms
double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2];
double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2];
double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2];
double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2];
// matrix coeffs and rhs for lamda equations
if (rmass) {
invmass0 = 1.0/rmass[i0];
invmass1 = 1.0/rmass[i1];
invmass2 = 1.0/rmass[i2];
} else {
invmass0 = 1.0/mass[type[i0]];
invmass1 = 1.0/mass[type[i1]];
invmass2 = 1.0/mass[type[i2]];
}
double a11 = 2.0 * (invmass0+invmass1) *
(s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]);
double a12 = 2.0 * invmass0 *
(s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]);
double a21 = 2.0 * invmass0 *
(s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]);
double a22 = 2.0 * (invmass0+invmass2) *
(s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]);
// inverse of matrix
double determ = a11*a22 - a12*a21;
if (determ == 0.0) error->one(FLERR,"Shake determinant = 0.0");
double determinv = 1.0/determ;
double a11inv = a22*determinv;
double a12inv = -a12*determinv;
double a21inv = -a21*determinv;
double a22inv = a11*determinv;
// quadratic correction coeffs
double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]);
double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq;
double quad1_0202 = invmass0*invmass0 * r02sq;
double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102;
double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq;
double quad2_0101 = invmass0*invmass0 * r01sq;
double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102;
// iterate until converged
double lamda01 = 0.0;
double lamda02 = 0.0;
int niter = 0;
int done = 0;
double quad1,quad2,b1,b2,lamda01_new,lamda02_new;
while (!done && niter < max_iter) {
quad1 = quad1_0101 * lamda01*lamda01 + quad1_0202 * lamda02*lamda02 +
quad1_0102 * lamda01*lamda02;
quad2 = quad2_0101 * lamda01*lamda01 + quad2_0202 * lamda02*lamda02 +
quad2_0102 * lamda01*lamda02;
b1 = bond1*bond1 - s01sq - quad1;
b2 = bond2*bond2 - s02sq - quad2;
lamda01_new = a11inv*b1 + a12inv*b2;
lamda02_new = a21inv*b1 + a22inv*b2;
done = 1;
if (fabs(lamda01_new-lamda01) > tolerance) done = 0;
if (fabs(lamda02_new-lamda02) > tolerance) done = 0;
lamda01 = lamda01_new;
lamda02 = lamda02_new;
+
+ // stop iterations before we have a floating point overflow
+ // max double is < 1.0e308, so 1e150 is a reasonable cutoff
+
+ if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150) done = 1;
+
niter++;
}
// update forces if atom is owned by this processor
lamda01 = lamda01/dtfsq;
lamda02 = lamda02/dtfsq;
if (i0 < nlocal) {
f[i0][0] += lamda01*r01[0] + lamda02*r02[0];
f[i0][1] += lamda01*r01[1] + lamda02*r02[1];
f[i0][2] += lamda01*r01[2] + lamda02*r02[2];
}
if (i1 < nlocal) {
f[i1][0] -= lamda01*r01[0];
f[i1][1] -= lamda01*r01[1];
f[i1][2] -= lamda01*r01[2];
}
if (i2 < nlocal) {
f[i2][0] -= lamda02*r02[0];
f[i2][1] -= lamda02*r02[1];
f[i2][2] -= lamda02*r02[2];
}
if (evflag) {
nlist = 0;
if (i0 < nlocal) list[nlist++] = i0;
if (i1 < nlocal) list[nlist++] = i1;
if (i2 < nlocal) list[nlist++] = i2;
v[0] = lamda01*r01[0]*r01[0] + lamda02*r02[0]*r02[0];
v[1] = lamda01*r01[1]*r01[1] + lamda02*r02[1]*r02[1];
v[2] = lamda01*r01[2]*r01[2] + lamda02*r02[2]*r02[2];
v[3] = lamda01*r01[0]*r01[1] + lamda02*r02[0]*r02[1];
v[4] = lamda01*r01[0]*r01[2] + lamda02*r02[0]*r02[2];
v[5] = lamda01*r01[1]*r01[2] + lamda02*r02[1]*r02[2];
v_tally(nlist,list,3.0,v);
}
}
/* ---------------------------------------------------------------------- */
void FixShake::shake4(int m)
{
int nlist,list[4];
double v[6];
double invmass0,invmass1,invmass2,invmass3;
// local atom IDs and constraint distances
int i0 = atom->map(shake_atom[m][0]);
int i1 = atom->map(shake_atom[m][1]);
int i2 = atom->map(shake_atom[m][2]);
int i3 = atom->map(shake_atom[m][3]);
double bond1 = bond_distance[shake_type[m][0]];
double bond2 = bond_distance[shake_type[m][1]];
double bond3 = bond_distance[shake_type[m][2]];
// r01,r02,r03 = distance vec between atoms, with PBC
double r01[3];
r01[0] = x[i0][0] - x[i1][0];
r01[1] = x[i0][1] - x[i1][1];
r01[2] = x[i0][2] - x[i1][2];
domain->minimum_image(r01);
double r02[3];
r02[0] = x[i0][0] - x[i2][0];
r02[1] = x[i0][1] - x[i2][1];
r02[2] = x[i0][2] - x[i2][2];
domain->minimum_image(r02);
double r03[3];
r03[0] = x[i0][0] - x[i3][0];
r03[1] = x[i0][1] - x[i3][1];
r03[2] = x[i0][2] - x[i3][2];
domain->minimum_image(r03);
// s01,s02,s03 = distance vec after unconstrained update, with PBC
// use Domain::minimum_image_once(), not minimum_image()
// b/c xshake values might be huge, due to e.g. fix gcmc
double s01[3];
s01[0] = xshake[i0][0] - xshake[i1][0];
s01[1] = xshake[i0][1] - xshake[i1][1];
s01[2] = xshake[i0][2] - xshake[i1][2];
domain->minimum_image_once(s01);
double s02[3];
s02[0] = xshake[i0][0] - xshake[i2][0];
s02[1] = xshake[i0][1] - xshake[i2][1];
s02[2] = xshake[i0][2] - xshake[i2][2];
domain->minimum_image_once(s02);
double s03[3];
s03[0] = xshake[i0][0] - xshake[i3][0];
s03[1] = xshake[i0][1] - xshake[i3][1];
s03[2] = xshake[i0][2] - xshake[i3][2];
domain->minimum_image_once(s03);
// scalar distances between atoms
double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2];
double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2];
double r03sq = r03[0]*r03[0] + r03[1]*r03[1] + r03[2]*r03[2];
double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2];
double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2];
double s03sq = s03[0]*s03[0] + s03[1]*s03[1] + s03[2]*s03[2];
// matrix coeffs and rhs for lamda equations
if (rmass) {
invmass0 = 1.0/rmass[i0];
invmass1 = 1.0/rmass[i1];
invmass2 = 1.0/rmass[i2];
invmass3 = 1.0/rmass[i3];
} else {
invmass0 = 1.0/mass[type[i0]];
invmass1 = 1.0/mass[type[i1]];
invmass2 = 1.0/mass[type[i2]];
invmass3 = 1.0/mass[type[i3]];
}
double a11 = 2.0 * (invmass0+invmass1) *
(s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]);
double a12 = 2.0 * invmass0 *
(s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]);
double a13 = 2.0 * invmass0 *
(s01[0]*r03[0] + s01[1]*r03[1] + s01[2]*r03[2]);
double a21 = 2.0 * invmass0 *
(s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]);
double a22 = 2.0 * (invmass0+invmass2) *
(s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]);
double a23 = 2.0 * invmass0 *
(s02[0]*r03[0] + s02[1]*r03[1] + s02[2]*r03[2]);
double a31 = 2.0 * invmass0 *
(s03[0]*r01[0] + s03[1]*r01[1] + s03[2]*r01[2]);
double a32 = 2.0 * invmass0 *
(s03[0]*r02[0] + s03[1]*r02[1] + s03[2]*r02[2]);
double a33 = 2.0 * (invmass0+invmass3) *
(s03[0]*r03[0] + s03[1]*r03[1] + s03[2]*r03[2]);
// inverse of matrix;
double determ = a11*a22*a33 + a12*a23*a31 + a13*a21*a32 -
a11*a23*a32 - a12*a21*a33 - a13*a22*a31;
if (determ == 0.0) error->one(FLERR,"Shake determinant = 0.0");
double determinv = 1.0/determ;
double a11inv = determinv * (a22*a33 - a23*a32);
double a12inv = -determinv * (a12*a33 - a13*a32);
double a13inv = determinv * (a12*a23 - a13*a22);
double a21inv = -determinv * (a21*a33 - a23*a31);
double a22inv = determinv * (a11*a33 - a13*a31);
double a23inv = -determinv * (a11*a23 - a13*a21);
double a31inv = determinv * (a21*a32 - a22*a31);
double a32inv = -determinv * (a11*a32 - a12*a31);
double a33inv = determinv * (a11*a22 - a12*a21);
// quadratic correction coeffs
double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]);
double r0103 = (r01[0]*r03[0] + r01[1]*r03[1] + r01[2]*r03[2]);
double r0203 = (r02[0]*r03[0] + r02[1]*r03[1] + r02[2]*r03[2]);
double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq;
double quad1_0202 = invmass0*invmass0 * r02sq;
double quad1_0303 = invmass0*invmass0 * r03sq;
double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102;
double quad1_0103 = 2.0 * (invmass0+invmass1)*invmass0 * r0103;
double quad1_0203 = 2.0 * invmass0*invmass0 * r0203;
double quad2_0101 = invmass0*invmass0 * r01sq;
double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq;
double quad2_0303 = invmass0*invmass0 * r03sq;
double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102;
double quad2_0103 = 2.0 * invmass0*invmass0 * r0103;
double quad2_0203 = 2.0 * (invmass0+invmass2)*invmass0 * r0203;
double quad3_0101 = invmass0*invmass0 * r01sq;
double quad3_0202 = invmass0*invmass0 * r02sq;
double quad3_0303 = (invmass0+invmass3)*(invmass0+invmass3) * r03sq;
double quad3_0102 = 2.0 * invmass0*invmass0 * r0102;
double quad3_0103 = 2.0 * (invmass0+invmass3)*invmass0 * r0103;
double quad3_0203 = 2.0 * (invmass0+invmass3)*invmass0 * r0203;
// iterate until converged
double lamda01 = 0.0;
double lamda02 = 0.0;
double lamda03 = 0.0;
int niter = 0;
int done = 0;
double quad1,quad2,quad3,b1,b2,b3,lamda01_new,lamda02_new,lamda03_new;
while (!done && niter < max_iter) {
quad1 = quad1_0101 * lamda01*lamda01 +
quad1_0202 * lamda02*lamda02 +
quad1_0303 * lamda03*lamda03 +
quad1_0102 * lamda01*lamda02 +
quad1_0103 * lamda01*lamda03 +
quad1_0203 * lamda02*lamda03;
quad2 = quad2_0101 * lamda01*lamda01 +
quad2_0202 * lamda02*lamda02 +
quad2_0303 * lamda03*lamda03 +
quad2_0102 * lamda01*lamda02 +
quad2_0103 * lamda01*lamda03 +
quad2_0203 * lamda02*lamda03;
quad3 = quad3_0101 * lamda01*lamda01 +
quad3_0202 * lamda02*lamda02 +
quad3_0303 * lamda03*lamda03 +
quad3_0102 * lamda01*lamda02 +
quad3_0103 * lamda01*lamda03 +
quad3_0203 * lamda02*lamda03;
b1 = bond1*bond1 - s01sq - quad1;
b2 = bond2*bond2 - s02sq - quad2;
b3 = bond3*bond3 - s03sq - quad3;
lamda01_new = a11inv*b1 + a12inv*b2 + a13inv*b3;
lamda02_new = a21inv*b1 + a22inv*b2 + a23inv*b3;
lamda03_new = a31inv*b1 + a32inv*b2 + a33inv*b3;
done = 1;
if (fabs(lamda01_new-lamda01) > tolerance) done = 0;
if (fabs(lamda02_new-lamda02) > tolerance) done = 0;
if (fabs(lamda03_new-lamda03) > tolerance) done = 0;
lamda01 = lamda01_new;
lamda02 = lamda02_new;
lamda03 = lamda03_new;
+
+ // stop iterations before we have a floating point overflow
+ // max double is < 1.0e308, so 1e150 is a reasonable cutoff
+
+ if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150
+ || fabs(lamda03) > 1e150) done = 1;
+
niter++;
}
// update forces if atom is owned by this processor
lamda01 = lamda01/dtfsq;
lamda02 = lamda02/dtfsq;
lamda03 = lamda03/dtfsq;
if (i0 < nlocal) {
f[i0][0] += lamda01*r01[0] + lamda02*r02[0] + lamda03*r03[0];
f[i0][1] += lamda01*r01[1] + lamda02*r02[1] + lamda03*r03[1];
f[i0][2] += lamda01*r01[2] + lamda02*r02[2] + lamda03*r03[2];
}
if (i1 < nlocal) {
f[i1][0] -= lamda01*r01[0];
f[i1][1] -= lamda01*r01[1];
f[i1][2] -= lamda01*r01[2];
}
if (i2 < nlocal) {
f[i2][0] -= lamda02*r02[0];
f[i2][1] -= lamda02*r02[1];
f[i2][2] -= lamda02*r02[2];
}
if (i3 < nlocal) {
f[i3][0] -= lamda03*r03[0];
f[i3][1] -= lamda03*r03[1];
f[i3][2] -= lamda03*r03[2];
}
if (evflag) {
nlist = 0;
if (i0 < nlocal) list[nlist++] = i0;
if (i1 < nlocal) list[nlist++] = i1;
if (i2 < nlocal) list[nlist++] = i2;
if (i3 < nlocal) list[nlist++] = i3;
v[0] = lamda01*r01[0]*r01[0]+lamda02*r02[0]*r02[0]+lamda03*r03[0]*r03[0];
v[1] = lamda01*r01[1]*r01[1]+lamda02*r02[1]*r02[1]+lamda03*r03[1]*r03[1];
v[2] = lamda01*r01[2]*r01[2]+lamda02*r02[2]*r02[2]+lamda03*r03[2]*r03[2];
v[3] = lamda01*r01[0]*r01[1]+lamda02*r02[0]*r02[1]+lamda03*r03[0]*r03[1];
v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda03*r03[0]*r03[2];
v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda03*r03[1]*r03[2];
v_tally(nlist,list,4.0,v);
}
}
/* ---------------------------------------------------------------------- */
void FixShake::shake3angle(int m)
{
int nlist,list[3];
double v[6];
double invmass0,invmass1,invmass2;
// local atom IDs and constraint distances
int i0 = atom->map(shake_atom[m][0]);
int i1 = atom->map(shake_atom[m][1]);
int i2 = atom->map(shake_atom[m][2]);
double bond1 = bond_distance[shake_type[m][0]];
double bond2 = bond_distance[shake_type[m][1]];
double bond12 = angle_distance[shake_type[m][2]];
// r01,r02,r12 = distance vec between atoms, with PBC
double r01[3];
r01[0] = x[i0][0] - x[i1][0];
r01[1] = x[i0][1] - x[i1][1];
r01[2] = x[i0][2] - x[i1][2];
domain->minimum_image(r01);
double r02[3];
r02[0] = x[i0][0] - x[i2][0];
r02[1] = x[i0][1] - x[i2][1];
r02[2] = x[i0][2] - x[i2][2];
domain->minimum_image(r02);
double r12[3];
r12[0] = x[i1][0] - x[i2][0];
r12[1] = x[i1][1] - x[i2][1];
r12[2] = x[i1][2] - x[i2][2];
domain->minimum_image(r12);
// s01,s02,s12 = distance vec after unconstrained update, with PBC
// use Domain::minimum_image_once(), not minimum_image()
// b/c xshake values might be huge, due to e.g. fix gcmc
double s01[3];
s01[0] = xshake[i0][0] - xshake[i1][0];
s01[1] = xshake[i0][1] - xshake[i1][1];
s01[2] = xshake[i0][2] - xshake[i1][2];
domain->minimum_image_once(s01);
double s02[3];
s02[0] = xshake[i0][0] - xshake[i2][0];
s02[1] = xshake[i0][1] - xshake[i2][1];
s02[2] = xshake[i0][2] - xshake[i2][2];
domain->minimum_image_once(s02);
double s12[3];
s12[0] = xshake[i1][0] - xshake[i2][0];
s12[1] = xshake[i1][1] - xshake[i2][1];
s12[2] = xshake[i1][2] - xshake[i2][2];
domain->minimum_image_once(s12);
// scalar distances between atoms
double r01sq = r01[0]*r01[0] + r01[1]*r01[1] + r01[2]*r01[2];
double r02sq = r02[0]*r02[0] + r02[1]*r02[1] + r02[2]*r02[2];
double r12sq = r12[0]*r12[0] + r12[1]*r12[1] + r12[2]*r12[2];
double s01sq = s01[0]*s01[0] + s01[1]*s01[1] + s01[2]*s01[2];
double s02sq = s02[0]*s02[0] + s02[1]*s02[1] + s02[2]*s02[2];
double s12sq = s12[0]*s12[0] + s12[1]*s12[1] + s12[2]*s12[2];
// matrix coeffs and rhs for lamda equations
if (rmass) {
invmass0 = 1.0/rmass[i0];
invmass1 = 1.0/rmass[i1];
invmass2 = 1.0/rmass[i2];
} else {
invmass0 = 1.0/mass[type[i0]];
invmass1 = 1.0/mass[type[i1]];
invmass2 = 1.0/mass[type[i2]];
}
double a11 = 2.0 * (invmass0+invmass1) *
(s01[0]*r01[0] + s01[1]*r01[1] + s01[2]*r01[2]);
double a12 = 2.0 * invmass0 *
(s01[0]*r02[0] + s01[1]*r02[1] + s01[2]*r02[2]);
double a13 = - 2.0 * invmass1 *
(s01[0]*r12[0] + s01[1]*r12[1] + s01[2]*r12[2]);
double a21 = 2.0 * invmass0 *
(s02[0]*r01[0] + s02[1]*r01[1] + s02[2]*r01[2]);
double a22 = 2.0 * (invmass0+invmass2) *
(s02[0]*r02[0] + s02[1]*r02[1] + s02[2]*r02[2]);
double a23 = 2.0 * invmass2 *
(s02[0]*r12[0] + s02[1]*r12[1] + s02[2]*r12[2]);
double a31 = - 2.0 * invmass1 *
(s12[0]*r01[0] + s12[1]*r01[1] + s12[2]*r01[2]);
double a32 = 2.0 * invmass2 *
(s12[0]*r02[0] + s12[1]*r02[1] + s12[2]*r02[2]);
double a33 = 2.0 * (invmass1+invmass2) *
(s12[0]*r12[0] + s12[1]*r12[1] + s12[2]*r12[2]);
// inverse of matrix
double determ = a11*a22*a33 + a12*a23*a31 + a13*a21*a32 -
a11*a23*a32 - a12*a21*a33 - a13*a22*a31;
if (determ == 0.0) error->one(FLERR,"Shake determinant = 0.0");
double determinv = 1.0/determ;
double a11inv = determinv * (a22*a33 - a23*a32);
double a12inv = -determinv * (a12*a33 - a13*a32);
double a13inv = determinv * (a12*a23 - a13*a22);
double a21inv = -determinv * (a21*a33 - a23*a31);
double a22inv = determinv * (a11*a33 - a13*a31);
double a23inv = -determinv * (a11*a23 - a13*a21);
double a31inv = determinv * (a21*a32 - a22*a31);
double a32inv = -determinv * (a11*a32 - a12*a31);
double a33inv = determinv * (a11*a22 - a12*a21);
// quadratic correction coeffs
double r0102 = (r01[0]*r02[0] + r01[1]*r02[1] + r01[2]*r02[2]);
double r0112 = (r01[0]*r12[0] + r01[1]*r12[1] + r01[2]*r12[2]);
double r0212 = (r02[0]*r12[0] + r02[1]*r12[1] + r02[2]*r12[2]);
double quad1_0101 = (invmass0+invmass1)*(invmass0+invmass1) * r01sq;
double quad1_0202 = invmass0*invmass0 * r02sq;
double quad1_1212 = invmass1*invmass1 * r12sq;
double quad1_0102 = 2.0 * (invmass0+invmass1)*invmass0 * r0102;
double quad1_0112 = - 2.0 * (invmass0+invmass1)*invmass1 * r0112;
double quad1_0212 = - 2.0 * invmass0*invmass1 * r0212;
double quad2_0101 = invmass0*invmass0 * r01sq;
double quad2_0202 = (invmass0+invmass2)*(invmass0+invmass2) * r02sq;
double quad2_1212 = invmass2*invmass2 * r12sq;
double quad2_0102 = 2.0 * (invmass0+invmass2)*invmass0 * r0102;
double quad2_0112 = 2.0 * invmass0*invmass2 * r0112;
double quad2_0212 = 2.0 * (invmass0+invmass2)*invmass2 * r0212;
double quad3_0101 = invmass1*invmass1 * r01sq;
double quad3_0202 = invmass2*invmass2 * r02sq;
double quad3_1212 = (invmass1+invmass2)*(invmass1+invmass2) * r12sq;
double quad3_0102 = - 2.0 * invmass1*invmass2 * r0102;
double quad3_0112 = - 2.0 * (invmass1+invmass2)*invmass1 * r0112;
double quad3_0212 = 2.0 * (invmass1+invmass2)*invmass2 * r0212;
// iterate until converged
double lamda01 = 0.0;
double lamda02 = 0.0;
double lamda12 = 0.0;
int niter = 0;
int done = 0;
double quad1,quad2,quad3,b1,b2,b3,lamda01_new,lamda02_new,lamda12_new;
while (!done && niter < max_iter) {
quad1 = quad1_0101 * lamda01*lamda01 +
quad1_0202 * lamda02*lamda02 +
quad1_1212 * lamda12*lamda12 +
quad1_0102 * lamda01*lamda02 +
quad1_0112 * lamda01*lamda12 +
quad1_0212 * lamda02*lamda12;
quad2 = quad2_0101 * lamda01*lamda01 +
quad2_0202 * lamda02*lamda02 +
quad2_1212 * lamda12*lamda12 +
quad2_0102 * lamda01*lamda02 +
quad2_0112 * lamda01*lamda12 +
quad2_0212 * lamda02*lamda12;
quad3 = quad3_0101 * lamda01*lamda01 +
quad3_0202 * lamda02*lamda02 +
quad3_1212 * lamda12*lamda12 +
quad3_0102 * lamda01*lamda02 +
quad3_0112 * lamda01*lamda12 +
quad3_0212 * lamda02*lamda12;
b1 = bond1*bond1 - s01sq - quad1;
b2 = bond2*bond2 - s02sq - quad2;
b3 = bond12*bond12 - s12sq - quad3;
lamda01_new = a11inv*b1 + a12inv*b2 + a13inv*b3;
lamda02_new = a21inv*b1 + a22inv*b2 + a23inv*b3;
lamda12_new = a31inv*b1 + a32inv*b2 + a33inv*b3;
done = 1;
if (fabs(lamda01_new-lamda01) > tolerance) done = 0;
if (fabs(lamda02_new-lamda02) > tolerance) done = 0;
if (fabs(lamda12_new-lamda12) > tolerance) done = 0;
lamda01 = lamda01_new;
lamda02 = lamda02_new;
lamda12 = lamda12_new;
+
+ // stop iterations before we have a floating point overflow
+ // max double is < 1.0e308, so 1e150 is a reasonable cutoff
+
+ if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150
+ || fabs(lamda12) > 1e150) done = 1;
+
niter++;
}
// update forces if atom is owned by this processor
lamda01 = lamda01/dtfsq;
lamda02 = lamda02/dtfsq;
lamda12 = lamda12/dtfsq;
if (i0 < nlocal) {
f[i0][0] += lamda01*r01[0] + lamda02*r02[0];
f[i0][1] += lamda01*r01[1] + lamda02*r02[1];
f[i0][2] += lamda01*r01[2] + lamda02*r02[2];
}
if (i1 < nlocal) {
f[i1][0] -= lamda01*r01[0] - lamda12*r12[0];
f[i1][1] -= lamda01*r01[1] - lamda12*r12[1];
f[i1][2] -= lamda01*r01[2] - lamda12*r12[2];
}
if (i2 < nlocal) {
f[i2][0] -= lamda02*r02[0] + lamda12*r12[0];
f[i2][1] -= lamda02*r02[1] + lamda12*r12[1];
f[i2][2] -= lamda02*r02[2] + lamda12*r12[2];
}
if (evflag) {
nlist = 0;
if (i0 < nlocal) list[nlist++] = i0;
if (i1 < nlocal) list[nlist++] = i1;
if (i2 < nlocal) list[nlist++] = i2;
v[0] = lamda01*r01[0]*r01[0]+lamda02*r02[0]*r02[0]+lamda12*r12[0]*r12[0];
v[1] = lamda01*r01[1]*r01[1]+lamda02*r02[1]*r02[1]+lamda12*r12[1]*r12[1];
v[2] = lamda01*r01[2]*r01[2]+lamda02*r02[2]*r02[2]+lamda12*r12[2]*r12[2];
v[3] = lamda01*r01[0]*r01[1]+lamda02*r02[0]*r02[1]+lamda12*r12[0]*r12[1];
v[4] = lamda01*r01[0]*r01[2]+lamda02*r02[0]*r02[2]+lamda12*r12[0]*r12[2];
v[5] = lamda01*r01[1]*r01[2]+lamda02*r02[1]*r02[2]+lamda12*r12[1]*r12[2];
v_tally(nlist,list,3.0,v);
}
}
/* ----------------------------------------------------------------------
print-out bond & angle statistics
------------------------------------------------------------------------- */
void FixShake::stats()
{
int i,j,m,n,iatom,jatom,katom;
double delx,dely,delz;
double r,r1,r2,r3,angle;
// zero out accumulators
int nb = atom->nbondtypes + 1;
int na = atom->nangletypes + 1;
for (i = 0; i < nb; i++) {
b_count[i] = 0;
b_ave[i] = b_max[i] = 0.0;
b_min[i] = BIG;
}
for (i = 0; i < na; i++) {
a_count[i] = 0;
a_ave[i] = a_max[i] = 0.0;
a_min[i] = BIG;
}
// log stats for each bond & angle
// OK to double count since are just averaging
double **x = atom->x;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
// bond stats
n = shake_flag[i];
if (n == 1) n = 3;
iatom = atom->map(shake_atom[i][0]);
for (j = 1; j < n; j++) {
jatom = atom->map(shake_atom[i][j]);
delx = x[iatom][0] - x[jatom][0];
dely = x[iatom][1] - x[jatom][1];
delz = x[iatom][2] - x[jatom][2];
domain->minimum_image(delx,dely,delz);
r = sqrt(delx*delx + dely*dely + delz*delz);
m = shake_type[i][j-1];
b_count[m]++;
b_ave[m] += r;
b_max[m] = MAX(b_max[m],r);
b_min[m] = MIN(b_min[m],r);
}
// angle stats
if (shake_flag[i] == 1) {
iatom = atom->map(shake_atom[i][0]);
jatom = atom->map(shake_atom[i][1]);
katom = atom->map(shake_atom[i][2]);
delx = x[iatom][0] - x[jatom][0];
dely = x[iatom][1] - x[jatom][1];
delz = x[iatom][2] - x[jatom][2];
domain->minimum_image(delx,dely,delz);
r1 = sqrt(delx*delx + dely*dely + delz*delz);
delx = x[iatom][0] - x[katom][0];
dely = x[iatom][1] - x[katom][1];
delz = x[iatom][2] - x[katom][2];
domain->minimum_image(delx,dely,delz);
r2 = sqrt(delx*delx + dely*dely + delz*delz);
delx = x[jatom][0] - x[katom][0];
dely = x[jatom][1] - x[katom][1];
delz = x[jatom][2] - x[katom][2];
domain->minimum_image(delx,dely,delz);
r3 = sqrt(delx*delx + dely*dely + delz*delz);
angle = acos((r1*r1 + r2*r2 - r3*r3) / (2.0*r1*r2));
angle *= 180.0/MY_PI;
m = shake_type[i][2];
a_count[m]++;
a_ave[m] += angle;
a_max[m] = MAX(a_max[m],angle);
a_min[m] = MIN(a_min[m],angle);
}
}
// sum across all procs
MPI_Allreduce(b_count,b_count_all,nb,MPI_INT,MPI_SUM,world);
MPI_Allreduce(b_ave,b_ave_all,nb,MPI_DOUBLE,MPI_SUM,world);
MPI_Allreduce(b_max,b_max_all,nb,MPI_DOUBLE,MPI_MAX,world);
MPI_Allreduce(b_min,b_min_all,nb,MPI_DOUBLE,MPI_MIN,world);
MPI_Allreduce(a_count,a_count_all,na,MPI_INT,MPI_SUM,world);
MPI_Allreduce(a_ave,a_ave_all,na,MPI_DOUBLE,MPI_SUM,world);
MPI_Allreduce(a_max,a_max_all,na,MPI_DOUBLE,MPI_MAX,world);
MPI_Allreduce(a_min,a_min_all,na,MPI_DOUBLE,MPI_MIN,world);
// print stats only for non-zero counts
if (me == 0) {
if (screen) {
fprintf(screen,
"SHAKE stats (type/ave/delta) on step " BIGINT_FORMAT "\n",
update->ntimestep);
for (i = 1; i < nb; i++)
if (b_count_all[i])
fprintf(screen," %d %g %g %d\n",i,
b_ave_all[i]/b_count_all[i],b_max_all[i]-b_min_all[i],
b_count_all[i]);
for (i = 1; i < na; i++)
if (a_count_all[i])
fprintf(screen," %d %g %g\n",i,
a_ave_all[i]/a_count_all[i],a_max_all[i]-a_min_all[i]);
}
if (logfile) {
fprintf(logfile,
"SHAKE stats (type/ave/delta) on step " BIGINT_FORMAT "\n",
update->ntimestep);
for (i = 0; i < nb; i++)
if (b_count_all[i])
fprintf(logfile," %d %g %g\n",i,
b_ave_all[i]/b_count_all[i],b_max_all[i]-b_min_all[i]);
for (i = 0; i < na; i++)
if (a_count_all[i])
fprintf(logfile," %d %g %g\n",i,
a_ave_all[i]/a_count_all[i],a_max_all[i]-a_min_all[i]);
}
}
// next timestep for stats
next_output += output_every;
}
/* ----------------------------------------------------------------------
find a bond between global atom IDs n1 and n2 stored with local atom i
if find it:
if setflag = 0, return bond type
if setflag = -1/1, set bond type to negative/positive and return 0
if do not find it, return 0
------------------------------------------------------------------------- */
int FixShake::bondtype_findset(int i, tagint n1, tagint n2, int setflag)
{
int m,nbonds;
int *btype;
if (molecular == 1) {
tagint *tag = atom->tag;
tagint **bond_atom = atom->bond_atom;
nbonds = atom->num_bond[i];
for (m = 0; m < nbonds; m++) {
if (n1 == tag[i] && n2 == bond_atom[i][m]) break;
if (n1 == bond_atom[i][m] && n2 == tag[i]) break;
}
} else {
int imol = atom->molindex[i];
int iatom = atom->molatom[i];
tagint *tag = atom->tag;
tagint tagprev = tag[i] - iatom - 1;
tagint *batom = atommols[imol]->bond_atom[iatom];
btype = atommols[imol]->bond_type[iatom];
nbonds = atommols[imol]->num_bond[iatom];
for (m = 0; m < nbonds; m++) {
if (n1 == tag[i] && n2 == batom[m]+tagprev) break;
if (n1 == batom[m]+tagprev && n2 == tag[i]) break;
}
}
if (m < nbonds) {
if (setflag == 0) {
if (molecular == 1) return atom->bond_type[i][m];
else return btype[m];
}
if (molecular == 1) {
if ((setflag < 0 && atom->bond_type[i][m] > 0) ||
(setflag > 0 && atom->bond_type[i][m] < 0))
atom->bond_type[i][m] = -atom->bond_type[i][m];
} else {
if ((setflag < 0 && btype[m] > 0) ||
(setflag > 0 && btype[m] < 0)) btype[m] = -btype[m];
}
}
return 0;
}
/* ----------------------------------------------------------------------
find an angle with global end atom IDs n1 and n2 stored with local atom i
if find it:
if setflag = 0, return angle type
if setflag = -1/1, set angle type to negative/positive and return 0
if do not find it, return 0
------------------------------------------------------------------------- */
int FixShake::angletype_findset(int i, tagint n1, tagint n2, int setflag)
{
int m,nangles;
int *atype;
if (molecular == 1) {
tagint **angle_atom1 = atom->angle_atom1;
tagint **angle_atom3 = atom->angle_atom3;
nangles = atom->num_angle[i];
for (m = 0; m < nangles; m++) {
if (n1 == angle_atom1[i][m] && n2 == angle_atom3[i][m]) break;
if (n1 == angle_atom3[i][m] && n2 == angle_atom1[i][m]) break;
}
} else {
int imol = atom->molindex[i];
int iatom = atom->molatom[i];
tagint *tag = atom->tag;
tagint tagprev = tag[i] - iatom - 1;
tagint *aatom1 = atommols[imol]->angle_atom1[iatom];
tagint *aatom3 = atommols[imol]->angle_atom3[iatom];
atype = atommols[imol]->angle_type[iatom];
nangles = atommols[imol]->num_angle[iatom];
for (m = 0; m < nangles; m++) {
if (n1 == aatom1[m]+tagprev && n2 == aatom3[m]+tagprev) break;
if (n1 == aatom3[m]+tagprev && n2 == aatom1[m]+tagprev) break;
}
}
if (m < nangles) {
if (setflag == 0) {
if (molecular == 1) return atom->angle_type[i][m];
else return atype[m];
}
if (molecular == 1) {
if ((setflag < 0 && atom->angle_type[i][m] > 0) ||
(setflag > 0 && atom->angle_type[i][m] < 0))
atom->angle_type[i][m] = -atom->angle_type[i][m];
} else {
if ((setflag < 0 && atype[m] > 0) ||
(setflag > 0 && atype[m] < 0)) atype[m] = -atype[m];
}
}
return 0;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixShake::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax * sizeof(int);
bytes += nmax*4 * sizeof(int);
bytes += nmax*3 * sizeof(int);
bytes += nmax*3 * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixShake::grow_arrays(int nmax)
{
memory->grow(shake_flag,nmax,"shake:shake_flag");
memory->grow(shake_atom,nmax,4,"shake:shake_atom");
memory->grow(shake_type,nmax,3,"shake:shake_type");
memory->destroy(xshake);
memory->create(xshake,nmax,3,"shake:xshake");
memory->destroy(ftmp);
memory->create(ftmp,nmax,3,"shake:ftmp");
memory->destroy(vtmp);
memory->create(vtmp,nmax,3,"shake:vtmp");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixShake::copy_arrays(int i, int j, int delflag)
{
int flag = shake_flag[j] = shake_flag[i];
if (flag == 1) {
shake_atom[j][0] = shake_atom[i][0];
shake_atom[j][1] = shake_atom[i][1];
shake_atom[j][2] = shake_atom[i][2];
shake_type[j][0] = shake_type[i][0];
shake_type[j][1] = shake_type[i][1];
shake_type[j][2] = shake_type[i][2];
} else if (flag == 2) {
shake_atom[j][0] = shake_atom[i][0];
shake_atom[j][1] = shake_atom[i][1];
shake_type[j][0] = shake_type[i][0];
} else if (flag == 3) {
shake_atom[j][0] = shake_atom[i][0];
shake_atom[j][1] = shake_atom[i][1];
shake_atom[j][2] = shake_atom[i][2];
shake_type[j][0] = shake_type[i][0];
shake_type[j][1] = shake_type[i][1];
} else if (flag == 4) {
shake_atom[j][0] = shake_atom[i][0];
shake_atom[j][1] = shake_atom[i][1];
shake_atom[j][2] = shake_atom[i][2];
shake_atom[j][3] = shake_atom[i][3];
shake_type[j][0] = shake_type[i][0];
shake_type[j][1] = shake_type[i][1];
shake_type[j][2] = shake_type[i][2];
}
}
/* ----------------------------------------------------------------------
initialize one atom's array values, called when atom is created
------------------------------------------------------------------------- */
void FixShake::set_arrays(int i)
{
shake_flag[i] = 0;
}
/* ----------------------------------------------------------------------
update one atom's array values
called when molecule is created from fix gcmc
------------------------------------------------------------------------- */
void FixShake::update_arrays(int i, int atom_offset)
{
int flag = shake_flag[i];
if (flag == 1) {
shake_atom[i][0] += atom_offset;
shake_atom[i][1] += atom_offset;
shake_atom[i][2] += atom_offset;
} else if (flag == 2) {
shake_atom[i][0] += atom_offset;
shake_atom[i][1] += atom_offset;
} else if (flag == 3) {
shake_atom[i][0] += atom_offset;
shake_atom[i][1] += atom_offset;
shake_atom[i][2] += atom_offset;
} else if (flag == 4) {
shake_atom[i][0] += atom_offset;
shake_atom[i][1] += atom_offset;
shake_atom[i][2] += atom_offset;
shake_atom[i][3] += atom_offset;
}
}
/* ----------------------------------------------------------------------
initialize a molecule inserted by another fix, e.g. deposit or pour
called when molecule is created
nlocalprev = # of atoms on this proc before molecule inserted
tagprev = atom ID previous to new atoms in the molecule
xgeom,vcm,quat ignored
------------------------------------------------------------------------- */
void FixShake::set_molecule(int nlocalprev, tagint tagprev, int imol,
double *xgeom, double *vcm, double *quat)
{
int m,flag;
int nlocal = atom->nlocal;
if (nlocalprev == nlocal) return;
tagint *tag = atom->tag;
tagint **mol_shake_atom = onemols[imol]->shake_atom;
int **mol_shake_type = onemols[imol]->shake_type;
for (int i = nlocalprev; i < nlocal; i++) {
m = tag[i] - tagprev-1;
flag = shake_flag[i] = onemols[imol]->shake_flag[m];
if (flag == 1) {
shake_atom[i][0] = mol_shake_atom[m][0] + tagprev;
shake_atom[i][1] = mol_shake_atom[m][1] + tagprev;
shake_atom[i][2] = mol_shake_atom[m][2] + tagprev;
shake_type[i][0] = mol_shake_type[m][0];
shake_type[i][1] = mol_shake_type[m][1];
shake_type[i][2] = mol_shake_type[m][2];
} else if (flag == 2) {
shake_atom[i][0] = mol_shake_atom[m][0] + tagprev;
shake_atom[i][1] = mol_shake_atom[m][1] + tagprev;
shake_type[i][0] = mol_shake_type[m][0];
} else if (flag == 3) {
shake_atom[i][0] = mol_shake_atom[m][0] + tagprev;
shake_atom[i][1] = mol_shake_atom[m][1] + tagprev;
shake_atom[i][2] = mol_shake_atom[m][2] + tagprev;
shake_type[i][0] = mol_shake_type[m][0];
shake_type[i][1] = mol_shake_type[m][1];
} else if (flag == 4) {
shake_atom[i][0] = mol_shake_atom[m][0] + tagprev;
shake_atom[i][1] = mol_shake_atom[m][1] + tagprev;
shake_atom[i][2] = mol_shake_atom[m][2] + tagprev;
shake_atom[i][3] = mol_shake_atom[m][3] + tagprev;
shake_type[i][0] = mol_shake_type[m][0];
shake_type[i][1] = mol_shake_type[m][1];
shake_type[i][2] = mol_shake_type[m][2];
}
}
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixShake::pack_exchange(int i, double *buf)
{
int m = 0;
buf[m++] = shake_flag[i];
int flag = shake_flag[i];
if (flag == 1) {
buf[m++] = shake_atom[i][0];
buf[m++] = shake_atom[i][1];
buf[m++] = shake_atom[i][2];
buf[m++] = shake_type[i][0];
buf[m++] = shake_type[i][1];
buf[m++] = shake_type[i][2];
} else if (flag == 2) {
buf[m++] = shake_atom[i][0];
buf[m++] = shake_atom[i][1];
buf[m++] = shake_type[i][0];
} else if (flag == 3) {
buf[m++] = shake_atom[i][0];
buf[m++] = shake_atom[i][1];
buf[m++] = shake_atom[i][2];
buf[m++] = shake_type[i][0];
buf[m++] = shake_type[i][1];
} else if (flag == 4) {
buf[m++] = shake_atom[i][0];
buf[m++] = shake_atom[i][1];
buf[m++] = shake_atom[i][2];
buf[m++] = shake_atom[i][3];
buf[m++] = shake_type[i][0];
buf[m++] = shake_type[i][1];
buf[m++] = shake_type[i][2];
}
return m;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixShake::unpack_exchange(int nlocal, double *buf)
{
int m = 0;
int flag = shake_flag[nlocal] = static_cast<int> (buf[m++]);
if (flag == 1) {
shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]);
shake_type[nlocal][0] = static_cast<int> (buf[m++]);
shake_type[nlocal][1] = static_cast<int> (buf[m++]);
shake_type[nlocal][2] = static_cast<int> (buf[m++]);
} else if (flag == 2) {
shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]);
shake_type[nlocal][0] = static_cast<int> (buf[m++]);
} else if (flag == 3) {
shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]);
shake_type[nlocal][0] = static_cast<int> (buf[m++]);
shake_type[nlocal][1] = static_cast<int> (buf[m++]);
} else if (flag == 4) {
shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]);
shake_atom[nlocal][3] = static_cast<tagint> (buf[m++]);
shake_type[nlocal][0] = static_cast<int> (buf[m++]);
shake_type[nlocal][1] = static_cast<int> (buf[m++]);
shake_type[nlocal][2] = static_cast<int> (buf[m++]);
}
return m;
}
/* ---------------------------------------------------------------------- */
int FixShake::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = xshake[j][0];
buf[m++] = xshake[j][1];
buf[m++] = xshake[j][2];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz;
dy = pbc[1]*domain->yprd + pbc[3]*domain->yz;
dz = pbc[2]*domain->zprd;
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = xshake[j][0] + dx;
buf[m++] = xshake[j][1] + dy;
buf[m++] = xshake[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void FixShake::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
xshake[i][0] = buf[m++];
xshake[i][1] = buf[m++];
xshake[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void FixShake::reset_dt()
{
if (strstr(update->integrate_style,"verlet")) {
dtv = update->dt;
if (rattle) dtfsq = 0.5 * update->dt * update->dt * force->ftm2v;
else dtfsq = update->dt * update->dt * force->ftm2v;
} else {
dtv = step_respa[0];
dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v;
if (rattle) dtf_inner = dtf_innerhalf;
else dtf_inner = step_respa[0] * force->ftm2v;
}
}
/* ----------------------------------------------------------------------
extract Molecule ptr
------------------------------------------------------------------------- */
void *FixShake::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"onemol") == 0) return onemols;
return NULL;
}
/* ----------------------------------------------------------------------
add coordinate constraining forces
this method is called at the end of a timestep
------------------------------------------------------------------------- */
void FixShake::shake_end_of_step(int vflag) {
if (!respa) {
dtv = update->dt;
dtfsq = 0.5 * update->dt * update->dt * force->ftm2v;
FixShake::post_force(vflag);
if (!rattle) dtfsq = update->dt * update->dt * force->ftm2v;
} else {
dtv = step_respa[0];
dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v;
dtf_inner = dtf_innerhalf;
// apply correction to all rRESPA levels
for (int ilevel = 0; ilevel < nlevels_respa; ilevel++) {
((Respa *) update->integrate)->copy_flevel_f(ilevel);
FixShake::post_force_respa(vflag,ilevel,loop_respa[ilevel]-1);
((Respa *) update->integrate)->copy_f_flevel(ilevel);
}
if (!rattle) dtf_inner = step_respa[0] * force->ftm2v;
}
}
/* ----------------------------------------------------------------------
wrapper method for end_of_step fixes which modify velocities
------------------------------------------------------------------------- */
void FixShake::correct_velocities() {}
/* ----------------------------------------------------------------------
calculate constraining forces based on the current configuration
change coordinates
------------------------------------------------------------------------- */
void FixShake::correct_coordinates(int vflag) {
// save current forces and velocities so that you
// initialise them to zero such that FixShake::unconstrained_coordinate_update has no effect
for (int j=0; j<nlocal; j++) {
for (int k=0; k<3; k++) {
// store current value of forces and velocities
ftmp[j][k] = f[j][k];
vtmp[j][k] = v[j][k];
// set f and v to zero for SHAKE
v[j][k] = 0;
f[j][k] = 0;
}
}
// call SHAKE to correct the coordinates which were updated without constraints
// IMPORTANT: use 1 as argument and thereby enforce velocity Verlet
dtfsq = 0.5 * update->dt * update->dt * force->ftm2v;
FixShake::post_force(vflag);
// integrate coordiantes: x' = xnp1 + dt^2/2m_i * f, where f is the constraining force
// NOTE: After this command, the coordinates geometry of the molecules will be correct!
double dtfmsq;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
dtfmsq = dtfsq/ rmass[i];
x[i][0] = x[i][0] + dtfmsq*f[i][0];
x[i][1] = x[i][1] + dtfmsq*f[i][1];
x[i][2] = x[i][2] + dtfmsq*f[i][2];
}
}
else {
for (int i = 0; i < nlocal; i++) {
dtfmsq = dtfsq / mass[type[i]];
x[i][0] = x[i][0] + dtfmsq*f[i][0];
x[i][1] = x[i][1] + dtfmsq*f[i][1];
x[i][2] = x[i][2] + dtfmsq*f[i][2];
}
}
// copy forces and velocities back
for (int j=0; j<nlocal; j++) {
for (int k=0; k<3; k++) {
f[j][k] = ftmp[j][k];
v[j][k] = vtmp[j][k];
}
}
if (!rattle) dtfsq = update->dt * update->dt * force->ftm2v;
// communicate changes
// NOTE: for compatibility xshake is temporarily set to x, such that pack/unpack_forward
// can be used for communicating the coordinates.
double **xtmp = xshake;
xshake = x;
if (nprocs > 1) {
comm->forward_comm_fix(this);
}
xshake = xtmp;
}
diff --git a/src/USER-CGSDK/pair_lj_sdk.cpp b/src/USER-CGSDK/pair_lj_sdk.cpp
index 23b0f47a6..56e56c960 100644
--- a/src/USER-CGSDK/pair_lj_sdk.cpp
+++ b/src/USER-CGSDK/pair_lj_sdk.cpp
@@ -1,510 +1,510 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
This style is a simplified re-implementation of the CG/CMM pair style
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_sdk.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include "lj_sdk_common.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace LJSDKParms;
/* ---------------------------------------------------------------------- */
PairLJSDK::PairLJSDK(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 0;
single_enable = 1;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJSDK::~PairLJSDK()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(lj_type);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
memory->destroy(rminsq);
memory->destroy(emin);
allocated = 0;
}
}
/* ---------------------------------------------------------------------- */
void PairLJSDK::compute(int eflag, int vflag)
{
if (eflag || vflag) {
ev_setup(eflag,vflag);
} else evflag = vflag_fdotr = 0;
if (evflag) {
if (eflag) {
if (force->newton_pair) eval<1,1,1>();
else eval<1,1,0>();
} else {
if (force->newton_pair) eval<1,0,1>();
else eval<1,0,0>();
}
} else {
if (force->newton_pair) eval<0,0,1>();
else eval<0,0,0>();
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
template <int EVFLAG, int EFLAG, int NEWTON_PAIR>
void PairLJSDK::eval()
{
int i,j,ii,jj,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,forcelj,factor_lj;
evdwl = 0.0;
const double * const * const x = atom->x;
double * const * const f = atom->f;
const int * const type = atom->type;
const int nlocal = atom->nlocal;
const double * const special_lj = force->special_lj;
double fxtmp,fytmp,fztmp;
const int inum = list->inum;
const int * const ilist = list->ilist;
const int * const numneigh = list->numneigh;
const int * const * const firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
fxtmp=fytmp=fztmp=0.0;
const int itype = type[i];
const int * const jlist = firstneigh[i];
const int jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
const int ljt = lj_type[itype][jtype];
if (ljt == LJ12_4) {
const double r4inv=r2inv*r2inv;
forcelj = r4inv*(lj1[itype][jtype]*r4inv*r4inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r4inv*(lj3[itype][jtype]*r4inv*r4inv
- lj4[itype][jtype]) - offset[itype][jtype];
} else if (ljt == LJ9_6) {
const double r3inv = r2inv*sqrt(r2inv);
const double r6inv = r3inv*r3inv;
forcelj = r6inv*(lj1[itype][jtype]*r3inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r6inv*(lj3[itype][jtype]*r3inv
- lj4[itype][jtype]) - offset[itype][jtype];
} else if (ljt == LJ12_6) {
const double r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv*(lj1[itype][jtype]*r6inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r6inv*(lj3[itype][jtype]*r6inv
- lj4[itype][jtype]) - offset[itype][jtype];
} else continue;
fpair = factor_lj*forcelj*r2inv;
fxtmp += delx*fpair;
fytmp += dely*fpair;
fztmp += delz*fpair;
if (NEWTON_PAIR || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (EFLAG) evdwl *= factor_lj;
if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR,
evdwl,0.0,fpair,delx,dely,delz);
}
}
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJSDK::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
memory->create(lj_type,n+1,n+1,"pair:lj_type");
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
setflag[i][j] = 0;
lj_type[i][j] = LJ_NOT_SET;
}
}
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
memory->create(rminsq,n+1,n+1,"pair:rminsq");
memory->create(emin,n+1,n+1,"pair:emin");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJSDK::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJSDK::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
int lj_type_one = find_lj_type(arg[2],lj_type_list);
if (lj_type_one == LJ_NOT_SET)
error->all(FLERR,"Cannot parse LJ type flag.");
double epsilon_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
lj_type[i][j] = lj_type_one;
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJSDK::init_one(int i, int j)
{
if (setflag[i][j] == 0)
error->all(FLERR,"No mixing support for lj/sdk. "
"Coefficients for all pairs need to be set explicitly.");
const int ljt = lj_type[i][j];
if (ljt == LJ_NOT_SET)
error->all(FLERR,"unrecognized LJ parameter flag");
lj1[i][j] = lj_prefact[ljt] * lj_pow1[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]);
lj2[i][j] = lj_prefact[ljt] * lj_pow2[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]);
lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]);
lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = lj_prefact[ljt] * epsilon[i][j] * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt]));
} else offset[i][j] = 0.0;
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
cut[j][i] = cut[i][j];
cutsq[j][i] = cutsq[i][j];
offset[j][i] = offset[i][j];
lj_type[j][i] = lj_type[i][j];
// compute derived parameters for SDK angle potential
const double eps = epsilon[i][j];
const double sig = sigma[i][j];
const double rmin = sig*exp(1.0/(lj_pow1[ljt]-lj_pow2[ljt])
*log(lj_pow1[ljt]/lj_pow2[ljt]) );
rminsq[j][i] = rminsq[i][j] = rmin*rmin;
const double ratio = sig/rmin;
const double emin_one = lj_prefact[ljt] * eps * (pow(ratio,lj_pow1[ljt])
- pow(ratio,lj_pow2[ljt]));
emin[j][i] = emin[i][j] = emin_one;
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag)
error->all(FLERR,"Tail flag not supported by lj/sdk pair style");
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJSDK::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&lj_type[i][j],sizeof(int),1,fp);
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJSDK::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&lj_type[i][j],sizeof(int),1,fp);
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&lj_type[i][j],1,MPI_INT,0,world);
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJSDK::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJSDK::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
lj/sdk does not support per atom type output with mixing
------------------------------------------------------------------------- */
void PairLJSDK::write_data(FILE *)
{
error->one(FLERR, "Pair style lj/sdk requires using "
"write_data with the 'pair ij' option");
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJSDK::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %s %g %g %g\n",i,j,lj_type_list[lj_type[i][j]],
epsilon[i][j],sigma[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJSDK::single(int, int, int itype, int jtype, double rsq,
double, double factor_lj, double &fforce)
{
if (rsq < cutsq[itype][jtype]) {
const int ljt = lj_type[itype][jtype];
const double ljpow1 = lj_pow1[ljt];
const double ljpow2 = lj_pow2[ljt];
const double ljpref = lj_prefact[ljt];
const double ratio = sigma[itype][jtype]/sqrt(rsq);
const double eps = epsilon[itype][jtype];
fforce = factor_lj * ljpref*eps * (ljpow1*pow(ratio,ljpow1)
- ljpow2*pow(ratio,ljpow2))/rsq;
return factor_lj * (ljpref*eps * (pow(ratio,ljpow1) - pow(ratio,ljpow2))
- offset[itype][jtype]);
} else fforce=0.0;
return 0.0;
}
/* ---------------------------------------------------------------------- */
void *PairLJSDK::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lj_type") == 0) return (void *) lj_type;
if (strcmp(str,"lj1") == 0) return (void *) lj1;
if (strcmp(str,"lj2") == 0) return (void *) lj2;
if (strcmp(str,"lj3") == 0) return (void *) lj3;
if (strcmp(str,"lj4") == 0) return (void *) lj4;
if (strcmp(str,"rminsq") == 0) return (void *) rminsq;
if (strcmp(str,"emin") == 0) return (void *) emin;
return NULL;
}
/* ---------------------------------------------------------------------- */
double PairLJSDK::memory_usage()
{
double bytes = Pair::memory_usage();
int n = atom->ntypes;
// setflag/lj_type
bytes += 2 * (n+1)*(n+1)*sizeof(int);
// cut/cutsq/epsilon/sigma/offset/lj1/lj2/lj3/lj4/rminsq/emin
bytes += 11 * (n+1)*(n+1)*sizeof(double);
return bytes;
}
diff --git a/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp b/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp
index 845c5822a..4c9e42f77 100644
--- a/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp
+++ b/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp
@@ -1,658 +1,658 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
This style is a simplified re-implementation of the CG/CMM pair style
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_sdk_coul_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include "lj_sdk_common.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace LJSDKParms;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJSDKCoulLong::PairLJSDKCoulLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
respa_enable = 0;
writedata = 1;
ftable = NULL;
}
/* ---------------------------------------------------------------------- */
PairLJSDKCoulLong::~PairLJSDKCoulLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(lj_type);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
memory->destroy(rminsq);
memory->destroy(emin);
allocated = 0;
}
if (ftable) free_tables();
}
/* ---------------------------------------------------------------------- */
void PairLJSDKCoulLong::compute(int eflag, int vflag)
{
if (eflag || vflag) {
ev_setup(eflag,vflag);
} else evflag = vflag_fdotr = 0;
if (evflag) {
if (eflag) {
if (force->newton_pair) eval<1,1,1>();
else eval<1,1,0>();
} else {
if (force->newton_pair) eval<1,0,1>();
else eval<1,0,0>();
}
} else {
if (force->newton_pair) eval<0,0,1>();
else eval<0,0,0>();
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
template <int EVFLAG, int EFLAG, int NEWTON_PAIR>
void PairLJSDKCoulLong::eval()
{
int i,ii,j,jj,jtype,itable;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double fraction,table;
double r,rsq,r2inv,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
const double * const * const x = atom->x;
double * const * const f = atom->f;
const double * const q = atom->q;
const int * const type = atom->type;
const int nlocal = atom->nlocal;
const double * const special_coul = force->special_coul;
const double * const special_lj = force->special_lj;
const double qqrd2e = force->qqrd2e;
double fxtmp,fytmp,fztmp;
const int inum = list->inum;
const int * const ilist = list->ilist;
const int * const numneigh = list->numneigh;
const int * const * const firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
fxtmp=fytmp=fztmp=0.0;
const int itype = type[i];
const int * const jlist = firstneigh[i];
const int jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
forcecoul = forcelj = evdwl = ecoul = 0.0;
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
const int ljt = lj_type[itype][jtype];
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = qqrd2e * qtmp*q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (EFLAG) ecoul = prefactor*erfc;
if (factor_coul < 1.0) {
forcecoul -= (1.0-factor_coul)*prefactor;
if (EFLAG) ecoul -= (1.0-factor_coul)*prefactor;
}
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qtmp*q[j] * table;
if (EFLAG) ecoul = qtmp*q[j] *
(etable[itable] + fraction*detable[itable]);
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qtmp*q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
if (EFLAG) ecoul -= (1.0-factor_coul)*prefactor;
}
}
}
if (rsq < cut_ljsq[itype][jtype]) {
if (ljt == LJ12_4) {
const double r4inv=r2inv*r2inv;
forcelj = r4inv*(lj1[itype][jtype]*r4inv*r4inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r4inv*(lj3[itype][jtype]*r4inv*r4inv
- lj4[itype][jtype]) - offset[itype][jtype];
} else if (ljt == LJ9_6) {
const double r3inv = r2inv*sqrt(r2inv);
const double r6inv = r3inv*r3inv;
forcelj = r6inv*(lj1[itype][jtype]*r3inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r6inv*(lj3[itype][jtype]*r3inv
- lj4[itype][jtype]) - offset[itype][jtype];
} else if (ljt == LJ12_6) {
const double r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv*(lj1[itype][jtype]*r6inv
- lj2[itype][jtype]);
if (EFLAG)
evdwl = r6inv*(lj3[itype][jtype]*r6inv
- lj4[itype][jtype]) - offset[itype][jtype];
}
forcelj *= factor_lj;
if (EFLAG) evdwl *= factor_lj;
}
fpair = (forcecoul + forcelj) * r2inv;
fxtmp += delx*fpair;
fytmp += dely*fpair;
fztmp += delz*fpair;
if (NEWTON_PAIR || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (EVFLAG) ev_tally(i,j,nlocal,NEWTON_PAIR,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
memory->create(lj_type,n+1,n+1,"pair:lj_type");
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
setflag[i][j] = 0;
lj_type[i][j] = LJ_NOT_SET;
}
}
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
memory->create(rminsq,n+1,n+1,"pair:rminsq");
memory->create(emin,n+1,n+1,"pair:emin");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
int lj_type_one = find_lj_type(arg[2],lj_type_list);
if (lj_type_one == LJ_NOT_SET)
error->all(FLERR,"Cannot parse LJ type flag.");
double epsilon_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
double cut_lj_one = cut_lj_global;
if (narg == 6) cut_lj_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
lj_type[i][j] = lj_type_one;
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/long requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
// setup force tables (no rRESPA support yet)
if (ncoultablebits) init_tables(cut_coul,NULL);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJSDKCoulLong::init_one(int i, int j)
{
if (setflag[i][j] == 0)
error->all(FLERR,"No mixing support for lj/sdk/coul/long. "
"Coefficients for all pairs need to be set explicitly.");
const int ljt = lj_type[i][j];
if (ljt == LJ_NOT_SET)
error->all(FLERR,"unrecognized LJ parameter flag");
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = lj_prefact[ljt] * lj_pow1[ljt] * epsilon[i][j] *
pow(sigma[i][j],lj_pow1[ljt]);
lj2[i][j] = lj_prefact[ljt] * lj_pow2[ljt] * epsilon[i][j] *
pow(sigma[i][j],lj_pow2[ljt]);
lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]);
lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = lj_prefact[ljt] * epsilon[i][j] *
(pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt]));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_lj[j][i] = cut_lj[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
lj_type[j][i] = lj_type[i][j];
// compute LJ derived parameters for SDK angle potential (LJ only!)
const double eps = epsilon[i][j];
const double sig = sigma[i][j];
const double rmin = sig*exp(1.0/(lj_pow1[ljt]-lj_pow2[ljt])
*log(lj_pow1[ljt]/lj_pow2[ljt]) );
rminsq[j][i] = rminsq[i][j] = rmin*rmin;
const double ratio = sig/rmin;
const double emin_one = lj_prefact[ljt] * eps * (pow(ratio,lj_pow1[ljt])
- pow(ratio,lj_pow2[ljt]));
emin[j][i] = emin[i][j] = emin_one;
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag)
error->all(FLERR,"Tail flag not supported by lj/sdk/coul/long pair style");
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&lj_type[i][j],sizeof(int),1,fp);
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&lj_type[i][j],sizeof(int),1,fp);
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&lj_type[i][j],1,MPI_INT,0,world);
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
lj/sdk does not support per atom type output with mixing
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::write_data(FILE *)
{
error->one(FLERR, "Pair style lj/sdk/coul/* requires using "
"write_data with the 'pair ij' option");
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJSDKCoulLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %s %g %g %g\n",i,j,lj_type_list[lj_type[i][j]],
epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJSDKCoulLong::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,grij,expm2,t,erfc,prefactor;
double fraction,table,forcecoul,forcelj,phicoul,philj;
int itable;
forcecoul = forcelj = phicoul = philj = 0.0;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
phicoul = prefactor*erfc;
if (factor_coul < 1.0) {
forcecoul -= (1.0-factor_coul)*prefactor;
phicoul -= (1.0-factor_coul)*prefactor;
}
} else {
union_int_float_t rsq_lookup_single;
rsq_lookup_single.f = rsq;
itable = rsq_lookup_single.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
phicoul -= (1.0-factor_coul)*prefactor;
}
}
}
if (rsq < cut_ljsq[itype][jtype]) {
const int ljt = lj_type[itype][jtype];
const double ljpow1 = lj_pow1[ljt];
const double ljpow2 = lj_pow2[ljt];
const double ljpref = lj_prefact[ljt];
const double ratio = sigma[itype][jtype]/sqrt(rsq);
const double eps = epsilon[itype][jtype];
forcelj = factor_lj * ljpref*eps * (ljpow1*pow(ratio,ljpow1)
- ljpow2*pow(ratio,ljpow2))/rsq;
philj = factor_lj * (ljpref*eps * (pow(ratio,ljpow1) - pow(ratio,ljpow2))
- offset[itype][jtype]);
}
fforce = (forcecoul + forcelj) * r2inv;
return phicoul + philj;
}
/* ---------------------------------------------------------------------- */
void *PairLJSDKCoulLong::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lj_type") == 0) return (void *) lj_type;
if (strcmp(str,"lj1") == 0) return (void *) lj1;
if (strcmp(str,"lj2") == 0) return (void *) lj2;
if (strcmp(str,"lj3") == 0) return (void *) lj3;
if (strcmp(str,"lj4") == 0) return (void *) lj4;
if (strcmp(str,"rminsq") == 0) return (void *) rminsq;
if (strcmp(str,"emin") == 0) return (void *) emin;
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
/* ---------------------------------------------------------------------- */
double PairLJSDKCoulLong::memory_usage()
{
double bytes = Pair::memory_usage();
int n = atom->ntypes;
// setflag/lj_type
bytes += 2 * (n+1)*(n+1)*sizeof(int);
// lj_cut/lj_cutsq/epsilon/sigma/offset/lj1/lj2/lj3/lj4/rminsq/emin
bytes += 11 * (n+1)*(n+1)*sizeof(double);
if (ncoultablebits) {
int ntable = 1<<ncoultablebits;
bytes += 8 * ntable*sizeof(double);
}
return bytes;
}
diff --git a/src/USER-COLVARS/colvarproxy_lammps.cpp b/src/USER-COLVARS/colvarproxy_lammps.cpp
index 89453ded9..17dff3056 100644
--- a/src/USER-COLVARS/colvarproxy_lammps.cpp
+++ b/src/USER-COLVARS/colvarproxy_lammps.cpp
@@ -1,495 +1,491 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#include <mpi.h>
#include "lammps.h"
#include "atom.h"
#include "error.h"
#include "output.h"
#include "random_park.h"
#include "fix_colvars.h"
#include "colvarmodule.h"
#include "colvar.h"
#include "colvarbias.h"
#include "colvaratoms.h"
#include "colvarproxy.h"
#include "colvarproxy_lammps.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#define HASH_FAIL -1
////////////////////////////////////////////////////////////////////////
// local helper functions
// safely move filename to filename.extension
static int my_backup_file(const char *filename, const char *extension)
{
struct stat sbuf;
if (stat(filename, &sbuf) == 0) {
if (!extension) extension = ".BAK";
char *backup = new char[strlen(filename)+strlen(extension)+1];
strcpy(backup, filename);
strcat(backup, extension);
#if defined(_WIN32) && !defined(__CYGWIN__)
remove(backup);
#endif
if (rename(filename,backup)) {
char *sys_err_msg = strerror(errno);
if (!sys_err_msg) sys_err_msg = (char *) "(unknown error)";
fprintf(stderr,"Error renaming file %s to %s: %s\n",
filename, backup, sys_err_msg);
delete [] backup;
return COLVARS_ERROR;
}
delete [] backup;
}
return COLVARS_OK;
}
////////////////////////////////////////////////////////////////////////
colvarproxy_lammps::colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp,
const char *inp_name,
const char *out_name,
const int seed,
const double temp,
MPI_Comm root2root)
: _lmp(lmp), inter_comm(root2root)
{
if (cvm::debug())
log("Initializing the colvars proxy object.\n");
_random = new LAMMPS_NS::RanPark(lmp,seed);
first_timestep=true;
total_force_requested=false;
previous_step=-1;
t_target=temp;
do_exit=false;
restart_every=0;
// User-scripted forces are not available in LAMMPS
force_script_defined = false;
have_scripts = false;
// set input restart name and strip the extension, if present
input_prefix_str = std::string(inp_name ? inp_name : "");
if (input_prefix_str.rfind(".colvars.state") != std::string::npos)
input_prefix_str.erase(input_prefix_str.rfind(".colvars.state"),
std::string(".colvars.state").size());
// output prefix is always given
output_prefix_str = std::string(out_name);
// not so for restarts
restart_output_prefix_str = std::string("rest");
// check if it is possible to save output configuration
if ((!output_prefix_str.size()) && (!restart_output_prefix_str.size())) {
fatal_error("Error: neither the final output state file or "
"the output restart file could be defined, exiting.\n");
}
// try to extract a restart prefix from a potential restart command.
LAMMPS_NS::Output *outp = _lmp->output;
if ((outp->restart_every_single > 0) && (outp->restart1 != 0)) {
restart_output_prefix_str = std::string(outp->restart1);
} else if ((outp->restart_every_double > 0) && (outp->restart2a != 0)) {
restart_output_prefix_str = std::string(outp->restart2a);
}
// trim off unwanted stuff from the restart prefix
if (restart_output_prefix_str.rfind(".*") != std::string::npos)
restart_output_prefix_str.erase(restart_output_prefix_str.rfind(".*"),2);
#if defined(_OPENMP)
if (smp_thread_id() == 0) {
omp_init_lock(&smp_lock_state);
}
#endif
// initialize multi-replica support, if available
if (replica_enabled()) {
MPI_Comm_rank(inter_comm, &inter_me);
MPI_Comm_size(inter_comm, &inter_num);
}
if (cvm::debug())
log("Done initializing the colvars proxy object.\n");
}
void colvarproxy_lammps::init(const char *conf_file)
{
// create the colvarmodule instance
colvars = new colvarmodule(this);
cvm::log("Using LAMMPS interface, version "+
cvm::to_str(COLVARPROXY_VERSION)+".\n");
my_angstrom = _lmp->force->angstrom;
my_boltzmann = _lmp->force->boltz;
my_timestep = _lmp->update->dt * _lmp->force->femtosecond;
// TODO move one or more of these to setup() if needed
colvars->read_config_file(conf_file);
colvars->setup_input();
colvars->setup_output();
if (_lmp->update->ntimestep != 0) {
cvm::log("Initializing step number as firstTimestep.\n");
colvars->it = colvars->it_restart = _lmp->update->ntimestep;
}
if (cvm::debug()) {
log("atoms_ids = "+cvm::to_str(atoms_ids)+"\n");
log("atoms_ncopies = "+cvm::to_str(atoms_ncopies)+"\n");
log("atoms_positions = "+cvm::to_str(atoms_positions)+"\n");
log(cvm::line_marker);
log("Info: done initializing the colvars proxy object.\n");
}
}
colvarproxy_lammps::~colvarproxy_lammps()
{
delete _random;
if (colvars != NULL) {
colvars->write_output_files();
delete colvars;
colvars = NULL;
}
}
// re-initialize data where needed
int colvarproxy_lammps::setup()
{
my_timestep = _lmp->update->dt * _lmp->force->femtosecond;
return colvars->setup();
}
// trigger colvars computation
double colvarproxy_lammps::compute()
{
if (first_timestep) {
first_timestep = false;
} else {
// Use the time step number inherited from LAMMPS
if ( _lmp->update->ntimestep - previous_step == 1 )
colvars->it++;
// Other cases could mean:
// - run 0
// - beginning of a new run statement
// then the internal counter should not be incremented
}
previous_step = _lmp->update->ntimestep;
if (cvm::debug()) {
cvm::log(std::string(cvm::line_marker)+
"colvarproxy_lammps, step no. "+cvm::to_str(colvars->it)+"\n"+
"Updating internal data.\n");
}
// zero the forces on the atoms, so that they can be accumulated by the colvars
for (size_t i = 0; i < atoms_new_colvar_forces.size(); i++) {
atoms_new_colvar_forces[i].reset();
}
bias_energy = 0.0;
if (cvm::debug()) {
log("atoms_ids = "+cvm::to_str(atoms_ids)+"\n");
log("atoms_ncopies = "+cvm::to_str(atoms_ncopies)+"\n");
log("atoms_positions = "+cvm::to_str(atoms_positions)+"\n");
log("atoms_new_colvar_forces = "+cvm::to_str(atoms_new_colvar_forces)+"\n");
}
// call the collective variable module
colvars->calc();
if (cvm::debug()) {
log("atoms_ids = "+cvm::to_str(atoms_ids)+"\n");
log("atoms_ncopies = "+cvm::to_str(atoms_ncopies)+"\n");
log("atoms_positions = "+cvm::to_str(atoms_positions)+"\n");
log("atoms_new_colvar_forces = "+cvm::to_str(atoms_new_colvar_forces)+"\n");
}
return bias_energy;
}
void colvarproxy_lammps::serialize_status(std::string &rst)
{
std::ostringstream os;
colvars->write_restart(os);
rst = os.str();
}
// set status from string
bool colvarproxy_lammps::deserialize_status(std::string &rst)
{
std::istringstream is;
is.str(rst);
if (!colvars->read_restart(is)) {
return false;
} else {
return true;
}
}
cvm::rvector colvarproxy_lammps::position_distance(cvm::atom_pos const &pos1,
cvm::atom_pos const &pos2)
{
double xtmp = pos2.x - pos1.x;
double ytmp = pos2.y - pos1.y;
double ztmp = pos2.z - pos1.z;
_lmp->domain->minimum_image(xtmp,ytmp,ztmp);
return cvm::rvector(xtmp, ytmp, ztmp);
}
cvm::real colvarproxy_lammps::position_dist2(cvm::atom_pos const &pos1,
cvm::atom_pos const &pos2)
{
double xtmp = pos2.x - pos1.x;
double ytmp = pos2.y - pos1.y;
double ztmp = pos2.z - pos1.z;
_lmp->domain->minimum_image(xtmp,ytmp,ztmp);
return cvm::real(xtmp*xtmp + ytmp*ytmp + ztmp*ztmp);
}
void colvarproxy_lammps::select_closest_image(cvm::atom_pos &pos,
cvm::atom_pos const &ref)
{
double xtmp = pos.x - ref.x;
double ytmp = pos.y - ref.y;
double ztmp = pos.z - ref.z;
_lmp->domain->minimum_image(xtmp,ytmp,ztmp);
pos.x = ref.x + xtmp;
pos.y = ref.y + ytmp;
pos.z = ref.z + ztmp;
}
void colvarproxy_lammps::log(std::string const &message)
{
std::istringstream is(message);
std::string line;
while (std::getline(is, line)) {
if (_lmp->screen)
fprintf(_lmp->screen,"colvars: %s\n",line.c_str());
if (_lmp->logfile)
fprintf(_lmp->logfile,"colvars: %s\n",line.c_str());
}
}
void colvarproxy_lammps::error(std::string const &message)
{
// In LAMMPS, all errors are fatal
fatal_error(message);
}
void colvarproxy_lammps::fatal_error(std::string const &message)
{
log(message);
- // if (!cvm::debug())
- // log("If this error message is unclear, try recompiling the "
- // "colvars library and LAMMPS with -DCOLVARS_DEBUG.\n");
-
_lmp->error->one(FLERR,
"Fatal error in the collective variables module.\n");
}
void colvarproxy_lammps::exit(std::string const &message)
{
log(message);
log("Request to exit the simulation made.\n");
do_exit=true;
}
int colvarproxy_lammps::backup_file(char const *filename)
{
if (std::string(filename).rfind(std::string(".colvars.state"))
!= std::string::npos) {
return my_backup_file(filename, ".old");
} else {
return my_backup_file(filename, ".BAK");
}
}
#if defined(_OPENMP)
// SMP support
int colvarproxy_lammps::smp_enabled()
{
if (b_smp_active) {
return COLVARS_OK;
}
return COLVARS_ERROR;
}
int colvarproxy_lammps::smp_colvars_loop()
{
colvarmodule *cv = this->colvars;
colvarproxy_lammps *proxy = (colvarproxy_lammps *) cv->proxy;
#pragma omp parallel for
for (size_t i = 0; i < cv->variables_active_smp()->size(); i++) {
colvar *x = (*(cv->variables_active_smp()))[i];
int x_item = (*(cv->variables_active_smp_items()))[i];
if (cvm::debug()) {
cvm::log("["+cvm::to_str(proxy->smp_thread_id())+"/"+cvm::to_str(proxy->smp_num_threads())+
"]: calc_colvars_items_smp(), i = "+cvm::to_str(i)+", cv = "+
x->name+", cvc = "+cvm::to_str(x_item)+"\n");
}
x->calc_cvcs(x_item, 1);
}
return cvm::get_error();
}
int colvarproxy_lammps::smp_biases_loop()
{
colvarmodule *cv = this->colvars;
#pragma omp parallel for
for (size_t i = 0; i < cv->biases_active()->size(); i++) {
colvarbias *b = (*(cv->biases_active()))[i];
if (cvm::debug()) {
cvm::log("Calculating bias \""+b->name+"\" on thread "+
cvm::to_str(smp_thread_id())+"\n");
}
b->update();
}
return cvm::get_error();
}
int colvarproxy_lammps::smp_thread_id()
{
return omp_get_thread_num();
}
int colvarproxy_lammps::smp_num_threads()
{
return omp_get_max_threads();
}
int colvarproxy_lammps::smp_lock()
{
omp_set_lock(&smp_lock_state);
return COLVARS_OK;
}
int colvarproxy_lammps::smp_trylock()
{
return omp_test_lock(&smp_lock_state) ? COLVARS_OK : COLVARS_ERROR;
}
int colvarproxy_lammps::smp_unlock()
{
omp_unset_lock(&smp_lock_state);
return COLVARS_OK;
}
#endif
// multi-replica support
void colvarproxy_lammps::replica_comm_barrier() {
MPI_Barrier(inter_comm);
}
int colvarproxy_lammps::replica_comm_recv(char* msg_data,
int buf_len, int src_rep)
{
MPI_Status status;
int retval;
retval = MPI_Recv(msg_data,buf_len,MPI_CHAR,src_rep,0,inter_comm,&status);
if (retval == MPI_SUCCESS) {
MPI_Get_count(&status, MPI_CHAR, &retval);
} else retval = 0;
return retval;
}
int colvarproxy_lammps::replica_comm_send(char* msg_data,
int msg_len, int dest_rep)
{
int retval;
retval = MPI_Send(msg_data,msg_len,MPI_CHAR,dest_rep,0,inter_comm);
if (retval == MPI_SUCCESS) {
retval = msg_len;
} else retval = 0;
return retval;
}
int colvarproxy_lammps::check_atom_id(int atom_number)
{
int const aid = atom_number;
if (cvm::debug())
log("Adding atom "+cvm::to_str(atom_number)+
" for collective variables calculation.\n");
// TODO add upper boundary check?
if ( (aid < 0) ) {
cvm::error("Error: invalid atom number specified, "+
cvm::to_str(atom_number)+"\n", INPUT_ERROR);
return INPUT_ERROR;
}
return aid;
}
int colvarproxy_lammps::init_atom(int atom_number)
{
int aid = atom_number;
for (size_t i = 0; i < atoms_ids.size(); i++) {
if (atoms_ids[i] == aid) {
// this atom id was already recorded
atoms_ncopies[i] += 1;
return i;
}
}
aid = check_atom_id(atom_number);
if (aid < 0) {
return aid;
}
int const index = colvarproxy::add_atom_slot(aid);
// add entries for the LAMMPS-specific fields
atoms_types.push_back(0);
return index;
}
diff --git a/src/USER-COLVARS/colvarproxy_lammps.h b/src/USER-COLVARS/colvarproxy_lammps.h
index ad63eb2f9..6cdf0edfe 100644
--- a/src/USER-COLVARS/colvarproxy_lammps.h
+++ b/src/USER-COLVARS/colvarproxy_lammps.h
@@ -1,182 +1,179 @@
// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
-
#ifndef COLVARPROXY_LAMMPS_H
#define COLVARPROXY_LAMMPS_H
+#include "colvarproxy_lammps_version.h"
+
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvarvalue.h"
#include "lammps.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include <string>
#include <vector>
#include <iostream>
#if defined(_OPENMP)
#include <omp.h>
#endif
-#ifndef COLVARPROXY_VERSION
-#define COLVARPROXY_VERSION "2017-01-09"
-#endif
-
/* struct for packed data communication of coordinates and forces. */
struct commdata {
int tag,type;
double x,y,z,m,q;
};
inline std::ostream & operator<< (std::ostream &out, const commdata &cd)
{
out << " (" << cd.tag << "/" << cd.type << ": "
<< cd.x << ", " << cd.y << ", " << cd.z << ") ";
return out;
}
/// \brief Communication between colvars and LAMMPS
/// (implementation of \link colvarproxy \endlink)
class colvarproxy_lammps : public colvarproxy {
// LAMMPS specific data objects and flags
protected:
// pointers to LAMMPS class instances
class LAMMPS_NS::LAMMPS *_lmp;
class LAMMPS_NS::RanPark *_random;
// state of LAMMPS properties
double t_target, my_timestep, my_boltzmann, my_angstrom;
double bias_energy;
int restart_every;
int previous_step;
bool first_timestep;
bool total_force_requested;
bool do_exit;
// std::vector<int> colvars_atoms;
// std::vector<size_t> colvars_atoms_ncopies;
// std::vector<struct commdata> positions;
// std::vector<struct commdata> total_forces;
// std::vector<struct commdata> applied_forces;
// std::vector<struct commdata> previous_applied_forces;
std::vector<int> atoms_types;
MPI_Comm inter_comm; // MPI comm with 1 root proc from each world
int inter_me, inter_num; // rank for the inter replica comm
public:
friend class cvm::atom;
colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp, const char *,
const char *, const int, const double, MPI_Comm);
virtual ~colvarproxy_lammps();
void init(const char*);
int setup();
// disable default and copy constructor
private:
colvarproxy_lammps() {};
colvarproxy_lammps(const colvarproxy_lammps &) {};
// methods for lammps to move data or trigger actions in the proxy
public:
void set_temperature(double t) { t_target = t; };
bool total_forces_enabled() const { return total_force_requested; };
bool want_exit() const { return do_exit; };
// perform colvars computation. returns biasing energy
double compute();
// dump status to string
void serialize_status(std::string &);
// set status from string
bool deserialize_status(std::string &);
// implementation of pure methods from base class
public:
inline cvm::real unit_angstrom() { return my_angstrom; };
inline cvm::real boltzmann() { return my_boltzmann; };
inline cvm::real temperature() { return t_target; };
inline cvm::real dt() { return my_timestep; }; // return _lmp->update->dt * _lmp->force->femtosecond; };
inline size_t restart_frequency() { return restart_every; };
void add_energy(cvm::real energy) { bias_energy += energy; };
void request_total_force(bool yesno) { total_force_requested = yesno; };
void log(std::string const &message);
void error(std::string const &message);
void fatal_error(std::string const &message);
void exit(std::string const &message);
cvm::rvector position_distance(cvm::atom_pos const &pos1,
cvm::atom_pos const &pos2);
cvm::real position_dist2(cvm::atom_pos const &pos1,
cvm::atom_pos const &pos2);
void select_closest_image(cvm::atom_pos &pos,
cvm::atom_pos const &ref_pos);
int backup_file(char const *filename);
cvm::real rand_gaussian(void) { return _random->gaussian(); };
int init_atom(int atom_number);
int check_atom_id(int atom_number);
inline std::vector<int> *modify_atom_types() { return &atoms_types; }
// implementation of optional methods from base class
public:
#if defined(_OPENMP)
// SMP support
int smp_enabled();
int smp_colvars_loop();
int smp_biases_loop();
int smp_thread_id();
int smp_num_threads();
protected:
omp_lock_t smp_lock_state;
public:
int smp_lock();
int smp_trylock();
int smp_unlock();
#endif
// Multi-replica support
// Indicate if multi-replica support is available and active
virtual bool replica_enabled() { return (inter_comm != MPI_COMM_NULL); }
// Index of this replica
virtual int replica_index() { return inter_me; }
// Total number of replica
virtual int replica_num() { return inter_num; }
// Synchronize replica
virtual void replica_comm_barrier();
// Receive data from other replica
virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep);
// Send data to other replica
virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep);
};
#endif
diff --git a/src/USER-COLVARS/colvarproxy_lammps_version.h b/src/USER-COLVARS/colvarproxy_lammps_version.h
new file mode 100644
index 000000000..834bd1748
--- /dev/null
+++ b/src/USER-COLVARS/colvarproxy_lammps_version.h
@@ -0,0 +1,10 @@
+#ifndef COLVARPROXY_VERSION
+#define COLVARPROXY_VERSION "2017-07-15"
+// This file is part of the Collective Variables module (Colvars).
+// The original version of Colvars and its updates are located at:
+// https://github.com/colvars/colvars
+// Please update all Colvars source files before making any changes.
+// If you wish to distribute your changes, please submit them to the
+// Colvars repository at GitHub.
+
+#endif
diff --git a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp
index a74f51477..ee9c0744d 100644
--- a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp
+++ b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp
@@ -1,705 +1,705 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_thole_long.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 9.95473818e-1
#define B0 -0.1335096380159268
#define B1 -2.57839507e-1
#define B2 -1.37203639e-1
#define B3 -8.88822059e-3
#define B4 -5.80844129e-3
#define B5 1.14652755e-1
/* ---------------------------------------------------------------------- */
PairLJCutTholeLong::PairLJCutTholeLong(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
writedata = 1;
ftable = NULL;
qdist = 0.0;
fix_drude = NULL;
}
/* ---------------------------------------------------------------------- */
PairLJCutTholeLong::~PairLJCutTholeLong()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(polar);
memory->destroy(thole);
memory->destroy(ascreen);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(scale);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
if (ftable) free_tables();
}
/* ---------------------------------------------------------------------- */
void PairLJCutTholeLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
double qi,qj,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair,evdwl;
double r,rsq,r2inv,forcecoul,factor_coul,forcelj,factor_lj,r6inv;
double fraction,table;
double grij,expm2,prefactor,t,erfc,u;
int *ilist,*jlist,*numneigh,**firstneigh;
double factor_f,factor_e;
int di,dj;
double dqi,dqj,dcoul,asr,exp_asr;
int di_closest;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
int *drudetype = fix_drude->drudetype;
tagint *drudeid = fix_drude->drudeid;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qi = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
if (drudetype[type[i]] != NOPOL_TYPE){
di = atom->map(drudeid[i]);
if (di < 0) error->all(FLERR, "Drude partner not found");
di_closest = domain->closest_image(i, di);
if (drudetype[type[i]] == CORE_TYPE)
dqi = -q[di];
else
dqi = qi;
}
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
qj = q[j];
r = sqrt(rsq);
if (!ncoultablebits || rsq <= tabinnersq) {
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
u = 1. - t;
erfc = t * (1.+u*(B0+u*(B1+u*(B2+u*(B3+u*(B4+u*B5)))))) * expm2;
prefactor = qqrd2e * qi*qj/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = qi*qj * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = qi*qj * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
if (drudetype[type[i]] != NOPOL_TYPE &&
drudetype[type[j]] != NOPOL_TYPE){
if (j != di_closest){
if (drudetype[type[j]] == CORE_TYPE){
dj = atom->map(drudeid[j]);
dqj = -q[dj];
} else dqj = qj;
asr = ascreen[type[i]][type[j]] * r;
exp_asr = exp(-asr);
dcoul = qqrd2e * dqi * dqj / r;
factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr))))
- factor_coul;
if (eflag) factor_e = 0.5*(2. - (exp_asr * (2. + asr)))
- factor_coul;
forcecoul += factor_f * dcoul;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
ecoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
ecoul = qi*qj * table;
}
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
if (drudetype[type[i]] != NOPOL_TYPE &&
drudetype[type[j]] != NOPOL_TYPE && j != di_closest){
ecoul += factor_e * dcoul;
}
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutTholeLong::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(scale,n+1,n+1,"pair:scale");
memory->create(ascreen,n+1,n+1,"pair:ascreen");
memory->create(thole,n+1,n+1,"pair:thole");
memory->create(polar,n+1,n+1,"pair:polar");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutTholeLong::settings(int narg, char **arg)
{
if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command");
thole_global = force->numeric(FLERR,arg[0]);
cut_lj_global = force->numeric(FLERR,arg[1]);
if (narg == 2) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[2]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
thole[i][j] = thole_global;
cut_lj[i][j] = cut_lj_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutTholeLong::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double polar_one = force->numeric(FLERR,arg[4]);
double thole_one = thole_global;
if (narg >=6) thole_one = force->numeric(FLERR,arg[5]);
double cut_lj_one = cut_lj_global;
if (narg == 7) cut_lj_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
polar[i][j] = polar_one;
thole[i][j] = thole_one;
ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.);
cut_lj[i][j] = cut_lj_one;
scale[i][j] = 1.0;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutTholeLong::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/thole/long requires atom attribute q");
int ifix;
for (ifix = 0; ifix < modify->nfix; ifix++)
if (strcmp(modify->fix[ifix]->style,"drude") == 0) break;
if (ifix == modify->nfix)
error->all(FLERR, "Pair style lj/cut/thole/long requires fix drude");
fix_drude = (FixDrude *) modify->fix[ifix];
int irequest = neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// set rRESPA cutoffs
cut_respa = NULL;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
// setup force tables
if (ncoultablebits) init_tables(cut_coul,cut_respa);
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCutTholeLong::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutTholeLong::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
polar[i][j] = sqrt(polar[i][i] * polar[j][j]);
thole[i][j] = 0.5 * (thole[i][i] + thole[j][j]);
ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.);
}
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
polar[j][i] = polar[i][j];
thole[j][i] = thole[i][j];
ascreen[j][i] = ascreen[i][j];
scale[j][i] = scale[i][j];
// check interior rRESPA cutoff
if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutTholeLong::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&polar[i][j],sizeof(double),1,fp);
fwrite(&thole[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutTholeLong::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&polar[i][j],sizeof(double),1,fp);
fread(&thole[i][j],sizeof(double),1,fp);
ascreen[i][j] = thole[i][j] / pow(polar[i][j], 1./3.);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&polar[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&thole[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&ascreen[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutTholeLong::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&thole_global,sizeof(double),1,fp);
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutTholeLong::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&thole_global,sizeof(double),1,fp);
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&thole_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutTholeLong::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,epsilon[i][i],sigma[i][i],polar[i][i],thole[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutTholeLong::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],polar[i][j],thole[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutTholeLong::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul,
double factor_lj, double &fforce)
{
double r2inv,r6inv,r,grij,expm2,t,erfc,prefactor,u;
double fraction,table,forcecoul,forcelj,phicoul,philj;
int itable;
double factor_f,factor_e;
double dqi,dqj,dcoul,asr,exp_asr;
int di, dj, di_closest;
int *drudetype = fix_drude->drudetype;
tagint *drudeid = fix_drude->drudeid;
int *type = atom->type;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
if (!ncoultablebits || rsq <= tabinnersq) {
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
u = 1. - t;
erfc = t * (1.+u*(B0+u*(B1+u*(B2+u*(B3+u*(B4+u*B5)))))) * expm2;
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else {
union_int_float_t rsq_lookup_single;
rsq_lookup_single.f = rsq;
itable = rsq_lookup_single.i & ncoulmask;
itable >>= ncoulshiftbits;
fraction = (rsq_lookup_single.f - rtable[itable]) * drtable[itable];
table = ftable[itable] + fraction*dftable[itable];
forcecoul = atom->q[i]*atom->q[j] * table;
if (factor_coul < 1.0) {
table = ctable[itable] + fraction*dctable[itable];
prefactor = atom->q[i]*atom->q[j] * table;
forcecoul -= (1.0-factor_coul)*prefactor;
}
}
if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE) {
di = atom->map(drudeid[i]);
di_closest = domain->closest_image(i, di);
if (j != di_closest){
if (drudetype[i] == CORE_TYPE) dqi = -atom->q[di];
else if (drudetype[i] == DRUDE_TYPE) dqi = atom->q[i];
else dqi = 0.0;
if (drudetype[j] == CORE_TYPE) {
dj = atom->map(drudeid[j]);
dqj = -atom->q[dj];
} else if (drudetype[j] == DRUDE_TYPE) dqj = atom->q[j];
else dqj = 0.0;
asr = ascreen[itype][jtype] * r;
exp_asr = exp(-asr);
dcoul = force->qqrd2e * dqi * dqj / r;
factor_f = 0.5*(2. + (exp_asr * (-2. - asr * (2. + asr))))
- factor_coul;
forcecoul += factor_f * dcoul;
factor_e = 0.5*(2. - (exp_asr * (2. + asr))) - factor_coul;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fforce = (forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
if (!ncoultablebits || rsq <= tabinnersq)
phicoul = prefactor*erfc;
else {
table = etable[itable] + fraction*detable[itable];
phicoul = atom->q[i]*atom->q[j] * table;
}
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
if (drudetype[type[i]] != NOPOL_TYPE && drudetype[type[j]] != NOPOL_TYPE &&
di_closest != j)
phicoul += factor_e * dcoul;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutTholeLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 6;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"scale") == 0) return (void *) scale;
if (strcmp(str,"polar") == 0) return (void *) polar;
if (strcmp(str,"thole") == 0) return (void *) thole;
if (strcmp(str,"ascreen") == 0) return (void *) ascreen;
return NULL;
}
diff --git a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp
index 81b82e977..d8bfd698b 100644
--- a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp
+++ b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp
@@ -1,1028 +1,1028 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_charmm_coul_long_soft.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJCharmmCoulLongSoft::PairLJCharmmCoulLongSoft(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 1;
ewaldflag = pppmflag = 1;
implicit = 0;
mix_flag = ARITHMETIC;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJCharmmCoulLongSoft::~PairLJCharmmCoulLongSoft()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lambda);
memory->destroy(eps14);
memory->destroy(sigma14);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(lj14_1);
memory->destroy(lj14_2);
memory->destroy(lj14_3);
memory->destroy(lj14_4);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double philj,switch1,switch2;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cut_bothsq) {
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
} else forcelj = 0.0;
fpair = forcecoul + factor_lj*forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc;
ecoul = prefactor*erfc;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq) {
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
evdwl *= switch1;
}
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcecoul,forcelj,factor_coul,factor_lj;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
jtype = type[j];
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = forcecoul + factor_lj*forcelj;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcecoul,forcelj,factor_coul,factor_lj;
double philj,switch1,switch2;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
jtype = type[j];
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
fpair = forcecoul + factor_lj*forcelj;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,fprefactor,eprefactor,t,erfc;
double philj,switch1,switch2;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_bothsq) {
jtype = type[j];
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
fprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] /
(denc*denc*denc);
forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2 - 1.0);
if (rsq > cut_in_off_sq) {
if (rsq < cut_in_on_sq) {
rsw = (r - cut_in_off)/cut_in_diff;
forcecoul += fprefactor*rsw*rsw*(3.0 - 2.0*rsw);
if (factor_coul < 1.0)
forcecoul -=
(1.0-factor_coul)*fprefactor*rsw*rsw*(3.0 - 2.0*rsw);
} else {
forcecoul += fprefactor;
if (factor_coul < 1.0)
forcecoul -= (1.0-factor_coul)*fprefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq && rsq > cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
forcelj *= rsw*rsw*(3.0 - 2.0*rsw);
}
} else forcelj = 0.0;
fpair = forcecoul + forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
eprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc;
ecoul = eprefactor*erfc;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*eprefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
evdwl *= switch1;
}
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (vflag) {
if (rsq < cut_coulsq) {
forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor;
} else forcecoul = 0.0;
if (rsq <= cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
} else if (rsq <= cut_in_on_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
}
fpair = forcecoul + factor_lj*forcelj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lambda,n+1,n+1,"pair:lambda");
memory->create(eps14,n+1,n+1,"pair:eps14");
memory->create(sigma14,n+1,n+1,"pair:sigma14");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(lj14_1,n+1,n+1,"pair:lj14_1");
memory->create(lj14_2,n+1,n+1,"pair:lj14_2");
memory->create(lj14_3,n+1,n+1,"pair:lj14_3");
memory->create(lj14_4,n+1,n+1,"pair:lj14_4");
}
/* ----------------------------------------------------------------------
global settings
unlike other pair styles,
there are no individual pair settings that these override
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::settings(int narg, char **arg)
{
if (narg != 5 && narg != 6) error->all(FLERR,"Illegal pair_style command");
nlambda = force->numeric(FLERR,arg[0]);
alphalj = force->numeric(FLERR,arg[1]);
alphac = force->numeric(FLERR,arg[2]);
cut_lj_inner = force->numeric(FLERR,arg[3]);
cut_lj = force->numeric(FLERR,arg[4]);
if (narg == 5) cut_coul = cut_lj;
else cut_coul = force->numeric(FLERR,arg[5]);
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::coeff(int narg, char **arg)
{
if (narg != 5 && narg != 7) error->all(FLERR,"Illegal pair_coeff command");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double lambda_one = force->numeric(FLERR,arg[4]);
double eps14_one = epsilon_one;
double sigma14_one = sigma_one;
if (narg == 7) {
eps14_one = force->numeric(FLERR,arg[5]);
sigma14_one = force->numeric(FLERR,arg[6]);
}
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
lambda[i][j] = lambda_one;
eps14[i][j] = eps14_one;
sigma14[i][j] = sigma14_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::init_style()
{
if (!atom->q_flag)
error->all(FLERR,
"Pair style lj/charmm/coul/long/soft requires atom attribute q");
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
// require cut_lj_inner < cut_lj
if (cut_lj_inner >= cut_lj)
error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff");
cut_lj_innersq = cut_lj_inner * cut_lj_inner;
cut_ljsq = cut_lj * cut_lj;
cut_coulsq = cut_coul * cut_coul;
cut_bothsq = MAX(cut_ljsq,cut_coulsq);
denom_lj = (cut_ljsq-cut_lj_innersq) * (cut_ljsq-cut_lj_innersq) *
(cut_ljsq-cut_lj_innersq);
// set & error check interior rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0) {
cut_respa = ((Respa *) update->integrate)->cutoff;
if (MIN(cut_lj,cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
if (cut_lj_inner < cut_respa[1])
error->all(FLERR,"Pair inner cutoff < Respa interior cutoff");
} else cut_respa = NULL;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCharmmCoulLongSoft::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
if (lambda[i][i] != lambda[j][j])
error->all(FLERR,"Pair lj/charmm/coul/long/soft different lambda values in mix");
lambda[i][j] = lambda[i][i];
eps14[i][j] = mix_energy(eps14[i][i],eps14[j][j],
sigma14[i][i],sigma14[j][j]);
sigma14[i][j] = mix_distance(sigma14[i][i],sigma14[j][j]);
}
double cut = MAX(cut_lj,cut_coul);
lj1[i][j] = pow(lambda[i][j], nlambda);
lj2[i][j] = pow(sigma[i][j], 6.0);
lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
// 1-4 interactions unaffected (they're part of the dihedral term)
lj14_1[i][j] = 48.0 * eps14[i][j] * pow(sigma14[i][j],12.0);
lj14_2[i][j] = 24.0 * eps14[i][j] * pow(sigma14[i][j],6.0);
lj14_3[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],12.0);
lj14_4[i][j] = 4.0 * eps14[i][j] * pow(sigma14[i][j],6.0);
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lambda[j][i] = lambda[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
lj14_1[j][i] = lj14_1[i][j];
lj14_2[j][i] = lj14_2[i][j];
lj14_3[j][i] = lj14_3[i][j];
lj14_4[j][i] = lj14_4[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&lambda[i][j],sizeof(double),1,fp);
fwrite(&eps14[i][j],sizeof(double),1,fp);
fwrite(&sigma14[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&lambda[i][j],sizeof(double),1,fp);
fread(&eps14[i][j],sizeof(double),1,fp);
fread(&sigma14[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&eps14[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma14[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::write_restart_settings(FILE *fp)
{
fwrite(&nlambda,sizeof(double),1,fp);
fwrite(&alphalj,sizeof(double),1,fp);
fwrite(&alphac,sizeof(double),1,fp);
fwrite(&cut_lj_inner,sizeof(double),1,fp);
fwrite(&cut_lj,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&nlambda,sizeof(double),1,fp);
fread(&alphalj,sizeof(double),1,fp);
fread(&alphac,sizeof(double),1,fp);
fread(&cut_lj_inner,sizeof(double),1,fp);
fread(&cut_lj,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_inner,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,epsilon[i][i],sigma[i][i],
lambda[i][i],eps14[i][i],sigma14[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCharmmCoulLongSoft::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],
lambda[i][j],eps14[i][j],sigma14[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCharmmCoulLongSoft::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r,grij,expm2,t,erfc,prefactor;
double switch1,switch2,forcecoul,forcelj,phicoul,philj;
double denc, denlj, r4sig6;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] /
(denc*denc*denc);
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
switch2 = 12.0 * (cut_ljsq-rsq) * (rsq-cut_lj_innersq) / denom_lj;
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj);
forcelj = forcelj*switch1 + philj*switch2;
}
} else forcelj = 0.0;
fforce = forcecoul + factor_lj*forcelj;
double eng = 0.0;
if (rsq < cut_coulsq) {
prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc;
phicoul = prefactor*erfc;
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq) {
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
- (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
+ (1.0/(denlj*denlj) - 1.0/denlj);
if (rsq > cut_lj_innersq) {
switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) *
(cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj;
philj *= switch1;
}
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCharmmCoulLongSoft::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"lj14_1") == 0) return (void *) lj14_1;
if (strcmp(str,"lj14_2") == 0) return (void *) lj14_2;
if (strcmp(str,"lj14_3") == 0) return (void *) lj14_3;
if (strcmp(str,"lj14_4") == 0) return (void *) lj14_4;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lambda") == 0) return (void *) lambda;
dim = 0;
if (strcmp(str,"implicit") == 0) return (void *) &implicit;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
diff --git a/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp
index b2e781c57..9e52a16a0 100644
--- a/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp
+++ b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp
@@ -1,514 +1,516 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_coul_cut_soft.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJCutCoulCutSoft::PairLJCutCoulCutSoft(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJCutCoulCutSoft::~PairLJCutCoulCutSoft()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lambda);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,forcecoul,forcelj,factor_coul,factor_lj;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq < cut_coulsq[itype][jtype]) {
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fpair = factor_coul*forcecoul + factor_lj*forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype])
ecoul = factor_coul * qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc;
else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lambda,n+1,n+1,"pair:lambda");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::settings(int narg, char **arg)
{
if (narg < 4 || narg > 5) error->all(FLERR,"Illegal pair_style command");
nlambda = force->numeric(FLERR,arg[0]);
alphalj = force->numeric(FLERR,arg[1]);
alphac = force->numeric(FLERR,arg[2]);
cut_lj_global = force->numeric(FLERR,arg[3]);
if (narg == 4) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[4]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double lambda_one = force->numeric(FLERR,arg[4]);
+ if (sigma_one <= 0.0)
+ error->all(FLERR,"Incorrect args for pair coefficients");
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 6) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[5]);
if (narg == 7) cut_coul_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
lambda[i][j] = lambda_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/cut/soft requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutCoulCutSoft::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
if (lambda[i][i] != lambda[j][j])
error->all(FLERR,"Pair lj/cut/coul/cut/soft different lambda values in mix");
lambda[i][j] = lambda[i][i];
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
lj1[i][j] = pow(lambda[i][j], nlambda);
lj2[i][j] = pow(sigma[i][j], 6.0);
lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0);
offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj);
} else offset[i][j] = 0.0;
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lambda[j][i] = lambda[i][j];
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&lambda[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&lambda[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::write_restart_settings(FILE *fp)
{
fwrite(&nlambda,sizeof(double),1,fp);
fwrite(&alphalj,sizeof(double),1,fp);
fwrite(&alphac,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&nlambda,sizeof(double),1,fp);
fread(&alphalj,sizeof(double),1,fp);
fread(&alphac,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutCoulCutSoft::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],
lambda[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutCoulCutSoft::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double forcecoul,forcelj,phicoul,philj;
double denc, denlj, r4sig6;
if (rsq < cut_coulsq[itype][jtype]) {
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] /
(denc*denc*denc);
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fforce = factor_coul*forcecoul + factor_lj*forcelj;
double eng = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
phicoul = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc;
eng += factor_coul*phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutCoulCutSoft::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lambda") == 0) return (void *) lambda;
return NULL;
}
diff --git a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp
index 3b80729b0..f7c4084fe 100644
--- a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp
+++ b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp
@@ -1,959 +1,961 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_coul_long_soft.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJCutCoulLongSoft::PairLJCutCoulLongSoft(LAMMPS *lmp) : Pair(lmp)
{
ewaldflag = pppmflag = 1;
respa_enable = 1;
writedata = 1;
qdist = 0.0;
}
/* ---------------------------------------------------------------------- */
PairLJCutCoulLongSoft::~PairLJCutCoulLongSoft()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lambda);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::compute(int eflag, int vflag)
{
int i,ii,j,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fpair = forcecoul + factor_lj*forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
prefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc;
ecoul = prefactor*erfc;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcecoul,forcelj,factor_coul,factor_lj;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
jtype = type[j];
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fpair = forcecoul + factor_lj*forcelj;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcecoul,forcelj,factor_coul,factor_lj;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
jtype = type[j];
denc = sqrt(lj4[itype][jtype] + rsq);
forcecoul = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*forcecoul;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fpair = forcecoul + factor_lj*forcelj;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,forcecoul,forcelj,factor_coul,factor_lj;
double grij,expm2,fprefactor,eprefactor,t,erfc;
double rsw;
double denc, denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
fprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / (denc*denc*denc);
forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2 - 1.0);
if (rsq > cut_in_off_sq) {
if (rsq < cut_in_on_sq) {
rsw = (r - cut_in_off)/cut_in_diff;
forcecoul += fprefactor*rsw*rsw*(3.0 - 2.0*rsw);
if (factor_coul < 1.0)
forcecoul -=
(1.0-factor_coul)*fprefactor*rsw*rsw*(3.0 - 2.0*rsw);
} else {
forcecoul += fprefactor;
if (factor_coul < 1.0)
forcecoul -= (1.0-factor_coul)*fprefactor;
}
}
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype] && rsq > cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
forcelj *= rsw*rsw*(3.0 - 2.0*rsw);
}
} else forcelj = 0.0;
fpair = forcecoul + forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
eprefactor = qqrd2e * lj1[itype][jtype] * qtmp*q[j] / denc;
ecoul = eprefactor*erfc;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*eprefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (vflag) {
if (rsq < cut_coulsq) {
forcecoul = fprefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*fprefactor;
} else forcecoul = 0.0;
if (rsq <= cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else if (rsq < cut_in_on_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
}
fpair = forcecoul + factor_lj*forcelj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lambda,n+1,n+1,"pair:lambda");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::settings(int narg, char **arg)
{
if (narg < 4 || narg > 5) error->all(FLERR,"Illegal pair_style command");
nlambda = force->numeric(FLERR,arg[0]);
alphalj = force->numeric(FLERR,arg[1]);
alphac = force->numeric(FLERR,arg[2]);
cut_lj_global = force->numeric(FLERR,arg[3]);
if (narg == 4) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[4]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double lambda_one = force->numeric(FLERR,arg[4]);
+ if (sigma_one <= 0.0)
+ error->all(FLERR,"Incorrect args for pair coefficients");
double cut_lj_one = cut_lj_global;
if (narg == 6) cut_lj_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
lambda[i][j] = lambda_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/long/soft requires atom attribute q");
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
// insure use of KSpace long-range solver, set g_ewald
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
g_ewald = force->kspace->g_ewald;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutCoulLongSoft::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
if (lambda[i][i] != lambda[j][j])
error->all(FLERR,"Pair lj/cut/coul/long/soft different lambda values in mix");
lambda[i][j] = lambda[i][i];
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
double cut = MAX(cut_lj[i][j],cut_coul+2.0*qdist);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = pow(lambda[i][j], nlambda);
lj2[i][j] = pow(sigma[i][j], 6.0);
lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0);
offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj);
} else offset[i][j] = 0.0;
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lambda[j][i] = lambda[i][j];
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&lambda[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&lambda[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::write_restart_settings(FILE *fp)
{
fwrite(&nlambda,sizeof(double),1,fp);
fwrite(&alphalj,sizeof(double),1,fp);
fwrite(&alphac,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&nlambda,sizeof(double),1,fp);
fread(&alphalj,sizeof(double),1,fp);
fread(&alphac,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphac,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutCoulLongSoft::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],
lambda[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutCoulLongSoft::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r,grij,expm2,t,erfc,prefactor;
double forcecoul,forcelj,phicoul,philj;
double denc, denlj, r4sig6;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
grij = g_ewald * r;
expm2 = exp(-grij*grij);
t = 1.0 / (1.0 + EWALD_P*grij);
erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2;
denc = sqrt(lj4[itype][jtype] + rsq);
prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] /
(denc*denc*denc);
forcecoul = prefactor * (erfc + EWALD_F*grij*expm2);
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fforce = forcecoul + factor_lj*forcelj;
double eng = 0.0;
if (rsq < cut_coulsq) {
prefactor = force->qqrd2e * lj1[itype][jtype] * atom->q[i]*atom->q[j] / denc;
phicoul = prefactor*erfc;
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutCoulLongSoft::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lambda") == 0) return (void *) lambda;
return NULL;
}
diff --git a/src/USER-FEP/pair_lj_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_soft.cpp
index 800fdfcde..8b6280a61 100644
--- a/src/USER-FEP/pair_lj_cut_soft.cpp
+++ b/src/USER-FEP/pair_lj_cut_soft.cpp
@@ -1,781 +1,783 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
Soft-core version: Agilio Padua (Univ Blaise Pascal & CNRS)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_soft.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJCutSoft::PairLJCutSoft(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 1;
writedata = 1;
allocated = 0;
}
/* ---------------------------------------------------------------------- */
PairLJCutSoft::~PairLJCutSoft()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lambda);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(offset);
allocated=0;
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutSoft::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,forcelj,factor_lj;
double denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = factor_lj*forcelj;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJCutSoft::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcelj,factor_lj,rsw;
double denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
jtype = type[j];
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = factor_lj*forcelj;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutSoft::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,forcelj,factor_lj,rsw;
double denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
jtype = type[j];
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = factor_lj*forcelj;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutSoft::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,forcelj,factor_lj,rsw;
double denlj, r4sig6;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq > cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = factor_lj*forcelj;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
if (eflag) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
evdwl = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
evdwl *= factor_lj;
}
if (vflag) {
if (rsq <= cut_in_off_sq) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
fpair = factor_lj*forcelj;
} else if (rsq < cut_in_on_sq)
fpair = factor_lj*forcelj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutSoft::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lambda,n+1,n+1,"pair:lambda");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutSoft::settings(int narg, char **arg)
{
if (narg != 3) error->all(FLERR,"Illegal pair_style command");
nlambda = force->numeric(FLERR,arg[0]);
alphalj = force->numeric(FLERR,arg[1]);
cut_global = force->numeric(FLERR,arg[2]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutSoft::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double lambda_one = force->numeric(FLERR,arg[4]);
+ if (sigma_one <= 0.0)
+ error->all(FLERR,"Incorrect args for pair coefficients");
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
lambda[i][j] = lambda_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutSoft::init_style()
{
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCutSoft::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutSoft::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
lj1[i][j] = pow(lambda[i][j], nlambda);
lj2[i][j] = pow(sigma[i][j], 6.0);
lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double denlj = lj3[i][j] + pow(cut[i][j] / sigma[i][j], 6.0);
offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj);
} else offset[i][j] = 0.0;
epsilon[j][i] = epsilon[i][j];
sigma[j][i] = sigma[i][j];
lambda[j][i] = lambda[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && cut[i][j] < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut[i][j]*cut[i][j]*cut[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]* lj1[i][j] * epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutSoft::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&lambda[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutSoft::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&lambda[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutSoft::write_restart_settings(FILE *fp)
{
fwrite(&nlambda,sizeof(double),1,fp);
fwrite(&alphalj,sizeof(double),1,fp);
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutSoft::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&nlambda,sizeof(double),1,fp);
fread(&alphalj,sizeof(double),1,fp);
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&nlambda,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alphalj,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutSoft::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],lambda[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutSoft::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],
lambda[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutSoft::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double forcelj,philj;
double r4sig6, denlj;
if (rsq < cutsq[itype][jtype]) {
r4sig6 = rsq*rsq / lj2[itype][jtype];
denlj = lj3[itype][jtype] + rsq*r4sig6;
forcelj = lj1[itype][jtype] * epsilon[itype][jtype] *
(48.0*r4sig6/(denlj*denlj*denlj) - 24.0*r4sig6/(denlj*denlj));
} else forcelj = 0.0;
fforce = factor_lj*forcelj;
if (rsq < cutsq[itype][jtype]) {
philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] *
(1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype];
} else philj = 0.0;
return factor_lj*philj;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutSoft::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"lambda") == 0) return (void *) lambda;
return NULL;
}
diff --git a/src/USER-MISC/pair_buck_mdf.cpp b/src/USER-MISC/pair_buck_mdf.cpp
index 6c3dcbd7e..372fbaf8c 100644
--- a/src/USER-MISC/pair_buck_mdf.cpp
+++ b/src/USER-MISC/pair_buck_mdf.cpp
@@ -1,433 +1,433 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paolo Raiteri (Curtin University)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_buck_mdf.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBuckMDF::PairBuckMDF(LAMMPS *lmp) : Pair(lmp) {}
/* ---------------------------------------------------------------------- */
PairBuckMDF::~PairBuckMDF()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(cut_inner);
memory->destroy(cut_inner_sq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(c);
memory->destroy(rhoinv);
memory->destroy(buck1);
memory->destroy(buck2);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBuckMDF::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forcebuck,factor_lj;
double r,rexp,phibuck;
int *ilist,*jlist,*numneigh,**firstneigh;
double dp, d, tt, dt, dd;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
if (rsq > cut_inner_sq[itype][jtype]) {
phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv;
dp = (cut[itype][jtype] - cut_inner[itype][jtype]);
d = (r-cut_inner[itype][jtype]) / dp;
dd = 1.-d;
// taperig function - mdf style
tt = (1. + 3.*d + 6.*d*d)*dd*dd*dd;
// minus the derivative of the tapering function
dt = 30.* d*d * dd*dd * r / dp;
forcebuck = forcebuck*tt + phibuck*dt;
} else {
tt = 1;
}
fpair = factor_lj*forcebuck*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv;
if (rsq > cut_inner_sq[itype][jtype]) evdwl *= tt;
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBuckMDF::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut_lj");
memory->create(cut_inner,n+1,n+1,"pair:cut_inner");
memory->create(cut_inner_sq,n+1,n+1,"pair:cut_inner_sq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(c,n+1,n+1,"pair:c");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(buck1,n+1,n+1,"pair:buck1");
memory->create(buck2,n+1,n+1,"pair:buck2");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBuckMDF::settings(int narg, char **arg)
{
if (narg != 2) error->all(FLERR,"Illegal pair_style command");
cut_inner_global = force->numeric(FLERR,arg[0]);
cut_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBuckMDF::coeff(int narg, char **arg)
{
if (narg != 5 && narg != 7) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[4]);
double cut_inner_one = cut_inner_global;
double cut_one = cut_global;
if (narg == 7) {
cut_inner_one = force->numeric(FLERR,arg[5]);
cut_one = force->numeric(FLERR,arg[6]);
}
if (cut_inner_global <= 0.0 || cut_inner_global > cut_global)
error->all(FLERR,"Illegal pair_style command");
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
c[i][j] = c_one;
cut[i][j] = cut_one;
cut[j][i] = cut_one;
cut_inner[i][j] = cut_inner_one;
cut_inner[j][i] = cut_inner_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBuckMDF::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
rhoinv[i][j] = 1.0/rho[i][j];
buck1[i][j] = a[i][j]/rho[i][j];
buck2[i][j] = 6.0*c[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double rexp = exp(-cut[i][j]/rho[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0);
} else offset[i][j] = 0.0;
cut_inner[j][i] = cut_inner[i][j];
cut_inner_sq[i][j] = cut_inner[i][j]*cut_inner[i][j];
cut_inner_sq[j][i] = cut_inner_sq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
rhoinv[j][i] = rhoinv[i][j];
buck1[j][i] = buck1[i][j];
buck2[j][i] = buck2[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
etail_ij = 2.0*MY_PI*all[0]*all[1]*
(a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]*
(-a[i][j]*exp(-rc/rho1)*
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckMDF::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckMDF::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckMDF::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckMDF::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
double PairBuckMDF::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,forcebuck,phibuck;
double dp, d, tt, dt, dd;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv;
if (rsq > cut_inner_sq[itype][jtype]) {
dp = (cut[itype][jtype] - cut_inner[itype][jtype]);
d = (r - cut_inner[itype][jtype]) / dp;
dd = 1-d;
tt = (1. + 3.*d + 6.*d*d)* dd*dd*dd;
dt = 30.* d*d * dd*dd * r / dp;
forcebuck = forcebuck*tt + phibuck*dt;
phibuck *= tt;
}
fforce = factor_lj*forcebuck*r2inv;
return factor_lj*phibuck;
}
/* ---------------------------------------------------------------------- */
void *PairBuckMDF::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"aparm") == 0) return (void *) a;
if (strcmp(str,"cparm") == 0) return (void *) c;
return NULL;
}
diff --git a/src/USER-MISC/pair_coul_diel.cpp b/src/USER-MISC/pair_coul_diel.cpp
index a62362aa6..c653e9abb 100644
--- a/src/USER-MISC/pair_coul_diel.cpp
+++ b/src/USER-MISC/pair_coul_diel.cpp
@@ -1,348 +1,348 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributiong authors: Arben Jusufi, Axel Kohlmeyer (Temple U.)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_coul_diel.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairCoulDiel::PairCoulDiel(LAMMPS *lmp) : Pair(lmp) {}
/* ---------------------------------------------------------------------- */
PairCoulDiel::~PairCoulDiel()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(sigmae);
memory->destroy(rme);
memory->destroy(offset);
memory->destroy(cutsq);
memory->destroy(cut);
allocated = 0;
}
}
/* ---------------------------------------------------------------------- */
void PairCoulDiel::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair;
double rsq,r,rarg,th,depsdr,epsr,forcecoul,factor_coul;
int *ilist,*jlist,*numneigh,**firstneigh;
ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r = sqrt(rsq);
rarg = (r-rme[itype][jtype])/sigmae[itype][jtype];
th=tanh(rarg);
epsr=a_eps+b_eps*th;
depsdr=b_eps * (1.0 - th*th) / sigmae[itype][jtype];
forcecoul = qqrd2e*qtmp*q[j]*((eps_s*(epsr+r*depsdr)/epsr/epsr) -1.)/rsq;
fpair = factor_coul*forcecoul/r;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
ecoul = (qqrd2e*qtmp*q[j]*((eps_s/epsr) -1.)/r) - offset[itype][jtype];
ecoul *= factor_coul;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,0.0,
ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairCoulDiel::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(sigmae,n+1,n+1,"pair:sigmae");
memory->create(rme,n+1,n+1,"pair:rme");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairCoulDiel::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairCoulDiel::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
eps_s = force->numeric(FLERR,arg[2]);
double rme_one =force->numeric(FLERR,arg[3]);
double sigmae_one = force->numeric(FLERR,arg[4]);
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
sigmae[i][j] = sigmae_one;
rme[i][j] = rme_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
a_eps = 0.5*(5.2+eps_s);
b_eps = 0.5*(eps_s-5.2);
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairCoulDiel::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style coul/diel requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairCoulDiel::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
error->all(FLERR,"for pair style coul/diel, parameters need to be set explicitly for all pairs.");
}
double *q = atom->q;
double qqrd2e = force->qqrd2e;
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double rarg = (cut[i][j]-rme[i][j])/sigmae[i][j];
double epsr=a_eps+b_eps*tanh(rarg);
offset[i][j] = qqrd2e*q[i]*q[j]*((eps_s/epsr) -1.)/cut[i][j];
} else offset[i][j] = 0.0;
sigmae[j][i] = sigmae[i][j];
rme[j][i] = rme[i][j];
offset[j][i] = offset[i][j];
cut[j][i] = cut[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairCoulDiel::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&rme[i][j],sizeof(double),1,fp);
fwrite(&sigmae[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairCoulDiel::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (setflag[i][j]) {
if (me == 0) {
fread(&rme[i][j],sizeof(double),1,fp);
fread(&sigmae[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&rme[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigmae[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairCoulDiel::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairCoulDiel::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
double PairCoulDiel::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r, rarg,forcedielec,phidielec;
double th,epsr,depsdr;
double *q = atom->q;
double qqrd2e = force->qqrd2e;
r=sqrt(rsq);
rarg = (r-rme[itype][jtype])/sigmae[itype][jtype];
th = tanh(rarg);
epsr=a_eps+b_eps*th;
depsdr=b_eps*(1.-th*th)/sigmae[itype][jtype];
forcedielec = qqrd2e*q[i]*q[j]*((eps_s*(epsr+r*depsdr)/epsr/epsr) -1.)/rsq;
fforce = factor_coul*forcedielec/r;
phidielec = (qqrd2e*q[i]*q[j]*((eps_s/epsr) -1.)/r)- offset[itype][jtype];
return factor_coul*phidielec;
}
diff --git a/src/USER-MISC/pair_gauss_cut.cpp b/src/USER-MISC/pair_gauss_cut.cpp
index 3836187a6..4408545c3 100644
--- a/src/USER-MISC/pair_gauss_cut.cpp
+++ b/src/USER-MISC/pair_gauss_cut.cpp
@@ -1,401 +1,404 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Arben Jusufi, Axel Kohlmeyer (Temple U.)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_gauss_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "update.h"
#include "integrate.h"
#include "memory.h"
#include "error.h"
#include "math_const.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairGaussCut::PairGaussCut(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 0;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairGaussCut::~PairGaussCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(hgauss);
memory->destroy(sigmah);
memory->destroy(rmh);
memory->destroy(pgauss);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairGaussCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r,rexp,ugauss,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r = sqrt(rsq);
rexp = (r-rmh[itype][jtype])/sigmah[itype][jtype];
ugauss = pgauss[itype][jtype]*exp(-0.5*rexp*rexp);
fpair = factor_lj*rexp/r*ugauss/sigmah[itype][jtype];
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = ugauss - offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairGaussCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(hgauss,n+1,n+1,"pair:hgauss");
memory->create(sigmah,n+1,n+1,"pair:sigmah");
memory->create(rmh,n+1,n+1,"pair:rmh");
memory->create(pgauss,n+1,n+1,"pair:pgauss");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairGaussCut::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairGaussCut::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double hgauss_one = force->numeric(FLERR,arg[2]);
double rmh_one = force->numeric(FLERR,arg[3]);
double sigmah_one = force->numeric(FLERR,arg[4]);
+ if (sigmah_one <= 0.0)
+ error->all(FLERR,"Incorrect args for pair coefficients");
+
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
hgauss[i][j] = hgauss_one;
sigmah[i][j] = sigmah_one;
rmh[i][j] = rmh_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairGaussCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
hgauss[i][j] = mix_energy(fabs(hgauss[i][i]), fabs(hgauss[j][j]),
fabs(sigmah[i][i]), fabs(sigmah[j][j]));
// If either of the particles is repulsive (ie, if hgauss > 0),
// then the interaction between both is repulsive.
double sign_hi = (hgauss[i][i] >= 0.0) ? 1.0 : -1.0;
double sign_hj = (hgauss[j][j] >= 0.0) ? 1.0 : -1.0;
hgauss[i][j] *= MAX(sign_hi, sign_hj);
sigmah[i][j] = mix_distance(sigmah[i][i], sigmah[j][j]);
rmh[i][j] = mix_distance(rmh[i][i], rmh[j][j]);
cut[i][j] = mix_distance(cut[i][i], cut[j][j]);
}
pgauss[i][j] = hgauss[i][j] / sqrt(MY_2PI) / sigmah[i][j];
if (offset_flag) {
double rexp = (cut[i][j]-rmh[i][j])/sigmah[i][j];
offset[i][j] = pgauss[i][j] * exp(-0.5*rexp*rexp);
} else offset[i][j] = 0.0;
hgauss[j][i] = hgauss[i][j];
sigmah[j][i] = sigmah[i][j];
rmh[j][i] = rmh[i][j];
pgauss[j][i] = pgauss[i][j];
offset[j][i] = offset[i][j];
cut[j][i] = cut[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairGaussCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&hgauss[i][j],sizeof(double),1,fp);
fwrite(&rmh[i][j],sizeof(double),1,fp);
fwrite(&sigmah[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairGaussCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&hgauss[i][j],sizeof(double),1,fp);
fread(&rmh[i][j],sizeof(double),1,fp);
fread(&sigmah[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&hgauss[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rmh[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigmah[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairGaussCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairGaussCut::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairGaussCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,hgauss[i][i],rmh[i][i],sigmah[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairGaussCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,hgauss[i][j],rmh[i][j],sigmah[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairGaussCut::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r, rexp,ugauss,phigauss;
r=sqrt(rsq);
rexp = (r-rmh[itype][jtype])/sigmah[itype][jtype];
ugauss = pgauss[itype][jtype]*exp(-0.5*rexp*rexp);
fforce = factor_lj*rexp/r*ugauss/sigmah[itype][jtype];
phigauss = ugauss - offset[itype][jtype];
return factor_lj*phigauss;
}
/* ---------------------------------------------------------------------- */
double PairGaussCut::memory_usage()
{
const int n=atom->ntypes;
double bytes = Pair::memory_usage();
bytes += 7*((n+1)*(n+1) * sizeof(double) + (n+1)*sizeof(double *));
bytes += 1*((n+1)*(n+1) * sizeof(int) + (n+1)*sizeof(int *));
return bytes;
}
diff --git a/src/USER-MISC/pair_kolmogorov_crespi_z.cpp b/src/USER-MISC/pair_kolmogorov_crespi_z.cpp
index 15a325e10..c03aee636 100644
--- a/src/USER-MISC/pair_kolmogorov_crespi_z.cpp
+++ b/src/USER-MISC/pair_kolmogorov_crespi_z.cpp
@@ -1,441 +1,441 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Jaap Kroes (Radboud Universiteit)
e-mail: jaapkroes at gmail dot com
based on previous versions by Merel van Wijk and by Marco Raguzzoni
This is a simplified version of the potential described in
[Kolmogorov & Crespi, Phys. Rev. B 71, 235415 (2005)]
The simplification is that all normals are taken along the z-direction
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_kolmogorov_crespi_z.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
#define DELTA 4
/* ---------------------------------------------------------------------- */
PairKolmogorovCrespiZ::PairKolmogorovCrespiZ(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
// initialize element to parameter maps
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
map = NULL;
// always compute energy offset
- offset_flag = true;
+ offset_flag = 1;
}
/* ---------------------------------------------------------------------- */
PairKolmogorovCrespiZ::~PairKolmogorovCrespiZ()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(offset);
}
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) delete [] map;
}
/* ---------------------------------------------------------------------- */
void PairKolmogorovCrespiZ::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair, fpair1;
double rsq,r,rhosq,exp1,exp2,r6,r8;
double frho,sumC,sumC2,sumCff,fsum,rdsq;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = type[j];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
// rho^2 = r^2 - (n,r) = r^2 - z^2
rhosq = delx*delx + dely*dely;
rsq = rhosq + delz*delz;
if (rsq < cutsq[itype][jtype]) {
int iparam_ij = elem2param[map[itype]][map[jtype]];
Param& p = params[iparam_ij];
r = sqrt(rsq);
r6 = rsq*rsq*rsq;
r8 = r6*rsq;
rdsq = rhosq*p.delta2inv; // (rho/delta)^2
// store exponents
exp1 = exp(-p.lambda*(r-p.z0));
exp2 = exp(-rdsq);
// note that f(rho_ij) equals f(rho_ji) as normals are all along z
sumC = p.C0+p.C2*rdsq+p.C4*rdsq*rdsq;
sumC2 = (2*p.C2+4*p.C4*rdsq)*p.delta2inv;
frho = exp2*sumC;
sumCff = p.C + 2*frho;
// derivatives
fpair = -6.0*p.A*p.z06/r8+p.lambda*exp1/r*sumCff;
fpair1 = exp1*exp2*(4.0*p.delta2inv*sumC-2.0*sumC2);
fsum = fpair + fpair1;
f[i][0] += delx*fsum;
f[i][1] += dely*fsum;
// fi_z does not contain contributions from df/dr
// because rho_ij does not depend on z_i or z_j
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fsum;
f[j][1] -= dely*fsum;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = -p.A*p.z06/r6+ exp1*sumCff - offset[itype][jtype];
}
if (evflag){
ev_tally_xyz(i,j,nlocal,newton_pair,evdwl,0,
fsum,fsum,fpair,delx,dely,delz);
}
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairKolmogorovCrespiZ::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(offset,n+1,n+1,"pair:offset");
map = new int[atom->ntypes+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairKolmogorovCrespiZ::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
if (strcmp(force->pair_style,"hybrid/overlay")!=0)
error->all(FLERR,"ERROR: requires hybrid/overlay pair_style");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairKolmogorovCrespiZ::coeff(int narg, char **arg)
{
int i,j,n;
if (narg != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
// read args that map atom types to elements in potential file
// map[i] = which element the Ith atom type is, -1 if NULL
// nelements = # of unique elements
// elements = list of element names
if (elements) {
for (i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
}
elements = new char*[atom->ntypes];
for (i = 0; i < atom->ntypes; i++) elements[i] = NULL;
nelements = 0;
for (i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
}
for (j = 0; j < nelements; j++)
if (strcmp(arg[i],elements[j]) == 0) break;
map[i-2] = j;
if (j == nelements) {
n = strlen(arg[i]) + 1;
elements[j] = new char[n];
strcpy(elements[j],arg[i]);
nelements++;
}
}
read_file(arg[2]);
double cut_one = cut_global;
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairKolmogorovCrespiZ::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
int iparam_ij = elem2param[map[i]][map[j]];
Param& p = params[iparam_ij];
offset[i][j] = -p.A*pow(p.z0/cut[i][j],6);
} else offset[i][j] = 0.0;
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
read Kolmogorov-Crespi potential file
------------------------------------------------------------------------- */
void PairKolmogorovCrespiZ::read_file(char *filename)
{
int params_per_line = 11;
char **words = new char*[params_per_line+1];
memory->sfree(params);
params = NULL;
nparams = maxparam = 0;
// open file on proc 0
FILE *fp;
if (comm->me == 0) {
fp = force->open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open KC potential file %s",filename);
error->one(FLERR,str);
}
}
// read each line out of file, skipping blank lines or leading '#'
// store line of params if all 3 element tags are in element list
int i,j,n,m,nwords,ielement,jelement;
char line[MAXLINE],*ptr;
int eof = 0;
while (1) {
if (comm->me == 0) {
ptr = fgets(line,MAXLINE,fp);
if (ptr == NULL) {
eof = 1;
fclose(fp);
} else n = strlen(line) + 1;
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) break;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
// strip comment, skip line if blank
if ((ptr = strchr(line,'#'))) *ptr = '\0';
nwords = atom->count_words(line);
if (nwords == 0) continue;
// concatenate additional lines until have params_per_line words
while (nwords < params_per_line) {
n = strlen(line);
if (comm->me == 0) {
ptr = fgets(&line[n],MAXLINE-n,fp);
if (ptr == NULL) {
eof = 1;
fclose(fp);
} else n = strlen(line) + 1;
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) break;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
if ((ptr = strchr(line,'#'))) *ptr = '\0';
nwords = atom->count_words(line);
}
if (nwords != params_per_line)
error->all(FLERR,"Insufficient format in KC potential file");
// words = ptrs to all words in line
nwords = 0;
words[nwords++] = strtok(line," \t\n\r\f");
while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
// ielement,jelement = 1st args
// if these 2 args are in element list, then parse this line
// else skip to next line (continue)
for (ielement = 0; ielement < nelements; ielement++)
if (strcmp(words[0],elements[ielement]) == 0) break;
if (ielement == nelements) continue;
for (jelement = 0; jelement < nelements; jelement++)
if (strcmp(words[1],elements[jelement]) == 0) break;
if (jelement == nelements) continue;
// load up parameter settings and error check their values
if (nparams == maxparam) {
maxparam += DELTA;
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
"pair:params");
}
params[nparams].ielement = ielement;
params[nparams].jelement = jelement;
params[nparams].z0 = atof(words[2]);
params[nparams].C0 = atof(words[3]);
params[nparams].C2 = atof(words[4]);
params[nparams].C4 = atof(words[5]);
params[nparams].C = atof(words[6]);
params[nparams].delta = atof(words[7]);
params[nparams].lambda = atof(words[8]);
params[nparams].A = atof(words[9]);
// S provides a convenient scaling of all energies
params[nparams].S = atof(words[10]);
// energies in meV further scaled by S
double meV = 1.0e-3*params[nparams].S;
params[nparams].C *= meV;
params[nparams].A *= meV;
params[nparams].C0 *= meV;
params[nparams].C2 *= meV;
params[nparams].C4 *= meV;
// precompute some quantities
params[nparams].delta2inv = pow(params[nparams].delta,-2);
params[nparams].z06 = pow(params[nparams].z0,6);
nparams++;
if(nparams >= pow(atom->ntypes,3)) break;
}
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++) {
for (j = 0; j < nelements; j++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement) {
if (n >= 0) error->all(FLERR,"Potential file has duplicate entry");
n = m;
}
}
if (n < 0) error->all(FLERR,"Potential file is missing an entry");
elem2param[i][j] = n;
}
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
diff --git a/src/USER-MISC/pair_list.cpp b/src/USER-MISC/pair_list.cpp
index 3adbe8b69..458c228d5 100644
--- a/src/USER-MISC/pair_list.cpp
+++ b/src/USER-MISC/pair_list.cpp
@@ -1,422 +1,422 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "pair_list.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "memory.h"
#include "error.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
using namespace LAMMPS_NS;
static const char * const stylename[] = {
"none", "harmonic", "morse", "lj126", NULL
};
// fast power function for integer exponent > 0
static double mypow(double x, int n) {
double yy;
if (x == 0.0) return 0.0;
for (yy = 1.0; n != 0; n >>= 1, x *=x)
if (n & 1) yy *= x;
return yy;
}
typedef struct { double x,y,z; } dbl3_t;
/* ---------------------------------------------------------------------- */
PairList::PairList(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
respa_enable = 0;
cut_global = 0.0;
style = NULL;
params = NULL;
check_flag = 1;
}
/* ---------------------------------------------------------------------- */
PairList::~PairList()
{
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(style);
memory->destroy(params);
}
/* ----------------------------------------------------------------------
in this pair style we don't use a neighbor list, but loop through
a list of pairwise interactions, determines the corresponding local
atom indices and compute those forces.
------------------------------------------------------------------------- */
void PairList::compute(int eflag, int vflag)
{
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = eflag_global =
- vflag_global = eflag_atom = vflag_atom = 0;
+ vflag_global = eflag_atom = vflag_atom = 0;
const int nlocal = atom->nlocal;
const int newton_pair = force->newton_pair;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
dbl3_t * _noalias const f = (dbl3_t *) atom->f[0];
double fpair,epair;
int i,j;
int pc = 0;
for (int n=0; n < npairs; ++n) {
const list_parm_t &par = params[n];
i = atom->map(par.id1);
j = atom->map(par.id2);
// if one of the two atoms is missing on the node skip
if ((i < 0) || (j < 0)) continue;
// both atoms are ghosts -> skip
if ((i >= nlocal) && (j >= nlocal)) continue;
// with newton pair and one ghost we have to skip half the cases.
// if id1 is a ghost, we skip if the sum of both ids is even.
// if id2 is a ghost, we skip if the sum of both ids is odd.
if (newton_pair) {
if ((i >= nlocal) && ((par.id1+par.id2) & 1) == 0) continue;
if ((j >= nlocal) && ((par.id1+par.id2) & 1) == 1) continue;
}
const double dx = x[i].x - x[j].x;
const double dy = x[i].y - x[j].y;
const double dz = x[i].z - x[j].z;
const double rsq = dx*dx + dy*dy + dz*dz;
fpair = epair = 0.0;
if (check_flag) {
if (newton_pair || i < nlocal) ++pc;
if (newton_pair || j < nlocal) ++pc;
}
if (rsq < par.cutsq) {
const double r2inv = 1.0/rsq;
if (style[n] == HARM) {
- const double r = sqrt(rsq);
- const double dr = par.parm.harm.r0 - r;
- fpair = 2.0*par.parm.harm.k*dr/r;
+ const double r = sqrt(rsq);
+ const double dr = par.parm.harm.r0 - r;
+ fpair = 2.0*par.parm.harm.k*dr/r;
- if (eflag_either)
- epair = par.parm.harm.k*dr*dr - par.offset;
+ if (eflag_either)
+ epair = par.parm.harm.k*dr*dr - par.offset;
} else if (style[n] == MORSE) {
- const double r = sqrt(rsq);
- const double dr = par.parm.morse.r0 - r;
- const double dexp = exp(par.parm.morse.alpha * dr);
- fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha
- * (dexp*dexp - dexp) / r;
+ const double r = sqrt(rsq);
+ const double dr = par.parm.morse.r0 - r;
+ const double dexp = exp(par.parm.morse.alpha * dr);
+ fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha
+ * (dexp*dexp - dexp) / r;
- if (eflag_either)
- epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset;
+ if (eflag_either)
+ epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset;
} else if (style[n] == LJ126) {
- const double r6inv = r2inv*r2inv*r2inv;
- const double sig6 = mypow(par.parm.lj126.sigma,6);
- fpair = 24.0*par.parm.lj126.epsilon*r6inv
- * (2.0*sig6*sig6*r6inv - sig6) * r2inv;
+ const double r6inv = r2inv*r2inv*r2inv;
+ const double sig6 = mypow(par.parm.lj126.sigma,6);
+ fpair = 24.0*par.parm.lj126.epsilon*r6inv
+ * (2.0*sig6*sig6*r6inv - sig6) * r2inv;
- if (eflag_either)
- epair = 4.0*par.parm.lj126.epsilon*r6inv
- * (sig6*sig6*r6inv - sig6) - par.offset;
+ if (eflag_either)
+ epair = 4.0*par.parm.lj126.epsilon*r6inv
+ * (sig6*sig6*r6inv - sig6) - par.offset;
}
if (newton_pair || i < nlocal) {
- f[i].x += dx*fpair;
- f[i].y += dy*fpair;
- f[i].z += dz*fpair;
+ f[i].x += dx*fpair;
+ f[i].y += dy*fpair;
+ f[i].z += dz*fpair;
}
if (newton_pair || j < nlocal) {
- f[j].x -= dx*fpair;
- f[j].y -= dy*fpair;
- f[j].z -= dz*fpair;
+ f[j].x -= dx*fpair;
+ f[j].y -= dy*fpair;
+ f[j].z -= dz*fpair;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,epair,0.0,fpair,dx,dy,dz);
}
}
if (vflag_fdotr) virial_fdotr_compute();
if (check_flag) {
- int tmp;
- MPI_Allreduce(&pc,&tmp,1,MPI_INT,MPI_SUM,world);
- if (tmp != 2*npairs)
- error->all(FLERR,"Not all pairs processed in pair_style list");
+ int tmp;
+ MPI_Allreduce(&pc,&tmp,1,MPI_INT,MPI_SUM,world);
+ if (tmp != 2*npairs)
+ error->all(FLERR,"Not all pairs processed in pair_style list");
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairList::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
}
/* ----------------------------------------------------------------------
create one pair style for each arg in list
------------------------------------------------------------------------- */
void PairList::settings(int narg, char **arg)
{
if (narg < 2)
error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[1]);
if (narg > 2) {
if (strcmp(arg[2],"nocheck") == 0) check_flag = 0;
if (strcmp(arg[2],"check") == 0) check_flag = 1;
}
FILE *fp = force->open_potential(arg[0]);
char line[1024];
if (fp == NULL)
error->all(FLERR,"Cannot open pair list file");
// count lines in file for upper limit of storage needed
int num = 1;
while(fgets(line,1024,fp)) ++num;
rewind(fp);
memory->create(style,num,"pair_list:style");
memory->create(params,num,"pair_list:params");
// now read and parse pair list file for real
npairs = 0;
char *ptr;
tagint id1, id2;
int nharm=0, nmorse=0, nlj126=0;
while(fgets(line,1024,fp)) {
ptr = strtok(line," \t\n\r\f");
// skip empty lines
if (!ptr) continue;
// skip comment lines starting with #
if (*ptr == '#') continue;
// get atom ids of pair
id1 = ATOTAGINT(ptr);
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
error->all(FLERR,"Incorrectly formatted pair list file");
id2 = ATOTAGINT(ptr);
// get potential type
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
error->all(FLERR,"Incorrectly formatted pair list file");
style[npairs] = NONE;
list_parm_t &par = params[npairs];
par.id1 = id1;
par.id2 = id2;
// harmonic potential
if (strcmp(ptr,stylename[HARM]) == 0) {
style[npairs] = HARM;
ptr = strtok(NULL," \t\n\r\f");
if ((ptr == NULL) || (*ptr == '#'))
- error->all(FLERR,"Incorrectly formatted harmonic pair parameters");
+ error->all(FLERR,"Incorrectly formatted harmonic pair parameters");
par.parm.harm.k = force->numeric(FLERR,ptr);
ptr = strtok(NULL," \t\n\r\f");
if ((ptr == NULL) || (*ptr == '#'))
- error->all(FLERR,"Incorrectly formatted harmonic pair parameters");
+ error->all(FLERR,"Incorrectly formatted harmonic pair parameters");
par.parm.harm.r0 = force->numeric(FLERR,ptr);
++nharm;
// morse potential
} else if (strcmp(ptr,stylename[MORSE]) == 0) {
style[npairs] = MORSE;
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
- error->all(FLERR,"Incorrectly formatted morse pair parameters");
+ error->all(FLERR,"Incorrectly formatted morse pair parameters");
par.parm.morse.d0 = force->numeric(FLERR,ptr);
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
- error->all(FLERR,"Incorrectly formatted morse pair parameters");
+ error->all(FLERR,"Incorrectly formatted morse pair parameters");
par.parm.morse.alpha = force->numeric(FLERR,ptr);
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
- error->all(FLERR,"Incorrectly formatted morse pair parameters");
+ error->all(FLERR,"Incorrectly formatted morse pair parameters");
par.parm.morse.r0 = force->numeric(FLERR,ptr);
++nmorse;
} else if (strcmp(ptr,stylename[LJ126]) == 0) {
// 12-6 lj potential
style[npairs] = LJ126;
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
- error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters");
+ error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters");
par.parm.lj126.epsilon = force->numeric(FLERR,ptr);
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
- error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters");
+ error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters");
par.parm.lj126.sigma = force->numeric(FLERR,ptr);
++nlj126;
} else {
error->all(FLERR,"Unknown pair list potential style");
}
// optional cutoff parameter. if not specified use global value
ptr = strtok(NULL," \t\n\r\f");
if ((ptr != NULL) && (*ptr != '#')) {
double cut = force->numeric(FLERR,ptr);
par.cutsq = cut*cut;
} else {
par.cutsq = cut_global*cut_global;
}
// count complete entry
++npairs;
}
fclose(fp);
// informative output
if (comm->me == 0) {
if (screen)
fprintf(screen,"Read %d (%d/%d/%d) interacting pairs from %s\n",
- npairs, nharm, nmorse, nlj126, arg[0]);
+ npairs, nharm, nmorse, nlj126, arg[0]);
if (logfile)
fprintf(logfile,"Read %d (%d/%d/%d) interacting pairs from %s\n",
- npairs, nharm, nmorse, nlj126, arg[0]);
+ npairs, nharm, nmorse, nlj126, arg[0]);
}
}
/* ----------------------------------------------------------------------
there are no coeffs to be set, but we need to update setflag and pretend
------------------------------------------------------------------------- */
void PairList::coeff(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style: compute energy offset at cutoff
------------------------------------------------------------------------- */
void PairList::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style list requires atom IDs");
if (atom->map_style == 0)
error->all(FLERR,"Pair style list requires an atom map");
if (offset_flag) {
for (int n=0; n < npairs; ++n) {
list_parm_t &par = params[n];
if (style[n] == HARM) {
- const double dr = sqrt(par.cutsq) - par.parm.harm.r0;
- par.offset = par.parm.harm.k*dr*dr;
+ const double dr = sqrt(par.cutsq) - par.parm.harm.r0;
+ par.offset = par.parm.harm.k*dr*dr;
} else if (style[n] == MORSE) {
- const double dr = par.parm.morse.r0 - sqrt(par.cutsq);
- const double dexp = exp(par.parm.morse.alpha * dr);
- par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp);
+ const double dr = par.parm.morse.r0 - sqrt(par.cutsq);
+ const double dexp = exp(par.parm.morse.alpha * dr);
+ par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp);
} else if (style[n] == LJ126) {
- const double r6inv = par.cutsq*par.cutsq*par.cutsq;
- const double sig6 = mypow(par.parm.lj126.sigma,6);
- par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6);
+ const double r6inv = par.cutsq*par.cutsq*par.cutsq;
+ const double sig6 = mypow(par.parm.lj126.sigma,6);
+ par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6);
}
}
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
since we don't use atom types or neighbor lists, this is a NOP.
------------------------------------------------------------------------- */
double PairList::init_one(int, int)
{
return cut_global;
}
/* ----------------------------------------------------------------------
memory usage of each sub-style
------------------------------------------------------------------------- */
double PairList::memory_usage()
{
double bytes = npairs * sizeof(int);
bytes += npairs * sizeof(list_parm_t);
const int n = atom->ntypes+1;
bytes += n*(n*sizeof(int) + sizeof(int *));
bytes += n*(n*sizeof(double) + sizeof(double *));
return bytes;
}
diff --git a/src/USER-MISC/pair_morse_smooth_linear.cpp b/src/USER-MISC/pair_morse_smooth_linear.cpp
index 3e776e7e1..0035338cd 100644
--- a/src/USER-MISC/pair_morse_smooth_linear.cpp
+++ b/src/USER-MISC/pair_morse_smooth_linear.cpp
@@ -1,371 +1,368 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_morse_smooth_linear.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairMorseSmoothLinear::PairMorseSmoothLinear(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairMorseSmoothLinear::~PairMorseSmoothLinear()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(d0);
memory->destroy(alpha);
memory->destroy(r0);
memory->destroy(morse1);
memory->destroy(der_at_cutoff);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairMorseSmoothLinear::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair, fpartial;
double rsq,r,dr,dexp,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r = sqrt(rsq);
dr = r - r0[itype][jtype];
dexp = exp(-alpha[itype][jtype] * dr);
fpartial = morse1[itype][jtype] * (dexp*dexp - dexp) / r;
fpair = factor_lj * ( fpartial + der_at_cutoff[itype][jtype] / r);
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) -
offset[itype][jtype];
evdwl -= ( r - cut[itype][jtype] ) * der_at_cutoff[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(d0,n+1,n+1,"pair:d0");
memory->create(alpha,n+1,n+1,"pair:alpha");
memory->create(r0,n+1,n+1,"pair:r0");
memory->create(morse1,n+1,n+1,"pair:morse1");
memory->create(der_at_cutoff,n+1,n+1,"pair:der_at_cutoff");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double d0_one = force->numeric(FLERR,arg[2]);
double alpha_one = force->numeric(FLERR,arg[3]);
double r0_one = force->numeric(FLERR,arg[4]);
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
d0[i][j] = d0_one;
alpha[i][j] = alpha_one;
r0[i][j] = r0_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairMorseSmoothLinear::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
morse1[i][j] = 2.0*d0[i][j]*alpha[i][j];
double alpha_dr = -alpha[i][j] * (cut[i][j] - r0[i][j]);
offset[i][j] = d0[i][j] * (exp(2.0*alpha_dr) - 2.0*exp(alpha_dr));
der_at_cutoff[i][j] = -2.0*alpha[i][j]*d0[i][j] * (exp(2.0*alpha_dr) - exp(alpha_dr));
d0[j][i] = d0[i][j];
alpha[j][i] = alpha[i][j];
r0[j][i] = r0[i][j];
morse1[j][i] = morse1[i][j];
der_at_cutoff[j][i] = der_at_cutoff[i][j];
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&d0[i][j],sizeof(double),1,fp);
fwrite(&alpha[i][j],sizeof(double),1,fp);
fwrite(&r0[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&d0[i][j],sizeof(double),1,fp);
fread(&alpha[i][j],sizeof(double),1,fp);
fread(&r0[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&d0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
- // fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
- // fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
- // MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,d0[i][i],alpha[i][i],r0[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairMorseSmoothLinear::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",
i,j,d0[i][j],alpha[i][j],r0[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairMorseSmoothLinear::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r,dr,dexp,phi;
r = sqrt(rsq);
dr = r - r0[itype][jtype];
dexp = exp(-alpha[itype][jtype] * dr);
fforce = factor_lj * (morse1[itype][jtype] * (dexp*dexp - dexp)
+ der_at_cutoff[itype][jtype]) / r;
phi = d0[itype][jtype] * (dexp*dexp - 2.0*dexp) - offset[itype][jtype];
dr = cut[itype][jtype] - r;
phi += dr * der_at_cutoff[itype][jtype];
return factor_lj*phi;
}
/* ---------------------------------------------------------------------- */
void *PairMorseSmoothLinear::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"d0") == 0) return (void *) d0;
if (strcmp(str,"r0") == 0) return (void *) r0;
if (strcmp(str,"alpha") == 0) return (void *) alpha;
return NULL;
}
diff --git a/src/USER-OMP/pair_peri_lps_omp.cpp b/src/USER-OMP/pair_peri_lps_omp.cpp
index 4876e6b15..a471b4775 100644
--- a/src/USER-OMP/pair_peri_lps_omp.cpp
+++ b/src/USER-OMP/pair_peri_lps_omp.cpp
@@ -1,455 +1,459 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
This software is distributed under the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include <math.h>
#include <float.h>
#include "pair_peri_lps_omp.h"
#include "fix.h"
#include "fix_peri_neigh.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "memory.h"
#include "lattice.h"
#include "modify.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairPeriLPSOMP::PairPeriLPSOMP(LAMMPS *lmp) :
PairPeriLPS(lmp), ThrOMP(lmp, THR_PAIR)
{
suffix_flag |= Suffix::OMP;
respa_enable = 0;
}
/* ---------------------------------------------------------------------- */
void PairPeriLPSOMP::compute(int eflag, int vflag)
{
if (eflag || vflag) {
ev_setup(eflag,vflag);
} else evflag = vflag_fdotr = eflag_global = eflag_atom = 0;
const int nall = atom->nlocal + atom->nghost;
const int nthreads = comm->nthreads;
const int inum = list->inum;
// grow bond forces array if necessary
if (atom->nmax > nmax) {
memory->destroy(s0_new);
memory->destroy(theta);
nmax = atom->nmax;
memory->create(s0_new,nmax,"pair:s0_new");
memory->create(theta,nmax,"pair:theta");
}
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
int ifrom, ito, tid;
loop_setup_thr(ifrom, ito, tid, inum, nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
ev_setup_thr(eflag, vflag, nall, eatom, vatom, thr);
if (evflag) {
if (eflag) {
if (force->newton_pair) eval<1,1,1>(ifrom, ito, thr);
else eval<1,1,0>(ifrom, ito, thr);
} else {
if (force->newton_pair) eval<1,0,1>(ifrom, ito, thr);
else eval<1,0,0>(ifrom, ito, thr);
}
} else {
if (force->newton_pair) eval<0,0,1>(ifrom, ito, thr);
else eval<0,0,0>(ifrom, ito, thr);
}
thr->timer(Timer::PAIR);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
template <int EVFLAG, int EFLAG, int NEWTON_PAIR>
void PairPeriLPSOMP::eval(int iifrom, int iito, ThrData * const thr)
{
int i,j,ii,jj,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0,rsq0;
double rsq,r,dr,rk,evdwl,fpair,fbond;
int *ilist,*jlist,*numneigh,**firstneigh;
double d_ij,delta,stretch;
evdwl = 0.0;
const double * const * const x = atom->x;
double * const * const f = thr->get_f();
const int * const type = atom->type;
const int nlocal = atom->nlocal;
double fxtmp,fytmp,fztmp;
double *vfrac = atom->vfrac;
double *s0 = atom->s0;
double **x0 = atom->x0;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
// lc = lattice constant
// init_style guarantees it's the same in x, y, and z
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double vfrac_scale = 1.0;
// short-range forces
int periodic = (domain->xperiodic || domain->yperiodic || domain->zperiodic);
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
// need minimg() for x0 difference since not ghosted
for (ii = iifrom; ii < iito; ++ii) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
fxtmp=fytmp=fztmp=0.0;
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0;
jtype = type[j];
r = sqrt(rsq);
// short-range interaction distance based on initial particle position
// 0.9 and 1.35 are constants
d_ij = MIN(0.9*sqrt(rsq0),1.35*lc);
// short-range contact forces
// 15 is constant taken from the EMU Theory Manual
// Silling, 12 May 2005, p 18
if (r < d_ij) {
dr = r - d_ij;
// kshort based upon short-range force constant
// of the bond-based theory used in PMB model
double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) /
(MY_PI * cutsq[itype][jtype] * cutsq[itype][jtype]);
rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]);
if (r > 0.0) fpair = -(rk/r);
else fpair = 0.0;
fxtmp += delx*fpair;
fytmp += dely*fpair;
fztmp += delz*fpair;
if (NEWTON_PAIR || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (EFLAG) evdwl = 0.5*rk*dr;
if (EVFLAG) ev_tally_thr(this,i,j,nlocal,NEWTON_PAIR,evdwl,0.0,
fpair*vfrac[i],delx,dely,delz,thr);
}
}
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
}
// wait until all threads are done since we
// need to distribute the work differently.
sync_threads();
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int idelta = 1 + nlocal/comm->nthreads;
iifrom = thr->get_tid()*idelta;
iito = ((iifrom + idelta) > nlocal) ? nlocal : (iifrom + idelta);
#else
iifrom = 0;
iito = nlocal;
#endif
// Compute the dilatation on each particle
if (iifrom < nlocal)
compute_dilatation_thr(iifrom, iito);
// wait until all threads are done before communication
sync_threads();
#if defined(_OPENMP)
#pragma omp master
#endif
{ // communicate dilatation (theta) of each particle
comm->forward_comm_pair(this);
// communicate weighted volume (wvolume) upon every reneighbor
if (neighbor->ago == 0)
comm->forward_comm_fix(modify->fix[ifix_peri]);
}
sync_threads();
// Volume-dependent part of the energy
if (EFLAG) {
for (i = iifrom; i < iito; i++) {
itype = type[i];
e_tally_thr(this, i, i, nlocal, NEWTON_PAIR,
0.5 * bulkmodulus[itype][itype] * (theta[i] * theta[i]), 0.0, thr);
}
}
// loop over my particles and their partners
// partner list contains all bond partners, so I-J appears twice
// if bond already broken, skip this partner
// first = true if this is first neighbor of particle i
bool first;
double omega_minus, omega_plus;
for (i = iifrom; i < iito; ++i) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
itype = type[i];
jnum = npartner[i];
first = true;
for (jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
j = atom->map(partner[i][jj]);
// check if lost a partner without first breaking bond
if (j < 0) {
partner[i][jj] = 0;
continue;
}
// compute force density, add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
jtype = type[j];
delta = cut[itype][jtype];
r = sqrt(rsq);
dr = r - r0[i][jj];
// avoid roundoff errors
if (fabs(dr) < 2.2204e-016) dr = 0.0;
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0);
omega_minus = influence_function(delx0,dely0,delz0);
- rk = ( (3.0 * bulkmodulus[itype][itype]) -
- (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale *
- ( (omega_plus * theta[i] / wvolume[i]) +
- ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj];
- rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
- ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr;
+ if ((wvolume[i] > 0.0) && (wvolume[j] > 0.0)) {
+ rk = ( (3.0 * bulkmodulus[itype][itype]) -
+ (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale *
+ ( (omega_plus * theta[i] / wvolume[i]) +
+ ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj];
+ rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
+ ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr;
+ } else rk = 0.0;
if (r > 0.0) fbond = -(rk/r);
else fbond = 0.0;
f[i][0] += delx*fbond;
f[i][1] += dely*fbond;
f[i][2] += delz*fbond;
// since I-J is double counted, set newton off & use 1/2 factor and I,I
double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0);
- if (EFLAG) evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) *
+ if (EFLAG && (wvolume[i] > 0.0))
+ evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) *
omega_plus*(deviatoric_extension * deviatoric_extension) *
vfrac[j] * vfrac_scale;
+ else evdwl = 0.0;
if (EVFLAG) ev_tally_thr(this,i,i,nlocal,0,0.5*evdwl,0.0,
0.5*fbond*vfrac[i],delx,dely,delz,thr);
// find stretch in bond I-J and break if necessary
// use s0 from previous timestep
stretch = dr / r0[i][jj];
if (stretch > MIN(s0[i],s0[j])) partner[i][jj] = 0;
// update s0 for next timestep
if (first)
s0_new[i] = s00[itype][jtype] - (alpha[itype][jtype] * stretch);
else
s0_new[i] = MAX(s0_new[i],s00[itype][jtype] - (alpha[itype][jtype] * stretch));
first = false;
}
}
sync_threads();
// store new s0 (in parallel)
if (iifrom < nlocal)
for (i = iifrom; i < iito; i++) s0[i] = s0_new[i];
}
/* ---------------------------------------------------------------------- */
void PairPeriLPSOMP::compute_dilatation_thr(int ifrom, int ito)
{
int i,j,jj,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz;
double xtmp0,ytmp0,ztmp0,delx0,dely0,delz0;
double rsq,r,dr;
double delta;
double **x = atom->x;
int *type = atom->type;
double **x0 = atom->x0;
double *vfrac = atom->vfrac;
double vfrac_scale = 1.0;
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double *wvolume = ((FixPeriNeigh *) modify->fix[ifix_peri])->wvolume;
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
// compute the dilatation theta
for (i = ifrom; i < ito; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
xtmp0 = x0[i][0];
ytmp0 = x0[i][1];
ztmp0 = x0[i][2];
jnum = npartner[i];
theta[i] = 0.0;
itype = type[i];
for (jj = 0; jj < jnum; jj++) {
// if bond already broken, skip this partner
if (partner[i][jj] == 0) continue;
// Look up local index of this partner particle
j = atom->map(partner[i][jj]);
// Skip if particle is "lost"
if (j < 0) continue;
// Compute force density and add to PD equation of motion
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
if (periodic) domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
delx0 = xtmp0 - x0[j][0];
dely0 = ytmp0 - x0[j][1];
delz0 = ztmp0 - x0[j][2];
if (periodic) domain->minimum_image(delx0,dely0,delz0);
r = sqrt(rsq);
dr = r - r0[i][jj];
if (fabs(dr) < 2.2204e-016) dr = 0.0;
jtype = type[j];
delta = cut[itype][jtype];
// scale vfrac[j] if particle j near the horizon
if ((fabs(r0[i][jj] - delta)) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((delta - half_lc)/(2*half_lc) ) );
else vfrac_scale = 1.0;
theta[i] += influence_function(delx0, dely0, delz0) * r0[i][jj] * dr *
vfrac[j] * vfrac_scale;
}
// if wvolume[i] is zero, then particle i has no bonds
// therefore, the dilatation is set to
if (wvolume[i] != 0.0) theta[i] = (3.0/wvolume[i]) * theta[i];
else theta[i] = 0;
}
}
/* ---------------------------------------------------------------------- */
double PairPeriLPSOMP::memory_usage()
{
double bytes = memory_usage_thr();
bytes += PairPeriLPS::memory_usage();
return bytes;
}
diff --git a/src/USER-OMP/pair_reaxc_omp.cpp b/src/USER-OMP/pair_reaxc_omp.cpp
index 0c16284e2..7ac8952b1 100644
--- a/src/USER-OMP/pair_reaxc_omp.cpp
+++ b/src/USER-OMP/pair_reaxc_omp.cpp
@@ -1,630 +1,631 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Per-atom energy/virial added by Ray Shan (Materials Design, Inc.)
Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added
by Ray Shan (Materials Design)
OpenMP based threading support for pair_style reax/c/omp added
by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF),
Kurt O'Hearn (MSU), Ray Shan (Materials Design), Wei Jiang (ALCF)
Integration of the pair_style reax/c/omp into the User-OMP package
by Axel Kohlmeyer (Temple U.)
Please cite the related publication:
H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan,
W. Jiang, "Optimizing the performance of reactive molecular dynamics
simulations for multi-core architectures", International Journal of
High Performance Computing Applications, to appear.
------------------------------------------------------------------------- */
#include "pair_reaxc_omp.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "modify.h"
#include "fix.h"
#include "fix_reaxc.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
#include "timer.h"
#include "reaxc_types.h"
#include "reaxc_allocate.h"
#include "reaxc_control.h"
#include "reaxc_ffield.h"
#include "reaxc_forces_omp.h"
#include "reaxc_init_md_omp.h"
#include "reaxc_io_tools.h"
#include "reaxc_list.h"
#include "reaxc_lookup.h"
#include "reaxc_reset_tools.h"
#include "reaxc_tool_box.h"
#include "reaxc_traj.h"
#include "reaxc_vector.h"
#include "fix_reaxc_bonds.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
#ifdef OMP_TIMING
double ompTimingData[LASTTIMINGINDEX];
int ompTimingCount[LASTTIMINGINDEX];
int ompTimingCGCount[LASTTIMINGINDEX];
#endif
static const char cite_pair_reax_c_omp[] =
"pair reax/c/omp and fix qeq/reax/omp command:\n\n"
"@Article{Aktulga17,\n"
" author = {H. M. Aktulga, C. Knight, P. Coffman, K. A. OHearn, T. R. Shan, W. Jiang},\n"
" title = {Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures},\n"
" journal = {International Journal of High Performance Computing Applications},\n"
" year = to appear\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
PairReaxCOMP::PairReaxCOMP(LAMMPS *lmp) : PairReaxC(lmp), ThrOMP(lmp, THR_PAIR)
{
if (lmp->citeme) lmp->citeme->add(cite_pair_reax_c_omp);
suffix_flag |= Suffix::OMP;
system->pair_ptr = this;
+ system->omp_active = 1;
num_nbrs_offset = NULL;
#ifdef OMP_TIMING
for (int i=0;i<LASTTIMINGINDEX;i++) {
ompTimingData[i] = 0;
ompTimingCount[i] = 0;
ompTimingCGCount[i] = 0;
}
#endif
}
/* ---------------------------------------------------------------------- */
PairReaxCOMP::~PairReaxCOMP()
{
if (setup_flag) {
reax_list * bonds = lists+BONDS;
for (int i=0; i<bonds->num_intrs; ++i)
sfree(bonds->select.bond_list[i].bo_data.CdboReduction, "CdboReduction");
}
memory->destroy(num_nbrs_offset);
#ifdef OMP_TIMING
int myrank;
MPI_Comm_rank(mpi_data->world,&myrank);
// Write screen output
if (timer->has_full() && myrank == 0 && screen) {
fprintf(screen,"\n\nWrite_Lists took %11.3lf seconds", ompTimingData[COMPUTEWLINDEX]);
fprintf(screen,"\n\nCompute_Forces took %11.3lf seconds:", ompTimingData[COMPUTEINDEX]);
fprintf(screen,"\n ->Initial Forces: %11.3lf seconds", ompTimingData[COMPUTEIFINDEX]);
fprintf(screen,"\n ->Bond Order: %11.3lf seconds", ompTimingData[COMPUTEBOINDEX]);
fprintf(screen,"\n ->Atom Energy: %11.3lf seconds", ompTimingData[COMPUTEATOMENERGYINDEX]);
fprintf(screen,"\n ->Bond: %11.3lf seconds", ompTimingData[COMPUTEBONDSINDEX]);
fprintf(screen,"\n ->Hydrogen bonds: %11.3lf seconds", ompTimingData[COMPUTEHBONDSINDEX]);
fprintf(screen,"\n ->Torsion Angles: %11.3lf seconds", ompTimingData[COMPUTETORSIONANGLESBOINDEX]);
fprintf(screen,"\n ->Valence Angles: %11.3lf seconds", ompTimingData[COMPUTEVALENCEANGLESBOINDEX]);
fprintf(screen,"\n ->Non-Bonded For: %11.3lf seconds", ompTimingData[COMPUTENBFINDEX]);
fprintf(screen,"\n ->Total Forces: %11.3lf seconds", ompTimingData[COMPUTETFINDEX]);
fprintf(screen,"\n\nfixQEQ: %11.3lf seconds", ompTimingData[COMPUTEQEQINDEX]);
fprintf(screen,"\n ->QEQ init: %11.3lf seconds", ompTimingData[COMPUTEINITMVINDEX]);
double avg = double(ompTimingCGCount[COMPUTECG1INDEX]) / double(ompTimingCount[COMPUTECG1INDEX]);
fprintf(screen,"\n ->QEQ CG1: %11.3lf seconds with %4.1lf iterations on average.", ompTimingData[COMPUTECG1INDEX], avg);
avg = double(ompTimingCGCount[COMPUTECG2INDEX]) / double(ompTimingCount[COMPUTECG2INDEX]);
fprintf(screen,"\n ->QEQ CG2: %11.3lf seconds with %4.1lf iterations on average.", ompTimingData[COMPUTECG2INDEX], avg);
fprintf(screen,"\n ->QEQ CalcQ: %11.3lf seconds\n", ompTimingData[COMPUTECALCQINDEX]);
}
// Write logfile output
if (timer->has_full() && myrank == 0 && logfile) {
fprintf(logfile,"\n\nWrite_Lists took %11.3lf seconds", ompTimingData[COMPUTEWLINDEX]);
fprintf(logfile,"\n\nCompute_Forces took %11.3lf seconds:", ompTimingData[COMPUTEINDEX]);
fprintf(logfile,"\n ->Initial Forces: %11.3lf seconds", ompTimingData[COMPUTEIFINDEX]);
fprintf(logfile,"\n ->Bond Order: %11.3lf seconds", ompTimingData[COMPUTEBOINDEX]);
fprintf(logfile,"\n ->Atom Energy: %11.3lf seconds", ompTimingData[COMPUTEATOMENERGYINDEX]);
fprintf(logfile,"\n ->Bond: %11.3lf seconds", ompTimingData[COMPUTEBONDSINDEX]);
fprintf(logfile,"\n ->Hydrogen bonds: %11.3lf seconds", ompTimingData[COMPUTEHBONDSINDEX]);
fprintf(logfile,"\n ->Torsion Angles: %11.3lf seconds", ompTimingData[COMPUTETORSIONANGLESBOINDEX]);
fprintf(logfile,"\n ->Valence Angles: %11.3lf seconds", ompTimingData[COMPUTEVALENCEANGLESBOINDEX]);
fprintf(logfile,"\n ->Non-Bonded For: %11.3lf seconds", ompTimingData[COMPUTENBFINDEX]);
fprintf(logfile,"\n ->Total Forces: %11.3lf seconds", ompTimingData[COMPUTETFINDEX]);
fprintf(logfile,"\n\nfixQEQ: %11.3lf seconds", ompTimingData[COMPUTEQEQINDEX]);
fprintf(logfile,"\n ->QEQ init: %11.3lf seconds", ompTimingData[COMPUTEINITMVINDEX]);
double avg = double(ompTimingCGCount[COMPUTECG1INDEX]) / double(ompTimingCount[COMPUTECG1INDEX]);
fprintf(logfile,"\n ->QEQ CG1: %11.3lf seconds with %4.1lf iterations on average.", ompTimingData[COMPUTECG1INDEX], avg);
avg = double(ompTimingCGCount[COMPUTECG2INDEX]) / double(ompTimingCount[COMPUTECG2INDEX]);
fprintf(logfile,"\n ->QEQ CG2: %11.3lf seconds with %4.1lf iterations on average.", ompTimingData[COMPUTECG2INDEX], avg);
fprintf(logfile,"\n ->QEQ CalcQ: %11.3lf seconds\n", ompTimingData[COMPUTECALCQINDEX]);
}
#endif
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::compute(int eflag, int vflag)
{
double evdwl,ecoul;
double t_start, t_end;
// communicate num_bonds once every reneighboring
// 2 num arrays stored by fix, grab ptr to them
if (neighbor->ago == 0) comm->forward_comm_fix(fix_reax);
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else ev_unset();
if (vflag_global) control->virial = 1;
else control->virial = 0;
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
system->big_box.V = 0;
system->big_box.box_norms[0] = 0;
system->big_box.box_norms[1] = 0;
system->big_box.box_norms[2] = 0;
if( comm->me == 0 ) t_start = MPI_Wtime();
// setup data structures
setup();
Reset( system, control, data, workspace, &lists, world );
// Why not update workspace like in MPI-only code?
// Using the MPI-only way messes up the hb energy
//workspace->realloc.num_far = write_reax_lists();
write_reax_lists();
// timing for filling in the reax lists
if( comm->me == 0 ) {
t_end = MPI_Wtime();
data->timing.nbrs = t_end - t_start;
}
// forces
#ifdef OMP_TIMING
double startTimeBase,endTimeBase;
startTimeBase = MPI_Wtime();
#endif
Compute_ForcesOMP(system,control,data,workspace,&lists,out_control,mpi_data);
read_reax_forces(vflag);
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEINDEX] += (endTimeBase-startTimeBase);
#endif
#if defined(_OPENMP)
#pragma omp parallel for schedule(static)
#endif
for(int k = 0; k < system->N; ++k) {
num_bonds[k] = system->my_atoms[k].num_bonds;
num_hbonds[k] = system->my_atoms[k].num_hbonds;
}
// energies and pressure
if (eflag_global) {
evdwl += data->my_en.e_bond;
evdwl += data->my_en.e_ov;
evdwl += data->my_en.e_un;
evdwl += data->my_en.e_lp;
evdwl += data->my_en.e_ang;
evdwl += data->my_en.e_pen;
evdwl += data->my_en.e_coa;
evdwl += data->my_en.e_hb;
evdwl += data->my_en.e_tor;
evdwl += data->my_en.e_con;
evdwl += data->my_en.e_vdW;
ecoul += data->my_en.e_ele;
ecoul += data->my_en.e_pol;
// Store the different parts of the energy
// in a list for output by compute pair command
pvector[0] = data->my_en.e_bond;
pvector[1] = data->my_en.e_ov + data->my_en.e_un;
pvector[2] = data->my_en.e_lp;
pvector[3] = 0.0;
pvector[4] = data->my_en.e_ang;
pvector[5] = data->my_en.e_pen;
pvector[6] = data->my_en.e_coa;
pvector[7] = data->my_en.e_hb;
pvector[8] = data->my_en.e_tor;
pvector[9] = data->my_en.e_con;
pvector[10] = data->my_en.e_vdW;
pvector[11] = data->my_en.e_ele;
pvector[12] = 0.0;
pvector[13] = data->my_en.e_pol;
}
if (vflag_fdotr) virial_fdotr_compute();
// Set internal timestep counter to that of LAMMPS
data->step = update->ntimestep;
Output_Results( system, control, data, &lists, out_control, mpi_data );
// populate tmpid and tmpbo arrays for fix reax/c/species
int i, j;
if(fixspecies_flag) {
if (system->N > nmax) {
memory->destroy(tmpid);
memory->destroy(tmpbo);
nmax = system->N;
memory->create(tmpid,nmax,MAXSPECBOND,"pair:tmpid");
memory->create(tmpbo,nmax,MAXSPECBOND,"pair:tmpbo");
}
#if defined(_OPENMP)
#pragma omp parallel for collapse(2) schedule(static) default(shared)
#endif
for (i = 0; i < system->N; i ++)
for (j = 0; j < MAXSPECBOND; j ++) {
tmpbo[i][j] = 0.0;
tmpid[i][j] = 0;
}
FindBond();
}
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::init_style( )
{
if (!atom->q_flag)
error->all(FLERR,"Pair reax/c/omp requires atom attribute q");
// firstwarn = 1;
int iqeq = modify->find_fix_by_style("qeq/reax/omp");
if (iqeq < 0 && qeqflag == 1)
error->all(FLERR,"Pair reax/c/omp requires use of fix qeq/reax/omp");
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
system->wsize = comm->nprocs;
system->big_box.V = 0;
system->big_box.box_norms[0] = 0;
system->big_box.box_norms[1] = 0;
system->big_box.box_norms[2] = 0;
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style reax/c/omp requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style reax/c/omp requires newton pair on");
// need a half neighbor list w/ Newton off and ghost neighbors
// built whenever re-neighboring occurs
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->newton = 2;
neighbor->requests[irequest]->ghost = 1;
cutmax = MAX3(control->nonb_cut, control->hbond_cut, 2*control->bond_cut);
for( int i = 0; i < LIST_N; ++i )
lists[i].allocated = 0;
if (fix_reax == NULL) {
char **fixarg = new char*[3];
fixarg[0] = (char *) "REAXC";
fixarg[1] = (char *) "all";
fixarg[2] = (char *) "REAXC";
modify->add_fix(3,fixarg);
delete [] fixarg;
fix_reax = (FixReaxC *) modify->fix[modify->nfix-1];
}
#if defined(_OPENMP)
control->nthreads = omp_get_max_threads();
#else
control->nthreads = 1;
#endif
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::setup( )
{
int oldN;
int mincap = system->mincap;
double safezone = system->safezone;
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
oldN = system->N;
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
if (system->N > nmax) {
memory->destroy(num_nbrs_offset);
// Don't update nmax here. It is updated at end of compute().
memory->create(num_nbrs_offset, system->N, "pair:num_nbrs_offset");
}
if (setup_flag == 0) {
setup_flag = 1;
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
control->vlist_cut = neighbor->cutneighmax;
// determine the local and total capacity
system->local_cap = MAX( (int)(system->n * safezone), mincap );
system->total_cap = MAX( (int)(system->N * safezone), mincap );
// initialize my data structures
PreAllocate_Space( system, control, workspace, world );
write_reax_atoms();
int num_nbrs = estimate_reax_lists();
if(!Make_List(system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR,
lists+FAR_NBRS, world))
error->all(FLERR,"Pair reax/c problem in far neighbor list");
write_reax_lists();
InitializeOMP( system, control, data, workspace, &lists, out_control,
mpi_data, world );
for( int k = 0; k < system->N; ++k ) {
num_bonds[k] = system->my_atoms[k].num_bonds;
num_hbonds[k] = system->my_atoms[k].num_hbonds;
}
} else {
// fill in reax datastructures
write_reax_atoms();
// reset the bond list info for new atoms
for(int k = oldN; k < system->N; ++k)
Set_End_Index( k, Start_Index( k, lists+BONDS ), lists+BONDS );
// estimate far neighbor list size
// Not present in MPI-only version
workspace->realloc.num_far = estimate_reax_lists();
// check if I need to shrink/extend my data-structs
ReAllocate( system, control, data, workspace, &lists, mpi_data );
}
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::write_reax_atoms()
{
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
if (system->N > system->total_cap)
error->all(FLERR,"Too many ghost atoms");
#if defined(_OPENMP)
#pragma omp parallel for schedule(static) default(shared)
#endif
for( int i = 0; i < system->N; ++i ){
system->my_atoms[i].orig_id = atom->tag[i];
system->my_atoms[i].type = map[atom->type[i]];
system->my_atoms[i].x[0] = atom->x[i][0];
system->my_atoms[i].x[1] = atom->x[i][1];
system->my_atoms[i].x[2] = atom->x[i][2];
system->my_atoms[i].q = atom->q[i];
system->my_atoms[i].num_bonds = num_bonds[i];
system->my_atoms[i].num_hbonds = num_hbonds[i];
}
}
/* ---------------------------------------------------------------------- */
int PairReaxCOMP::estimate_reax_lists()
{
int i;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int numall = list->inum + list->gnum;
int mincap = system->mincap;
// for good performance in the OpenMP implementation, each thread needs
// to know where to place the neighbors of the atoms it is responsible for.
// The sumscan values for the list->numneigh will be used to determine the
// neighbor offset of each atom. Note that this may cause some significant
// memory overhead if delayed neighboring is used - so it may be desirable
// to work on this part to reduce the memory footprint of the far_nbrs list.
int num_nbrs = 0;
for (int itr_i = 0; itr_i < numall; ++itr_i) {
i = ilist[itr_i];
num_nbrs += numneigh[i];
}
int new_estimate = MAX (num_nbrs, mincap*MIN_NBRS);
return new_estimate;
}
/* ---------------------------------------------------------------------- */
int PairReaxCOMP::write_reax_lists()
{
#ifdef OMP_TIMING
double startTimeBase, endTimeBase;
startTimeBase = MPI_Wtime();
#endif
int itr_i, itr_j, i, j, num_mynbrs;
int *jlist;
double d_sqr, dist, cutoff_sqr;
rvec dvec;
double **x = atom->x;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
reax_list *far_nbrs = lists + FAR_NBRS;
far_neighbor_data *far_list = far_nbrs->select.far_nbr_list;
int num_nbrs = 0;
int inum = list->inum;
int gnum = list->gnum;
int numall = inum + gnum;
// sumscan of the number of neighbors per atom to determine the offsets
// most likely, we are overallocating. desirable to work on this part
// to reduce the memory footprint of the far_nbrs list.
num_nbrs = 0;
for (itr_i = 0; itr_i < numall; ++itr_i) {
i = ilist[itr_i];
num_nbrs_offset[i] = num_nbrs;
num_nbrs += numneigh[i];
}
#if defined(_OPENMP)
#pragma omp parallel for schedule(dynamic,50) default(shared) \
private(itr_i, itr_j, i, j, jlist, cutoff_sqr, num_mynbrs, d_sqr, dvec, dist)
#endif
for (itr_i = 0; itr_i < numall; ++itr_i) {
i = ilist[itr_i];
jlist = firstneigh[i];
Set_Start_Index( i, num_nbrs_offset[i], far_nbrs );
if (i < inum)
cutoff_sqr = control->nonb_cut*control->nonb_cut;
else
cutoff_sqr = control->bond_cut*control->bond_cut;
num_mynbrs = 0;
for (itr_j = 0; itr_j < numneigh[i]; ++itr_j) {
j = jlist[itr_j];
j &= NEIGHMASK;
get_distance( x[j], x[i], &d_sqr, &dvec );
if (d_sqr <= cutoff_sqr) {
dist = sqrt( d_sqr );
set_far_nbr( &far_list[num_nbrs_offset[i] + num_mynbrs], j, dist, dvec );
++num_mynbrs;
}
}
Set_End_Index( i, num_nbrs_offset[i] + num_mynbrs, far_nbrs );
}
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEWLINDEX] += (endTimeBase-startTimeBase);
#endif
return num_nbrs;
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::read_reax_forces(int vflag)
{
#if defined(_OPENMP)
#pragma omp parallel for schedule(static) default(shared)
#endif
for( int i = 0; i < system->N; ++i ) {
system->my_atoms[i].f[0] = workspace->f[i][0];
system->my_atoms[i].f[1] = workspace->f[i][1];
system->my_atoms[i].f[2] = workspace->f[i][2];
atom->f[i][0] = -workspace->f[i][0];
atom->f[i][1] = -workspace->f[i][1];
atom->f[i][2] = -workspace->f[i][2];
}
}
/* ---------------------------------------------------------------------- */
void PairReaxCOMP::FindBond()
{
const double bo_cut = 0.10;
int i;
#if defined(_OPENMP)
#pragma omp parallel for schedule(static) default(shared) \
private(i)
#endif
for (i = 0; i < system->n; i++) {
int j, pj, nj;
double bo_tmp;
bond_data *bo_ij;
nj = 0;
for( pj = Start_Index(i, lists); pj < End_Index(i, lists); ++pj ) {
bo_ij = &( lists->select.bond_list[pj] );
j = bo_ij->nbr;
if (j < i) continue;
bo_tmp = bo_ij->bo_data.BO;
if (bo_tmp >= bo_cut ) {
tmpid[i][nj] = j;
tmpbo[i][nj] = bo_tmp;
nj ++;
if (nj > MAXSPECBOND) error->all(FLERR,"Increase MAXSPECBOND in fix_reaxc_species.h");
}
}
}
}
diff --git a/src/USER-OMP/pppm_cg_omp.cpp b/src/USER-OMP/pppm_cg_omp.cpp
index 021765d14..df0e632f7 100644
--- a/src/USER-OMP/pppm_cg_omp.cpp
+++ b/src/USER-OMP/pppm_cg_omp.cpp
@@ -1,735 +1,733 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "pppm_cg_omp.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_omp.h"
#include "force.h"
#include "neighbor.h"
#include "memory.h"
#include "math_const.h"
#include "math_special.h"
#include <string.h>
#include <math.h>
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace MathSpecial;
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#define ONEF 1.0f
#else
#define ZEROF 0.0
#define ONEF 1.0
#endif
#define EPS_HOC 1.0e-7
/* ---------------------------------------------------------------------- */
PPPMCGOMP::PPPMCGOMP(LAMMPS *lmp, int narg, char **arg) :
PPPMCG(lmp, narg, arg), ThrOMP(lmp, THR_KSPACE)
{
triclinic_support = 0;
suffix_flag |= Suffix::OMP;
}
/* ----------------------------------------------------------------------
- allocate memory that depends on # of K-vectors and order
+ clean up per-thread allocations
------------------------------------------------------------------------- */
-void PPPMCGOMP::allocate()
+PPPMCGOMP::~PPPMCGOMP()
{
- PPPMCG::allocate();
-
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(order,memory);
+ thr->init_pppm(-order,memory);
}
}
/* ----------------------------------------------------------------------
- free memory that depends on # of K-vectors and order
+ allocate memory that depends on # of K-vectors and order
------------------------------------------------------------------------- */
-void PPPMCGOMP::deallocate()
+void PPPMCGOMP::allocate()
{
- PPPMCG::deallocate();
+ PPPMCG::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(-order,memory);
+ thr->init_pppm(order,memory);
}
}
/* ----------------------------------------------------------------------
pre-compute modified (Hockney-Eastwood) Coulomb Green's function
------------------------------------------------------------------------- */
void PPPMCGOMP::compute_gf_ik()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int nbx = static_cast<int> ((g_ewald*xprd/(MY_PI*nx_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nby = static_cast<int> ((g_ewald*yprd/(MY_PI*ny_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nbz = static_cast<int> ((g_ewald*zprd_slab/(MY_PI*nz_pppm)) *
pow(-log(EPS_HOC),0.25));
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double snx,sny,snz;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double sum1,dot1,dot2;
double numerator,denominator;
double sqk;
int k,l,m,nx,ny,nz,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
snz = square(sin(0.5*unitkz*mper*zprd_slab/nz_pppm));
lper = l - ny_pppm*(2*l/ny_pppm);
sny = square(sin(0.5*unitky*lper*yprd/ny_pppm));
kper = k - nx_pppm*(2*k/nx_pppm);
snx = square(sin(0.5*unitkx*kper*xprd/nx_pppm));
sqk = square(unitkx*kper) + square(unitky*lper) + square(unitkz*mper);
if (sqk != 0.0) {
numerator = 12.5663706/sqk;
denominator = gf_denom(snx,sny,snz);
sum1 = 0.0;
for (nx = -nbx; nx <= nbx; nx++) {
qx = unitkx*(kper+nx_pppm*nx);
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
for (ny = -nby; ny <= nby; ny++) {
qy = unitky*(lper+ny_pppm*ny);
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
for (nz = -nbz; nz <= nbz; nz++) {
qz = unitkz*(mper+nz_pppm*nz);
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
dot1 = unitkx*kper*qx + unitky*lper*qy + unitkz*mper*qz;
dot2 = qx*qx+qy*qy+qz*qz;
sum1 += (dot1/dot2) * sx*sy*sz * wx*wy*wz;
}
}
}
greensfn[n] = numerator*sum1/denominator;
} else greensfn[n] = 0.0;
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
compute optimized Green's function for energy calculation
------------------------------------------------------------------------- */
void PPPMCGOMP::compute_gf_ad()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0;
#if defined(_OPENMP)
#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5)
#endif
{
double snx,sny,snz,sqk;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double numerator,denominator;
int k,l,m,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
qz = unitkz*mper;
snz = square(sin(0.5*qz*zprd_slab/nz_pppm));
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
lper = l - ny_pppm*(2*l/ny_pppm);
qy = unitky*lper;
sny = square(sin(0.5*qy*yprd/ny_pppm));
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
kper = k - nx_pppm*(2*k/nx_pppm);
qx = unitkx*kper;
snx = square(sin(0.5*qx*xprd/nx_pppm));
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
sqk = qx*qx + qy*qy + qz*qz;
if (sqk != 0.0) {
numerator = MY_4PI/sqk;
denominator = gf_denom(snx,sny,snz);
greensfn[n] = numerator*sx*sy*sz*wx*wy*wz/denominator;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
} else {
greensfn[n] = 0.0;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
}
}
thr->timer(Timer::KSPACE);
} // end of paralle region
// compute the coefficients for the self-force correction
double prex, prey, prez, tmp[6];
prex = prey = prez = MY_PI/volume;
prex *= nx_pppm/xprd;
prey *= ny_pppm/yprd;
prez *= nz_pppm/zprd_slab;
tmp[0] = sf0 * prex;
tmp[1] = sf1 * prex*2;
tmp[2] = sf2 * prey;
tmp[3] = sf3 * prey*2;
tmp[4] = sf4 * prez;
tmp[5] = sf5 * prez*2;
// communicate values with other procs
MPI_Allreduce(tmp,sf_coeff,6,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
run the regular toplevel compute method from plain PPPMCG
which will have individual methods replaced by our threaded
versions and then call the obligatory force reduction.
------------------------------------------------------------------------- */
void PPPMCGOMP::compute(int eflag, int vflag)
{
PPPMCG::compute(eflag,vflag);
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
/* ----------------------------------------------------------------------
create discretized "density" on section of global grid due to my particles
density(x,y,z) = charge "density" at grid points of my 3d brick
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
in global grid
------------------------------------------------------------------------- */
void PPPMCGOMP::make_rho()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick[nzlo_out][nylo_out][nxlo_out]);
memset(d,0,ngrid*sizeof(FFT_SCALAR));
// no local atoms with a charge => nothing else to do
if (num_charged == 0) return;
const int ix = nxhi_out - nxlo_out + 1;
const int iy = nyhi_out - nylo_out + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const double * _noalias const q = atom->q;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (int j = 0; j < num_charged; j++) {
i = is_charged[j];
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower-nzlo_out)*ix*iy >= jto)
|| ((nz+nupper-nzlo_out+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone - (x[i].x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (x[i].y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (x[i].z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
const FFT_SCALAR z0 = delvolinv * q[i];
for (int n = nlower; n <= nupper; ++n) {
const int jn = (nz+n-nzlo_out)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower; m <= nupper; ++m) {
const int jm = jn+(ny+m-nylo_out)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower; l <= nupper; ++l) {
const int jl = jm+nx+l-nxlo_out;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
thr->timer(Timer::KSPACE);
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ik
------------------------------------------------------------------------- */
void PPPMCGOMP::fieldforce_ik()
{
// no local atoms with a charge => nothing to do
if (num_charged == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const double qqrd2e = force->qqrd2e;
const int nthreads = comm->nthreads;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
FFT_SCALAR dx,dy,dz,x0,y0,z0,ekx,eky,ekz;
int i,ifrom,ito,tid,l,m,n,nx,ny,nz,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,num_charged,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (int j = ifrom; j < ito; ++j) {
i = is_charged[j];
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i].x-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i].y-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i].z-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick[mz][my][mx];
eky -= x0*vdy_brick[mz][my][mx];
ekz -= x0*vdz_brick[mz][my][mx];
}
}
}
// convert E-field to force
const double qfactor = qqrd2e * scale * q[i];
f[i].x += qfactor*ekx;
f[i].y += qfactor*eky;
if (slabflag != 2) f[i].z += qfactor*ekz;
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ad
------------------------------------------------------------------------- */
void PPPMCGOMP::fieldforce_ad()
{
// no local atoms with a charge => nothing to do
if (num_charged == 0) return;
const double *prd = (triclinic == 0) ? domain->prd : domain->prd_lamda;
const double hx_inv = nx_pppm/prd[0];
const double hy_inv = ny_pppm/prd[1];
const double hz_inv = nz_pppm/prd[2];
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const double qqrd2e = force->qqrd2e;
const int nthreads = comm->nthreads;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
int i,ifrom,ito,tid,l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,ekx,eky,ekz;
double s1,s2,s3,sf;
loop_setup_thr(ifrom,ito,tid,num_charged,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
FFT_SCALAR * const * const d1d = static_cast<FFT_SCALAR **>(thr->get_drho1d());
for (int j = ifrom; j < ito; ++j) {
i = is_charged[j];
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i].x-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i].y-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i].z-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
compute_drho1d_thr(d1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
for (m = nlower; m <= nupper; m++) {
my = m+ny;
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
ekx += d1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
eky += r1d[0][l]*d1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*d1d[2][n]*u_brick[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force and substract self forces
const double qi = q[i];
const double qfactor = qqrd2e * scale * qi;
s1 = x[i].x*hx_inv;
sf = sf_coeff[0]*sin(MY_2PI*s1);
sf += sf_coeff[1]*sin(MY_4PI*s1);
sf *= 2.0*qi;
f[i].x += qfactor*(ekx - sf);
s2 = x[i].y*hy_inv;
sf = sf_coeff[2]*sin(MY_2PI*s2);
sf += sf_coeff[3]*sin(MY_4PI*s2);
sf *= 2*qi;
f[i].y += qfactor*(eky - sf);
s3 = x[i].z*hz_inv;
sf = sf_coeff[4]*sin(MY_2PI*s3);
sf += sf_coeff[5]*sin(MY_4PI*s3);
sf *= 2*qi;
if (slabflag != 2) f[i].z += qfactor*(ekz - sf);
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial
------------------------------------------------------------------------- */
void PPPMCGOMP::fieldforce_peratom()
{
// no local atoms with a charge => nothing to do
if (num_charged == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int nthreads = comm->nthreads;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u,v0,v1,v2,v3,v4,v5;
int i,ifrom,ito,tid,l,m,n,nx,ny,nz,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,num_charged,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (int j=ifrom; j < ito; ++j) {
i = is_charged[j];
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i].x-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i].y-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i].z-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) u += x0*u_brick[mz][my][mx];
if (vflag_atom) {
v0 += x0*v0_brick[mz][my][mx];
v1 += x0*v1_brick[mz][my][mx];
v2 += x0*v2_brick[mz][my][mx];
v3 += x0*v3_brick[mz][my][mx];
v4 += x0*v4_brick[mz][my][mx];
v5 += x0*v5_brick[mz][my][mx];
}
}
}
}
const double qi = q[i];
if (eflag_atom) eatom[i] += qi*u;
if (vflag_atom) {
vatom[i][0] += qi*v0;
vatom[i][1] += qi*v1;
vatom[i][2] += qi*v2;
vatom[i][3] += qi*v3;
vatom[i][4] += qi*v4;
vatom[i][5] += qi*v5;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
charge assignment into rho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMCGOMP::compute_rho1d_thr(FFT_SCALAR * const * const r1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-1; l >= 0; l--) {
r1 = rho_coeff[l][k] + r1*dx;
r2 = rho_coeff[l][k] + r2*dy;
r3 = rho_coeff[l][k] + r3*dz;
}
r1d[0][k] = r1;
r1d[1][k] = r2;
r1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
charge assignment into drho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMCGOMP::compute_drho1d_thr(FFT_SCALAR * const * const d1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-2; l >= 0; l--) {
r1 = drho_coeff[l][k] + r1*dx;
r2 = drho_coeff[l][k] + r2*dy;
r3 = drho_coeff[l][k] + r3*dz;
}
d1d[0][k] = r1;
d1d[1][k] = r2;
d1d[2][k] = r3;
}
}
diff --git a/src/USER-OMP/pppm_cg_omp.h b/src/USER-OMP/pppm_cg_omp.h
index 91f09ebbf..07763eba3 100644
--- a/src/USER-OMP/pppm_cg_omp.h
+++ b/src/USER-OMP/pppm_cg_omp.h
@@ -1,56 +1,55 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef KSPACE_CLASS
KSpaceStyle(pppm/cg/omp,PPPMCGOMP)
#else
#ifndef LMP_PPPM_CG_OMP_H
#define LMP_PPPM_CG_OMP_H
#include "pppm_cg.h"
#include "thr_omp.h"
namespace LAMMPS_NS {
class PPPMCGOMP : public PPPMCG, public ThrOMP {
public:
PPPMCGOMP(class LAMMPS *, int, char **);
- virtual ~PPPMCGOMP () {};
+ virtual ~PPPMCGOMP ();
virtual void compute(int, int);
protected:
virtual void allocate();
- virtual void deallocate();
virtual void compute_gf_ik();
virtual void compute_gf_ad();
virtual void make_rho();
virtual void fieldforce_ik();
virtual void fieldforce_ad();
virtual void fieldforce_peratom();
private:
void compute_rho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
void compute_drho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
};
}
#endif
#endif
diff --git a/src/USER-OMP/pppm_disp_omp.cpp b/src/USER-OMP/pppm_disp_omp.cpp
index 16d3001dd..6cf298376 100644
--- a/src/USER-OMP/pppm_disp_omp.cpp
+++ b/src/USER-OMP/pppm_disp_omp.cpp
@@ -1,1873 +1,1862 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Axel Kohlmeyer (Temple U)
Rolf Isele-Holder (RWTH Aachen University)
------------------------------------------------------------------------- */
#include "pppm_disp_omp.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "memory.h"
#include "math_const.h"
#include <string.h>
#include <math.h>
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#define ONEF 1.0f
#else
#define ZEROF 0.0
#define ONEF 1.0
#endif
#define OFFSET 16384
/* ---------------------------------------------------------------------- */
PPPMDispOMP::PPPMDispOMP(LAMMPS *lmp, int narg, char **arg) :
PPPMDisp(lmp, narg, arg), ThrOMP(lmp, THR_KSPACE)
{
triclinic_support = 0;
suffix_flag |= Suffix::OMP;
}
/* ---------------------------------------------------------------------- */
PPPMDispOMP::~PPPMDispOMP()
{
- deallocate();
-}
-
-/* ----------------------------------------------------------------------
- allocate memory that depends on # of K-vectors and order
-------------------------------------------------------------------------- */
-
-void PPPMDispOMP::allocate()
-{
- PPPMDisp::allocate();
-
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
-
if (function[0]) {
- ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(order,memory);
+ ThrData * thr = fix->get_thr(tid);
+ thr->init_pppm(-order,memory);
}
if (function[1] + function[2]) {
ThrData * thr = fix->get_thr(tid);
- thr->init_pppm_disp(order_6,memory);
+ thr->init_pppm_disp(-order_6,memory);
}
}
}
/* ----------------------------------------------------------------------
- free memory that depends on # of K-vectors and order
+ allocate memory that depends on # of K-vectors and order
------------------------------------------------------------------------- */
-void PPPMDispOMP::deallocate()
+void PPPMDispOMP::allocate()
{
- PPPMDisp::deallocate();
+ PPPMDisp::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
+
if (function[0]) {
- ThrData * thr = fix->get_thr(tid);
- thr->init_pppm(-order,memory);
+ ThrData *thr = fix->get_thr(tid);
+ thr->init_pppm(order,memory);
}
if (function[1] + function[2]) {
ThrData * thr = fix->get_thr(tid);
- thr->init_pppm_disp(-order_6,memory);
+ thr->init_pppm_disp(order_6,memory);
}
}
}
/* ----------------------------------------------------------------------
Compute the modified (hockney-eastwood) coulomb green function
------------------------------------------------------------------------- */
void PPPMDispOMP::compute_gf()
{
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
double unitkx = (2.0*MY_PI/xprd);
double unitky = (2.0*MY_PI/yprd);
double unitkz = (2.0*MY_PI/zprd_slab);
int tid,nn,nnfrom,nnto,k,l,m;
int kper,lper,mper;
double snx,sny,snz,snx2,sny2,snz2;
double sqk;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double numerator,denominator;
const int nnx = nxhi_fft-nxlo_fft+1;
const int nny = nyhi_fft-nylo_fft+1;
loop_setup_thr(nnfrom, nnto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (m = nzlo_fft; m <= nzhi_fft; m++) {
mper = m - nz_pppm*(2*m/nz_pppm);
qz = unitkz*mper;
snz = sin(0.5*qz*zprd_slab/nz_pppm);
snz2 = snz*snz;
sz = exp(-0.25*pow(qz/g_ewald,2.0));
wz = 1.0;
argz = 0.5*qz*zprd_slab/nz_pppm;
if (argz != 0.0) wz = pow(sin(argz)/argz,order);
wz *= wz;
for (l = nylo_fft; l <= nyhi_fft; l++) {
lper = l - ny_pppm*(2*l/ny_pppm);
qy = unitky*lper;
sny = sin(0.5*qy*yprd/ny_pppm);
sny2 = sny*sny;
sy = exp(-0.25*pow(qy/g_ewald,2.0));
wy = 1.0;
argy = 0.5*qy*yprd/ny_pppm;
if (argy != 0.0) wy = pow(sin(argy)/argy,order);
wy *= wy;
for (k = nxlo_fft; k <= nxhi_fft; k++) {
/* only compute the part designated to this thread */
nn = k-nxlo_fft + nnx*(l-nylo_fft + nny*(m-nzlo_fft));
if ((nn < nnfrom) || (nn >=nnto)) continue;
kper = k - nx_pppm*(2*k/nx_pppm);
qx = unitkx*kper;
snx = sin(0.5*qx*xprd/nx_pppm);
snx2 = snx*snx;
sx = exp(-0.25*pow(qx/g_ewald,2.0));
wx = 1.0;
argx = 0.5*qx*xprd/nx_pppm;
if (argx != 0.0) wx = pow(sin(argx)/argx,order);
wx *= wx;
sqk = pow(qx,2.0) + pow(qy,2.0) + pow(qz,2.0);
if (sqk != 0.0) {
numerator = 4.0*MY_PI/sqk;
denominator = gf_denom(snx2,sny2,snz2, gf_b, order);
greensfn[nn] = numerator*sx*sy*sz*wx*wy*wz/denominator;
} else greensfn[nn] = 0.0;
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
Compyute the modified (hockney-eastwood) dispersion green function
------------------------------------------------------------------------- */
void PPPMDispOMP::compute_gf_6()
{
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double *prd;
int k,l,m,nn;
// volume-dependent factors
// adjust z dimension for 2d slab PPPM
// z dimension for 3d PPPM is zprd since slab_volfactor = 1.0
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
double unitkx = (2.0*MY_PI/xprd);
double unitky = (2.0*MY_PI/yprd);
double unitkz = (2.0*MY_PI/zprd_slab);
int kper,lper,mper;
double sqk;
double snx,sny,snz,snx2,sny2,snz2;
double argx,argy,argz,wx,wy,wz,sx,sy,sz;
double qx,qy,qz;
double rtsqk, term;
double numerator,denominator;
double inv2ew = 2*g_ewald_6;
inv2ew = 1/inv2ew;
double rtpi = sqrt(MY_PI);
int nnfrom, nnto, tid;
numerator = -MY_PI*rtpi*g_ewald_6*g_ewald_6*g_ewald_6/(3.0);
const int nnx = nxhi_fft_6-nxlo_fft_6+1;
const int nny = nyhi_fft_6-nylo_fft_6+1;
loop_setup_thr(nnfrom, nnto, tid, nfft_6, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (m = nzlo_fft_6; m <= nzhi_fft_6; m++) {
mper = m - nz_pppm_6*(2*m/nz_pppm_6);
qz = unitkz*mper;
snz = sin(0.5*unitkz*mper*zprd_slab/nz_pppm_6);
snz2 = snz*snz;
sz = exp(-qz*qz*inv2ew*inv2ew);
wz = 1.0;
argz = 0.5*qz*zprd_slab/nz_pppm_6;
if (argz != 0.0) wz = pow(sin(argz)/argz,order_6);
wz *= wz;
for (l = nylo_fft_6; l <= nyhi_fft_6; l++) {
lper = l - ny_pppm_6*(2*l/ny_pppm_6);
qy = unitky*lper;
sny = sin(0.5*unitky*lper*yprd/ny_pppm_6);
sny2 = sny*sny;
sy = exp(-qy*qy*inv2ew*inv2ew);
wy = 1.0;
argy = 0.5*qy*yprd/ny_pppm_6;
if (argy != 0.0) wy = pow(sin(argy)/argy,order_6);
wy *= wy;
for (k = nxlo_fft_6; k <= nxhi_fft_6; k++) {
/* only compute the part designated to this thread */
nn = k-nxlo_fft_6 + nnx*(l-nylo_fft_6 + nny*(m-nzlo_fft_6));
if ((nn < nnfrom) || (nn >=nnto)) continue;
kper = k - nx_pppm_6*(2*k/nx_pppm_6);
qx = unitkx*kper;
snx = sin(0.5*unitkx*kper*xprd/nx_pppm_6);
snx2 = snx*snx;
sx = exp(-qx*qx*inv2ew*inv2ew);
wx = 1.0;
argx = 0.5*qx*xprd/nx_pppm_6;
if (argx != 0.0) wx = pow(sin(argx)/argx,order_6);
wx *= wx;
sqk = pow(qx,2.0) + pow(qy,2.0) + pow(qz,2.0);
if (sqk != 0.0) {
denominator = gf_denom(snx2,sny2,snz2, gf_b_6, order_6);
rtsqk = sqrt(sqk);
term = (1-2*sqk*inv2ew*inv2ew)*sx*sy*sz +
2*sqk*rtsqk*inv2ew*inv2ew*inv2ew*rtpi*erfc(rtsqk*inv2ew);
greensfn_6[nn] = numerator*term*wx*wy*wz/denominator;
} else greensfn_6[nn] = 0.0;
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
run the regular toplevel compute method from plain PPPPM
which will have individual methods replaced by our threaded
versions and then call the obligatory force reduction.
------------------------------------------------------------------------- */
void PPPMDispOMP::compute(int eflag, int vflag)
{
PPPMDisp::compute(eflag,vflag);
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
/* ----------------------------------------------------------------------
find center grid pt for each of my particles
check that full stencil for the particle will fit in my 3d brick
store central grid pt indices in part2grid array
------------------------------------------------------------------------- */
void PPPMDispOMP::particle_map(double dxinv, double dyinv,
double dzinv, double sft,
int ** part2grid, int nup,
int nlw, int nxlo_o,
int nylo_o, int nzlo_o,
int nxhi_o, int nyhi_o,
int nzhi_o)
{
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
const int nlocal = atom->nlocal;
const double delxinv = dxinv;
const double delyinv = dyinv;
const double delzinv = dzinv;
const double shift = sft;
const int nupper = nup;
const int nlower = nlw;
const int nxlo_out = nxlo_o;
const int nylo_out = nylo_o;
const int nzlo_out = nzlo_o;
const int nxhi_out = nxhi_o;
const int nyhi_out = nyhi_o;
const int nzhi_out = nzhi_o;
if (!ISFINITE(boxlo[0]) || !ISFINITE(boxlo[1]) || !ISFINITE(boxlo[2]))
error->one(FLERR,"Non-numeric box dimensions. Simulation unstable.");
int i, flag = 0;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) reduction(+:flag) schedule(static)
#endif
for (i = 0; i < nlocal; i++) {
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// current particle coord can be outside global and local box
// add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1
const int nx = static_cast<int> ((x[i].x-boxlox)*delxinv+shift) - OFFSET;
const int ny = static_cast<int> ((x[i].y-boxloy)*delyinv+shift) - OFFSET;
const int nz = static_cast<int> ((x[i].z-boxloz)*delzinv+shift) - OFFSET;
p2g[i].a = nx;
p2g[i].b = ny;
p2g[i].t = nz;
// check that entire stencil around nx,ny,nz will fit in my 3d brick
if (nx+nlower < nxlo_out || nx+nupper > nxhi_out ||
ny+nlower < nylo_out || ny+nupper > nyhi_out ||
nz+nlower < nzlo_out || nz+nupper > nzhi_out)
flag++;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Out of range atoms - cannot compute PPPM");
}
/* ----------------------------------------------------------------------
create discretized "density" on section of global grid due to my particles
density(x,y,z) = charge "density" at grid points of my 3d brick
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
in global grid
------------------------------------------------------------------------- */
void PPPMDispOMP::make_rho_c()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick[nzlo_out][nylo_out][nxlo_out]);
memset(d,0,ngrid*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out - nxlo_out + 1;
const int iy = nyhi_out - nylo_out + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const double * _noalias const q = atom->q;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower-nzlo_out)*ix*iy >= jto)
|| ((nz+nupper-nzlo_out+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone - (x[i].x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (x[i].y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (x[i].z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz,order,rho_coeff);
const FFT_SCALAR z0 = delvolinv * q[i];
for (int n = nlower; n <= nupper; ++n) {
const int jn = (nz+n-nzlo_out)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower; m <= nupper; ++m) {
const int jm = jn+(ny+m-nylo_out)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower; l <= nupper; ++l) {
const int jl = jm+nx+l-nxlo_out;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
same as above for dispersion interaction with geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::make_rho_g()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick_g[nzlo_out_6][nylo_out_6][nxlo_out_6]);
memset(d,0,ngrid_6*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out_6 - nxlo_out_6 + 1;
const int iy = nyhi_out_6 - nylo_out_6 + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid_6[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid_6,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower_6-nzlo_out_6)*ix*iy >= jto)
|| ((nz+nupper_6-nzlo_out_6+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone_6 - (x[i].x-boxlox)*delxinv_6;
const FFT_SCALAR dy = ny+shiftone_6 - (x[i].y-boxloy)*delyinv_6;
const FFT_SCALAR dz = nz+shiftone_6 - (x[i].z-boxloz)*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz,order_6,rho_coeff_6);
const int type = atom->type[i];
const double lj = B[type];
const FFT_SCALAR z0 = delvolinv_6 * lj;
for (int n = nlower_6; n <= nupper_6; ++n) {
const int jn = (nz+n-nzlo_out_6)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower_6; m <= nupper_6; ++m) {
const int jm = jn+(ny+m-nylo_out_6)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower_6; l <= nupper_6; ++l) {
const int jl = jm+nx+l-nxlo_out_6;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
same as above for dispersion interaction with arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::make_rho_a()
{
// clear 3d density array
FFT_SCALAR * _noalias const d0 = &(density_brick_a0[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d1 = &(density_brick_a1[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d2 = &(density_brick_a2[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d3 = &(density_brick_a3[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d4 = &(density_brick_a4[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d5 = &(density_brick_a5[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d6 = &(density_brick_a6[nzlo_out_6][nylo_out_6][nxlo_out_6]);
memset(d0,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d1,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d2,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d3,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d4,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d5,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d6,0,ngrid_6*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out_6 - nxlo_out_6 + 1;
const int iy = nyhi_out_6 - nylo_out_6 + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid_6[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid_6,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower_6-nzlo_out_6)*ix*iy >= jto)
|| ((nz+nupper_6-nzlo_out_6+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone_6 - (x[i].x-boxlox)*delxinv_6;
const FFT_SCALAR dy = ny+shiftone_6 - (x[i].y-boxloy)*delyinv_6;
const FFT_SCALAR dz = nz+shiftone_6 - (x[i].z-boxloz)*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz,order_6,rho_coeff_6);
const int type = atom->type[i];
const double lj0 = B[7*type];
const double lj1 = B[7*type+1];
const double lj2 = B[7*type+2];
const double lj3 = B[7*type+3];
const double lj4 = B[7*type+4];
const double lj5 = B[7*type+5];
const double lj6 = B[7*type+6];
const FFT_SCALAR z0 = delvolinv_6;
for (int n = nlower_6; n <= nupper_6; ++n) {
const int jn = (nz+n-nzlo_out_6)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower_6; m <= nupper_6; ++m) {
const int jm = jn+(ny+m-nylo_out_6)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower_6; l <= nupper_6; ++l) {
const int jl = jm+nx+l-nxlo_out_6;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
const double w = x0*r1d[0][l];
d0[jl] += w*lj0;
d1[jl] += w*lj1;
d2[jl] += w*lj2;
d3[jl] += w*lj3;
d4[jl] += w*lj4;
d5[jl] += w*lj5;
d6[jl] += w*lj6;
}
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles
for ik scheme
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_c_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const q = atom->q;
const double * const * const x = atom->x;
const double qqrd2e = force->qqrd2e;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx,eky,ekz;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz, order, rho_coeff);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick[mz][my][mx];
eky -= x0*vdy_brick[mz][my][mx];
ekz -= x0*vdz_brick[mz][my][mx];
}
}
}
// convert E-field to force
const double qfactor = qqrd2e*scale*q[i];
f[i][0] += qfactor*ekx;
f[i][1] += qfactor*eky;
f[i][2] += qfactor*ekz;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles
for ad scheme
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_c_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const q = atom->q;
const double * const * const x = atom->x;
const double qqrd2e = force->qqrd2e;
//const double * const sf_c = sf_coeff;
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
const double hx_inv = nx_pppm/xprd;
const double hy_inv = ny_pppm/yprd;
const double hz_inv = nz_pppm/zprd_slab;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
FFT_SCALAR * const * const dr1d = static_cast<FFT_SCALAR **>(thr->get_drho1d());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz;
FFT_SCALAR ekx,eky,ekz;
double sf = 0.0;
double s1,s2,s3;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz, order, rho_coeff);
compute_drho1d_thr(dr1d,dx,dy,dz, order, drho_coeff);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
for (m = nlower; m <= nupper; m++) {
my = m+ny;
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
ekx += dr1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
eky += r1d[0][l]*dr1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*dr1d[2][n]*u_brick[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force
const double qfactor = qqrd2e*scale;
s1 = x[i][0]*hx_inv;
s2 = x[i][1]*hy_inv;
s3 = x[i][2]*hz_inv;
sf = sf_coeff[0]*sin(2*MY_PI*s1);
sf += sf_coeff[1]*sin(4*MY_PI*s1);
sf *= 2*q[i]*q[i];
f[i][0] += qfactor*(ekx*q[i] - sf);
sf = sf_coeff[2]*sin(2*MY_PI*s2);
sf += sf_coeff[3]*sin(4*MY_PI*s2);
sf *= 2*q[i]*q[i];
f[i][1] += qfactor*(eky*q[i] - sf);
sf = sf_coeff[4]*sin(2*MY_PI*s3);
sf += sf_coeff[5]*sin(4*MY_PI*s3);
sf *= 2*q[i]*q[i];
if (slabflag != 2) f[i][2] += qfactor*(ekz*q[i] - sf);
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_c_peratom()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const double * const q = atom->q;
const double * const * const x = atom->x;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u,v0,v1,v2,v3,v4,v5;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz, order, rho_coeff);
u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) u += x0*u_brick[mz][my][mx];
if (vflag_atom) {
v0 += x0*v0_brick[mz][my][mx];
v1 += x0*v1_brick[mz][my][mx];
v2 += x0*v2_brick[mz][my][mx];
v3 += x0*v3_brick[mz][my][mx];
v4 += x0*v4_brick[mz][my][mx];
v5 += x0*v5_brick[mz][my][mx];
}
}
}
}
const double qfactor = 0.5*force->qqrd2e * scale * q[i];
if (eflag_atom) eatom[i] += u*qfactor;
if (vflag_atom) {
vatom[i][0] += v0*qfactor;
vatom[i][1] += v1*qfactor;
vatom[i][2] += v2*qfactor;
vatom[i][3] += v3*qfactor;
vatom[i][4] += v4*qfactor;
vatom[i][5] += v5*qfactor;
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ik scheme and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_g_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx,eky,ekz;
int type;
double lj;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
ekx = eky = ekz = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick_g[mz][my][mx];
eky -= x0*vdy_brick_g[mz][my][mx];
ekz -= x0*vdz_brick_g[mz][my][mx];
}
}
}
// convert E-field to force
type = atom->type[i];
lj = B[type];
f[i][0] += lj*ekx;
f[i][1] += lj*eky;
f[i][2] += lj*ekz;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ad scheme and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_g_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
const double hx_inv = nx_pppm_6/xprd;
const double hy_inv = ny_pppm_6/yprd;
const double hz_inv = nz_pppm_6/zprd_slab;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
FFT_SCALAR * const * const dr1d = static_cast<FFT_SCALAR **>(thr->get_drho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz;
FFT_SCALAR ekx,eky,ekz;
int type;
double lj;
double sf = 0.0;
double s1,s2,s3;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
compute_drho1d_thr(dr1d,dx,dy,dz, order_6, drho_coeff_6);
ekx = eky = ekz = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
ekx += dr1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick_g[mz][my][mx];
eky += r1d[0][l]*dr1d[1][m]*r1d[2][n]*u_brick_g[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*dr1d[2][n]*u_brick_g[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force
type = atom->type[i];
lj = B[type];
s1 = x[i][0]*hx_inv;
s2 = x[i][1]*hy_inv;
s3 = x[i][2]*hz_inv;
sf = sf_coeff_6[0]*sin(2*MY_PI*s1);
sf += sf_coeff_6[1]*sin(4*MY_PI*s1);
sf *= 2*lj*lj;
f[i][0] += ekx*lj - sf;
sf = sf_coeff_6[2]*sin(2*MY_PI*s2);
sf += sf_coeff_6[3]*sin(4*MY_PI*s2);
sf *= 2*lj*lj;
f[i][1] += eky*lj - sf;
sf = sf_coeff_6[4]*sin(2*MY_PI*s3);
sf += sf_coeff_6[5]*sin(4*MY_PI*s3);
sf *= 2*lj*lj;
if (slabflag != 2) f[i][2] += ekz*lj - sf;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial for dispersion
interaction and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_g_peratom()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const double * const * const x = atom->x;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u,v0,v1,v2,v3,v4,v5;
int type;
double lj;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) u += x0*u_brick_g[mz][my][mx];
if (vflag_atom) {
v0 += x0*v0_brick_g[mz][my][mx];
v1 += x0*v1_brick_g[mz][my][mx];
v2 += x0*v2_brick_g[mz][my][mx];
v3 += x0*v3_brick_g[mz][my][mx];
v4 += x0*v4_brick_g[mz][my][mx];
v5 += x0*v5_brick_g[mz][my][mx];
}
}
}
}
type = atom->type[i];
lj = B[type]*0.5;
if (eflag_atom) eatom[i] += u*lj;
if (vflag_atom) {
vatom[i][0] += v0*lj;
vatom[i][1] += v1*lj;
vatom[i][2] += v2*lj;
vatom[i][3] += v3*lj;
vatom[i][4] += v4*lj;
vatom[i][5] += v5*lj;
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ik scheme and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_a_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx0, eky0, ekz0, ekx1, eky1, ekz1, ekx2, eky2, ekz2;
FFT_SCALAR ekx3, eky3, ekz3, ekx4, eky4, ekz4, ekx5, eky5, ekz5;
FFT_SCALAR ekx6, eky6, ekz6;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
ekx0 = eky0 = ekz0 = ZEROF;
ekx1 = eky1 = ekz1 = ZEROF;
ekx2 = eky2 = ekz2 = ZEROF;
ekx3 = eky3 = ekz3 = ZEROF;
ekx4 = eky4 = ekz4 = ZEROF;
ekx5 = eky5 = ekz5 = ZEROF;
ekx6 = eky6 = ekz6 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx0 -= x0*vdx_brick_a0[mz][my][mx];
eky0 -= x0*vdy_brick_a0[mz][my][mx];
ekz0 -= x0*vdz_brick_a0[mz][my][mx];
ekx1 -= x0*vdx_brick_a1[mz][my][mx];
eky1 -= x0*vdy_brick_a1[mz][my][mx];
ekz1 -= x0*vdz_brick_a1[mz][my][mx];
ekx2 -= x0*vdx_brick_a2[mz][my][mx];
eky2 -= x0*vdy_brick_a2[mz][my][mx];
ekz2 -= x0*vdz_brick_a2[mz][my][mx];
ekx3 -= x0*vdx_brick_a3[mz][my][mx];
eky3 -= x0*vdy_brick_a3[mz][my][mx];
ekz3 -= x0*vdz_brick_a3[mz][my][mx];
ekx4 -= x0*vdx_brick_a4[mz][my][mx];
eky4 -= x0*vdy_brick_a4[mz][my][mx];
ekz4 -= x0*vdz_brick_a4[mz][my][mx];
ekx5 -= x0*vdx_brick_a5[mz][my][mx];
eky5 -= x0*vdy_brick_a5[mz][my][mx];
ekz5 -= x0*vdz_brick_a5[mz][my][mx];
ekx6 -= x0*vdx_brick_a6[mz][my][mx];
eky6 -= x0*vdy_brick_a6[mz][my][mx];
ekz6 -= x0*vdz_brick_a6[mz][my][mx];
}
}
}
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6];
lj1 = B[7*type+5];
lj2 = B[7*type+4];
lj3 = B[7*type+3];
lj4 = B[7*type+2];
lj5 = B[7*type+1];
lj6 = B[7*type];
f[i][0] += lj0*ekx0 + lj1*ekx1 + lj2*ekx2 + lj3*ekx3 + lj4*ekx4 + lj5*ekx5 + lj6*ekx6;
f[i][1] += lj0*eky0 + lj1*eky1 + lj2*eky2 + lj3*eky3 + lj4*eky4 + lj5*eky5 + lj6*eky6;
f[i][2] += lj0*ekz0 + lj1*ekz1 + lj2*ekz2 + lj3*ekz3 + lj4*ekz4 + lj5*ekz5 + lj6*ekz6;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ad scheme and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_a_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
const double hx_inv = nx_pppm_6/xprd;
const double hy_inv = ny_pppm_6/yprd;
const double hz_inv = nz_pppm_6/zprd_slab;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
FFT_SCALAR * const * const dr1d = static_cast<FFT_SCALAR **>(thr->get_drho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx0, eky0, ekz0, ekx1, eky1, ekz1, ekx2, eky2, ekz2;
FFT_SCALAR ekx3, eky3, ekz3, ekx4, eky4, ekz4, ekx5, eky5, ekz5;
FFT_SCALAR ekx6, eky6, ekz6;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
double sf = 0.0;
double s1,s2,s3;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
compute_drho1d_thr(dr1d,dx,dy,dz, order_6, drho_coeff_6);
ekx0 = eky0 = ekz0 = ZEROF;
ekx1 = eky1 = ekz1 = ZEROF;
ekx2 = eky2 = ekz2 = ZEROF;
ekx3 = eky3 = ekz3 = ZEROF;
ekx4 = eky4 = ekz4 = ZEROF;
ekx5 = eky5 = ekz5 = ZEROF;
ekx6 = eky6 = ekz6 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = dr1d[0][l]*r1d[1][m]*r1d[2][n];
y0 = r1d[0][l]*dr1d[1][m]*r1d[2][n];
z0 = r1d[0][l]*r1d[1][m]*dr1d[2][n];
ekx0 += x0*u_brick_a0[mz][my][mx];
eky0 += y0*u_brick_a0[mz][my][mx];
ekz0 += z0*u_brick_a0[mz][my][mx];
ekx1 += x0*u_brick_a1[mz][my][mx];
eky1 += y0*u_brick_a1[mz][my][mx];
ekz1 += z0*u_brick_a1[mz][my][mx];
ekx2 += x0*u_brick_a2[mz][my][mx];
eky2 += y0*u_brick_a2[mz][my][mx];
ekz2 += z0*u_brick_a2[mz][my][mx];
ekx3 += x0*u_brick_a3[mz][my][mx];
eky3 += y0*u_brick_a3[mz][my][mx];
ekz3 += z0*u_brick_a3[mz][my][mx];
ekx4 += x0*u_brick_a4[mz][my][mx];
eky4 += y0*u_brick_a4[mz][my][mx];
ekz4 += z0*u_brick_a4[mz][my][mx];
ekx5 += x0*u_brick_a5[mz][my][mx];
eky5 += y0*u_brick_a5[mz][my][mx];
ekz5 += z0*u_brick_a5[mz][my][mx];
ekx6 += x0*u_brick_a6[mz][my][mx];
eky6 += y0*u_brick_a6[mz][my][mx];
ekz6 += z0*u_brick_a6[mz][my][mx];
}
}
}
ekx0 *= hx_inv;
eky0 *= hy_inv;
ekz0 *= hz_inv;
ekx1 *= hx_inv;
eky1 *= hy_inv;
ekz1 *= hz_inv;
ekx2 *= hx_inv;
eky2 *= hy_inv;
ekz2 *= hz_inv;
ekx3 *= hx_inv;
eky3 *= hy_inv;
ekz3 *= hz_inv;
ekx4 *= hx_inv;
eky4 *= hy_inv;
ekz4 *= hz_inv;
ekx5 *= hx_inv;
eky5 *= hy_inv;
ekz5 *= hz_inv;
ekx6 *= hx_inv;
eky6 *= hy_inv;
ekz6 *= hz_inv;
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6];
lj1 = B[7*type+5];
lj2 = B[7*type+4];
lj3 = B[7*type+3];
lj4 = B[7*type+2];
lj5 = B[7*type+1];
lj6 = B[7*type];
s1 = x[i][0]*hx_inv;
s2 = x[i][1]*hy_inv;
s3 = x[i][2]*hz_inv;
sf = sf_coeff_6[0]*sin(2*MY_PI*s1);
sf += sf_coeff_6[1]*sin(4*MY_PI*s1);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
f[i][0] += lj0*ekx0 + lj1*ekx1 + lj2*ekx2 + lj3*ekx3 + lj4*ekx4 + lj5*ekx5 + lj6*ekx6 - sf;
sf = sf_coeff_6[2]*sin(2*MY_PI*s2);
sf += sf_coeff_6[3]*sin(4*MY_PI*s2);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
f[i][1] += lj0*eky0 + lj1*eky1 + lj2*eky2 + lj3*eky3 + lj4*eky4 + lj5*eky5 + lj6*eky6 - sf;
sf = sf_coeff_6[4]*sin(2*MY_PI*s3);
sf += sf_coeff_6[5]*sin(4*MY_PI*s3);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
if (slabflag != 2) f[i][2] += lj0*ekz0 + lj1*ekz1 + lj2*ekz2 + lj3*ekz3 + lj4*ekz4 + lj5*ekz5 + lj6*ekz6 - sf;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial for dispersion
interaction and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispOMP::fieldforce_a_peratom()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const double * const * const x = atom->x;
#if defined(_OPENMP)
const int nthreads = comm->nthreads;
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u0,v00,v10,v20,v30,v40,v50;
FFT_SCALAR u1,v01,v11,v21,v31,v41,v51;
FFT_SCALAR u2,v02,v12,v22,v32,v42,v52;
FFT_SCALAR u3,v03,v13,v23,v33,v43,v53;
FFT_SCALAR u4,v04,v14,v24,v34,v44,v54;
FFT_SCALAR u5,v05,v15,v25,v35,v45,v55;
FFT_SCALAR u6,v06,v16,v26,v36,v46,v56;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
u0 = v00 = v10 = v20 = v30 = v40 = v50 = ZEROF;
u1 = v01 = v11 = v21 = v31 = v41 = v51 = ZEROF;
u2 = v02 = v12 = v22 = v32 = v42 = v52 = ZEROF;
u3 = v03 = v13 = v23 = v33 = v43 = v53 = ZEROF;
u4 = v04 = v14 = v24 = v34 = v44 = v54 = ZEROF;
u5 = v05 = v15 = v25 = v35 = v45 = v55 = ZEROF;
u6 = v06 = v16 = v26 = v36 = v46 = v56 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) {
u0 += x0*u_brick_a0[mz][my][mx];
u1 += x0*u_brick_a1[mz][my][mx];
u2 += x0*u_brick_a2[mz][my][mx];
u3 += x0*u_brick_a3[mz][my][mx];
u4 += x0*u_brick_a4[mz][my][mx];
u5 += x0*u_brick_a5[mz][my][mx];
u6 += x0*u_brick_a6[mz][my][mx];
}
if (vflag_atom) {
v00 += x0*v0_brick_a0[mz][my][mx];
v10 += x0*v1_brick_a0[mz][my][mx];
v20 += x0*v2_brick_a0[mz][my][mx];
v30 += x0*v3_brick_a0[mz][my][mx];
v40 += x0*v4_brick_a0[mz][my][mx];
v50 += x0*v5_brick_a0[mz][my][mx];
v01 += x0*v0_brick_a1[mz][my][mx];
v11 += x0*v1_brick_a1[mz][my][mx];
v21 += x0*v2_brick_a1[mz][my][mx];
v31 += x0*v3_brick_a1[mz][my][mx];
v41 += x0*v4_brick_a1[mz][my][mx];
v51 += x0*v5_brick_a1[mz][my][mx];
v02 += x0*v0_brick_a2[mz][my][mx];
v12 += x0*v1_brick_a2[mz][my][mx];
v22 += x0*v2_brick_a2[mz][my][mx];
v32 += x0*v3_brick_a2[mz][my][mx];
v42 += x0*v4_brick_a2[mz][my][mx];
v52 += x0*v5_brick_a2[mz][my][mx];
v03 += x0*v0_brick_a3[mz][my][mx];
v13 += x0*v1_brick_a3[mz][my][mx];
v23 += x0*v2_brick_a3[mz][my][mx];
v33 += x0*v3_brick_a3[mz][my][mx];
v43 += x0*v4_brick_a3[mz][my][mx];
v53 += x0*v5_brick_a3[mz][my][mx];
v04 += x0*v0_brick_a4[mz][my][mx];
v14 += x0*v1_brick_a4[mz][my][mx];
v24 += x0*v2_brick_a4[mz][my][mx];
v34 += x0*v3_brick_a4[mz][my][mx];
v44 += x0*v4_brick_a4[mz][my][mx];
v54 += x0*v5_brick_a4[mz][my][mx];
v05 += x0*v0_brick_a5[mz][my][mx];
v15 += x0*v1_brick_a5[mz][my][mx];
v25 += x0*v2_brick_a5[mz][my][mx];
v35 += x0*v3_brick_a5[mz][my][mx];
v45 += x0*v4_brick_a5[mz][my][mx];
v55 += x0*v5_brick_a5[mz][my][mx];
v06 += x0*v0_brick_a6[mz][my][mx];
v16 += x0*v1_brick_a6[mz][my][mx];
v26 += x0*v2_brick_a6[mz][my][mx];
v36 += x0*v3_brick_a6[mz][my][mx];
v46 += x0*v4_brick_a6[mz][my][mx];
v56 += x0*v5_brick_a6[mz][my][mx];
}
}
}
}
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6]*0.5;
lj1 = B[7*type+5]*0.5;
lj2 = B[7*type+4]*0.5;
lj3 = B[7*type+3]*0.5;
lj4 = B[7*type+2]*0.5;
lj5 = B[7*type+1]*0.5;
lj6 = B[7*type]*0.5;
if (eflag_atom)
eatom[i] += u0*lj0 + u1*lj1 + u2*lj2 +
u3*lj3 + u4*lj4 + u5*lj5 + u6*lj6;
if (vflag_atom) {
vatom[i][0] += v00*lj0 + v01*lj1 + v02*lj2 + v03*lj3 +
v04*lj4 + v05*lj5 + v06*lj6;
vatom[i][1] += v10*lj0 + v11*lj1 + v12*lj2 + v13*lj3 +
v14*lj4 + v15*lj5 + v16*lj6;
vatom[i][2] += v20*lj0 + v21*lj1 + v22*lj2 + v23*lj3 +
v24*lj4 + v25*lj5 + v26*lj6;
vatom[i][3] += v30*lj0 + v31*lj1 + v32*lj2 + v33*lj3 +
v34*lj4 + v35*lj5 + v36*lj6;
vatom[i][4] += v40*lj0 + v41*lj1 + v42*lj2 + v43*lj3 +
v44*lj4 + v45*lj5 + v46*lj6;
vatom[i][5] += v50*lj0 + v51*lj1 + v52*lj2 + v53*lj3 +
v54*lj4 + v55*lj5 + v56*lj6;
}
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
charge assignment into rho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMDispOMP::compute_rho1d_thr(FFT_SCALAR * const * const r1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz,
const int ord, FFT_SCALAR * const * const rho_c)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-ord)/2; k <= ord/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = ord-1; l >= 0; l--) {
r1 = rho_c[l][k] + r1*dx;
r2 = rho_c[l][k] + r2*dy;
r3 = rho_c[l][k] + r3*dz;
}
r1d[0][k] = r1;
r1d[1][k] = r2;
r1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
charge assignment into drho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMDispOMP::compute_drho1d_thr(FFT_SCALAR * const * const dr1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz,
const int ord, FFT_SCALAR * const * const drho_c)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-ord)/2; k <= ord/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = ord-2; l >= 0; l--) {
r1 = drho_c[l][k] + r1*dx;
r2 = drho_c[l][k] + r2*dy;
r3 = drho_c[l][k] + r3*dz;
}
dr1d[0][k] = r1;
dr1d[1][k] = r2;
dr1d[2][k] = r3;
}
}
diff --git a/src/USER-OMP/pppm_disp_omp.h b/src/USER-OMP/pppm_disp_omp.h
index 86c213282..b1ec2856b 100644
--- a/src/USER-OMP/pppm_disp_omp.h
+++ b/src/USER-OMP/pppm_disp_omp.h
@@ -1,74 +1,73 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef KSPACE_CLASS
KSpaceStyle(pppm/disp/omp,PPPMDispOMP)
#else
#ifndef LMP_PPPM_DISP_OMP_H
#define LMP_PPPM_DISP_OMP_H
#include "pppm_disp.h"
#include "thr_omp.h"
namespace LAMMPS_NS {
class PPPMDispOMP : public PPPMDisp, public ThrOMP {
public:
PPPMDispOMP(class LAMMPS *, int, char **);
virtual ~PPPMDispOMP ();
virtual void compute(int, int);
protected:
virtual void allocate();
- virtual void deallocate();
virtual void compute_gf();
virtual void compute_gf_6();
virtual void particle_map(double,double,double,
double,int**,int,int,
int,int,int,int,int,int);
virtual void fieldforce_c_ik();
virtual void fieldforce_c_ad();
virtual void fieldforce_c_peratom();
virtual void fieldforce_g_ik();
virtual void fieldforce_g_ad();
virtual void fieldforce_g_peratom();
virtual void fieldforce_a_ik();
virtual void fieldforce_a_ad();
virtual void fieldforce_a_peratom();
virtual void make_rho_c();
virtual void make_rho_g();
virtual void make_rho_a();
void compute_rho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &,
const int, FFT_SCALAR * const * const);
void compute_drho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &,
const int, FFT_SCALAR * const * const);
// void compute_rho_coeff();
// void slabcorr(int);
};
}
#endif
#endif
diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.cpp b/src/USER-OMP/pppm_disp_tip4p_omp.cpp
index 8872c849f..29aeeb79d 100644
--- a/src/USER-OMP/pppm_disp_tip4p_omp.cpp
+++ b/src/USER-OMP/pppm_disp_tip4p_omp.cpp
@@ -1,1873 +1,1869 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "pppm_disp_tip4p_omp.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_omp.h"
#include "force.h"
#include "memory.h"
#include "math_const.h"
#include "math_special.h"
#include <string.h>
#include <math.h>
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace MathSpecial;
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#else
#define ZEROF 0.0
#endif
#define OFFSET 16384
/* ---------------------------------------------------------------------- */
PPPMDispTIP4POMP::PPPMDispTIP4POMP(LAMMPS *lmp, int narg, char **arg) :
PPPMDispTIP4P(lmp, narg, arg), ThrOMP(lmp, THR_KSPACE)
{
triclinic_support = 0;
tip4pflag = 1;
suffix_flag |= Suffix::OMP;
}
-/* ----------------------------------------------------------------------
- allocate memory that depends on # of K-vectors and order
-------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
-void PPPMDispTIP4POMP::allocate()
+PPPMDispTIP4POMP::~PPPMDispTIP4POMP()
{
- PPPMDispTIP4P::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
-
if (function[0]) {
- ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(order,memory);
+ ThrData * thr = fix->get_thr(tid);
+ thr->init_pppm(-order,memory);
}
if (function[1] + function[2]) {
ThrData * thr = fix->get_thr(tid);
- thr->init_pppm_disp(order_6,memory);
+ thr->init_pppm_disp(-order_6,memory);
}
}
}
/* ----------------------------------------------------------------------
- free memory that depends on # of K-vectors and order
+ allocate memory that depends on # of K-vectors and order
------------------------------------------------------------------------- */
-void PPPMDispTIP4POMP::deallocate()
+void PPPMDispTIP4POMP::allocate()
{
- PPPMDispTIP4P::deallocate();
+ PPPMDispTIP4P::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
+
if (function[0]) {
- ThrData * thr = fix->get_thr(tid);
- thr->init_pppm(-order,memory);
+ ThrData *thr = fix->get_thr(tid);
+ thr->init_pppm(order,memory);
}
if (function[1] + function[2]) {
ThrData * thr = fix->get_thr(tid);
- thr->init_pppm_disp(-order_6,memory);
+ thr->init_pppm_disp(order_6,memory);
}
}
}
-
/* ----------------------------------------------------------------------
Compute the modified (hockney-eastwood) coulomb green function
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::compute_gf()
{
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
double unitkx = (2.0*MY_PI/xprd);
double unitky = (2.0*MY_PI/yprd);
double unitkz = (2.0*MY_PI/zprd_slab);
int tid,nn,nnfrom,nnto,k,l,m;
int kper,lper,mper;
double snx,sny,snz,snx2,sny2,snz2;
double sqk;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double numerator,denominator;
const int nnx = nxhi_fft-nxlo_fft+1;
const int nny = nyhi_fft-nylo_fft+1;
loop_setup_thr(nnfrom, nnto, tid, nfft, comm->nthreads);
for (m = nzlo_fft; m <= nzhi_fft; m++) {
mper = m - nz_pppm*(2*m/nz_pppm);
qz = unitkz*mper;
snz = sin(0.5*qz*zprd_slab/nz_pppm);
snz2 = snz*snz;
sz = exp(-0.25*pow(qz/g_ewald,2.0));
wz = 1.0;
argz = 0.5*qz*zprd_slab/nz_pppm;
if (argz != 0.0) wz = pow(sin(argz)/argz,order);
wz *= wz;
for (l = nylo_fft; l <= nyhi_fft; l++) {
lper = l - ny_pppm*(2*l/ny_pppm);
qy = unitky*lper;
sny = sin(0.5*qy*yprd/ny_pppm);
sny2 = sny*sny;
sy = exp(-0.25*pow(qy/g_ewald,2.0));
wy = 1.0;
argy = 0.5*qy*yprd/ny_pppm;
if (argy != 0.0) wy = pow(sin(argy)/argy,order);
wy *= wy;
for (k = nxlo_fft; k <= nxhi_fft; k++) {
/* only compute the part designated to this thread */
nn = k-nxlo_fft + nnx*(l-nylo_fft + nny*(m-nzlo_fft));
if ((nn < nnfrom) || (nn >=nnto)) continue;
kper = k - nx_pppm*(2*k/nx_pppm);
qx = unitkx*kper;
snx = sin(0.5*qx*xprd/nx_pppm);
snx2 = snx*snx;
sx = exp(-0.25*pow(qx/g_ewald,2.0));
wx = 1.0;
argx = 0.5*qx*xprd/nx_pppm;
if (argx != 0.0) wx = pow(sin(argx)/argx,order);
wx *= wx;
sqk = pow(qx,2.0) + pow(qy,2.0) + pow(qz,2.0);
if (sqk != 0.0) {
numerator = 4.0*MY_PI/sqk;
denominator = gf_denom(snx2,sny2,snz2, gf_b, order);
greensfn[nn] = numerator*sx*sy*sz*wx*wy*wz/denominator;
} else greensfn[nn] = 0.0;
}
}
}
}
}
/* ----------------------------------------------------------------------
Compyute the modified (hockney-eastwood) dispersion green function
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::compute_gf_6()
{
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double *prd;
int k,l,m,nn;
// volume-dependent factors
// adjust z dimension for 2d slab PPPM
// z dimension for 3d PPPM is zprd since slab_volfactor = 1.0
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
double unitkx = (2.0*MY_PI/xprd);
double unitky = (2.0*MY_PI/yprd);
double unitkz = (2.0*MY_PI/zprd_slab);
int kper,lper,mper;
double sqk;
double snx,sny,snz,snx2,sny2,snz2;
double argx,argy,argz,wx,wy,wz,sx,sy,sz;
double qx,qy,qz;
double rtsqk, term;
double numerator,denominator;
double inv2ew = 2*g_ewald_6;
inv2ew = 1/inv2ew;
double rtpi = sqrt(MY_PI);
int nnfrom, nnto, tid;
numerator = -MY_PI*rtpi*g_ewald_6*g_ewald_6*g_ewald_6/(3.0);
const int nnx = nxhi_fft_6-nxlo_fft_6+1;
const int nny = nyhi_fft_6-nylo_fft_6+1;
loop_setup_thr(nnfrom, nnto, tid, nfft_6, comm->nthreads);
for (m = nzlo_fft_6; m <= nzhi_fft_6; m++) {
mper = m - nz_pppm_6*(2*m/nz_pppm_6);
qz = unitkz*mper;
snz = sin(0.5*unitkz*mper*zprd_slab/nz_pppm_6);
snz2 = snz*snz;
sz = exp(-qz*qz*inv2ew*inv2ew);
wz = 1.0;
argz = 0.5*qz*zprd_slab/nz_pppm_6;
if (argz != 0.0) wz = pow(sin(argz)/argz,order_6);
wz *= wz;
for (l = nylo_fft_6; l <= nyhi_fft_6; l++) {
lper = l - ny_pppm_6*(2*l/ny_pppm_6);
qy = unitky*lper;
sny = sin(0.5*unitky*lper*yprd/ny_pppm_6);
sny2 = sny*sny;
sy = exp(-qy*qy*inv2ew*inv2ew);
wy = 1.0;
argy = 0.5*qy*yprd/ny_pppm_6;
if (argy != 0.0) wy = pow(sin(argy)/argy,order_6);
wy *= wy;
for (k = nxlo_fft_6; k <= nxhi_fft_6; k++) {
/* only compute the part designated to this thread */
nn = k-nxlo_fft_6 + nnx*(l-nylo_fft_6 + nny*(m-nzlo_fft_6));
if ((nn < nnfrom) || (nn >=nnto)) continue;
kper = k - nx_pppm_6*(2*k/nx_pppm_6);
qx = unitkx*kper;
snx = sin(0.5*unitkx*kper*xprd/nx_pppm_6);
snx2 = snx*snx;
sx = exp(-qx*qx*inv2ew*inv2ew);
wx = 1.0;
argx = 0.5*qx*xprd/nx_pppm_6;
if (argx != 0.0) wx = pow(sin(argx)/argx,order_6);
wx *= wx;
sqk = pow(qx,2.0) + pow(qy,2.0) + pow(qz,2.0);
denominator = gf_denom(snx2,sny2,snz2, gf_b_6, order_6);
rtsqk = sqrt(sqk);
term = (1-2*sqk*inv2ew*inv2ew)*sx*sy*sz +
2*sqk*rtsqk*inv2ew*inv2ew*inv2ew*rtpi*erfc(rtsqk*inv2ew);
greensfn_6[nn] = numerator*term*wx*wy*wz/denominator;
}
}
}
}
}
/* ----------------------------------------------------------------------
run the regular toplevel compute method from plain PPPM
which will have individual methods replaced by our threaded
versions and then call the obligatory force reduction.
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::compute(int eflag, int vflag)
{
PPPMDispTIP4P::compute(eflag,vflag);
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
/* ----------------------------------------------------------------------
find center grid pt for each of my particles
check that full stencil for the particle will fit in my 3d brick
store central grid pt indices in part2grid array
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::particle_map_c(double dxinv, double dyinv,
double dzinv, double sft,
int ** part2grid, int nup,
int nlw, int nxlo_o,
int nylo_o, int nzlo_o,
int nxhi_o, int nyhi_o,
int nzhi_o)
{
// no local atoms => nothing to do
if (atom->nlocal == 0) return;
const int * _noalias const type = atom->type;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
const int nlocal = atom->nlocal;
const double delxinv = dxinv;
const double delyinv = dyinv;
const double delzinv = dzinv;
const double shift = sft;
const int nupper = nup;
const int nlower = nlw;
const int nxlo_out = nxlo_o;
const int nylo_out = nylo_o;
const int nzlo_out = nzlo_o;
const int nxhi_out = nxhi_o;
const int nyhi_out = nyhi_o;
const int nzhi_out = nzhi_o;
if (!ISFINITE(boxlo[0]) || !ISFINITE(boxlo[1]) || !ISFINITE(boxlo[2]))
error->one(FLERR,"Non-numeric box dimensions - simulation unstable");
int i, flag = 0;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) reduction(+:flag) schedule(static)
#endif
for (i = 0; i < nlocal; i++) {
dbl3_t xM;
int iH1,iH2;
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else {
xM = x[i];
}
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// current particle coord can be outside global and local box
// add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1
const int nx = static_cast<int> ((xM.x-boxlox)*delxinv+shift) - OFFSET;
const int ny = static_cast<int> ((xM.y-boxloy)*delyinv+shift) - OFFSET;
const int nz = static_cast<int> ((xM.z-boxloz)*delzinv+shift) - OFFSET;
p2g[i].a = nx;
p2g[i].b = ny;
p2g[i].t = nz;
// check that entire stencil around nx,ny,nz will fit in my 3d brick
if (nx+nlower < nxlo_out || nx+nupper > nxhi_out ||
ny+nlower < nylo_out || ny+nupper > nyhi_out ||
nz+nlower < nzlo_out || nz+nupper > nzhi_out)
flag++;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Out of range atoms - cannot compute PPPM");
}
/* ----------------------------------------------------------------------
find center grid pt for each of my particles
check that full stencil for the particle will fit in my 3d brick
store central grid pt indices in part2grid array
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::particle_map(double dxinv, double dyinv,
double dzinv, double sft,
int ** part2grid, int nup,
int nlw, int nxlo_o,
int nylo_o, int nzlo_o,
int nxhi_o, int nyhi_o,
int nzhi_o)
{
// no local atoms => nothing to do
if (atom->nlocal == 0) return;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
const int nlocal = atom->nlocal;
const double delxinv = dxinv;
const double delyinv = dyinv;
const double delzinv = dzinv;
const double shift = sft;
const int nupper = nup;
const int nlower = nlw;
const int nxlo_out = nxlo_o;
const int nylo_out = nylo_o;
const int nzlo_out = nzlo_o;
const int nxhi_out = nxhi_o;
const int nyhi_out = nyhi_o;
const int nzhi_out = nzhi_o;
int i, flag = 0;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) reduction(+:flag) schedule(static)
#endif
for (i = 0; i < nlocal; i++) {
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// current particle coord can be outside global and local box
// add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1
const int nx = static_cast<int> ((x[i].x-boxlox)*delxinv+shift) - OFFSET;
const int ny = static_cast<int> ((x[i].y-boxloy)*delyinv+shift) - OFFSET;
const int nz = static_cast<int> ((x[i].z-boxloz)*delzinv+shift) - OFFSET;
p2g[i].a = nx;
p2g[i].b = ny;
p2g[i].t = nz;
// check that entire stencil around nx,ny,nz will fit in my 3d brick
if (nx+nlower < nxlo_out || nx+nupper > nxhi_out ||
ny+nlower < nylo_out || ny+nupper > nyhi_out ||
nz+nlower < nzlo_out || nz+nupper > nzhi_out)
flag++;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Out of range atoms - cannot compute PPPM");
}
/* ----------------------------------------------------------------------
create discretized "density" on section of global grid due to my particles
density(x,y,z) = charge "density" at grid points of my 3d brick
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
in global grid
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::make_rho_c()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick[nzlo_out][nylo_out][nxlo_out]);
memset(d,0,ngrid*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out - nxlo_out + 1;
const int iy = nyhi_out - nylo_out + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const double * _noalias const q = atom->q;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
dbl3_t xM;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid,iH1,iH2;
loop_setup_thr(jfrom,jto,tid,ngrid,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower-nzlo_out)*ix*iy >= jto)
|| ((nz+nupper-nzlo_out+1)*ix*iy < jfrom) ) continue;
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else {
xM = x[i];
}
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz,order,rho_coeff);
const FFT_SCALAR z0 = delvolinv * q[i];
for (int n = nlower; n <= nupper; ++n) {
const int jn = (nz+n-nzlo_out)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower; m <= nupper; ++m) {
const int jm = jn+(ny+m-nylo_out)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower; l <= nupper; ++l) {
const int jl = jm+nx+l-nxlo_out;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
}
}
/* ----------------------------------------------------------------------
same as above for dispersion interaction with geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::make_rho_g()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick_g[nzlo_out_6][nylo_out_6][nxlo_out_6]);
memset(d,0,ngrid_6*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out_6 - nxlo_out_6 + 1;
const int iy = nyhi_out_6 - nylo_out_6 + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid_6[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid_6,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower_6-nzlo_out_6)*ix*iy >= jto)
|| ((nz+nupper_6-nzlo_out_6+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone_6 - (x[i].x-boxlox)*delxinv_6;
const FFT_SCALAR dy = ny+shiftone_6 - (x[i].y-boxloy)*delyinv_6;
const FFT_SCALAR dz = nz+shiftone_6 - (x[i].z-boxloz)*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz,order_6,rho_coeff_6);
const int type = atom->type[i];
const double lj = B[type];
const FFT_SCALAR z0 = delvolinv_6 * lj;
for (int n = nlower_6; n <= nupper_6; ++n) {
const int jn = (nz+n-nzlo_out_6)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower_6; m <= nupper_6; ++m) {
const int jm = jn+(ny+m-nylo_out_6)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower_6; l <= nupper_6; ++l) {
const int jl = jm+nx+l-nxlo_out_6;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
}
}
/* ----------------------------------------------------------------------
same as above for dispersion interaction with arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::make_rho_a()
{
// clear 3d density array
FFT_SCALAR * _noalias const d0 = &(density_brick_a0[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d1 = &(density_brick_a1[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d2 = &(density_brick_a2[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d3 = &(density_brick_a3[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d4 = &(density_brick_a4[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d5 = &(density_brick_a5[nzlo_out_6][nylo_out_6][nxlo_out_6]);
FFT_SCALAR * _noalias const d6 = &(density_brick_a6[nzlo_out_6][nylo_out_6][nxlo_out_6]);
memset(d0,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d1,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d2,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d3,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d4,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d5,0,ngrid_6*sizeof(FFT_SCALAR));
memset(d6,0,ngrid_6*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out_6 - nxlo_out_6 + 1;
const int iy = nyhi_out_6 - nylo_out_6 + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid_6[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid_6,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower_6-nzlo_out_6)*ix*iy >= jto)
|| ((nz+nupper_6-nzlo_out_6+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone_6 - (x[i].x-boxlox)*delxinv_6;
const FFT_SCALAR dy = ny+shiftone_6 - (x[i].y-boxloy)*delyinv_6;
const FFT_SCALAR dz = nz+shiftone_6 - (x[i].z-boxloz)*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz,order_6,rho_coeff_6);
const int type = atom->type[i];
const double lj0 = B[7*type];
const double lj1 = B[7*type+1];
const double lj2 = B[7*type+2];
const double lj3 = B[7*type+3];
const double lj4 = B[7*type+4];
const double lj5 = B[7*type+5];
const double lj6 = B[7*type+6];
const FFT_SCALAR z0 = delvolinv_6;
for (int n = nlower_6; n <= nupper_6; ++n) {
const int jn = (nz+n-nzlo_out_6)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower_6; m <= nupper_6; ++m) {
const int jm = jn+(ny+m-nylo_out_6)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower_6; l <= nupper_6; ++l) {
const int jl = jm+nx+l-nxlo_out_6;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
const double w = x0*r1d[0][l];
d0[jl] += w*lj0;
d1[jl] += w*lj1;
d2[jl] += w*lj2;
d3[jl] += w*lj3;
d4[jl] += w*lj4;
d5[jl] += w*lj5;
d6[jl] += w*lj6;
}
}
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ik
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_c_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
dbl3_t xM;
FFT_SCALAR x0,y0,z0,ekx,eky,ekz;
int i,ifrom,ito,tid,iH1,iH2,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (i = ifrom; i < ito; ++i) {
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else xM = x[i];
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz, order, rho_coeff);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick[mz][my][mx];
eky -= x0*vdy_brick[mz][my][mx];
ekz -= x0*vdz_brick[mz][my][mx];
}
}
}
// convert E-field to force
const double qfactor = qqrd2e * scale * q[i];
if (type[i] != typeO) {
f[i].x += qfactor*ekx;
f[i].y += qfactor*eky;
if (slabflag != 2) f[i].z += qfactor*ekz;
} else {
const double fx = qfactor * ekx;
const double fy = qfactor * eky;
const double fz = qfactor * ekz;
f[i].x += fx*(1 - alpha);
f[i].y += fy*(1 - alpha);
if (slabflag != 2) f[i].z += fz*(1 - alpha);
f[iH1].x += 0.5*alpha*fx;
f[iH1].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH1].z += 0.5*alpha*fz;
f[iH2].x += 0.5*alpha*fx;
f[iH2].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH2].z += 0.5*alpha*fz;
}
}
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ad
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_c_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
const double *prd = (triclinic == 0) ? domain->prd : domain->prd_lamda;
const double hx_inv = nx_pppm/prd[0];
const double hy_inv = ny_pppm/prd[1];
const double hz_inv = nz_pppm/prd[2];
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double s1,s2,s3,sf;
dbl3_t xM;
FFT_SCALAR ekx,eky,ekz;
int i,ifrom,ito,tid,iH1,iH2,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
FFT_SCALAR * const * const d1d = static_cast<FFT_SCALAR **>(thr->get_drho1d());
for (i = ifrom; i < ito; ++i) {
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else xM = x[i];
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz,order,rho_coeff);
compute_drho1d_thr(d1d,dx,dy,dz,order,drho_coeff);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
for (m = nlower; m <= nupper; m++) {
my = m+ny;
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
ekx += d1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
eky += r1d[0][l]*d1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*d1d[2][n]*u_brick[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force and substract self forces
const double qi = q[i];
const double qfactor = qqrd2e * scale * qi;
s1 = x[i].x*hx_inv;
sf = sf_coeff[0]*sin(MY_2PI*s1);
sf += sf_coeff[1]*sin(MY_4PI*s1);
sf *= 2.0*qi;
const double fx = qfactor*(ekx - sf);
s2 = x[i].y*hy_inv;
sf = sf_coeff[2]*sin(MY_2PI*s2);
sf += sf_coeff[3]*sin(MY_4PI*s2);
sf *= 2.0*qi;
const double fy = qfactor*(eky - sf);
s3 = x[i].z*hz_inv;
sf = sf_coeff[4]*sin(MY_2PI*s3);
sf += sf_coeff[5]*sin(MY_4PI*s3);
sf *= 2.0*qi;
const double fz = qfactor*(ekz - sf);
if (type[i] != typeO) {
f[i].x += fx;
f[i].y += fy;
if (slabflag != 2) f[i].z += fz;
} else {
f[i].x += fx*(1 - alpha);
f[i].y += fy*(1 - alpha);
if (slabflag != 2) f[i].z += fz*(1 - alpha);
f[iH1].x += 0.5*alpha*fx;
f[iH1].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH1].z += 0.5*alpha*fz;
f[iH2].x += 0.5*alpha*fx;
f[iH2].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH2].z += 0.5*alpha*fz;
}
}
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ik scheme and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_g_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx,eky,ekz;
int type;
double lj;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
ekx = eky = ekz = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick_g[mz][my][mx];
eky -= x0*vdy_brick_g[mz][my][mx];
ekz -= x0*vdz_brick_g[mz][my][mx];
}
}
}
// convert E-field to force
type = atom->type[i];
lj = B[type];
f[i][0] += lj*ekx;
f[i][1] += lj*eky;
f[i][2] += lj*ekz;
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ad scheme and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_g_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
const double hx_inv = nx_pppm_6/xprd;
const double hy_inv = ny_pppm_6/yprd;
const double hz_inv = nz_pppm_6/zprd_slab;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
FFT_SCALAR * const * const dr1d = static_cast<FFT_SCALAR **>(thr->get_drho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz;
FFT_SCALAR ekx,eky,ekz;
int type;
double lj;
double sf = 0.0;
double s1,s2,s3;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
compute_drho1d_thr(dr1d,dx,dy,dz, order_6, drho_coeff_6);
ekx = eky = ekz = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
ekx += dr1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick_g[mz][my][mx];
eky += r1d[0][l]*dr1d[1][m]*r1d[2][n]*u_brick_g[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*dr1d[2][n]*u_brick_g[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force
type = atom->type[i];
lj = B[type];
s1 = x[i][0]*hx_inv;
s2 = x[i][1]*hy_inv;
s3 = x[i][2]*hz_inv;
sf = sf_coeff_6[0]*sin(2*MY_PI*s1);
sf += sf_coeff_6[1]*sin(4*MY_PI*s1);
sf *= 2*lj*lj;
f[i][0] += ekx*lj - sf;
sf = sf_coeff_6[2]*sin(2*MY_PI*s2);
sf += sf_coeff_6[3]*sin(4*MY_PI*s2);
sf *= 2*lj*lj;
f[i][1] += eky*lj - sf;
sf = sf_coeff_6[4]*sin(2*MY_PI*s3);
sf += sf_coeff_6[5]*sin(4*MY_PI*s3);
sf *= 2*lj*lj;
if (slabflag != 2) f[i][2] += ekz*lj - sf;
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial for dispersion
interaction and geometric mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_g_peratom()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const double * const * const x = atom->x;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u,v0,v1,v2,v3,v4,v5;
int type;
double lj;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) u += x0*u_brick_g[mz][my][mx];
if (vflag_atom) {
v0 += x0*v0_brick_g[mz][my][mx];
v1 += x0*v1_brick_g[mz][my][mx];
v2 += x0*v2_brick_g[mz][my][mx];
v3 += x0*v3_brick_g[mz][my][mx];
v4 += x0*v4_brick_g[mz][my][mx];
v5 += x0*v5_brick_g[mz][my][mx];
}
}
}
}
type = atom->type[i];
lj = B[type]*0.5;
if (eflag_atom) eatom[i] += u*lj;
if (vflag_atom) {
vatom[i][0] += v0*lj;
vatom[i][1] += v1*lj;
vatom[i][2] += v2*lj;
vatom[i][3] += v3*lj;
vatom[i][4] += v4*lj;
vatom[i][5] += v5*lj;
}
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ik scheme and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_a_ik()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx0, eky0, ekz0, ekx1, eky1, ekz1, ekx2, eky2, ekz2;
FFT_SCALAR ekx3, eky3, ekz3, ekx4, eky4, ekz4, ekx5, eky5, ekz5;
FFT_SCALAR ekx6, eky6, ekz6;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
ekx0 = eky0 = ekz0 = ZEROF;
ekx1 = eky1 = ekz1 = ZEROF;
ekx2 = eky2 = ekz2 = ZEROF;
ekx3 = eky3 = ekz3 = ZEROF;
ekx4 = eky4 = ekz4 = ZEROF;
ekx5 = eky5 = ekz5 = ZEROF;
ekx6 = eky6 = ekz6 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx0 -= x0*vdx_brick_a0[mz][my][mx];
eky0 -= x0*vdy_brick_a0[mz][my][mx];
ekz0 -= x0*vdz_brick_a0[mz][my][mx];
ekx1 -= x0*vdx_brick_a1[mz][my][mx];
eky1 -= x0*vdy_brick_a1[mz][my][mx];
ekz1 -= x0*vdz_brick_a1[mz][my][mx];
ekx2 -= x0*vdx_brick_a2[mz][my][mx];
eky2 -= x0*vdy_brick_a2[mz][my][mx];
ekz2 -= x0*vdz_brick_a2[mz][my][mx];
ekx3 -= x0*vdx_brick_a3[mz][my][mx];
eky3 -= x0*vdy_brick_a3[mz][my][mx];
ekz3 -= x0*vdz_brick_a3[mz][my][mx];
ekx4 -= x0*vdx_brick_a4[mz][my][mx];
eky4 -= x0*vdy_brick_a4[mz][my][mx];
ekz4 -= x0*vdz_brick_a4[mz][my][mx];
ekx5 -= x0*vdx_brick_a5[mz][my][mx];
eky5 -= x0*vdy_brick_a5[mz][my][mx];
ekz5 -= x0*vdz_brick_a5[mz][my][mx];
ekx6 -= x0*vdx_brick_a6[mz][my][mx];
eky6 -= x0*vdy_brick_a6[mz][my][mx];
ekz6 -= x0*vdz_brick_a6[mz][my][mx];
}
}
}
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6];
lj1 = B[7*type+5];
lj2 = B[7*type+4];
lj3 = B[7*type+3];
lj4 = B[7*type+2];
lj5 = B[7*type+1];
lj6 = B[7*type];
f[i][0] += lj0*ekx0 + lj1*ekx1 + lj2*ekx2 + lj3*ekx3 + lj4*ekx4 + lj5*ekx5 + lj6*ekx6;
f[i][1] += lj0*eky0 + lj1*eky1 + lj2*eky2 + lj3*eky3 + lj4*eky4 + lj5*eky5 + lj6*eky6;
f[i][2] += lj0*ekz0 + lj1*ekz1 + lj2*ekz2 + lj3*ekz3 + lj4*ekz4 + lj5*ekz5 + lj6*ekz6;
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get dispersion field & force on my particles
for ad scheme and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_a_ad()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const double * const * const x = atom->x;
double *prd;
if (triclinic == 0) prd = domain->prd;
else prd = domain->prd_lamda;
double xprd = prd[0];
double yprd = prd[1];
double zprd = prd[2];
double zprd_slab = zprd*slab_volfactor;
const double hx_inv = nx_pppm_6/xprd;
const double hy_inv = ny_pppm_6/yprd;
const double hz_inv = nz_pppm_6/zprd_slab;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
double * const * const f = thr->get_f();
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
FFT_SCALAR * const * const dr1d = static_cast<FFT_SCALAR **>(thr->get_drho1d_6());
int l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR ekx0, eky0, ekz0, ekx1, eky1, ekz1, ekx2, eky2, ekz2;
FFT_SCALAR ekx3, eky3, ekz3, ekx4, eky4, ekz4, ekx5, eky5, ekz5;
FFT_SCALAR ekx6, eky6, ekz6;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
double sf = 0.0;
double s1,s2,s3;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (int i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
compute_drho1d_thr(dr1d,dx,dy,dz, order_6, drho_coeff_6);
ekx0 = eky0 = ekz0 = ZEROF;
ekx1 = eky1 = ekz1 = ZEROF;
ekx2 = eky2 = ekz2 = ZEROF;
ekx3 = eky3 = ekz3 = ZEROF;
ekx4 = eky4 = ekz4 = ZEROF;
ekx5 = eky5 = ekz5 = ZEROF;
ekx6 = eky6 = ekz6 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = dr1d[0][l]*r1d[1][m]*r1d[2][n];
y0 = r1d[0][l]*dr1d[1][m]*r1d[2][n];
z0 = r1d[0][l]*r1d[1][m]*dr1d[2][n];
ekx0 += x0*u_brick_a0[mz][my][mx];
eky0 += y0*u_brick_a0[mz][my][mx];
ekz0 += z0*u_brick_a0[mz][my][mx];
ekx1 += x0*u_brick_a1[mz][my][mx];
eky1 += y0*u_brick_a1[mz][my][mx];
ekz1 += z0*u_brick_a1[mz][my][mx];
ekx2 += x0*u_brick_a2[mz][my][mx];
eky2 += y0*u_brick_a2[mz][my][mx];
ekz2 += z0*u_brick_a2[mz][my][mx];
ekx3 += x0*u_brick_a3[mz][my][mx];
eky3 += y0*u_brick_a3[mz][my][mx];
ekz3 += z0*u_brick_a3[mz][my][mx];
ekx4 += x0*u_brick_a4[mz][my][mx];
eky4 += y0*u_brick_a4[mz][my][mx];
ekz4 += z0*u_brick_a4[mz][my][mx];
ekx5 += x0*u_brick_a5[mz][my][mx];
eky5 += y0*u_brick_a5[mz][my][mx];
ekz5 += z0*u_brick_a5[mz][my][mx];
ekx6 += x0*u_brick_a6[mz][my][mx];
eky6 += y0*u_brick_a6[mz][my][mx];
ekz6 += z0*u_brick_a6[mz][my][mx];
}
}
}
ekx0 *= hx_inv;
eky0 *= hy_inv;
ekz0 *= hz_inv;
ekx1 *= hx_inv;
eky1 *= hy_inv;
ekz1 *= hz_inv;
ekx2 *= hx_inv;
eky2 *= hy_inv;
ekz2 *= hz_inv;
ekx3 *= hx_inv;
eky3 *= hy_inv;
ekz3 *= hz_inv;
ekx4 *= hx_inv;
eky4 *= hy_inv;
ekz4 *= hz_inv;
ekx5 *= hx_inv;
eky5 *= hy_inv;
ekz5 *= hz_inv;
ekx6 *= hx_inv;
eky6 *= hy_inv;
ekz6 *= hz_inv;
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6];
lj1 = B[7*type+5];
lj2 = B[7*type+4];
lj3 = B[7*type+3];
lj4 = B[7*type+2];
lj5 = B[7*type+1];
lj6 = B[7*type];
s1 = x[i][0]*hx_inv;
s2 = x[i][1]*hy_inv;
s3 = x[i][2]*hz_inv;
sf = sf_coeff_6[0]*sin(2*MY_PI*s1);
sf += sf_coeff_6[1]*sin(4*MY_PI*s1);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
f[i][0] += lj0*ekx0 + lj1*ekx1 + lj2*ekx2 + lj3*ekx3 + lj4*ekx4 + lj5*ekx5 + lj6*ekx6 - sf;
sf = sf_coeff_6[2]*sin(2*MY_PI*s2);
sf += sf_coeff_6[3]*sin(4*MY_PI*s2);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
f[i][1] += lj0*eky0 + lj1*eky1 + lj2*eky2 + lj3*eky3 + lj4*eky4 + lj5*eky5 + lj6*eky6 - sf;
sf = sf_coeff_6[4]*sin(2*MY_PI*s3);
sf += sf_coeff_6[5]*sin(4*MY_PI*s3);
sf *= 4*lj0*lj6 + 4*lj1*lj5 + 4*lj2*lj4 + 2*lj3*lj3;
if (slabflag != 2) f[i][2] += lj0*ekz0 + lj1*ekz1 + lj2*ekz2 + lj3*ekz3 + lj4*ekz4 + lj5*ekz5 + lj6*ekz6 - sf;
}
}
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial for dispersion
interaction and arithmetic mixing rule
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::fieldforce_a_peratom()
{
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const double * const * const x = atom->x;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
// each thread works on a fixed chunk of atoms.
const int tid = omp_get_thread_num();
const int inum = nlocal;
const int idelta = 1 + inum/comm->nthreads;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > inum) ? inum : ifrom + idelta;
#else
const int ifrom = 0;
const int ito = nlocal;
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d_6());
int i,l,m,n,nx,ny,nz,mx,my,mz;
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u0,v00,v10,v20,v30,v40,v50;
FFT_SCALAR u1,v01,v11,v21,v31,v41,v51;
FFT_SCALAR u2,v02,v12,v22,v32,v42,v52;
FFT_SCALAR u3,v03,v13,v23,v33,v43,v53;
FFT_SCALAR u4,v04,v14,v24,v34,v44,v54;
FFT_SCALAR u5,v05,v15,v25,v35,v45,v55;
FFT_SCALAR u6,v06,v16,v26,v36,v46,v56;
int type;
double lj0,lj1,lj2,lj3,lj4,lj5,lj6;
// this if protects against having more threads than local atoms
if (ifrom < nlocal) {
for (i = ifrom; i < ito; i++) {
nx = part2grid_6[i][0];
ny = part2grid_6[i][1];
nz = part2grid_6[i][2];
dx = nx+shiftone_6 - (x[i][0]-boxlo[0])*delxinv_6;
dy = ny+shiftone_6 - (x[i][1]-boxlo[1])*delyinv_6;
dz = nz+shiftone_6 - (x[i][2]-boxlo[2])*delzinv_6;
compute_rho1d_thr(r1d,dx,dy,dz, order_6, rho_coeff_6);
u0 = v00 = v10 = v20 = v30 = v40 = v50 = ZEROF;
u1 = v01 = v11 = v21 = v31 = v41 = v51 = ZEROF;
u2 = v02 = v12 = v22 = v32 = v42 = v52 = ZEROF;
u3 = v03 = v13 = v23 = v33 = v43 = v53 = ZEROF;
u4 = v04 = v14 = v24 = v34 = v44 = v54 = ZEROF;
u5 = v05 = v15 = v25 = v35 = v45 = v55 = ZEROF;
u6 = v06 = v16 = v26 = v36 = v46 = v56 = ZEROF;
for (n = nlower_6; n <= nupper_6; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower_6; m <= nupper_6; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower_6; l <= nupper_6; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) {
u0 += x0*u_brick_a0[mz][my][mx];
u1 += x0*u_brick_a1[mz][my][mx];
u2 += x0*u_brick_a2[mz][my][mx];
u3 += x0*u_brick_a3[mz][my][mx];
u4 += x0*u_brick_a4[mz][my][mx];
u5 += x0*u_brick_a5[mz][my][mx];
u6 += x0*u_brick_a6[mz][my][mx];
}
if (vflag_atom) {
v00 += x0*v0_brick_a0[mz][my][mx];
v10 += x0*v1_brick_a0[mz][my][mx];
v20 += x0*v2_brick_a0[mz][my][mx];
v30 += x0*v3_brick_a0[mz][my][mx];
v40 += x0*v4_brick_a0[mz][my][mx];
v50 += x0*v5_brick_a0[mz][my][mx];
v01 += x0*v0_brick_a1[mz][my][mx];
v11 += x0*v1_brick_a1[mz][my][mx];
v21 += x0*v2_brick_a1[mz][my][mx];
v31 += x0*v3_brick_a1[mz][my][mx];
v41 += x0*v4_brick_a1[mz][my][mx];
v51 += x0*v5_brick_a1[mz][my][mx];
v02 += x0*v0_brick_a2[mz][my][mx];
v12 += x0*v1_brick_a2[mz][my][mx];
v22 += x0*v2_brick_a2[mz][my][mx];
v32 += x0*v3_brick_a2[mz][my][mx];
v42 += x0*v4_brick_a2[mz][my][mx];
v52 += x0*v5_brick_a2[mz][my][mx];
v03 += x0*v0_brick_a3[mz][my][mx];
v13 += x0*v1_brick_a3[mz][my][mx];
v23 += x0*v2_brick_a3[mz][my][mx];
v33 += x0*v3_brick_a3[mz][my][mx];
v43 += x0*v4_brick_a3[mz][my][mx];
v53 += x0*v5_brick_a3[mz][my][mx];
v04 += x0*v0_brick_a4[mz][my][mx];
v14 += x0*v1_brick_a4[mz][my][mx];
v24 += x0*v2_brick_a4[mz][my][mx];
v34 += x0*v3_brick_a4[mz][my][mx];
v44 += x0*v4_brick_a4[mz][my][mx];
v54 += x0*v5_brick_a4[mz][my][mx];
v05 += x0*v0_brick_a5[mz][my][mx];
v15 += x0*v1_brick_a5[mz][my][mx];
v25 += x0*v2_brick_a5[mz][my][mx];
v35 += x0*v3_brick_a5[mz][my][mx];
v45 += x0*v4_brick_a5[mz][my][mx];
v55 += x0*v5_brick_a5[mz][my][mx];
v06 += x0*v0_brick_a6[mz][my][mx];
v16 += x0*v1_brick_a6[mz][my][mx];
v26 += x0*v2_brick_a6[mz][my][mx];
v36 += x0*v3_brick_a6[mz][my][mx];
v46 += x0*v4_brick_a6[mz][my][mx];
v56 += x0*v5_brick_a6[mz][my][mx];
}
}
}
}
// convert D-field to force
type = atom->type[i];
lj0 = B[7*type+6]*0.5;
lj1 = B[7*type+5]*0.5;
lj2 = B[7*type+4]*0.5;
lj3 = B[7*type+3]*0.5;
lj4 = B[7*type+2]*0.5;
lj5 = B[7*type+1]*0.5;
lj6 = B[7*type]*0.5;
if (eflag_atom)
eatom[i] += u0*lj0 + u1*lj1 + u2*lj2 +
u3*lj3 + u4*lj4 + u5*lj5 + u6*lj6;
if (vflag_atom) {
vatom[i][0] += v00*lj0 + v01*lj1 + v02*lj2 + v03*lj3 +
v04*lj4 + v05*lj5 + v06*lj6;
vatom[i][1] += v10*lj0 + v11*lj1 + v12*lj2 + v13*lj3 +
v14*lj4 + v15*lj5 + v16*lj6;
vatom[i][2] += v20*lj0 + v21*lj1 + v22*lj2 + v23*lj3 +
v24*lj4 + v25*lj5 + v26*lj6;
vatom[i][3] += v30*lj0 + v31*lj1 + v32*lj2 + v33*lj3 +
v34*lj4 + v35*lj5 + v36*lj6;
vatom[i][4] += v40*lj0 + v41*lj1 + v42*lj2 + v43*lj3 +
v44*lj4 + v45*lj5 + v46*lj6;
vatom[i][5] += v50*lj0 + v51*lj1 + v52*lj2 + v53*lj3 +
v54*lj4 + v55*lj5 + v56*lj6;
}
}
}
}
}
/* ----------------------------------------------------------------------
charge assignment into rho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::compute_rho1d_thr(FFT_SCALAR * const * const r1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz,
const int ord, FFT_SCALAR * const * const rho_c)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-ord)/2; k <= ord/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = ord-1; l >= 0; l--) {
r1 = rho_c[l][k] + r1*dx;
r2 = rho_c[l][k] + r2*dy;
r3 = rho_c[l][k] + r3*dz;
}
r1d[0][k] = r1;
r1d[1][k] = r2;
r1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
charge assignment into drho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::compute_drho1d_thr(FFT_SCALAR * const * const dr1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz,
const int ord, FFT_SCALAR * const * const drho_c)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-ord)/2; k <= ord/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = ord-2; l >= 0; l--) {
r1 = drho_c[l][k] + r1*dx;
r2 = drho_c[l][k] + r2*dy;
r3 = drho_c[l][k] + r3*dz;
}
dr1d[0][k] = r1;
dr1d[1][k] = r2;
dr1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
find 2 H atoms bonded to O atom i
compute position xM of fictitious charge site for O atom
also return local indices iH1,iH2 of H atoms
------------------------------------------------------------------------- */
void PPPMDispTIP4POMP::find_M_thr(int i, int &iH1, int &iH2, dbl3_t &xM)
{
iH1 = atom->map(atom->tag[i] + 1);
iH2 = atom->map(atom->tag[i] + 2);
if (iH1 == -1 || iH2 == -1) error->one(FLERR,"TIP4P hydrogen is missing");
if (atom->type[iH1] != typeH || atom->type[iH2] != typeH)
error->one(FLERR,"TIP4P hydrogen has incorrect atom type");
// set iH1,iH2 to index of closest image to O
iH1 = domain->closest_image(i,iH1);
iH2 = domain->closest_image(i,iH2);
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
double delx1 = x[iH1].x - x[i].x;
double dely1 = x[iH1].y - x[i].y;
double delz1 = x[iH1].z - x[i].z;
double delx2 = x[iH2].x - x[i].x;
double dely2 = x[iH2].y - x[i].y;
double delz2 = x[iH2].z - x[i].z;
xM.x = x[i].x + alpha * 0.5 * (delx1 + delx2);
xM.y = x[i].y + alpha * 0.5 * (dely1 + dely2);
xM.z = x[i].z + alpha * 0.5 * (delz1 + delz2);
}
diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.h b/src/USER-OMP/pppm_disp_tip4p_omp.h
index e05a52ac8..296444366 100644
--- a/src/USER-OMP/pppm_disp_tip4p_omp.h
+++ b/src/USER-OMP/pppm_disp_tip4p_omp.h
@@ -1,84 +1,83 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef KSPACE_CLASS
KSpaceStyle(pppm/disp/tip4p/omp,PPPMDispTIP4POMP)
#else
#ifndef LMP_PPPM_DISP_TIP4P_OMP_H
#define LMP_PPPM_DISP_TIP4P_OMP_H
#include "pppm_disp_tip4p.h"
#include "thr_omp.h"
namespace LAMMPS_NS {
class PPPMDispTIP4POMP : public PPPMDispTIP4P, public ThrOMP {
public:
PPPMDispTIP4POMP(class LAMMPS *, int, char **);
- virtual ~PPPMDispTIP4POMP () {};
+ virtual ~PPPMDispTIP4POMP ();
protected:
virtual void allocate();
- virtual void deallocate();
virtual void compute_gf();
virtual void compute_gf_6();
virtual void compute(int,int);
virtual void particle_map(double, double, double,
double, int **, int, int,
int, int, int, int, int, int);
virtual void particle_map_c(double, double, double,
double, int **, int, int,
int, int, int, int, int, int);
virtual void make_rho_c(); // XXX: not (yet) multi-threaded
virtual void make_rho_g();
virtual void make_rho_a();
virtual void fieldforce_c_ik();
virtual void fieldforce_c_ad();
// virtual void fieldforce_peratom(); XXX: need to benchmark first.
virtual void fieldforce_g_ik();
virtual void fieldforce_g_ad();
virtual void fieldforce_g_peratom();
virtual void fieldforce_a_ik();
virtual void fieldforce_a_ad();
virtual void fieldforce_a_peratom();
private:
void compute_rho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &,
const int, FFT_SCALAR * const * const);
void compute_drho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &,
const int, FFT_SCALAR * const * const);
virtual void find_M_thr(int, int &, int &, dbl3_t &);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Kspace style pppm/tip4p/omp requires newton on
Self-explanatory.
*/
diff --git a/src/USER-OMP/pppm_omp.cpp b/src/USER-OMP/pppm_omp.cpp
index a62199be5..48b91e3a7 100644
--- a/src/USER-OMP/pppm_omp.cpp
+++ b/src/USER-OMP/pppm_omp.cpp
@@ -1,740 +1,738 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "pppm_omp.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_omp.h"
#include "force.h"
#include "memory.h"
#include "math_const.h"
#include "math_special.h"
#include <string.h>
#include <math.h>
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace MathSpecial;
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#else
#define ZEROF 0.0
#endif
#define EPS_HOC 1.0e-7
/* ---------------------------------------------------------------------- */
PPPMOMP::PPPMOMP(LAMMPS *lmp, int narg, char **arg) :
PPPM(lmp, narg, arg), ThrOMP(lmp, THR_KSPACE)
{
triclinic_support = 0;
suffix_flag |= Suffix::OMP;
}
/* ----------------------------------------------------------------------
allocate memory that depends on # of K-vectors and order
------------------------------------------------------------------------- */
void PPPMOMP::allocate()
{
PPPM::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->init_pppm(order,memory);
}
}
/* ----------------------------------------------------------------------
- free memory that depends on # of K-vectors and order
+ clean up per-thread allocations
------------------------------------------------------------------------- */
-void PPPMOMP::deallocate()
+PPPMOMP::~PPPMOMP()
{
- PPPM::deallocate();
-
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->init_pppm(-order,memory);
}
}
/* ----------------------------------------------------------------------
pre-compute modified (Hockney-Eastwood) Coulomb Green's function
------------------------------------------------------------------------- */
void PPPMOMP::compute_gf_ik()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int nbx = static_cast<int> ((g_ewald*xprd/(MY_PI*nx_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nby = static_cast<int> ((g_ewald*yprd/(MY_PI*ny_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nbz = static_cast<int> ((g_ewald*zprd_slab/(MY_PI*nz_pppm)) *
pow(-log(EPS_HOC),0.25));
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double snx,sny,snz;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double sum1,dot1,dot2;
double numerator,denominator;
double sqk;
int k,l,m,nx,ny,nz,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
snz = square(sin(0.5*unitkz*mper*zprd_slab/nz_pppm));
lper = l - ny_pppm*(2*l/ny_pppm);
sny = square(sin(0.5*unitky*lper*yprd/ny_pppm));
kper = k - nx_pppm*(2*k/nx_pppm);
snx = square(sin(0.5*unitkx*kper*xprd/nx_pppm));
sqk = square(unitkx*kper) + square(unitky*lper) + square(unitkz*mper);
if (sqk != 0.0) {
numerator = 12.5663706/sqk;
denominator = gf_denom(snx,sny,snz);
sum1 = 0.0;
for (nx = -nbx; nx <= nbx; nx++) {
qx = unitkx*(kper+nx_pppm*nx);
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
for (ny = -nby; ny <= nby; ny++) {
qy = unitky*(lper+ny_pppm*ny);
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
for (nz = -nbz; nz <= nbz; nz++) {
qz = unitkz*(mper+nz_pppm*nz);
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
dot1 = unitkx*kper*qx + unitky*lper*qy + unitkz*mper*qz;
dot2 = qx*qx+qy*qy+qz*qz;
sum1 += (dot1/dot2) * sx*sy*sz * wx*wy*wz;
}
}
}
greensfn[n] = numerator*sum1/denominator;
} else greensfn[n] = 0.0;
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
compute optimized Green's function for energy calculation
------------------------------------------------------------------------- */
void PPPMOMP::compute_gf_ad()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0;
#if defined(_OPENMP)
#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5)
#endif
{
double snx,sny,snz,sqk;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double numerator,denominator;
int k,l,m,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
qz = unitkz*mper;
snz = square(sin(0.5*qz*zprd_slab/nz_pppm));
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
lper = l - ny_pppm*(2*l/ny_pppm);
qy = unitky*lper;
sny = square(sin(0.5*qy*yprd/ny_pppm));
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
kper = k - nx_pppm*(2*k/nx_pppm);
qx = unitkx*kper;
snx = square(sin(0.5*qx*xprd/nx_pppm));
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
sqk = qx*qx + qy*qy + qz*qz;
if (sqk != 0.0) {
numerator = MY_4PI/sqk;
denominator = gf_denom(snx,sny,snz);
greensfn[n] = numerator*sx*sy*sz*wx*wy*wz/denominator;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
} else {
greensfn[n] = 0.0;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
}
}
thr->timer(Timer::KSPACE);
} // end of paralle region
// compute the coefficients for the self-force correction
double prex, prey, prez, tmp[6];
prex = prey = prez = MY_PI/volume;
prex *= nx_pppm/xprd;
prey *= ny_pppm/yprd;
prez *= nz_pppm/zprd_slab;
tmp[0] = sf0 * prex;
tmp[1] = sf1 * prex*2;
tmp[2] = sf2 * prey;
tmp[3] = sf3 * prey*2;
tmp[4] = sf4 * prez;
tmp[5] = sf5 * prez*2;
// communicate values with other procs
MPI_Allreduce(tmp,sf_coeff,6,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
run the regular toplevel compute method from plain PPPM
which will have individual methods replaced by our threaded
versions and then call the obligatory force reduction.
------------------------------------------------------------------------- */
void PPPMOMP::compute(int eflag, int vflag)
{
PPPM::compute(eflag,vflag);
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
/* ----------------------------------------------------------------------
create discretized "density" on section of global grid due to my particles
density(x,y,z) = charge "density" at grid points of my 3d brick
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
in global grid
------------------------------------------------------------------------- */
void PPPMOMP::make_rho()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick[nzlo_out][nylo_out][nxlo_out]);
memset(d,0,ngrid*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out - nxlo_out + 1;
const int iy = nyhi_out - nylo_out + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const double * _noalias const q = atom->q;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid;
loop_setup_thr(jfrom,jto,tid,ngrid,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower-nzlo_out)*ix*iy >= jto)
|| ((nz+nupper-nzlo_out+1)*ix*iy < jfrom) ) continue;
const FFT_SCALAR dx = nx+shiftone - (x[i].x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (x[i].y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (x[i].z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
const FFT_SCALAR z0 = delvolinv * q[i];
for (int n = nlower; n <= nupper; ++n) {
const int jn = (nz+n-nzlo_out)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower; m <= nupper; ++m) {
const int jm = jn+(ny+m-nylo_out)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower; l <= nupper; ++l) {
const int jl = jm+nx+l-nxlo_out;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
thr->timer(Timer::KSPACE);
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ik
------------------------------------------------------------------------- */
void PPPMOMP::fieldforce_ik()
{
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const int nthreads = comm->nthreads;
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
FFT_SCALAR x0,y0,z0,ekx,eky,ekz;
int i,ifrom,ito,tid,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (i = ifrom; i < ito; ++i) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (x[i].x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (x[i].y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (x[i].z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick[mz][my][mx];
eky -= x0*vdy_brick[mz][my][mx];
ekz -= x0*vdz_brick[mz][my][mx];
}
}
}
// convert E-field to force
const double qfactor = qqrd2e * scale * q[i];
f[i].x += qfactor*ekx;
f[i].y += qfactor*eky;
if (slabflag != 2) f[i].z += qfactor*ekz;
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ad
------------------------------------------------------------------------- */
void PPPMOMP::fieldforce_ad()
{
const int nthreads = comm->nthreads;
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
const double *prd = (triclinic == 0) ? domain->prd : domain->prd_lamda;
const double hx_inv = nx_pppm/prd[0];
const double hy_inv = ny_pppm/prd[1];
const double hz_inv = nz_pppm/prd[2];
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double s1,s2,s3,sf;
FFT_SCALAR ekx,eky,ekz;
int i,ifrom,ito,tid,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
FFT_SCALAR * const * const d1d = static_cast<FFT_SCALAR **>(thr->get_drho1d());
for (i = ifrom; i < ito; ++i) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (x[i].x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (x[i].y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (x[i].z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
compute_drho1d_thr(d1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
for (m = nlower; m <= nupper; m++) {
my = m+ny;
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
ekx += d1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
eky += r1d[0][l]*d1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*d1d[2][n]*u_brick[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force and substract self forces
const double qi = q[i];
const double qfactor = qqrd2e * scale * qi;
s1 = x[i].x*hx_inv;
sf = sf_coeff[0]*sin(MY_2PI*s1);
sf += sf_coeff[1]*sin(MY_4PI*s1);
sf *= 2.0*qi;
f[i].x += qfactor*(ekx - sf);
s2 = x[i].y*hy_inv;
sf = sf_coeff[2]*sin(MY_2PI*s2);
sf += sf_coeff[3]*sin(MY_4PI*s2);
sf *= 2.0*qi;
f[i].y += qfactor*(eky - sf);
s3 = x[i].z*hz_inv;
sf = sf_coeff[4]*sin(MY_2PI*s3);
sf += sf_coeff[5]*sin(MY_4PI*s3);
sf *= 2.0*qi;
if (slabflag != 2) f[i].z += qfactor*(ekz - sf);
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get per-atom energy/virial
------------------------------------------------------------------------- */
void PPPMOMP::fieldforce_peratom()
{
const int nthreads = comm->nthreads;
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
FFT_SCALAR dx,dy,dz,x0,y0,z0;
FFT_SCALAR u,v0,v1,v2,v3,v4,v5;
int i,ifrom,ito,tid,l,m,n,nx,ny,nz,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (i = ifrom; i < ito; ++i) {
nx = part2grid[i][0];
ny = part2grid[i][1];
nz = part2grid[i][2];
dx = nx+shiftone - (x[i].x-boxlo[0])*delxinv;
dy = ny+shiftone - (x[i].y-boxlo[1])*delyinv;
dz = nz+shiftone - (x[i].z-boxlo[2])*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
if (eflag_atom) u += x0*u_brick[mz][my][mx];
if (vflag_atom) {
v0 += x0*v0_brick[mz][my][mx];
v1 += x0*v1_brick[mz][my][mx];
v2 += x0*v2_brick[mz][my][mx];
v3 += x0*v3_brick[mz][my][mx];
v4 += x0*v4_brick[mz][my][mx];
v5 += x0*v5_brick[mz][my][mx];
}
}
}
}
const double qi = q[i];
if (eflag_atom) eatom[i] += qi*u;
if (vflag_atom) {
vatom[i][0] += qi*v0;
vatom[i][1] += qi*v1;
vatom[i][2] += qi*v2;
vatom[i][3] += qi*v3;
vatom[i][4] += qi*v4;
vatom[i][5] += qi*v5;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
charge assignment into rho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMOMP::compute_rho1d_thr(FFT_SCALAR * const * const r1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-1; l >= 0; l--) {
r1 = rho_coeff[l][k] + r1*dx;
r2 = rho_coeff[l][k] + r2*dy;
r3 = rho_coeff[l][k] + r3*dz;
}
r1d[0][k] = r1;
r1d[1][k] = r2;
r1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
charge assignment into drho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMOMP::compute_drho1d_thr(FFT_SCALAR * const * const d1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-2; l >= 0; l--) {
r1 = drho_coeff[l][k] + r1*dx;
r2 = drho_coeff[l][k] + r2*dy;
r3 = drho_coeff[l][k] + r3*dz;
}
d1d[0][k] = r1;
d1d[1][k] = r2;
d1d[2][k] = r3;
}
}
diff --git a/src/USER-OMP/pppm_omp.h b/src/USER-OMP/pppm_omp.h
index 03eb0e110..bf8a9e0c2 100644
--- a/src/USER-OMP/pppm_omp.h
+++ b/src/USER-OMP/pppm_omp.h
@@ -1,58 +1,57 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef KSPACE_CLASS
KSpaceStyle(pppm/omp,PPPMOMP)
#else
#ifndef LMP_PPPM_OMP_H
#define LMP_PPPM_OMP_H
#include "pppm.h"
#include "thr_omp.h"
namespace LAMMPS_NS {
class PPPMOMP : public PPPM, public ThrOMP {
public:
PPPMOMP(class LAMMPS *, int, char **);
- virtual ~PPPMOMP () {};
+ virtual ~PPPMOMP ();
virtual void compute(int, int);
protected:
virtual void allocate();
- virtual void deallocate();
virtual void compute_gf_ik();
virtual void compute_gf_ad();
virtual void make_rho();
virtual void fieldforce_ik();
virtual void fieldforce_ad();
virtual void fieldforce_peratom();
private:
void compute_rho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
void compute_drho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
// void slabcorr(int);
};
}
#endif
#endif
diff --git a/src/USER-OMP/pppm_tip4p_omp.cpp b/src/USER-OMP/pppm_tip4p_omp.cpp
index 21e3081c6..1eab140ce 100644
--- a/src/USER-OMP/pppm_tip4p_omp.cpp
+++ b/src/USER-OMP/pppm_tip4p_omp.cpp
@@ -1,893 +1,891 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "pppm_tip4p_omp.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "fix_omp.h"
#include "force.h"
#include "memory.h"
#include "math_const.h"
#include "math_special.h"
#include <string.h>
#include <math.h>
#include "suffix.h"
using namespace LAMMPS_NS;
using namespace MathConst;
using namespace MathSpecial;
#ifdef FFT_SINGLE
#define ZEROF 0.0f
#else
#define ZEROF 0.0
#endif
#define EPS_HOC 1.0e-7
#define OFFSET 16384
/* ---------------------------------------------------------------------- */
PPPMTIP4POMP::PPPMTIP4POMP(LAMMPS *lmp, int narg, char **arg) :
PPPMTIP4P(lmp, narg, arg), ThrOMP(lmp, THR_KSPACE)
{
triclinic_support = 1;
suffix_flag |= Suffix::OMP;
}
/* ----------------------------------------------------------------------
- allocate memory that depends on # of K-vectors and order
+ clean up per-thread allocations
------------------------------------------------------------------------- */
-void PPPMTIP4POMP::allocate()
+PPPMTIP4POMP::~PPPMTIP4POMP()
{
- PPPMTIP4P::allocate();
-
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(order,memory);
+ thr->init_pppm(-order,memory);
}
}
/* ----------------------------------------------------------------------
- free memory that depends on # of K-vectors and order
+ allocate memory that depends on # of K-vectors and order
------------------------------------------------------------------------- */
-void PPPMTIP4POMP::deallocate()
+void PPPMTIP4POMP::allocate()
{
- PPPMTIP4P::deallocate();
+ PPPMTIP4P::allocate();
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
- thr->init_pppm(-order,memory);
+ thr->init_pppm(order,memory);
}
}
/* ----------------------------------------------------------------------
pre-compute modified (Hockney-Eastwood) Coulomb Green's function
------------------------------------------------------------------------- */
void PPPMTIP4POMP::compute_gf_ik()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int nbx = static_cast<int> ((g_ewald*xprd/(MY_PI*nx_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nby = static_cast<int> ((g_ewald*yprd/(MY_PI*ny_pppm)) *
pow(-log(EPS_HOC),0.25));
const int nbz = static_cast<int> ((g_ewald*zprd_slab/(MY_PI*nz_pppm)) *
pow(-log(EPS_HOC),0.25));
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double snx,sny,snz;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double sum1,dot1,dot2;
double numerator,denominator;
double sqk;
int k,l,m,nx,ny,nz,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
snz = square(sin(0.5*unitkz*mper*zprd_slab/nz_pppm));
lper = l - ny_pppm*(2*l/ny_pppm);
sny = square(sin(0.5*unitky*lper*yprd/ny_pppm));
kper = k - nx_pppm*(2*k/nx_pppm);
snx = square(sin(0.5*unitkx*kper*xprd/nx_pppm));
sqk = square(unitkx*kper) + square(unitky*lper) + square(unitkz*mper);
if (sqk != 0.0) {
numerator = 12.5663706/sqk;
denominator = gf_denom(snx,sny,snz);
sum1 = 0.0;
for (nx = -nbx; nx <= nbx; nx++) {
qx = unitkx*(kper+nx_pppm*nx);
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
for (ny = -nby; ny <= nby; ny++) {
qy = unitky*(lper+ny_pppm*ny);
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
for (nz = -nbz; nz <= nbz; nz++) {
qz = unitkz*(mper+nz_pppm*nz);
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
dot1 = unitkx*kper*qx + unitky*lper*qy + unitkz*mper*qz;
dot2 = qx*qx+qy*qy+qz*qz;
sum1 += (dot1/dot2) * sx*sy*sz * wx*wy*wz;
}
}
}
greensfn[n] = numerator*sum1/denominator;
} else greensfn[n] = 0.0;
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
compute optimized Green's function for energy calculation
------------------------------------------------------------------------- */
void PPPMTIP4POMP::compute_gf_ad()
{
const double * const prd = (triclinic==0) ? domain->prd : domain->prd_lamda;
const double xprd = prd[0];
const double yprd = prd[1];
const double zprd = prd[2];
const double zprd_slab = zprd*slab_volfactor;
const double unitkx = (MY_2PI/xprd);
const double unitky = (MY_2PI/yprd);
const double unitkz = (MY_2PI/zprd_slab);
const int numk = nxhi_fft - nxlo_fft + 1;
const int numl = nyhi_fft - nylo_fft + 1;
const int twoorder = 2*order;
double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0;
#if defined(_OPENMP)
#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5)
#endif
{
double snx,sny,snz,sqk;
double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz;
double numerator,denominator;
int k,l,m,kper,lper,mper,n,nfrom,nto,tid;
loop_setup_thr(nfrom, nto, tid, nfft, comm->nthreads);
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
for (n = nfrom; n < nto; ++n) {
m = n / (numl*numk);
l = (n - m*numl*numk) / numk;
k = n - m*numl*numk - l*numk;
m += nzlo_fft;
l += nylo_fft;
k += nxlo_fft;
mper = m - nz_pppm*(2*m/nz_pppm);
qz = unitkz*mper;
snz = square(sin(0.5*qz*zprd_slab/nz_pppm));
sz = exp(-0.25*square(qz/g_ewald));
argz = 0.5*qz*zprd_slab/nz_pppm;
wz = powsinxx(argz,twoorder);
lper = l - ny_pppm*(2*l/ny_pppm);
qy = unitky*lper;
sny = square(sin(0.5*qy*yprd/ny_pppm));
sy = exp(-0.25*square(qy/g_ewald));
argy = 0.5*qy*yprd/ny_pppm;
wy = powsinxx(argy,twoorder);
kper = k - nx_pppm*(2*k/nx_pppm);
qx = unitkx*kper;
snx = square(sin(0.5*qx*xprd/nx_pppm));
sx = exp(-0.25*square(qx/g_ewald));
argx = 0.5*qx*xprd/nx_pppm;
wx = powsinxx(argx,twoorder);
sqk = qx*qx + qy*qy + qz*qz;
if (sqk != 0.0) {
numerator = MY_4PI/sqk;
denominator = gf_denom(snx,sny,snz);
greensfn[n] = numerator*sx*sy*sz*wx*wy*wz/denominator;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
} else {
greensfn[n] = 0.0;
sf0 += sf_precoeff1[n]*greensfn[n];
sf1 += sf_precoeff2[n]*greensfn[n];
sf2 += sf_precoeff3[n]*greensfn[n];
sf3 += sf_precoeff4[n]*greensfn[n];
sf4 += sf_precoeff5[n]*greensfn[n];
sf5 += sf_precoeff6[n]*greensfn[n];
}
}
thr->timer(Timer::KSPACE);
} // end of paralle region
// compute the coefficients for the self-force correction
double prex, prey, prez, tmp[6];
prex = prey = prez = MY_PI/volume;
prex *= nx_pppm/xprd;
prey *= ny_pppm/yprd;
prez *= nz_pppm/zprd_slab;
tmp[0] = sf0 * prex;
tmp[1] = sf1 * prex*2;
tmp[2] = sf2 * prey;
tmp[3] = sf3 * prey*2;
tmp[4] = sf4 * prez;
tmp[5] = sf5 * prez*2;
// communicate values with other procs
MPI_Allreduce(tmp,sf_coeff,6,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
run the regular toplevel compute method from plain PPPM
which will have individual methods replaced by our threaded
versions and then call the obligatory force reduction.
------------------------------------------------------------------------- */
void PPPMTIP4POMP::compute(int eflag, int vflag)
{
PPPMTIP4P::compute(eflag,vflag);
#if defined(_OPENMP)
#pragma omp parallel default(none) shared(eflag,vflag)
#endif
{
#if defined(_OPENMP)
const int tid = omp_get_thread_num();
#else
const int tid = 0;
#endif
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
reduce_thr(this, eflag, vflag, thr);
} // end of omp parallel region
}
/* ----------------------------------------------------------------------
find center grid pt for each of my particles
check that full stencil for the particle will fit in my 3d brick
store central grid pt indices in part2grid array
------------------------------------------------------------------------- */
void PPPMTIP4POMP::particle_map()
{
// no local atoms => nothing to do
if (atom->nlocal == 0) return;
const int * _noalias const type = atom->type;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
const int nlocal = atom->nlocal;
if (!ISFINITE(boxlo[0]) || !ISFINITE(boxlo[1]) || !ISFINITE(boxlo[2]))
error->one(FLERR,"Non-numeric box dimensions - simulation unstable");
int i, flag = 0;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) reduction(+:flag) schedule(static)
#endif
for (i = 0; i < nlocal; i++) {
dbl3_t xM;
int iH1,iH2;
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else {
xM = x[i];
}
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// current particle coord can be outside global and local box
// add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1
const int nx = static_cast<int> ((xM.x-boxlox)*delxinv+shift) - OFFSET;
const int ny = static_cast<int> ((xM.y-boxloy)*delyinv+shift) - OFFSET;
const int nz = static_cast<int> ((xM.z-boxloz)*delzinv+shift) - OFFSET;
p2g[i].a = nx;
p2g[i].b = ny;
p2g[i].t = nz;
// check that entire stencil around nx,ny,nz will fit in my 3d brick
if (nx+nlower < nxlo_out || nx+nupper > nxhi_out ||
ny+nlower < nylo_out || ny+nupper > nyhi_out ||
nz+nlower < nzlo_out || nz+nupper > nzhi_out)
flag++;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Out of range atoms - cannot compute PPPM");
}
/* ----------------------------------------------------------------------
create discretized "density" on section of global grid due to my particles
density(x,y,z) = charge "density" at grid points of my 3d brick
(nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts)
in global grid
------------------------------------------------------------------------- */
void PPPMTIP4POMP::make_rho()
{
// clear 3d density array
FFT_SCALAR * _noalias const d = &(density_brick[nzlo_out][nylo_out][nxlo_out]);
memset(d,0,ngrid*sizeof(FFT_SCALAR));
// no local atoms => nothing else to do
const int nlocal = atom->nlocal;
if (nlocal == 0) return;
const int ix = nxhi_out - nxlo_out + 1;
const int iy = nyhi_out - nylo_out + 1;
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
const double * _noalias const q = atom->q;
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
dbl3_t xM;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
// determine range of grid points handled by this thread
int i,jfrom,jto,tid,iH1,iH2;
loop_setup_thr(jfrom,jto,tid,ngrid,comm->nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
// loop over my charges, add their contribution to nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// loop over all local atoms for all threads
for (i = 0; i < nlocal; i++) {
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
// pre-screen whether this atom will ever come within
// reach of the data segement this thread is updating.
if ( ((nz+nlower-nzlo_out)*ix*iy >= jto)
|| ((nz+nupper-nzlo_out+1)*ix*iy < jfrom) ) continue;
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else {
xM = x[i];
}
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
const FFT_SCALAR z0 = delvolinv * q[i];
for (int n = nlower; n <= nupper; ++n) {
const int jn = (nz+n-nzlo_out)*ix*iy;
const FFT_SCALAR y0 = z0*r1d[2][n];
for (int m = nlower; m <= nupper; ++m) {
const int jm = jn+(ny+m-nylo_out)*ix;
const FFT_SCALAR x0 = y0*r1d[1][m];
for (int l = nlower; l <= nupper; ++l) {
const int jl = jm+nx+l-nxlo_out;
// make sure each thread only updates
// "his" elements of the density grid
if (jl >= jto) break;
if (jl < jfrom) continue;
d[jl] += x0*r1d[0][l];
}
}
}
}
thr->timer(Timer::KSPACE);
}
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ik
------------------------------------------------------------------------- */
void PPPMTIP4POMP::fieldforce_ik()
{
const int nthreads = comm->nthreads;
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
dbl3_t xM;
FFT_SCALAR x0,y0,z0,ekx,eky,ekz;
int i,ifrom,ito,tid,iH1,iH2,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
for (i = ifrom; i < ito; ++i) {
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else xM = x[i];
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
z0 = r1d[2][n];
for (m = nlower; m <= nupper; m++) {
my = m+ny;
y0 = z0*r1d[1][m];
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
x0 = y0*r1d[0][l];
ekx -= x0*vdx_brick[mz][my][mx];
eky -= x0*vdy_brick[mz][my][mx];
ekz -= x0*vdz_brick[mz][my][mx];
}
}
}
// convert E-field to force
const double qfactor = qqrd2e * scale * q[i];
if (type[i] != typeO) {
f[i].x += qfactor*ekx;
f[i].y += qfactor*eky;
if (slabflag != 2) f[i].z += qfactor*ekz;
} else {
const double fx = qfactor * ekx;
const double fy = qfactor * eky;
const double fz = qfactor * ekz;
f[i].x += fx*(1 - alpha);
f[i].y += fy*(1 - alpha);
if (slabflag != 2) f[i].z += fz*(1 - alpha);
f[iH1].x += 0.5*alpha*fx;
f[iH1].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH1].z += 0.5*alpha*fz;
f[iH2].x += 0.5*alpha*fx;
f[iH2].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH2].z += 0.5*alpha*fz;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
interpolate from grid to get electric field & force on my particles for ad
------------------------------------------------------------------------- */
void PPPMTIP4POMP::fieldforce_ad()
{
const int nthreads = comm->nthreads;
const int nlocal = atom->nlocal;
// no local atoms => nothing to do
if (nlocal == 0) return;
const double *prd = (triclinic == 0) ? domain->prd : domain->prd_lamda;
const double hx_inv = nx_pppm/prd[0];
const double hy_inv = ny_pppm/prd[1];
const double hz_inv = nz_pppm/prd[2];
// loop over my charges, interpolate electric field from nearby grid points
// (nx,ny,nz) = global coords of grid pt to "lower left" of charge
// (dx,dy,dz) = distance to "lower left" grid pt
// (mx,my,mz) = global coords of moving stencil pt
// ek = 3 components of E-field on particle
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
const double * _noalias const q = atom->q;
const int3_t * _noalias const p2g = (int3_t *) part2grid[0];
const int * _noalias const type = atom->type;
const double qqrd2e = force->qqrd2e;
const double boxlox = boxlo[0];
const double boxloy = boxlo[1];
const double boxloz = boxlo[2];
#if defined(_OPENMP)
#pragma omp parallel default(none)
#endif
{
double s1,s2,s3,sf;
dbl3_t xM;
FFT_SCALAR ekx,eky,ekz;
int i,ifrom,ito,tid,iH1,iH2,l,m,n,mx,my,mz;
loop_setup_thr(ifrom,ito,tid,nlocal,nthreads);
// get per thread data
ThrData *thr = fix->get_thr(tid);
thr->timer(Timer::START);
dbl3_t * _noalias const f = (dbl3_t *) thr->get_f()[0];
FFT_SCALAR * const * const r1d = static_cast<FFT_SCALAR **>(thr->get_rho1d());
FFT_SCALAR * const * const d1d = static_cast<FFT_SCALAR **>(thr->get_drho1d());
for (i = ifrom; i < ito; ++i) {
if (type[i] == typeO) {
find_M_thr(i,iH1,iH2,xM);
} else xM = x[i];
const int nx = p2g[i].a;
const int ny = p2g[i].b;
const int nz = p2g[i].t;
const FFT_SCALAR dx = nx+shiftone - (xM.x-boxlox)*delxinv;
const FFT_SCALAR dy = ny+shiftone - (xM.y-boxloy)*delyinv;
const FFT_SCALAR dz = nz+shiftone - (xM.z-boxloz)*delzinv;
compute_rho1d_thr(r1d,dx,dy,dz);
compute_drho1d_thr(d1d,dx,dy,dz);
ekx = eky = ekz = ZEROF;
for (n = nlower; n <= nupper; n++) {
mz = n+nz;
for (m = nlower; m <= nupper; m++) {
my = m+ny;
for (l = nlower; l <= nupper; l++) {
mx = l+nx;
ekx += d1d[0][l]*r1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
eky += r1d[0][l]*d1d[1][m]*r1d[2][n]*u_brick[mz][my][mx];
ekz += r1d[0][l]*r1d[1][m]*d1d[2][n]*u_brick[mz][my][mx];
}
}
}
ekx *= hx_inv;
eky *= hy_inv;
ekz *= hz_inv;
// convert E-field to force and substract self forces
const double qi = q[i];
const double qfactor = qqrd2e * scale * qi;
s1 = x[i].x*hx_inv;
sf = sf_coeff[0]*sin(MY_2PI*s1);
sf += sf_coeff[1]*sin(MY_4PI*s1);
sf *= 2.0*qi;
const double fx = qfactor*(ekx - sf);
s2 = x[i].y*hy_inv;
sf = sf_coeff[2]*sin(MY_2PI*s2);
sf += sf_coeff[3]*sin(MY_4PI*s2);
sf *= 2.0*qi;
const double fy = qfactor*(eky - sf);
s3 = x[i].z*hz_inv;
sf = sf_coeff[4]*sin(MY_2PI*s3);
sf += sf_coeff[5]*sin(MY_4PI*s3);
sf *= 2.0*qi;
const double fz = qfactor*(ekz - sf);
if (type[i] != typeO) {
f[i].x += fx;
f[i].y += fy;
if (slabflag != 2) f[i].z += fz;
} else {
f[i].x += fx*(1 - alpha);
f[i].y += fy*(1 - alpha);
if (slabflag != 2) f[i].z += fz*(1 - alpha);
f[iH1].x += 0.5*alpha*fx;
f[iH1].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH1].z += 0.5*alpha*fz;
f[iH2].x += 0.5*alpha*fx;
f[iH2].y += 0.5*alpha*fy;
if (slabflag != 2) f[iH2].z += 0.5*alpha*fz;
}
}
thr->timer(Timer::KSPACE);
} // end of parallel region
}
/* ----------------------------------------------------------------------
find 2 H atoms bonded to O atom i
compute position xM of fictitious charge site for O atom
also return local indices iH1,iH2 of H atoms
------------------------------------------------------------------------- */
void PPPMTIP4POMP::find_M_thr(int i, int &iH1, int &iH2, dbl3_t &xM)
{
double **x = atom->x;
iH1 = atom->map(atom->tag[i] + 1);
iH2 = atom->map(atom->tag[i] + 2);
if (iH1 == -1 || iH2 == -1) error->one(FLERR,"TIP4P hydrogen is missing");
if (atom->type[iH1] != typeH || atom->type[iH2] != typeH)
error->one(FLERR,"TIP4P hydrogen has incorrect atom type");
if (triclinic) {
// need to use custom code to find the closest image for triclinic,
// since local atoms are in lambda coordinates, but ghosts are not.
int *sametag = atom->sametag;
double xo[3],xh1[3],xh2[3];
domain->lamda2x(x[i],xo);
domain->lamda2x(x[iH1],xh1);
domain->lamda2x(x[iH2],xh2);
double delx = xo[0] - xh1[0];
double dely = xo[1] - xh1[1];
double delz = xo[2] - xh1[2];
double rsqmin = delx*delx + dely*dely + delz*delz;
double rsq;
int closest = iH1;
while (sametag[iH1] >= 0) {
iH1 = sametag[iH1];
delx = xo[0] - x[iH1][0];
dely = xo[1] - x[iH1][1];
delz = xo[2] - x[iH1][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < rsqmin) {
rsqmin = rsq;
closest = iH1;
xh1[0] = x[iH1][0];
xh1[1] = x[iH1][1];
xh1[2] = x[iH1][2];
}
}
iH1 = closest;
closest = iH2;
delx = xo[0] - xh2[0];
dely = xo[1] - xh2[1];
delz = xo[2] - xh2[2];
rsqmin = delx*delx + dely*dely + delz*delz;
while (sametag[iH2] >= 0) {
iH2 = sametag[iH2];
delx = xo[0] - x[iH2][0];
dely = xo[1] - x[iH2][1];
delz = xo[2] - x[iH2][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < rsqmin) {
rsqmin = rsq;
closest = iH2;
xh2[0] = x[iH2][0];
xh2[1] = x[iH2][1];
xh2[2] = x[iH2][2];
}
}
iH2 = closest;
// finally compute M in real coordinates ...
double delx1 = xh1[0] - xo[0];
double dely1 = xh1[1] - xo[1];
double delz1 = xh1[2] - xo[2];
double delx2 = xh2[0] - xo[0];
double dely2 = xh2[1] - xo[1];
double delz2 = xh2[2] - xo[2];
xM.x = xo[0] + alpha * 0.5 * (delx1 + delx2);
xM.y = xo[1] + alpha * 0.5 * (dely1 + dely2);
xM.z = xo[2] + alpha * 0.5 * (delz1 + delz2);
// ... and convert M to lamda space for PPPM
domain->x2lamda((double *)&xM,(double *)&xM);
} else {
// set iH1,iH2 to index of closest image to O
iH1 = domain->closest_image(i,iH1);
iH2 = domain->closest_image(i,iH2);
const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0];
double delx1 = x[iH1].x - x[i].x;
double dely1 = x[iH1].y - x[i].y;
double delz1 = x[iH1].z - x[i].z;
double delx2 = x[iH2].x - x[i].x;
double dely2 = x[iH2].y - x[i].y;
double delz2 = x[iH2].z - x[i].z;
xM.x = x[i].x + alpha * 0.5 * (delx1 + delx2);
xM.y = x[i].y + alpha * 0.5 * (dely1 + dely2);
xM.z = x[i].z + alpha * 0.5 * (delz1 + delz2);
}
}
/* ----------------------------------------------------------------------
charge assignment into rho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMTIP4POMP::compute_rho1d_thr(FFT_SCALAR * const * const r1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-1; l >= 0; l--) {
r1 = rho_coeff[l][k] + r1*dx;
r2 = rho_coeff[l][k] + r2*dy;
r3 = rho_coeff[l][k] + r3*dz;
}
r1d[0][k] = r1;
r1d[1][k] = r2;
r1d[2][k] = r3;
}
}
/* ----------------------------------------------------------------------
charge assignment into drho1d
dx,dy,dz = distance of particle from "lower left" grid point
------------------------------------------------------------------------- */
void PPPMTIP4POMP::compute_drho1d_thr(FFT_SCALAR * const * const d1d, const FFT_SCALAR &dx,
const FFT_SCALAR &dy, const FFT_SCALAR &dz)
{
int k,l;
FFT_SCALAR r1,r2,r3;
for (k = (1-order)/2; k <= order/2; k++) {
r1 = r2 = r3 = ZEROF;
for (l = order-2; l >= 0; l--) {
r1 = drho_coeff[l][k] + r1*dx;
r2 = drho_coeff[l][k] + r2*dy;
r3 = drho_coeff[l][k] + r3*dz;
}
d1d[0][k] = r1;
d1d[1][k] = r2;
d1d[2][k] = r3;
}
}
diff --git a/src/USER-OMP/pppm_tip4p_omp.h b/src/USER-OMP/pppm_tip4p_omp.h
index 0ee807651..59559cd58 100644
--- a/src/USER-OMP/pppm_tip4p_omp.h
+++ b/src/USER-OMP/pppm_tip4p_omp.h
@@ -1,71 +1,70 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef KSPACE_CLASS
KSpaceStyle(pppm/tip4p/omp,PPPMTIP4POMP)
#else
#ifndef LMP_PPPM_TIP4P_OMP_H
#define LMP_PPPM_TIP4P_OMP_H
#include "pppm_tip4p.h"
#include "thr_omp.h"
namespace LAMMPS_NS {
class PPPMTIP4POMP : public PPPMTIP4P, public ThrOMP {
public:
PPPMTIP4POMP(class LAMMPS *, int, char **);
- virtual ~PPPMTIP4POMP () {};
+ virtual ~PPPMTIP4POMP ();
virtual void compute(int, int);
protected:
virtual void allocate();
- virtual void deallocate();
virtual void compute_gf_ik();
virtual void compute_gf_ad();
virtual void particle_map();
virtual void make_rho(); // XXX: not (yet) multi-threaded
virtual void fieldforce_ik();
virtual void fieldforce_ad();
// virtual void fieldforce_peratom(); XXX: need to benchmark first.
private:
void compute_rho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
void compute_drho1d_thr(FFT_SCALAR * const * const, const FFT_SCALAR &,
const FFT_SCALAR &, const FFT_SCALAR &);
void find_M_thr(const int, int &, int &, dbl3_t &);
// void slabcorr(int); // XXX: not (yet) multi-threaded
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Kspace style pppm/tip4p/omp requires newton on
Self-explanatory.
*/
diff --git a/src/USER-OMP/reaxc_bonds_omp.cpp b/src/USER-OMP/reaxc_bonds_omp.cpp
index d079db667..7522df2f6 100644
--- a/src/USER-OMP/reaxc_bonds_omp.cpp
+++ b/src/USER-OMP/reaxc_bonds_omp.cpp
@@ -1,186 +1,187 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "reaxc_bonds_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_tool_box.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
void BondsOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace, reax_list **lists,
output_controls *out_control )
{
#ifdef OMP_TIMING
double endTimeBase, startTimeBase;
startTimeBase = MPI_Wtime();
#endif
const int natoms = system->n;
reax_list *bonds = (*lists) + BONDS;
const double gp3 = system->reax_param.gp.l[3];
const double gp4 = system->reax_param.gp.l[4];
const double gp7 = system->reax_param.gp.l[7];
const double gp10 = system->reax_param.gp.l[10];
const int gp37 = (int) system->reax_param.gp.l[37];
double total_Ebond = 0.0;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+: total_Ebond)
#endif
{
int i, j, pj;
int start_i, end_i;
int type_i, type_j;
double ebond, pow_BOs_be2, exp_be12, CEbo;
double exphu, exphua1, exphub1, exphuov, hulpov, estriph;
double decobdbo, decobdboua, decobdboub;
single_body_parameters *sbp_i, *sbp_j;
two_body_parameters *twbp;
bond_order_data *bo_ij;
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either, natoms,
+ system->pair_ptr->vflag_either, system->N,
system->pair_ptr->eatom, system->pair_ptr->vatom, thr);
#if defined(_OPENMP)
#pragma omp for schedule(guided)
#endif
for (i = 0; i < natoms; ++i) {
start_i = Start_Index(i, bonds);
end_i = End_Index(i, bonds);
for (pj = start_i; pj < end_i; ++pj) {
j = bonds->select.bond_list[pj].nbr;
if( system->my_atoms[i].orig_id > system->my_atoms[j].orig_id ) continue;
if( system->my_atoms[i].orig_id == system->my_atoms[j].orig_id ) {
if (system->my_atoms[j].x[2] < system->my_atoms[i].x[2]) continue;
if (system->my_atoms[j].x[2] == system->my_atoms[i].x[2] &&
system->my_atoms[j].x[1] < system->my_atoms[i].x[1]) continue;
if (system->my_atoms[j].x[2] == system->my_atoms[i].x[2] &&
system->my_atoms[j].x[1] == system->my_atoms[i].x[1] &&
system->my_atoms[j].x[0] < system->my_atoms[i].x[0]) continue;
}
/* set the pointers */
type_i = system->my_atoms[i].type;
type_j = system->my_atoms[j].type;
sbp_i = &( system->reax_param.sbp[type_i] );
sbp_j = &( system->reax_param.sbp[type_j] );
twbp = &( system->reax_param.tbp[type_i][type_j] );
bo_ij = &( bonds->select.bond_list[pj].bo_data );
/* calculate the constants */
- pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 );
+ if (bo_ij->BO_s == 0.0) pow_BOs_be2 = 0.0;
+ else pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 );
exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) );
CEbo = -twbp->De_s * exp_be12 *
( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 );
/* calculate the Bond Energy */
total_Ebond += ebond =
-twbp->De_s * bo_ij->BO_s * exp_be12
-twbp->De_p * bo_ij->BO_pi
-twbp->De_pp * bo_ij->BO_pi2;
/* tally into per-atom energy */
if (system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, j, natoms, 1,
ebond, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
/* calculate derivatives of Bond Orders */
bo_ij->Cdbo += CEbo;
bo_ij->Cdbopi -= (CEbo + twbp->De_p);
bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp);
/* Stabilisation terminal triple bond */
if (bo_ij->BO >= 1.00) {
if (gp37 == 2 ||
(sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990) ||
(sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990)) {
exphu = exp( -gp7 * SQR(bo_ij->BO - 2.50) );
exphua1 = exp(-gp3 * (workspace->total_bond_order[i]-bo_ij->BO));
exphub1 = exp(-gp3 * (workspace->total_bond_order[j]-bo_ij->BO));
exphuov = exp(gp4 * (workspace->Delta[i] + workspace->Delta[j]));
hulpov = 1.0 / (1.0 + 25.0 * exphuov);
estriph = gp10 * exphu * hulpov * (exphua1 + exphub1);
total_Ebond += estriph;
decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) *
( gp3 - 2.0 * gp7 * (bo_ij->BO-2.50) );
decobdboua = -gp10 * exphu * hulpov *
(gp3*exphua1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
decobdboub = -gp10 * exphu * hulpov *
(gp3*exphub1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
/* tally into per-atom energy */
if (system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, j, natoms, 1,
estriph, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
bo_ij->Cdbo += decobdbo;
workspace->CdDelta[i] += decobdboua;
workspace->CdDeltaReduction[reductionOffset+j] += decobdboub;
}
}
}
} // for(i)
} // omp
data->my_en.e_bond += total_Ebond;
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEBONDSINDEX] += (endTimeBase-startTimeBase);
#endif
}
diff --git a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp
index be1444824..c6486ae8e 100644
--- a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp
+++ b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp
@@ -1,254 +1,246 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "reaxc_hydrogen_bonds_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_valence_angles.h" // To access Calculate_Theta()
#include "reaxc_valence_angles_omp.h" // To access Calculate_dCos_ThetaOMP()
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
void Hydrogen_BondsOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists, output_controls *out_control )
{
#ifdef OMP_TIMING
double endTimeBase, startTimeBase;
startTimeBase = MPI_Wtime();
#endif
const int nthreads = control->nthreads;
#if defined(_OPENMP)
#pragma omp parallel default(shared) //default(none)
#endif
{
int i, j, k, pi, pk;
int type_i, type_j, type_k;
int start_j, end_j, hb_start_j, hb_end_j;
int hblist[MAX_BONDS];
int itr, top;
int num_hb_intrs = 0;
ivec rel_jk;
double r_jk, theta, cos_theta, sin_xhz4, cos_xhz1, sin_theta2;
double e_hb, e_hb_thr = 0.0, exp_hb2, exp_hb3, CEhb1, CEhb2, CEhb3;
rvec dcos_theta_di, dcos_theta_dj, dcos_theta_dk;
rvec dvec_jk, force, ext_press;
hbond_parameters *hbp;
bond_order_data *bo_ij;
bond_data *pbond_ij;
far_neighbor_data *nbr_jk;
reax_list *bonds, *hbonds;
bond_data *bond_list;
hbond_data *hbond_list;
// tally variables
double fi_tmp[3], fk_tmp[3], delij[3], delkj[3];
bonds = (*lists) + BONDS;
bond_list = bonds->select.bond_list;
hbonds = (*lists) + HBONDS;
hbond_list = hbonds->select.hbond_list;
int natoms = system->n;
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
const int idelta = 1 + natoms/nthreads;
int ifrom = tid*idelta;
int ito = ((ifrom + idelta) > natoms) ? natoms : ifrom + idelta;
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either,
- natoms, system->pair_ptr->eatom,
- system->pair_ptr->vatom, thr);
-
/* loops below discover the Hydrogen bonds between i-j-k triplets.
here j is H atom and there has to be some bond between i and j.
Hydrogen bond is between j and k.
so in this function i->X, j->H, k->Z when we map
variables onto the ones in the handout.*/
// for( j = 0; j < system->n; ++j )
for( j = ifrom; j < ito; ++j ) {
/* j has to be of type H */
if( system->reax_param.sbp[system->my_atoms[j].type].p_hbond == 1 ) {
/*set j's variables */
type_j = system->my_atoms[j].type;
start_j = Start_Index(j, bonds);
end_j = End_Index(j, bonds);
hb_start_j = Start_Index( system->my_atoms[j].Hindex, hbonds );
hb_end_j = End_Index( system->my_atoms[j].Hindex, hbonds );
if(type_j < 0) continue;
top = 0;
for( pi = start_j; pi < end_j; ++pi ) {
pbond_ij = &( bond_list[pi] );
i = pbond_ij->nbr;
type_i = system->my_atoms[i].type;
if(type_i < 0) continue;
bo_ij = &(pbond_ij->bo_data);
if( system->reax_param.sbp[type_i].p_hbond == 2 &&
bo_ij->BO >= HB_THRESHOLD )
hblist[top++] = pi;
}
for( pk = hb_start_j; pk < hb_end_j; ++pk ) {
/* set k's varibles */
k = hbond_list[pk].nbr;
type_k = system->my_atoms[k].type;
if(type_k < 0) continue;
nbr_jk = hbond_list[pk].ptr;
r_jk = nbr_jk->d;
rvec_Scale( dvec_jk, hbond_list[pk].scl, nbr_jk->dvec );
for( itr = 0; itr < top; ++itr ) {
pi = hblist[itr];
pbond_ij = &( bonds->select.bond_list[pi] );
i = pbond_ij->nbr;
if( system->my_atoms[i].orig_id != system->my_atoms[k].orig_id ) {
bo_ij = &(pbond_ij->bo_data);
type_i = system->my_atoms[i].type;
if(type_i < 0) continue;
hbp = &(system->reax_param.hbp[ type_i ][ type_j ][ type_k ]);
++num_hb_intrs;
Calculate_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
&theta, &cos_theta );
/* the derivative of cos(theta) */
Calculate_dCos_ThetaOMP( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
&dcos_theta_di, &dcos_theta_dj,
&dcos_theta_dk );
/* hydrogen bond energy*/
sin_theta2 = sin( theta/2.0 );
sin_xhz4 = SQR(sin_theta2);
sin_xhz4 *= sin_xhz4;
cos_xhz1 = ( 1.0 - cos_theta );
exp_hb2 = exp( -hbp->p_hb2 * bo_ij->BO );
exp_hb3 = exp( -hbp->p_hb3 * ( hbp->r0_hb / r_jk +
r_jk / hbp->r0_hb - 2.0 ) );
e_hb_thr += e_hb = hbp->p_hb1 * (1.0 - exp_hb2) * exp_hb3 * sin_xhz4;
CEhb1 = hbp->p_hb1 * hbp->p_hb2 * exp_hb2 * exp_hb3 * sin_xhz4;
CEhb2 = -hbp->p_hb1/2.0 * (1.0 - exp_hb2) * exp_hb3 * cos_xhz1;
CEhb3 = -hbp->p_hb3 *
(-hbp->r0_hb / SQR(r_jk) + 1.0 / hbp->r0_hb) * e_hb;
/* hydrogen bond forces */
bo_ij->Cdbo += CEhb1; // dbo term
if( control->virial == 0 ) {
// dcos terms
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+i], +CEhb2, dcos_theta_di );
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+j], +CEhb2, dcos_theta_dj );
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+k], +CEhb2, dcos_theta_dk );
// dr terms
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+j], -CEhb3/r_jk, dvec_jk );
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+k], +CEhb3/r_jk, dvec_jk );
}
else {
/* for pressure coupling, terms that are not related to bond order
derivatives are added directly into pressure vector/tensor */
rvec_Scale( force, +CEhb2, dcos_theta_di ); // dcos terms
rvec_Add(workspace->forceReduction[reductionOffset+i], force );
rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
rvec_ScaledAdd( workspace->my_ext_pressReduction[tid],1.0, ext_press );
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+j], +CEhb2, dcos_theta_dj );
ivec_Scale( rel_jk, hbond_list[pk].scl, nbr_jk->rel_box );
rvec_Scale( force, +CEhb2, dcos_theta_dk );
rvec_Add(workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, rel_jk, force );
rvec_ScaledAdd( workspace->my_ext_pressReduction[tid],1.0, ext_press );
// dr terms
rvec_ScaledAdd(workspace->forceReduction[reductionOffset+j],-CEhb3/r_jk, dvec_jk );
rvec_Scale( force, CEhb3/r_jk, dvec_jk );
rvec_Add(workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, rel_jk, force );
rvec_ScaledAdd( workspace->my_ext_pressReduction[tid],1.0, ext_press );
}
/* tally into per-atom virials */
if (system->pair_ptr->vflag_atom || system->pair_ptr->evflag) {
rvec_ScaledSum( delij, 1., system->my_atoms[j].x,
-1., system->my_atoms[i].x );
rvec_ScaledSum( delkj, 1., system->my_atoms[j].x,
-1., system->my_atoms[k].x );
rvec_Scale(fi_tmp, CEhb2, dcos_theta_di);
rvec_Scale(fk_tmp, CEhb2, dcos_theta_dk);
rvec_ScaledAdd(fk_tmp, CEhb3/r_jk, dvec_jk);
pair_reax_ptr->ev_tally3_thr_proxy(system->pair_ptr,i,j,k,e_hb,0.0,fi_tmp,fk_tmp,delij,delkj,thr);
}
}
}
}
}
}
#if defined(_OPENMP)
#pragma omp critical
#endif
{
data->my_en.e_hb += e_hb_thr;
}
-
- pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either, thr);
}
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEHBONDSINDEX] += (endTimeBase-startTimeBase);
#endif
}
diff --git a/src/USER-OMP/reaxc_init_md_omp.cpp b/src/USER-OMP/reaxc_init_md_omp.cpp
index 79fec8b26..c0e4a45ea 100644
--- a/src/USER-OMP/reaxc_init_md_omp.cpp
+++ b/src/USER-OMP/reaxc_init_md_omp.cpp
@@ -1,188 +1,188 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "reaxc_init_md_omp.h"
#include "reaxc_allocate.h"
#include "reaxc_forces.h"
#include "reaxc_forces_omp.h"
#include "reaxc_io_tools.h"
#include "reaxc_list.h"
#include "reaxc_lookup.h"
#include "reaxc_reset_tools.h"
#include "reaxc_system_props.h"
#include "reaxc_tool_box.h"
#include "reaxc_vector.h"
-// Functions definedd in reaxc_init_md.cpp
+// Functions defined in reaxc_init_md.cpp
extern int Init_MPI_Datatypes(reax_system*, storage*, mpi_datatypes*, MPI_Comm, char*);
extern int Init_System(reax_system*, control_params*, char*);
extern int Init_Simulation_Data(reax_system*, control_params*, simulation_data*, char*);
extern int Init_Workspace(reax_system*, control_params*, storage*, MPI_Comm, char*);
/* ---------------------------------------------------------------------- */
int Init_ListsOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace, reax_list **lists,
mpi_datatypes *mpi_data, char *msg )
{
int i, total_hbonds, total_bonds, bond_cap, num_3body, cap_3body, Htop;
int *hb_top, *bond_top;
MPI_Comm comm;
int mincap = system->mincap;
double safezone = system->safezone;
double saferzone = system->saferzone;
comm = mpi_data->world;
bond_top = (int*) calloc( system->total_cap, sizeof(int) );
hb_top = (int*) calloc( system->local_cap, sizeof(int) );
Estimate_Storages( system, control, lists,
&Htop, hb_top, bond_top, &num_3body, comm );
if( control->hbond_cut > 0 ) {
/* init H indexes */
total_hbonds = 0;
for( i = 0; i < system->n; ++i ) {
system->my_atoms[i].num_hbonds = hb_top[i];
total_hbonds += hb_top[i];
}
total_hbonds = (int)(MAX( total_hbonds*saferzone, mincap*MIN_HBONDS ));
if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND,
*lists+HBONDS, comm ) ) {
fprintf( stderr, "not enough space for hbonds list. terminating!\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
}
total_bonds = 0;
for( i = 0; i < system->N; ++i ) {
system->my_atoms[i].num_bonds = bond_top[i];
total_bonds += bond_top[i];
}
bond_cap = (int)(MAX( total_bonds*safezone, mincap*MIN_BONDS ));
if( !Make_List( system->total_cap, bond_cap, TYP_BOND,
*lists+BONDS, comm ) ) {
fprintf( stderr, "not enough space for bonds list. terminating!\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
int nthreads = control->nthreads;
reax_list *bonds = (*lists)+BONDS;
for (i = 0; i < bonds->num_intrs; ++i)
bonds->select.bond_list[i].bo_data.CdboReduction =
(double*) smalloc(sizeof(double)*nthreads, "CdboReduction", comm);
/* 3bodies list */
cap_3body = (int)(MAX( num_3body*safezone, MIN_3BODIES ));
if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY,
- *lists+THREE_BODIES, comm ) ){
+ *lists+THREE_BODIES, comm ) ){
fprintf( stderr, "Problem in initializing angles list. Terminating!\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
free( hb_top );
free( bond_top );
return SUCCESS;
}
/* ---------------------------------------------------------------------- */
// The only difference with the MPI-only function is calls to Init_ListsOMP and Init_Force_FunctionsOMP().
void InitializeOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists, output_controls *out_control,
mpi_datatypes *mpi_data, MPI_Comm comm )
{
char msg[MAX_STR];
if( Init_MPI_Datatypes(system, workspace, mpi_data, comm, msg) == FAILURE ) {
fprintf( stderr, "p%d: init_mpi_datatypes: could not create datatypes\n",
system->my_rank );
fprintf( stderr, "p%d: mpi_data couldn't be initialized! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( Init_System(system, control, msg) == FAILURE ){
fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( Init_Simulation_Data( system, control, data, msg ) == FAILURE ) {
fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
fprintf( stderr, "p%d: sim_data couldn't be initialized! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( Init_Workspace( system, control, workspace, mpi_data->world, msg ) ==
FAILURE ) {
fprintf( stderr, "p%d:init_workspace: not enough memory\n",
system->my_rank );
fprintf( stderr, "p%d:workspace couldn't be initialized! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( Init_ListsOMP( system, control, data, workspace, lists, mpi_data, msg ) ==
FAILURE ) {
fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
fprintf( stderr, "p%d: system could not be initialized! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( Init_Output_Files(system,control,out_control,mpi_data,msg)== FAILURE) {
fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
fprintf( stderr, "p%d: could not open output files! terminating...\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
if( control->tabulate ) {
if( Init_Lookup_Tables( system, control, workspace, mpi_data, msg ) == FAILURE ) {
fprintf( stderr, "p%d: %s\n", system->my_rank, msg );
fprintf( stderr, "p%d: couldn't create lookup table! terminating.\n",
system->my_rank );
MPI_Abort( mpi_data->world, CANNOT_INITIALIZE );
}
}
Init_Force_FunctionsOMP( control );
}
diff --git a/src/USER-OMP/reaxc_multi_body_omp.cpp b/src/USER-OMP/reaxc_multi_body_omp.cpp
index 13d250750..27779f8e8 100644
--- a/src/USER-OMP/reaxc_multi_body_omp.cpp
+++ b/src/USER-OMP/reaxc_multi_body_omp.cpp
@@ -1,297 +1,288 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "thr_data.h"
#include "reaxc_multi_body_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
void Atom_EnergyOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace, reax_list **lists,
output_controls *out_control )
{
#ifdef OMP_TIMING
double endTimeBase, startTimeBase;
startTimeBase = MPI_Wtime();
#endif
/* Initialize parameters */
const double p_lp3 = system->reax_param.gp.l[5];
const double p_ovun3 = system->reax_param.gp.l[32];
const double p_ovun4 = system->reax_param.gp.l[31];
const double p_ovun6 = system->reax_param.gp.l[6];
const double p_ovun7 = system->reax_param.gp.l[8];
const double p_ovun8 = system->reax_param.gp.l[9];
- const int natoms = system->n;
reax_list *bonds = (*lists) + BONDS;
double total_Elp = 0.0;
double total_Eun = 0.0;
double total_Eov = 0.0;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+:total_Elp, total_Eun, total_Eov)
#endif
{
int i, j, pj, type_i, type_j;
double Delta_lpcorr, dfvl;
double e_lp, expvd2, inv_expvd2, dElp, CElp, DlpVi;
double e_lph, Di, vov3, deahu2dbo, deahu2dsbo;
double e_ov, CEover1, CEover2, CEover3, CEover4;
double exp_ovun1, exp_ovun2, sum_ovun1, sum_ovun2;
double exp_ovun2n, exp_ovun6, exp_ovun8;
double inv_exp_ovun1, inv_exp_ovun2, inv_exp_ovun2n, inv_exp_ovun8;
double e_un, CEunder1, CEunder2, CEunder3, CEunder4;
double eng_tmp;
double p_lp2, p_ovun2, p_ovun5;
int numbonds;
single_body_parameters *sbp_i;
two_body_parameters *twbp;
bond_data *pbond;
bond_order_data *bo_ij;
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either, natoms,
- system->pair_ptr->eatom, system->pair_ptr->vatom, thr);
-
#if defined(_OPENMP)
#pragma omp for schedule(guided)
#endif
for ( i = 0; i < system->n; ++i) {
type_i = system->my_atoms[i].type;
if(type_i < 0) continue;
sbp_i = &(system->reax_param.sbp[ type_i ]);
/* lone-pair Energy */
p_lp2 = sbp_i->p_lp2;
expvd2 = exp( -75 * workspace->Delta_lp[i] );
inv_expvd2 = 1. / (1. + expvd2 );
numbonds = 0;
e_lp = 0.0;
for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj )
numbonds ++;
/* calculate the energy */
if(numbonds > 0)
total_Elp += e_lp =
p_lp2 * workspace->Delta_lp[i] * inv_expvd2;
dElp = p_lp2 * inv_expvd2 +
75 * p_lp2 * workspace->Delta_lp[i] * expvd2 * SQR(inv_expvd2);
CElp = dElp * workspace->dDelta_lp[i];
if(numbonds > 0) workspace->CdDelta[i] += CElp; // lp - 1st term
/* tally into per-atom energy */
if( system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, i, system->n, 1,
e_lp, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
/* correction for C2 */
if( p_lp3 > 0.001 && !strcmp(system->reax_param.sbp[type_i].name, "C") )
for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj ) {
j = bonds->select.bond_list[pj].nbr;
type_j = system->my_atoms[j].type;
if(type_j < 0) continue;
if( !strcmp( system->reax_param.sbp[type_j].name, "C" ) ) {
twbp = &( system->reax_param.tbp[type_i][type_j]);
bo_ij = &( bonds->select.bond_list[pj].bo_data );
Di = workspace->Delta[i];
vov3 = bo_ij->BO - Di - 0.040*pow(Di, 4.);
if( vov3 > 3. ) {
total_Elp += e_lph = p_lp3 * SQR(vov3-3.0);
deahu2dbo = 2.*p_lp3*(vov3 - 3.);
deahu2dsbo = 2.*p_lp3*(vov3 - 3.)*(-1. - 0.16*pow(Di, 3.));
bo_ij->Cdbo += deahu2dbo;
workspace->CdDelta[i] += deahu2dsbo;
/* tally into per-atom energy */
if( system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, j, system->n, 1,
e_lph, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
}
}
}
}
#if defined(_OPENMP)
#pragma omp barrier
#pragma omp for schedule(guided)
#endif
for (i = 0; i < system->n; ++i) {
type_i = system->my_atoms[i].type;
if(type_i < 0) continue;
sbp_i = &(system->reax_param.sbp[ type_i ]);
/* over-coordination energy */
if( sbp_i->mass > 21.0 )
dfvl = 0.0;
else dfvl = 1.0; // only for 1st-row elements
p_ovun2 = sbp_i->p_ovun2;
sum_ovun1 = sum_ovun2 = 0;
for (pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj) {
j = bonds->select.bond_list[pj].nbr;
type_j = system->my_atoms[j].type;
if(type_j < 0) continue;
bo_ij = &(bonds->select.bond_list[pj].bo_data);
twbp = &(system->reax_param.tbp[ type_i ][ type_j ]);
sum_ovun1 += twbp->p_ovun1 * twbp->De_s * bo_ij->BO;
sum_ovun2 += (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j])*
( bo_ij->BO_pi + bo_ij->BO_pi2 );
}
exp_ovun1 = p_ovun3 * exp( p_ovun4 * sum_ovun2 );
inv_exp_ovun1 = 1.0 / (1 + exp_ovun1);
Delta_lpcorr = workspace->Delta[i] -
(dfvl * workspace->Delta_lp_temp[i]) * inv_exp_ovun1;
exp_ovun2 = exp( p_ovun2 * Delta_lpcorr );
inv_exp_ovun2 = 1.0 / (1.0 + exp_ovun2);
DlpVi = 1.0 / (Delta_lpcorr + sbp_i->valency + 1e-8);
CEover1 = Delta_lpcorr * DlpVi * inv_exp_ovun2;
total_Eov += e_ov = sum_ovun1 * CEover1;
CEover2 = sum_ovun1 * DlpVi * inv_exp_ovun2 *
(1.0 - Delta_lpcorr * ( DlpVi + p_ovun2 * exp_ovun2 * inv_exp_ovun2 ));
CEover3 = CEover2 * (1.0 - dfvl * workspace->dDelta_lp[i] * inv_exp_ovun1 );
CEover4 = CEover2 * (dfvl * workspace->Delta_lp_temp[i]) *
p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1);
/* under-coordination potential */
p_ovun2 = sbp_i->p_ovun2;
p_ovun5 = sbp_i->p_ovun5;
exp_ovun2n = 1.0 / exp_ovun2;
exp_ovun6 = exp( p_ovun6 * Delta_lpcorr );
exp_ovun8 = p_ovun7 * exp(p_ovun8 * sum_ovun2);
inv_exp_ovun2n = 1.0 / (1.0 + exp_ovun2n);
inv_exp_ovun8 = 1.0 / (1.0 + exp_ovun8);
numbonds = 0;
e_un = 0.0;
for( pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj )
numbonds ++;
if(numbonds > 0) total_Eun += e_un =
-p_ovun5 * (1.0 - exp_ovun6) * inv_exp_ovun2n * inv_exp_ovun8;
CEunder1 = inv_exp_ovun2n *
( p_ovun5 * p_ovun6 * exp_ovun6 * inv_exp_ovun8 +
p_ovun2 * e_un * exp_ovun2n );
CEunder2 = -e_un * p_ovun8 * exp_ovun8 * inv_exp_ovun8;
CEunder3 = CEunder1 * (1.0 - dfvl*workspace->dDelta_lp[i]*inv_exp_ovun1);
CEunder4 = CEunder1 * (dfvl*workspace->Delta_lp_temp[i]) *
p_ovun4 * exp_ovun1 * SQR(inv_exp_ovun1) + CEunder2;
/* tally into per-atom energy */
if (system->pair_ptr->evflag) {
eng_tmp = e_ov;
if(numbonds > 0) eng_tmp+= e_un;
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, i, system->n, 1,
eng_tmp, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
}
/* forces */
workspace->CdDelta[i] += CEover3; // OvCoor - 2nd term
if(numbonds > 0) workspace->CdDelta[i] += CEunder3; // UnCoor - 1st term
for (pj = Start_Index(i, bonds); pj < End_Index(i, bonds); ++pj) {
pbond = &(bonds->select.bond_list[pj]);
j = pbond->nbr;
bo_ij = &(pbond->bo_data);
twbp = &(system->reax_param.tbp[ system->my_atoms[i].type ]
[system->my_atoms[pbond->nbr].type]);
bo_ij->Cdbo += CEover1 * twbp->p_ovun1 * twbp->De_s; // OvCoor-1st
workspace->CdDeltaReduction[reductionOffset+j] +=
CEover4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * (bo_ij->BO_pi + bo_ij->BO_pi2); // OvCoor-3a
bo_ij->Cdbopi += CEover4 *
(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // OvCoor-3b
bo_ij->Cdbopi2 += CEover4 *
(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // OvCoor-3b
workspace->CdDeltaReduction[reductionOffset+j] +=
CEunder4 * (1.0 - dfvl*workspace->dDelta_lp[j]) * (bo_ij->BO_pi + bo_ij->BO_pi2); // UnCoor - 2a
bo_ij->Cdbopi += CEunder4 *
(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // UnCoor-2b
bo_ij->Cdbopi2 += CEunder4 *
(workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // UnCoor-2b
}
}
-
- pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either, thr);
-
}
data->my_en.e_lp += total_Elp;
data->my_en.e_ov += total_Eov;
data->my_en.e_un += total_Eun;
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEATOMENERGYINDEX] += (endTimeBase-startTimeBase);
#endif
}
diff --git a/src/USER-OMP/reaxc_nonbonded_omp.cpp b/src/USER-OMP/reaxc_nonbonded_omp.cpp
index 0c595e07d..d131195ca 100644
--- a/src/USER-OMP/reaxc_nonbonded_omp.cpp
+++ b/src/USER-OMP/reaxc_nonbonded_omp.cpp
@@ -1,398 +1,389 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "thr_data.h"
#include "reaxc_types.h"
#include "reaxc_nonbonded.h"
#include "reaxc_nonbonded_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
void vdW_Coulomb_Energy_OMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists, output_controls *out_control ) {
int natoms = system->n;
reax_list *far_nbrs = (*lists) + FAR_NBRS;
double p_vdW1 = system->reax_param.gp.l[28];
double p_vdW1i = 1.0 / p_vdW1;
double total_EvdW = 0.;
double total_Eele = 0.;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+: total_EvdW, total_Eele)
#endif
{
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
int i, j, pj;
int start_i, end_i, orig_i, orig_j, flag;
double powr_vdW1, powgi_vdW1;
double tmp, r_ij, fn13, exp1, exp2;
double Tap, dTap, dfn13, CEvd, CEclmb, de_core;
double dr3gamij_1, dr3gamij_3;
double e_ele, e_vdW, e_core;
const double SMALL = 0.0001;
double e_lg, de_lg, r_ij5, r_ij6, re6;
rvec temp, ext_press;
two_body_parameters *twbp;
far_neighbor_data *nbr_pj;
// Tallying variables:
double pe_vdw, f_tmp, delij[3];
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either,
- natoms, system->pair_ptr->eatom,
- system->pair_ptr->vatom, thr);
e_core = 0;
e_vdW = 0;
e_lg = 0;
de_lg = 0.0;
#if defined(_OPENMP)
#pragma omp for schedule(guided)
#endif
for( i = 0; i < natoms; ++i ) {
if(system->my_atoms[i].type < 0) continue;
start_i = Start_Index(i, far_nbrs);
end_i = End_Index(i, far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for( pj = start_i; pj < end_i; ++pj ) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
if(nbr_pj->d <= control->nonb_cut) {
if(j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
r_ij = nbr_pj->d;
twbp = &(system->reax_param.tbp[ system->my_atoms[i].type ]
[ system->my_atoms[j].type ]);
/* Calculate Taper and its derivative */
// Tap = nbr_pj->Tap; -- precomputed during compte_H
Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
Tap = Tap * r_ij + workspace->Tap[5];
Tap = Tap * r_ij + workspace->Tap[4];
Tap = Tap * r_ij + workspace->Tap[3];
Tap = Tap * r_ij + workspace->Tap[2];
Tap = Tap * r_ij + workspace->Tap[1];
Tap = Tap * r_ij + workspace->Tap[0];
dTap = 7*workspace->Tap[7] * r_ij + 6*workspace->Tap[6];
dTap = dTap * r_ij + 5*workspace->Tap[5];
dTap = dTap * r_ij + 4*workspace->Tap[4];
dTap = dTap * r_ij + 3*workspace->Tap[3];
dTap = dTap * r_ij + 2*workspace->Tap[2];
dTap += workspace->Tap[1]/r_ij;
/*vdWaals Calculations*/
if(system->reax_param.gp.vdw_type==1 || system->reax_param.gp.vdw_type==3)
{ // shielding
powr_vdW1 = pow(r_ij, p_vdW1);
powgi_vdW1 = pow( 1.0 / twbp->gamma_w, p_vdW1);
fn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i );
exp1 = exp( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
exp2 = exp( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
e_vdW = twbp->D * (exp1 - 2.0 * exp2);
total_EvdW += Tap * e_vdW;
dfn13 = pow( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) *
pow(r_ij, p_vdW1 - 2.0);
CEvd = dTap * e_vdW -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
}
else{ // no shielding
exp1 = exp( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
exp2 = exp( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
e_vdW = twbp->D * (exp1 - 2.0 * exp2);
total_EvdW += Tap * e_vdW;
CEvd = dTap * e_vdW -
Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) / r_ij;
}
if(system->reax_param.gp.vdw_type==2 || system->reax_param.gp.vdw_type==3)
{ // innner wall
e_core = twbp->ecore * exp(twbp->acore * (1.0-(r_ij/twbp->rcore)));
total_EvdW += Tap * e_core;
de_core = -(twbp->acore/twbp->rcore) * e_core;
CEvd += dTap * e_core + Tap * de_core / r_ij;
// lg correction, only if lgvdw is yes
if (control->lgflag) {
r_ij5 = pow( r_ij, 5.0 );
r_ij6 = pow( r_ij, 6.0 );
re6 = pow( twbp->lgre, 6.0 );
e_lg = -(twbp->lgcij/( r_ij6 + re6 ));
total_EvdW += Tap * e_lg;
de_lg = -6.0 * e_lg * r_ij5 / ( r_ij6 + re6 ) ;
CEvd += dTap * e_lg + Tap * de_lg / r_ij;
}
}
/*Coulomb Calculations*/
dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
dr3gamij_3 = pow( dr3gamij_1 , 0.33333333333333 );
tmp = Tap / dr3gamij_3;
total_Eele += e_ele =
C_ele * system->my_atoms[i].q * system->my_atoms[j].q * tmp;
CEclmb = C_ele * system->my_atoms[i].q * system->my_atoms[j].q *
( dTap - Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
/* tally into per-atom energy */
if( system->pair_ptr->evflag || system->pair_ptr->vflag_atom) {
pe_vdw = Tap * (e_vdW + e_core + e_lg);
rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x );
f_tmp = -(CEvd + CEclmb);
pair_reax_ptr->ev_tally_thr_proxy( system->pair_ptr, i, j, natoms,
1, pe_vdw, e_ele, f_tmp,
delij[0], delij[1], delij[2], thr);
}
if( control->virial == 0 ) {
rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+j],
+(CEvd + CEclmb), nbr_pj->dvec );
}
else { /* NPT, iNPT or sNPT */
/* for pressure coupling, terms not related to bond order
derivatives are added directly into pressure vector/tensor */
rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );
rvec_ScaledAdd( workspace->f[reductionOffset+i], -1., temp );
rvec_Add( workspace->forceReduction[reductionOffset+j], temp);
rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
}
}
}
}
pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either,
system->pair_ptr->vflag_either, thr);
} // parallel region
data->my_en.e_vdW = total_EvdW;
data->my_en.e_ele = total_Eele;
Compute_Polarization_Energy( system, data );
}
/* ---------------------------------------------------------------------- */
void Tabulated_vdW_Coulomb_Energy_OMP(reax_system *system,control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists,
output_controls *out_control ) {
double SMALL = 0.0001;
int natoms = system->n;
reax_list *far_nbrs = (*lists) + FAR_NBRS;
double total_EvdW = 0.;
double total_Eele = 0.;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+:total_EvdW, total_Eele)
#endif
{
int i, j, pj, r;
int type_i, type_j, tmin, tmax;
int start_i, end_i, orig_i, orig_j, flag;
double r_ij, base, dif;
double e_vdW, e_ele;
double CEvd, CEclmb;
double f_tmp, delij[3];
rvec temp, ext_press;
far_neighbor_data *nbr_pj;
LR_lookup_table *t;
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
long froffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either,
- natoms, system->pair_ptr->eatom,
- system->pair_ptr->vatom, thr);
-
#if defined(_OPENMP)
#pragma omp for schedule(guided)
#endif
for (i = 0; i < natoms; ++i) {
type_i = system->my_atoms[i].type;
if(type_i < 0) continue;
start_i = Start_Index(i,far_nbrs);
end_i = End_Index(i,far_nbrs);
orig_i = system->my_atoms[i].orig_id;
for (pj = start_i; pj < end_i; ++pj) {
nbr_pj = &(far_nbrs->select.far_nbr_list[pj]);
j = nbr_pj->nbr;
type_j = system->my_atoms[j].type;
if(type_j < 0) continue;
orig_j = system->my_atoms[j].orig_id;
flag = 0;
if(nbr_pj->d <= control->nonb_cut) {
if(j < natoms) flag = 1;
else if (orig_i < orig_j) flag = 1;
else if (orig_i == orig_j) {
if (nbr_pj->dvec[2] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[2]) < SMALL) {
if (nbr_pj->dvec[1] > SMALL) flag = 1;
else if (fabs(nbr_pj->dvec[1]) < SMALL && nbr_pj->dvec[0] > SMALL)
flag = 1;
}
}
}
if (flag) {
r_ij = nbr_pj->d;
tmin = MIN( type_i, type_j );
tmax = MAX( type_i, type_j );
t = &( LR[tmin][tmax] );
/* Cubic Spline Interpolation */
r = (int)(r_ij * t->inv_dx);
if( r == 0 ) ++r;
base = (double)(r+1) * t->dx;
dif = r_ij - base;
e_vdW = ((t->vdW[r].d*dif + t->vdW[r].c)*dif + t->vdW[r].b)*dif +
t->vdW[r].a;
e_ele = ((t->ele[r].d*dif + t->ele[r].c)*dif + t->ele[r].b)*dif +
t->ele[r].a;
e_ele *= system->my_atoms[i].q * system->my_atoms[j].q;
total_EvdW += e_vdW;
total_Eele += e_ele;
CEvd = ((t->CEvd[r].d*dif + t->CEvd[r].c)*dif + t->CEvd[r].b)*dif +
t->CEvd[r].a;
CEclmb = ((t->CEclmb[r].d*dif+t->CEclmb[r].c)*dif+t->CEclmb[r].b)*dif +
t->CEclmb[r].a;
CEclmb *= system->my_atoms[i].q * system->my_atoms[j].q;
/* tally into per-atom energy */
if( system->pair_ptr->evflag || system->pair_ptr->vflag_atom) {
rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x );
f_tmp = -(CEvd + CEclmb);
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, i, j, natoms, 1, e_vdW, e_ele,
f_tmp, delij[0], delij[1], delij[2], thr);
}
if( control->virial == 0 ) {
rvec_ScaledAdd( workspace->f[i], -(CEvd + CEclmb), nbr_pj->dvec );
rvec_ScaledAdd( workspace->forceReduction[froffset+j],
+(CEvd + CEclmb), nbr_pj->dvec );
}
else { // NPT, iNPT or sNPT
/* for pressure coupling, terms not related to bond order derivatives
are added directly into pressure vector/tensor */
rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );
rvec_ScaledAdd( workspace->f[i], -1., temp );
rvec_Add( workspace->forceReduction[froffset+j], temp );
rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
}
}
}
}
pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either,
system->pair_ptr->vflag_either, thr);
} // end omp parallel
data->my_en.e_vdW = total_EvdW;
data->my_en.e_ele = total_Eele;
Compute_Polarization_Energy( system, data );
}
diff --git a/src/USER-OMP/reaxc_torsion_angles_omp.cpp b/src/USER-OMP/reaxc_torsion_angles_omp.cpp
index b6920c670..4227f6276 100644
--- a/src/USER-OMP/reaxc_torsion_angles_omp.cpp
+++ b/src/USER-OMP/reaxc_torsion_angles_omp.cpp
@@ -1,479 +1,474 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "thr_data.h"
#include "reaxc_types.h"
#include "reaxc_torsion_angles_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_tool_box.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
#define MIN_SINE 1e-10
using namespace LAMMPS_NS;
// Functions defined in reaxc_torsion_angles.cpp
extern double Calculate_Omega(rvec, double, rvec, double, rvec, double, rvec, double,
three_body_interaction_data*, three_body_interaction_data*,
rvec, rvec, rvec, rvec, output_controls*);
/* ---------------------------------------------------------------------- */
void Torsion_AnglesOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists, output_controls *out_control )
{
#ifdef OMP_TIMING
double endTimeBase, startTimeBase;
startTimeBase = MPI_Wtime();
#endif
int natoms = system->n;
reax_list *bonds = (*lists) + BONDS;
reax_list *thb_intrs = (*lists) + THREE_BODIES;
double p_tor2 = system->reax_param.gp.l[23];
double p_tor3 = system->reax_param.gp.l[24];
double p_tor4 = system->reax_param.gp.l[25];
double p_cot2 = system->reax_param.gp.l[27];
double total_Etor = 0;
double total_Econ = 0;
int nthreads = control->nthreads;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+: total_Etor, total_Econ)
#endif
{
int i, j, k, l, pi, pj, pk, pl, pij, plk;
int type_i, type_j, type_k, type_l;
int start_j, end_j;
int start_pj, end_pj, start_pk, end_pk;
int num_frb_intrs = 0;
double Delta_j, Delta_k;
double r_ij, r_jk, r_kl, r_li;
double BOA_ij, BOA_jk, BOA_kl;
double exp_tor2_ij, exp_tor2_jk, exp_tor2_kl;
double exp_tor1, exp_tor3_DjDk, exp_tor4_DjDk, exp_tor34_inv;
double exp_cot2_jk, exp_cot2_ij, exp_cot2_kl;
double fn10, f11_DjDk, dfn11, fn12;
double theta_ijk, theta_jkl;
double sin_ijk, sin_jkl;
double cos_ijk, cos_jkl;
double tan_ijk_i, tan_jkl_i;
double omega, cos_omega, cos2omega, cos3omega;
rvec dcos_omega_di, dcos_omega_dj, dcos_omega_dk, dcos_omega_dl;
double CV, cmn, CEtors1, CEtors2, CEtors3, CEtors4;
double CEtors5, CEtors6, CEtors7, CEtors8, CEtors9;
double Cconj, CEconj1, CEconj2, CEconj3;
double CEconj4, CEconj5, CEconj6;
double e_tor, e_con;
rvec dvec_li;
rvec force, ext_press;
ivec rel_box_jl;
// rtensor total_rtensor, temp_rtensor;
four_body_header *fbh;
four_body_parameters *fbp;
bond_data *pbond_ij, *pbond_jk, *pbond_kl;
bond_order_data *bo_ij, *bo_jk, *bo_kl;
three_body_interaction_data *p_ijk, *p_jkl;
// Virial tallying variables
double delil[3], deljl[3], delkl[3];
double eng_tmp, fi_tmp[3], fj_tmp[3], fk_tmp[3];
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either,
- system->N, system->pair_ptr->eatom,
- system->pair_ptr->vatom, thr);
-
#if defined(_OPENMP)
#pragma omp for schedule(static)
#endif
for (j = 0; j < system->N; ++j) {
start_j = Start_Index(j, bonds);
end_j = End_Index(j, bonds);
for (pk = start_j; pk < end_j; ++pk) {
bo_jk = &( bonds->select.bond_list[pk].bo_data );
for (k = 0; k < nthreads; ++k)
bo_jk->CdboReduction[k] = 0.;
}
}
#if defined(_OPENMP)
#pragma omp for schedule(dynamic,50)
#endif
for (j = 0; j < natoms; ++j) {
type_j = system->my_atoms[j].type;
Delta_j = workspace->Delta_boc[j];
start_j = Start_Index(j, bonds);
end_j = End_Index(j, bonds);
for (pk = start_j; pk < end_j; ++pk) {
pbond_jk = &( bonds->select.bond_list[pk] );
k = pbond_jk->nbr;
bo_jk = &( pbond_jk->bo_data );
BOA_jk = bo_jk->BO - control->thb_cut;
/* see if there are any 3-body interactions involving j&k
where j is the central atom. Otherwise there is no point in
trying to form a 4-body interaction out of this neighborhood */
if (system->my_atoms[j].orig_id < system->my_atoms[k].orig_id &&
bo_jk->BO > control->thb_cut/*0*/ && Num_Entries(pk, thb_intrs)) {
pj = pbond_jk->sym_index; // pj points to j on k's list
/* do the same check as above:
are there any 3-body interactions involving k&j
where k is the central atom */
if (Num_Entries(pj, thb_intrs)) {
type_k = system->my_atoms[k].type;
Delta_k = workspace->Delta_boc[k];
r_jk = pbond_jk->d;
start_pk = Start_Index(pk, thb_intrs );
end_pk = End_Index(pk, thb_intrs );
start_pj = Start_Index(pj, thb_intrs );
end_pj = End_Index(pj, thb_intrs );
exp_tor2_jk = exp( -p_tor2 * BOA_jk );
exp_cot2_jk = exp( -p_cot2 * SQR(BOA_jk - 1.5) );
exp_tor3_DjDk = exp( -p_tor3 * (Delta_j + Delta_k) );
exp_tor4_DjDk = exp( p_tor4 * (Delta_j + Delta_k) );
exp_tor34_inv = 1.0 / (1.0 + exp_tor3_DjDk + exp_tor4_DjDk);
f11_DjDk = (2.0 + exp_tor3_DjDk) * exp_tor34_inv;
/* pick i up from j-k interaction where j is the central atom */
for (pi = start_pk; pi < end_pk; ++pi) {
p_ijk = &( thb_intrs->select.three_body_list[pi] );
pij = p_ijk->pthb; // pij is pointer to i on j's bond_list
pbond_ij = &( bonds->select.bond_list[pij] );
bo_ij = &( pbond_ij->bo_data );
if (bo_ij->BO > control->thb_cut/*0*/) {
i = p_ijk->thb;
type_i = system->my_atoms[i].type;
r_ij = pbond_ij->d;
BOA_ij = bo_ij->BO - control->thb_cut;
theta_ijk = p_ijk->theta;
sin_ijk = sin( theta_ijk );
cos_ijk = cos( theta_ijk );
//tan_ijk_i = 1. / tan( theta_ijk );
if( sin_ijk >= 0 && sin_ijk <= MIN_SINE )
tan_ijk_i = cos_ijk / MIN_SINE;
else if( sin_ijk <= 0 && sin_ijk >= -MIN_SINE )
tan_ijk_i = cos_ijk / -MIN_SINE;
else tan_ijk_i = cos_ijk / sin_ijk;
exp_tor2_ij = exp( -p_tor2 * BOA_ij );
exp_cot2_ij = exp( -p_cot2 * SQR(BOA_ij -1.5) );
/* pick l up from j-k interaction where k is the central atom */
for (pl = start_pj; pl < end_pj; ++pl) {
p_jkl = &( thb_intrs->select.three_body_list[pl] );
l = p_jkl->thb;
plk = p_jkl->pthb; //pointer to l on k's bond_list!
pbond_kl = &( bonds->select.bond_list[plk] );
bo_kl = &( pbond_kl->bo_data );
type_l = system->my_atoms[l].type;
fbh = &(system->reax_param.fbp[type_i][type_j]
[type_k][type_l]);
fbp = &(system->reax_param.fbp[type_i][type_j]
[type_k][type_l].prm[0]);
if (i != l && fbh->cnt &&
bo_kl->BO > control->thb_cut/*0*/ &&
bo_ij->BO * bo_jk->BO * bo_kl->BO > control->thb_cut/*0*/) {
++num_frb_intrs;
//fprintf(stderr,
// "%5d: %6d %6d %6d %6d\n", num_frb_intrs,
// system->my_atoms[i].orig_id,system->my_atoms[j].orig_id,
// system->my_atoms[k].orig_id,system->my_atoms[l].orig_id);
r_kl = pbond_kl->d;
BOA_kl = bo_kl->BO - control->thb_cut;
theta_jkl = p_jkl->theta;
sin_jkl = sin( theta_jkl );
cos_jkl = cos( theta_jkl );
//tan_jkl_i = 1. / tan( theta_jkl );
if( sin_jkl >= 0 && sin_jkl <= MIN_SINE )
tan_jkl_i = cos_jkl / MIN_SINE;
else if( sin_jkl <= 0 && sin_jkl >= -MIN_SINE )
tan_jkl_i = cos_jkl / -MIN_SINE;
else tan_jkl_i = cos_jkl /sin_jkl;
rvec_ScaledSum( dvec_li, 1., system->my_atoms[i].x,
-1., system->my_atoms[l].x );
r_li = rvec_Norm( dvec_li );
/* omega and its derivative */
omega = Calculate_Omega( pbond_ij->dvec, r_ij,
pbond_jk->dvec, r_jk,
pbond_kl->dvec, r_kl,
dvec_li, r_li,
p_ijk, p_jkl,
dcos_omega_di, dcos_omega_dj,
dcos_omega_dk, dcos_omega_dl,
out_control );
cos_omega = cos( omega );
cos2omega = cos( 2. * omega );
cos3omega = cos( 3. * omega );
/* end omega calculations */
/* torsion energy */
exp_tor1 = exp( fbp->p_tor1 *
SQR(2.0 - bo_jk->BO_pi - f11_DjDk) );
exp_tor2_kl = exp( -p_tor2 * BOA_kl );
exp_cot2_kl = exp( -p_cot2 * SQR(BOA_kl - 1.5) );
fn10 = (1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) *
(1.0 - exp_tor2_kl);
CV = 0.5 * ( fbp->V1 * (1.0 + cos_omega) +
fbp->V2 * exp_tor1 * (1.0 - cos2omega) +
fbp->V3 * (1.0 + cos3omega) );
total_Etor += e_tor = fn10 * sin_ijk * sin_jkl * CV;
dfn11 = (-p_tor3 * exp_tor3_DjDk +
(p_tor3 * exp_tor3_DjDk - p_tor4 * exp_tor4_DjDk) *
(2.0 + exp_tor3_DjDk) * exp_tor34_inv) *
exp_tor34_inv;
CEtors1 = sin_ijk * sin_jkl * CV;
CEtors2 = -fn10 * 2.0 * fbp->p_tor1 * fbp->V2 * exp_tor1 *
(2.0 - bo_jk->BO_pi - f11_DjDk) * (1.0 - SQR(cos_omega)) *
sin_ijk * sin_jkl;
CEtors3 = CEtors2 * dfn11;
CEtors4 = CEtors1 * p_tor2 * exp_tor2_ij *
(1.0 - exp_tor2_jk) * (1.0 - exp_tor2_kl);
CEtors5 = CEtors1 * p_tor2 *
(1.0 - exp_tor2_ij) * exp_tor2_jk * (1.0 - exp_tor2_kl);
CEtors6 = CEtors1 * p_tor2 *
(1.0 - exp_tor2_ij) * (1.0 - exp_tor2_jk) * exp_tor2_kl;
cmn = -fn10 * CV;
CEtors7 = cmn * sin_jkl * tan_ijk_i;
CEtors8 = cmn * sin_ijk * tan_jkl_i;
CEtors9 = fn10 * sin_ijk * sin_jkl *
(0.5 * fbp->V1 - 2.0 * fbp->V2 * exp_tor1 * cos_omega +
1.5 * fbp->V3 * (cos2omega + 2.0 * SQR(cos_omega)));
/* end of torsion energy */
/* 4-body conjugation energy */
fn12 = exp_cot2_ij * exp_cot2_jk * exp_cot2_kl;
//data->my_en.e_con += e_con =
total_Econ += e_con =
fbp->p_cot1 * fn12 *
(1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl);
Cconj = -2.0 * fn12 * fbp->p_cot1 * p_cot2 *
(1.0 + (SQR(cos_omega) - 1.0) * sin_ijk * sin_jkl);
CEconj1 = Cconj * (BOA_ij - 1.5e0);
CEconj2 = Cconj * (BOA_jk - 1.5e0);
CEconj3 = Cconj * (BOA_kl - 1.5e0);
CEconj4 = -fbp->p_cot1 * fn12 *
(SQR(cos_omega) - 1.0) * sin_jkl * tan_ijk_i;
CEconj5 = -fbp->p_cot1 * fn12 *
(SQR(cos_omega) - 1.0) * sin_ijk * tan_jkl_i;
CEconj6 = 2.0 * fbp->p_cot1 * fn12 *
cos_omega * sin_ijk * sin_jkl;
/* end 4-body conjugation energy */
/* FORCES */
bo_jk->Cdbopi += CEtors2;
workspace->CdDelta[j] += CEtors3;
//workspace->CdDelta[k] += CEtors3;
workspace->CdDeltaReduction[reductionOffset+k] += CEtors3;
bo_ij->Cdbo += (CEtors4 + CEconj1);
bo_jk->Cdbo += (CEtors5 + CEconj2);
//bo_kl->Cdbo += (CEtors6 + CEconj3);
bo_kl->CdboReduction[tid] += (CEtors6 + CEconj3);
if( control->virial == 0 ) {
/* dcos_theta_ijk */
rvec_ScaledAdd( workspace->f[j],
CEtors7 + CEconj4, p_ijk->dcos_dj );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+i],
CEtors7 + CEconj4, p_ijk->dcos_dk );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+k],
CEtors7 + CEconj4, p_ijk->dcos_di );
/* dcos_theta_jkl */
rvec_ScaledAdd( workspace->f[j],
CEtors8 + CEconj5, p_jkl->dcos_di );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+k],
CEtors8 + CEconj5, p_jkl->dcos_dj );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+l],
CEtors8 + CEconj5, p_jkl->dcos_dk );
/* dcos_omega */
rvec_ScaledAdd( workspace->f[j],
CEtors9 + CEconj6, dcos_omega_dj );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+i],
CEtors9 + CEconj6, dcos_omega_di );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+k],
CEtors9 + CEconj6, dcos_omega_dk );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+l],
CEtors9 + CEconj6, dcos_omega_dl );
}
else {
ivec_Sum(rel_box_jl, pbond_jk->rel_box, pbond_kl->rel_box);
/* dcos_theta_ijk */
rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_dk );
rvec_Add( workspace->forceReduction[reductionOffset+i], force );
rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
rvec_ScaledAdd( workspace->f[j],
CEtors7 + CEconj4, p_ijk->dcos_dj );
rvec_Scale( force, CEtors7 + CEconj4, p_ijk->dcos_di );
rvec_Add( workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
/* dcos_theta_jkl */
rvec_ScaledAdd( workspace->f[j],
CEtors8 + CEconj5, p_jkl->dcos_di );
rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dj );
rvec_Add( workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
rvec_Scale( force, CEtors8 + CEconj5, p_jkl->dcos_dk );
rvec_Add( workspace->forceReduction[reductionOffset+l], force );
rvec_iMultiply( ext_press, rel_box_jl, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
/* dcos_omega */
rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_di );
rvec_Add( workspace->forceReduction[reductionOffset+i], force );
rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
rvec_ScaledAdd( workspace->f[j],
CEtors9 + CEconj6, dcos_omega_dj );
rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dk );
rvec_Add( workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
rvec_Scale( force, CEtors9 + CEconj6, dcos_omega_dl );
rvec_Add( workspace->forceReduction[reductionOffset+i], force );
rvec_iMultiply( ext_press, rel_box_jl, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
}
/* tally into per-atom virials */
if( system->pair_ptr->vflag_atom || system->pair_ptr->evflag) {
// acquire vectors
rvec_ScaledSum( delil, 1., system->my_atoms[l].x,
-1., system->my_atoms[i].x );
rvec_ScaledSum( deljl, 1., system->my_atoms[l].x,
-1., system->my_atoms[j].x );
rvec_ScaledSum( delkl, 1., system->my_atoms[l].x,
-1., system->my_atoms[k].x );
// dcos_theta_ijk
rvec_Scale( fi_tmp, CEtors7 + CEconj4, p_ijk->dcos_dk );
rvec_Scale( fj_tmp, CEtors7 + CEconj4, p_ijk->dcos_dj );
rvec_Scale( fk_tmp, CEtors7 + CEconj4, p_ijk->dcos_di );
// dcos_theta_jkl
rvec_ScaledAdd( fj_tmp, CEtors8 + CEconj5, p_jkl->dcos_di );
rvec_ScaledAdd( fk_tmp, CEtors8 + CEconj5, p_jkl->dcos_dj );
// dcos_omega
rvec_ScaledAdd( fi_tmp, CEtors9 + CEconj6, dcos_omega_di );
rvec_ScaledAdd( fj_tmp, CEtors9 + CEconj6, dcos_omega_dj );
rvec_ScaledAdd( fk_tmp, CEtors9 + CEconj6, dcos_omega_dk );
// tally
eng_tmp = e_tor + e_con;
if (system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, j, k, system->n, 1,
eng_tmp, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
// NEED TO MAKE AN OMP VERSION OF THIS CALL!
if (system->pair_ptr->vflag_atom)
system->pair_ptr->v_tally4(i, j, k, l, fi_tmp, fj_tmp, fk_tmp,
delil, deljl, delkl );
}
} // pl check ends
} // pl loop ends
} // pi check ends
} // pi loop ends
} // k-j neighbor check ends
} // j<k && j-k neighbor check ends
} // pk loop ends
} // j loop
} // end omp parallel
data->my_en.e_tor = total_Etor;
data->my_en.e_con = total_Econ;
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTETORSIONANGLESBOINDEX] += (endTimeBase-startTimeBase);
#endif
}
diff --git a/src/USER-OMP/reaxc_valence_angles_omp.cpp b/src/USER-OMP/reaxc_valence_angles_omp.cpp
index 888eeab4a..6c15a529d 100644
--- a/src/USER-OMP/reaxc_valence_angles_omp.cpp
+++ b/src/USER-OMP/reaxc_valence_angles_omp.cpp
@@ -1,625 +1,616 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Website: https://www.cs.purdue.edu/puremd
Copyright (2010) Purdue University
Contributing authors:
H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama
Corresponding author:
Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc_omp.h"
#include "thr_data.h"
#include "reaxc_types.h"
#include "reaxc_valence_angles.h"
#include "reaxc_valence_angles_omp.h"
#include "reaxc_bond_orders_omp.h"
#include "reaxc_list.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
void Calculate_dCos_ThetaOMP( rvec dvec_ji, double d_ji, rvec dvec_jk, double d_jk,
rvec* dcos_theta_di,
rvec* dcos_theta_dj,
rvec* dcos_theta_dk )
{
double sqr_d_ji = SQR(d_ji);
double sqr_d_jk = SQR(d_jk);
double inv_dists = 1.0 / (d_ji * d_jk);
double inv_dists3 = inv_dists * inv_dists * inv_dists;
double dot_dvecs = dvec_ji[0]*dvec_jk[0] + dvec_ji[1]*dvec_jk[1] + dvec_ji[2]*dvec_jk[2];
double Cdot_inv3 = dot_dvecs * inv_dists3;
double csqr_jk = Cdot_inv3 * sqr_d_jk;
double csqr_ji = Cdot_inv3 * sqr_d_ji;
// Try to help compiler out by unrolling
// x-component
double dinv_jk = dvec_jk[0] * inv_dists;
double dinv_ji = dvec_ji[0] * inv_dists;
double cdev_ji = csqr_jk * dvec_ji[0];
double cdev_jk = csqr_ji * dvec_jk[0];
(*dcos_theta_di)[0] = dinv_jk - cdev_ji;
(*dcos_theta_dj)[0] = -(dinv_jk + dinv_ji) + cdev_ji + cdev_jk;
(*dcos_theta_dk)[0] = dinv_ji - cdev_jk;
// y-component
dinv_jk = dvec_jk[1] * inv_dists;
dinv_ji = dvec_ji[1] * inv_dists;
cdev_ji = csqr_jk * dvec_ji[1];
cdev_jk = csqr_ji * dvec_jk[1];
(*dcos_theta_di)[1] = dinv_jk - cdev_ji;
(*dcos_theta_dj)[1] = -(dinv_jk + dinv_ji) + cdev_ji + cdev_jk;
(*dcos_theta_dk)[1] = dinv_ji - cdev_jk;
// z-component
dinv_jk = dvec_jk[2] * inv_dists;
dinv_ji = dvec_ji[2] * inv_dists;
cdev_ji = csqr_jk * dvec_ji[2];
cdev_jk = csqr_ji * dvec_jk[2];
(*dcos_theta_di)[2] = dinv_jk - cdev_ji;
(*dcos_theta_dj)[2] = -(dinv_jk + dinv_ji) + cdev_ji + cdev_jk;
(*dcos_theta_dk)[2] = dinv_ji - cdev_jk;
}
/* ---------------------------------------------------------------------- */
/* this is a 3-body interaction in which the main role is
played by j which sits in the middle of the other two. */
void Valence_AnglesOMP( reax_system *system, control_params *control,
simulation_data *data, storage *workspace,
reax_list **lists, output_controls *out_control )
{
#ifdef OMP_TIMING
double endTimeBase, startTimeBase;
startTimeBase = MPI_Wtime();
#endif
reax_list *bonds = (*lists) + BONDS;
reax_list *thb_intrs = (*lists) + THREE_BODIES;
// Precompute and store valence_angle offsets for OpenMP code.
int * _my_offset = workspace->valence_angle_atom_myoffset;
/* global parameters used in these calculations */
double p_val6 = system->reax_param.gp.l[14];
double p_val8 = system->reax_param.gp.l[33];
double p_val9 = system->reax_param.gp.l[16];
double p_val10 = system->reax_param.gp.l[17];
double total_Eang = 0;
double total_Epen = 0;
double total_Ecoa = 0;
int nthreads = control->nthreads;
int num_thb_intrs = 0;
int TWICE = 2;
#if defined(_OPENMP)
#pragma omp parallel default(shared) reduction(+:total_Eang, total_Epen, total_Ecoa, num_thb_intrs)
#endif
{
int i, j, pi, k, pk, t;
int type_i, type_j, type_k;
int start_j, end_j, start_pk, end_pk;
int cnt, my_offset;
double temp, temp_bo_jt, pBOjt7;
double p_val1, p_val2, p_val3, p_val4, p_val5, p_val7;
double p_pen1, p_pen2, p_pen3, p_pen4;
double p_coa1, p_coa2, p_coa3, p_coa4;
double trm8, expval6, expval7, expval2theta, expval12theta, exp3ij, exp3jk;
double exp_pen2ij, exp_pen2jk, exp_pen3, exp_pen4, trm_pen34, exp_coa2;
double dSBO1, dSBO2, SBO, SBO2, CSBO2, SBOp, prod_SBO, vlpadj;
double CEval1, CEval2, CEval3, CEval4, CEval5, CEval6, CEval7, CEval8;
double CEpen1, CEpen2, CEpen3;
double e_ang, e_coa, e_pen;
double CEcoa1, CEcoa2, CEcoa3, CEcoa4, CEcoa5;
double Cf7ij, Cf7jk, Cf8j, Cf9j;
double f7_ij, f7_jk, f8_Dj, f9_Dj;
double Ctheta_0, theta_0, theta_00, theta, cos_theta, sin_theta;
double BOA_ij, BOA_jk;
rvec force, ext_press;
// rtensor temp_rtensor, total_rtensor;
// Tallying variables
double eng_tmp, fi_tmp[3], fj_tmp[3], fk_tmp[3];
double delij[3], delkj[3];
three_body_header *thbh;
three_body_parameters *thbp;
three_body_interaction_data *p_ijk, *p_kji;
bond_data *pbond_ij, *pbond_jk, *pbond_jt;
bond_order_data *bo_ij, *bo_jk, *bo_jt;
#if defined(_OPENMP)
int tid = omp_get_thread_num();
#else
int tid = 0;
#endif
long reductionOffset = (system->N * tid);
class PairReaxCOMP *pair_reax_ptr;
pair_reax_ptr = static_cast<class PairReaxCOMP*>(system->pair_ptr);
class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid);
- pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either,
- system->N, system->pair_ptr->eatom,
- system->pair_ptr->vatom, thr);
-
-
// Run through a minimal for(j<N) loop once to precompute offsets with safe number of threads
const int per_thread = thb_intrs->num_intrs / nthreads;
#if defined(_OPENMP)
#pragma omp for schedule(dynamic,50)
#endif
for (j = 0; j < system->N; ++j) {
type_j = system->my_atoms[j].type;
_my_offset[j] = 0;
if(type_j < 0) continue;
start_j = Start_Index(j, bonds);
end_j = End_Index(j, bonds);
// Always point to start of workspace to count angles
my_offset = tid * per_thread;
for (pi = start_j; pi < end_j; ++pi) {
Set_Start_Index( pi, my_offset, thb_intrs );
pbond_ij = &(bonds->select.bond_list[pi]);
bo_ij = &(pbond_ij->bo_data);
BOA_ij = bo_ij->BO - control->thb_cut;
if (BOA_ij > 0.0) {
i = pbond_ij->nbr;
/* first copy 3-body intrs from previously computed ones where i>k.
in the second for-loop below,
we compute only new 3-body intrs where i < k */
for (pk = start_j; pk < pi; ++pk) {
start_pk = Start_Index( pk, thb_intrs );
end_pk = End_Index( pk, thb_intrs );
for (t = start_pk; t < end_pk; ++t)
if (thb_intrs->select.three_body_list[t].thb == i) {
p_ijk = &(thb_intrs->select.three_body_list[my_offset] );
p_ijk->thb = bonds->select.bond_list[pk].nbr;
++my_offset;
break;
}
} // for(pk)
/* and this is the second for loop mentioned above */
for (pk = pi+1; pk < end_j; ++pk) {
pbond_jk = &(bonds->select.bond_list[pk]);
k = pbond_jk->nbr;
if (j >= system->n && i >= system->n && k >= system->n) continue;
p_ijk = &( thb_intrs->select.three_body_list[my_offset] );
p_ijk->thb = k;
++my_offset; // add this to the list of 3-body interactions
} // for(pk)
} // if()
Set_End_Index(pi, my_offset, thb_intrs );
} // for(pi)
// Confirm that thb_intrs->num_intrs / nthreads is enough to hold all angles from a single atom
if(my_offset >= (tid+1)*per_thread) {
int me;
MPI_Comm_rank(MPI_COMM_WORLD,&me);
fprintf( stderr, "step%d-ran out of space on angle_list on proc %i for atom %i:", data->step, me, j);
fprintf( stderr, " nthreads= %d, tid=%d, my_offset=%d, per_thread=%d\n", nthreads, tid, my_offset, per_thread);
fprintf( stderr, " num_intrs= %i N= %i\n",thb_intrs->num_intrs , system->N);
MPI_Abort( MPI_COMM_WORLD, INSUFFICIENT_MEMORY );
}
// Number of angles owned by this atom
_my_offset[j] = my_offset - tid * per_thread;
} // for(j)
// Wait for all threads to finish counting angles
#if defined(_OPENMP) && !defined(__NVCC__)
#pragma omp barrier
#endif
// Master thread uses angle counts to compute offsets
// This can be threaded
#if defined(_OPENMP) && !defined(__NVCC__)
#pragma omp master
#endif
{
int current_count = 0;
int m = _my_offset[0];
_my_offset[0] = current_count;
for(j=1; j<system->N; j++) {
current_count+= m;
m = _my_offset[j];
_my_offset[j] = current_count;
}
_my_offset[system->N] = current_count + m; // Used to test if last particle has any angles
}
// All threads wait till master thread finished computing offsets
#if defined(_OPENMP) && !defined(__NVCC__)
#pragma omp barrier
#endif
// Original loop, but now using precomputed offsets
// Safe to use all threads available, regardless of threads tasked above
// We also now skip over atoms that have no angles assigned
#if defined(_OPENMP)
#pragma omp for schedule(dynamic,50)//(dynamic,chunksize)//(guided)
#endif
for (j = 0; j < system->N; ++j) { // Ray: the first one with system->N
type_j = system->my_atoms[j].type;
if(type_j < 0) continue;
// Skip if no angles for this atom
if(_my_offset[j] == _my_offset[j+1]) continue;
start_j = Start_Index(j, bonds);
end_j = End_Index(j, bonds);
type_j = system->my_atoms[j].type;
my_offset = _my_offset[j];
p_val3 = system->reax_param.sbp[ type_j ].p_val3;
p_val5 = system->reax_param.sbp[ type_j ].p_val5;
SBOp = 0, prod_SBO = 1;
for (t = start_j; t < end_j; ++t) {
bo_jt = &(bonds->select.bond_list[t].bo_data);
SBOp += (bo_jt->BO_pi + bo_jt->BO_pi2);
temp = SQR( bo_jt->BO );
temp *= temp;
temp *= temp;
prod_SBO *= exp( -temp );
}
// modifications to match Adri's code - 09/01/09
if( workspace->vlpex[j] >= 0 ){
vlpadj = 0;
dSBO2 = prod_SBO - 1;
}
else{
vlpadj = workspace->nlp[j];
dSBO2 = (prod_SBO - 1) * (1 - p_val8 * workspace->dDelta_lp[j]);
}
SBO = SBOp + (1 - prod_SBO) * (-workspace->Delta_boc[j] - p_val8 * vlpadj);
dSBO1 = -8 * prod_SBO * ( workspace->Delta_boc[j] + p_val8 * vlpadj );
if( SBO <= 0 )
SBO2 = 0, CSBO2 = 0;
else if( SBO > 0 && SBO <= 1 ) {
SBO2 = pow( SBO, p_val9 );
CSBO2 = p_val9 * pow( SBO, p_val9 - 1 );
}
else if( SBO > 1 && SBO < 2 ) {
SBO2 = 2 - pow( 2-SBO, p_val9 );
CSBO2 = p_val9 * pow( 2 - SBO, p_val9 - 1 );
}
else
SBO2 = 2, CSBO2 = 0;
expval6 = exp( p_val6 * workspace->Delta_boc[j] );
for (pi = start_j; pi < end_j; ++pi) {
Set_Start_Index( pi, my_offset, thb_intrs );
pbond_ij = &(bonds->select.bond_list[pi]);
bo_ij = &(pbond_ij->bo_data);
BOA_ij = bo_ij->BO - control->thb_cut;
if (BOA_ij > 0.0) {
i = pbond_ij->nbr;
type_i = system->my_atoms[i].type;
/* first copy 3-body intrs from previously computed ones where i>k.
in the second for-loop below,
we compute only new 3-body intrs where i < k */
for (pk = start_j; pk < pi; ++pk) {
start_pk = Start_Index( pk, thb_intrs );
end_pk = End_Index( pk, thb_intrs );
for (t = start_pk; t < end_pk; ++t)
if (thb_intrs->select.three_body_list[t].thb == i) {
p_ijk = &(thb_intrs->select.three_body_list[my_offset] );
p_kji = &(thb_intrs->select.three_body_list[t]);
p_ijk->thb = bonds->select.bond_list[pk].nbr;
p_ijk->pthb = pk;
p_ijk->theta = p_kji->theta;
rvec_Copy( p_ijk->dcos_di, p_kji->dcos_dk );
rvec_Copy( p_ijk->dcos_dj, p_kji->dcos_dj );
rvec_Copy( p_ijk->dcos_dk, p_kji->dcos_di );
++my_offset;
++num_thb_intrs;
break;
}
} // for(pk)
/* and this is the second for loop mentioned above */
for (pk = pi+1; pk < end_j; ++pk) {
pbond_jk = &(bonds->select.bond_list[pk]);
bo_jk = &(pbond_jk->bo_data);
BOA_jk = bo_jk->BO - control->thb_cut;
k = pbond_jk->nbr;
type_k = system->my_atoms[k].type;
p_ijk = &( thb_intrs->select.three_body_list[my_offset] );
// Fix by Sudhir
// if (BOA_jk <= 0) continue;
if (j >= system->n && i >= system->n && k >= system->n) continue;
Calculate_Theta( pbond_ij->dvec, pbond_ij->d,
pbond_jk->dvec, pbond_jk->d,
&theta, &cos_theta );
Calculate_dCos_ThetaOMP( pbond_ij->dvec, pbond_ij->d,
pbond_jk->dvec, pbond_jk->d,
&(p_ijk->dcos_di), &(p_ijk->dcos_dj),
&(p_ijk->dcos_dk) );
p_ijk->thb = k;
p_ijk->pthb = pk;
p_ijk->theta = theta;
sin_theta = sin( theta );
if( sin_theta < 1.0e-5 )
sin_theta = 1.0e-5;
++my_offset; // add this to the list of 3-body interactions
++num_thb_intrs;
if ((j < system->n) && (BOA_jk > 0.0) &&
(bo_ij->BO > control->thb_cut) &&
(bo_jk->BO > control->thb_cut) &&
(bo_ij->BO * bo_jk->BO > control->thb_cutsq)) {
thbh = &( system->reax_param.thbp[ type_i ][ type_j ][ type_k ] );
for (cnt = 0; cnt < thbh->cnt; ++cnt) {
if( fabs(thbh->prm[cnt].p_val1) > 0.001 ) {
thbp = &( thbh->prm[cnt] );
/* ANGLE ENERGY */
p_val1 = thbp->p_val1;
p_val2 = thbp->p_val2;
p_val4 = thbp->p_val4;
p_val7 = thbp->p_val7;
theta_00 = thbp->theta_00;
exp3ij = exp( -p_val3 * pow( BOA_ij, p_val4 ) );
f7_ij = 1.0 - exp3ij;
Cf7ij = p_val3 * p_val4 * pow( BOA_ij, p_val4 - 1.0 ) * exp3ij;
exp3jk = exp( -p_val3 * pow( BOA_jk, p_val4 ) );
f7_jk = 1.0 - exp3jk;
Cf7jk = p_val3 * p_val4 * pow( BOA_jk, p_val4 - 1.0 ) * exp3jk;
expval7 = exp( -p_val7 * workspace->Delta_boc[j] );
trm8 = 1.0 + expval6 + expval7;
f8_Dj = p_val5 - ( (p_val5 - 1.0) * (2.0 + expval6) / trm8 );
Cf8j = ( (1.0 - p_val5) / SQR(trm8) ) *
( p_val6 * expval6 * trm8 -
(2.0 + expval6) * ( p_val6*expval6 - p_val7*expval7 ) );
theta_0 = 180.0 - theta_00 * (1.0 -
exp(-p_val10 * (2.0 - SBO2)));
theta_0 = DEG2RAD( theta_0 );
expval2theta = exp( -p_val2 * SQR(theta_0 - theta) );
if (p_val1 >= 0)
expval12theta = p_val1 * (1.0 - expval2theta);
else // To avoid linear Me-H-Me angles (6/6/06)
expval12theta = p_val1 * -expval2theta;
CEval1 = Cf7ij * f7_jk * f8_Dj * expval12theta;
CEval2 = Cf7jk * f7_ij * f8_Dj * expval12theta;
CEval3 = Cf8j * f7_ij * f7_jk * expval12theta;
CEval4 = -2.0 * p_val1 * p_val2 * f7_ij * f7_jk * f8_Dj *
expval2theta * (theta_0 - theta);
Ctheta_0 = p_val10 * DEG2RAD(theta_00) *
exp( -p_val10 * (2.0 - SBO2) );
CEval5 = -CEval4 * Ctheta_0 * CSBO2;
CEval6 = CEval5 * dSBO1;
CEval7 = CEval5 * dSBO2;
CEval8 = -CEval4 / sin_theta;
total_Eang += e_ang =
f7_ij * f7_jk * f8_Dj * expval12theta;
/* END ANGLE ENERGY*/
/* PENALTY ENERGY */
p_pen1 = thbp->p_pen1;
p_pen2 = system->reax_param.gp.l[19];
p_pen3 = system->reax_param.gp.l[20];
p_pen4 = system->reax_param.gp.l[21];
exp_pen2ij = exp( -p_pen2 * SQR( BOA_ij - 2.0 ) );
exp_pen2jk = exp( -p_pen2 * SQR( BOA_jk - 2.0 ) );
exp_pen3 = exp( -p_pen3 * workspace->Delta[j] );
exp_pen4 = exp( p_pen4 * workspace->Delta[j] );
trm_pen34 = 1.0 + exp_pen3 + exp_pen4;
f9_Dj = ( 2.0 + exp_pen3 ) / trm_pen34;
Cf9j = ( -p_pen3 * exp_pen3 * trm_pen34 -
(2.0 + exp_pen3) * ( -p_pen3 * exp_pen3 +
p_pen4 * exp_pen4 ) ) /
SQR( trm_pen34 );
total_Epen += e_pen =
p_pen1 * f9_Dj * exp_pen2ij * exp_pen2jk;
CEpen1 = e_pen * Cf9j / f9_Dj;
temp = -2.0 * p_pen2 * e_pen;
CEpen2 = temp * (BOA_ij - 2.0);
CEpen3 = temp * (BOA_jk - 2.0);
/* END PENALTY ENERGY */
/* COALITION ENERGY */
p_coa1 = thbp->p_coa1;
p_coa2 = system->reax_param.gp.l[2];
p_coa3 = system->reax_param.gp.l[38];
p_coa4 = system->reax_param.gp.l[30];
exp_coa2 = exp( p_coa2 * workspace->Delta_val[j] );
total_Ecoa += e_coa =
p_coa1 / (1. + exp_coa2) *
exp( -p_coa3 * SQR(workspace->total_bond_order[i]-BOA_ij) ) *
exp( -p_coa3 * SQR(workspace->total_bond_order[k]-BOA_jk) ) *
exp( -p_coa4 * SQR(BOA_ij - 1.5) ) *
exp( -p_coa4 * SQR(BOA_jk - 1.5) );
CEcoa1 = -2 * p_coa4 * (BOA_ij - 1.5) * e_coa;
CEcoa2 = -2 * p_coa4 * (BOA_jk - 1.5) * e_coa;
CEcoa3 = -p_coa2 * exp_coa2 * e_coa / (1 + exp_coa2);
CEcoa4 = -2 * p_coa3 *
(workspace->total_bond_order[i]-BOA_ij) * e_coa;
CEcoa5 = -2 * p_coa3 *
(workspace->total_bond_order[k]-BOA_jk) * e_coa;
/* END COALITION ENERGY */
/* FORCES */
bo_ij->Cdbo += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4));
bo_jk->Cdbo += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5));
workspace->CdDelta[j] += ((CEval3 + CEval7) + CEpen1 + CEcoa3);
workspace->CdDeltaReduction[reductionOffset+i] += CEcoa4;
workspace->CdDeltaReduction[reductionOffset+k] += CEcoa5;
for (t = start_j; t < end_j; ++t) {
pbond_jt = &( bonds->select.bond_list[t] );
bo_jt = &(pbond_jt->bo_data);
temp_bo_jt = bo_jt->BO;
temp = CUBE( temp_bo_jt );
pBOjt7 = temp * temp * temp_bo_jt;
bo_jt->Cdbo += (CEval6 * pBOjt7);
bo_jt->Cdbopi += CEval5;
bo_jt->Cdbopi2 += CEval5;
}
if( control->virial == 0 ) {
rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+i],
CEval8, p_ijk->dcos_di );
rvec_ScaledAdd( workspace->forceReduction[reductionOffset+k],
CEval8, p_ijk->dcos_dk );
}
else {
/* terms not related to bond order derivatives are
added directly into forces and pressure vector/tensor */
rvec_Scale( force, CEval8, p_ijk->dcos_di );
rvec_Add( workspace->forceReduction[reductionOffset+i], force );
rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );
rvec_Scale( force, CEval8, p_ijk->dcos_dk );
rvec_Add( workspace->forceReduction[reductionOffset+k], force );
rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
rvec_Add( workspace->my_ext_pressReduction[tid], ext_press );
}
/* tally into per-atom virials */
if( system->pair_ptr->vflag_atom || system->pair_ptr->evflag) {
/* Acquire vectors */
rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
-1., system->my_atoms[j].x );
rvec_ScaledSum( delkj, 1., system->my_atoms[k].x,
-1., system->my_atoms[j].x );
rvec_Scale( fi_tmp, -CEval8, p_ijk->dcos_di );
rvec_Scale( fj_tmp, -CEval8, p_ijk->dcos_dj );
rvec_Scale( fk_tmp, -CEval8, p_ijk->dcos_dk );
eng_tmp = e_ang + e_pen + e_coa;
if( system->pair_ptr->evflag)
pair_reax_ptr->ev_tally_thr_proxy(system->pair_ptr, j, j, system->N, 1,
eng_tmp, 0.0, 0.0, 0.0, 0.0, 0.0, thr);
if( system->pair_ptr->vflag_atom)
// NEED TO MAKE AN OMP VERSION OF THIS CALL!
system->pair_ptr->v_tally3( i, j, k, fi_tmp, fk_tmp, delij, delkj);
}
} // if(p_val1>0.001)
} // for(cnt)
} // if(j<n && BOA_jk>0)
} // for(pk)
} // if(BOA_ij>0)
Set_End_Index(pi, my_offset, thb_intrs );
} // for(pi)
} // for(j)
-
- pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either,
- system->pair_ptr->vflag_either, thr);
} // end omp parallel
data->my_en.e_ang = total_Eang;
data->my_en.e_pen = total_Epen;
data->my_en.e_coa = total_Ecoa;
if( num_thb_intrs >= thb_intrs->num_intrs * DANGER_ZONE ) {
workspace->realloc.num_3body = num_thb_intrs * TWICE;
if( num_thb_intrs > thb_intrs->num_intrs ) {
fprintf( stderr, "step%d-ran out of space on angle_list: top=%d, max=%d",
data->step, num_thb_intrs, thb_intrs->num_intrs );
MPI_Abort( MPI_COMM_WORLD, INSUFFICIENT_MEMORY );
}
}
#ifdef OMP_TIMING
endTimeBase = MPI_Wtime();
ompTimingData[COMPUTEVALENCEANGLESBOINDEX] += (endTimeBase-startTimeBase);
#endif
}
diff --git a/src/USER-OMP/thr_data.cpp b/src/USER-OMP/thr_data.cpp
index 28fd27f9b..9d0b657b3 100644
--- a/src/USER-OMP/thr_data.cpp
+++ b/src/USER-OMP/thr_data.cpp
@@ -1,369 +1,379 @@
/* -------------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
per-thread data management for LAMMPS
------------------------------------------------------------------------- */
#include "thr_data.h"
#include <string.h>
#include <stdio.h>
#include "memory.h"
#include "timer.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ThrData::ThrData(int tid, Timer *t)
: _f(0),_torque(0),_erforce(0),_de(0),_drho(0),_mu(0),_lambda(0),_rhoB(0),
- _D_values(0),_rho(0),_fp(0),_rho1d(0),_drho1d(0),_tid(tid), _timer(t)
+ _D_values(0),_rho(0),_fp(0),_rho1d(0),_drho1d(0),_rho1d_6(0),_drho1d_6(0),
+ _tid(tid), _timer(t)
{
_timer_active = 0;
}
/* ---------------------------------------------------------------------- */
void ThrData::check_tid(int tid)
{
if (tid != _tid)
fprintf(stderr,"WARNING: external and internal tid mismatch %d != %d\n",tid,_tid);
}
/* ---------------------------------------------------------------------- */
void ThrData::_stamp(enum Timer::ttype flag)
{
// do nothing until it gets set to 0 in ::setup()
if (_timer_active < 0) return;
if (flag == Timer::START) {
_timer_active = 1;
}
if (_timer_active) _timer->stamp(flag);
}
/* ---------------------------------------------------------------------- */
double ThrData::get_time(enum Timer::ttype flag)
{
if (_timer)
return _timer->get_wall(flag);
else
return 0.0;
}
/* ---------------------------------------------------------------------- */
void ThrData::init_force(int nall, double **f, double **torque,
double *erforce, double *de, double *drho)
{
eng_vdwl=eng_coul=eng_bond=eng_angle=eng_dihed=eng_imprp=eng_kspce=0.0;
memset(virial_pair,0,6*sizeof(double));
memset(virial_bond,0,6*sizeof(double));
memset(virial_angle,0,6*sizeof(double));
memset(virial_dihed,0,6*sizeof(double));
memset(virial_imprp,0,6*sizeof(double));
memset(virial_kspce,0,6*sizeof(double));
eatom_pair=eatom_bond=eatom_angle=eatom_dihed=eatom_imprp=eatom_kspce=NULL;
vatom_pair=vatom_bond=vatom_angle=vatom_dihed=vatom_imprp=vatom_kspce=NULL;
if (nall >= 0 && f) {
_f = f + _tid*nall;
memset(&(_f[0][0]),0,nall*3*sizeof(double));
} else _f = NULL;
if (nall >= 0 && torque) {
_torque = torque + _tid*nall;
memset(&(_torque[0][0]),0,nall*3*sizeof(double));
} else _torque = NULL;
if (nall >= 0 && erforce) {
_erforce = erforce + _tid*nall;
memset(&(_erforce[0]),0,nall*sizeof(double));
} else _erforce = NULL;
if (nall >= 0 && de) {
_de = de + _tid*nall;
memset(&(_de[0]),0,nall*sizeof(double));
} else _de = NULL;
if (nall >= 0 && drho) {
_drho = drho + _tid*nall;
memset(&(_drho[0]),0,nall*sizeof(double));
} else _drho = NULL;
}
/* ----------------------------------------------------------------------
set up and clear out locally managed per atom arrays
------------------------------------------------------------------------- */
void ThrData::init_eam(int nall, double *rho)
{
if (nall >= 0 && rho) {
_rho = rho + _tid*nall;
memset(_rho, 0, nall*sizeof(double));
}
}
/* ---------------------------------------------------------------------- */
void ThrData::init_adp(int nall, double *rho, double **mu, double **lambda)
{
init_eam(nall, rho);
if (nall >= 0 && mu && lambda) {
_mu = mu + _tid*nall;
_lambda = lambda + _tid*nall;
memset(&(_mu[0][0]), 0, nall*3*sizeof(double));
memset(&(_lambda[0][0]), 0, nall*6*sizeof(double));
}
}
/* ---------------------------------------------------------------------- */
void ThrData::init_cdeam(int nall, double *rho, double *rhoB, double *D_values)
{
init_eam(nall, rho);
if (nall >= 0 && rhoB && D_values) {
_rhoB = rhoB + _tid*nall;
_D_values = D_values + _tid*nall;
memset(_rhoB, 0, nall*sizeof(double));
memset(_D_values, 0, nall*sizeof(double));
}
}
/* ---------------------------------------------------------------------- */
void ThrData::init_eim(int nall, double *rho, double *fp)
{
init_eam(nall, rho);
if (nall >= 0 && fp) {
_fp = fp + _tid*nall;
memset(_fp,0,nall*sizeof(double));
}
}
/* ----------------------------------------------------------------------
if order > 0 : set up per thread storage for PPPM
if order < 0 : free per thread storage for PPPM
------------------------------------------------------------------------- */
#if defined(FFT_SINGLE)
typedef float FFT_SCALAR;
#else
typedef double FFT_SCALAR;
#endif
void ThrData::init_pppm(int order, Memory *memory)
{
FFT_SCALAR **rho1d, **drho1d;
if (order > 0) {
- memory->create2d_offset(rho1d,3,-order/2,order/2,"thr_data:rho1d");
- memory->create2d_offset(drho1d,3,-order/2,order/2,"thr_data:drho1d");
- _rho1d = static_cast<void *>(rho1d);
- _drho1d = static_cast<void *>(drho1d);
+ rho1d = static_cast<FFT_SCALAR **>(_rho1d);
+ drho1d = static_cast<FFT_SCALAR **>(_drho1d);
+ if (rho1d) memory->destroy2d_offset(rho1d,-order/2);
+ if (drho1d) memory->destroy2d_offset(drho1d,-order/2);
+ memory->create2d_offset(rho1d,3,-order/2,order/2,"thr_data:rho1d");
+ memory->create2d_offset(drho1d,3,-order/2,order/2,"thr_data:drho1d");
+ _rho1d = static_cast<void *>(rho1d);
+ _drho1d = static_cast<void *>(drho1d);
} else {
order = -order;
rho1d = static_cast<FFT_SCALAR **>(_rho1d);
drho1d = static_cast<FFT_SCALAR **>(_drho1d);
- memory->destroy2d_offset(rho1d,-order/2);
- memory->destroy2d_offset(drho1d,-order/2);
+ if (rho1d) memory->destroy2d_offset(rho1d,-order/2);
+ if (drho1d) memory->destroy2d_offset(drho1d,-order/2);
+ _rho1d = NULL;
+ _drho1d = NULL;
}
}
/* ----------------------------------------------------------------------
if order > 0 : set up per thread storage for PPPM
if order < 0 : free per thread storage for PPPM
------------------------------------------------------------------------- */
#if defined(FFT_SINGLE)
typedef float FFT_SCALAR;
#else
typedef double FFT_SCALAR;
#endif
void ThrData::init_pppm_disp(int order_6, Memory *memory)
{
FFT_SCALAR **rho1d_6, **drho1d_6;
if (order_6 > 0) {
- memory->create2d_offset(rho1d_6,3,-order_6/2,order_6/2,"thr_data:rho1d_6");
- memory->create2d_offset(drho1d_6,3,-order_6/2,order_6/2,"thr_data:drho1d_6");
- _rho1d_6 = static_cast<void *>(rho1d_6);
- _drho1d_6 = static_cast<void *>(drho1d_6);
+ rho1d_6 = static_cast<FFT_SCALAR **>(_rho1d_6);
+ drho1d_6 = static_cast<FFT_SCALAR **>(_drho1d_6);
+ if (rho1d_6) memory->destroy2d_offset(rho1d_6,-order_6/2);
+ if (drho1d_6) memory->destroy2d_offset(drho1d_6,-order_6/2);
+ memory->create2d_offset(rho1d_6,3,-order_6/2,order_6/2,"thr_data:rho1d_6");
+ memory->create2d_offset(drho1d_6,3,-order_6/2,order_6/2,"thr_data:drho1d_6");
+ _rho1d_6 = static_cast<void *>(rho1d_6);
+ _drho1d_6 = static_cast<void *>(drho1d_6);
} else {
order_6 = -order_6;
rho1d_6 = static_cast<FFT_SCALAR **>(_rho1d_6);
drho1d_6 = static_cast<FFT_SCALAR **>(_drho1d_6);
- memory->destroy2d_offset(rho1d_6,-order_6/2);
- memory->destroy2d_offset(drho1d_6,-order_6/2);
+ if (rho1d_6) memory->destroy2d_offset(rho1d_6,-order_6/2);
+ if (drho1d_6) memory->destroy2d_offset(drho1d_6,-order_6/2);
}
}
-
/* ----------------------------------------------------------------------
compute global pair virial via summing F dot r over own & ghost atoms
at this point, only pairwise forces have been accumulated in atom->f
------------------------------------------------------------------------- */
void ThrData::virial_fdotr_compute(double **x, int nlocal, int nghost, int nfirst)
{
// sum over force on all particles including ghosts
if (nfirst < 0) {
int nall = nlocal + nghost;
for (int i = 0; i < nall; i++) {
virial_pair[0] += _f[i][0]*x[i][0];
virial_pair[1] += _f[i][1]*x[i][1];
virial_pair[2] += _f[i][2]*x[i][2];
virial_pair[3] += _f[i][1]*x[i][0];
virial_pair[4] += _f[i][2]*x[i][0];
virial_pair[5] += _f[i][2]*x[i][1];
}
// neighbor includegroup flag is set
// sum over force on initial nfirst particles and ghosts
} else {
int nall = nfirst;
for (int i = 0; i < nall; i++) {
virial_pair[0] += _f[i][0]*x[i][0];
virial_pair[1] += _f[i][1]*x[i][1];
virial_pair[2] += _f[i][2]*x[i][2];
virial_pair[3] += _f[i][1]*x[i][0];
virial_pair[4] += _f[i][2]*x[i][0];
virial_pair[5] += _f[i][2]*x[i][1];
}
nall = nlocal + nghost;
for (int i = nlocal; i < nall; i++) {
virial_pair[0] += _f[i][0]*x[i][0];
virial_pair[1] += _f[i][1]*x[i][1];
virial_pair[2] += _f[i][2]*x[i][2];
virial_pair[3] += _f[i][1]*x[i][0];
virial_pair[4] += _f[i][2]*x[i][0];
virial_pair[5] += _f[i][2]*x[i][1];
}
}
}
/* ---------------------------------------------------------------------- */
double ThrData::memory_usage()
{
double bytes = (7 + 6*6) * sizeof(double);
bytes += 2 * sizeof(double*);
bytes += 4 * sizeof(int);
return bytes;
}
/* additional helper functions */
// reduce per thread data into the first part of the data
// array that is used for the non-threaded parts and reset
// the temporary storage to 0.0. this routine depends on
// multi-dimensional arrays like force stored in this order
// x1,y1,z1,x2,y2,z2,...
// we need to post a barrier to wait until all threads are done
// with writing to the array .
void LAMMPS_NS::data_reduce_thr(double *dall, int nall, int nthreads, int ndim, int tid)
{
#if defined(_OPENMP)
// NOOP in single-threaded execution.
if (nthreads == 1) return;
#pragma omp barrier
{
const int nvals = ndim*nall;
const int idelta = nvals/nthreads + 1;
const int ifrom = tid*idelta;
const int ito = ((ifrom + idelta) > nvals) ? nvals : (ifrom + idelta);
#if defined(USER_OMP_NO_UNROLL)
if (ifrom < nvals) {
int m = 0;
for (m = ifrom; m < ito; ++m) {
for (int n = 1; n < nthreads; ++n) {
dall[m] += dall[n*nvals + m];
dall[n*nvals + m] = 0.0;
}
}
}
#else
// this if protects against having more threads than atoms
if (ifrom < nvals) {
int m = 0;
// for architectures that have L1 D-cache line sizes of 64 bytes
// (8 doubles) wide, explicitly unroll this loop to compute 8
// contiguous values in the array at a time
// -- modify this code based on the size of the cache line
double t0, t1, t2, t3, t4, t5, t6, t7;
for (m = ifrom; m < (ito-7); m+=8) {
t0 = dall[m ];
t1 = dall[m+1];
t2 = dall[m+2];
t3 = dall[m+3];
t4 = dall[m+4];
t5 = dall[m+5];
t6 = dall[m+6];
t7 = dall[m+7];
for (int n = 1; n < nthreads; ++n) {
t0 += dall[n*nvals + m ];
t1 += dall[n*nvals + m+1];
t2 += dall[n*nvals + m+2];
t3 += dall[n*nvals + m+3];
t4 += dall[n*nvals + m+4];
t5 += dall[n*nvals + m+5];
t6 += dall[n*nvals + m+6];
t7 += dall[n*nvals + m+7];
dall[n*nvals + m ] = 0.0;
dall[n*nvals + m+1] = 0.0;
dall[n*nvals + m+2] = 0.0;
dall[n*nvals + m+3] = 0.0;
dall[n*nvals + m+4] = 0.0;
dall[n*nvals + m+5] = 0.0;
dall[n*nvals + m+6] = 0.0;
dall[n*nvals + m+7] = 0.0;
}
dall[m ] = t0;
dall[m+1] = t1;
dall[m+2] = t2;
dall[m+3] = t3;
dall[m+4] = t4;
dall[m+5] = t5;
dall[m+6] = t6;
dall[m+7] = t7;
}
// do the last < 8 values
for (; m < ito; m++) {
for (int n = 1; n < nthreads; ++n) {
dall[m] += dall[n*nvals + m];
dall[n*nvals + m] = 0.0;
}
}
}
#endif
}
#else
// NOOP in non-threaded execution.
return;
#endif
}
diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp
index e8b23c761..6bbbcdb8e 100644
--- a/src/USER-QUIP/pair_quip.cpp
+++ b/src/USER-QUIP/pair_quip.cpp
@@ -1,288 +1,320 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Albert Bartok (Cambridge University)
Aidan Thompson (Sandia, athomps@sandia.gov)
------------------------------------------------------------------------- */
#include <mpi.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_quip.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "memory.h"
#include "error.h"
#include "domain.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairQUIP::PairQUIP(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
no_virial_fdotr_compute = 1;
+ manybody_flag = 1;
}
PairQUIP::~PairQUIP()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
delete [] quip_potential;
}
}
void PairQUIP::compute(int eflag, int vflag)
{
int inum, jnum, sum_num_neigh, ii, jj, i, iquip;
int *ilist;
int *jlist;
int *numneigh, **firstneigh;
int *quip_num_neigh, *quip_neigh, *atomic_numbers;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int ntotal = nlocal + nghost;
int *type = atom->type;
+ tagint *tag = atom->tag;
double **x = atom->x;
double **f = atom->f;
double *quip_local_e, *quip_force, *quip_local_virial, *quip_virial, quip_energy, *lattice;
if (eflag || vflag) ev_setup(eflag,vflag);
else ev_unset();
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
sum_num_neigh = 0;
quip_num_neigh = new int [inum];
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
quip_num_neigh[ii] = numneigh[i];
sum_num_neigh += numneigh[i];
}
quip_neigh = new int [sum_num_neigh];
iquip = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
- quip_neigh[iquip] = jlist[jj]+1;
+ quip_neigh[iquip] = (jlist[jj] & NEIGHMASK) + 1;
iquip++;
}
}
atomic_numbers = new int[ntotal];
for (ii = 0; ii < ntotal; ii++)
atomic_numbers[ii] = map[type[ii]-1];
quip_local_e = new double [ntotal];
quip_force = new double [ntotal*3];
quip_local_virial = new double [ntotal*9];
quip_virial = new double [9];
lattice = new double [9];
lattice[0] = domain->xprd;
lattice[1] = 0.0;
lattice[2] = 0.0;
lattice[3] = domain->xy;
lattice[4] = domain->yprd;
lattice[5] = 0.0;
lattice[6] = domain->xz;
lattice[7] = domain->yz;
lattice[8] = domain->zprd;
- quip_lammps_wrapper
- (&nlocal,&nghost,atomic_numbers,
- &inum,&sum_num_neigh,ilist,
- quip_num_neigh,quip_neigh,lattice,
- quip_potential,&n_quip_potential,&x[0][0],
- &quip_energy,quip_local_e,quip_virial,quip_local_virial,quip_force);
+#if defined(LAMMPS_BIGBIG)
+ int *tmptag = new int[ntotal];
+ int tmplarge = 0, toolarge = 0;
+ for (ii = 0; ii < ntotal; ++ii) {
+ tmptag[ii] = tag[ii];
+ if (tag[ii] > MAXSMALLINT) tmplarge=1;
+ }
+ MPI_Allreduce(&tmplarge,&toolarge,1,MPI_INT,MPI_MAX,world);
+ if (toolarge > 0)
+ error->all(FLERR,"Pair style quip does not support 64-bit atom IDs");
+
+ quip_lammps_wrapper(&nlocal,&nghost,atomic_numbers,tmptag,
+ &inum,&sum_num_neigh,ilist,
+ quip_num_neigh,quip_neigh,lattice,
+ quip_potential,&n_quip_potential,&x[0][0],
+ &quip_energy,quip_local_e,quip_virial,
+ quip_local_virial,quip_force);
+
+ delete[] tmptag;
+#else
+ quip_lammps_wrapper(&nlocal,&nghost,atomic_numbers,tag,
+ &inum,&sum_num_neigh,ilist,
+ quip_num_neigh,quip_neigh,lattice,
+ quip_potential,&n_quip_potential,&x[0][0],
+ &quip_energy,quip_local_e,quip_virial,
+ quip_local_virial,quip_force);
+#endif
+
iquip = 0;
for (ii = 0; ii < ntotal; ii++) {
for( jj = 0; jj < 3; jj++ ) {
- f[ii][jj] = quip_force[iquip];
+ f[ii][jj] += quip_force[iquip];
iquip++;
}
}
if(eflag_global) {
eng_vdwl = quip_energy;
}
if(eflag_atom) {
for (ii = 0; ii < ntotal; ii++) {
eatom[ii] = quip_local_e[ii];
}
}
if (vflag_global) {
virial[0] = quip_virial[0];
virial[1] = quip_virial[4];
virial[2] = quip_virial[8];
virial[3] = (quip_virial[3] + quip_virial[1])*0.5;
virial[4] = (quip_virial[2] + quip_virial[6])*0.5;
virial[5] = (quip_virial[5] + quip_virial[7])*0.5;
}
if(vflag_atom) {
int iatom = 0;
for(ii = 0; ii < ntotal; ii++) {
vatom[ii][0] += quip_local_virial[iatom+0];
vatom[ii][1] += quip_local_virial[iatom+4];
vatom[ii][2] += quip_local_virial[iatom+8];
vatom[ii][3] += (quip_local_virial[iatom+3] +
- quip_local_virial[iatom+1])*0.5;
+ quip_local_virial[iatom+1])*0.5;
vatom[ii][4] += (quip_local_virial[iatom+2] +
- quip_local_virial[iatom+6])*0.5;
+ quip_local_virial[iatom+6])*0.5;
vatom[ii][5] += (quip_local_virial[iatom+5] +
- quip_local_virial[iatom+7])*0.5;
+ quip_local_virial[iatom+7])*0.5;
iatom += 9;
}
}
delete [] atomic_numbers;
delete [] quip_num_neigh;
delete [] quip_neigh;
delete [] quip_local_e;
delete [] quip_force;
delete [] quip_virial;
delete [] quip_local_virial;
delete [] lattice;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairQUIP::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
+ if (strcmp(force->pair_style,"hybrid") == 0)
+ error->all(FLERR,"Pair style quip is only compatible with hybrid/overlay");
+
+ // check if linked to the correct QUIP library API version
+ // as of 2017-07-19 this is API_VERSION 1
+ if (quip_lammps_api_version() != 1)
+ error->all(FLERR,"QUIP LAMMPS wrapper API version is not compatible "
+ "with this version of LAMMPS");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairQUIP::allocate()
{
allocated = 1;
int n = atom->ntypes;
setflag = memory->create(setflag,n+1,n+1,"pair:setflag");
cutsq = memory->create(cutsq,n+1,n+1,"pair:cutsq");
map = new int[n];
}
void PairQUIP::coeff(int narg, char **arg)
{
if (!allocated) allocate();
int n = atom->ntypes;
// ensure I,J args are * *
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++) {
setflag[i][j] = 1;
}
}
if( narg != (4+n) ) {
char str[1024];
sprintf(str,"Number of arguments %d is not correct, it should be %d", narg, 4+n);
error->all(FLERR,str);
}
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
n_quip_file = strlen(arg[2]);
- quip_file = new char[n_quip_file];
+ quip_file = new char[n_quip_file+1];
strcpy(quip_file,arg[2]);
n_quip_string = strlen(arg[3]);
- quip_string = new char[n_quip_string];
+ quip_string = new char[n_quip_string+1];
strcpy(quip_string,arg[3]);
for (int i = 4; i < narg; i++) {
if( 0 == sscanf(arg[i],"%d",&map[i-4])) {
char str[1024];
sprintf(str,"Incorrect atomic number %s at position %d",arg[i],i);
error->all(FLERR,str);
}
}
// Initialise potential
// First call initialises potential via the fortran code in memory, and returns the necessary size
// of quip_potential. This behaviour is invoked by setting n_potential_quip to 0.
n_quip_potential = 0;
quip_potential = new int[0];
quip_lammps_potential_initialise(quip_potential,&n_quip_potential,&cutoff,quip_file,&n_quip_file,quip_string,&n_quip_string);
delete [] quip_potential;
// Allocate quip_potential integer array. This initialise call will transfer the location of the
// previously initialised potential to the quip_potential variable, and we will use it as a handle
// when calling the actual calculation routine. We return the cutoff as well.
quip_potential = new int[n_quip_potential];
quip_lammps_potential_initialise(quip_potential,&n_quip_potential,&cutoff,quip_file,&n_quip_file,quip_string,&n_quip_string);
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairQUIP::init_style()
{
// Require newton pair on
if (force->newton_pair != 1)
error->all(FLERR,"Pair style quip requires newton pair on");
// Initialise neighbour list
int irequest_full = neighbor->request(this);
neighbor->requests[irequest_full]->id = 1;
neighbor->requests[irequest_full]->half = 0;
neighbor->requests[irequest_full]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairQUIP::init_one(int i, int j)
{
return cutoff;
}
diff --git a/src/USER-QUIP/pair_quip.h b/src/USER-QUIP/pair_quip.h
index f86df015e..debdc2cb8 100644
--- a/src/USER-QUIP/pair_quip.h
+++ b/src/USER-QUIP/pair_quip.h
@@ -1,64 +1,65 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef PAIR_CLASS
PairStyle(quip,PairQUIP)
#else
#ifndef LMP_PAIR_QUIP_H
#define LMP_PAIR_QUIP_H
#include "pair.h"
extern "C"
{
- void quip_lammps_wrapper(int*, int*, int*,
+ int quip_lammps_api_version();
+ void quip_lammps_wrapper(int*, int*, int*, int*,
int*, int*, int*,
int*, int*, double*,
int*, int*, double*,
double*, double*, double*, double*, double*);
- void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*);
+ void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*);
}
namespace LAMMPS_NS {
class PairQUIP : public Pair {
public:
PairQUIP(class LAMMPS *);
~PairQUIP();
void compute(int, int);
void settings(int, char **);
void coeff(int, char **);
void init_style();
double init_one(int, int);
void allocate();
private:
double cutoff;
int* quip_potential;
int n_quip_potential;
int *map; // mapping from atom types to elements
char *quip_file; // mapping from atom types to elements
int n_quip_file;
char *quip_string; // mapping from atom types to elements
int n_quip_string;
};
}
#endif
#endif
diff --git a/src/USER-REAXC/fix_reaxc_species.cpp b/src/USER-REAXC/fix_reaxc_species.cpp
index 62b3bff93..181c9bcd3 100644
--- a/src/USER-REAXC/fix_reaxc_species.cpp
+++ b/src/USER-REAXC/fix_reaxc_species.cpp
@@ -1,991 +1,993 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Ray Shan (Sandia, tnshan@sandia.gov)
Oleg Sergeev (VNIIA, sergeev@vniia.ru)
------------------------------------------------------------------------- */
#include <stdlib.h>
#include <math.h>
#include "atom.h"
#include <string.h>
#include "fix_ave_atom.h"
#include "fix_reaxc_species.h"
#include "domain.h"
#include "update.h"
#include "pair_reaxc.h"
#include "modify.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "comm.h"
#include "force.h"
#include "compute.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
#include "reaxc_list.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixReaxCSpecies::FixReaxCSpecies(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 7) error->all(FLERR,"Illegal fix reax/c/species command");
force_reneighbor = 0;
vector_flag = 1;
size_vector = 2;
extvector = 0;
peratom_flag = 1;
size_peratom_cols = 0;
peratom_freq = 1;
nvalid = -1;
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
ntypes = atom->ntypes;
nevery = atoi(arg[3]);
nrepeat = atoi(arg[4]);
global_freq = nfreq = atoi(arg[5]);
comm_forward = 4;
if (nevery <= 0 || nrepeat <= 0 || nfreq <= 0)
error->all(FLERR,"Illegal fix reax/c/species command");
if (nfreq % nevery || nrepeat*nevery > nfreq)
error->all(FLERR,"Illegal fix reax/c/species command");
// Neighbor lists must stay unchanged during averaging of bonds,
// but may be updated when no averaging is performed.
int rene_flag = 0;
if (nevery * nrepeat != 1 && (nfreq % neighbor->every != 0 || neighbor->every < nevery * nrepeat)) {
int newneighborevery = nevery * nrepeat;
while (nfreq % newneighborevery != 0 && newneighborevery <= nfreq / 2)
newneighborevery++;
if (nfreq % newneighborevery != 0)
newneighborevery = nfreq;
neighbor->every = newneighborevery;
rene_flag = 1;
}
if (nevery * nrepeat != 1 && (neighbor->delay != 0 || neighbor->dist_check != 0)) {
neighbor->delay = 0;
neighbor->dist_check = 0;
rene_flag = 1;
}
if (me == 0 && rene_flag) {
char str[128];
sprintf(str,"Resetting reneighboring criteria for fix reax/c/species");
error->warning(FLERR,str);
}
tmparg = NULL;
memory->create(tmparg,4,4,"reax/c/species:tmparg");
strcpy(tmparg[0],arg[3]);
strcpy(tmparg[1],arg[4]);
strcpy(tmparg[2],arg[5]);
if (me == 0) {
char *suffix = strrchr(arg[6],'.');
if (suffix && strcmp(suffix,".gz") == 0) {
#ifdef LAMMPS_GZIP
char gzip[128];
sprintf(gzip,"gzip -6 > %s",arg[6]);
#ifdef _WIN32
fp = _popen(gzip,"wb");
#else
fp = popen(gzip,"w");
#endif
#else
error->one(FLERR,"Cannot open gzipped file");
#endif
} else fp = fopen(arg[6],"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix reax/c/species file %s",arg[6]);
error->one(FLERR,str);
}
}
x0 = NULL;
clusterID = NULL;
int ntmp = 1;
memory->create(x0,ntmp,"reax/c/species:x0");
memory->create(clusterID,ntmp,"reax/c/species:clusterID");
vector_atom = clusterID;
BOCut = NULL;
Name = NULL;
MolName = NULL;
MolType = NULL;
NMol = NULL;
nd = NULL;
molmap = NULL;
nmax = 0;
setupflag = 0;
// set default bond order cutoff
int n, i, j, itype, jtype;
double bo_cut;
bg_cut = 0.30;
n = ntypes+1;
memory->create(BOCut,n,n,"reax/c/species:BOCut");
for (i = 1; i < n; i ++)
for (j = 1; j < n; j ++)
BOCut[i][j] = bg_cut;
// optional args
eletype = NULL;
ele = filepos = NULL;
eleflag = posflag = padflag = 0;
singlepos_opened = multipos_opened = 0;
multipos = 0;
posfreq = 0;
int iarg = 7;
while (iarg < narg) {
// set BO cutoff
if (strcmp(arg[iarg],"cutoff") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal fix reax/c/species command");
itype = atoi(arg[iarg+1]);
jtype = atoi(arg[iarg+2]);
bo_cut = atof(arg[iarg+3]);
if (itype > ntypes || jtype > ntypes)
error->all(FLERR,"Illegal fix reax/c/species command");
if (itype <= 0 || jtype <= 0)
error->all(FLERR,"Illegal fix reax/c/species command");
if (bo_cut > 1.0 || bo_cut < 0.0)
error->all(FLERR,"Illegal fix reax/c/species command");
BOCut[itype][jtype] = bo_cut;
BOCut[jtype][itype] = bo_cut;
iarg += 4;
// modify element type names
} else if (strcmp(arg[iarg],"element") == 0) {
if (iarg+ntypes+1 > narg) error->all(FLERR,"Illegal fix reax/c/species command");
eletype = (char**) malloc(ntypes*sizeof(char*));
+ int len;
for (int i = 0; i < ntypes; i ++) {
- eletype[i] = (char*) malloc(2*sizeof(char));
+ len = strlen(arg[iarg+1+i])+1;
+ eletype[i] = (char*) malloc(len*sizeof(char));
strcpy(eletype[i],arg[iarg+1+i]);
}
eleflag = 1;
iarg += ntypes + 1;
// position of molecules
} else if (strcmp(arg[iarg],"position") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix reax/c/species command");
posflag = 1;
posfreq = atoi(arg[iarg+1]);
if (posfreq < nfreq || (posfreq%nfreq != 0))
error->all(FLERR,"Illegal fix reax/c/species command");
filepos = new char[255];
strcpy(filepos,arg[iarg+2]);
if (strchr(filepos,'*')) {
multipos = 1;
} else {
if (me == 0) {
pos = fopen(filepos, "w");
if (pos == NULL) error->one(FLERR,"Cannot open fix reax/c/species position file");
}
singlepos_opened = 1;
multipos = 0;
}
iarg += 3;
} else error->all(FLERR,"Illegal fix reax/c/species command");
}
if (!eleflag) {
memory->create(ele,ntypes+1,"reax/c/species:ele");
ele[0]='C';
if (ntypes > 1)
ele[1]='H';
if (ntypes > 2)
ele[2]='O';
if (ntypes > 3)
ele[3]='N';
}
vector_nmole = 0;
vector_nspec = 0;
}
/* ---------------------------------------------------------------------- */
FixReaxCSpecies::~FixReaxCSpecies()
{
memory->destroy(ele);
memory->destroy(BOCut);
memory->destroy(clusterID);
memory->destroy(x0);
memory->destroy(nd);
memory->destroy(Name);
memory->destroy(NMol);
memory->destroy(MolType);
memory->destroy(MolName);
memory->destroy(tmparg);
if (filepos)
delete [] filepos;
if (me == 0) fclose(fp);
if (me == 0 && posflag && multipos_opened) fclose(pos);
modify->delete_compute("SPECATOM");
modify->delete_fix("SPECBOND");
}
/* ---------------------------------------------------------------------- */
int FixReaxCSpecies::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::setup(int vflag)
{
ntotal = static_cast<int> (atom->natoms);
if (Name == NULL)
memory->create(Name,ntypes,"reax/c/species:Name");
post_integrate();
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::init()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use fix reax/c/species unless atoms have IDs");
reaxc = (PairReaxC *) force->pair_match("reax/c",0);
if (reaxc == NULL) error->all(FLERR,"Cannot use fix reax/c/species without "
"pair_style reax/c, reax/c/kk, or reax/c/omp");
reaxc->fixspecies_flag = 1;
// reset next output timestep if not yet set or timestep has been reset
if (nvalid != update->ntimestep)
nvalid = update->ntimestep+nfreq;
// check if this fix has been called twice
int count = 0;
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"reax/c/species") == 0) count++;
if (count > 1 && comm->me == 0)
error->warning(FLERR,"More than one fix reax/c/species");
if (!setupflag) {
// create a compute to store properties
create_compute();
// create a fix to point to fix_ave_atom for averaging stored properties
create_fix();
setupflag = 1;
}
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::create_compute()
{
int narg;
char **args;
narg = 34;
args = new char*[narg];
args[0] = (char *) "SPECATOM";
args[1] = (char *) "all";
args[2] = (char *) "SPEC/ATOM";
args[3] = (char *) "q";
args[4] = (char *) "x";
args[5] = (char *) "y";
args[6] = (char *) "z";
args[7] = (char *) "vx";
args[8] = (char *) "vy";
args[9] = (char *) "vz";
args[10] = (char *) "abo01";
args[11] = (char *) "abo02";
args[12] = (char *) "abo03";
args[13] = (char *) "abo04";
args[14] = (char *) "abo05";
args[15] = (char *) "abo06";
args[16] = (char *) "abo07";
args[17] = (char *) "abo08";
args[18] = (char *) "abo09";
args[19] = (char *) "abo10";
args[20] = (char *) "abo11";
args[21] = (char *) "abo12";
args[22] = (char *) "abo13";
args[23] = (char *) "abo14";
args[24] = (char *) "abo15";
args[25] = (char *) "abo16";
args[26] = (char *) "abo17";
args[27] = (char *) "abo18";
args[28] = (char *) "abo19";
args[29] = (char *) "abo20";
args[30] = (char *) "abo21";
args[31] = (char *) "abo22";
args[32] = (char *) "abo23";
args[33] = (char *) "abo24";
modify->add_compute(narg,args);
delete [] args;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::create_fix()
{
int narg;
char **args;
narg = 37;
args = new char*[narg];
args[0] = (char *) "SPECBOND";
args[1] = (char *) "all";
args[2] = (char *) "ave/atom";
args[3] = tmparg[0];
args[4] = tmparg[1];
args[5] = tmparg[2];
args[6] = (char *) "c_SPECATOM[1]"; // q, array_atoms[i][0]
args[7] = (char *) "c_SPECATOM[2]"; // x, 1
args[8] = (char *) "c_SPECATOM[3]"; // y, 2
args[9] = (char *) "c_SPECATOM[4]"; // z, 3
args[10] = (char *) "c_SPECATOM[5]"; // vx, 4
args[11] = (char *) "c_SPECATOM[6]"; // vy, 5
args[12] = (char *) "c_SPECATOM[7]"; // vz, 6
args[13] = (char *) "c_SPECATOM[8]"; // abo01, 7
args[14] = (char *) "c_SPECATOM[9]";
args[15] = (char *) "c_SPECATOM[10]";
args[16] = (char *) "c_SPECATOM[11]";
args[17] = (char *) "c_SPECATOM[12]";
args[18] = (char *) "c_SPECATOM[13]";
args[19] = (char *) "c_SPECATOM[14]";
args[20] = (char *) "c_SPECATOM[15]";
args[21] = (char *) "c_SPECATOM[16]";
args[22] = (char *) "c_SPECATOM[17]";
args[23] = (char *) "c_SPECATOM[18]";
args[24] = (char *) "c_SPECATOM[19]"; // abo12, 18
args[25] = (char *) "c_SPECATOM[20]";
args[26] = (char *) "c_SPECATOM[21]";
args[27] = (char *) "c_SPECATOM[22]";
args[28] = (char *) "c_SPECATOM[23]";
args[29] = (char *) "c_SPECATOM[24]";
args[30] = (char *) "c_SPECATOM[25]";
args[31] = (char *) "c_SPECATOM[26]";
args[32] = (char *) "c_SPECATOM[27]";
args[33] = (char *) "c_SPECATOM[28]";
args[34] = (char *) "c_SPECATOM[29]";
args[35] = (char *) "c_SPECATOM[30]";
args[36] = (char *) "c_SPECATOM[31]";
modify->add_fix(narg,args);
f_SPECBOND = (FixAveAtom *) modify->fix[modify->nfix-1];
delete [] args;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::post_integrate()
{
Output_ReaxC_Bonds(update->ntimestep,fp);
if (me == 0) fflush(fp);
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::Output_ReaxC_Bonds(bigint ntimestep, FILE *fp)
{
int Nmole, Nspec;
// point to fix_ave_atom
f_SPECBOND->end_of_step();
if (ntimestep != nvalid) return;
nlocal = atom->nlocal;
if (atom->nmax > nmax) {
nmax = atom->nmax;
memory->destroy(x0);
memory->destroy(clusterID);
memory->create(x0,nmax,"reax/c/species:x0");
memory->create(clusterID,nmax,"reax/c/species:clusterID");
vector_atom = clusterID;
}
for (int i = 0; i < nmax; i++) {
x0[i].x = x0[i].y = x0[i].z = 0.0;
}
Nmole = Nspec = 0;
FindMolecule();
SortMolecule (Nmole);
FindSpecies(Nmole, Nspec);
vector_nmole = Nmole;
vector_nspec = Nspec;
if (me == 0 && ntimestep >= 0)
WriteFormulas (Nmole, Nspec);
if (posflag && ((ntimestep)%posfreq==0)) {
WritePos(Nmole, Nspec);
if (me == 0) fflush(pos);
}
nvalid += nfreq;
}
/* ---------------------------------------------------------------------- */
AtomCoord FixReaxCSpecies::chAnchor(AtomCoord in1, AtomCoord in2)
{
if (in1.x < in2.x)
return in1;
else if (in1.x == in2.x) {
if (in1.y < in2.y)
return in1;
else if (in1.y == in2.y) {
if (in1.z < in2.z)
return in1;
}
}
return in2;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::FindMolecule ()
{
int i,j,ii,jj,inum,itype,jtype,loop,looptot;
int change,done,anychange;
int *mask = atom->mask;
int *ilist;
double bo_tmp,bo_cut;
double **spec_atom = f_SPECBOND->array_atom;
inum = reaxc->list->inum;
ilist = reaxc->list->ilist;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit) {
clusterID[i] = atom->tag[i];
x0[i].x = spec_atom[i][1];
x0[i].y = spec_atom[i][2];
x0[i].z = spec_atom[i][3];
}
else clusterID[i] = 0.0;
}
loop = 0;
while (1) {
comm->forward_comm_fix(this);
loop ++;
change = 0;
while (1) {
done = 1;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (!(mask[i] & groupbit)) continue;
itype = atom->type[i];
for (jj = 0; jj < MAXSPECBOND; jj++) {
j = reaxc->tmpid[i][jj];
if ((j == 0) || (j < i)) continue;
if (!(mask[j] & groupbit)) continue;
if (clusterID[i] == clusterID[j]
&& x0[i].x == x0[j].x
&& x0[i].y == x0[j].y
&& x0[i].z == x0[j].z) continue;
jtype = atom->type[j];
bo_cut = BOCut[itype][jtype];
bo_tmp = spec_atom[i][jj+7];
if (bo_tmp > bo_cut) {
clusterID[i] = clusterID[j] = MIN(clusterID[i], clusterID[j]);
x0[i] = x0[j] = chAnchor(x0[i], x0[j]);
done = 0;
}
}
}
if (!done) change = 1;
if (done) break;
}
MPI_Allreduce(&change,&anychange,1,MPI_INT,MPI_MAX,world);
if (!anychange) break;
MPI_Allreduce(&loop,&looptot,1,MPI_INT,MPI_SUM,world);
if (looptot >= 400*nprocs) break;
}
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::SortMolecule(int &Nmole)
{
memory->destroy(molmap);
molmap = NULL;
int n, idlo, idhi;
int *mask =atom->mask;
int lo = ntotal;
int hi = -ntotal;
int flag = 0;
for (n = 0; n < nlocal; n++) {
if (!(mask[n] & groupbit)) continue;
if (clusterID[n] == 0.0) flag = 1;
lo = MIN(lo,nint(clusterID[n]));
hi = MAX(hi,nint(clusterID[n]));
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && me == 0)
error->warning(FLERR,"Atom with cluster ID = 0 included in "
"fix reax/c/species group");
MPI_Allreduce(&lo,&idlo,1,MPI_INT,MPI_MIN,world);
MPI_Allreduce(&hi,&idhi,1,MPI_INT,MPI_MAX,world);
if (idlo == ntotal)
if (me == 0)
error->warning(FLERR,"Atom with cluster ID = maxmol "
"included in fix reax/c/species group");
int nlen = idhi - idlo + 1;
memory->create(molmap,nlen,"reax/c/species:molmap");
for (n = 0; n < nlen; n++) molmap[n] = 0;
for (n = 0; n < nlocal; n++) {
if (!(mask[n] & groupbit)) continue;
molmap[nint(clusterID[n])-idlo] = 1;
}
int *molmapall;
memory->create(molmapall,nlen,"reax/c/species:molmapall");
MPI_Allreduce(molmap,molmapall,nlen,MPI_INT,MPI_MAX,world);
Nmole = 0;
for (n = 0; n < nlen; n++) {
if (molmapall[n]) molmap[n] = Nmole++;
else molmap[n] = -1;
}
memory->destroy(molmapall);
flag = 0;
for (n = 0; n < nlocal; n++) {
if (mask[n] & groupbit) continue;
if (nint(clusterID[n]) < idlo || nint(clusterID[n]) > idhi) continue;
if (molmap[nint(clusterID[n])-idlo] >= 0) flag = 1;
}
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->warning(FLERR,"One or more cluster has atoms not in group");
for (n = 0; n < nlocal; n++) {
if (!(mask[n] & groupbit)) continue;
clusterID[n] = molmap[nint(clusterID[n])-idlo] + 1;
}
memory->destroy(molmap);
molmap = NULL;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::FindSpecies(int Nmole, int &Nspec)
{
int k, l, m, n, itype, cid;
int flag_identity, flag_mol, flag_spec;
int flag_tmp;
int *mask =atom->mask;
int *Nameall, *NMolall;
memory->destroy(MolName);
MolName = NULL;
memory->create(MolName,Nmole*(ntypes+1),"reax/c/species:MolName");
memory->destroy(NMol);
NMol = NULL;
memory->create(NMol,Nmole,"reax/c/species:NMol");
for (m = 0; m < Nmole; m ++)
NMol[m] = 1;
memory->create(Nameall,ntypes,"reax/c/species:Nameall");
memory->create(NMolall,Nmole,"reax/c/species:NMolall");
for (m = 1, Nspec = 0; m <= Nmole; m ++) {
for (n = 0; n < ntypes; n ++) Name[n] = 0;
for (n = 0, flag_mol = 0; n < nlocal; n ++) {
if (!(mask[n] & groupbit)) continue;
cid = nint(clusterID[n]);
if (cid == m) {
itype = atom->type[n]-1;
Name[itype] ++;
flag_mol = 1;
}
}
MPI_Allreduce(&flag_mol,&flag_tmp,1,MPI_INT,MPI_MAX,world);
flag_mol = flag_tmp;
MPI_Allreduce(Name,Nameall,ntypes,MPI_INT,MPI_SUM,world);
for (n = 0; n < ntypes; n++) Name[n] = Nameall[n];
if (flag_mol == 1) {
flag_identity = 1;
for (k = 0; k < Nspec; k ++) {
flag_spec=0;
for (l = 0; l < ntypes; l ++)
if (MolName[ntypes*k+l] != Name[l]) flag_spec = 1;
if (flag_spec == 0) NMol[k] ++;
flag_identity *= flag_spec;
}
if (Nspec == 0 || flag_identity == 1) {
for (l = 0; l < ntypes; l ++)
MolName[ntypes*Nspec+l] = Name[l];
Nspec ++;
}
}
}
memory->destroy(NMolall);
memory->destroy(Nameall);
memory->destroy(nd);
nd = NULL;
memory->create(nd,Nspec,"reax/c/species:nd");
memory->destroy(MolType);
MolType = NULL;
memory->create(MolType,Nspec*(ntypes+2),"reax/c/species:MolType");
}
/* ---------------------------------------------------------------------- */
int FixReaxCSpecies::CheckExistence(int id, int ntypes)
{
int i, j, molid, flag;
for (i = 0; i < Nmoltype; i ++) {
flag = 0;
for (j = 0; j < ntypes; j ++) {
molid = MolType[ntypes * i + j];
if (molid != MolName[ntypes * id + j]) flag = 1;
}
if (flag == 0) return i;
}
for (i = 0; i < ntypes; i ++)
MolType[ntypes * Nmoltype + i] = MolName[ntypes *id + i];
Nmoltype ++;
return Nmoltype - 1;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::WriteFormulas(int Nmole, int Nspec)
{
int i, j, itemp;
bigint ntimestep = update->ntimestep;
fprintf(fp,"# Timestep No_Moles No_Specs ");
Nmoltype = 0;
for (i = 0; i < Nspec; i ++)
nd[i] = CheckExistence(i, ntypes);
for (i = 0; i < Nmoltype; i ++) {
for (j = 0;j < ntypes; j ++) {
itemp = MolType[ntypes * i + j];
if (itemp != 0) {
if (eletype) fprintf(fp,"%s",eletype[j]);
else fprintf(fp,"%c",ele[j]);
if (itemp != 1) fprintf(fp,"%d",itemp);
}
}
fprintf(fp,"\t");
}
fprintf(fp,"\n");
fprintf(fp,BIGINT_FORMAT,ntimestep);
fprintf(fp,"%11d%11d\t",Nmole,Nspec);
for (i = 0; i < Nmoltype; i ++)
fprintf(fp," %d\t",NMol[i]);
fprintf(fp,"\n");
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::OpenPos()
{
char *filecurrent;
bigint ntimestep = update->ntimestep;
filecurrent = (char*) malloc((strlen(filepos)+16)*sizeof(char));
char *ptr = strchr(filepos,'*');
*ptr = '\0';
if (padflag == 0)
sprintf(filecurrent,"%s" BIGINT_FORMAT "%s",
filepos,ntimestep,ptr+1);
else {
char bif[8],pad[16];
strcpy(bif,BIGINT_FORMAT);
sprintf(pad,"%%s%%0%d%s%%s",padflag,&bif[1]);
sprintf(filecurrent,pad,filepos,ntimestep,ptr+1);
}
*ptr = '*';
if (me == 0) {
pos = fopen(filecurrent, "w");
if (pos == NULL) error->one(FLERR,"Cannot open fix reax/c/species position file");
} else pos = NULL;
multipos_opened = 1;
free(filecurrent);
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::WritePos(int Nmole, int Nspec)
{
int i, itype, cid;
int count, count_tmp, m, n, k;
int *Nameall;
int *mask =atom->mask;
double avq, avq_tmp, avx[3], avx_tmp, box[3], halfbox[3];
double **spec_atom = f_SPECBOND->array_atom;
if (multipos) OpenPos();
box[0] = domain->boxhi[0] - domain->boxlo[0];
box[1] = domain->boxhi[1] - domain->boxlo[1];
box[2] = domain->boxhi[2] - domain->boxlo[2];
for (int j = 0; j < 3; j++)
halfbox[j] = box[j] / 2;
if (me == 0) {
fprintf(pos,"Timestep " BIGINT_FORMAT " NMole %d NSpec %d xlo %f "
"xhi %f ylo %f yhi %f zlo %f zhi %f\n",
update->ntimestep,Nmole, Nspec,
domain->boxlo[0],domain->boxhi[0],
domain->boxlo[1],domain->boxhi[1],
domain->boxlo[2],domain->boxhi[2]);
fprintf(pos,"ID\tAtom_Count\tType\tAve_q\t\tCoM_x\t\tCoM_y\t\tCoM_z\n");
}
Nameall = NULL;
memory->create(Nameall,ntypes,"reax/c/species:Nameall");
for (m = 1; m <= Nmole; m ++) {
count = 0;
avq = 0.0;
for (n = 0; n < 3; n++)
avx[n] = 0.0;
for (n = 0; n < ntypes; n ++)
Name[n] = 0;
for (i = 0; i < nlocal; i ++) {
if (!(mask[i] & groupbit)) continue;
cid = nint(clusterID[i]);
if (cid == m) {
itype = atom->type[i]-1;
Name[itype] ++;
count ++;
avq += spec_atom[i][0];
if ((x0[i].x - spec_atom[i][1]) > halfbox[0])
spec_atom[i][1] += box[0];
if ((spec_atom[i][1] - x0[i].x) > halfbox[0])
spec_atom[i][1] -= box[0];
if ((x0[i].y - spec_atom[i][2]) > halfbox[1])
spec_atom[i][2] += box[1];
if ((spec_atom[i][2] - x0[i].y) > halfbox[1])
spec_atom[i][2] -= box[1];
if ((x0[i].z - spec_atom[i][3]) > halfbox[2])
spec_atom[i][3] += box[2];
if ((spec_atom[i][3] - x0[i].z) > halfbox[2])
spec_atom[i][3] -= box[2];
for (n = 0; n < 3; n++)
avx[n] += spec_atom[i][n+1];
}
}
avq_tmp = 0.0;
MPI_Allreduce(&avq,&avq_tmp,1,MPI_DOUBLE,MPI_SUM,world);
avq = avq_tmp;
for (n = 0; n < 3; n++) {
avx_tmp = 0.0;
MPI_Reduce(&avx[n],&avx_tmp,1,MPI_DOUBLE,MPI_SUM,0,world);
avx[n] = avx_tmp;
}
MPI_Reduce(&count,&count_tmp,1,MPI_INT,MPI_SUM,0,world);
count = count_tmp;
MPI_Reduce(Name,Nameall,ntypes,MPI_INT,MPI_SUM,0,world);
for (n = 0; n < ntypes; n++) Name[n] = Nameall[n];
if (me == 0) {
fprintf(pos,"%d\t%d\t",m,count);
for (n = 0; n < ntypes; n++) {
if (Name[n] != 0) {
if (eletype) fprintf(pos,"%s",eletype[n]);
else fprintf(pos,"%c",ele[n]);
if (Name[n] != 1) fprintf(pos,"%d",Name[n]);
}
}
if (count > 0) {
avq /= count;
for (k = 0; k < 3; k++) {
avx[k] /= count;
if (avx[k] >= domain->boxhi[k])
avx[k] -= box[k];
if (avx[k] < domain->boxlo[k])
avx[k] += box[k];
avx[k] -= domain->boxlo[k];
avx[k] /= box[k];
}
fprintf(pos,"\t%.8f \t%.8f \t%.8f \t%.8f",
avq,avx[0],avx[1],avx[2]);
}
fprintf(pos,"\n");
}
}
if (me == 0 && !multipos) fprintf(pos,"#\n");
memory->destroy(Nameall);
}
/* ---------------------------------------------------------------------- */
double FixReaxCSpecies::compute_vector(int n)
{
if (n == 0)
return vector_nmole;
if (n == 1)
return vector_nspec;
return 0.0;
}
/* ---------------------------------------------------------------------- */
int FixReaxCSpecies::nint(const double &r)
{
int i = 0;
if (r>0.0) i = static_cast<int>(r+0.5);
else if (r<0.0) i = static_cast<int>(r-0.5);
return i;
}
/* ---------------------------------------------------------------------- */
int FixReaxCSpecies::pack_forward_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m] = clusterID[j];
buf[m+1] = x0[j].x;
buf[m+2] = x0[j].y;
buf[m+3] = x0[j].z;
m += 4;
}
return m;
}
/* ---------------------------------------------------------------------- */
void FixReaxCSpecies::unpack_forward_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
clusterID[i] = buf[m];
x0[i].x = buf[m+1];
x0[i].y = buf[m+2];
x0[i].z = buf[m+3];
m += 4;
}
}
/* ---------------------------------------------------------------------- */
double FixReaxCSpecies::memory_usage()
{
double bytes;
bytes = 4*nmax*sizeof(double); // clusterID + x0
return bytes;
}
/* ---------------------------------------------------------------------- */
diff --git a/src/USER-REAXC/pair_reaxc.cpp b/src/USER-REAXC/pair_reaxc.cpp
index bf3b2e446..0f4bd49cc 100644
--- a/src/USER-REAXC/pair_reaxc.cpp
+++ b/src/USER-REAXC/pair_reaxc.cpp
@@ -1,839 +1,842 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Hasan Metin Aktulga, Purdue University
(now at Lawrence Berkeley National Laboratory, hmaktulga@lbl.gov)
Per-atom energy/virial added by Ray Shan (Sandia)
Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added by
Ray Shan (Sandia)
Hybrid and hybrid/overlay compatibility added by Ray Shan (Sandia)
------------------------------------------------------------------------- */
#include "pair_reaxc.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "modify.h"
#include "fix.h"
#include "fix_reaxc.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
#include "reaxc_types.h"
#include "reaxc_allocate.h"
#include "reaxc_control.h"
#include "reaxc_ffield.h"
#include "reaxc_forces.h"
#include "reaxc_init_md.h"
#include "reaxc_io_tools.h"
#include "reaxc_list.h"
#include "reaxc_lookup.h"
#include "reaxc_reset_tools.h"
#include "reaxc_traj.h"
#include "reaxc_vector.h"
#include "fix_reaxc_bonds.h"
using namespace LAMMPS_NS;
static const char cite_pair_reax_c[] =
"pair reax/c command:\n\n"
"@Article{Aktulga12,\n"
" author = {H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama},\n"
" title = {Parallel reactive molecular dynamics: Numerical methods and algorithmic techniques},\n"
" journal = {Parallel Computing},\n"
" year = 2012,\n"
" volume = 38,\n"
" pages = {245--259}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp)
{
if (lmp->citeme) lmp->citeme->add(cite_pair_reax_c);
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
ghostneigh = 1;
system = (reax_system *)
memory->smalloc(sizeof(reax_system),"reax:system");
control = (control_params *)
memory->smalloc(sizeof(control_params),"reax:control");
data = (simulation_data *)
memory->smalloc(sizeof(simulation_data),"reax:data");
workspace = (storage *)
memory->smalloc(sizeof(storage),"reax:storage");
lists = (reax_list *)
memory->smalloc(LIST_N * sizeof(reax_list),"reax:lists");
+ memset(lists,0,LIST_N * sizeof(reax_list));
out_control = (output_controls *)
memory->smalloc(sizeof(output_controls),"reax:out_control");
mpi_data = (mpi_datatypes *)
memory->smalloc(sizeof(mpi_datatypes),"reax:mpi");
MPI_Comm_rank(world,&system->my_rank);
system->my_coords[0] = 0;
system->my_coords[1] = 0;
system->my_coords[2] = 0;
system->num_nbrs = 0;
system->n = 0; // my atoms
system->N = 0; // mine + ghosts
system->bigN = 0; // all atoms in the system
system->local_cap = 0;
system->total_cap = 0;
system->gcell_cap = 0;
system->bndry_cuts.ghost_nonb = 0;
system->bndry_cuts.ghost_hbond = 0;
system->bndry_cuts.ghost_bond = 0;
system->bndry_cuts.ghost_cutoff = 0;
system->my_atoms = NULL;
system->pair_ptr = this;
+ system->omp_active = 0;
+
fix_reax = NULL;
tmpid = NULL;
tmpbo = NULL;
nextra = 14;
pvector = new double[nextra];
setup_flag = 0;
fixspecies_flag = 0;
nmax = 0;
}
/* ---------------------------------------------------------------------- */
PairReaxC::~PairReaxC()
{
if (copymode) return;
if (fix_reax) modify->delete_fix("REAXC");
if (setup_flag) {
Close_Output_Files( system, control, out_control, mpi_data );
// deallocate reax data-structures
if( control->tabulate ) Deallocate_Lookup_Tables( system );
if( control->hbond_cut > 0 ) Delete_List( lists+HBONDS, world );
Delete_List( lists+BONDS, world );
Delete_List( lists+THREE_BODIES, world );
Delete_List( lists+FAR_NBRS, world );
DeAllocate_Workspace( control, workspace );
DeAllocate_System( system );
}
memory->destroy( system );
memory->destroy( control );
memory->destroy( data );
memory->destroy( workspace );
memory->destroy( lists );
memory->destroy( out_control );
memory->destroy( mpi_data );
// deallocate interface storage
if( allocated ) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
delete [] map;
delete [] chi;
delete [] eta;
delete [] gamma;
}
memory->destroy(tmpid);
memory->destroy(tmpbo);
delete [] pvector;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::allocate( )
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cutghost,n+1,n+1,"pair:cutghost");
map = new int[n+1];
chi = new double[n+1];
eta = new double[n+1];
gamma = new double[n+1];
}
/* ---------------------------------------------------------------------- */
void PairReaxC::settings(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal pair_style command");
// read name of control file or use default controls
if (strcmp(arg[0],"NULL") == 0) {
strcpy( control->sim_name, "simulate" );
control->ensemble = 0;
out_control->energy_update_freq = 0;
control->tabulate = 0;
control->reneighbor = 1;
control->vlist_cut = control->nonb_cut;
control->bond_cut = 5.;
control->hbond_cut = 7.50;
control->thb_cut = 0.001;
control->thb_cutsq = 0.00001;
control->bg_cut = 0.3;
// Initialize for when omp style included
control->nthreads = 1;
out_control->write_steps = 0;
out_control->traj_method = 0;
strcpy( out_control->traj_title, "default_title" );
out_control->atom_info = 0;
out_control->bond_info = 0;
out_control->angle_info = 0;
} else Read_Control_File(arg[0], control, out_control);
// default values
qeqflag = 1;
control->lgflag = 0;
control->enobondsflag = 1;
system->mincap = MIN_CAP;
system->safezone = SAFE_ZONE;
system->saferzone = SAFER_ZONE;
// process optional keywords
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"checkqeq") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_style reax/c command");
if (strcmp(arg[iarg+1],"yes") == 0) qeqflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) qeqflag = 0;
else error->all(FLERR,"Illegal pair_style reax/c command");
iarg += 2;
} else if (strcmp(arg[iarg],"enobonds") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_style reax/c command");
if (strcmp(arg[iarg+1],"yes") == 0) control->enobondsflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) control->enobondsflag = 0;
else error->all(FLERR,"Illegal pair_style reax/c command");
iarg += 2;
} else if (strcmp(arg[iarg],"lgvdw") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_style reax/c command");
if (strcmp(arg[iarg+1],"yes") == 0) control->lgflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) control->lgflag = 0;
else error->all(FLERR,"Illegal pair_style reax/c command");
iarg += 2;
} else if (strcmp(arg[iarg],"safezone") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_style reax/c command");
system->safezone = force->numeric(FLERR,arg[iarg+1]);
if (system->safezone < 0.0)
error->all(FLERR,"Illegal pair_style reax/c safezone command");
system->saferzone = system->safezone*1.2 + 0.2;
iarg += 2;
} else if (strcmp(arg[iarg],"mincap") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_style reax/c command");
system->mincap = force->inumeric(FLERR,arg[iarg+1]);
if (system->mincap < 0)
error->all(FLERR,"Illegal pair_style reax/c mincap command");
iarg += 2;
} else error->all(FLERR,"Illegal pair_style reax/c command");
}
// LAMMPS is responsible for generating nbrs
control->reneighbor = 1;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::coeff( int nargs, char **args )
{
if (!allocated) allocate();
if (nargs != 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// insure I,J args are * *
if (strcmp(args[0],"*") != 0 || strcmp(args[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read ffield file
char *file = args[2];
FILE *fp;
fp = force->open_potential(file);
if (fp != NULL)
Read_Force_Field(fp, &(system->reax_param), control);
else {
char str[128];
sprintf(str,"Cannot open ReaxFF potential file %s",file);
error->all(FLERR,str);
}
// read args that map atom types to elements in potential file
// map[i] = which element the Ith atom type is, -1 if NULL
int itmp = 0;
int nreax_types = system->reax_param.num_atom_types;
for (int i = 3; i < nargs; i++) {
if (strcmp(args[i],"NULL") == 0) {
map[i-2] = -1;
itmp ++;
continue;
}
}
int n = atom->ntypes;
// pair_coeff element map
for (int i = 3; i < nargs; i++)
for (int j = 0; j < nreax_types; j++)
if (strcasecmp(args[i],system->reax_param.sbp[j].name) == 0) {
map[i-2] = j;
itmp ++;
}
// error check
if (itmp != n)
error->all(FLERR,"Non-existent ReaxFF type");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
// set setflag i,j for type pairs where both are mapped to elements
int count = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
if (map[i] >= 0 && map[j] >= 0) {
setflag[i][j] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ---------------------------------------------------------------------- */
void PairReaxC::init_style( )
{
if (!atom->q_flag)
error->all(FLERR,"Pair style reax/c requires atom attribute q");
// firstwarn = 1;
int iqeq;
for (iqeq = 0; iqeq < modify->nfix; iqeq++)
if (strstr(modify->fix[iqeq]->style,"qeq/reax")) break;
if (iqeq == modify->nfix && qeqflag == 1)
error->all(FLERR,"Pair reax/c requires use of fix qeq/reax");
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
system->wsize = comm->nprocs;
system->big_box.V = 0;
system->big_box.box_norms[0] = 0;
system->big_box.box_norms[1] = 0;
system->big_box.box_norms[2] = 0;
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style reax/c requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style reax/c requires newton pair on");
// need a half neighbor list w/ Newton off and ghost neighbors
// built whenever re-neighboring occurs
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->newton = 2;
neighbor->requests[irequest]->ghost = 1;
cutmax = MAX3(control->nonb_cut, control->hbond_cut, 2*control->bond_cut);
for( int i = 0; i < LIST_N; ++i )
lists[i].allocated = 0;
if (fix_reax == NULL) {
char **fixarg = new char*[3];
fixarg[0] = (char *) "REAXC";
fixarg[1] = (char *) "all";
fixarg[2] = (char *) "REAXC";
modify->add_fix(3,fixarg);
delete [] fixarg;
fix_reax = (FixReaxC *) modify->fix[modify->nfix-1];
}
}
/* ---------------------------------------------------------------------- */
void PairReaxC::setup( )
{
int oldN;
int mincap = system->mincap;
double safezone = system->safezone;
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
oldN = system->N;
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
if (setup_flag == 0) {
setup_flag = 1;
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
control->vlist_cut = neighbor->cutneighmax;
// determine the local and total capacity
system->local_cap = MAX( (int)(system->n * safezone), mincap );
system->total_cap = MAX( (int)(system->N * safezone), mincap );
// initialize my data structures
PreAllocate_Space( system, control, workspace, world );
write_reax_atoms();
int num_nbrs = estimate_reax_lists();
if(!Make_List(system->total_cap, num_nbrs, TYP_FAR_NEIGHBOR,
lists+FAR_NBRS, world))
error->all(FLERR,"Pair reax/c problem in far neighbor list");
write_reax_lists();
Initialize( system, control, data, workspace, &lists, out_control,
mpi_data, world );
for( int k = 0; k < system->N; ++k ) {
num_bonds[k] = system->my_atoms[k].num_bonds;
num_hbonds[k] = system->my_atoms[k].num_hbonds;
}
} else {
// fill in reax datastructures
write_reax_atoms();
// reset the bond list info for new atoms
for(int k = oldN; k < system->N; ++k)
Set_End_Index( k, Start_Index( k, lists+BONDS ), lists+BONDS );
// check if I need to shrink/extend my data-structs
ReAllocate( system, control, data, workspace, &lists, mpi_data );
}
bigint local_ngroup = list->inum;
MPI_Allreduce( &local_ngroup, &ngroup, 1, MPI_LMP_BIGINT, MPI_SUM, world );
}
/* ---------------------------------------------------------------------- */
double PairReaxC::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
cutghost[i][j] = cutghost[j][i] = cutmax;
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::compute(int eflag, int vflag)
{
double evdwl,ecoul;
double t_start, t_end;
// communicate num_bonds once every reneighboring
// 2 num arrays stored by fix, grab ptr to them
if (neighbor->ago == 0) comm->forward_comm_fix(fix_reax);
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else ev_unset();
if (vflag_global) control->virial = 1;
else control->virial = 0;
system->n = atom->nlocal; // my atoms
system->N = atom->nlocal + atom->nghost; // mine + ghosts
system->bigN = static_cast<int> (atom->natoms); // all atoms in the system
system->big_box.V = 0;
system->big_box.box_norms[0] = 0;
system->big_box.box_norms[1] = 0;
system->big_box.box_norms[2] = 0;
if( comm->me == 0 ) t_start = MPI_Wtime();
// setup data structures
setup();
Reset( system, control, data, workspace, &lists, world );
workspace->realloc.num_far = write_reax_lists();
// timing for filling in the reax lists
if( comm->me == 0 ) {
t_end = MPI_Wtime();
data->timing.nbrs = t_end - t_start;
}
// forces
Compute_Forces(system,control,data,workspace,&lists,out_control,mpi_data);
read_reax_forces(vflag);
for(int k = 0; k < system->N; ++k) {
num_bonds[k] = system->my_atoms[k].num_bonds;
num_hbonds[k] = system->my_atoms[k].num_hbonds;
}
// energies and pressure
if (eflag_global) {
evdwl += data->my_en.e_bond;
evdwl += data->my_en.e_ov;
evdwl += data->my_en.e_un;
evdwl += data->my_en.e_lp;
evdwl += data->my_en.e_ang;
evdwl += data->my_en.e_pen;
evdwl += data->my_en.e_coa;
evdwl += data->my_en.e_hb;
evdwl += data->my_en.e_tor;
evdwl += data->my_en.e_con;
evdwl += data->my_en.e_vdW;
ecoul += data->my_en.e_ele;
ecoul += data->my_en.e_pol;
// eng_vdwl += evdwl;
// eng_coul += ecoul;
// Store the different parts of the energy
// in a list for output by compute pair command
pvector[0] = data->my_en.e_bond;
pvector[1] = data->my_en.e_ov + data->my_en.e_un;
pvector[2] = data->my_en.e_lp;
pvector[3] = 0.0;
pvector[4] = data->my_en.e_ang;
pvector[5] = data->my_en.e_pen;
pvector[6] = data->my_en.e_coa;
pvector[7] = data->my_en.e_hb;
pvector[8] = data->my_en.e_tor;
pvector[9] = data->my_en.e_con;
pvector[10] = data->my_en.e_vdW;
pvector[11] = data->my_en.e_ele;
pvector[12] = 0.0;
pvector[13] = data->my_en.e_pol;
}
if (vflag_fdotr) virial_fdotr_compute();
// Set internal timestep counter to that of LAMMPS
data->step = update->ntimestep;
Output_Results( system, control, data, &lists, out_control, mpi_data );
// populate tmpid and tmpbo arrays for fix reax/c/species
int i, j;
if(fixspecies_flag) {
if (system->N > nmax) {
memory->destroy(tmpid);
memory->destroy(tmpbo);
nmax = system->N;
memory->create(tmpid,nmax,MAXSPECBOND,"pair:tmpid");
memory->create(tmpbo,nmax,MAXSPECBOND,"pair:tmpbo");
}
for (i = 0; i < system->N; i ++)
for (j = 0; j < MAXSPECBOND; j ++) {
tmpbo[i][j] = 0.0;
tmpid[i][j] = 0;
}
FindBond();
}
}
/* ---------------------------------------------------------------------- */
void PairReaxC::write_reax_atoms()
{
int *num_bonds = fix_reax->num_bonds;
int *num_hbonds = fix_reax->num_hbonds;
if (system->N > system->total_cap)
error->all(FLERR,"Too many ghost atoms");
for( int i = 0; i < system->N; ++i ){
system->my_atoms[i].orig_id = atom->tag[i];
system->my_atoms[i].type = map[atom->type[i]];
system->my_atoms[i].x[0] = atom->x[i][0];
system->my_atoms[i].x[1] = atom->x[i][1];
system->my_atoms[i].x[2] = atom->x[i][2];
system->my_atoms[i].q = atom->q[i];
system->my_atoms[i].num_bonds = num_bonds[i];
system->my_atoms[i].num_hbonds = num_hbonds[i];
}
}
/* ---------------------------------------------------------------------- */
void PairReaxC::get_distance( rvec xj, rvec xi, double *d_sqr, rvec *dvec )
{
(*dvec)[0] = xj[0] - xi[0];
(*dvec)[1] = xj[1] - xi[1];
(*dvec)[2] = xj[2] - xi[2];
*d_sqr = SQR((*dvec)[0]) + SQR((*dvec)[1]) + SQR((*dvec)[2]);
}
/* ---------------------------------------------------------------------- */
void PairReaxC::set_far_nbr( far_neighbor_data *fdest,
int j, double d, rvec dvec )
{
fdest->nbr = j;
fdest->d = d;
rvec_Copy( fdest->dvec, dvec );
ivec_MakeZero( fdest->rel_box );
}
/* ---------------------------------------------------------------------- */
int PairReaxC::estimate_reax_lists()
{
int itr_i, itr_j, i, j;
int num_nbrs, num_marked;
int *ilist, *jlist, *numneigh, **firstneigh, *marked;
double d_sqr;
rvec dvec;
double **x;
int mincap = system->mincap;
double safezone = system->safezone;
x = atom->x;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
num_nbrs = 0;
num_marked = 0;
marked = (int*) calloc( system->N, sizeof(int) );
int numall = list->inum + list->gnum;
for( itr_i = 0; itr_i < numall; ++itr_i ){
i = ilist[itr_i];
marked[i] = 1;
++num_marked;
jlist = firstneigh[i];
for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
j = jlist[itr_j];
j &= NEIGHMASK;
get_distance( x[j], x[i], &d_sqr, &dvec );
if( d_sqr <= SQR(control->nonb_cut) )
++num_nbrs;
}
}
free( marked );
return static_cast<int> (MAX( num_nbrs*safezone, mincap*MIN_NBRS ));
}
/* ---------------------------------------------------------------------- */
int PairReaxC::write_reax_lists()
{
int itr_i, itr_j, i, j;
int num_nbrs;
int *ilist, *jlist, *numneigh, **firstneigh;
double d_sqr;
rvec dvec;
double *dist, **x;
reax_list *far_nbrs;
far_neighbor_data *far_list;
x = atom->x;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
far_nbrs = lists + FAR_NBRS;
far_list = far_nbrs->select.far_nbr_list;
num_nbrs = 0;
dist = (double*) calloc( system->N, sizeof(double) );
int numall = list->inum + list->gnum;
for( itr_i = 0; itr_i < numall; ++itr_i ){
i = ilist[itr_i];
jlist = firstneigh[i];
Set_Start_Index( i, num_nbrs, far_nbrs );
for( itr_j = 0; itr_j < numneigh[i]; ++itr_j ){
j = jlist[itr_j];
j &= NEIGHMASK;
get_distance( x[j], x[i], &d_sqr, &dvec );
if( d_sqr <= (control->nonb_cut*control->nonb_cut) ){
dist[j] = sqrt( d_sqr );
set_far_nbr( &far_list[num_nbrs], j, dist[j], dvec );
++num_nbrs;
}
}
Set_End_Index( i, num_nbrs, far_nbrs );
}
free( dist );
return num_nbrs;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::read_reax_forces(int vflag)
{
for( int i = 0; i < system->N; ++i ) {
system->my_atoms[i].f[0] = workspace->f[i][0];
system->my_atoms[i].f[1] = workspace->f[i][1];
system->my_atoms[i].f[2] = workspace->f[i][2];
atom->f[i][0] += -workspace->f[i][0];
atom->f[i][1] += -workspace->f[i][1];
atom->f[i][2] += -workspace->f[i][2];
}
}
/* ---------------------------------------------------------------------- */
void *PairReaxC::extract(const char *str, int &dim)
{
dim = 1;
if (strcmp(str,"chi") == 0 && chi) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) chi[i] = system->reax_param.sbp[map[i]].chi;
else chi[i] = 0.0;
return (void *) chi;
}
if (strcmp(str,"eta") == 0 && eta) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) eta[i] = system->reax_param.sbp[map[i]].eta;
else eta[i] = 0.0;
return (void *) eta;
}
if (strcmp(str,"gamma") == 0 && gamma) {
for (int i = 1; i <= atom->ntypes; i++)
if (map[i] >= 0) gamma[i] = system->reax_param.sbp[map[i]].gamma;
else gamma[i] = 0.0;
return (void *) gamma;
}
return NULL;
}
/* ---------------------------------------------------------------------- */
double PairReaxC::memory_usage()
{
double bytes = 0.0;
// From pair_reax_c
bytes += 1.0 * system->N * sizeof(int);
bytes += 1.0 * system->N * sizeof(double);
// From reaxc_allocate: BO
bytes += 1.0 * system->total_cap * sizeof(reax_atom);
bytes += 19.0 * system->total_cap * sizeof(double);
bytes += 3.0 * system->total_cap * sizeof(int);
// From reaxc_lists
bytes += 2.0 * lists->n * sizeof(int);
bytes += lists->num_intrs * sizeof(three_body_interaction_data);
bytes += lists->num_intrs * sizeof(bond_data);
bytes += lists->num_intrs * sizeof(dbond_data);
bytes += lists->num_intrs * sizeof(dDelta_data);
bytes += lists->num_intrs * sizeof(far_neighbor_data);
bytes += lists->num_intrs * sizeof(hbond_data);
if(fixspecies_flag)
bytes += 2 * nmax * MAXSPECBOND * sizeof(double);
return bytes;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::FindBond()
{
int i, j, pj, nj;
double bo_tmp, bo_cut;
bond_data *bo_ij;
bo_cut = 0.10;
for (i = 0; i < system->n; i++) {
nj = 0;
for( pj = Start_Index(i, lists); pj < End_Index(i, lists); ++pj ) {
bo_ij = &( lists->select.bond_list[pj] );
j = bo_ij->nbr;
if (j < i) continue;
bo_tmp = bo_ij->bo_data.BO;
if (bo_tmp >= bo_cut ) {
tmpid[i][nj] = j;
tmpbo[i][nj] = bo_tmp;
nj ++;
if (nj > MAXSPECBOND) error->all(FLERR,"Increase MAXSPECBOND in reaxc_defs.h");
}
}
}
}
diff --git a/src/USER-REAXC/reaxc_allocate.cpp b/src/USER-REAXC/reaxc_allocate.cpp
index e3fc54c50..1b8274916 100644
--- a/src/USER-REAXC/reaxc_allocate.cpp
+++ b/src/USER-REAXC/reaxc_allocate.cpp
@@ -1,510 +1,512 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc.h"
#include "reaxc_allocate.h"
#include "reaxc_list.h"
#include "reaxc_reset_tools.h"
#include "reaxc_tool_box.h"
#include "reaxc_vector.h"
#if defined(_OPENMP)
#include <omp.h>
#endif
/* allocate space for my_atoms
important: we cannot know the exact number of atoms that will fall into a
process's box throughout the whole simulation. therefore
we need to make upper bound estimates for various data structures */
int PreAllocate_Space( reax_system *system, control_params *control,
storage *workspace, MPI_Comm comm )
{
int mincap = system->mincap;
double safezone = system->safezone;
// determine the local and total capacity
system->local_cap = MAX( (int)(system->n * safezone), mincap );
system->total_cap = MAX( (int)(system->N * safezone), mincap );
system->my_atoms = (reax_atom*)
scalloc( system->total_cap, sizeof(reax_atom), "my_atoms", comm );
// Nullify some arrays only used in omp styles
// Should be safe to do here since called in pair->setup();
#ifdef LMP_USER_OMP
workspace->CdDeltaReduction = NULL;
workspace->forceReduction = NULL;
workspace->valence_angle_atom_myoffset = NULL;
workspace->my_ext_pressReduction = NULL;
#endif
return SUCCESS;
}
/************* system *************/
int Allocate_System( reax_system *system, int local_cap, int total_cap,
char *msg )
{
system->my_atoms = (reax_atom*)
realloc( system->my_atoms, total_cap*sizeof(reax_atom) );
return SUCCESS;
}
void DeAllocate_System( reax_system *system )
{
int i, j, k;
int ntypes;
reax_interaction *ff_params;
// dealloocate the atom list
sfree( system->my_atoms, "system->my_atoms" );
// deallocate the ffield parameters storage
ff_params = &(system->reax_param);
ntypes = ff_params->num_atom_types;
sfree( ff_params->gp.l, "ff:globals" );
for( i = 0; i < ntypes; ++i ) {
for( j = 0; j < ntypes; ++j ) {
for( k = 0; k < ntypes; ++k ) {
sfree( ff_params->fbp[i][j][k], "ff:fbp[i,j,k]" );
}
sfree( ff_params->fbp[i][j], "ff:fbp[i,j]" );
sfree( ff_params->thbp[i][j], "ff:thbp[i,j]" );
sfree( ff_params->hbp[i][j], "ff:hbp[i,j]" );
}
sfree( ff_params->fbp[i], "ff:fbp[i]" );
sfree( ff_params->thbp[i], "ff:thbp[i]" );
sfree( ff_params->hbp[i], "ff:hbp[i]" );
sfree( ff_params->tbp[i], "ff:tbp[i]" );
}
sfree( ff_params->fbp, "ff:fbp" );
sfree( ff_params->thbp, "ff:thbp" );
sfree( ff_params->hbp, "ff:hbp" );
sfree( ff_params->tbp, "ff:tbp" );
sfree( ff_params->sbp, "ff:sbp" );
}
/************* workspace *************/
void DeAllocate_Workspace( control_params *control, storage *workspace )
{
int i;
if( !workspace->allocated )
return;
workspace->allocated = 0;
/* communication storage */
for( i = 0; i < MAX_NBRS; ++i ) {
sfree( workspace->tmp_dbl[i], "tmp_dbl[i]" );
sfree( workspace->tmp_rvec[i], "tmp_rvec[i]" );
sfree( workspace->tmp_rvec2[i], "tmp_rvec2[i]" );
}
/* bond order storage */
sfree( workspace->within_bond_box, "skin" );
sfree( workspace->total_bond_order, "total_bo" );
sfree( workspace->Deltap, "Deltap" );
sfree( workspace->Deltap_boc, "Deltap_boc" );
sfree( workspace->dDeltap_self, "dDeltap_self" );
sfree( workspace->Delta, "Delta" );
sfree( workspace->Delta_lp, "Delta_lp" );
sfree( workspace->Delta_lp_temp, "Delta_lp_temp" );
sfree( workspace->dDelta_lp, "dDelta_lp" );
sfree( workspace->dDelta_lp_temp, "dDelta_lp_temp" );
sfree( workspace->Delta_e, "Delta_e" );
sfree( workspace->Delta_boc, "Delta_boc" );
sfree( workspace->Delta_val, "Delta_val" );
sfree( workspace->nlp, "nlp" );
sfree( workspace->nlp_temp, "nlp_temp" );
sfree( workspace->Clp, "Clp" );
sfree( workspace->vlpex, "vlpex" );
sfree( workspace->bond_mark, "bond_mark" );
sfree( workspace->done_after, "done_after" );
/* QEq storage */
sfree( workspace->Hdia_inv, "Hdia_inv" );
sfree( workspace->b_s, "b_s" );
sfree( workspace->b_t, "b_t" );
sfree( workspace->b_prc, "b_prc" );
sfree( workspace->b_prm, "b_prm" );
sfree( workspace->s, "s" );
sfree( workspace->t, "t" );
sfree( workspace->droptol, "droptol" );
sfree( workspace->b, "b" );
sfree( workspace->x, "x" );
/* GMRES storage */
for( i = 0; i < RESTART+1; ++i ) {
sfree( workspace->h[i], "h[i]" );
sfree( workspace->v[i], "v[i]" );
}
sfree( workspace->h, "h" );
sfree( workspace->v, "v" );
sfree( workspace->y, "y" );
sfree( workspace->z, "z" );
sfree( workspace->g, "g" );
sfree( workspace->hs, "hs" );
sfree( workspace->hc, "hc" );
/* CG storage */
sfree( workspace->r, "r" );
sfree( workspace->d, "d" );
sfree( workspace->q, "q" );
sfree( workspace->p, "p" );
sfree( workspace->r2, "r2" );
sfree( workspace->d2, "d2" );
sfree( workspace->q2, "q2" );
sfree( workspace->p2, "p2" );
/* integrator storage */
sfree( workspace->v_const, "v_const" );
/* force related storage */
sfree( workspace->f, "f" );
sfree( workspace->CdDelta, "CdDelta" );
/* reductions */
#ifdef LMP_USER_OMP
if (workspace->CdDeltaReduction) sfree( workspace->CdDeltaReduction, "cddelta_reduce" );
if (workspace->forceReduction) sfree( workspace->forceReduction, "f_reduce" );
if (workspace->valence_angle_atom_myoffset) sfree( workspace->valence_angle_atom_myoffset, "valence_angle_atom_myoffset");
if (workspace->my_ext_pressReduction) sfree( workspace->my_ext_pressReduction, "ext_press_reduce");
#endif
}
int Allocate_Workspace( reax_system *system, control_params *control,
storage *workspace, int local_cap, int total_cap,
MPI_Comm comm, char *msg )
{
int i, total_real, total_rvec, local_rvec;
workspace->allocated = 1;
total_real = total_cap * sizeof(double);
total_rvec = total_cap * sizeof(rvec);
local_rvec = local_cap * sizeof(rvec);
/* communication storage */
for( i = 0; i < MAX_NBRS; ++i ) {
workspace->tmp_dbl[i] = (double*)
scalloc( total_cap, sizeof(double), "tmp_dbl", comm );
workspace->tmp_rvec[i] = (rvec*)
scalloc( total_cap, sizeof(rvec), "tmp_rvec", comm );
workspace->tmp_rvec2[i] = (rvec2*)
scalloc( total_cap, sizeof(rvec2), "tmp_rvec2", comm );
}
/* bond order related storage */
workspace->within_bond_box = (int*)
scalloc( total_cap, sizeof(int), "skin", comm );
workspace->total_bond_order = (double*) smalloc( total_real, "total_bo", comm );
workspace->Deltap = (double*) smalloc( total_real, "Deltap", comm );
workspace->Deltap_boc = (double*) smalloc( total_real, "Deltap_boc", comm );
workspace->dDeltap_self = (rvec*) smalloc( total_rvec, "dDeltap_self", comm );
workspace->Delta = (double*) smalloc( total_real, "Delta", comm );
workspace->Delta_lp = (double*) smalloc( total_real, "Delta_lp", comm );
workspace->Delta_lp_temp = (double*)
smalloc( total_real, "Delta_lp_temp", comm );
workspace->dDelta_lp = (double*) smalloc( total_real, "dDelta_lp", comm );
workspace->dDelta_lp_temp = (double*)
smalloc( total_real, "dDelta_lp_temp", comm );
workspace->Delta_e = (double*) smalloc( total_real, "Delta_e", comm );
workspace->Delta_boc = (double*) smalloc( total_real, "Delta_boc", comm );
workspace->Delta_val = (double*) smalloc( total_real, "Delta_val", comm );
workspace->nlp = (double*) smalloc( total_real, "nlp", comm );
workspace->nlp_temp = (double*) smalloc( total_real, "nlp_temp", comm );
workspace->Clp = (double*) smalloc( total_real, "Clp", comm );
workspace->vlpex = (double*) smalloc( total_real, "vlpex", comm );
workspace->bond_mark = (int*)
scalloc( total_cap, sizeof(int), "bond_mark", comm );
workspace->done_after = (int*)
scalloc( total_cap, sizeof(int), "done_after", comm );
/* QEq storage */
workspace->Hdia_inv = (double*)
scalloc( total_cap, sizeof(double), "Hdia_inv", comm );
workspace->b_s = (double*) scalloc( total_cap, sizeof(double), "b_s", comm );
workspace->b_t = (double*) scalloc( total_cap, sizeof(double), "b_t", comm );
workspace->b_prc = (double*) scalloc( total_cap, sizeof(double), "b_prc", comm );
workspace->b_prm = (double*) scalloc( total_cap, sizeof(double), "b_prm", comm );
workspace->s = (double*) scalloc( total_cap, sizeof(double), "s", comm );
workspace->t = (double*) scalloc( total_cap, sizeof(double), "t", comm );
workspace->droptol = (double*)
scalloc( total_cap, sizeof(double), "droptol", comm );
workspace->b = (rvec2*) scalloc( total_cap, sizeof(rvec2), "b", comm );
workspace->x = (rvec2*) scalloc( total_cap, sizeof(rvec2), "x", comm );
/* GMRES storage */
workspace->y = (double*) scalloc( RESTART+1, sizeof(double), "y", comm );
workspace->z = (double*) scalloc( RESTART+1, sizeof(double), "z", comm );
workspace->g = (double*) scalloc( RESTART+1, sizeof(double), "g", comm );
workspace->h = (double**) scalloc( RESTART+1, sizeof(double*), "h", comm );
workspace->hs = (double*) scalloc( RESTART+1, sizeof(double), "hs", comm );
workspace->hc = (double*) scalloc( RESTART+1, sizeof(double), "hc", comm );
workspace->v = (double**) scalloc( RESTART+1, sizeof(double*), "v", comm );
for( i = 0; i < RESTART+1; ++i ) {
workspace->h[i] = (double*) scalloc( RESTART+1, sizeof(double), "h[i]", comm );
workspace->v[i] = (double*) scalloc( total_cap, sizeof(double), "v[i]", comm );
}
/* CG storage */
workspace->r = (double*) scalloc( total_cap, sizeof(double), "r", comm );
workspace->d = (double*) scalloc( total_cap, sizeof(double), "d", comm );
workspace->q = (double*) scalloc( total_cap, sizeof(double), "q", comm );
workspace->p = (double*) scalloc( total_cap, sizeof(double), "p", comm );
workspace->r2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "r2", comm );
workspace->d2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "d2", comm );
workspace->q2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "q2", comm );
workspace->p2 = (rvec2*) scalloc( total_cap, sizeof(rvec2), "p2", comm );
/* integrator storage */
workspace->v_const = (rvec*) smalloc( local_rvec, "v_const", comm );
/* force related storage */
workspace->f = (rvec*) scalloc( total_cap, sizeof(rvec), "f", comm );
workspace->CdDelta = (double*)
scalloc( total_cap, sizeof(double), "CdDelta", comm );
// storage for reductions with multiple threads
#ifdef LMP_USER_OMP
workspace->CdDeltaReduction = (double *) scalloc(sizeof(double), total_cap*control->nthreads,
"cddelta_reduce", comm);
workspace->forceReduction = (rvec *) scalloc(sizeof(rvec), total_cap*control->nthreads,
"forceReduction", comm);
workspace->valence_angle_atom_myoffset = (int *) scalloc(sizeof(int), total_cap, "valence_angle_atom_myoffset", comm);
workspace->my_ext_pressReduction = (rvec *) calloc(sizeof(rvec), control->nthreads);
#endif
return SUCCESS;
}
static void Reallocate_Neighbor_List( reax_list *far_nbrs, int n,
int num_intrs, MPI_Comm comm )
{
Delete_List( far_nbrs, comm );
if(!Make_List( n, num_intrs, TYP_FAR_NEIGHBOR, far_nbrs, comm )){
fprintf(stderr, "Problem in initializing far nbrs list. Terminating!\n");
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
}
static int Reallocate_HBonds_List( reax_system *system, reax_list *hbonds,
MPI_Comm comm )
{
int i, id, total_hbonds;
int mincap = system->mincap;
double saferzone = system->saferzone;
total_hbonds = 0;
for( i = 0; i < system->n; ++i )
if( (id = system->my_atoms[i].Hindex) >= 0 ) {
total_hbonds += system->my_atoms[i].num_hbonds;
}
total_hbonds = (int)(MAX( total_hbonds*saferzone, mincap*MIN_HBONDS ));
Delete_List( hbonds, comm );
if( !Make_List( system->Hcap, total_hbonds, TYP_HBOND, hbonds, comm ) ) {
fprintf( stderr, "not enough space for hbonds list. terminating!\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
return total_hbonds;
}
static int Reallocate_Bonds_List( reax_system *system, reax_list *bonds,
int *total_bonds, int *est_3body,
MPI_Comm comm )
{
int i;
int mincap = system->mincap;
double safezone = system->safezone;
*total_bonds = 0;
*est_3body = 0;
for( i = 0; i < system->N; ++i ){
*est_3body += SQR(system->my_atoms[i].num_bonds);
*total_bonds += system->my_atoms[i].num_bonds;
}
*total_bonds = (int)(MAX( *total_bonds * safezone, mincap*MIN_BONDS ));
#ifdef LMP_USER_OMP
- for (i = 0; i < bonds->num_intrs; ++i)
- sfree(bonds->select.bond_list[i].bo_data.CdboReduction, "CdboReduction");
+ if (system->omp_active)
+ for (i = 0; i < bonds->num_intrs; ++i)
+ sfree(bonds->select.bond_list[i].bo_data.CdboReduction, "CdboReduction");
#endif
Delete_List( bonds, comm );
if(!Make_List(system->total_cap, *total_bonds, TYP_BOND, bonds, comm)) {
fprintf( stderr, "not enough space for bonds list. terminating!\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
#ifdef LMP_USER_OMP
#if defined(_OPENMP)
int nthreads = omp_get_num_threads();
#else
int nthreads = 1;
#endif
- for (i = 0; i < bonds->num_intrs; ++i)
- bonds->select.bond_list[i].bo_data.CdboReduction =
- (double*) smalloc(sizeof(double)*nthreads, "CdboReduction", comm);
+ if (system->omp_active)
+ for (i = 0; i < bonds->num_intrs; ++i)
+ bonds->select.bond_list[i].bo_data.CdboReduction =
+ (double*) smalloc(sizeof(double)*nthreads, "CdboReduction", comm);
#endif
return SUCCESS;
}
void ReAllocate( reax_system *system, control_params *control,
simulation_data *data, storage *workspace, reax_list **lists,
mpi_datatypes *mpi_data )
{
int num_bonds, est_3body, Hflag, ret;
int renbr, newsize;
reallocate_data *realloc;
reax_list *far_nbrs;
MPI_Comm comm;
char msg[200];
int mincap = system->mincap;
double safezone = system->safezone;
double saferzone = system->saferzone;
realloc = &(workspace->realloc);
comm = mpi_data->world;
if( system->n >= DANGER_ZONE * system->local_cap ||
(0 && system->n <= LOOSE_ZONE * system->local_cap) ) {
system->local_cap = MAX( (int)(system->n * safezone), mincap );
}
int Nflag = 0;
if( system->N >= DANGER_ZONE * system->total_cap ||
(0 && system->N <= LOOSE_ZONE * system->total_cap) ) {
Nflag = 1;
system->total_cap = MAX( (int)(system->N * safezone), mincap );
}
if( Nflag ) {
/* system */
ret = Allocate_System( system, system->local_cap, system->total_cap, msg );
if( ret != SUCCESS ) {
fprintf( stderr, "not enough space for atom_list: total_cap=%d",
system->total_cap );
fprintf( stderr, "terminating...\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
/* workspace */
DeAllocate_Workspace( control, workspace );
ret = Allocate_Workspace( system, control, workspace, system->local_cap,
system->total_cap, comm, msg );
if( ret != SUCCESS ) {
fprintf( stderr, "no space for workspace: local_cap=%d total_cap=%d",
system->local_cap, system->total_cap );
fprintf( stderr, "terminating...\n" );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
}
renbr = (data->step - data->prev_steps) % control->reneighbor == 0;
/* far neighbors */
if( renbr ) {
far_nbrs = *lists + FAR_NBRS;
if( Nflag || realloc->num_far >= far_nbrs->num_intrs * DANGER_ZONE ) {
if( realloc->num_far > far_nbrs->num_intrs ) {
fprintf( stderr, "step%d-ran out of space on far_nbrs: top=%d, max=%d",
data->step, realloc->num_far, far_nbrs->num_intrs );
MPI_Abort( comm, INSUFFICIENT_MEMORY );
}
newsize = static_cast<int>
(MAX( realloc->num_far*safezone, mincap*MIN_NBRS ));
Reallocate_Neighbor_List( far_nbrs, system->total_cap, newsize, comm );
realloc->num_far = 0;
}
}
/* hydrogen bonds list */
if( control->hbond_cut > 0 ) {
Hflag = 0;
if( system->numH >= DANGER_ZONE * system->Hcap ||
(0 && system->numH <= LOOSE_ZONE * system->Hcap) ) {
Hflag = 1;
system->Hcap = int(MAX( system->numH * saferzone, mincap ));
}
if( Hflag || realloc->hbonds ) {
ret = Reallocate_HBonds_List( system, (*lists)+HBONDS, comm );
realloc->hbonds = 0;
}
}
/* bonds list */
num_bonds = est_3body = -1;
if( Nflag || realloc->bonds ){
Reallocate_Bonds_List( system, (*lists)+BONDS, &num_bonds,
&est_3body, comm );
realloc->bonds = 0;
realloc->num_3body = MAX( realloc->num_3body, est_3body ) * 2;
}
/* 3-body list */
if( realloc->num_3body > 0 ) {
Delete_List( (*lists)+THREE_BODIES, comm );
if( num_bonds == -1 )
num_bonds = ((*lists)+BONDS)->num_intrs;
realloc->num_3body = (int)(MAX(realloc->num_3body*safezone, MIN_3BODIES));
if( !Make_List( num_bonds, realloc->num_3body, TYP_THREE_BODY,
(*lists)+THREE_BODIES, comm ) ) {
fprintf( stderr, "Problem in initializing angles list. Terminating!\n" );
MPI_Abort( comm, CANNOT_INITIALIZE );
}
realloc->num_3body = -1;
}
}
diff --git a/src/USER-REAXC/reaxc_bonds.cpp b/src/USER-REAXC/reaxc_bonds.cpp
index a8a129816..cf536fe60 100644
--- a/src/USER-REAXC/reaxc_bonds.cpp
+++ b/src/USER-REAXC/reaxc_bonds.cpp
@@ -1,137 +1,138 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc.h"
#include "reaxc_bonds.h"
#include "reaxc_bond_orders.h"
#include "reaxc_list.h"
#include "reaxc_tool_box.h"
#include "reaxc_vector.h"
void Bonds( reax_system *system, control_params *control,
simulation_data *data, storage *workspace, reax_list **lists,
output_controls *out_control )
{
int i, j, pj, natoms;
int start_i, end_i;
int type_i, type_j;
double ebond, pow_BOs_be2, exp_be12, CEbo;
double gp3, gp4, gp7, gp10, gp37;
double exphu, exphua1, exphub1, exphuov, hulpov, estriph;
double decobdbo, decobdboua, decobdboub;
single_body_parameters *sbp_i, *sbp_j;
two_body_parameters *twbp;
bond_order_data *bo_ij;
reax_list *bonds;
bonds = (*lists) + BONDS;
gp3 = system->reax_param.gp.l[3];
gp4 = system->reax_param.gp.l[4];
gp7 = system->reax_param.gp.l[7];
gp10 = system->reax_param.gp.l[10];
gp37 = (int) system->reax_param.gp.l[37];
natoms = system->n;
for( i = 0; i < natoms; ++i ) {
start_i = Start_Index(i, bonds);
end_i = End_Index(i, bonds);
for( pj = start_i; pj < end_i; ++pj ) {
j = bonds->select.bond_list[pj].nbr;
if( system->my_atoms[i].orig_id > system->my_atoms[j].orig_id )
continue;
if( system->my_atoms[i].orig_id == system->my_atoms[j].orig_id ) {
if (system->my_atoms[j].x[2] < system->my_atoms[i].x[2]) continue;
if (system->my_atoms[j].x[2] == system->my_atoms[i].x[2] &&
system->my_atoms[j].x[1] < system->my_atoms[i].x[1]) continue;
if (system->my_atoms[j].x[2] == system->my_atoms[i].x[2] &&
system->my_atoms[j].x[1] == system->my_atoms[i].x[1] &&
system->my_atoms[j].x[0] < system->my_atoms[i].x[0]) continue;
}
/* set the pointers */
type_i = system->my_atoms[i].type;
type_j = system->my_atoms[j].type;
sbp_i = &( system->reax_param.sbp[type_i] );
sbp_j = &( system->reax_param.sbp[type_j] );
twbp = &( system->reax_param.tbp[type_i][type_j] );
bo_ij = &( bonds->select.bond_list[pj].bo_data );
/* calculate the constants */
- pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 );
+ if (bo_ij->BO_s == 0.0) pow_BOs_be2 = 0.0;
+ else pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 );
exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) );
CEbo = -twbp->De_s * exp_be12 *
( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 );
/* calculate the Bond Energy */
data->my_en.e_bond += ebond =
-twbp->De_s * bo_ij->BO_s * exp_be12
-twbp->De_p * bo_ij->BO_pi
-twbp->De_pp * bo_ij->BO_pi2;
/* tally into per-atom energy */
if( system->pair_ptr->evflag)
system->pair_ptr->ev_tally(i,j,natoms,1,ebond,0.0,0.0,0.0,0.0,0.0);
/* calculate derivatives of Bond Orders */
bo_ij->Cdbo += CEbo;
bo_ij->Cdbopi -= (CEbo + twbp->De_p);
bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp);
/* Stabilisation terminal triple bond */
if( bo_ij->BO >= 1.00 ) {
if( gp37 == 2 ||
(sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990) ||
(sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990) ) {
exphu = exp( -gp7 * SQR(bo_ij->BO - 2.50) );
exphua1 = exp(-gp3 * (workspace->total_bond_order[i]-bo_ij->BO));
exphub1 = exp(-gp3 * (workspace->total_bond_order[j]-bo_ij->BO));
exphuov = exp(gp4 * (workspace->Delta[i] + workspace->Delta[j]));
hulpov = 1.0 / (1.0 + 25.0 * exphuov);
estriph = gp10 * exphu * hulpov * (exphua1 + exphub1);
data->my_en.e_bond += estriph;
decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) *
( gp3 - 2.0 * gp7 * (bo_ij->BO-2.50) );
decobdboua = -gp10 * exphu * hulpov *
(gp3*exphua1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
decobdboub = -gp10 * exphu * hulpov *
(gp3*exphub1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
/* tally into per-atom energy */
if( system->pair_ptr->evflag)
system->pair_ptr->ev_tally(i,j,natoms,1,estriph,0.0,0.0,0.0,0.0,0.0);
bo_ij->Cdbo += decobdbo;
workspace->CdDelta[i] += decobdboua;
workspace->CdDelta[j] += decobdboub;
}
}
}
}
}
diff --git a/src/USER-REAXC/reaxc_ffield.cpp b/src/USER-REAXC/reaxc_ffield.cpp
index 58a347ebf..fcface79f 100644
--- a/src/USER-REAXC/reaxc_ffield.cpp
+++ b/src/USER-REAXC/reaxc_ffield.cpp
@@ -1,699 +1,706 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc.h"
#include "error.h"
#include "reaxc_ffield.h"
#include "reaxc_tool_box.h"
char Read_Force_Field( FILE *fp, reax_interaction *reax,
control_params *control )
{
char *s;
char **tmp;
char ****tor_flag;
int c, i, j, k, l, m, n, o, p, cnt;
int lgflag = control->lgflag;
int errorflag = 1;
double val;
MPI_Comm comm;
+ int me;
comm = MPI_COMM_WORLD;
+ MPI_Comm_rank(comm, &me);
s = (char*) malloc(sizeof(char)*MAX_LINE);
tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS);
for (i=0; i < MAX_TOKENS; i++)
tmp[i] = (char*) malloc(sizeof(char)*MAX_TOKEN_LEN);
/* reading first header comment */
fgets( s, MAX_LINE, fp );
/* line 2 is number of global parameters */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
/* reading the number of global parameters */
n = atoi(tmp[0]);
if (n < 1) {
- fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" );
+ if (me == 0)
+ fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" );
fclose(fp);
free(s);
free(tmp);
return 1;
}
reax->gp.n_global = n;
reax->gp.l = (double*) malloc(sizeof(double)*n);
/* see reax_types.h for mapping between l[i] and the lambdas used in ff */
for (i=0; i < n; i++) {
fgets(s,MAX_LINE,fp);
c = Tokenize(s,&tmp);
val = (double) atof(tmp[0]);
reax->gp.l[i] = val;
}
control->bo_cut = 0.01 * reax->gp.l[29];
control->nonb_low = reax->gp.l[11];
control->nonb_cut = reax->gp.l[12];
/* next line is number of atom types and some comments */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
reax->num_atom_types = atoi(tmp[0]);
/* 3 lines of comments */
fgets(s,MAX_LINE,fp);
fgets(s,MAX_LINE,fp);
fgets(s,MAX_LINE,fp);
/* Allocating structures in reax_interaction */
reax->sbp = (single_body_parameters*)
scalloc( reax->num_atom_types, sizeof(single_body_parameters), "sbp",
comm );
reax->tbp = (two_body_parameters**)
scalloc( reax->num_atom_types, sizeof(two_body_parameters*), "tbp", comm );
reax->thbp= (three_body_header***)
scalloc( reax->num_atom_types, sizeof(three_body_header**), "thbp", comm );
reax->hbp = (hbond_parameters***)
scalloc( reax->num_atom_types, sizeof(hbond_parameters**), "hbp", comm );
reax->fbp = (four_body_header****)
scalloc( reax->num_atom_types, sizeof(four_body_header***), "fbp", comm );
tor_flag = (char****)
scalloc( reax->num_atom_types, sizeof(char***), "tor_flag", comm );
for( i = 0; i < reax->num_atom_types; i++ ) {
reax->tbp[i] = (two_body_parameters*)
scalloc( reax->num_atom_types, sizeof(two_body_parameters), "tbp[i]",
comm );
reax->thbp[i]= (three_body_header**)
scalloc( reax->num_atom_types, sizeof(three_body_header*), "thbp[i]",
comm );
reax->hbp[i] = (hbond_parameters**)
scalloc( reax->num_atom_types, sizeof(hbond_parameters*), "hbp[i]",
comm );
reax->fbp[i] = (four_body_header***)
scalloc( reax->num_atom_types, sizeof(four_body_header**), "fbp[i]",
comm );
tor_flag[i] = (char***)
scalloc( reax->num_atom_types, sizeof(char**), "tor_flag[i]", comm );
for( j = 0; j < reax->num_atom_types; j++ ) {
reax->thbp[i][j]= (three_body_header*)
scalloc( reax->num_atom_types, sizeof(three_body_header), "thbp[i,j]",
comm );
reax->hbp[i][j] = (hbond_parameters*)
scalloc( reax->num_atom_types, sizeof(hbond_parameters), "hbp[i,j]",
comm );
reax->fbp[i][j] = (four_body_header**)
scalloc( reax->num_atom_types, sizeof(four_body_header*), "fbp[i,j]",
comm );
tor_flag[i][j] = (char**)
scalloc( reax->num_atom_types, sizeof(char*), "tor_flag[i,j]", comm );
for (k=0; k < reax->num_atom_types; k++) {
reax->fbp[i][j][k] = (four_body_header*)
scalloc( reax->num_atom_types, sizeof(four_body_header), "fbp[i,j,k]",
comm );
tor_flag[i][j][k] = (char*)
scalloc( reax->num_atom_types, sizeof(char), "tor_flag[i,j,k]",
comm );
}
}
}
reax->gp.vdw_type = 0;
for( i = 0; i < reax->num_atom_types; i++ ) {
/* line one */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
for( j = 0; j < (int)(strlen(tmp[0])); ++j )
reax->sbp[i].name[j] = toupper( tmp[0][j] );
val = atof(tmp[1]); reax->sbp[i].r_s = val;
val = atof(tmp[2]); reax->sbp[i].valency = val;
val = atof(tmp[3]); reax->sbp[i].mass = val;
val = atof(tmp[4]); reax->sbp[i].r_vdw = val;
val = atof(tmp[5]); reax->sbp[i].epsilon = val;
val = atof(tmp[6]); reax->sbp[i].gamma = val;
val = atof(tmp[7]); reax->sbp[i].r_pi = val;
val = atof(tmp[8]); reax->sbp[i].valency_e = val;
reax->sbp[i].nlp_opt = 0.5 * (reax->sbp[i].valency_e-reax->sbp[i].valency);
/* line two */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
val = atof(tmp[0]); reax->sbp[i].alpha = val;
val = atof(tmp[1]); reax->sbp[i].gamma_w = val;
val = atof(tmp[2]); reax->sbp[i].valency_boc= val;
val = atof(tmp[3]); reax->sbp[i].p_ovun5 = val;
val = atof(tmp[4]);
val = atof(tmp[5]); reax->sbp[i].chi = val;
val = atof(tmp[6]); reax->sbp[i].eta = 2.0 * val;
val = atof(tmp[7]); reax->sbp[i].p_hbond = (int) val;
/* line 3 */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
val = atof(tmp[0]); reax->sbp[i].r_pi_pi = val;
val = atof(tmp[1]); reax->sbp[i].p_lp2 = val;
val = atof(tmp[2]);
val = atof(tmp[3]); reax->sbp[i].b_o_131 = val;
val = atof(tmp[4]); reax->sbp[i].b_o_132 = val;
val = atof(tmp[5]); reax->sbp[i].b_o_133 = val;
val = atof(tmp[6]);
val = atof(tmp[7]);
/* line 4 */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
/* Sanity check */
if (c < 3) {
- fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n");
+ if (me == 0)
+ fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n");
MPI_Abort( comm, FILE_NOT_FOUND );
}
val = atof(tmp[0]); reax->sbp[i].p_ovun2 = val;
val = atof(tmp[1]); reax->sbp[i].p_val3 = val;
val = atof(tmp[2]);
val = atof(tmp[3]); reax->sbp[i].valency_val= val;
val = atof(tmp[4]); reax->sbp[i].p_val5 = val;
val = atof(tmp[5]); reax->sbp[i].rcore2 = val;
val = atof(tmp[6]); reax->sbp[i].ecore2 = val;
val = atof(tmp[7]); reax->sbp[i].acore2 = val;
/* line 5, only if lgvdw is yes */
if (lgflag) {
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
/* Sanity check */
if (c > 3) {
- fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n");
+ if (me == 0)
+ fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n");
MPI_Abort( comm, FILE_NOT_FOUND );
}
val = atof(tmp[0]); reax->sbp[i].lgcij = val;
val = atof(tmp[1]); reax->sbp[i].lgre = val;
}
if( reax->sbp[i].rcore2>0.01 && reax->sbp[i].acore2>0.01 ){ // Inner-wall
if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals
if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 3 ) {
- if (errorflag)
- fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
- "Force field parameters for element %s\n" \
- "indicate inner wall+shielding, but earlier\n" \
- "atoms indicate different vdWaals-method.\n" \
- "This may cause division-by-zero errors.\n" \
+ if (errorflag && (me == 0))
+ fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
+ "Force field parameters for element %s\n" \
+ "indicate inner wall+shielding, but earlier\n" \
+ "atoms indicate different vdWaals-method.\n" \
+ "This may cause division-by-zero errors.\n" \
"Keeping vdWaals-setting for earlier atoms.\n",
reax->sbp[i].name );
errorflag = 0;
- }
- else{
+ } else{
reax->gp.vdw_type = 3;
}
}
else { // No shielding vdWaals parameters present
- if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 )
- fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
- "Force field parameters for element %s\n" \
+ if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 ) {
+ if (me == 0)
+ fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
+ "Force field parameters for element %s\n" \
"indicate inner wall without shielding, but earlier\n" \
- "atoms indicate different vdWaals-method.\n" \
- "This may cause division-by-zero errors.\n" \
+ "atoms indicate different vdWaals-method.\n" \
+ "This may cause division-by-zero errors.\n" \
"Keeping vdWaals-setting for earlier atoms.\n",
reax->sbp[i].name );
- else{
+ } else {
reax->gp.vdw_type = 2;
}
}
}
else{ // No Inner wall parameters present
if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals
- if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 )
- fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
- "Force field parameters for element %s\n" \
+ if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 ) {
+ if (me == 0)
+ fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \
+ "Force field parameters for element %s\n" \
"indicate shielding without inner wall, but earlier\n" \
- "atoms indicate different vdWaals-method.\n" \
- "This may cause division-by-zero errors.\n" \
+ "atoms indicate different vdWaals-method.\n" \
+ "This may cause division-by-zero errors.\n" \
"Keeping vdWaals-setting for earlier atoms.\n",
reax->sbp[i].name );
- else{
+ } else {
reax->gp.vdw_type = 1;
}
- }
- else{
- fprintf( stderr, "Error: inconsistent vdWaals-parameters\n"\
+ } else {
+ if (me == 0)
+ fprintf( stderr, "Error: inconsistent vdWaals-parameters\n" \
"No shielding or inner-wall set for element %s\n",
reax->sbp[i].name );
MPI_Abort( comm, INVALID_INPUT );
}
}
}
/* Equate vval3 to valf for first-row elements (25/10/2004) */
for( i = 0; i < reax->num_atom_types; i++ )
if( reax->sbp[i].mass < 21 &&
- reax->sbp[i].valency_val != reax->sbp[i].valency_boc ){
- fprintf( stderr, "Warning: changed valency_val to valency_boc for %s\n",
+ reax->sbp[i].valency_val != reax->sbp[i].valency_boc ) {
+ if (me == 0)
+ fprintf(stderr,"Warning: changed valency_val to valency_boc for %s\n",
reax->sbp[i].name );
reax->sbp[i].valency_val = reax->sbp[i].valency_boc;
}
/* next line is number of two body combination and some comments */
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
l = atoi(tmp[0]);
/* a line of comments */
fgets(s,MAX_LINE,fp);
for (i=0; i < l; i++) {
/* line 1 */
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
j = atoi(tmp[0]) - 1;
k = atoi(tmp[1]) - 1;
if (j < reax->num_atom_types && k < reax->num_atom_types) {
val = atof(tmp[2]); reax->tbp[j][k].De_s = val;
reax->tbp[k][j].De_s = val;
val = atof(tmp[3]); reax->tbp[j][k].De_p = val;
reax->tbp[k][j].De_p = val;
val = atof(tmp[4]); reax->tbp[j][k].De_pp = val;
reax->tbp[k][j].De_pp = val;
val = atof(tmp[5]); reax->tbp[j][k].p_be1 = val;
reax->tbp[k][j].p_be1 = val;
val = atof(tmp[6]); reax->tbp[j][k].p_bo5 = val;
reax->tbp[k][j].p_bo5 = val;
val = atof(tmp[7]); reax->tbp[j][k].v13cor = val;
reax->tbp[k][j].v13cor = val;
val = atof(tmp[8]); reax->tbp[j][k].p_bo6 = val;
reax->tbp[k][j].p_bo6 = val;
val = atof(tmp[9]); reax->tbp[j][k].p_ovun1 = val;
reax->tbp[k][j].p_ovun1 = val;
/* line 2 */
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
val = atof(tmp[0]); reax->tbp[j][k].p_be2 = val;
reax->tbp[k][j].p_be2 = val;
val = atof(tmp[1]); reax->tbp[j][k].p_bo3 = val;
reax->tbp[k][j].p_bo3 = val;
val = atof(tmp[2]); reax->tbp[j][k].p_bo4 = val;
reax->tbp[k][j].p_bo4 = val;
val = atof(tmp[3]);
val = atof(tmp[4]); reax->tbp[j][k].p_bo1 = val;
reax->tbp[k][j].p_bo1 = val;
val = atof(tmp[5]); reax->tbp[j][k].p_bo2 = val;
reax->tbp[k][j].p_bo2 = val;
val = atof(tmp[6]); reax->tbp[j][k].ovc = val;
reax->tbp[k][j].ovc = val;
val = atof(tmp[7]);
}
}
for (i=0; i < reax->num_atom_types; i++)
for (j=i; j < reax->num_atom_types; j++) {
reax->tbp[i][j].r_s = 0.5 *
(reax->sbp[i].r_s + reax->sbp[j].r_s);
reax->tbp[j][i].r_s = 0.5 *
(reax->sbp[j].r_s + reax->sbp[i].r_s);
reax->tbp[i][j].r_p = 0.5 *
(reax->sbp[i].r_pi + reax->sbp[j].r_pi);
reax->tbp[j][i].r_p = 0.5 *
(reax->sbp[j].r_pi + reax->sbp[i].r_pi);
reax->tbp[i][j].r_pp = 0.5 *
(reax->sbp[i].r_pi_pi + reax->sbp[j].r_pi_pi);
reax->tbp[j][i].r_pp = 0.5 *
(reax->sbp[j].r_pi_pi + reax->sbp[i].r_pi_pi);
reax->tbp[i][j].p_boc3 =
sqrt(reax->sbp[i].b_o_132 *
reax->sbp[j].b_o_132);
reax->tbp[j][i].p_boc3 =
sqrt(reax->sbp[j].b_o_132 *
reax->sbp[i].b_o_132);
reax->tbp[i][j].p_boc4 =
sqrt(reax->sbp[i].b_o_131 *
reax->sbp[j].b_o_131);
reax->tbp[j][i].p_boc4 =
sqrt(reax->sbp[j].b_o_131 *
reax->sbp[i].b_o_131);
reax->tbp[i][j].p_boc5 =
sqrt(reax->sbp[i].b_o_133 *
reax->sbp[j].b_o_133);
reax->tbp[j][i].p_boc5 =
sqrt(reax->sbp[j].b_o_133 *
reax->sbp[i].b_o_133);
reax->tbp[i][j].D =
sqrt(reax->sbp[i].epsilon *
reax->sbp[j].epsilon);
reax->tbp[j][i].D =
sqrt(reax->sbp[j].epsilon *
reax->sbp[i].epsilon);
reax->tbp[i][j].alpha =
sqrt(reax->sbp[i].alpha *
reax->sbp[j].alpha);
reax->tbp[j][i].alpha =
sqrt(reax->sbp[j].alpha *
reax->sbp[i].alpha);
reax->tbp[i][j].r_vdW =
2.0 * sqrt(reax->sbp[i].r_vdw * reax->sbp[j].r_vdw);
reax->tbp[j][i].r_vdW =
2.0 * sqrt(reax->sbp[j].r_vdw * reax->sbp[i].r_vdw);
reax->tbp[i][j].gamma_w =
sqrt(reax->sbp[i].gamma_w *
reax->sbp[j].gamma_w);
reax->tbp[j][i].gamma_w =
sqrt(reax->sbp[j].gamma_w *
reax->sbp[i].gamma_w);
reax->tbp[i][j].gamma =
pow(reax->sbp[i].gamma *
reax->sbp[j].gamma,-1.5);
reax->tbp[j][i].gamma =
pow(reax->sbp[j].gamma *
reax->sbp[i].gamma,-1.5);
// additions for additional vdWaals interaction types - inner core
reax->tbp[i][j].rcore = reax->tbp[j][i].rcore =
sqrt( reax->sbp[i].rcore2 * reax->sbp[j].rcore2 );
reax->tbp[i][j].ecore = reax->tbp[j][i].ecore =
sqrt( reax->sbp[i].ecore2 * reax->sbp[j].ecore2 );
reax->tbp[i][j].acore = reax->tbp[j][i].acore =
sqrt( reax->sbp[i].acore2 * reax->sbp[j].acore2 );
// additions for additional vdWalls interaction types lg correction
reax->tbp[i][j].lgcij = reax->tbp[j][i].lgcij =
sqrt( reax->sbp[i].lgcij * reax->sbp[j].lgcij );
reax->tbp[i][j].lgre = reax->tbp[j][i].lgre = 2.0 * reax->gp.l[35] *
sqrt( reax->sbp[i].lgre*reax->sbp[j].lgre );
}
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
l = atoi(tmp[0]);
for (i=0; i < l; i++) {
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
j = atoi(tmp[0]) - 1;
k = atoi(tmp[1]) - 1;
if (j < reax->num_atom_types && k < reax->num_atom_types) {
val = atof(tmp[2]);
if (val > 0.0) {
reax->tbp[j][k].D = val;
reax->tbp[k][j].D = val;
}
val = atof(tmp[3]);
if (val > 0.0) {
reax->tbp[j][k].r_vdW = 2 * val;
reax->tbp[k][j].r_vdW = 2 * val;
}
val = atof(tmp[4]);
if (val > 0.0) {
reax->tbp[j][k].alpha = val;
reax->tbp[k][j].alpha = val;
}
val = atof(tmp[5]);
if (val > 0.0) {
reax->tbp[j][k].r_s = val;
reax->tbp[k][j].r_s = val;
}
val = atof(tmp[6]);
if (val > 0.0) {
reax->tbp[j][k].r_p = val;
reax->tbp[k][j].r_p = val;
}
val = atof(tmp[7]);
if (val > 0.0) {
reax->tbp[j][k].r_pp = val;
reax->tbp[k][j].r_pp = val;
}
val = atof(tmp[8]);
if (val >= 0.0) {
reax->tbp[j][k].lgcij = val;
reax->tbp[k][j].lgcij = val;
}
}
}
for( i = 0; i < reax->num_atom_types; ++i )
for( j = 0; j < reax->num_atom_types; ++j )
for( k = 0; k < reax->num_atom_types; ++k )
reax->thbp[i][j][k].cnt = 0;
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
l = atoi( tmp[0] );
for( i = 0; i < l; i++ ) {
fgets(s,MAX_LINE,fp);
c=Tokenize(s,&tmp);
j = atoi(tmp[0]) - 1;
k = atoi(tmp[1]) - 1;
m = atoi(tmp[2]) - 1;
if (j < reax->num_atom_types && k < reax->num_atom_types &&
m < reax->num_atom_types) {
cnt = reax->thbp[j][k][m].cnt;
reax->thbp[j][k][m].cnt++;
reax->thbp[m][k][j].cnt++;
val = atof(tmp[3]);
reax->thbp[j][k][m].prm[cnt].theta_00 = val;
reax->thbp[m][k][j].prm[cnt].theta_00 = val;
val = atof(tmp[4]);
reax->thbp[j][k][m].prm[cnt].p_val1 = val;
reax->thbp[m][k][j].prm[cnt].p_val1 = val;
val = atof(tmp[5]);
reax->thbp[j][k][m].prm[cnt].p_val2 = val;
reax->thbp[m][k][j].prm[cnt].p_val2 = val;
val = atof(tmp[6]);
reax->thbp[j][k][m].prm[cnt].p_coa1 = val;
reax->thbp[m][k][j].prm[cnt].p_coa1 = val;
val = atof(tmp[7]);
reax->thbp[j][k][m].prm[cnt].p_val7 = val;
reax->thbp[m][k][j].prm[cnt].p_val7 = val;
val = atof(tmp[8]);
reax->thbp[j][k][m].prm[cnt].p_pen1 = val;
reax->thbp[m][k][j].prm[cnt].p_pen1 = val;
val = atof(tmp[9]);
reax->thbp[j][k][m].prm[cnt].p_val4 = val;
reax->thbp[m][k][j].prm[cnt].p_val4 = val;
}
}
/* clear all entries first */
for( i = 0; i < reax->num_atom_types; ++i )
for( j = 0; j < reax->num_atom_types; ++j )
for( k = 0; k < reax->num_atom_types; ++k )
for( m = 0; m < reax->num_atom_types; ++m ) {
reax->fbp[i][j][k][m].cnt = 0;
tor_flag[i][j][k][m] = 0;
}
/* next line is number of 4-body params and some comments */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
l = atoi( tmp[0] );
for( i = 0; i < l; i++ ) {
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
j = atoi(tmp[0]) - 1;
k = atoi(tmp[1]) - 1;
m = atoi(tmp[2]) - 1;
n = atoi(tmp[3]) - 1;
if (j >= 0 && n >= 0) { // this means the entry is not in compact form
if (j < reax->num_atom_types && k < reax->num_atom_types &&
m < reax->num_atom_types && n < reax->num_atom_types) {
tor_flag[j][k][m][n] = 1;
tor_flag[n][m][k][j] = 1;
reax->fbp[j][k][m][n].cnt = 1;
reax->fbp[n][m][k][j].cnt = 1;
val = atof(tmp[4]);
reax->fbp[j][k][m][n].prm[0].V1 = val;
reax->fbp[n][m][k][j].prm[0].V1 = val;
val = atof(tmp[5]);
reax->fbp[j][k][m][n].prm[0].V2 = val;
reax->fbp[n][m][k][j].prm[0].V2 = val;
val = atof(tmp[6]);
reax->fbp[j][k][m][n].prm[0].V3 = val;
reax->fbp[n][m][k][j].prm[0].V3 = val;
val = atof(tmp[7]);
reax->fbp[j][k][m][n].prm[0].p_tor1 = val;
reax->fbp[n][m][k][j].prm[0].p_tor1 = val;
val = atof(tmp[8]);
reax->fbp[j][k][m][n].prm[0].p_cot1 = val;
reax->fbp[n][m][k][j].prm[0].p_cot1 = val;
}
}
else { /* This means the entry is of the form 0-X-Y-0 */
if( k < reax->num_atom_types && m < reax->num_atom_types )
for( p = 0; p < reax->num_atom_types; p++ )
for( o = 0; o < reax->num_atom_types; o++ ) {
reax->fbp[p][k][m][o].cnt = 1;
reax->fbp[o][m][k][p].cnt = 1;
if (tor_flag[p][k][m][o] == 0) {
reax->fbp[p][k][m][o].prm[0].V1 = atof(tmp[4]);
reax->fbp[p][k][m][o].prm[0].V2 = atof(tmp[5]);
reax->fbp[p][k][m][o].prm[0].V3 = atof(tmp[6]);
reax->fbp[p][k][m][o].prm[0].p_tor1 = atof(tmp[7]);
reax->fbp[p][k][m][o].prm[0].p_cot1 = atof(tmp[8]);
}
if (tor_flag[o][m][k][p] == 0) {
reax->fbp[o][m][k][p].prm[0].V1 = atof(tmp[4]);
reax->fbp[o][m][k][p].prm[0].V2 = atof(tmp[5]);
reax->fbp[o][m][k][p].prm[0].V3 = atof(tmp[6]);
reax->fbp[o][m][k][p].prm[0].p_tor1 = atof(tmp[7]);
reax->fbp[o][m][k][p].prm[0].p_cot1 = atof(tmp[8]);
}
}
}
}
/* next line is number of hydrogen bond params and some comments */
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
l = atoi( tmp[0] );
for( i = 0; i < reax->num_atom_types; ++i )
for( j = 0; j < reax->num_atom_types; ++j )
for( k = 0; k < reax->num_atom_types; ++k )
reax->hbp[i][j][k].r0_hb = -1.0;
for( i = 0; i < l; i++ ) {
fgets( s, MAX_LINE, fp );
c = Tokenize( s, &tmp );
j = atoi(tmp[0]) - 1;
k = atoi(tmp[1]) - 1;
m = atoi(tmp[2]) - 1;
if( j < reax->num_atom_types && m < reax->num_atom_types ) {
val = atof(tmp[3]);
reax->hbp[j][k][m].r0_hb = val;
val = atof(tmp[4]);
reax->hbp[j][k][m].p_hb1 = val;
val = atof(tmp[5]);
reax->hbp[j][k][m].p_hb2 = val;
val = atof(tmp[6]);
reax->hbp[j][k][m].p_hb3 = val;
}
}
/* deallocate helper storage */
for( i = 0; i < MAX_TOKENS; i++ )
free( tmp[i] );
free( tmp );
free( s );
/* deallocate tor_flag */
for( i = 0; i < reax->num_atom_types; i++ ) {
for( j = 0; j < reax->num_atom_types; j++ ) {
for( k = 0; k < reax->num_atom_types; k++ ) {
free( tor_flag[i][j][k] );
}
free( tor_flag[i][j] );
}
free( tor_flag[i] );
}
free( tor_flag );
// close file
fclose(fp);
return SUCCESS;
}
diff --git a/src/USER-REAXC/reaxc_list.cpp b/src/USER-REAXC/reaxc_list.cpp
index 2755d5506..c15ba7927 100644
--- a/src/USER-REAXC/reaxc_list.cpp
+++ b/src/USER-REAXC/reaxc_list.cpp
@@ -1,126 +1,144 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#include "pair_reaxc.h"
#include "reaxc_list.h"
#include "reaxc_tool_box.h"
/************* allocate list space ******************/
int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm)
{
l->allocated = 1;
l->n = n;
l->num_intrs = num_intrs;
+ if (l->index) sfree(l->index, "list:index");
+ if (l->end_index) sfree(l->end_index, "list:end_index");
l->index = (int*) smalloc( n * sizeof(int), "list:index", comm );
l->end_index = (int*) smalloc( n * sizeof(int), "list:end_index", comm );
l->type = type;
switch(l->type) {
case TYP_VOID:
+ if (l->select.v) sfree(l->select.v, "list:v");
l->select.v = (void*) smalloc(l->num_intrs * sizeof(void*), "list:v", comm);
break;
case TYP_THREE_BODY:
+ if (l->select.three_body_list) sfree(l->select.three_body_list,"list:three_bodies");
l->select.three_body_list = (three_body_interaction_data*)
smalloc( l->num_intrs * sizeof(three_body_interaction_data),
"list:three_bodies", comm );
break;
case TYP_BOND:
+ if (l->select.bond_list) sfree(l->select.bond_list,"list:bonds");
l->select.bond_list = (bond_data*)
smalloc( l->num_intrs * sizeof(bond_data), "list:bonds", comm );
break;
case TYP_DBO:
+ if (l->select.dbo_list) sfree(l->select.dbo_list,"list:dbonds");
l->select.dbo_list = (dbond_data*)
smalloc( l->num_intrs * sizeof(dbond_data), "list:dbonds", comm );
break;
case TYP_DDELTA:
+ if (l->select.dDelta_list) sfree(l->select.dDelta_list,"list:dDeltas");
l->select.dDelta_list = (dDelta_data*)
smalloc( l->num_intrs * sizeof(dDelta_data), "list:dDeltas", comm );
break;
case TYP_FAR_NEIGHBOR:
+ if (l->select.far_nbr_list) sfree(l->select.far_nbr_list,"list:far_nbrs");
l->select.far_nbr_list = (far_neighbor_data*)
smalloc(l->num_intrs * sizeof(far_neighbor_data), "list:far_nbrs", comm);
break;
case TYP_HBOND:
+ if (l->select.hbond_list) sfree(l->select.hbond_list,"list:hbonds");
l->select.hbond_list = (hbond_data*)
smalloc( l->num_intrs * sizeof(hbond_data), "list:hbonds", comm );
break;
default:
fprintf( stderr, "ERROR: no %d list type defined!\n", l->type );
MPI_Abort( comm, INVALID_INPUT );
}
return SUCCESS;
}
void Delete_List( reax_list *l, MPI_Comm comm )
{
if( l->allocated == 0 )
return;
l->allocated = 0;
sfree( l->index, "list:index" );
sfree( l->end_index, "list:end_index" );
+ l->index = NULL;
+ l->end_index = NULL;
switch(l->type) {
case TYP_VOID:
sfree( l->select.v, "list:v" );
+ l->select.v = NULL;
break;
case TYP_HBOND:
sfree( l->select.hbond_list, "list:hbonds" );
+ l->select.hbond_list = NULL;
break;
case TYP_FAR_NEIGHBOR:
sfree( l->select.far_nbr_list, "list:far_nbrs" );
+ l->select.far_nbr_list = NULL;
break;
case TYP_BOND:
sfree( l->select.bond_list, "list:bonds" );
+ l->select.bond_list = NULL;
break;
case TYP_DBO:
sfree( l->select.dbo_list, "list:dbos" );
+ l->select.dbo_list = NULL;
break;
case TYP_DDELTA:
sfree( l->select.dDelta_list, "list:dDeltas" );
+ l->select.dDelta_list = NULL;
break;
case TYP_THREE_BODY:
sfree( l->select.three_body_list, "list:three_bodies" );
+ l->select.three_body_list = NULL;
break;
default:
fprintf( stderr, "ERROR: no %d list type defined!\n", l->type );
MPI_Abort( comm, INVALID_INPUT );
}
}
diff --git a/src/USER-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h
index 547602feb..14078feb0 100644
--- a/src/USER-REAXC/reaxc_types.h
+++ b/src/USER-REAXC/reaxc_types.h
@@ -1,905 +1,905 @@
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, hmaktulga@lbl.gov
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
Please cite the related publication:
H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama,
"Parallel Reactive Molecular Dynamics: Numerical Methods and
Algorithmic Techniques", Parallel Computing, in press.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#ifndef __REAX_TYPES_H_
#define __REAX_TYPES_H_
#include "lmptype.h"
#include <ctype.h>
#include <math.h>
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sys/time.h"
#include <time.h>
#if defined LMP_USER_OMP
#define OMP_TIMING 1
#ifdef OMP_TIMING
// pkcoff timing fields
enum {
- COMPUTEINDEX=0,
- COMPUTEWLINDEX,
- COMPUTEBFINDEX,
- COMPUTEQEQINDEX,
- COMPUTENBFINDEX,
- COMPUTEIFINDEX,
- COMPUTETFINDEX,
- COMPUTEBOINDEX,
- COMPUTEBONDSINDEX,
- COMPUTEATOMENERGYINDEX,
- COMPUTEVALENCEANGLESBOINDEX,
- COMPUTETORSIONANGLESBOINDEX,
- COMPUTEHBONDSINDEX,
- COMPUTECG1INDEX,
- COMPUTECG2INDEX,
- COMPUTECGCOMPUTEINDEX,
- COMPUTECALCQINDEX,
- COMPUTEINITMVINDEX,
- COMPUTEMVCOMPINDEX,
- LASTTIMINGINDEX
+ COMPUTEINDEX=0,
+ COMPUTEWLINDEX,
+ COMPUTEBFINDEX,
+ COMPUTEQEQINDEX,
+ COMPUTENBFINDEX,
+ COMPUTEIFINDEX,
+ COMPUTETFINDEX,
+ COMPUTEBOINDEX,
+ COMPUTEBONDSINDEX,
+ COMPUTEATOMENERGYINDEX,
+ COMPUTEVALENCEANGLESBOINDEX,
+ COMPUTETORSIONANGLESBOINDEX,
+ COMPUTEHBONDSINDEX,
+ COMPUTECG1INDEX,
+ COMPUTECG2INDEX,
+ COMPUTECGCOMPUTEINDEX,
+ COMPUTECALCQINDEX,
+ COMPUTEINITMVINDEX,
+ COMPUTEMVCOMPINDEX,
+ LASTTIMINGINDEX
};
extern double ompTimingData[LASTTIMINGINDEX];
extern int ompTimingCount[LASTTIMINGINDEX];
extern int ompTimingCGCount[LASTTIMINGINDEX];
#endif
#endif
/************* SOME DEFS - crucial for reax_types.h *********/
#define LAMMPS_REAX
//#define DEBUG
//#define DEBUG_FOCUS
//#define TEST_ENERGY
//#define TEST_FORCES
//#define CG_PERFORMANCE
//#define LOG_PERFORMANCE
//#define STANDARD_BOUNDARIES
//#define OLD_BOUNDARIES
//#define MIDPOINT_BOUNDARIES
#define REAX_MAX_STR 1024
#define REAX_MAX_NBRS 6
#define REAX_MAX_3BODY_PARAM 5
#define REAX_MAX_4BODY_PARAM 5
#define REAX_MAX_ATOM_TYPES 25
#define REAX_MAX_MOLECULE_SIZE 20
#define MAX_BOND 20 // same as reaxc_defs.h
/********************** TYPE DEFINITIONS ********************/
typedef int ivec[3];
typedef double rvec[3];
typedef double rtensor[3][3];
typedef double rvec2[2];
typedef double rvec4[4];
// import LAMMPS' definition of tagint and bigint
typedef LAMMPS_NS::tagint rc_tagint;
typedef LAMMPS_NS::bigint rc_bigint;
typedef struct
{
int cnt;
int *index;
void *out_atoms;
} mpi_out_data;
typedef struct
{
MPI_Comm world;
MPI_Comm comm_mesh3D;
MPI_Datatype sys_info;
MPI_Datatype mpi_atom_type;
MPI_Datatype boundary_atom_type;
MPI_Datatype mpi_rvec, mpi_rvec2;
MPI_Datatype restart_atom_type;
MPI_Datatype header_line;
MPI_Datatype header_view;
MPI_Datatype init_desc_line;
MPI_Datatype init_desc_view;
MPI_Datatype atom_line;
MPI_Datatype atom_view;
MPI_Datatype bond_line;
MPI_Datatype bond_view;
MPI_Datatype angle_line;
MPI_Datatype angle_view;
mpi_out_data out_buffers[REAX_MAX_NBRS];
void *in1_buffer;
void *in2_buffer;
} mpi_datatypes;
typedef struct
{
int n_global;
double* l;
int vdw_type;
} global_parameters;
typedef struct
{
/* Line one in field file */
char name[15]; // Two character atom name
double r_s;
double valency; // Valency of the atom
double mass; // Mass of atom
double r_vdw;
double epsilon;
double gamma;
double r_pi;
double valency_e;
double nlp_opt;
/* Line two in field file */
double alpha;
double gamma_w;
double valency_boc;
double p_ovun5;
double chi;
double eta;
int p_hbond; // 1 for H, 2 for hbonding atoms (O,S,P,N), 0 for others
/* Line three in field file */
double r_pi_pi;
double p_lp2;
double b_o_131;
double b_o_132;
double b_o_133;
/* Line four in the field file */
double p_ovun2;
double p_val3;
double valency_val;
double p_val5;
double rcore2;
double ecore2;
double acore2;
/* Line five in the ffield file, only for lgvdw yes */
double lgcij;
double lgre;
} single_body_parameters;
/* Two Body Parameters */
typedef struct {
/* Bond Order parameters */
double p_bo1,p_bo2,p_bo3,p_bo4,p_bo5,p_bo6;
double r_s, r_p, r_pp; // r_o distances in BO formula
double p_boc3, p_boc4, p_boc5;
/* Bond Energy parameters */
double p_be1, p_be2;
double De_s, De_p, De_pp;
/* Over/Under coordination parameters */
double p_ovun1;
/* Van der Waal interaction parameters */
double D;
double alpha;
double r_vdW;
double gamma_w;
double rcore, ecore, acore;
double lgcij, lgre;
/* electrostatic parameters */
double gamma; // note: this parameter is gamma^-3 and not gamma.
double v13cor, ovc;
} two_body_parameters;
/* 3-body parameters */
typedef struct {
/* valence angle */
double theta_00;
double p_val1, p_val2, p_val4, p_val7;
/* penalty */
double p_pen1;
/* 3-body conjugation */
double p_coa1;
} three_body_parameters;
typedef struct{
int cnt;
three_body_parameters prm[REAX_MAX_3BODY_PARAM];
} three_body_header;
/* hydrogen-bond parameters */
typedef struct{
double r0_hb, p_hb1, p_hb2, p_hb3;
} hbond_parameters;
/* 4-body parameters */
typedef struct {
double V1, V2, V3;
/* torsion angle */
double p_tor1;
/* 4-body conjugation */
double p_cot1;
} four_body_parameters;
typedef struct
{
int cnt;
four_body_parameters prm[REAX_MAX_4BODY_PARAM];
} four_body_header;
typedef struct
{
int num_atom_types;
global_parameters gp;
single_body_parameters *sbp;
two_body_parameters **tbp;
three_body_header ***thbp;
hbond_parameters ***hbp;
four_body_header ****fbp;
} reax_interaction;
struct _reax_atom
{
rc_tagint orig_id;
int imprt_id;
int type;
char name[8];
rvec x; // position
rvec v; // velocity
rvec f; // force
rvec f_old;
double q; // charge
rvec4 s; // they take part in
rvec4 t; // computing q
int Hindex;
int num_bonds;
int num_hbonds;
int renumber;
int numbonds; // true number of bonds around atoms
int nbr_id[MAX_BOND]; // ids of neighbors around atoms
double nbr_bo[MAX_BOND]; // BO values of bond between i and nbr
double sum_bo, no_lp; // sum of BO values and no. of lone pairs
};
typedef _reax_atom reax_atom;
typedef struct
{
double V;
rvec min, max, box_norms;
rtensor box, box_inv;
rtensor trans, trans_inv;
rtensor g;
} simulation_box;
struct grid_cell
{
double cutoff;
rvec min, max;
ivec rel_box;
int mark;
int type;
int str;
int end;
int top;
int* atoms;
struct grid_cell** nbrs;
ivec* nbrs_x;
rvec* nbrs_cp;
};
typedef struct grid_cell grid_cell;
typedef struct
{
int total, max_atoms, max_nbrs;
ivec ncells;
rvec cell_len;
rvec inv_len;
ivec bond_span;
ivec nonb_span;
ivec vlist_span;
ivec native_cells;
ivec native_str;
ivec native_end;
double ghost_cut;
ivec ghost_span;
ivec ghost_nonb_span;
ivec ghost_hbond_span;
ivec ghost_bond_span;
grid_cell*** cells;
ivec *order;
} grid;
typedef struct
{
int rank;
int est_send, est_recv;
int atoms_str, atoms_cnt;
ivec rltv, prdc;
rvec bndry_min, bndry_max;
int send_type;
int recv_type;
ivec str_send;
ivec end_send;
ivec str_recv;
ivec end_recv;
} neighbor_proc;
typedef struct
{
int N;
int exc_gcells;
int exc_atoms;
} bound_estimate;
typedef struct
{
double ghost_nonb;
double ghost_hbond;
double ghost_bond;
double ghost_cutoff;
} boundary_cutoff;
using LAMMPS_NS::Pair;
struct _reax_system
{
reax_interaction reax_param;
rc_bigint bigN;
int n, N, numH;
int local_cap, total_cap, gcell_cap, Hcap;
int est_recv, est_trans, max_recved;
int wsize, my_rank, num_nbrs;
ivec my_coords;
neighbor_proc my_nbrs[REAX_MAX_NBRS];
int *global_offset;
simulation_box big_box, my_box, my_ext_box;
grid my_grid;
boundary_cutoff bndry_cuts;
reax_atom *my_atoms;
class Pair *pair_ptr;
int my_bonds;
int mincap;
double safezone, saferzone;
+ int omp_active;
};
typedef _reax_system reax_system;
/* system control parameters */
typedef struct
{
char sim_name[REAX_MAX_STR];
int nprocs;
int nthreads;
ivec procs_by_dim;
/* ensemble values:
0 : NVE
1 : bNVT (Berendsen)
2 : nhNVT (Nose-Hoover)
3 : sNPT (Parrinello-Rehman-Nose-Hoover) semiisotropic
4 : iNPT (Parrinello-Rehman-Nose-Hoover) isotropic
5 : NPT (Parrinello-Rehman-Nose-Hoover) Anisotropic*/
int ensemble;
int nsteps;
double dt;
int geo_format;
int restart;
int restrict_bonds;
int remove_CoM_vel;
int random_vel;
int reposition_atoms;
int reneighbor;
double vlist_cut;
double bond_cut;
double nonb_cut, nonb_low;
double hbond_cut;
double user_ghost_cut;
double bg_cut;
double bo_cut;
double thb_cut;
double thb_cutsq;
int tabulate;
int qeq_freq;
double q_err;
int refactor;
double droptol;
double T_init, T_final, T;
double Tau_T;
int T_mode;
double T_rate, T_freq;
int virial;
rvec P, Tau_P, Tau_PT;
int press_mode;
double compressibility;
int molecular_analysis;
int num_ignored;
int ignore[REAX_MAX_ATOM_TYPES];
int dipole_anal;
int freq_dipole_anal;
int diffusion_coef;
int freq_diffusion_coef;
int restrict_type;
int lgflag;
int enobondsflag;
} control_params;
typedef struct
{
double T;
double xi;
double v_xi;
double v_xi_old;
double G_xi;
} thermostat;
typedef struct
{
double P;
double eps;
double v_eps;
double v_eps_old;
double a_eps;
} isotropic_barostat;
typedef struct
{
rtensor P;
double P_scalar;
double eps;
double v_eps;
double v_eps_old;
double a_eps;
rtensor h0;
rtensor v_g0;
rtensor v_g0_old;
rtensor a_g0;
} flexible_barostat;
typedef struct
{
double start;
double end;
double elapsed;
double total;
double comm;
double nbrs;
double init_forces;
double bonded;
double nonb;
double qEq;
int s_matvecs;
int t_matvecs;
} reax_timing;
typedef struct
{
double e_tot;
double e_kin; // Total kinetic energy
double e_pot;
double e_bond; // Total bond energy
double e_ov; // Total over coordination
double e_un; // Total under coordination energy
double e_lp; // Total under coordination energy
double e_ang; // Total valance angle energy
double e_pen; // Total penalty energy
double e_coa; // Total three body conjgation energy
double e_hb; // Total Hydrogen bond energy
double e_tor; // Total torsional energy
double e_con; // Total four body conjugation energy
double e_vdW; // Total van der Waals energy
double e_ele; // Total electrostatics energy
double e_pol; // Polarization energy
} energy_data;
typedef struct
{
int step;
int prev_steps;
double time;
double M; // Total Mass
double inv_M; // 1 / Total Mass
rvec xcm; // Center of mass
rvec vcm; // Center of mass velocity
rvec fcm; // Center of mass force
rvec amcm; // Angular momentum of CoM
rvec avcm; // Angular velocity of CoM
double etran_cm; // Translational kinetic energy of CoM
double erot_cm; // Rotational kinetic energy of CoM
rtensor kinetic; // Kinetic energy tensor
rtensor virial; // Hydrodynamic virial
energy_data my_en;
energy_data sys_en;
double N_f; //Number of degrees of freedom
rvec t_scale;
rtensor p_scale;
thermostat therm; // Used in Nose_Hoover method
isotropic_barostat iso_bar;
flexible_barostat flex_bar;
double inv_W;
double kin_press;
rvec int_press;
rvec my_ext_press;
rvec ext_press;
rvec tot_press;
reax_timing timing;
} simulation_data;
typedef struct{
int thb;
int pthb; // pointer to the third body on the central atom's nbrlist
double theta, cos_theta;
rvec dcos_di, dcos_dj, dcos_dk;
} three_body_interaction_data;
typedef struct {
int nbr;
ivec rel_box;
double d;
rvec dvec;
} far_neighbor_data;
typedef struct {
int nbr;
int scl;
far_neighbor_data *ptr;
} hbond_data;
typedef struct{
int wrt;
rvec dVal;
} dDelta_data;
typedef struct{
int wrt;
rvec dBO, dBOpi, dBOpi2;
} dbond_data;
typedef struct{
double BO, BO_s, BO_pi, BO_pi2;
double Cdbo, Cdbopi, Cdbopi2;
double C1dbo, C2dbo, C3dbo;
double C1dbopi, C2dbopi, C3dbopi, C4dbopi;
double C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2;
rvec dBOp, dln_BOp_s, dln_BOp_pi, dln_BOp_pi2;
double *CdboReduction;
} bond_order_data;
typedef struct {
int nbr;
int sym_index;
int dbond_index;
ivec rel_box;
// rvec ext_factor;
double d;
rvec dvec;
bond_order_data bo_data;
} bond_data;
typedef struct {
int j;
double val;
} sparse_matrix_entry;
typedef struct {
int cap, n, m;
int *start, *end;
sparse_matrix_entry *entries;
} sparse_matrix;
typedef struct {
int num_far;
int H, Htop;
int hbonds, num_hbonds;
int bonds, num_bonds;
int num_3body;
int gcell_atoms;
} reallocate_data;
typedef struct
{
int allocated;
/* communication storage */
double *tmp_dbl[REAX_MAX_NBRS];
rvec *tmp_rvec[REAX_MAX_NBRS];
rvec2 *tmp_rvec2[REAX_MAX_NBRS];
int *within_bond_box;
/* bond order related storage */
double *total_bond_order;
double *Deltap, *Deltap_boc;
double *Delta, *Delta_lp, *Delta_lp_temp, *Delta_e, *Delta_boc, *Delta_val;
double *dDelta_lp, *dDelta_lp_temp;
double *nlp, *nlp_temp, *Clp, *vlpex;
rvec *dDeltap_self;
int *bond_mark, *done_after;
/* QEq storage */
sparse_matrix *H, *L, *U;
double *Hdia_inv, *b_s, *b_t, *b_prc, *b_prm, *s, *t;
double *droptol;
rvec2 *b, *x;
/* GMRES storage */
double *y, *z, *g;
double *hc, *hs;
double **h, **v;
/* CG storage */
double *r, *d, *q, *p;
rvec2 *r2, *d2, *q2, *p2;
/* Taper */
double Tap[8]; //Tap7, Tap6, Tap5, Tap4, Tap3, Tap2, Tap1, Tap0;
/* storage for analysis */
int *mark, *old_mark;
rvec *x_old;
/* storage space for bond restrictions */
int *restricted;
int **restricted_list;
/* integrator */
rvec *v_const;
/* force calculations */
double *CdDelta; // coefficient of dDelta
rvec *f;
/* omp */
rvec *forceReduction;
rvec *my_ext_pressReduction;
double *CdDeltaReduction;
int *valence_angle_atom_myoffset;
-
reallocate_data realloc;
} storage;
typedef union
{
void *v;
three_body_interaction_data *three_body_list;
bond_data *bond_list;
dbond_data *dbo_list;
dDelta_data *dDelta_list;
far_neighbor_data *far_nbr_list;
hbond_data *hbond_list;
} list_type;
struct _reax_list
{
int allocated;
int n;
int num_intrs;
int *index;
int *end_index;
int type;
list_type select;
};
typedef _reax_list reax_list;
typedef struct
{
FILE *strj;
int trj_offset;
int atom_line_len;
int bond_line_len;
int angle_line_len;
int write_atoms;
int write_bonds;
int write_angles;
char *line;
int buffer_len;
char *buffer;
FILE *out;
FILE *pot;
FILE *log;
FILE *mol, *ign;
FILE *dpl;
FILE *drft;
FILE *pdb;
FILE *prs;
int write_steps;
int traj_compress;
int traj_method;
char traj_title[81];
int atom_info;
int bond_info;
int angle_info;
int restart_format;
int restart_freq;
int debug_level;
int energy_update_freq;
} output_controls;
typedef struct
{
int atom_count;
int atom_list[REAX_MAX_MOLECULE_SIZE];
int mtypes[REAX_MAX_ATOM_TYPES];
} molecule;
struct LR_data
{
double H;
double e_vdW, CEvd;
double e_ele, CEclmb;
void operator = (const LR_data& rhs) {
H = rhs.H;
e_vdW = rhs.e_vdW;
CEvd = rhs.CEvd;
e_ele = rhs.e_ele;
CEclmb = rhs.CEclmb;
}
void operator = (const LR_data& rhs) volatile {
H = rhs.H;
e_vdW = rhs.e_vdW;
CEvd = rhs.CEvd;
e_ele = rhs.e_ele;
CEclmb = rhs.CEclmb;
}
};
struct cubic_spline_coef
{
double a, b, c, d;
void operator = (const cubic_spline_coef& rhs) {
a = rhs.a;
b = rhs.b;
c = rhs.c;
d = rhs.d;
}
void operator = (const cubic_spline_coef& rhs) volatile {
a = rhs.a;
b = rhs.b;
c = rhs.c;
d = rhs.d;
}
};
typedef struct
{
double xmin, xmax;
int n;
double dx, inv_dx;
double a;
double m;
double c;
LR_data *y;
cubic_spline_coef *H;
cubic_spline_coef *vdW, *CEvd;
cubic_spline_coef *ele, *CEclmb;
} LR_lookup_table;
extern LR_lookup_table **LR;
/* function pointer defs */
typedef void (*evolve_function)(reax_system*, control_params*,
simulation_data*, storage*, reax_list**,
output_controls*, mpi_datatypes* );
typedef void (*interaction_function) (reax_system*, control_params*,
simulation_data*, storage*,
reax_list**, output_controls*);
typedef void (*print_interaction)(reax_system*, control_params*,
simulation_data*, storage*,
reax_list**, output_controls*);
typedef double (*lookup_function)(double);
typedef void (*message_sorter) (reax_system*, int, int, int, mpi_out_data*);
typedef void (*unpacker) ( reax_system*, int, void*, int, neighbor_proc*, int );
typedef void (*dist_packer) (void*, mpi_out_data*);
typedef void (*coll_unpacker) (void*, void*, mpi_out_data*);
#endif
diff --git a/src/USER-TALLY/compute_force_tally.cpp b/src/USER-TALLY/compute_force_tally.cpp
index cb7e3a4f2..5f29aea5b 100644
--- a/src/USER-TALLY/compute_force_tally.cpp
+++ b/src/USER-TALLY/compute_force_tally.cpp
@@ -1,221 +1,221 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <string.h>
#include "compute_force_tally.h"
#include "atom.h"
#include "group.h"
#include "pair.h"
#include "update.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeForceTally::ComputeForceTally(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute force/tally command");
igroup2 = group->find(arg[3]);
if (igroup2 == -1)
error->all(FLERR,"Could not find compute force/tally second group ID");
groupbit2 = group->bitmask[igroup2];
scalar_flag = 1;
vector_flag = 0;
peratom_flag = 1;
timeflag = 1;
comm_reverse = size_peratom_cols = 3;
extscalar = 1;
peflag = 1; // we need Pair::ev_tally() to be run
did_setup = invoked_peratom = invoked_scalar = -1;
nmax = -1;
fatom = NULL;
vector = new double[size_peratom_cols];
}
/* ---------------------------------------------------------------------- */
ComputeForceTally::~ComputeForceTally()
{
if (force && force->pair) force->pair->del_tally_callback(this);
memory->destroy(fatom);
delete[] vector;
}
/* ---------------------------------------------------------------------- */
void ComputeForceTally::init()
{
if (force->pair == NULL)
error->all(FLERR,"Trying to use compute force/tally without pair style");
else
force->pair->add_tally_callback(this);
if (comm->me == 0) {
if (force->pair->single_enable == 0 || force->pair->manybody_flag)
error->warning(FLERR,"Compute force/tally used with incompatible pair style");
if (force->bond || force->angle || force->dihedral
|| force->improper || force->kspace)
error->warning(FLERR,"Compute force/tally only called from pair style");
}
did_setup = -1;
}
/* ---------------------------------------------------------------------- */
void ComputeForceTally::pair_setup_callback(int, int)
{
const int ntotal = atom->nlocal + atom->nghost;
// grow per-atom storage, if needed
if (atom->nmax > nmax) {
memory->destroy(fatom);
nmax = atom->nmax;
memory->create(fatom,nmax,size_peratom_cols,"force/tally:fatom");
array_atom = fatom;
}
// clear storage
for (int i=0; i < ntotal; ++i)
for (int j=0; j < size_peratom_cols; ++j)
fatom[i][j] = 0.0;
for (int i=0; i < size_peratom_cols; ++i)
vector[i] = ftotal[i] = 0.0;
did_setup = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void ComputeForceTally::pair_tally_callback(int i, int j, int nlocal, int newton,
double, double, double fpair,
double dx, double dy, double dz)
{
const int * const mask = atom->mask;
if ( ((mask[i] & groupbit) && (mask[j] & groupbit2))
|| ((mask[i] & groupbit2) && (mask[j] & groupbit)) ) {
if (newton || i < nlocal) {
if (mask[i] & groupbit) {
ftotal[0] += fpair*dx;
ftotal[1] += fpair*dy;
ftotal[2] += fpair*dz;
}
fatom[i][0] += fpair*dx;
fatom[i][1] += fpair*dy;
fatom[i][2] += fpair*dz;
}
if (newton || j < nlocal) {
if (mask[j] & groupbit) {
ftotal[0] -= fpair*dx;
ftotal[1] -= fpair*dy;
ftotal[2] -= fpair*dz;
}
fatom[j][0] -= fpair*dx;
fatom[j][1] -= fpair*dy;
fatom[j][2] -= fpair*dz;
}
}
}
/* ---------------------------------------------------------------------- */
int ComputeForceTally::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = fatom[i][0];
buf[m++] = fatom[i][1];
buf[m++] = fatom[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeForceTally::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
fatom[j][0] += buf[m++];
fatom[j][1] += buf[m++];
fatom[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
double ComputeForceTally::compute_scalar()
{
invoked_scalar = update->ntimestep;
if ((did_setup != invoked_scalar)
|| (update->eflag_global != invoked_scalar))
error->all(FLERR,"Energy was not tallied on needed timestep");
// sum accumulated forces across procs
MPI_Allreduce(ftotal,vector,size_peratom_cols,MPI_DOUBLE,MPI_SUM,world);
scalar = sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]);
return scalar;
}
/* ---------------------------------------------------------------------- */
void ComputeForceTally::compute_peratom()
{
invoked_peratom = update->ntimestep;
if ((did_setup != invoked_peratom)
|| (update->eflag_global != invoked_peratom))
error->all(FLERR,"Energy was not tallied on needed timestep");
// collect contributions from ghost atoms
if (force->newton_pair) {
comm->reverse_comm_compute(this);
// clear out ghost atom data after it has been collected to local atoms
const int nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; ++i)
for (int j = 0; j < size_peratom_cols; ++j)
fatom[i][j] = 0.0;
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputeForceTally::memory_usage()
{
- double bytes = nmax*size_peratom_cols * sizeof(double);
+ double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double);
return bytes;
}
diff --git a/src/USER-TALLY/compute_heat_flux_tally.cpp b/src/USER-TALLY/compute_heat_flux_tally.cpp
index b366b92be..c090050b1 100644
--- a/src/USER-TALLY/compute_heat_flux_tally.cpp
+++ b/src/USER-TALLY/compute_heat_flux_tally.cpp
@@ -1,281 +1,281 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <string.h>
#include "compute_heat_flux_tally.h"
#include "atom.h"
#include "group.h"
#include "pair.h"
#include "update.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeHeatFluxTally::ComputeHeatFluxTally(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute heat/flux/tally command");
igroup2 = group->find(arg[3]);
if (igroup2 == -1)
error->all(FLERR,"Could not find compute heat/flux/tally second group ID");
groupbit2 = group->bitmask[igroup2];
vector_flag = 1;
timeflag = 1;
comm_reverse = 7;
extvector = 1;
size_vector = 6;
peflag = 1; // we need Pair::ev_tally() to be run
did_setup = 0;
invoked_peratom = invoked_scalar = -1;
nmax = -1;
stress = NULL;
eatom = NULL;
vector = new double[size_vector];
heatj = new double[size_vector];
}
/* ---------------------------------------------------------------------- */
ComputeHeatFluxTally::~ComputeHeatFluxTally()
{
if (force && force->pair) force->pair->del_tally_callback(this);
memory->destroy(stress);
memory->destroy(eatom);
delete[] heatj;
delete[] vector;
}
/* ---------------------------------------------------------------------- */
void ComputeHeatFluxTally::init()
{
if (force->pair == NULL)
error->all(FLERR,"Trying to use compute heat/flux/tally without pair style");
else
force->pair->add_tally_callback(this);
if (comm->me == 0) {
if (force->pair->single_enable == 0 || force->pair->manybody_flag)
error->warning(FLERR,"Compute heat/flux/tally used with incompatible pair style");
if (force->bond || force->angle || force->dihedral
|| force->improper || force->kspace)
error->warning(FLERR,"Compute heat/flux/tally only called from pair style");
}
did_setup = -1;
}
/* ---------------------------------------------------------------------- */
void ComputeHeatFluxTally::pair_setup_callback(int, int)
{
const int ntotal = atom->nlocal + atom->nghost;
// grow per-atom storage, if needed
if (atom->nmax > nmax) {
memory->destroy(stress);
memory->destroy(eatom);
nmax = atom->nmax;
memory->create(stress,nmax,6,"heat/flux/tally:stress");
memory->create(eatom,nmax,"heat/flux/tally:eatom");
}
// clear storage
for (int i=0; i < ntotal; ++i) {
eatom[i] = 0.0;
stress[i][0] = 0.0;
stress[i][1] = 0.0;
stress[i][2] = 0.0;
stress[i][3] = 0.0;
stress[i][4] = 0.0;
stress[i][5] = 0.0;
}
for (int i=0; i < size_vector; ++i)
vector[i] = heatj[i] = 0.0;
did_setup = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void ComputeHeatFluxTally::pair_tally_callback(int i, int j, int nlocal, int newton,
double evdwl, double ecoul, double fpair,
double dx, double dy, double dz)
{
const int * const mask = atom->mask;
if ( ((mask[i] & groupbit) && (mask[j] & groupbit2))
|| ((mask[i] & groupbit2) && (mask[j] & groupbit)) ) {
const double epairhalf = 0.5 * (evdwl + ecoul);
fpair *= 0.5;
const double v0 = dx*dx*fpair; // dx*fpair = Fij_x
const double v1 = dy*dy*fpair;
const double v2 = dz*dz*fpair;
const double v3 = dx*dy*fpair;
const double v4 = dx*dz*fpair;
const double v5 = dy*dz*fpair;
if (newton || i < nlocal) {
eatom[i] += epairhalf;
stress[i][0] += v0;
stress[i][1] += v1;
stress[i][2] += v2;
stress[i][3] += v3;
stress[i][4] += v4;
stress[i][5] += v5;
}
if (newton || j < nlocal) {
eatom[j] += epairhalf;
stress[j][0] += v0;
stress[j][1] += v1;
stress[j][2] += v2;
stress[j][3] += v3;
stress[j][4] += v4;
stress[j][5] += v5;
}
}
}
/* ---------------------------------------------------------------------- */
int ComputeHeatFluxTally::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = eatom[i];
buf[m++] = stress[i][0];
buf[m++] = stress[i][1];
buf[m++] = stress[i][2];
buf[m++] = stress[i][3];
buf[m++] = stress[i][4];
buf[m++] = stress[i][5];
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeHeatFluxTally::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
eatom[j] += buf[m++];
stress[j][0] += buf[m++];
stress[j][1] += buf[m++];
stress[j][2] += buf[m++];
stress[j][3] += buf[m++];
stress[j][4] += buf[m++];
stress[j][5] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void ComputeHeatFluxTally::compute_vector()
{
invoked_vector = update->ntimestep;
if ((did_setup != invoked_vector) || (update->eflag_global != invoked_vector))
error->all(FLERR,"Energy was not tallied on needed timestep");
// collect contributions from ghost atoms
if (force->newton_pair) {
comm->reverse_comm_compute(this);
const int nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; ++i) {
eatom[i] = 0.0;
stress[i][0] = 0.0;
stress[i][1] = 0.0;
stress[i][2] = 0.0;
stress[i][3] = 0.0;
stress[i][4] = 0.0;
stress[i][5] = 0.0;
}
}
// compute heat currents
// heat flux vector = jc[3] + jv[3]
// jc[3] = convective portion of heat flux = sum_i (ke_i + pe_i) v_i[3]
// jv[3] = virial portion of heat flux = sum_i (stress_tensor_i . v_i[3])
// normalization by volume is not included
// J = sum_i( (0.5*m*v_i^2 + 0.5*(evdwl_i+ecoul_i))*v_i +
// + (F_ij . v_i)*dR_ij/2 )
int nlocal = atom->nlocal;
int *mask = atom->mask;
const double pfactor = 0.5 * force->mvv2e;
double **v = atom->v;
double *mass = atom->mass;
double *rmass = atom->rmass;
int *type = atom->type;
double jc[3] = {0.0,0.0,0.0};
double jv[3] = {0.0,0.0,0.0};
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
const double * const vi = v[i];
const double * const si = stress[i];
double ke_i;
if (rmass) ke_i = pfactor * rmass[i];
else ke_i = pfactor * mass[type[i]];
ke_i *= (vi[0]*vi[0] + vi[1]*vi[1] + vi[2]*vi[2]);
ke_i += eatom[i];
jc[0] += ke_i*vi[0];
jc[1] += ke_i*vi[1];
jc[2] += ke_i*vi[2];
jv[0] += si[0]*vi[0] + si[3]*vi[1] + si[4]*vi[2];
jv[1] += si[3]*vi[0] + si[1]*vi[1] + si[5]*vi[2];
jv[2] += si[4]*vi[0] + si[5]*vi[1] + si[2]*vi[2];
}
}
// sum accumulated heatj across procs
heatj[0] = jc[0] + jv[0];
heatj[1] = jc[1] + jv[1];
heatj[2] = jc[2] + jv[2];
heatj[3] = jc[0];
heatj[4] = jc[1];
heatj[5] = jc[2];
MPI_Allreduce(heatj,vector,size_vector,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputeHeatFluxTally::memory_usage()
{
- double bytes = nmax*comm_reverse * sizeof(double);
+ double bytes = (nmax < 0) ? 0 : nmax*comm_reverse * sizeof(double);
return bytes;
}
diff --git a/src/USER-TALLY/compute_pe_tally.cpp b/src/USER-TALLY/compute_pe_tally.cpp
index e7c0bdd03..5b4644d4e 100644
--- a/src/USER-TALLY/compute_pe_tally.cpp
+++ b/src/USER-TALLY/compute_pe_tally.cpp
@@ -1,205 +1,205 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <string.h>
#include "compute_pe_tally.h"
#include "atom.h"
#include "group.h"
#include "pair.h"
#include "update.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputePETally::ComputePETally(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute pe/tally command");
igroup2 = group->find(arg[3]);
if (igroup2 == -1)
error->all(FLERR,"Could not find compute pe/tally second group ID");
groupbit2 = group->bitmask[igroup2];
scalar_flag = 1;
vector_flag = 0;
peratom_flag = 1;
timeflag = 1;
comm_reverse = size_peratom_cols = 2;
extscalar = 1;
peflag = 1; // we need Pair::ev_tally() to be run
did_setup = invoked_peratom = invoked_scalar = -1;
nmax = -1;
eatom = NULL;
vector = new double[size_peratom_cols];
}
/* ---------------------------------------------------------------------- */
ComputePETally::~ComputePETally()
{
if (force && force->pair) force->pair->del_tally_callback(this);
memory->destroy(eatom);
delete[] vector;
}
/* ---------------------------------------------------------------------- */
void ComputePETally::init()
{
if (force->pair == NULL)
error->all(FLERR,"Trying to use compute pe/tally without a pair style");
else
force->pair->add_tally_callback(this);
if (comm->me == 0) {
if (force->pair->single_enable == 0 || force->pair->manybody_flag)
error->warning(FLERR,"Compute pe/tally used with incompatible pair style");
if (force->bond || force->angle || force->dihedral
|| force->improper || force->kspace)
error->warning(FLERR,"Compute pe/tally only called from pair style");
}
did_setup = -1;
}
/* ---------------------------------------------------------------------- */
void ComputePETally::pair_setup_callback(int, int)
{
const int ntotal = atom->nlocal + atom->nghost;
// grow per-atom storage, if needed
if (atom->nmax > nmax) {
memory->destroy(eatom);
nmax = atom->nmax;
memory->create(eatom,nmax,size_peratom_cols,"pe/tally:eatom");
array_atom = eatom;
}
// clear storage
for (int i=0; i < ntotal; ++i)
eatom[i][0] = eatom[i][1] = 0.0;
vector[0] = etotal[0] = vector[1] = etotal[1] = 0.0;
did_setup = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void ComputePETally::pair_tally_callback(int i, int j, int nlocal, int newton,
double evdwl, double ecoul, double,
double, double, double)
{
const int * const mask = atom->mask;
if ( ((mask[i] & groupbit) && (mask[j] & groupbit2))
|| ((mask[i] & groupbit2) && (mask[j] & groupbit)) ) {
evdwl *= 0.5; ecoul *= 0.5;
if (newton || i < nlocal) {
etotal[0] += evdwl; eatom[i][0] += evdwl;
etotal[1] += ecoul; eatom[i][1] += ecoul;
}
if (newton || j < nlocal) {
etotal[0] += evdwl; eatom[j][0] += evdwl;
etotal[1] += ecoul; eatom[j][1] += ecoul;
}
}
}
/* ---------------------------------------------------------------------- */
int ComputePETally::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = eatom[i][0];
buf[m++] = eatom[i][1];
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputePETally::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
eatom[j][0] += buf[m++];
eatom[j][1] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
double ComputePETally::compute_scalar()
{
invoked_scalar = update->ntimestep;
if ((did_setup != invoked_scalar)
|| (update->eflag_global != invoked_scalar))
error->all(FLERR,"Energy was not tallied on needed timestep");
// sum accumulated energies across procs
MPI_Allreduce(etotal,vector,size_peratom_cols,MPI_DOUBLE,MPI_SUM,world);
scalar = vector[0]+vector[1];
return scalar;
}
/* ---------------------------------------------------------------------- */
void ComputePETally::compute_peratom()
{
invoked_peratom = update->ntimestep;
if ((did_setup != invoked_peratom)
|| (update->eflag_global != invoked_peratom))
error->all(FLERR,"Energy was not tallied on needed timestep");
// collect contributions from ghost atoms
if (force->newton_pair) {
comm->reverse_comm_compute(this);
// clear out ghost atom data after it has been collected to local atoms
const int nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; ++i)
eatom[i][0] = eatom[i][1] = 0.0;
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputePETally::memory_usage()
{
- double bytes = nmax*size_peratom_cols * sizeof(double);
+ double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double);
return bytes;
}
diff --git a/src/USER-TALLY/compute_stress_tally.cpp b/src/USER-TALLY/compute_stress_tally.cpp
index 28baafb9f..32253d2ca 100644
--- a/src/USER-TALLY/compute_stress_tally.cpp
+++ b/src/USER-TALLY/compute_stress_tally.cpp
@@ -1,248 +1,248 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <string.h>
#include "compute_stress_tally.h"
#include "atom.h"
#include "group.h"
#include "pair.h"
#include "update.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeStressTally::ComputeStressTally(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute stress/tally command");
igroup2 = group->find(arg[3]);
if (igroup2 == -1)
error->all(FLERR,"Could not find compute stress/tally second group ID");
groupbit2 = group->bitmask[igroup2];
scalar_flag = 1;
vector_flag = 0;
peratom_flag = 1;
timeflag = 1;
comm_reverse = size_peratom_cols = 6;
extscalar = 0;
peflag = 1; // we need Pair::ev_tally() to be run
did_setup = invoked_peratom = invoked_scalar = -1;
nmax = -1;
stress = NULL;
vector = new double[size_peratom_cols];
virial = new double[size_peratom_cols];
}
/* ---------------------------------------------------------------------- */
ComputeStressTally::~ComputeStressTally()
{
if (force && force->pair) force->pair->del_tally_callback(this);
memory->destroy(stress);
delete[] virial;
delete[] vector;
}
/* ---------------------------------------------------------------------- */
void ComputeStressTally::init()
{
if (force->pair == NULL)
error->all(FLERR,"Trying to use compute stress/tally without pair style");
else
force->pair->add_tally_callback(this);
if (comm->me == 0) {
if (force->pair->single_enable == 0 || force->pair->manybody_flag)
error->warning(FLERR,"Compute stress/tally used with incompatible pair style");
if (force->bond || force->angle || force->dihedral
|| force->improper || force->kspace)
error->warning(FLERR,"Compute stress/tally only called from pair style");
}
did_setup = -1;
}
/* ---------------------------------------------------------------------- */
void ComputeStressTally::pair_setup_callback(int, int)
{
const int ntotal = atom->nlocal + atom->nghost;
// grow per-atom storage, if needed
if (atom->nmax > nmax) {
memory->destroy(stress);
nmax = atom->nmax;
memory->create(stress,nmax,size_peratom_cols,"stress/tally:stress");
array_atom = stress;
}
// clear storage
for (int i=0; i < ntotal; ++i)
for (int j=0; j < size_peratom_cols; ++j)
stress[i][j] = 0.0;
for (int i=0; i < size_peratom_cols; ++i)
vector[i] = virial[i] = 0.0;
did_setup = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void ComputeStressTally::pair_tally_callback(int i, int j, int nlocal, int newton,
double, double, double fpair,
double dx, double dy, double dz)
{
const int * const mask = atom->mask;
if ( ((mask[i] & groupbit) && (mask[j] & groupbit2))
|| ((mask[i] & groupbit2) && (mask[j] & groupbit)) ) {
fpair *= 0.5;
const double v0 = dx*dx*fpair;
const double v1 = dy*dy*fpair;
const double v2 = dz*dz*fpair;
const double v3 = dx*dy*fpair;
const double v4 = dx*dz*fpair;
const double v5 = dy*dz*fpair;
if (newton || i < nlocal) {
virial[0] += v0; stress[i][0] += v0;
virial[1] += v1; stress[i][1] += v1;
virial[2] += v2; stress[i][2] += v2;
virial[3] += v3; stress[i][3] += v3;
virial[4] += v4; stress[i][4] += v4;
virial[5] += v5; stress[i][5] += v5;
}
if (newton || j < nlocal) {
virial[0] += v0; stress[j][0] += v0;
virial[1] += v1; stress[j][1] += v1;
virial[2] += v2; stress[j][2] += v2;
virial[3] += v3; stress[j][3] += v3;
virial[4] += v4; stress[j][4] += v4;
virial[5] += v5; stress[j][5] += v5;
}
}
}
/* ---------------------------------------------------------------------- */
int ComputeStressTally::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = stress[i][0];
buf[m++] = stress[i][1];
buf[m++] = stress[i][2];
buf[m++] = stress[i][3];
buf[m++] = stress[i][4];
buf[m++] = stress[i][5];
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeStressTally::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
stress[j][0] += buf[m++];
stress[j][1] += buf[m++];
stress[j][2] += buf[m++];
stress[j][3] += buf[m++];
stress[j][4] += buf[m++];
stress[j][5] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
double ComputeStressTally::compute_scalar()
{
invoked_scalar = update->ntimestep;
if ((did_setup != invoked_scalar)
|| (update->eflag_global != invoked_scalar))
error->all(FLERR,"Energy was not tallied on needed timestep");
// sum accumulated forces across procs
MPI_Allreduce(virial,vector,size_peratom_cols,MPI_DOUBLE,MPI_SUM,world);
if (domain->dimension == 3)
scalar = (vector[0]+vector[1]+vector[2])/3.0;
else
scalar = (vector[0]+vector[1])/2.0;
return scalar;
}
/* ---------------------------------------------------------------------- */
void ComputeStressTally::compute_peratom()
{
invoked_peratom = update->ntimestep;
if ((did_setup != invoked_peratom)
|| (update->eflag_global != invoked_peratom))
error->all(FLERR,"Energy was not tallied on needed timestep");
// collect contributions from ghost atoms
if (force->newton_pair) {
comm->reverse_comm_compute(this);
const int nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; ++i)
for (int j = 0; j < size_peratom_cols; ++j)
stress[i][j] = 0.0;
}
// convert to stress*volume units = -pressure*volume
const double nktv2p = -force->nktv2p;
for (int i = 0; i < atom->nlocal; i++) {
stress[i][0] *= nktv2p;
stress[i][1] *= nktv2p;
stress[i][2] *= nktv2p;
stress[i][3] *= nktv2p;
stress[i][4] *= nktv2p;
stress[i][5] *= nktv2p;
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputeStressTally::memory_usage()
{
- double bytes = nmax*size_peratom_cols * sizeof(double);
+ double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double);
return bytes;
}
diff --git a/src/compute_rdf.cpp b/src/compute_rdf.cpp
index 72eb46f6f..167de4576 100644
--- a/src/compute_rdf.cpp
+++ b/src/compute_rdf.cpp
@@ -1,413 +1,413 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Paul Crozier (SNL), Jeff Greathouse (SNL)
------------------------------------------------------------------------- */
#include <mpi.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "compute_rdf.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "neigh_list.h"
#include "group.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg),
rdfpair(NULL), nrdfpair(NULL), ilo(NULL), ihi(NULL), jlo(NULL), jhi(NULL),
- hist(NULL), histall(NULL), typecount(NULL), icount(NULL), jcount(NULL),
+ hist(NULL), histall(NULL), typecount(NULL), icount(NULL), jcount(NULL),
duplicates(NULL)
{
if (narg < 4 || (narg-4) % 2) error->all(FLERR,"Illegal compute rdf command");
array_flag = 1;
extarray = 0;
nbin = force->inumeric(FLERR,arg[3]);
if (nbin < 1) error->all(FLERR,"Illegal compute rdf command");
// optional args
// nargpair = # of pairwise args, starting at iarg = 4
cutflag = 0;
int iarg;
for (iarg = 4; iarg < narg; iarg++)
if (strcmp(arg[iarg],"cutoff") == 0) break;
int nargpair = iarg - 4;
while (iarg < narg) {
if (strcmp(arg[iarg],"cutoff") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal compute rdf command");
cutoff_user = force->numeric(FLERR,arg[iarg+1]);
if (cutoff_user <= 0.0) cutflag = 0;
else cutflag = 1;
iarg += 2;
} else error->all(FLERR,"Illegal compute rdf command");
}
-
+
// pairwise args
if (nargpair == 0) npairs = 1;
else npairs = nargpair/2;
size_array_rows = nbin;
size_array_cols = 1 + 2*npairs;
int ntypes = atom->ntypes;
memory->create(rdfpair,npairs,ntypes+1,ntypes+1,"rdf:rdfpair");
memory->create(nrdfpair,ntypes+1,ntypes+1,"rdf:nrdfpair");
ilo = new int[npairs];
ihi = new int[npairs];
jlo = new int[npairs];
jhi = new int[npairs];
if (nargpair == 0) {
ilo[0] = 1; ihi[0] = ntypes;
jlo[0] = 1; jhi[0] = ntypes;
npairs = 1;
} else {
npairs = 0;
iarg = 4;
while (iarg < 4+nargpair) {
force->bounds(FLERR,arg[iarg],atom->ntypes,ilo[npairs],ihi[npairs]);
force->bounds(FLERR,arg[iarg+1],atom->ntypes,jlo[npairs],jhi[npairs]);
if (ilo[npairs] > ihi[npairs] || jlo[npairs] > jhi[npairs])
error->all(FLERR,"Illegal compute rdf command");
npairs++;
iarg += 2;
}
}
int i,j;
for (i = 1; i <= ntypes; i++)
for (j = 1; j <= ntypes; j++)
nrdfpair[i][j] = 0;
for (int m = 0; m < npairs; m++)
for (i = ilo[m]; i <= ihi[m]; i++)
for (j = jlo[m]; j <= jhi[m]; j++)
rdfpair[nrdfpair[i][j]++][i][j] = m;
memory->create(hist,npairs,nbin,"rdf:hist");
memory->create(histall,npairs,nbin,"rdf:histall");
memory->create(array,nbin,1+2*npairs,"rdf:array");
typecount = new int[ntypes+1];
icount = new int[npairs];
jcount = new int[npairs];
duplicates = new int[npairs];
dynamic = 0;
natoms_old = 0;
}
/* ---------------------------------------------------------------------- */
ComputeRDF::~ComputeRDF()
{
memory->destroy(rdfpair);
memory->destroy(nrdfpair);
delete [] ilo;
delete [] ihi;
delete [] jlo;
delete [] jhi;
memory->destroy(hist);
memory->destroy(histall);
memory->destroy(array);
delete [] typecount;
delete [] icount;
delete [] jcount;
delete [] duplicates;
}
/* ---------------------------------------------------------------------- */
void ComputeRDF::init()
{
if (!force->pair && !cutflag)
error->all(FLERR,"Compute rdf requires a pair style be defined "
"or cutoff specified");
if (cutflag) {
double skin = neighbor->skin;
mycutneigh = cutoff_user + skin;
double cutghost; // as computed by Neighbor and Comm
- if (force->pair)
+ if (force->pair)
cutghost = MAX(force->pair->cutforce+skin,comm->cutghostuser);
- else
+ else
cutghost = comm->cutghostuser;
- if (mycutneigh > cutghost)
+ if (mycutneigh > cutghost)
error->all(FLERR,"Compure rdf cutoff exceeds ghost atom range - "
"use comm_modify cutoff command");
if (force->pair && mycutneigh < force->pair->cutforce + skin)
if (comm->me == 0)
error->warning(FLERR,"Compute rdf cutoff less than neighbor cutoff - "
"forcing a needless neighbor list build");
delr = cutoff_user / nbin;
} else delr = force->pair->cutforce / nbin;
delrinv = 1.0/delr;
// set 1st column of output array to bin coords
for (int i = 0; i < nbin; i++)
array[i][0] = (i+0.5) * delr;
// initialize normalization, finite size correction, and changing atom counts
natoms_old = atom->natoms;
dynamic = group->dynamic[igroup];
if (dynamic_user) dynamic = 1;
init_norm();
// need an occasional half neighbor list
// if user specified, request a cutoff = cutoff_user + skin
// skin is included b/c Neighbor uses this value similar
// to its cutneighmax = force cutoff + skin
// also, this NeighList may be used by this compute for multiple steps
// (until next reneighbor), so it needs to contain atoms further
// than cutoff_user apart, just like a normal neighbor list does
int irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->compute = 1;
neighbor->requests[irequest]->occasional = 1;
if (cutflag) {
neighbor->requests[irequest]->cut = 1;
neighbor->requests[irequest]->cutoff = mycutneigh;
}
}
/* ---------------------------------------------------------------------- */
void ComputeRDF::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void ComputeRDF::init_norm()
{
int i,j,m;
// count atoms of each type that are also in group
const int nlocal = atom->nlocal;
const int ntypes = atom->ntypes;
const int * const mask = atom->mask;
const int * const type = atom->type;
for (i = 1; i <= ntypes; i++) typecount[i] = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) typecount[type[i]]++;
// icount = # of I atoms participating in I,J pairs for each histogram
// jcount = # of J atoms participating in I,J pairs for each histogram
// duplicates = # of atoms in both groups I and J for each histogram
for (m = 0; m < npairs; m++) {
icount[m] = 0;
for (i = ilo[m]; i <= ihi[m]; i++) icount[m] += typecount[i];
jcount[m] = 0;
for (i = jlo[m]; i <= jhi[m]; i++) jcount[m] += typecount[i];
duplicates[m] = 0;
for (i = ilo[m]; i <= ihi[m]; i++)
for (j = jlo[m]; j <= jhi[m]; j++)
if (i == j) duplicates[m] += typecount[i];
}
int *scratch = new int[npairs];
MPI_Allreduce(icount,scratch,npairs,MPI_INT,MPI_SUM,world);
for (i = 0; i < npairs; i++) icount[i] = scratch[i];
MPI_Allreduce(jcount,scratch,npairs,MPI_INT,MPI_SUM,world);
for (i = 0; i < npairs; i++) jcount[i] = scratch[i];
MPI_Allreduce(duplicates,scratch,npairs,MPI_INT,MPI_SUM,world);
for (i = 0; i < npairs; i++) duplicates[i] = scratch[i];
delete [] scratch;
}
/* ---------------------------------------------------------------------- */
void ComputeRDF::compute_array()
{
int i,j,m,ii,jj,inum,jnum,itype,jtype,ipair,jpair,ibin,ihisto;
double xtmp,ytmp,ztmp,delx,dely,delz,r;
int *ilist,*jlist,*numneigh,**firstneigh;
double factor_lj,factor_coul;
if (natoms_old != atom->natoms) {
dynamic = 1;
natoms_old = atom->natoms;
}
// if the number of atoms has changed or we have a dynamic group
// or dynamic updates are requested (e.g. when changing atom types)
// we need to recompute some normalization parameters
if (dynamic) init_norm();
invoked_array = update->ntimestep;
// invoke half neighbor list (will copy or build if necessary)
neighbor->build_one(list);
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// zero the histogram counts
for (i = 0; i < npairs; i++)
for (j = 0; j < nbin; j++)
hist[i][j] = 0;
// tally the RDF
// both atom i and j must be in fix group
// itype,jtype must have been specified by user
// consider I,J as one interaction even if neighbor pair is stored on 2 procs
// tally I,J pair each time I is central atom, and each time J is central
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (!(mask[i] & groupbit)) continue;
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
// if both weighting factors are 0, skip this pair
// could be 0 and still be in neigh list for long-range Coulombics
// want consistency with non-charged pairs which wouldn't be in list
if (factor_lj == 0.0 && factor_coul == 0.0) continue;
if (!(mask[j] & groupbit)) continue;
jtype = type[j];
ipair = nrdfpair[itype][jtype];
jpair = nrdfpair[jtype][itype];
if (!ipair && !jpair) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
r = sqrt(delx*delx + dely*dely + delz*delz);
ibin = static_cast<int> (r*delrinv);
if (ibin >= nbin) continue;
if (ipair)
for (ihisto = 0; ihisto < ipair; ihisto++)
hist[rdfpair[ihisto][itype][jtype]][ibin] += 1.0;
if (newton_pair || j < nlocal) {
if (jpair)
for (ihisto = 0; ihisto < jpair; ihisto++)
hist[rdfpair[ihisto][jtype][itype]][ibin] += 1.0;
}
}
}
// sum histograms across procs
MPI_Allreduce(hist[0],histall[0],npairs*nbin,MPI_DOUBLE,MPI_SUM,world);
// convert counts to g(r) and coord(r) and copy into output array
// vfrac = fraction of volume in shell m
// npairs = number of pairs, corrected for duplicates
// duplicates = pairs in which both atoms are the same
double constant,vfrac,gr,ncoord,rlower,rupper,normfac;
if (domain->dimension == 3) {
constant = 4.0*MY_PI / (3.0*domain->xprd*domain->yprd*domain->zprd);
for (m = 0; m < npairs; m++) {
normfac = (icount[m] > 0) ? static_cast<double>(jcount[m])
- static_cast<double>(duplicates[m])/icount[m] : 0.0;
ncoord = 0.0;
for (ibin = 0; ibin < nbin; ibin++) {
rlower = ibin*delr;
rupper = (ibin+1)*delr;
vfrac = constant * (rupper*rupper*rupper - rlower*rlower*rlower);
if (vfrac * normfac != 0.0)
gr = histall[m][ibin] / (vfrac * normfac * icount[m]);
else gr = 0.0;
if (icount[m] != 0)
ncoord += gr * vfrac * normfac;
array[ibin][1+2*m] = gr;
array[ibin][2+2*m] = ncoord;
}
}
} else {
constant = MY_PI / (domain->xprd*domain->yprd);
for (m = 0; m < npairs; m++) {
ncoord = 0.0;
normfac = (icount[m] > 0) ? static_cast<double>(jcount[m])
- static_cast<double>(duplicates[m])/icount[m] : 0.0;
for (ibin = 0; ibin < nbin; ibin++) {
rlower = ibin*delr;
rupper = (ibin+1)*delr;
vfrac = constant * (rupper*rupper - rlower*rlower);
if (vfrac * normfac != 0.0)
gr = histall[m][ibin] / (vfrac * normfac * icount[m]);
else gr = 0.0;
if (icount[m] != 0)
ncoord += gr * vfrac * normfac;
array[ibin][1+2*m] = gr;
array[ibin][2+2*m] = ncoord;
}
}
}
}
diff --git a/src/dump_local.cpp b/src/dump_local.cpp
index 4843352ea..a3e62907a 100644
--- a/src/dump_local.cpp
+++ b/src/dump_local.cpp
@@ -1,601 +1,604 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <mpi.h>
#include <string.h>
#include <stdlib.h>
#include "dump_local.h"
#include "atom.h"
#include "modify.h"
#include "fix.h"
#include "compute.h"
#include "domain.h"
#include "update.h"
#include "input.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
enum{INT,DOUBLE};
#define INVOKED_LOCAL 16
#define ONEFIELD 32
#define DELTA 1048576
/* ---------------------------------------------------------------------- */
DumpLocal::DumpLocal(LAMMPS *lmp, int narg, char **arg) :
Dump(lmp, narg, arg),
label(NULL), vtype(NULL), vformat(NULL), columns(NULL), field2index(NULL),
argindex(NULL), id_compute(NULL), compute(NULL), id_fix(NULL), fix(NULL),
pack_choice(NULL)
{
if (narg == 5) error->all(FLERR,"No dump local arguments specified");
clearstep = 1;
nevery = force->inumeric(FLERR,arg[3]);
if (nevery <= 0) error->all(FLERR,"Illegal dump local command");
+ if (binary)
+ error->all(FLERR,"Binary files are not supported with dump local");
+
nfield = narg - 5;
// expand args if any have wildcard character "*"
int expand = 0;
char **earg;
nfield = input->expand_args(nfield,&arg[5],1,earg);
if (earg != &arg[5]) expand = 1;
// allocate field vectors
pack_choice = new FnPtrPack[nfield];
vtype = new int[nfield];
buffer_allow = 1;
buffer_flag = 1;
// computes & fixes which the dump accesses
field2index = new int[nfield];
argindex = new int[nfield];
ncompute = 0;
id_compute = NULL;
compute = NULL;
nfix = 0;
id_fix = NULL;
fix = NULL;
// process attributes
parse_fields(nfield,earg);
size_one = nfield;
// setup format strings
vformat = new char*[size_one];
format_default = new char[3*size_one+1];
format_default[0] = '\0';
for (int i = 0; i < size_one; i++) {
if (vtype[i] == INT) strcat(format_default,"%d ");
else if (vtype[i] == DOUBLE) strcat(format_default,"%g ");
vformat[i] = NULL;
}
format_column_user = new char*[size_one];
for (int i = 0; i < size_one; i++) format_column_user[i] = NULL;
// setup column string
int n = 0;
for (int iarg = 0; iarg < nfield; iarg++) n += strlen(earg[iarg]) + 2;
columns = new char[n];
columns[0] = '\0';
for (int iarg = 0; iarg < nfield; iarg++) {
strcat(columns,earg[iarg]);
strcat(columns," ");
}
// setup default label string
char *str = (char *) "ENTRIES";
n = strlen(str) + 1;
label = new char[n];
strcpy(label,str);
// if wildcard expansion occurred, free earg memory from exapnd_args()
if (expand) {
for (int i = 0; i < nfield; i++) delete [] earg[i];
memory->sfree(earg);
}
}
/* ---------------------------------------------------------------------- */
DumpLocal::~DumpLocal()
{
delete [] pack_choice;
delete [] vtype;
delete [] field2index;
delete [] argindex;
for (int i = 0; i < ncompute; i++) delete [] id_compute[i];
memory->sfree(id_compute);
delete [] compute;
for (int i = 0; i < nfix; i++) delete [] id_fix[i];
memory->sfree(id_fix);
delete [] fix;
for (int i = 0; i < size_one; i++) delete [] vformat[i];
delete [] vformat;
for (int i = 0; i < size_one; i++) delete [] format_column_user[i];
delete [] format_column_user;
delete [] columns;
delete [] label;
}
/* ---------------------------------------------------------------------- */
void DumpLocal::init_style()
{
if (sort_flag && sortcol == 0)
error->all(FLERR,"Dump local cannot sort by atom ID");
// format = copy of default or user-specified line format
delete [] format;
char *str;
if (format_line_user) str = format_line_user;
else str = format_default;
int n = strlen(str) + 1;
format = new char[n];
strcpy(format,str);
// tokenize the format string and add space at end of each format element
// if user-specified int/float format exists, use it instead
// if user-specified column format exists, use it instead
// lo priority = line, medium priority = int/float, hi priority = column
char *ptr;
for (int i = 0; i < size_one; i++) {
if (i == 0) ptr = strtok(format," \0");
else ptr = strtok(NULL," \0");
if (ptr == NULL) error->all(FLERR,"Dump_modify format line is too short");
delete [] vformat[i];
if (format_column_user[i]) {
vformat[i] = new char[strlen(format_column_user[i]) + 2];
strcpy(vformat[i],format_column_user[i]);
} else if (vtype[i] == INT && format_int_user) {
vformat[i] = new char[strlen(format_int_user) + 2];
strcpy(vformat[i],format_int_user);
} else if (vtype[i] == DOUBLE && format_float_user) {
vformat[i] = new char[strlen(format_float_user) + 2];
strcpy(vformat[i],format_float_user);
} else {
vformat[i] = new char[strlen(ptr) + 2];
strcpy(vformat[i],ptr);
}
vformat[i] = strcat(vformat[i]," ");
}
// setup boundary string
domain->boundary_string(boundstr);
// setup function ptrs
if (buffer_flag == 1) write_choice = &DumpLocal::write_string;
else write_choice = &DumpLocal::write_lines;
// find current ptr for each compute,fix,variable
// check that fix frequency is acceptable
int icompute;
for (int i = 0; i < ncompute; i++) {
icompute = modify->find_compute(id_compute[i]);
if (icompute < 0) error->all(FLERR,"Could not find dump local compute ID");
compute[i] = modify->compute[icompute];
}
int ifix;
for (int i = 0; i < nfix; i++) {
ifix = modify->find_fix(id_fix[i]);
if (ifix < 0) error->all(FLERR,"Could not find dump local fix ID");
fix[i] = modify->fix[ifix];
if (nevery % modify->fix[ifix]->local_freq)
error->all(FLERR,"Dump local and fix not computed at compatible times");
}
// open single file, one time only
if (multifile == 0) openfile();
}
/* ---------------------------------------------------------------------- */
int DumpLocal::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"label") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
delete [] label;
int n = strlen(arg[1]) + 1;
label = new char[n];
strcpy(label,arg[1]);
return 2;
}
return 0;
}
/* ---------------------------------------------------------------------- */
void DumpLocal::write_header(bigint ndump)
{
if (me == 0) {
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF %s\n",label);
fprintf(fp,BIGINT_FORMAT "\n",ndump);
if (domain->triclinic) {
fprintf(fp,"ITEM: BOX BOUNDS xy xz yz %s\n",boundstr);
fprintf(fp,"%g %g %g\n",boxxlo,boxxhi,boxxy);
fprintf(fp,"%g %g %g\n",boxylo,boxyhi,boxxz);
fprintf(fp,"%g %g %g\n",boxzlo,boxzhi,boxyz);
} else {
fprintf(fp,"ITEM: BOX BOUNDS %s\n",boundstr);
fprintf(fp,"%g %g\n",boxxlo,boxxhi);
fprintf(fp,"%g %g\n",boxylo,boxyhi);
fprintf(fp,"%g %g\n",boxzlo,boxzhi);
}
fprintf(fp,"ITEM: %s %s\n",label,columns);
}
}
/* ---------------------------------------------------------------------- */
int DumpLocal::count()
{
int i;
// invoke Computes for local quantities
// only if within a run or minimize
// else require that computes are current
// this prevents a compute from being invoked by the WriteDump class
if (ncompute) {
if (update->whichflag == 0) {
for (i = 0; i < ncompute; i++)
if (compute[i]->invoked_local != update->ntimestep)
error->all(FLERR,"Compute used in dump between runs is not current");
} else {
for (i = 0; i < ncompute; i++) {
if (!(compute[i]->invoked_flag & INVOKED_LOCAL)) {
compute[i]->compute_local();
compute[i]->invoked_flag |= INVOKED_LOCAL;
}
}
}
}
// nmine = # of local values I contribute
// must be consistent for all input fields
nmine = -1;
for (int i = 0; i < ncompute; i++) {
if (nmine < 0) nmine = compute[i]->size_local_rows;
else if (nmine != compute[i]->size_local_rows)
error->one(FLERR,
"Dump local count is not consistent across input fields");
}
for (int i = 0; i < nfix; i++) {
if (nmine < 0) nmine = fix[i]->size_local_rows;
else if (nmine != fix[i]->size_local_rows)
error->one(FLERR,
"Dump local count is not consistent across input fields");
}
return nmine;
}
/* ---------------------------------------------------------------------- */
void DumpLocal::pack(tagint *dummy)
{
for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n);
}
/* ----------------------------------------------------------------------
convert mybuf of doubles to one big formatted string in sbuf
return -1 if strlen exceeds an int, since used as arg in MPI calls in Dump
------------------------------------------------------------------------- */
int DumpLocal::convert_string(int n, double *mybuf)
{
int i,j;
int offset = 0;
int m = 0;
for (i = 0; i < n; i++) {
if (offset + size_one*ONEFIELD > maxsbuf) {
if ((bigint) maxsbuf + DELTA > MAXSMALLINT) return -1;
maxsbuf += DELTA;
memory->grow(sbuf,maxsbuf,"dump:sbuf");
}
for (j = 0; j < size_one; j++) {
if (vtype[j] == INT)
offset += sprintf(&sbuf[offset],vformat[j],static_cast<int> (mybuf[m]));
else
offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]);
m++;
}
offset += sprintf(&sbuf[offset],"\n");
}
return offset;
}
/* ---------------------------------------------------------------------- */
void DumpLocal::write_data(int n, double *mybuf)
{
(this->*write_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpLocal::write_string(int n, double *mybuf)
{
fwrite(mybuf,sizeof(char),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpLocal::write_lines(int n, double *mybuf)
{
int i,j;
int m = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < size_one; j++) {
if (vtype[j] == INT) fprintf(fp,vformat[j],static_cast<int> (mybuf[m]));
else fprintf(fp,vformat[j],mybuf[m]);
m++;
}
fprintf(fp,"\n");
}
}
/* ---------------------------------------------------------------------- */
void DumpLocal::parse_fields(int narg, char **arg)
{
int computefixflag = 0;
// customize by adding to if statement
int i;
for (int iarg = 0; iarg < narg; iarg++) {
i = iarg;
if (strcmp(arg[iarg],"index") == 0) {
pack_choice[i] = &DumpLocal::pack_index;
vtype[i] = INT;
// compute value = c_ID
// if no trailing [], then arg is set to 0, else arg is int between []
} else if (strncmp(arg[iarg],"c_",2) == 0) {
computefixflag = 1;
pack_choice[i] = &DumpLocal::pack_compute;
vtype[i] = DOUBLE;
int n = strlen(arg[iarg]);
char *suffix = new char[n];
strcpy(suffix,&arg[iarg][2]);
char *ptr = strchr(suffix,'[');
if (ptr) {
if (suffix[strlen(suffix)-1] != ']')
error->all(FLERR,"Invalid attribute in dump local command");
argindex[i] = atoi(ptr+1);
*ptr = '\0';
} else argindex[i] = 0;
n = modify->find_compute(suffix);
if (n < 0) error->all(FLERR,"Could not find dump local compute ID");
if (modify->compute[n]->local_flag == 0)
error->all(FLERR,"Dump local compute does not compute local info");
if (argindex[i] == 0 && modify->compute[n]->size_local_cols > 0)
error->all(FLERR,"Dump local compute does not calculate local vector");
if (argindex[i] > 0 && modify->compute[n]->size_local_cols == 0)
error->all(FLERR,"Dump local compute does not calculate local array");
if (argindex[i] > 0 &&
argindex[i] > modify->compute[n]->size_local_cols)
error->all(FLERR,"Dump local compute vector is accessed out-of-range");
field2index[i] = add_compute(suffix);
delete [] suffix;
// fix value = f_ID
// if no trailing [], then arg is set to 0, else arg is between []
} else if (strncmp(arg[iarg],"f_",2) == 0) {
computefixflag = 1;
pack_choice[i] = &DumpLocal::pack_fix;
vtype[i] = DOUBLE;
int n = strlen(arg[iarg]);
char *suffix = new char[n];
strcpy(suffix,&arg[iarg][2]);
char *ptr = strchr(suffix,'[');
if (ptr) {
if (suffix[strlen(suffix)-1] != ']')
error->all(FLERR,"Invalid attribute in dump local command");
argindex[i] = atoi(ptr+1);
*ptr = '\0';
} else argindex[i] = 0;
n = modify->find_fix(suffix);
if (n < 0) error->all(FLERR,"Could not find dump local fix ID");
if (modify->fix[n]->local_flag == 0)
error->all(FLERR,"Dump local fix does not compute local info");
if (argindex[i] == 0 && modify->fix[n]->size_local_cols > 0)
error->all(FLERR,"Dump local fix does not compute local vector");
if (argindex[i] > 0 && modify->fix[n]->size_local_cols == 0)
error->all(FLERR,"Dump local fix does not compute local array");
if (argindex[i] > 0 &&
argindex[i] > modify->fix[n]->size_local_cols)
error->all(FLERR,"Dump local fix vector is accessed out-of-range");
field2index[i] = add_fix(suffix);
delete [] suffix;
} else error->all(FLERR,"Invalid attribute in dump local command");
}
if (computefixflag == 0)
error->all(FLERR,"Dump local attributes contain no compute or fix");
}
/* ----------------------------------------------------------------------
add Compute to list of Compute objects used by dump
return index of where this Compute is in list
if already in list, do not add, just return index, else add to list
------------------------------------------------------------------------- */
int DumpLocal::add_compute(char *id)
{
int icompute;
for (icompute = 0; icompute < ncompute; icompute++)
if (strcmp(id,id_compute[icompute]) == 0) break;
if (icompute < ncompute) return icompute;
id_compute = (char **)
memory->srealloc(id_compute,(ncompute+1)*sizeof(char *),"dump:id_compute");
delete [] compute;
compute = new Compute*[ncompute+1];
int n = strlen(id) + 1;
id_compute[ncompute] = new char[n];
strcpy(id_compute[ncompute],id);
ncompute++;
return ncompute-1;
}
/* ----------------------------------------------------------------------
add Fix to list of Fix objects used by dump
return index of where this Fix is in list
if already in list, do not add, just return index, else add to list
------------------------------------------------------------------------- */
int DumpLocal::add_fix(char *id)
{
int ifix;
for (ifix = 0; ifix < nfix; ifix++)
if (strcmp(id,id_fix[ifix]) == 0) break;
if (ifix < nfix) return ifix;
id_fix = (char **)
memory->srealloc(id_fix,(nfix+1)*sizeof(char *),"dump:id_fix");
delete [] fix;
fix = new Fix*[nfix+1];
int n = strlen(id) + 1;
id_fix[nfix] = new char[n];
strcpy(id_fix[nfix],id);
nfix++;
return nfix-1;
}
/* ----------------------------------------------------------------------
extraction of Compute, Fix results
------------------------------------------------------------------------- */
void DumpLocal::pack_compute(int n)
{
double *vector = compute[field2index[n]]->vector_local;
double **array = compute[field2index[n]]->array_local;
int ncount = compute[field2index[n]]->size_local_rows;
int index = argindex[n];
if (index == 0) {
for (int i = 0; i < ncount; i++) {
buf[n] = vector[i];
n += size_one;
}
} else {
index--;
for (int i = 0; i < ncount; i++) {
buf[n] = array[i][index];
n += size_one;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpLocal::pack_fix(int n)
{
double *vector = fix[field2index[n]]->vector_local;
double **array = fix[field2index[n]]->array_local;
int index = argindex[n];
if (index == 0) {
for (int i = 0; i < nmine; i++) {
buf[n] = vector[i];
n += size_one;
}
} else {
index--;
for (int i = 0; i < nmine; i++) {
buf[n] = array[i][index];
n += size_one;
}
}
}
/* ----------------------------------------------------------------------
one method for every attribute dump local can output
the local value is packed into buf starting at n with stride size_one
customize a new attribute by adding a method
------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
void DumpLocal::pack_index(int n)
{
int index;
MPI_Scan(&nmine,&index,1,MPI_INT,MPI_SUM,world);
index -= nmine;
for (int i = 0; i < nmine; i++) {
buf[n] = ++index;
n += size_one;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index cc8f8be90..7401183fe 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,49 +1,65 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <mpi.h>
#include "lammps.h"
#include "input.h"
#include "error.h"
#include <stdio.h>
#include <stdlib.h>
+#if defined(LAMMPS_TRAP_FPE) && defined(_GNU_SOURCE)
+#include <fenv.h>
+#endif
+
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
main program to drive LAMMPS
------------------------------------------------------------------------- */
int main(int argc, char **argv)
{
MPI_Init(&argc,&argv);
+// enable trapping selected floating point exceptions.
+// this uses GNU extensions and is only tested on Linux
+// therefore we make it depend on -D_GNU_SOURCE, too.
+
+#if defined(LAMMPS_TRAP_FPE) && defined(_GNU_SOURCE)
+ fesetenv(FE_NOMASK_ENV);
+ fedisableexcept(FE_ALL_EXCEPT);
+ feenableexcept(FE_DIVBYZERO);
+ feenableexcept(FE_INVALID);
+ feenableexcept(FE_OVERFLOW);
+#endif
+
#ifdef LAMMPS_EXCEPTIONS
try {
LAMMPS *lammps = new LAMMPS(argc,argv,MPI_COMM_WORLD);
lammps->input->file();
delete lammps;
} catch(LAMMPSAbortException & ae) {
MPI_Abort(ae.universe, 1);
} catch(LAMMPSException & e) {
MPI_Finalize();
exit(1);
}
#else
LAMMPS *lammps = new LAMMPS(argc,argv,MPI_COMM_WORLD);
lammps->input->file();
delete lammps;
#endif
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
}
diff --git a/src/neighbor.cpp b/src/neighbor.cpp
index 487b860c9..ef150902e 100644
--- a/src/neighbor.cpp
+++ b/src/neighbor.cpp
@@ -1,2462 +1,2462 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author (triclinic and multi-neigh) : Pieter in 't Veld (SNL)
------------------------------------------------------------------------- */
#include <mpi.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "style_nbin.h"
#include "style_nstencil.h"
#include "style_npair.h"
#include "style_ntopo.h"
#include "atom.h"
#include "atom_vec.h"
#include "comm.h"
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "group.h"
#include "modify.h"
#include "fix.h"
#include "compute.h"
#include "update.h"
#include "respa.h"
#include "output.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
#include <map>
using namespace LAMMPS_NS;
using namespace NeighConst;
#define RQDELTA 1
#define EXDELTA 1
#define BIG 1.0e20
enum{NSQ,BIN,MULTI}; // also in NBin, NeighList, NStencil
enum{NONE,ALL,PARTIAL,TEMPLATE};
static const char cite_neigh_multi[] =
"neighbor multi command:\n\n"
"@Article{Intveld08,\n"
" author = {P.{\\,}J.~in{\\,}'t~Veld and S.{\\,}J.~Plimpton"
" and G.{\\,}S.~Grest},\n"
" title = {Accurate and Efficient Methods for Modeling Colloidal\n"
" Mixtures in an Explicit Solvent using Molecular Dynamics},\n"
" journal = {Comp.~Phys.~Comm.},\n"
" year = 2008,\n"
" volume = 179,\n"
" pages = {320--329}\n"
"}\n\n";
//#define NEIGH_LIST_DEBUG 1
/* ---------------------------------------------------------------------- */
Neighbor::Neighbor(LAMMPS *lmp) : Pointers(lmp),
pairclass(NULL), pairnames(NULL), pairmasks(NULL)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
firsttime = 1;
style = BIN;
every = 1;
delay = 10;
dist_check = 1;
pgsize = 100000;
oneatom = 2000;
binsizeflag = 0;
build_once = 0;
cluster_check = 0;
ago = -1;
cutneighmax = 0.0;
cutneighsq = NULL;
cutneighghostsq = NULL;
cuttype = NULL;
cuttypesq = NULL;
fixchecklist = NULL;
// pairwise neighbor lists and associated data structs
nlist = 0;
lists = NULL;
nbin = 0;
neigh_bin = NULL;
nstencil = 0;
neigh_stencil = NULL;
neigh_pair = NULL;
nstencil_perpetual = 0;
slist = NULL;
npair_perpetual = 0;
plist = NULL;
nrequest = maxrequest = 0;
requests = NULL;
old_nrequest = 0;
old_requests = NULL;
old_style = style;
old_triclinic = 0;
old_pgsize = pgsize;
old_oneatom = oneatom;
zeroes = NULL;
binclass = NULL;
binnames = NULL;
binmasks = NULL;
stencilclass = NULL;
stencilnames = NULL;
stencilmasks = NULL;
// topology lists
bondwhich = anglewhich = dihedralwhich = improperwhich = NONE;
neigh_bond = NULL;
neigh_angle = NULL;
neigh_dihedral = NULL;
neigh_improper = NULL;
// coords at last neighboring
maxhold = 0;
xhold = NULL;
lastcall = -1;
last_setup_bins = -1;
// pair exclusion list info
includegroup = 0;
nex_type = maxex_type = 0;
ex1_type = ex2_type = NULL;
ex_type = NULL;
nex_group = maxex_group = 0;
ex1_group = ex2_group = ex1_bit = ex2_bit = NULL;
nex_mol = maxex_mol = 0;
ex_mol_group = ex_mol_bit = ex_mol_intra = NULL;
// Kokkos setting
copymode = 0;
}
/* ---------------------------------------------------------------------- */
Neighbor::~Neighbor()
{
if (copymode) return;
memory->destroy(cutneighsq);
memory->destroy(cutneighghostsq);
delete [] cuttype;
delete [] cuttypesq;
delete [] fixchecklist;
for (int i = 0; i < nlist; i++) delete lists[i];
for (int i = 0; i < nbin; i++) delete neigh_bin[i];
for (int i = 0; i < nstencil; i++) delete neigh_stencil[i];
for (int i = 0; i < nlist; i++) delete neigh_pair[i];
delete [] lists;
delete [] neigh_bin;
delete [] neigh_stencil;
delete [] neigh_pair;
delete [] slist;
delete [] plist;
- for (int i = 0; i < nlist; i++)
+ for (int i = 0; i < nrequest; i++)
if (requests[i]) delete requests[i];
memory->sfree(requests);
for (int i = 0; i < old_nrequest; i++)
if (old_requests[i]) delete old_requests[i];
memory->sfree(old_requests);
delete [] zeroes;
delete [] binclass;
delete [] binnames;
delete [] binmasks;
delete [] stencilclass;
delete [] stencilnames;
delete [] stencilmasks;
delete [] pairclass;
delete [] pairnames;
delete [] pairmasks;
delete neigh_bond;
delete neigh_angle;
delete neigh_dihedral;
delete neigh_improper;
memory->destroy(xhold);
memory->destroy(ex1_type);
memory->destroy(ex2_type);
memory->destroy(ex_type);
memory->destroy(ex1_group);
memory->destroy(ex2_group);
delete [] ex1_bit;
delete [] ex2_bit;
memory->destroy(ex_mol_group);
delete [] ex_mol_bit;
memory->destroy(ex_mol_intra);
}
/* ---------------------------------------------------------------------- */
void Neighbor::init()
{
int i,j,n;
ncalls = ndanger = 0;
dimension = domain->dimension;
triclinic = domain->triclinic;
newton_pair = force->newton_pair;
// error check
if (delay > 0 && (delay % every) != 0)
error->all(FLERR,"Neighbor delay must be 0 or multiple of every setting");
if (pgsize < 10*oneatom)
error->all(FLERR,"Neighbor page size must be >= 10x the one atom setting");
// ------------------------------------------------------------------
// settings
// bbox lo/hi ptrs = bounding box of entire domain, stored by Domain
if (triclinic == 0) {
bboxlo = domain->boxlo;
bboxhi = domain->boxhi;
} else {
bboxlo = domain->boxlo_bound;
bboxhi = domain->boxhi_bound;
}
// set neighbor cutoffs (force cutoff + skin)
// trigger determines when atoms migrate and neighbor lists are rebuilt
// needs to be non-zero for migration distance check
// even if pair = NULL and no neighbor lists are used
// cutneigh = force cutoff + skin if cutforce > 0, else cutneigh = 0
// cutneighghost = pair cutghost if it requests it, else same as cutneigh
triggersq = 0.25*skin*skin;
boxcheck = 0;
if (domain->box_change && (domain->xperiodic || domain->yperiodic ||
(dimension == 3 && domain->zperiodic)))
boxcheck = 1;
n = atom->ntypes;
if (cutneighsq == NULL) {
if (lmp->kokkos) init_cutneighsq_kokkos(n);
else memory->create(cutneighsq,n+1,n+1,"neigh:cutneighsq");
memory->create(cutneighghostsq,n+1,n+1,"neigh:cutneighghostsq");
cuttype = new double[n+1];
cuttypesq = new double[n+1];
}
double cutoff,delta,cut;
cutneighmin = BIG;
cutneighmax = 0.0;
for (i = 1; i <= n; i++) {
cuttype[i] = cuttypesq[i] = 0.0;
for (j = 1; j <= n; j++) {
if (force->pair) cutoff = sqrt(force->pair->cutsq[i][j]);
else cutoff = 0.0;
if (cutoff > 0.0) delta = skin;
else delta = 0.0;
cut = cutoff + delta;
cutneighsq[i][j] = cut*cut;
cuttype[i] = MAX(cuttype[i],cut);
cuttypesq[i] = MAX(cuttypesq[i],cut*cut);
cutneighmin = MIN(cutneighmin,cut);
cutneighmax = MAX(cutneighmax,cut);
if (force->pair && force->pair->ghostneigh) {
cut = force->pair->cutghost[i][j] + skin;
cutneighghostsq[i][j] = cut*cut;
} else cutneighghostsq[i][j] = cut*cut;
}
}
cutneighmaxsq = cutneighmax * cutneighmax;
// rRESPA cutoffs
int respa = 0;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
}
if (respa) {
double *cut_respa = ((Respa *) update->integrate)->cutoff;
cut_inner_sq = (cut_respa[1] + skin) * (cut_respa[1] + skin);
cut_middle_sq = (cut_respa[3] + skin) * (cut_respa[3] + skin);
cut_middle_inside_sq = (cut_respa[0] - skin) * (cut_respa[0] - skin);
if (cut_respa[0]-skin < 0) cut_middle_inside_sq = 0.0;
}
// fixchecklist = other classes that can induce reneighboring in decide()
restart_check = 0;
if (output->restart_flag) restart_check = 1;
delete [] fixchecklist;
fixchecklist = NULL;
fixchecklist = new int[modify->nfix];
fix_check = 0;
for (i = 0; i < modify->nfix; i++)
if (modify->fix[i]->force_reneighbor)
fixchecklist[fix_check++] = i;
must_check = 0;
if (restart_check || fix_check) must_check = 1;
// set special_flag for 1-2, 1-3, 1-4 neighbors
// flag[0] is not used, flag[1] = 1-2, flag[2] = 1-3, flag[3] = 1-4
// flag = 0 if both LJ/Coulomb special values are 0.0
// flag = 1 if both LJ/Coulomb special values are 1.0
// flag = 2 otherwise or if KSpace solver is enabled
// pairwise portion of KSpace solver uses all 1-2,1-3,1-4 neighbors
// or selected Coulomb-approixmation pair styles require it
if (force->special_lj[1] == 0.0 && force->special_coul[1] == 0.0)
special_flag[1] = 0;
else if (force->special_lj[1] == 1.0 && force->special_coul[1] == 1.0)
special_flag[1] = 1;
else special_flag[1] = 2;
if (force->special_lj[2] == 0.0 && force->special_coul[2] == 0.0)
special_flag[2] = 0;
else if (force->special_lj[2] == 1.0 && force->special_coul[2] == 1.0)
special_flag[2] = 1;
else special_flag[2] = 2;
if (force->special_lj[3] == 0.0 && force->special_coul[3] == 0.0)
special_flag[3] = 0;
else if (force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0)
special_flag[3] = 1;
else special_flag[3] = 2;
if (force->kspace || force->pair_match("coul/wolf",0) ||
force->pair_match("coul/dsf",0) || force->pair_match("thole",0))
special_flag[1] = special_flag[2] = special_flag[3] = 2;
// maxwt = max multiplicative factor on atom indices stored in neigh list
maxwt = 0;
if (special_flag[1] == 2) maxwt = 2;
if (special_flag[2] == 2) maxwt = 3;
if (special_flag[3] == 2) maxwt = 4;
// ------------------------------------------------------------------
// xhold array
// free if not needed for this run
if (dist_check == 0) {
memory->destroy(xhold);
maxhold = 0;
xhold = NULL;
}
// first time allocation
if (dist_check) {
if (maxhold == 0) {
maxhold = atom->nmax;
memory->create(xhold,maxhold,3,"neigh:xhold");
}
}
// ------------------------------------------------------------------
// exclusion lists
// depend on type, group, molecule settings from neigh_modify
// warn if exclusions used with KSpace solver
n = atom->ntypes;
if (nex_type == 0 && nex_group == 0 && nex_mol == 0) exclude = 0;
else exclude = 1;
if (nex_type) {
if (lmp->kokkos)
init_ex_type_kokkos(n);
else {
memory->destroy(ex_type);
memory->create(ex_type,n+1,n+1,"neigh:ex_type");
}
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
ex_type[i][j] = 0;
for (i = 0; i < nex_type; i++) {
if (ex1_type[i] <= 0 || ex1_type[i] > n ||
ex2_type[i] <= 0 || ex2_type[i] > n)
error->all(FLERR,"Invalid atom type in neighbor exclusion list");
ex_type[ex1_type[i]][ex2_type[i]] = 1;
ex_type[ex2_type[i]][ex1_type[i]] = 1;
}
}
if (nex_group) {
if (lmp->kokkos)
init_ex_bit_kokkos();
else {
delete [] ex1_bit;
delete [] ex2_bit;
ex1_bit = new int[nex_group];
ex2_bit = new int[nex_group];
}
for (i = 0; i < nex_group; i++) {
ex1_bit[i] = group->bitmask[ex1_group[i]];
ex2_bit[i] = group->bitmask[ex2_group[i]];
}
}
if (nex_mol) {
if (lmp->kokkos)
init_ex_mol_bit_kokkos();
else {
delete [] ex_mol_bit;
ex_mol_bit = new int[nex_mol];
}
for (i = 0; i < nex_mol; i++)
ex_mol_bit[i] = group->bitmask[ex_mol_group[i]];
}
if (exclude && force->kspace && me == 0)
error->warning(FLERR,"Neighbor exclusions used with KSpace solver "
"may give inconsistent Coulombic energies");
// ------------------------------------------------------------------
// create pairwise lists
// one-time call to init_styles() to scan style files and setup
// init_pair() creates auxiliary classes: NBin, NStencil, NPair
if (firsttime) init_styles();
firsttime = 0;
int same = init_pair();
// invoke copy_neighbor_info() in Bin,Stencil,Pair classes
// copied once per run in case any cutoff, exclusion, special info changed
for (i = 0; i < nbin; i++) neigh_bin[i]->copy_neighbor_info();
for (i = 0; i < nstencil; i++) neigh_stencil[i]->copy_neighbor_info();
for (i = 0; i < nlist; i++)
if (neigh_pair[i]) neigh_pair[i]->copy_neighbor_info();
if (!same && comm->me == 0) print_pairwise_info();
// can now delete requests so next run can make new ones
// print_pairwise_info() made use of requests
// set of NeighLists now stores all needed info
for (int i = 0; i < nrequest; i++) {
delete requests[i];
requests[i] = NULL;
}
nrequest = 0;
// ------------------------------------------------------------------
// create topology lists
// instantiated topo styles can change from run to run
init_topology();
}
/* ----------------------------------------------------------------------
create and initialize lists of Nbin, Nstencil, NPair classes
lists have info on all classes in 3 style*.h files
cannot do this in constructor, b/c too early to instantiate classes
------------------------------------------------------------------------- */
void Neighbor::init_styles()
{
// extract info from NBin classes listed in style_nbin.h
nbclass = 0;
#define NBIN_CLASS
#define NBinStyle(key,Class,bitmasks) nbclass++;
#include "style_nbin.h"
#undef NBinStyle
#undef NBIN_CLASS
binclass = new BinCreator[nbclass];
binnames = new char*[nbclass];
binmasks = new int[nbclass];
nbclass = 0;
#define NBIN_CLASS
#define NBinStyle(key,Class,bitmasks) \
binnames[nbclass] = (char *) #key; \
binclass[nbclass] = &bin_creator<Class>; \
binmasks[nbclass++] = bitmasks;
#include "style_nbin.h"
#undef NBinStyle
#undef NBIN_CLASS
// extract info from NStencil classes listed in style_nstencil.h
nsclass = 0;
#define NSTENCIL_CLASS
#define NStencilStyle(key,Class,bitmasks) nsclass++;
#include "style_nstencil.h"
#undef NStencilStyle
#undef NSTENCIL_CLASS
stencilclass = new StencilCreator[nsclass];
stencilnames = new char*[nsclass];
stencilmasks = new int[nsclass];
nsclass = 0;
#define NSTENCIL_CLASS
#define NStencilStyle(key,Class,bitmasks) \
stencilnames[nsclass] = (char *) #key; \
stencilclass[nsclass] = &stencil_creator<Class>; \
stencilmasks[nsclass++] = bitmasks;
#include "style_nstencil.h"
#undef NStencilStyle
#undef NSTENCIL_CLASS
// extract info from NPair classes listed in style_npair.h
npclass = 0;
#define NPAIR_CLASS
#define NPairStyle(key,Class,bitmasks) npclass++;
#include "style_npair.h"
#undef NPairStyle
#undef NPAIR_CLASS
pairclass = new PairCreator[npclass];
pairnames = new char*[npclass];
pairmasks = new int[npclass];
npclass = 0;
#define NPAIR_CLASS
#define NPairStyle(key,Class,bitmasks) \
pairnames[npclass] = (char *) #key; \
pairclass[npclass] = &pair_creator<Class>; \
pairmasks[npclass++] = bitmasks;
#include "style_npair.h"
#undef NPairStyle
#undef NPAIR_CLASS
}
/* ----------------------------------------------------------------------
create and initialize NPair classes
------------------------------------------------------------------------- */
int Neighbor::init_pair()
{
int i,j,k,m;
// test if pairwise lists need to be re-created
// no need to re-create if:
// neigh style, triclinic, pgsize, oneatom have not changed
// current requests = old requests
// so just return:
// delete requests so next run can make new ones
// current set of NeighLists already stores all needed info
// requests are compared via identical() before:
// any requests are morphed using logic below
// any requests are added below, e.g. as parents of pair hybrid skip lists
// copy them via requests_new2old() BEFORE any changes made to requests
// necessary b/c morphs can change requestor settings (see comment below)
int same = 1;
if (style != old_style) same = 0;
if (triclinic != old_triclinic) same = 0;
if (pgsize != old_pgsize) same = 0;
if (oneatom != old_oneatom) same = 0;
if (nrequest != old_nrequest) same = 0;
else
for (i = 0; i < nrequest; i++)
if (requests[i]->identical(old_requests[i]) == 0) same = 0;
#ifdef NEIGH_LIST_DEBUG
if (comm->me == 0) printf("SAME flag %d\n",same);
#endif
if (same) return same;
requests_new2old();
// delete old lists since creating new ones
for (i = 0; i < nlist; i++) delete lists[i];
for (i = 0; i < nbin; i++) delete neigh_bin[i];
for (i = 0; i < nstencil; i++) delete neigh_stencil[i];
for (i = 0; i < nlist; i++) delete neigh_pair[i];
delete [] lists;
delete [] neigh_bin;
delete [] neigh_stencil;
delete [] neigh_pair;
// error check on requests
// do not allow occasional, ghost, bin list
// b/c it still uses variant of coord2bin() in NPair() method
// instead of atom2bin, this could cause error b/c stoms have
// moved out of proc domain by time occasional list is built
// solution would be to use a different NBin variant
// that used Npair::coord2bin(x,ix,iy,iz) (then delete it from NPair)
// and stored the ix,iy,iz values for all atoms (including ghosts)
// at time of binning when neighbor lists are rebuilt,
// similar to what vanilla Nbin::coord2atom() does now in atom2bin
if (style == BIN) {
for (i = 0; i < nrequest; i++)
if (requests[i]->occasional && requests[i]->ghost)
error->all(FLERR,"Cannot request an occasional binned neighbor list "
"with ghost info");
}
// morph requests in various ways
// purpose is to avoid duplicate or inefficient builds
// may add new requests if a needed request to derive from does not exist
// methods:
// (1) other = point history and rRESPA lists at their partner lists
// (2) skip = create any new non-skip lists needed by pair hybrid skip lists
// (3) granular = adjust parent and skip lists for granular onesided usage
// (4) h/f = pair up any matching half/full lists
// (5) copy = convert as many lists as possible to copy lists
// order of morph methods matters:
// (1) before (2), b/c (2) needs to know history partner pairings
// (2) after (1), b/c (2) may also need to create new history lists
// (3) after (2), b/c it adjusts lists created by (2)
// (4) after (2) and (3),
// b/c (2) may create new full lists, (3) may change them
// (5) last, after all lists are finalized, so all possible copies found
int nrequest_original = nrequest;
morph_other();
morph_skip();
morph_granular(); // this method can change flags set by requestor
morph_halffull();
morph_copy();
// create new lists, one per request including added requests
// wait to allocate initial pages until copy lists are detected
// NOTE: can I allocate now, instead of down below?
nlist = nrequest;
lists = new NeighList*[nrequest];
neigh_bin = new NBin*[nrequest];
neigh_stencil = new NStencil*[nrequest];
neigh_pair = new NPair*[nrequest];
// allocate new lists
// pass list ptr back to requestor (except for Command class)
// only for original requests, not ones added by Neighbor class
for (i = 0; i < nrequest; i++) {
if (requests[i]->kokkos_host || requests[i]->kokkos_device)
create_kokkos_list(i);
else lists[i] = new NeighList(lmp);
lists[i]->index = i;
if (requests[i]->pair && i < nrequest_original) {
Pair *pair = (Pair *) requests[i]->requestor;
pair->init_list(requests[i]->id,lists[i]);
} else if (requests[i]->fix && i < nrequest_original) {
Fix *fix = (Fix *) requests[i]->requestor;
fix->init_list(requests[i]->id,lists[i]);
} else if (requests[i]->compute && i < nrequest_original) {
Compute *compute = (Compute *) requests[i]->requestor;
compute->init_list(requests[i]->id,lists[i]);
}
}
// invoke post_constructor() for all lists
// copies info from requests to lists, sets ptrs to related lists
for (i = 0; i < nrequest; i++)
lists[i]->post_constructor(requests[i]);
// assign Bin,Stencil,Pair style to each list
int flag;
for (i = 0; i < nrequest; i++) {
flag = choose_bin(requests[i]);
lists[i]->bin_method = flag;
if (flag < 0)
error->all(FLERR,"Requested neighbor bin option does not exist");
flag = choose_stencil(requests[i]);
lists[i]->stencil_method = flag;
if (flag < 0)
error->all(FLERR,"Requested neighbor stencil method does not exist");
flag = choose_pair(requests[i]);
lists[i]->pair_method = flag;
if (flag < 0)
error->all(FLERR,"Requested neighbor pair method does not exist");
}
// instantiate unique Bin,Stencil classes in neigh_bin & neigh_stencil vecs
// unique = only one of its style, or request unique flag set (custom cutoff)
nbin = 0;
for (i = 0; i < nrequest; i++) {
requests[i]->index_bin = -1;
flag = lists[i]->bin_method;
if (flag == 0) continue;
for (j = 0; j < nbin; j++)
if (neigh_bin[j]->istyle == flag) break;
if (j < nbin && !requests[i]->unique) {
requests[i]->index_bin = j;
continue;
}
BinCreator bin_creator = binclass[flag-1];
neigh_bin[nbin] = bin_creator(lmp);
neigh_bin[nbin]->post_constructor(requests[i]);
neigh_bin[nbin]->istyle = flag;
requests[i]->index_bin = nbin;
nbin++;
}
nstencil = 0;
for (i = 0; i < nrequest; i++) {
requests[i]->index_stencil = -1;
flag = lists[i]->stencil_method;
if (flag == 0) continue;
for (j = 0; j < nstencil; j++)
if (neigh_stencil[j]->istyle == flag) break;
if (j < nstencil && !requests[i]->unique) {
requests[i]->index_stencil = j;
continue;
}
StencilCreator stencil_creator = stencilclass[flag-1];
neigh_stencil[nstencil] = stencil_creator(lmp);
neigh_stencil[nstencil]->post_constructor(requests[i]);
neigh_stencil[nstencil]->istyle = flag;
if (lists[i]->bin_method > 0) {
neigh_stencil[nstencil]->nb = neigh_bin[requests[i]->index_bin];
if (neigh_stencil[nstencil]->nb == NULL)
error->all(FLERR,"Could not assign bin method to neighbor stencil");
}
requests[i]->index_stencil = nstencil;
nstencil++;
}
// instantiate one Pair class per list in neigh_pair vec
for (i = 0; i < nrequest; i++) {
requests[i]->index_pair = -1;
flag = lists[i]->pair_method;
if (flag == 0) {
neigh_pair[i] = NULL;
continue;
}
PairCreator pair_creator = pairclass[flag-1];
neigh_pair[i] = pair_creator(lmp);
neigh_pair[i]->post_constructor(requests[i]);
neigh_pair[i]->istyle = flag;
if (lists[i]->bin_method > 0) {
neigh_pair[i]->nb = neigh_bin[requests[i]->index_bin];
if (neigh_pair[i]->nb == NULL)
error->all(FLERR,"Could not assign bin method to neighbor pair");
}
if (lists[i]->stencil_method > 0) {
neigh_pair[i]->ns = neigh_stencil[requests[i]->index_stencil];
if (neigh_pair[i]->ns == NULL)
error->all(FLERR,"Could not assign stencil method to neighbor pair");
}
requests[i]->index_pair = i;
}
// allocate initial pages for each list, except if copy flag set
// allocate dnum vector of zeroes if set
int dnummax = 0;
for (i = 0; i < nlist; i++) {
if (lists[i]->copy) continue;
lists[i]->setup_pages(pgsize,oneatom);
dnummax = MAX(dnummax,lists[i]->dnum);
}
if (dnummax) {
delete [] zeroes;
zeroes = new double[dnummax];
for (i = 0; i < dnummax; i++) zeroes[i] = 0.0;
}
// first-time allocation of per-atom data for lists that are built and store
// lists that are not built: granhistory, respa inner/middle (no neigh_pair)
// lists that do not store: copy
// use atom->nmax for both grow() args
// i.e. grow first time to expanded size to avoid future reallocs
// also Kokkos list initialization
int maxatom = atom->nmax;
for (i = 0; i < nlist; i++)
if (neigh_pair[i] && !lists[i]->copy) lists[i]->grow(maxatom,maxatom);
// plist = indices of perpetual NPair classes
// perpetual = non-occasional, re-built at every reneighboring
// slist = indices of perpetual NStencil classes
// perpetual = used by any perpetual NPair class
delete [] slist;
delete [] plist;
nstencil_perpetual = npair_perpetual = 0;
slist = new int[nstencil];
plist = new int[nlist];
for (i = 0; i < nlist; i++) {
if (lists[i]->occasional == 0 && lists[i]->pair_method)
plist[npair_perpetual++] = i;
}
for (i = 0; i < nstencil; i++) {
flag = 0;
for (j = 0; j < npair_perpetual; j++)
if (lists[plist[j]]->stencil_method == neigh_stencil[i]->istyle)
flag = 1;
if (flag) slist[nstencil_perpetual++] = i;
}
// reorder plist vector if necessary
// relevant for lists that are derived from a parent list:
// half-full,copy,skip
// the child index must appear in plist after the parent index
// swap two indices within plist when dependency is mis-ordered
// start double loop check again whenever a swap is made
// done when entire double loop test results in no swaps
NeighList *ptr;
int done = 0;
while (!done) {
done = 1;
for (i = 0; i < npair_perpetual; i++) {
for (k = 0; k < 3; k++) {
ptr = NULL;
if (k == 0) ptr = lists[plist[i]]->listcopy;
if (k == 1) ptr = lists[plist[i]]->listskip;
if (k == 2) ptr = lists[plist[i]]->listfull;
if (ptr == NULL) continue;
for (m = 0; m < nrequest; m++)
if (ptr == lists[m]) break;
for (j = 0; j < npair_perpetual; j++)
if (m == plist[j]) break;
if (j < i) continue;
int tmp = plist[i]; // swap I,J indices
plist[i] = plist[j];
plist[j] = tmp;
done = 0;
break;
}
if (!done) break;
}
}
// debug output
#ifdef NEIGH_LIST_DEBUG
for (i = 0; i < nrequest; i++) lists[i]->print_attributes();
#endif
return same;
}
/* ----------------------------------------------------------------------
scan NeighRequests to set additional flags
only for history, respaouter, custom cutoff lists
------------------------------------------------------------------------- */
void Neighbor::morph_other()
{
NeighRequest *irq;
for (int i = 0; i < nrequest; i++) {
irq = requests[i];
// if history, point this list and partner list at each other
if (irq->history) {
irq->historylist = i-1;
requests[i-1]->history_partner = 1;
requests[i-1]->historylist = i;
}
// if respaouter, point all associated rRESPA lists at each other
if (irq->respaouter) {
if (requests[i-1]->respainner) {
irq->respainnerlist = i-1;
requests[i-1]->respaouterlist = i;
} else {
irq->respamiddlelist = i-1;
requests[i-1]->respaouterlist = i;
requests[i-1]->respainnerlist = i-1;
irq->respainnerlist = i-2;
requests[i-2]->respaouterlist = i;
requests[i-2]->respamiddlelist = i-1;
}
}
// if cut flag set by requestor, set unique flag
// this forces Pair,Stencil,Bin styles to be instantiated separately
if (irq->cut) irq->unique = 1;
}
}
/* ----------------------------------------------------------------------
scan NeighRequests to process all skip lists
look for a matching non-skip list
if one exists, point at it via skiplist
else make new parent via copy_request() and point at it
------------------------------------------------------------------------- */
void Neighbor::morph_skip()
{
int i,j,inewton,jnewton;
NeighRequest *irq,*jrq,*nrq;
for (i = 0; i < nrequest; i++) {
irq = requests[i];
// only processing skip lists
if (!irq->skip) continue;
// these lists are created other ways, no need for skipping
// halffull list and its full parent may both skip,
// but are checked to insure matching skip info
if (irq->history) continue;
if (irq->respainner || irq->respamiddle) continue;
if (irq->halffull) continue;
if (irq->copy) continue;
// check all other lists
for (j = 0; j < nrequest; j++) {
if (i == j) continue;
jrq = requests[j];
// can only skip from a perpetual non-skip list
if (jrq->occasional) continue;
if (jrq->skip) continue;
// both lists must be half, or both full
if (irq->half != jrq->half) continue;
if (irq->full != jrq->full) continue;
// both lists must be newton on, or both newton off
// IJ newton = 1 for newton on, 2 for newton off
inewton = irq->newton;
if (inewton == 0) inewton = force->newton_pair ? 1 : 2;
jnewton = jrq->newton;
if (jnewton == 0) jnewton = force->newton_pair ? 1 : 2;
if (inewton != jnewton) continue;
// these flags must be same,
// else 2 lists do not store same pairs
// or their data structures are different
// this includes custom cutoff set by requestor
// no need to check respaouter b/c it stores same pairs
// no need to check dnum b/c only set for history
// NOTE: need check for 2 Kokkos flags?
if (irq->ghost != jrq->ghost) continue;
if (irq->size != jrq->size) continue;
if (irq->bond != jrq->bond) continue;
if (irq->omp != jrq->omp) continue;
if (irq->intel != jrq->intel) continue;
if (irq->kokkos_host != jrq->kokkos_host) continue;
if (irq->kokkos_device != jrq->kokkos_device) continue;
if (irq->ssa != jrq->ssa) continue;
if (irq->cut != jrq->cut) continue;
if (irq->cutoff != jrq->cutoff) continue;
// 2 lists are a match
break;
}
// if matching list exists, point to it
// else create a new identical list except non-skip
// for new list, set neigh = 1, skip = 0, no skip vec/array,
// copy unique flag (since copy_request() will not do it)
// note: parents of skip lists do not have associated history list
// b/c child skip lists store their own history info
if (j < nrequest) irq->skiplist = j;
else {
int newrequest = request(this,-1);
irq->skiplist = newrequest;
nrq = requests[newrequest];
nrq->copy_request(irq,0);
nrq->pair = nrq->fix = nrq->compute = nrq->command = 0;
nrq->neigh = 1;
nrq->skip = 0;
if (irq->unique) nrq->unique = 1;
}
}
}
/* ----------------------------------------------------------------------
scan NeighRequests just added by morph_skip for hybrid granular
adjust newton/oneside parent settings if children require onesided skipping
also set children off2on flag if parent becomes a newton off list
this is needed because line/gran and tri/gran pair styles
require onesided neigh lists and system newton on,
but parent list must be newton off to enable the onesided skipping
------------------------------------------------------------------------- */
void Neighbor::morph_granular()
{
int i,j;
NeighRequest *irq,*jrq;
for (i = 0; i < nrequest; i++) {
irq = requests[i];
// only examine NeighRequests added by morph_skip()
// only those with size attribute for granular systems
if (!irq->neigh) continue;
if (!irq->size) continue;
// check children of this list
int onesided = -1;
for (j = 0; j < nrequest; j++) {
jrq = requests[j];
// only consider JRQ pair, size lists that skip from Irq list
if (!jrq->pair) continue;
if (!jrq->size) continue;
if (!jrq->skip || jrq->skiplist != i) continue;
// onesided = -1 if no children
// onesided = 0/1 = child granonesided value if same for all children
// onesided = 2 if children have different granonesided values
if (onesided < 0) onesided = jrq->granonesided;
else if (onesided != jrq->granonesided) onesided = 2;
if (onesided == 2) break;
}
// if onesided = 2, parent has children with both granonesided = 0/1
// force parent newton off (newton = 2) to enable onesided skip by child
// set parent granonesided = 0, so it stores all neighs in usual manner
// set off2on = 1 for all children, since they expect newton on lists
// this is b/c granonesided only set by line/gran and tri/gran which
// both require system newton on
if (onesided == 2) {
irq->newton = 2;
irq->granonesided = 0;
for (j = 0; j < nrequest; j++) {
jrq = requests[j];
// only consider JRQ pair, size lists that skip from Irq list
if (!jrq->pair) continue;
if (!jrq->size) continue;
if (!jrq->skip || jrq->skiplist != i) continue;
jrq->off2on = 1;
}
}
}
}
/* ----------------------------------------------------------------------
scan NeighRequests for possible half lists to derive from full lists
if 2 requests match, set half list to derive from full list
------------------------------------------------------------------------- */
void Neighbor::morph_halffull()
{
int i,j;
NeighRequest *irq,*jrq;
for (i = 0; i < nrequest; i++) {
irq = requests[i];
// only processing half lists
if (!irq->half) continue;
// Kokkos doesn't yet support half from full
if (irq->kokkos_host) continue;
if (irq->kokkos_device) continue;
// these lists are created other ways, no need for halffull
// do want to process skip lists
if (irq->history) continue;
if (irq->respainner || irq->respamiddle) continue;
if (irq->copy) continue;
// check all other lists
for (j = 0; j < nrequest; j++) {
if (i == j) continue;
jrq = requests[j];
// can only derive from a perpetual full list
// newton setting of derived list does not matter
if (jrq->occasional) continue;
if (!jrq->full) continue;
// these flags must be same,
// else 2 lists do not store same pairs
// or their data structures are different
// this includes custom cutoff set by requestor
// no need to check respaouter b/c it stores same pairs
// no need to check dnum b/c only set for history
if (irq->ghost != jrq->ghost) continue;
if (irq->size != jrq->size) continue;
if (irq->bond != jrq->bond) continue;
if (irq->omp != jrq->omp) continue;
if (irq->intel != jrq->intel) continue;
if (irq->kokkos_host != jrq->kokkos_host) continue;
if (irq->kokkos_device != jrq->kokkos_device) continue;
if (irq->ssa != jrq->ssa) continue;
if (irq->cut != jrq->cut) continue;
if (irq->cutoff != jrq->cutoff) continue;
// skip flag must be same
// if both are skip lists, skip info must match
if (irq->skip != jrq->skip) continue;
if (irq->skip && irq->same_skip(jrq) == 0) continue;
// 2 lists are a match
break;
}
// if matching list exists, point to it
if (j < nrequest) {
irq->halffull = 1;
irq->halffulllist = j;
}
}
}
/* ----------------------------------------------------------------------
scan NeighRequests for possible copies
if 2 requests match, turn one into a copy of the other
------------------------------------------------------------------------- */
void Neighbor::morph_copy()
{
int i,j,inewton,jnewton;
NeighRequest *irq,*jrq;
for (i = 0; i < nrequest; i++) {
irq = requests[i];
// this list is already a copy list due to another morph method
if (irq->copy) continue;
// these lists are created other ways, no need to copy
// skip lists are eligible to become a copy list
if (irq->history) continue;
if (irq->respainner || irq->respamiddle) continue;
// check all other lists
for (j = 0; j < nrequest; j++) {
if (i == j) continue;
jrq = requests[j];
// other list is already copied from this one
if (jrq->copy && jrq->copylist == i) continue;
// other list (jrq) to copy from must be perpetual
// list that becomes a copy list (irq) can be perpetual or occasional
// if both lists are perpetual, require j < i
// to prevent circular dependence with 3 or more copies of a list
if (jrq->occasional) continue;
if (!irq->occasional && j > i) continue;
// both lists must be half, or both full
if (irq->half != jrq->half) continue;
if (irq->full != jrq->full) continue;
// both lists must be newton on, or both newton off
// IJ newton = 1 for newton on, 2 for newton off
inewton = irq->newton;
if (inewton == 0) inewton = force->newton_pair ? 1 : 2;
jnewton = jrq->newton;
if (jnewton == 0) jnewton = force->newton_pair ? 1 : 2;
if (inewton != jnewton) continue;
// ok for non-ghost list to copy from ghost list, but not vice versa
if (irq->ghost && !jrq->ghost) continue;
// do not copy from a history list or a respa middle/inner list
if (jrq->history) continue;
if (jrq->respamiddle) continue;
if (jrq->respainner) continue;
// these flags must be same,
// else 2 lists do not store same pairs
// or their data structures are different
// this includes custom cutoff set by requestor
// no need to check respaouter b/c it stores same pairs
// no need to check omp b/c it stores same pairs
// no need to check dnum b/c only set for history
// NOTE: need check for 2 Kokkos flags?
if (irq->size != jrq->size) continue;
if (irq->bond != jrq->bond) continue;
if (irq->intel != jrq->intel) continue;
if (irq->kokkos_host != jrq->kokkos_host) continue;
if (irq->kokkos_device != jrq->kokkos_device) continue;
if (irq->ssa != jrq->ssa) continue;
if (irq->cut != jrq->cut) continue;
if (irq->cutoff != jrq->cutoff) continue;
// skip flag must be same
// if both are skip lists, skip info must match
if (irq->skip != jrq->skip) continue;
if (irq->skip && irq->same_skip(jrq) == 0) continue;
// 2 lists are a match
break;
}
// turn list I into a copy of list J
// do not copy a list from another copy list, but from its parent list
if (j < nrequest) {
irq->copy = 1;
if (jrq->copy) irq->copylist = jrq->copylist;
else irq->copylist = j;
}
}
}
/* ----------------------------------------------------------------------
create and initialize NTopo classes
------------------------------------------------------------------------- */
void Neighbor::init_topology()
{
int i,m;
if (!atom->molecular) return;
// set flags that determine which topology neighbor classes to use
// these settings could change from run to run, depending on fixes defined
// bonds,etc can only be broken for atom->molecular = 1, not 2
// SHAKE sets bonds and angles negative
// gcmc sets all bonds, angles, etc negative
// bond_quartic sets bonds to 0
// delete_bonds sets all interactions negative
int bond_off = 0;
int angle_off = 0;
for (i = 0; i < modify->nfix; i++)
if ((strcmp(modify->fix[i]->style,"shake") == 0)
|| (strcmp(modify->fix[i]->style,"rattle") == 0))
bond_off = angle_off = 1;
if (force->bond && force->bond_match("quartic")) bond_off = 1;
if (atom->avec->bonds_allow && atom->molecular == 1) {
for (i = 0; i < atom->nlocal; i++) {
if (bond_off) break;
for (m = 0; m < atom->num_bond[i]; m++)
if (atom->bond_type[i][m] <= 0) bond_off = 1;
}
}
if (atom->avec->angles_allow && atom->molecular == 1) {
for (i = 0; i < atom->nlocal; i++) {
if (angle_off) break;
for (m = 0; m < atom->num_angle[i]; m++)
if (atom->angle_type[i][m] <= 0) angle_off = 1;
}
}
int dihedral_off = 0;
if (atom->avec->dihedrals_allow && atom->molecular == 1) {
for (i = 0; i < atom->nlocal; i++) {
if (dihedral_off) break;
for (m = 0; m < atom->num_dihedral[i]; m++)
if (atom->dihedral_type[i][m] <= 0) dihedral_off = 1;
}
}
int improper_off = 0;
if (atom->avec->impropers_allow && atom->molecular == 1) {
for (i = 0; i < atom->nlocal; i++) {
if (improper_off) break;
for (m = 0; m < atom->num_improper[i]; m++)
if (atom->improper_type[i][m] <= 0) improper_off = 1;
}
}
for (i = 0; i < modify->nfix; i++)
if ((strcmp(modify->fix[i]->style,"gcmc") == 0))
bond_off = angle_off = dihedral_off = improper_off = 1;
// sync on/off settings across all procs
int onoff = bond_off;
MPI_Allreduce(&onoff,&bond_off,1,MPI_INT,MPI_MAX,world);
onoff = angle_off;
MPI_Allreduce(&onoff,&angle_off,1,MPI_INT,MPI_MAX,world);
onoff = dihedral_off;
MPI_Allreduce(&onoff,&dihedral_off,1,MPI_INT,MPI_MAX,world);
onoff = improper_off;
MPI_Allreduce(&onoff,&improper_off,1,MPI_INT,MPI_MAX,world);
// instantiate NTopo classes
if (atom->avec->bonds_allow) {
int old_bondwhich = bondwhich;
if (atom->molecular == 2) bondwhich = TEMPLATE;
else if (bond_off) bondwhich = PARTIAL;
else bondwhich = ALL;
if (!neigh_bond || bondwhich != old_bondwhich) {
delete neigh_bond;
if (bondwhich == ALL)
neigh_bond = new NTopoBondAll(lmp);
else if (bondwhich == PARTIAL)
neigh_bond = new NTopoBondPartial(lmp);
else if (bondwhich == TEMPLATE)
neigh_bond = new NTopoBondTemplate(lmp);
}
}
if (atom->avec->angles_allow) {
int old_anglewhich = anglewhich;
if (atom->molecular == 2) anglewhich = TEMPLATE;
else if (angle_off) anglewhich = PARTIAL;
else anglewhich = ALL;
if (!neigh_angle || anglewhich != old_anglewhich) {
delete neigh_angle;
if (anglewhich == ALL)
neigh_angle = new NTopoAngleAll(lmp);
else if (anglewhich == PARTIAL)
neigh_angle = new NTopoAnglePartial(lmp);
else if (anglewhich == TEMPLATE)
neigh_angle = new NTopoAngleTemplate(lmp);
}
}
if (atom->avec->dihedrals_allow) {
int old_dihedralwhich = dihedralwhich;
if (atom->molecular == 2) dihedralwhich = TEMPLATE;
else if (dihedral_off) dihedralwhich = PARTIAL;
else dihedralwhich = ALL;
if (!neigh_dihedral || dihedralwhich != old_dihedralwhich) {
delete neigh_dihedral;
if (dihedralwhich == ALL)
neigh_dihedral = new NTopoDihedralAll(lmp);
else if (dihedralwhich == PARTIAL)
neigh_dihedral = new NTopoDihedralPartial(lmp);
else if (dihedralwhich == TEMPLATE)
neigh_dihedral = new NTopoDihedralTemplate(lmp);
}
}
if (atom->avec->impropers_allow) {
int old_improperwhich = improperwhich;
if (atom->molecular == 2) improperwhich = TEMPLATE;
else if (improper_off) improperwhich = PARTIAL;
else improperwhich = ALL;
if (!neigh_improper || improperwhich != old_improperwhich) {
delete neigh_improper;
if (improperwhich == ALL)
neigh_improper = new NTopoImproperAll(lmp);
else if (improperwhich == PARTIAL)
neigh_improper = new NTopoImproperPartial(lmp);
else if (improperwhich == TEMPLATE)
neigh_improper = new NTopoImproperTemplate(lmp);
}
}
}
/* ----------------------------------------------------------------------
output summary of pairwise neighbor list info
only called by proc 0
------------------------------------------------------------------------- */
void Neighbor::print_pairwise_info()
{
int i,m;
char str[128];
NeighRequest *rq;
FILE *out;
const double cutghost = MAX(cutneighmax,comm->cutghostuser);
double binsize, bbox[3];
bbox[0] = bboxhi[0]-bboxlo[0];
bbox[1] = bboxhi[1]-bboxlo[1];
bbox[2] = bboxhi[2]-bboxlo[2];
if (binsizeflag) binsize = binsize_user;
else if (style == BIN) binsize = 0.5*cutneighmax;
else binsize = 0.5*cutneighmin;
if (binsize == 0.0) binsize = bbox[0];
int nperpetual = 0;
int noccasional = 0;
int nextra = 0;
for (i = 0; i < nlist; i++) {
if (lists[i]->pair_method == 0) nextra++;
else if (lists[i]->occasional) noccasional++;
else nperpetual++;
}
for (m = 0; m < 2; m++) {
if (m == 0) out = screen;
else out = logfile;
if (out) {
fprintf(out,"Neighbor list info ...\n");
fprintf(out," update every %d steps, delay %d steps, check %s\n",
every,delay,dist_check ? "yes" : "no");
fprintf(out," max neighbors/atom: %d, page size: %d\n",
oneatom, pgsize);
fprintf(out," master list distance cutoff = %g\n",cutneighmax);
fprintf(out," ghost atom cutoff = %g\n",cutghost);
if (style != NSQ)
fprintf(out," binsize = %g, bins = %g %g %g\n",binsize,
ceil(bbox[0]/binsize), ceil(bbox[1]/binsize),
ceil(bbox[2]/binsize));
fprintf(out," %d neighbor lists, "
"perpetual/occasional/extra = %d %d %d\n",
nlist,nperpetual,noccasional,nextra);
for (i = 0; i < nlist; i++) {
rq = requests[i];
if (rq->pair) {
char *pname = force->pair_match_ptr((Pair *) rq->requestor);
sprintf(str," (%d) pair %s",i+1,pname);
} else if (rq->fix) {
sprintf(str," (%d) fix %s",i+1,((Fix *) rq->requestor)->style);
} else if (rq->compute) {
sprintf(str," (%d) compute %s",i+1,
((Compute *) rq->requestor)->style);
} else if (rq->command) {
sprintf(str," (%d) command %s",i+1,rq->command_style);
} else if (rq->neigh) {
sprintf(str," (%d) neighbor class addition",i+1);
}
fprintf(out,"%s",str);
if (rq->occasional) fprintf(out,", occasional");
else fprintf(out,", perpetual");
// order these to get single output of most relevant
if (rq->history)
fprintf(out,", history for (%d)",rq->historylist+1);
else if (rq->copy)
fprintf(out,", copy from (%d)",rq->copylist+1);
else if (rq->halffull)
fprintf(out,", half/full from (%d)",rq->halffulllist+1);
else if (rq->skip)
fprintf(out,", skip from (%d)",rq->skiplist+1);
fprintf(out,"\n");
// list of neigh list attributes
fprintf(out," attributes: ");
if (rq->half) fprintf(out,"half");
else if (rq->full) fprintf(out,"full");
if (rq->newton == 0) {
if (force->newton_pair) fprintf(out,", newton on");
else fprintf(out,", newton off");
} else if (rq->newton == 1) fprintf(out,", newton on");
else if (rq->newton == 2) fprintf(out,", newton off");
if (rq->ghost) fprintf(out,", ghost");
if (rq->size) fprintf(out,", size");
if (rq->history) fprintf(out,", history");
if (rq->granonesided) fprintf(out,", onesided");
if (rq->respainner) fprintf(out,", respa outer");
if (rq->respamiddle) fprintf(out,", respa middle");
if (rq->respaouter) fprintf(out,", respa inner");
if (rq->bond) fprintf(out,", bond");
if (rq->omp) fprintf(out,", omp");
if (rq->intel) fprintf(out,", intel");
if (rq->kokkos_device) fprintf(out,", kokkos_device");
if (rq->kokkos_host) fprintf(out,", kokkos_host");
if (rq->ssa) fprintf(out,", ssa");
if (rq->cut) fprintf(out,", cut %g",rq->cutoff);
if (rq->off2on) fprintf(out,", off2on");
fprintf(out,"\n");
fprintf(out," ");
if (lists[i]->pair_method == 0) fprintf(out,"pair build: none\n");
else fprintf(out,"pair build: %s\n",pairnames[lists[i]->pair_method-1]);
fprintf(out," ");
if (lists[i]->stencil_method == 0) fprintf(out,"stencil: none\n");
else fprintf(out,"stencil: %s\n",
stencilnames[lists[i]->stencil_method-1]);
fprintf(out," ");
if (lists[i]->bin_method == 0) fprintf(out,"bin: none\n");
else fprintf(out,"bin: %s\n",binnames[lists[i]->bin_method-1]);
}
/*
fprintf(out," %d stencil methods\n",nstencil);
for (i = 0; i < nstencil; i++)
fprintf(out," (%d) %s\n",
i+1,stencilnames[neigh_stencil[i]->istyle-1]);
fprintf(out," %d bin methods\n",nbin);
for (i = 0; i < nbin; i++)
fprintf(out," (%d) %s\n",i+1,binnames[neigh_bin[i]->istyle-1]);
*/
}
}
}
/* ----------------------------------------------------------------------
make copy of current requests and Neighbor params
used to compare to when next run occurs
------------------------------------------------------------------------- */
void Neighbor::requests_new2old()
{
for (int i = 0; i < old_nrequest; i++) delete old_requests[i];
memory->sfree(old_requests);
old_nrequest = nrequest;
old_requests = (NeighRequest **)
memory->smalloc(old_nrequest*sizeof(NeighRequest *),
"neighbor:old_requests");
for (int i = 0; i < old_nrequest; i++) {
old_requests[i] = new NeighRequest(lmp);
old_requests[i]->copy_request(requests[i],1);
}
old_style = style;
old_triclinic = triclinic;
old_pgsize = pgsize;
old_oneatom = oneatom;
}
/* ----------------------------------------------------------------------
find and return request made by classptr
if not found or classpt = NULL, return NULL
------------------------------------------------------------------------- */
NeighRequest *Neighbor::find_request(void *classptr)
{
if (classptr == NULL) return NULL;
for (int i = 0; i < nrequest; i++)
if (requests[i]->requestor == classptr) return requests[i];
return NULL;
}
/* ----------------------------------------------------------------------
assign NBin class to a NeighList
use neigh request settings to build mask
match mask to list of masks of known Nbin classes
return index+1 of match in list of masks
return 0 for no binning
return -1 if no match
------------------------------------------------------------------------- */
int Neighbor::choose_bin(NeighRequest *rq)
{
// no binning needed
if (style == NSQ) return 0;
if (rq->skip || rq->copy || rq->halffull) return 0;
if (rq->history) return 0;
if (rq->respainner || rq->respamiddle) return 0;
// use request settings to match exactly one NBin class mask
// checks are bitwise using NeighConst bit masks
int mask;
for (int i = 0; i < nbclass; i++) {
mask = binmasks[i];
// require match of these request flags and mask bits
// (!A != !B) is effectively a logical xor
if (!rq->intel != !(mask & NB_INTEL)) continue;
if (!rq->ssa != !(mask & NB_SSA)) continue;
if (!rq->kokkos_device != !(mask & NB_KOKKOS_DEVICE)) continue;
if (!rq->kokkos_host != !(mask & NB_KOKKOS_HOST)) continue;
return i+1;
}
// error return if matched none
return -1;
}
/* ----------------------------------------------------------------------
assign NStencil class to a NeighList
use neigh request settings to build mask
match mask to list of masks of known NStencil classes
return index+1 of match in list of masks
return 0 for no binning
return -1 if no match
------------------------------------------------------------------------- */
int Neighbor::choose_stencil(NeighRequest *rq)
{
// no stencil creation needed
if (style == NSQ) return 0;
if (rq->skip || rq->copy || rq->halffull) return 0;
if (rq->history) return 0;
if (rq->respainner || rq->respamiddle) return 0;
// convert newton request to newtflag = on or off
int newtflag;
if (rq->newton == 0 && newton_pair) newtflag = 1;
else if (rq->newton == 0 && !newton_pair) newtflag = 0;
else if (rq->newton == 1) newtflag = 1;
else if (rq->newton == 2) newtflag = 0;
//printf("STENCIL RQ FLAGS: hff %d %d n %d g %d s %d newtflag %d\n",
// rq->half,rq->full,rq->newton,rq->ghost,rq->ssa,
// newtflag);
// use request and system settings to match exactly one NStencil class mask
// checks are bitwise using NeighConst bit masks
int mask;
for (int i = 0; i < nsclass; i++) {
mask = stencilmasks[i];
//printf("III %d: half %d full %d newton %d newtoff %d ghost %d ssa %d\n",
// i,mask & NS_HALF,mask & NS_FULL,mask & NS_NEWTON,
// mask & NS_NEWTOFF,mask & NS_GHOST,mask & NS_SSA);
// exactly one of half or full is set and must match
if (rq->half) {
if (!(mask & NS_HALF)) continue;
} else if (rq->full) {
if (!(mask & NS_FULL)) continue;
}
// newtflag is on or off and must match
if (newtflag) {
if (!(mask & NS_NEWTON)) continue;
} else if (!newtflag) {
if (!(mask & NS_NEWTOFF)) continue;
}
// require match of these request flags and mask bits
// (!A != !B) is effectively a logical xor
if (!rq->ghost != !(mask & NS_GHOST)) continue;
if (!rq->ssa != !(mask & NS_SSA)) continue;
// neighbor style is BIN or MULTI and must match
if (style == BIN) {
if (!(mask & NS_BIN)) continue;
} else if (style == MULTI) {
if (!(mask & NS_MULTI)) continue;
}
// dimension is 2 or 3 and must match
if (dimension == 2) {
if (!(mask & NS_2D)) continue;
} else if (dimension == 3) {
if (!(mask & NS_3D)) continue;
}
// domain triclinic flag is on or off and must match
if (triclinic) {
if (!(mask & NS_TRI)) continue;
} else if (!triclinic) {
if (!(mask & NS_ORTHO)) continue;
}
return i+1;
}
// error return if matched none
return -1;
}
/* ----------------------------------------------------------------------
assign NPair class to a NeighList
use neigh request settings to build mask
match mask to list of masks of known NPair classes
return index+1 of match in list of masks
return 0 for no binning
return -1 if no match
------------------------------------------------------------------------- */
int Neighbor::choose_pair(NeighRequest *rq)
{
// no neighbor list build performed
if (rq->history) return 0;
if (rq->respainner || rq->respamiddle) return 0;
// error check for includegroup with ghost neighbor request
if (includegroup && rq->ghost)
error->all(FLERR,"Neighbor include group not allowed with ghost neighbors");
// convert newton request to newtflag = on or off
int newtflag;
if (rq->newton == 0 && newton_pair) newtflag = 1;
else if (rq->newton == 0 && !newton_pair) newtflag = 0;
else if (rq->newton == 1) newtflag = 1;
else if (rq->newton == 2) newtflag = 0;
int molecular = atom->molecular;
//printf("PAIR RQ FLAGS: hf %d %d n %d g %d sz %d gos %d r %d b %d o %d i %d "
// "kk %d %d ss %d dn %d sk %d cp %d hf %d oo %d\n",
// rq->half,rq->full,rq->newton,rq->ghost,rq->size,
// rq->granonesided,rq->respaouter,rq->bond,rq->omp,rq->intel,
// rq->kokkos_host,rq->kokkos_device,rq->ssa,rq->dnum,
// rq->skip,rq->copy,rq->halffull,rq->off2on);
// use request and system settings to match exactly one NPair class mask
// checks are bitwise using NeighConst bit masks
int mask;
for (int i = 0; i < npclass; i++) {
mask = pairmasks[i];
//printf(" PAIR NAMES i %d %d name %s mask %d\n",i,nrequest,
// pairnames[i],pairmasks[i]);
// if copy request, no further checks needed, just return or continue
// Kokkos device/host flags must also match in order to copy
if (rq->copy) {
if (!(mask & NP_COPY)) continue;
if (!rq->kokkos_device != !(mask & NP_KOKKOS_DEVICE)) continue;
if (!rq->kokkos_host != !(mask & NP_KOKKOS_HOST)) continue;
return i+1;
}
// exactly one of half or full is set and must match
if (rq->half) {
if (!(mask & NP_HALF)) continue;
} else if (rq->full) {
if (!(mask & NP_FULL)) continue;
}
// newtflag is on or off and must match
if (newtflag) {
if (!(mask & NP_NEWTON)) continue;
} else if (!newtflag) {
if (!(mask & NP_NEWTOFF)) continue;
}
// if molecular on, do not match ATOMONLY (b/c a MOLONLY Npair exists)
// if molecular off, do not match MOLONLY (b/c an ATOMONLY Npair exists)
if (molecular) {
if (mask & NP_ATOMONLY) continue;
} else if (!molecular) {
if (mask & NP_MOLONLY) continue;
}
// require match of these request flags and mask bits
// (!A != !B) is effectively a logical xor
if (!rq->ghost != !(mask & NP_GHOST)) continue;
if (!rq->size != !(mask & NP_SIZE)) continue;
if (!rq->respaouter != !(mask & NP_RESPA)) continue;
if (!rq->granonesided != !(mask & NP_ONESIDE)) continue;
if (!rq->respaouter != !(mask & NP_RESPA)) continue;
if (!rq->bond != !(mask & NP_BOND)) continue;
if (!rq->omp != !(mask & NP_OMP)) continue;
if (!rq->intel != !(mask & NP_INTEL)) continue;
if (!rq->kokkos_device != !(mask & NP_KOKKOS_DEVICE)) continue;
if (!rq->kokkos_host != !(mask & NP_KOKKOS_HOST)) continue;
if (!rq->ssa != !(mask & NP_SSA)) continue;
if (!rq->skip != !(mask & NP_SKIP)) continue;
if (!rq->halffull != !(mask & NP_HALF_FULL)) continue;
if (!rq->off2on != !(mask & NP_OFF2ON)) continue;
// neighbor style is one of NSQ,BIN,MULTI and must match
if (style == NSQ) {
if (!(mask & NP_NSQ)) continue;
} else if (style == BIN) {
if (!(mask & NP_BIN)) continue;
} else if (style == MULTI) {
if (!(mask & NP_MULTI)) continue;
}
// domain triclinic flag is on or off and must match
if (triclinic) {
if (!(mask & NP_TRI)) continue;
} else if (!triclinic) {
if (!(mask & NP_ORTHO)) continue;
}
return i+1;
}
// error return if matched none
return -1;
}
/* ----------------------------------------------------------------------
called by other classes to request a pairwise neighbor list
------------------------------------------------------------------------- */
int Neighbor::request(void *requestor, int instance)
{
if (nrequest == maxrequest) {
maxrequest += RQDELTA;
requests = (NeighRequest **)
memory->srealloc(requests,maxrequest*sizeof(NeighRequest *),
"neighbor:requests");
}
requests[nrequest] = new NeighRequest(lmp);
requests[nrequest]->index = nrequest;
requests[nrequest]->requestor = requestor;
requests[nrequest]->requestor_instance = instance;
nrequest++;
return nrequest-1;
}
/* ----------------------------------------------------------------------
one instance per entry in style_neigh_bin.h
------------------------------------------------------------------------- */
template <typename T>
NBin *Neighbor::bin_creator(LAMMPS *lmp)
{
return new T(lmp);
}
/* ----------------------------------------------------------------------
one instance per entry in style_neigh_stencil.h
------------------------------------------------------------------------- */
template <typename T>
NStencil *Neighbor::stencil_creator(LAMMPS *lmp)
{
return new T(lmp);
}
/* ----------------------------------------------------------------------
one instance per entry in style_neigh_pair.h
------------------------------------------------------------------------- */
template <typename T>
NPair *Neighbor::pair_creator(LAMMPS *lmp)
{
return new T(lmp);
}
/* ----------------------------------------------------------------------
setup neighbor binning and neighbor stencils
called before run and every reneighbor if box size/shape changes
only operates on perpetual lists
build_one() operates on occasional lists
------------------------------------------------------------------------- */
void Neighbor::setup_bins()
{
// invoke setup_bins() for all NBin
// actual binning is performed in build()
for (int i = 0; i < nbin; i++)
neigh_bin[i]->setup_bins(style);
// invoke create_setup() and create() for all perpetual NStencil
// same ops performed for occasional lists in build_one()
for (int i = 0; i < nstencil_perpetual; i++) {
neigh_stencil[slist[i]]->create_setup();
neigh_stencil[slist[i]]->create();
}
last_setup_bins = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
int Neighbor::decide()
{
if (must_check) {
bigint n = update->ntimestep;
if (restart_check && n == output->next_restart) return 1;
for (int i = 0; i < fix_check; i++)
if (n == modify->fix[fixchecklist[i]]->next_reneighbor) return 1;
}
ago++;
if (ago >= delay && ago % every == 0) {
if (build_once) return 0;
if (dist_check == 0) return 1;
return check_distance();
} else return 0;
}
/* ----------------------------------------------------------------------
if any atom moved trigger distance (half of neighbor skin) return 1
shrink trigger distance if box size has changed
conservative shrink procedure:
compute distance each of 8 corners of box has moved since last reneighbor
reduce skin distance by sum of 2 largest of the 8 values
new trigger = 1/2 of reduced skin distance
for orthogonal box, only need 2 lo/hi corners
for triclinic, need all 8 corners since deformations can displace all 8
------------------------------------------------------------------------- */
int Neighbor::check_distance()
{
double delx,dely,delz,rsq;
double delta,deltasq,delta1,delta2;
if (boxcheck) {
if (triclinic == 0) {
delx = bboxlo[0] - boxlo_hold[0];
dely = bboxlo[1] - boxlo_hold[1];
delz = bboxlo[2] - boxlo_hold[2];
delta1 = sqrt(delx*delx + dely*dely + delz*delz);
delx = bboxhi[0] - boxhi_hold[0];
dely = bboxhi[1] - boxhi_hold[1];
delz = bboxhi[2] - boxhi_hold[2];
delta2 = sqrt(delx*delx + dely*dely + delz*delz);
delta = 0.5 * (skin - (delta1+delta2));
deltasq = delta*delta;
} else {
domain->box_corners();
delta1 = delta2 = 0.0;
for (int i = 0; i < 8; i++) {
delx = corners[i][0] - corners_hold[i][0];
dely = corners[i][1] - corners_hold[i][1];
delz = corners[i][2] - corners_hold[i][2];
delta = sqrt(delx*delx + dely*dely + delz*delz);
if (delta > delta1) delta1 = delta;
else if (delta > delta2) delta2 = delta;
}
delta = 0.5 * (skin - (delta1+delta2));
deltasq = delta*delta;
}
} else deltasq = triggersq;
double **x = atom->x;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int flag = 0;
for (int i = 0; i < nlocal; i++) {
delx = x[i][0] - xhold[i][0];
dely = x[i][1] - xhold[i][1];
delz = x[i][2] - xhold[i][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq > deltasq) flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall && ago == MAX(every,delay)) ndanger++;
return flagall;
}
/* ----------------------------------------------------------------------
build perpetual neighbor lists
called at setup and every few timesteps during run or minimization
topology lists also built if topoflag = 1 (Kokkos calls with topoflag=0)
------------------------------------------------------------------------- */
void Neighbor::build(int topoflag)
{
int i,m;
ago = 0;
ncalls++;
lastcall = update->ntimestep;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
// check that using special bond flags will not overflow neigh lists
if (nall > NEIGHMASK)
error->one(FLERR,"Too many local+ghost atoms for neighbor list");
// store current atom positions and box size if needed
if (dist_check) {
double **x = atom->x;
if (includegroup) nlocal = atom->nfirst;
if (atom->nmax > maxhold) {
maxhold = atom->nmax;
memory->destroy(xhold);
memory->create(xhold,maxhold,3,"neigh:xhold");
}
for (i = 0; i < nlocal; i++) {
xhold[i][0] = x[i][0];
xhold[i][1] = x[i][1];
xhold[i][2] = x[i][2];
}
if (boxcheck) {
if (triclinic == 0) {
boxlo_hold[0] = bboxlo[0];
boxlo_hold[1] = bboxlo[1];
boxlo_hold[2] = bboxlo[2];
boxhi_hold[0] = bboxhi[0];
boxhi_hold[1] = bboxhi[1];
boxhi_hold[2] = bboxhi[2];
} else {
domain->box_corners();
corners = domain->corners;
for (i = 0; i < 8; i++) {
corners_hold[i][0] = corners[i][0];
corners_hold[i][1] = corners[i][1];
corners_hold[i][2] = corners[i][2];
}
}
}
}
// bin atoms for all NBin instances
// not just NBin associated with perpetual lists, also occasional lists
// b/c cannot wait to bin occasional lists in build_one() call
// if bin then, atoms may have moved outside of proc domain & bin extent,
// leading to errors or even a crash
if (style != NSQ) {
for (int i = 0; i < nbin; i++) {
neigh_bin[i]->bin_atoms_setup(nall);
neigh_bin[i]->bin_atoms();
}
}
// build pairwise lists for all perpetual NPair/NeighList
// grow() with nlocal/nall args so that only realloc if have to
for (i = 0; i < npair_perpetual; i++) {
m = plist[i];
if (!lists[m]->copy) lists[m]->grow(nlocal,nall);
neigh_pair[m]->build_setup();
neigh_pair[m]->build(lists[m]);
}
// build topology lists for bonds/angles/etc
if (atom->molecular && topoflag) build_topology();
}
/* ----------------------------------------------------------------------
build topology neighbor lists: bond, angle, dihedral, improper
copy their list info back to Neighbor for access by bond/angle/etc classes
------------------------------------------------------------------------- */
void Neighbor::build_topology()
{
if (force->bond) {
neigh_bond->build();
nbondlist = neigh_bond->nbondlist;
bondlist = neigh_bond->bondlist;
}
if (force->angle) {
neigh_angle->build();
nanglelist = neigh_angle->nanglelist;
anglelist = neigh_angle->anglelist;
}
if (force->dihedral) {
neigh_dihedral->build();
ndihedrallist = neigh_dihedral->ndihedrallist;
dihedrallist = neigh_dihedral->dihedrallist;
}
if (force->improper) {
neigh_improper->build();
nimproperlist = neigh_improper->nimproperlist;
improperlist = neigh_improper->improperlist;
}
}
/* ----------------------------------------------------------------------
build a single occasional pairwise neighbor list indexed by I
called by other classes
------------------------------------------------------------------------- */
void Neighbor::build_one(class NeighList *mylist, int preflag)
{
// check if list structure is initialized
if (mylist == NULL)
error->all(FLERR,"Trying to build an occasional neighbor list "
"before initialization completed");
// build_one() should never be invoked on a perpetual list
if (!mylist->occasional)
error->all(FLERR,"Neighbor build one invoked on perpetual list");
// no need to build if already built since last re-neighbor
// preflag is set by fix bond/create and fix bond/swap
// b/c they invoke build_one() on same step neigh list is re-built,
// but before re-build, so need to use ">" instead of ">="
NPair *np = neigh_pair[mylist->index];
if (preflag) {
if (np->last_build > lastcall) return;
} else {
if (np->last_build >= lastcall) return;
}
// if this is copy list and parent is occasional list,
// or this is halffull and parent is occasional list,
// insure parent is current
if (mylist->listcopy && mylist->listcopy->occasional)
build_one(mylist->listcopy,preflag);
if (mylist->listfull && mylist->listfull->occasional)
build_one(mylist->listfull,preflag);
// create stencil if hasn't been created since last setup_bins() call
NStencil *ns = np->ns;
if (ns && ns->last_stencil < last_setup_bins) {
ns->create_setup();
ns->create();
}
// build the list
if (!mylist->copy) mylist->grow(atom->nlocal,atom->nlocal+atom->nghost);
np->build_setup();
np->build(mylist);
}
/* ----------------------------------------------------------------------
set neighbor style and skin distance
------------------------------------------------------------------------- */
void Neighbor::set(int narg, char **arg)
{
if (narg != 2) error->all(FLERR,"Illegal neighbor command");
skin = force->numeric(FLERR,arg[0]);
if (skin < 0.0) error->all(FLERR,"Illegal neighbor command");
if (strcmp(arg[1],"nsq") == 0) style = NSQ;
else if (strcmp(arg[1],"bin") == 0) style = BIN;
else if (strcmp(arg[1],"multi") == 0) style = MULTI;
else error->all(FLERR,"Illegal neighbor command");
if (style == MULTI && lmp->citeme) lmp->citeme->add(cite_neigh_multi);
}
/* ----------------------------------------------------------------------
reset timestamps in all NeignBin, NStencil, NPair classes
so that neighbor lists will rebuild properly with timestep change
ditto for lastcall and last_setup_bins
------------------------------------------------------------------------- */
void Neighbor::reset_timestep(bigint ntimestep)
{
for (int i = 0; i < nbin; i++)
neigh_bin[i]->last_bin = -1;
for (int i = 0; i < nstencil; i++)
neigh_stencil[i]->last_stencil = -1;
for (int i = 0; i < nlist; i++) {
if (!neigh_pair[i]) continue;
neigh_pair[i]->last_build = -1;
}
lastcall = -1;
last_setup_bins = -1;
}
/* ----------------------------------------------------------------------
modify parameters of the pair-wise neighbor build
------------------------------------------------------------------------- */
void Neighbor::modify_params(int narg, char **arg)
{
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"every") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
every = force->inumeric(FLERR,arg[iarg+1]);
if (every <= 0) error->all(FLERR,"Illegal neigh_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"delay") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
delay = force->inumeric(FLERR,arg[iarg+1]);
if (delay < 0) error->all(FLERR,"Illegal neigh_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"check") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) dist_check = 1;
else if (strcmp(arg[iarg+1],"no") == 0) dist_check = 0;
else error->all(FLERR,"Illegal neigh_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"once") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) build_once = 1;
else if (strcmp(arg[iarg+1],"no") == 0) build_once = 0;
else error->all(FLERR,"Illegal neigh_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"page") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
old_pgsize = pgsize;
pgsize = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"one") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
old_oneatom = oneatom;
oneatom = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"binsize") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
binsize_user = force->numeric(FLERR,arg[iarg+1]);
if (binsize_user <= 0.0) binsizeflag = 0;
else binsizeflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"cluster") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) cluster_check = 1;
else if (strcmp(arg[iarg+1],"no") == 0) cluster_check = 0;
else error->all(FLERR,"Illegal neigh_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"include") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
includegroup = group->find(arg[iarg+1]);
if (includegroup < 0)
error->all(FLERR,"Invalid group ID in neigh_modify command");
if (includegroup && (atom->firstgroupname == NULL ||
strcmp(arg[iarg+1],atom->firstgroupname) != 0))
error->all(FLERR,
"Neigh_modify include group != atom_modify first group");
iarg += 2;
} else if (strcmp(arg[iarg],"exclude") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (strcmp(arg[iarg+1],"type") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (nex_type == maxex_type) {
maxex_type += EXDELTA;
memory->grow(ex1_type,maxex_type,"neigh:ex1_type");
memory->grow(ex2_type,maxex_type,"neigh:ex2_type");
}
ex1_type[nex_type] = force->inumeric(FLERR,arg[iarg+2]);
ex2_type[nex_type] = force->inumeric(FLERR,arg[iarg+3]);
nex_type++;
iarg += 4;
} else if (strcmp(arg[iarg+1],"group") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (nex_group == maxex_group) {
maxex_group += EXDELTA;
memory->grow(ex1_group,maxex_group,"neigh:ex1_group");
memory->grow(ex2_group,maxex_group,"neigh:ex2_group");
}
ex1_group[nex_group] = group->find(arg[iarg+2]);
ex2_group[nex_group] = group->find(arg[iarg+3]);
if (ex1_group[nex_group] == -1 || ex2_group[nex_group] == -1)
error->all(FLERR,"Invalid group ID in neigh_modify command");
nex_group++;
iarg += 4;
} else if (strcmp(arg[iarg+1],"molecule/inter") == 0 ||
strcmp(arg[iarg+1],"molecule/intra") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal neigh_modify command");
if (atom->molecule_flag == 0)
error->all(FLERR,"Neigh_modify exclude molecule "
"requires atom attribute molecule");
if (nex_mol == maxex_mol) {
maxex_mol += EXDELTA;
memory->grow(ex_mol_group,maxex_mol,"neigh:ex_mol_group");
if (lmp->kokkos)
grow_ex_mol_intra_kokkos();
else
memory->grow(ex_mol_intra,maxex_mol,"neigh:ex_mol_intra");
}
ex_mol_group[nex_mol] = group->find(arg[iarg+2]);
if (ex_mol_group[nex_mol] == -1)
error->all(FLERR,"Invalid group ID in neigh_modify command");
if (strcmp(arg[iarg+1],"molecule/intra") == 0)
ex_mol_intra[nex_mol] = 1;
else
ex_mol_intra[nex_mol] = 0;
nex_mol++;
iarg += 3;
} else if (strcmp(arg[iarg+1],"none") == 0) {
nex_type = nex_group = nex_mol = 0;
iarg += 2;
} else error->all(FLERR,"Illegal neigh_modify command");
} else error->all(FLERR,"Illegal neigh_modify command");
}
}
/* ----------------------------------------------------------------------
remove the first group-group exclusion matching group1, group2
------------------------------------------------------------------------- */
void Neighbor::exclusion_group_group_delete(int group1, int group2)
{
int m, mlast;
for (m = 0; m < nex_group; m++)
if (ex1_group[m] == group1 && ex2_group[m] == group2 )
break;
mlast = m;
if (mlast == nex_group)
error->all(FLERR,"Unable to find group-group exclusion");
for (m = mlast+1; m < nex_group; m++) {
ex1_group[m-1] = ex1_group[m];
ex2_group[m-1] = ex2_group[m];
ex1_bit[m-1] = ex1_bit[m];
ex2_bit[m-1] = ex2_bit[m];
}
nex_group--;
}
/* ----------------------------------------------------------------------
return the value of exclude - used to check compatibility with GPU
------------------------------------------------------------------------- */
int Neighbor::exclude_setting()
{
return exclude;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint Neighbor::memory_usage()
{
bigint bytes = 0;
bytes += memory->usage(xhold,maxhold,3);
for (int i = 0; i < nlist; i++)
if (lists[i]) bytes += lists[i]->memory_usage();
for (int i = 0; i < nstencil; i++)
bytes += neigh_stencil[i]->memory_usage();
for (int i = 0; i < nbin; i++)
bytes += neigh_bin[i]->memory_usage();
if (neigh_bond) bytes += neigh_bond->memory_usage();
if (neigh_angle) bytes += neigh_angle->memory_usage();
if (neigh_dihedral) bytes += neigh_dihedral->memory_usage();
if (neigh_improper) bytes += neigh_improper->memory_usage();
return bytes;
}
diff --git a/src/pair.cpp b/src/pair.cpp
index 06792060c..ce711c4f5 100644
--- a/src/pair.cpp
+++ b/src/pair.cpp
@@ -1,1733 +1,1733 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include <mpi.h>
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "modify.h"
#include "compute.h"
#include "suffix.h"
#include "atom_masks.h"
#include "memory.h"
#include "math_const.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
enum{NONE,RLINEAR,RSQ,BMP};
// allocate space for static class instance variable and initialize it
int Pair::instance_total = 0;
/* ---------------------------------------------------------------------- */
Pair::Pair(LAMMPS *lmp) : Pointers(lmp)
{
instance_me = instance_total++;
eng_vdwl = eng_coul = 0.0;
comm_forward = comm_reverse = comm_reverse_off = 0;
single_enable = 1;
restartinfo = 1;
respa_enable = 0;
one_coeff = 0;
no_virial_fdotr_compute = 0;
writedata = 0;
ghostneigh = 0;
nextra = 0;
pvector = NULL;
single_extra = 0;
svector = NULL;
ewaldflag = pppmflag = msmflag = dispersionflag = tip4pflag = dipoleflag = 0;
reinitflag = 1;
// pair_modify settingsx
compute_flag = 1;
manybody_flag = 0;
offset_flag = 0;
mix_flag = GEOMETRIC;
tail_flag = 0;
etail = ptail = etail_ij = ptail_ij = 0.0;
ncoultablebits = 12;
ndisptablebits = 12;
tabinner = sqrt(2.0);
tabinner_disp = sqrt(2.0);
ftable = NULL;
fdisptable = NULL;
allocated = 0;
suffix_flag = Suffix::NONE;
maxeatom = maxvatom = 0;
eatom = NULL;
vatom = NULL;
num_tally_compute = 0;
list_tally_compute = NULL;
// KOKKOS per-fix data masks
execution_space = Host;
datamask_read = ALL_MASK;
datamask_modify = ALL_MASK;
copymode = 0;
}
/* ---------------------------------------------------------------------- */
Pair::~Pair()
{
num_tally_compute = 0;
memory->sfree((void *) list_tally_compute);
list_tally_compute = NULL;
if (copymode) return;
memory->destroy(eatom);
memory->destroy(vatom);
}
/* ----------------------------------------------------------------------
modify parameters of the pair style
pair_hybrid has its own version of this routine
to apply modifications to each of its sub-styles
------------------------------------------------------------------------- */
void Pair::modify_params(int narg, char **arg)
{
if (narg == 0) error->all(FLERR,"Illegal pair_modify command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"mix") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
if (strcmp(arg[iarg+1],"geometric") == 0) mix_flag = GEOMETRIC;
else if (strcmp(arg[iarg+1],"arithmetic") == 0) mix_flag = ARITHMETIC;
else if (strcmp(arg[iarg+1],"sixthpower") == 0) mix_flag = SIXTHPOWER;
else error->all(FLERR,"Illegal pair_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"shift") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) offset_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) offset_flag = 0;
else error->all(FLERR,"Illegal pair_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"table") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
ncoultablebits = force->inumeric(FLERR,arg[iarg+1]);
if (ncoultablebits > sizeof(float)*CHAR_BIT)
error->all(FLERR,"Too many total bits for bitmapped lookup table");
iarg += 2;
} else if (strcmp(arg[iarg],"table/disp") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
ndisptablebits = force->inumeric(FLERR,arg[iarg+1]);
if (ndisptablebits > sizeof(float)*CHAR_BIT)
error->all(FLERR,"Too many total bits for bitmapped lookup table");
iarg += 2;
} else if (strcmp(arg[iarg],"tabinner") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
tabinner = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"tabinner/disp") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
tabinner_disp = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"tail") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) tail_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) tail_flag = 0;
else error->all(FLERR,"Illegal pair_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"compute") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal pair_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) compute_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) compute_flag = 0;
else error->all(FLERR,"Illegal pair_modify command");
iarg += 2;
} else error->all(FLERR,"Illegal pair_modify command");
}
}
/* ---------------------------------------------------------------------- */
void Pair::init()
{
int i,j;
if (offset_flag && tail_flag)
error->all(FLERR,"Cannot have both pair_modify shift and tail set to yes");
if (tail_flag && domain->dimension == 2)
error->all(FLERR,"Cannot use pair tail corrections with 2d simulations");
if (tail_flag && domain->nonperiodic && comm->me == 0)
error->warning(FLERR,"Using pair tail corrections with nonperiodic system");
- if (!compute_flag && tail_flag)
+ if (!compute_flag && tail_flag && comm->me == 0)
error->warning(FLERR,"Using pair tail corrections with "
"pair_modify compute no");
- if (!compute_flag && offset_flag)
+ if (!compute_flag && offset_flag && comm->me == 0)
error->warning(FLERR,"Using pair potential shift with "
"pair_modify compute no");
// for manybody potentials
// check if bonded exclusions could invalidate the neighbor list
if (manybody_flag && atom->molecular) {
int flag = 0;
if (atom->nbonds > 0 && force->special_lj[1] == 0.0 &&
force->special_coul[1] == 0.0) flag = 1;
if (atom->nangles > 0 && force->special_lj[2] == 0.0 &&
force->special_coul[2] == 0.0) flag = 1;
if (atom->ndihedrals > 0 && force->special_lj[3] == 0.0 &&
force->special_coul[3] == 0.0) flag = 1;
if (flag && comm->me == 0)
error->warning(FLERR,"Using a manybody potential with "
"bonds/angles/dihedrals and special_bond exclusions");
}
// I,I coeffs must be set
// init_one() will check if I,J is set explicitly or inferred by mixing
if (!allocated) error->all(FLERR,"All pair coeffs are not set");
for (i = 1; i <= atom->ntypes; i++)
if (setflag[i][i] == 0) error->all(FLERR,"All pair coeffs are not set");
// style-specific initialization
init_style();
// call init_one() for each I,J
// set cutsq for each I,J, used to neighbor
// cutforce = max of all I,J cutoffs
cutforce = 0.0;
etail = ptail = 0.0;
double cut;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
cut = init_one(i,j);
cutsq[i][j] = cutsq[j][i] = cut*cut;
cutforce = MAX(cutforce,cut);
if (tail_flag) {
etail += etail_ij;
ptail += ptail_ij;
if (i != j) {
etail += etail_ij;
ptail += ptail_ij;
}
}
}
}
/* ----------------------------------------------------------------------
reset all type-based params by invoking init_one() for each I,J
called by fix adapt after it changes one or more params
------------------------------------------------------------------------- */
void Pair::reinit()
{
// generalize this error message if reinit() is used by more than fix adapt
if (!reinitflag)
error->all(FLERR,"Fix adapt interface to this pair style not supported");
etail = ptail = 0.0;
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++) {
init_one(i,j);
if (tail_flag) {
etail += etail_ij;
ptail += ptail_ij;
if (i != j) {
etail += etail_ij;
ptail += ptail_ij;
}
}
}
}
/* ----------------------------------------------------------------------
init specific to a pair style
specific pair style can override this function
if needs its own error checks
if needs another kind of neighbor list
request default neighbor list = half list
------------------------------------------------------------------------- */
void Pair::init_style()
{
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
specific pair style can override this function
------------------------------------------------------------------------- */
void Pair::init_list(int which, NeighList *ptr)
{
list = ptr;
}
/* ----------------------------------------------------------------------
setup Coulomb force tables used in compute routines
------------------------------------------------------------------------- */
void Pair::init_tables(double cut_coul, double *cut_respa)
{
int masklo,maskhi;
double r,grij,expm2,derfc,egamma,fgamma,rsw;
double qqrd2e = force->qqrd2e;
if (force->kspace == NULL)
error->all(FLERR,"Pair style requires a KSpace style");
double g_ewald = force->kspace->g_ewald;
double cut_coulsq = cut_coul * cut_coul;
tabinnersq = tabinner*tabinner;
init_bitmap(tabinner,cut_coul,ncoultablebits,
masklo,maskhi,ncoulmask,ncoulshiftbits);
int ntable = 1;
for (int i = 0; i < ncoultablebits; i++) ntable *= 2;
// linear lookup tables of length N = 2^ncoultablebits
// stored value = value at lower edge of bin
// d values = delta from lower edge to upper edge of bin
if (ftable) free_tables();
memory->create(rtable,ntable,"pair:rtable");
memory->create(ftable,ntable,"pair:ftable");
memory->create(ctable,ntable,"pair:ctable");
memory->create(etable,ntable,"pair:etable");
memory->create(drtable,ntable,"pair:drtable");
memory->create(dftable,ntable,"pair:dftable");
memory->create(dctable,ntable,"pair:dctable");
memory->create(detable,ntable,"pair:detable");
if (cut_respa == NULL) {
vtable = ptable = dvtable = dptable = NULL;
} else {
memory->create(vtable,ntable,"pair:vtable");
memory->create(ptable,ntable,"pair:ptable");
memory->create(dvtable,ntable,"pair:dvtable");
memory->create(dptable,ntable,"pair:dptable");
}
union_int_float_t rsq_lookup;
union_int_float_t minrsq_lookup;
int itablemin;
minrsq_lookup.i = 0 << ncoulshiftbits;
minrsq_lookup.i |= maskhi;
for (int i = 0; i < ntable; i++) {
rsq_lookup.i = i << ncoulshiftbits;
rsq_lookup.i |= masklo;
if (rsq_lookup.f < tabinnersq) {
rsq_lookup.i = i << ncoulshiftbits;
rsq_lookup.i |= maskhi;
}
r = sqrtf(rsq_lookup.f);
if (msmflag) {
egamma = 1.0 - (r/cut_coul)*force->kspace->gamma(r/cut_coul);
fgamma = 1.0 + (rsq_lookup.f/cut_coulsq)*
force->kspace->dgamma(r/cut_coul);
} else {
grij = g_ewald * r;
expm2 = exp(-grij*grij);
derfc = erfc(grij);
}
if (cut_respa == NULL) {
rtable[i] = rsq_lookup.f;
ctable[i] = qqrd2e/r;
if (msmflag) {
ftable[i] = qqrd2e/r * fgamma;
etable[i] = qqrd2e/r * egamma;
} else {
ftable[i] = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
etable[i] = qqrd2e/r * derfc;
}
} else {
rtable[i] = rsq_lookup.f;
ctable[i] = 0.0;
ptable[i] = qqrd2e/r;
if (msmflag) {
ftable[i] = qqrd2e/r * (fgamma - 1.0);
etable[i] = qqrd2e/r * egamma;
vtable[i] = qqrd2e/r * fgamma;
} else {
ftable[i] = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2 - 1.0);
etable[i] = qqrd2e/r * derfc;
vtable[i] = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
}
if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) {
if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) {
rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]);
ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw);
ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw);
} else {
if (msmflag) ftable[i] = qqrd2e/r * fgamma;
else ftable[i] = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
ctable[i] = qqrd2e/r;
}
}
}
minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f);
}
tabinnersq = minrsq_lookup.f;
int ntablem1 = ntable - 1;
for (int i = 0; i < ntablem1; i++) {
drtable[i] = 1.0/(rtable[i+1] - rtable[i]);
dftable[i] = ftable[i+1] - ftable[i];
dctable[i] = ctable[i+1] - ctable[i];
detable[i] = etable[i+1] - etable[i];
}
if (cut_respa) {
for (int i = 0; i < ntablem1; i++) {
dvtable[i] = vtable[i+1] - vtable[i];
dptable[i] = ptable[i+1] - ptable[i];
}
}
// get the delta values for the last table entries
// tables are connected periodically between 0 and ntablem1
drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]);
dftable[ntablem1] = ftable[0] - ftable[ntablem1];
dctable[ntablem1] = ctable[0] - ctable[ntablem1];
detable[ntablem1] = etable[0] - etable[ntablem1];
if (cut_respa) {
dvtable[ntablem1] = vtable[0] - vtable[ntablem1];
dptable[ntablem1] = ptable[0] - ptable[ntablem1];
}
// get the correct delta values at itablemax
// smallest r is in bin itablemin
// largest r is in bin itablemax, which is itablemin-1,
// or ntablem1 if itablemin=0
// deltas at itablemax only needed if corresponding rsq < cut*cut
// if so, compute deltas between rsq and cut*cut
double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp;
p_tmp = 0.0;
v_tmp = 0.0;
itablemin = minrsq_lookup.i & ncoulmask;
itablemin >>= ncoulshiftbits;
int itablemax = itablemin - 1;
if (itablemin == 0) itablemax = ntablem1;
rsq_lookup.i = itablemax << ncoulshiftbits;
rsq_lookup.i |= maskhi;
if (rsq_lookup.f < cut_coulsq) {
rsq_lookup.f = cut_coulsq;
r = sqrtf(rsq_lookup.f);
if (msmflag) {
egamma = 1.0 - (r/cut_coul)*force->kspace->gamma(r/cut_coul);
fgamma = 1.0 + (rsq_lookup.f/cut_coulsq)*
force->kspace->dgamma(r/cut_coul);
} else {
grij = g_ewald * r;
expm2 = exp(-grij*grij);
derfc = erfc(grij);
}
if (cut_respa == NULL) {
c_tmp = qqrd2e/r;
if (msmflag) {
f_tmp = qqrd2e/r * fgamma;
e_tmp = qqrd2e/r * egamma;
} else {
f_tmp = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
e_tmp = qqrd2e/r * derfc;
}
} else {
c_tmp = 0.0;
p_tmp = qqrd2e/r;
if (msmflag) {
f_tmp = qqrd2e/r * (fgamma - 1.0);
e_tmp = qqrd2e/r * egamma;
v_tmp = qqrd2e/r * fgamma;
} else {
f_tmp = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2 - 1.0);
e_tmp = qqrd2e/r * derfc;
v_tmp = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
}
if (rsq_lookup.f > cut_respa[2]*cut_respa[2]) {
if (rsq_lookup.f < cut_respa[3]*cut_respa[3]) {
rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]);
f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw);
c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw);
} else {
if (msmflag) f_tmp = qqrd2e/r * fgamma;
else f_tmp = qqrd2e/r * (derfc + MY_ISPI4*grij*expm2);
c_tmp = qqrd2e/r;
}
}
}
drtable[itablemax] = 1.0/(rsq_lookup.f - rtable[itablemax]);
dftable[itablemax] = f_tmp - ftable[itablemax];
dctable[itablemax] = c_tmp - ctable[itablemax];
detable[itablemax] = e_tmp - etable[itablemax];
if (cut_respa) {
dvtable[itablemax] = v_tmp - vtable[itablemax];
dptable[itablemax] = p_tmp - ptable[itablemax];
}
}
}
/* ----------------------------------------------------------------------
setup force tables for dispersion used in compute routines
------------------------------------------------------------------------- */
void Pair::init_tables_disp(double cut_lj_global)
{
int masklo,maskhi;
double rsq;
double g_ewald_6 = force->kspace->g_ewald_6;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
tabinnerdispsq = tabinner_disp*tabinner_disp;
init_bitmap(tabinner_disp,cut_lj_global,ndisptablebits,
masklo,maskhi,ndispmask,ndispshiftbits);
int ntable = 1;
for (int i = 0; i < ndisptablebits; i++) ntable *= 2;
// linear lookup tables of length N = 2^ndisptablebits
// stored value = value at lower edge of bin
// d values = delta from lower edge to upper edge of bin
if (fdisptable) free_disp_tables();
memory->create(rdisptable,ntable,"pair:rdisptable");
memory->create(fdisptable,ntable,"pair:fdisptable");
memory->create(edisptable,ntable,"pair:edisptable");
memory->create(drdisptable,ntable,"pair:drdisptable");
memory->create(dfdisptable,ntable,"pair:dfdisptable");
memory->create(dedisptable,ntable,"pair:dedisptable");
union_int_float_t rsq_lookup;
union_int_float_t minrsq_lookup;
int itablemin;
minrsq_lookup.i = 0 << ndispshiftbits;
minrsq_lookup.i |= maskhi;
for (int i = 0; i < ntable; i++) {
rsq_lookup.i = i << ndispshiftbits;
rsq_lookup.i |= masklo;
if (rsq_lookup.f < tabinnerdispsq) {
rsq_lookup.i = i << ndispshiftbits;
rsq_lookup.i |= maskhi;
}
rsq = rsq_lookup.f;
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2);
rdisptable[i] = rsq_lookup.f;
fdisptable[i] = g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
edisptable[i] = g6*((a2+1.0)*a2+0.5)*x2;
minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f);
}
tabinnerdispsq = minrsq_lookup.f;
int ntablem1 = ntable - 1;
for (int i = 0; i < ntablem1; i++) {
drdisptable[i] = 1.0/(rdisptable[i+1] - rdisptable[i]);
dfdisptable[i] = fdisptable[i+1] - fdisptable[i];
dedisptable[i] = edisptable[i+1] - edisptable[i];
}
// get the delta values for the last table entries
// tables are connected periodically between 0 and ntablem1
drdisptable[ntablem1] = 1.0/(rdisptable[0] - rdisptable[ntablem1]);
dfdisptable[ntablem1] = fdisptable[0] - fdisptable[ntablem1];
dedisptable[ntablem1] = edisptable[0] - edisptable[ntablem1];
// get the correct delta values at itablemax
// smallest r is in bin itablemin
// largest r is in bin itablemax, which is itablemin-1,
// or ntablem1 if itablemin=0
// deltas at itablemax only needed if corresponding rsq < cut*cut
// if so, compute deltas between rsq and cut*cut
double f_tmp,e_tmp;
double cut_lj_globalsq;
itablemin = minrsq_lookup.i & ndispmask;
itablemin >>= ndispshiftbits;
int itablemax = itablemin - 1;
if (itablemin == 0) itablemax = ntablem1;
rsq_lookup.i = itablemax << ndispshiftbits;
rsq_lookup.i |= maskhi;
if (rsq_lookup.f < (cut_lj_globalsq = cut_lj_global * cut_lj_global)) {
rsq_lookup.f = cut_lj_globalsq;
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2);
f_tmp = g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
e_tmp = g6*((a2+1.0)*a2+0.5)*x2;
drdisptable[itablemax] = 1.0/(rsq_lookup.f - rdisptable[itablemax]);
dfdisptable[itablemax] = f_tmp - fdisptable[itablemax];
dedisptable[itablemax] = e_tmp - edisptable[itablemax];
}
}
/* ----------------------------------------------------------------------
free memory for tables used in Coulombic pair computations
------------------------------------------------------------------------- */
void Pair::free_tables()
{
memory->destroy(rtable);
memory->destroy(drtable);
memory->destroy(ftable);
memory->destroy(dftable);
memory->destroy(ctable);
memory->destroy(dctable);
memory->destroy(etable);
memory->destroy(detable);
memory->destroy(vtable);
memory->destroy(dvtable);
memory->destroy(ptable);
memory->destroy(dptable);
}
/* ----------------------------------------------------------------------
free memory for tables used in pair computations for dispersion
------------------------------------------------------------------------- */
void Pair::free_disp_tables()
{
memory->destroy(rdisptable);
memory->destroy(drdisptable);
memory->destroy(fdisptable);
memory->destroy(dfdisptable);
memory->destroy(edisptable);
memory->destroy(dedisptable);
}
/* ----------------------------------------------------------------------
mixing of pair potential prefactors (epsilon)
------------------------------------------------------------------------- */
double Pair::mix_energy(double eps1, double eps2, double sig1, double sig2)
{
if (mix_flag == GEOMETRIC)
return sqrt(eps1*eps2);
else if (mix_flag == ARITHMETIC)
return sqrt(eps1*eps2);
else if (mix_flag == SIXTHPOWER)
return (2.0 * sqrt(eps1*eps2) *
pow(sig1,3.0) * pow(sig2,3.0) / (pow(sig1,6.0) + pow(sig2,6.0)));
else return 0.0;
}
/* ----------------------------------------------------------------------
mixing of pair potential distances (sigma, cutoff)
------------------------------------------------------------------------- */
double Pair::mix_distance(double sig1, double sig2)
{
if (mix_flag == GEOMETRIC)
return sqrt(sig1*sig2);
else if (mix_flag == ARITHMETIC)
return (0.5 * (sig1+sig2));
else if (mix_flag == SIXTHPOWER)
return pow((0.5 * (pow(sig1,6.0) + pow(sig2,6.0))),1.0/6.0);
else return 0.0;
}
/* ---------------------------------------------------------------------- */
void Pair::compute_dummy(int eflag, int vflag)
{
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
}
/* -------------------------------------------------------------------
register a callback to a compute, so it can compute and accumulate
additional properties during the pair computation from within
Pair::ev_tally(). ensure each compute instance is registered only once
---------------------------------------------------------------------- */
void Pair::add_tally_callback(Compute *ptr)
{
if (lmp->kokkos)
error->all(FLERR,"Cannot yet use compute tally with Kokkos");
int i,found=-1;
for (i=0; i < num_tally_compute; ++i) {
if (list_tally_compute[i] == ptr)
found = i;
}
if (found < 0) {
found = num_tally_compute;
++num_tally_compute;
void *p = memory->srealloc((void *)list_tally_compute,
sizeof(Compute *) * num_tally_compute,
"pair:list_tally_compute");
list_tally_compute = (Compute **) p;
list_tally_compute[num_tally_compute-1] = ptr;
}
}
/* -------------------------------------------------------------------
unregister a callback to a fix for additional pairwise tallying
---------------------------------------------------------------------- */
void Pair::del_tally_callback(Compute *ptr)
{
int i,found=-1;
for (i=0; i < num_tally_compute; ++i) {
if (list_tally_compute[i] == ptr)
found = i;
}
if (found < 0)
return;
// compact the list of active computes
--num_tally_compute;
for (i=found; i < num_tally_compute; ++i) {
list_tally_compute[i] = list_tally_compute[i+1];
}
}
/* ----------------------------------------------------------------------
setup for energy, virial computation
see integrate::ev_set() for values of eflag (0-3) and vflag (0-6)
------------------------------------------------------------------------- */
void Pair::ev_setup(int eflag, int vflag, int alloc)
{
int i,n;
evflag = 1;
eflag_either = eflag;
eflag_global = eflag % 2;
eflag_atom = eflag / 2;
vflag_either = vflag;
vflag_global = vflag % 4;
vflag_atom = vflag / 4;
// reallocate per-atom arrays if necessary
if (eflag_atom && atom->nmax > maxeatom) {
maxeatom = atom->nmax;
if (alloc) {
memory->destroy(eatom);
memory->create(eatom,comm->nthreads*maxeatom,"pair:eatom");
}
}
if (vflag_atom && atom->nmax > maxvatom) {
maxvatom = atom->nmax;
if (alloc) {
memory->destroy(vatom);
memory->create(vatom,comm->nthreads*maxvatom,6,"pair:vatom");
}
}
// zero accumulators
// use force->newton instead of newton_pair
// b/c some bonds/dihedrals call pair::ev_tally with pairwise info
if (eflag_global) eng_vdwl = eng_coul = 0.0;
if (vflag_global) for (i = 0; i < 6; i++) virial[i] = 0.0;
if (eflag_atom && alloc) {
n = atom->nlocal;
if (force->newton) n += atom->nghost;
for (i = 0; i < n; i++) eatom[i] = 0.0;
}
if (vflag_atom && alloc) {
n = atom->nlocal;
if (force->newton) n += atom->nghost;
for (i = 0; i < n; i++) {
vatom[i][0] = 0.0;
vatom[i][1] = 0.0;
vatom[i][2] = 0.0;
vatom[i][3] = 0.0;
vatom[i][4] = 0.0;
vatom[i][5] = 0.0;
}
}
// if vflag_global = 2 and pair::compute() calls virial_fdotr_compute()
// compute global virial via (F dot r) instead of via pairwise summation
// unset other flags as appropriate
if (vflag_global == 2 && no_virial_fdotr_compute == 0) {
vflag_fdotr = 1;
vflag_global = 0;
if (vflag_atom == 0) vflag_either = 0;
if (vflag_either == 0 && eflag_either == 0) evflag = 0;
} else vflag_fdotr = 0;
// run ev_setup option for USER-TALLY computes
if (num_tally_compute > 0) {
for (int k=0; k < num_tally_compute; ++k) {
Compute *c = list_tally_compute[k];
c->pair_setup_callback(eflag,vflag);
}
}
}
/* ----------------------------------------------------------------------
set all flags to zero for energy, virial computation
called by some complicated many-body potentials that use individual flags
to insure no holdover of flags from previous timestep
------------------------------------------------------------------------- */
void Pair::ev_unset()
{
evflag = 0;
eflag_either = 0;
eflag_global = 0;
eflag_atom = 0;
vflag_either = 0;
vflag_global = 0;
vflag_atom = 0;
vflag_fdotr = 0;
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
need i < nlocal test since called by bond_quartic and dihedral_charmm
------------------------------------------------------------------------- */
void Pair::ev_tally(int i, int j, int nlocal, int newton_pair,
double evdwl, double ecoul, double fpair,
double delx, double dely, double delz)
{
double evdwlhalf,ecoulhalf,epairhalf,v[6];
if (eflag_either) {
if (eflag_global) {
if (newton_pair) {
eng_vdwl += evdwl;
eng_coul += ecoul;
} else {
evdwlhalf = 0.5*evdwl;
ecoulhalf = 0.5*ecoul;
if (i < nlocal) {
eng_vdwl += evdwlhalf;
eng_coul += ecoulhalf;
}
if (j < nlocal) {
eng_vdwl += evdwlhalf;
eng_coul += ecoulhalf;
}
}
}
if (eflag_atom) {
epairhalf = 0.5 * (evdwl + ecoul);
if (newton_pair || i < nlocal) eatom[i] += epairhalf;
if (newton_pair || j < nlocal) eatom[j] += epairhalf;
}
}
if (vflag_either) {
v[0] = delx*delx*fpair;
v[1] = dely*dely*fpair;
v[2] = delz*delz*fpair;
v[3] = delx*dely*fpair;
v[4] = delx*delz*fpair;
v[5] = dely*delz*fpair;
if (vflag_global) {
if (newton_pair) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
} else {
if (i < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
if (j < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
}
}
if (vflag_atom) {
if (newton_pair || i < nlocal) {
vatom[i][0] += 0.5*v[0];
vatom[i][1] += 0.5*v[1];
vatom[i][2] += 0.5*v[2];
vatom[i][3] += 0.5*v[3];
vatom[i][4] += 0.5*v[4];
vatom[i][5] += 0.5*v[5];
}
if (newton_pair || j < nlocal) {
vatom[j][0] += 0.5*v[0];
vatom[j][1] += 0.5*v[1];
vatom[j][2] += 0.5*v[2];
vatom[j][3] += 0.5*v[3];
vatom[j][4] += 0.5*v[4];
vatom[j][5] += 0.5*v[5];
}
}
}
if (num_tally_compute > 0) {
for (int k=0; k < num_tally_compute; ++k) {
Compute *c = list_tally_compute[k];
c->pair_tally_callback(i, j, nlocal, newton_pair,
evdwl, ecoul, fpair, delx, dely, delz);
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
can use this version with full neighbor lists
------------------------------------------------------------------------- */
void Pair::ev_tally_full(int i, double evdwl, double ecoul, double fpair,
double delx, double dely, double delz)
{
double v[6];
if (eflag_either) {
if (eflag_global) {
eng_vdwl += 0.5*evdwl;
eng_coul += 0.5*ecoul;
}
if (eflag_atom) eatom[i] += 0.5 * (evdwl + ecoul);
}
if (vflag_either) {
v[0] = 0.5*delx*delx*fpair;
v[1] = 0.5*dely*dely*fpair;
v[2] = 0.5*delz*delz*fpair;
v[3] = 0.5*delx*dely*fpair;
v[4] = 0.5*delx*delz*fpair;
v[5] = 0.5*dely*delz*fpair;
if (vflag_global) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
}
if (vflag_atom) {
vatom[i][0] += v[0];
vatom[i][1] += v[1];
vatom[i][2] += v[2];
vatom[i][3] += v[3];
vatom[i][4] += v[4];
vatom[i][5] += v[5];
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
for virial, have delx,dely,delz and fx,fy,fz
------------------------------------------------------------------------- */
void Pair::ev_tally_xyz(int i, int j, int nlocal, int newton_pair,
double evdwl, double ecoul,
double fx, double fy, double fz,
double delx, double dely, double delz)
{
double evdwlhalf,ecoulhalf,epairhalf,v[6];
if (eflag_either) {
if (eflag_global) {
if (newton_pair) {
eng_vdwl += evdwl;
eng_coul += ecoul;
} else {
evdwlhalf = 0.5*evdwl;
ecoulhalf = 0.5*ecoul;
if (i < nlocal) {
eng_vdwl += evdwlhalf;
eng_coul += ecoulhalf;
}
if (j < nlocal) {
eng_vdwl += evdwlhalf;
eng_coul += ecoulhalf;
}
}
}
if (eflag_atom) {
epairhalf = 0.5 * (evdwl + ecoul);
if (newton_pair || i < nlocal) eatom[i] += epairhalf;
if (newton_pair || j < nlocal) eatom[j] += epairhalf;
}
}
if (vflag_either) {
v[0] = delx*fx;
v[1] = dely*fy;
v[2] = delz*fz;
v[3] = delx*fy;
v[4] = delx*fz;
v[5] = dely*fz;
if (vflag_global) {
if (newton_pair) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
} else {
if (i < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
if (j < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
}
}
if (vflag_atom) {
if (newton_pair || i < nlocal) {
vatom[i][0] += 0.5*v[0];
vatom[i][1] += 0.5*v[1];
vatom[i][2] += 0.5*v[2];
vatom[i][3] += 0.5*v[3];
vatom[i][4] += 0.5*v[4];
vatom[i][5] += 0.5*v[5];
}
if (newton_pair || j < nlocal) {
vatom[j][0] += 0.5*v[0];
vatom[j][1] += 0.5*v[1];
vatom[j][2] += 0.5*v[2];
vatom[j][3] += 0.5*v[3];
vatom[j][4] += 0.5*v[4];
vatom[j][5] += 0.5*v[5];
}
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
for virial, have delx,dely,delz and fx,fy,fz
called when using full neighbor lists
------------------------------------------------------------------------- */
void Pair::ev_tally_xyz_full(int i, double evdwl, double ecoul,
double fx, double fy, double fz,
double delx, double dely, double delz)
{
double evdwlhalf,ecoulhalf,epairhalf,v[6];
if (eflag_either) {
if (eflag_global) {
evdwlhalf = 0.5*evdwl;
ecoulhalf = 0.5*ecoul;
eng_vdwl += evdwlhalf;
eng_coul += ecoulhalf;
}
if (eflag_atom) {
epairhalf = 0.5 * (evdwl + ecoul);
eatom[i] += epairhalf;
}
}
if (vflag_either) {
v[0] = 0.5*delx*fx;
v[1] = 0.5*dely*fy;
v[2] = 0.5*delz*fz;
v[3] = 0.5*delx*fy;
v[4] = 0.5*delx*fz;
v[5] = 0.5*dely*fz;
if (vflag_global) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
}
if (vflag_atom) {
vatom[i][0] += v[0];
vatom[i][1] += v[1];
vatom[i][2] += v[2];
vatom[i][3] += v[3];
vatom[i][4] += v[4];
vatom[i][5] += v[5];
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
called by SW and hbond potentials, newton_pair is always on
virial = riFi + rjFj + rkFk = (rj-ri) Fj + (rk-ri) Fk = drji*fj + drki*fk
------------------------------------------------------------------------- */
void Pair::ev_tally3(int i, int j, int k, double evdwl, double ecoul,
double *fj, double *fk, double *drji, double *drki)
{
double epairthird,v[6];
if (eflag_either) {
if (eflag_global) {
eng_vdwl += evdwl;
eng_coul += ecoul;
}
if (eflag_atom) {
epairthird = THIRD * (evdwl + ecoul);
eatom[i] += epairthird;
eatom[j] += epairthird;
eatom[k] += epairthird;
}
}
if (vflag_either) {
v[0] = drji[0]*fj[0] + drki[0]*fk[0];
v[1] = drji[1]*fj[1] + drki[1]*fk[1];
v[2] = drji[2]*fj[2] + drki[2]*fk[2];
v[3] = drji[0]*fj[1] + drki[0]*fk[1];
v[4] = drji[0]*fj[2] + drki[0]*fk[2];
v[5] = drji[1]*fj[2] + drki[1]*fk[2];
if (vflag_global) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
}
if (vflag_atom) {
vatom[i][0] += THIRD*v[0]; vatom[i][1] += THIRD*v[1];
vatom[i][2] += THIRD*v[2]; vatom[i][3] += THIRD*v[3];
vatom[i][4] += THIRD*v[4]; vatom[i][5] += THIRD*v[5];
vatom[j][0] += THIRD*v[0]; vatom[j][1] += THIRD*v[1];
vatom[j][2] += THIRD*v[2]; vatom[j][3] += THIRD*v[3];
vatom[j][4] += THIRD*v[4]; vatom[j][5] += THIRD*v[5];
vatom[k][0] += THIRD*v[0]; vatom[k][1] += THIRD*v[1];
vatom[k][2] += THIRD*v[2]; vatom[k][3] += THIRD*v[3];
vatom[k][4] += THIRD*v[4]; vatom[k][5] += THIRD*v[5];
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
called by AIREBO potential, newton_pair is always on
------------------------------------------------------------------------- */
void Pair::ev_tally4(int i, int j, int k, int m, double evdwl,
double *fi, double *fj, double *fk,
double *drim, double *drjm, double *drkm)
{
double epairfourth,v[6];
if (eflag_either) {
if (eflag_global) eng_vdwl += evdwl;
if (eflag_atom) {
epairfourth = 0.25 * evdwl;
eatom[i] += epairfourth;
eatom[j] += epairfourth;
eatom[k] += epairfourth;
eatom[m] += epairfourth;
}
}
if (vflag_atom) {
v[0] = 0.25 * (drim[0]*fi[0] + drjm[0]*fj[0] + drkm[0]*fk[0]);
v[1] = 0.25 * (drim[1]*fi[1] + drjm[1]*fj[1] + drkm[1]*fk[1]);
v[2] = 0.25 * (drim[2]*fi[2] + drjm[2]*fj[2] + drkm[2]*fk[2]);
v[3] = 0.25 * (drim[0]*fi[1] + drjm[0]*fj[1] + drkm[0]*fk[1]);
v[4] = 0.25 * (drim[0]*fi[2] + drjm[0]*fj[2] + drkm[0]*fk[2]);
v[5] = 0.25 * (drim[1]*fi[2] + drjm[1]*fj[2] + drkm[1]*fk[2]);
vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
vatom[m][0] += v[0]; vatom[m][1] += v[1]; vatom[m][2] += v[2];
vatom[m][3] += v[3]; vatom[m][4] += v[4]; vatom[m][5] += v[5];
}
}
/* ----------------------------------------------------------------------
tally ecoul and virial into each of atoms in list
called by TIP4P potential, newton_pair is always on
weight assignments by alpha, so contribution is all to O atom as alpha -> 0.0
key = 0 if neither atom = water O
key = 1 if first atom = water O
key = 2 if second atom = water O
key = 3 if both atoms = water O
------------------------------------------------------------------------- */
void Pair::ev_tally_tip4p(int key, int *list, double *v,
double ecoul, double alpha)
{
int i;
if (eflag_either) {
if (eflag_global) eng_coul += ecoul;
if (eflag_atom) {
if (key == 0) {
eatom[list[0]] += 0.5*ecoul;
eatom[list[1]] += 0.5*ecoul;
} else if (key == 1) {
eatom[list[0]] += 0.5*ecoul*(1-alpha);
eatom[list[1]] += 0.25*ecoul*alpha;
eatom[list[2]] += 0.25*ecoul*alpha;
eatom[list[3]] += 0.5*ecoul;
} else if (key == 2) {
eatom[list[0]] += 0.5*ecoul;
eatom[list[1]] += 0.5*ecoul*(1-alpha);
eatom[list[2]] += 0.25*ecoul*alpha;
eatom[list[3]] += 0.25*ecoul*alpha;
} else {
eatom[list[0]] += 0.5*ecoul*(1-alpha);
eatom[list[1]] += 0.25*ecoul*alpha;
eatom[list[2]] += 0.25*ecoul*alpha;
eatom[list[3]] += 0.5*ecoul*(1-alpha);
eatom[list[4]] += 0.25*ecoul*alpha;
eatom[list[5]] += 0.25*ecoul*alpha;
}
}
}
if (vflag_either) {
if (vflag_global) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
}
if (vflag_atom) {
if (key == 0) {
for (i = 0; i <= 5; i++) {
vatom[list[0]][i] += 0.5*v[i];
vatom[list[1]][i] += 0.5*v[i];
}
} else if (key == 1) {
for (i = 0; i <= 5; i++) {
vatom[list[0]][i] += 0.5*v[i]*(1-alpha);
vatom[list[1]][i] += 0.25*v[i]*alpha;
vatom[list[2]][i] += 0.25*v[i]*alpha;
vatom[list[3]][i] += 0.5*v[i];
}
} else if (key == 2) {
for (i = 0; i <= 5; i++) {
vatom[list[0]][i] += 0.5*v[i];
vatom[list[1]][i] += 0.5*v[i]*(1-alpha);
vatom[list[2]][i] += 0.25*v[i]*alpha;
vatom[list[3]][i] += 0.25*v[i]*alpha;
}
} else {
for (i = 0; i <= 5; i++) {
vatom[list[0]][i] += 0.5*v[i]*(1-alpha);
vatom[list[1]][i] += 0.25*v[i]*alpha;
vatom[list[2]][i] += 0.25*v[i]*alpha;
vatom[list[3]][i] += 0.5*v[i]*(1-alpha);
vatom[list[4]][i] += 0.25*v[i]*alpha;
vatom[list[5]][i] += 0.25*v[i]*alpha;
}
}
}
}
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by REAX/C potential, newton_pair is always on
fi is magnitude of force on atom i
------------------------------------------------------------------------- */
void Pair::v_tally(int i, double *fi, double *deli)
{
double v[6];
v[0] = 0.5*deli[0]*fi[0];
v[1] = 0.5*deli[1]*fi[1];
v[2] = 0.5*deli[2]*fi[2];
v[3] = 0.5*deli[0]*fi[1];
v[4] = 0.5*deli[0]*fi[2];
v[5] = 0.5*deli[1]*fi[2];
vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO potential, newton_pair is always on
fpair is magnitude of force on atom I
------------------------------------------------------------------------- */
void Pair::v_tally2(int i, int j, double fpair, double *drij)
{
double v[6];
v[0] = 0.5 * drij[0]*drij[0]*fpair;
v[1] = 0.5 * drij[1]*drij[1]*fpair;
v[2] = 0.5 * drij[2]*drij[2]*fpair;
v[3] = 0.5 * drij[0]*drij[1]*fpair;
v[4] = 0.5 * drij[0]*drij[2]*fpair;
v[5] = 0.5 * drij[1]*drij[2]*fpair;
vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO and Tersoff potential, newton_pair is always on
------------------------------------------------------------------------- */
void Pair::v_tally3(int i, int j, int k,
double *fi, double *fj, double *drik, double *drjk)
{
double v[6];
v[0] = THIRD * (drik[0]*fi[0] + drjk[0]*fj[0]);
v[1] = THIRD * (drik[1]*fi[1] + drjk[1]*fj[1]);
v[2] = THIRD * (drik[2]*fi[2] + drjk[2]*fj[2]);
v[3] = THIRD * (drik[0]*fi[1] + drjk[0]*fj[1]);
v[4] = THIRD * (drik[0]*fi[2] + drjk[0]*fj[2]);
v[5] = THIRD * (drik[1]*fi[2] + drjk[1]*fj[2]);
vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO potential, newton_pair is always on
------------------------------------------------------------------------- */
void Pair::v_tally4(int i, int j, int k, int m,
double *fi, double *fj, double *fk,
double *drim, double *drjm, double *drkm)
{
double v[6];
v[0] = 0.25 * (drim[0]*fi[0] + drjm[0]*fj[0] + drkm[0]*fk[0]);
v[1] = 0.25 * (drim[1]*fi[1] + drjm[1]*fj[1] + drkm[1]*fk[1]);
v[2] = 0.25 * (drim[2]*fi[2] + drjm[2]*fj[2] + drkm[2]*fk[2]);
v[3] = 0.25 * (drim[0]*fi[1] + drjm[0]*fj[1] + drkm[0]*fk[1]);
v[4] = 0.25 * (drim[0]*fi[2] + drjm[0]*fj[2] + drkm[0]*fk[2]);
v[5] = 0.25 * (drim[1]*fi[2] + drjm[1]*fj[2] + drkm[1]*fk[2]);
vatom[i][0] += v[0]; vatom[i][1] += v[1]; vatom[i][2] += v[2];
vatom[i][3] += v[3]; vatom[i][4] += v[4]; vatom[i][5] += v[5];
vatom[j][0] += v[0]; vatom[j][1] += v[1]; vatom[j][2] += v[2];
vatom[j][3] += v[3]; vatom[j][4] += v[4]; vatom[j][5] += v[5];
vatom[k][0] += v[0]; vatom[k][1] += v[1]; vatom[k][2] += v[2];
vatom[k][3] += v[3]; vatom[k][4] += v[4]; vatom[k][5] += v[5];
vatom[m][0] += v[0]; vatom[m][1] += v[1]; vatom[m][2] += v[2];
vatom[m][3] += v[3]; vatom[m][4] += v[4]; vatom[m][5] += v[5];
}
/* ----------------------------------------------------------------------
tally virial into global and per-atom accumulators
called by pair lubricate potential with 6 tensor components
------------------------------------------------------------------------- */
void Pair::v_tally_tensor(int i, int j, int nlocal, int newton_pair,
double vxx, double vyy, double vzz,
double vxy, double vxz, double vyz)
{
double v[6];
v[0] = vxx;
v[1] = vyy;
v[2] = vzz;
v[3] = vxy;
v[4] = vxz;
v[5] = vyz;
if (vflag_global) {
if (newton_pair) {
virial[0] += v[0];
virial[1] += v[1];
virial[2] += v[2];
virial[3] += v[3];
virial[4] += v[4];
virial[5] += v[5];
} else {
if (i < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
if (j < nlocal) {
virial[0] += 0.5*v[0];
virial[1] += 0.5*v[1];
virial[2] += 0.5*v[2];
virial[3] += 0.5*v[3];
virial[4] += 0.5*v[4];
virial[5] += 0.5*v[5];
}
}
}
if (vflag_atom) {
if (newton_pair || i < nlocal) {
vatom[i][0] += 0.5*v[0];
vatom[i][1] += 0.5*v[1];
vatom[i][2] += 0.5*v[2];
vatom[i][3] += 0.5*v[3];
vatom[i][4] += 0.5*v[4];
vatom[i][5] += 0.5*v[5];
}
if (newton_pair || j < nlocal) {
vatom[j][0] += 0.5*v[0];
vatom[j][1] += 0.5*v[1];
vatom[j][2] += 0.5*v[2];
vatom[j][3] += 0.5*v[3];
vatom[j][4] += 0.5*v[4];
vatom[j][5] += 0.5*v[5];
}
}
}
/* ----------------------------------------------------------------------
compute global pair virial via summing F dot r over own & ghost atoms
at this point, only pairwise forces have been accumulated in atom->f
------------------------------------------------------------------------- */
void Pair::virial_fdotr_compute()
{
double **x = atom->x;
double **f = atom->f;
// sum over force on all particles including ghosts
if (neighbor->includegroup == 0) {
int nall = atom->nlocal + atom->nghost;
for (int i = 0; i < nall; i++) {
virial[0] += f[i][0]*x[i][0];
virial[1] += f[i][1]*x[i][1];
virial[2] += f[i][2]*x[i][2];
virial[3] += f[i][1]*x[i][0];
virial[4] += f[i][2]*x[i][0];
virial[5] += f[i][2]*x[i][1];
}
// neighbor includegroup flag is set
// sum over force on initial nfirst particles and ghosts
} else {
int nall = atom->nfirst;
for (int i = 0; i < nall; i++) {
virial[0] += f[i][0]*x[i][0];
virial[1] += f[i][1]*x[i][1];
virial[2] += f[i][2]*x[i][2];
virial[3] += f[i][1]*x[i][0];
virial[4] += f[i][2]*x[i][0];
virial[5] += f[i][2]*x[i][1];
}
nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; i++) {
virial[0] += f[i][0]*x[i][0];
virial[1] += f[i][1]*x[i][1];
virial[2] += f[i][2]*x[i][2];
virial[3] += f[i][1]*x[i][0];
virial[4] += f[i][2]*x[i][0];
virial[5] += f[i][2]*x[i][1];
}
}
// prevent multiple calls to update the virial
// when a hybrid pair style uses both a gpu and non-gpu pair style
// or when respa is used with gpu pair styles
vflag_fdotr = 0;
}
/* ----------------------------------------------------------------------
write a table of pair potential energy/force vs distance to a file
------------------------------------------------------------------------- */
void Pair::write_file(int narg, char **arg)
{
if (narg != 8 && narg != 10) error->all(FLERR,"Illegal pair_write command");
if (single_enable == 0)
error->all(FLERR,"Pair style does not support pair_write");
// parse arguments
int itype = force->inumeric(FLERR,arg[0]);
int jtype = force->inumeric(FLERR,arg[1]);
if (itype < 1 || itype > atom->ntypes || jtype < 1 || jtype > atom->ntypes)
error->all(FLERR,"Invalid atom types in pair_write command");
int n = force->inumeric(FLERR,arg[2]);
int style = NONE;
if (strcmp(arg[3],"r") == 0) style = RLINEAR;
else if (strcmp(arg[3],"rsq") == 0) style = RSQ;
else if (strcmp(arg[3],"bitmap") == 0) style = BMP;
else error->all(FLERR,"Invalid style in pair_write command");
double inner = force->numeric(FLERR,arg[4]);
double outer = force->numeric(FLERR,arg[5]);
if (inner <= 0.0 || inner >= outer)
error->all(FLERR,"Invalid cutoffs in pair_write command");
// open file in append mode
// print header in format used by pair_style table
int me;
MPI_Comm_rank(world,&me);
FILE *fp;
if (me == 0) {
fp = fopen(arg[6],"a");
if (fp == NULL) error->one(FLERR,"Cannot open pair_write file");
fprintf(fp,"# Pair potential %s for atom types %d %d: i,r,energy,force\n",
force->pair_style,itype,jtype);
if (style == RLINEAR)
fprintf(fp,"\n%s\nN %d R %.15g %.15g\n\n",arg[7],n,inner,outer);
if (style == RSQ)
fprintf(fp,"\n%s\nN %d RSQ %.15g %.15g\n\n",arg[7],n,inner,outer);
}
// initialize potentials before evaluating pair potential
// insures all pair coeffs are set and force constants
// also initialize neighbor so that neighbor requests are processed
// NOTE: might be safest to just do lmp->init()
force->init();
neighbor->init();
// if pair style = any of EAM, swap in dummy fp vector
double eamfp[2];
eamfp[0] = eamfp[1] = 0.0;
double *eamfp_hold;
Pair *epair = force->pair_match("eam",0);
if (epair) epair->swap_eam(eamfp,&eamfp_hold);
// if atom style defines charge, swap in dummy q vec
double q[2];
q[0] = q[1] = 1.0;
if (narg == 10) {
q[0] = force->numeric(FLERR,arg[8]);
q[1] = force->numeric(FLERR,arg[9]);
}
double *q_hold;
if (atom->q) {
q_hold = atom->q;
atom->q = q;
}
// evaluate energy and force at each of N distances
int masklo,maskhi,nmask,nshiftbits;
if (style == BMP) {
init_bitmap(inner,outer,n,masklo,maskhi,nmask,nshiftbits);
int ntable = 1 << n;
if (me == 0)
fprintf(fp,"\n%s\nN %d BITMAP %.15g %.15g\n\n",arg[7],ntable,inner,outer);
n = ntable;
}
double r,e,f,rsq;
union_int_float_t rsq_lookup;
for (int i = 0; i < n; i++) {
if (style == RLINEAR) {
r = inner + (outer-inner) * i/(n-1);
rsq = r*r;
} else if (style == RSQ) {
rsq = inner*inner + (outer*outer - inner*inner) * i/(n-1);
r = sqrt(rsq);
} else if (style == BMP) {
rsq_lookup.i = i << nshiftbits;
rsq_lookup.i |= masklo;
if (rsq_lookup.f < inner*inner) {
rsq_lookup.i = i << nshiftbits;
rsq_lookup.i |= maskhi;
}
rsq = rsq_lookup.f;
r = sqrt(rsq);
}
if (rsq < cutsq[itype][jtype]) {
e = single(0,1,itype,jtype,rsq,1.0,1.0,f);
f *= r;
} else e = f = 0.0;
if (me == 0) fprintf(fp,"%d %.15g %.15g %.15g\n",i+1,r,e,f);
}
// restore original vecs that were swapped in for
double *tmp;
if (epair) epair->swap_eam(eamfp_hold,&tmp);
if (atom->q) atom->q = q_hold;
if (me == 0) fclose(fp);
}
/* ----------------------------------------------------------------------
define bitmap parameters based on inner and outer cutoffs
------------------------------------------------------------------------- */
void Pair::init_bitmap(double inner, double outer, int ntablebits,
int &masklo, int &maskhi, int &nmask, int &nshiftbits)
{
if (sizeof(int) != sizeof(float))
error->all(FLERR,"Bitmapped lookup tables require int/float be same size");
if (ntablebits > sizeof(float)*CHAR_BIT)
error->all(FLERR,"Too many total bits for bitmapped lookup table");
if (inner >= outer)
error->warning(FLERR,"Table inner cutoff >= outer cutoff");
int nlowermin = 1;
while (!((pow(double(2),(double)nlowermin) <= inner*inner) &&
(pow(double(2),(double)nlowermin+1.0) > inner*inner))) {
if (pow(double(2),(double)nlowermin) <= inner*inner) nlowermin++;
else nlowermin--;
}
int nexpbits = 0;
double required_range = outer*outer / pow(double(2),(double)nlowermin);
double available_range = 2.0;
while (available_range < required_range) {
nexpbits++;
available_range = pow(double(2),pow(double(2),(double)nexpbits));
}
int nmantbits = ntablebits - nexpbits;
if (nexpbits > sizeof(float)*CHAR_BIT - FLT_MANT_DIG)
error->all(FLERR,"Too many exponent bits for lookup table");
if (nmantbits+1 > FLT_MANT_DIG)
error->all(FLERR,"Too many mantissa bits for lookup table");
if (nmantbits < 3) error->all(FLERR,"Too few bits for lookup table");
nshiftbits = FLT_MANT_DIG - (nmantbits+1);
nmask = 1;
for (int j = 0; j < ntablebits+nshiftbits; j++) nmask *= 2;
nmask -= 1;
union_int_float_t rsq_lookup;
rsq_lookup.f = outer*outer;
maskhi = rsq_lookup.i & ~(nmask);
rsq_lookup.f = inner*inner;
masklo = rsq_lookup.i & ~(nmask);
}
/* ---------------------------------------------------------------------- */
double Pair::memory_usage()
{
double bytes = comm->nthreads*maxeatom * sizeof(double);
bytes += comm->nthreads*maxvatom*6 * sizeof(double);
return bytes;
}
diff --git a/src/pair_born.cpp b/src/pair_born.cpp
index 6d420fb36..979499488 100644
--- a/src/pair_born.cpp
+++ b/src/pair_born.cpp
@@ -1,438 +1,438 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing Author: Sai Jayaraman (Sandia)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_born.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBorn::PairBorn(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairBorn::~PairBorn()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(sigma);
memory->destroy(c);
memory->destroy(d);
memory->destroy(rhoinv);
memory->destroy(born1);
memory->destroy(born2);
memory->destroy(born3);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBorn::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forceborn,factor_lj;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
fpair = factor_lj*forceborn*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv
+ d[itype][jtype]*r6inv*r2inv - offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBorn::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(c,n+1,n+1,"pair:c");
memory->create(d,n+1,n+1,"pair:d");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(born1,n+1,n+1,"pair:born1");
memory->create(born2,n+1,n+1,"pair:born2");
memory->create(born3,n+1,n+1,"pair:born3");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBorn::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBorn::coeff(int narg, char **arg)
{
if (narg < 7 || narg > 8) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[5]);
double d_one = force->numeric(FLERR,arg[6]);
double cut_one = cut_global;
if (narg == 8) cut_one = force->numeric(FLERR,arg[7]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
sigma[i][j] = sigma_one;
c[i][j] = c_one;
d[i][j] = d_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBorn::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
rhoinv[i][j] = 1.0/rho[i][j];
born1[i][j] = a[i][j]/rho[i][j];
born2[i][j] = 6.0*c[i][j];
born3[i][j] = 8.0*d[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double rexp = exp((sigma[i][j]-cut[i][j])*rhoinv[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0) +
d[i][j]/pow(cut[i][j],8.0);
} else offset[i][j] = 0.0;
a[j][i] = a[i][j];
c[j][i] = c[i][j];
d[j][i] = d[i][j];
rhoinv[j][i] = rhoinv[i][j];
sigma[j][i] = sigma[i][j];
born1[j][i] = born1[i][j];
born2[j][i] = born2[i][j];
born3[j][i] = born3[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
double rc5 = rc3*rc2;
etail_ij = 2.0*MY_PI*all[0]*all[1] *
(a[i][j]*exp((sigma[i][j]-rc)/rho1)*rho1*
(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3) + d[i][j]/(5.0*rc5));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1] *
(-a[i][j]*exp((sigma[i][j]-rc)/rho1) *
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) +
2.0*c[i][j]/rc3 - 8.0*d[i][j]/(5.0*rc5));
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBorn::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&d[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBorn::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&d[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBorn::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBorn::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBorn::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,
a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBorn::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j,
a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairBorn::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,forceborn,phiborn;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv +
born3[itype][jtype]*r2inv*r6inv;
fforce = factor_lj*forceborn*r2inv;
phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv +
d[itype][jtype]*r2inv*r6inv - offset[itype][jtype];
return factor_lj*phiborn;
}
/* ---------------------------------------------------------------------- */
void *PairBorn::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"a") == 0) return (void *) a;
if (strcmp(str,"c") == 0) return (void *) c;
if (strcmp(str,"d") == 0) return (void *) d;
return NULL;
}
diff --git a/src/pair_born_coul_dsf.cpp b/src/pair_born_coul_dsf.cpp
index caec95759..d53e9cf00 100644
--- a/src/pair_born_coul_dsf.cpp
+++ b/src/pair_born_coul_dsf.cpp
@@ -1,494 +1,494 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Ariel Lozano (arielzn@gmail.com)
References: Fennell and Gezelter, JCP 124, 234104 (2006)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_born_coul_dsf.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include "math_special.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBornCoulDSF::PairBornCoulDSF(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
single_enable = 0;
}
/* ---------------------------------------------------------------------- */
PairBornCoulDSF::~PairBornCoulDSF()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(sigma);
memory->destroy(c);
memory->destroy(d);
memory->destroy(rhoinv);
memory->destroy(born1);
memory->destroy(born2);
memory->destroy(born3);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBornCoulDSF::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,r2inv,r6inv,forcecoul,forceborn,factor_coul,factor_lj;
double prefactor,erfcc,erfcd,arg;
double rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
double *special_coul = force->special_coul;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
// self coulombic energy
if (eflag) {
double e_self = -(e_shift/2.0 + alpha/MY_PIS) * qtmp*qtmp*qqrd2e;
ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0);
}
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = qqrd2e*qtmp*q[j]/r;
arg = alpha * r ;
erfcd = MathSpecial::expmsq(arg);
erfcc = MathSpecial::my_erfcx(arg) * erfcd;
forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd +
r*f_shift) * r;
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fpair = (forcecoul + factor_lj*forceborn) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
ecoul = prefactor * (erfcc - r*e_shift - rsq*f_shift);
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv +
d[itype][jtype]*r6inv*r2inv - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBornCoulDSF::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(c,n+1,n+1,"pair:c");
memory->create(d,n+1,n+1,"pair:d");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(born1,n+1,n+1,"pair:born1");
memory->create(born2,n+1,n+1,"pair:born2");
memory->create(born3,n+1,n+1,"pair:born3");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBornCoulDSF::settings(int narg, char **arg)
{
if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command");
alpha = force->numeric(FLERR,arg[0]);
cut_lj_global = force->numeric(FLERR,arg[1]);
if (narg == 2) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[2]);
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBornCoulDSF::coeff(int narg, char **arg)
{
if (narg < 7 || narg > 8)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[5]);
double d_one = force->numeric(FLERR,arg[6]);
double cut_lj_one = cut_lj_global;
if (narg == 8) cut_lj_one = force->numeric(FLERR,arg[7]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
sigma[i][j] = sigma_one;
c[i][j] = c_one;
d[i][j] = d_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBornCoulDSF::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style born/coul/dsf requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
double erfcc = erfc(alpha*cut_coul);
double erfcd = exp(-alpha*alpha*cut_coul*cut_coul);
f_shift = -(erfcc/cut_coulsq + 2.0/MY_PIS*alpha*erfcd/cut_coul);
e_shift = erfcc/cut_coul - f_shift*cut_coul;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBornCoulDSF::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
rhoinv[i][j] = 1.0/rho[i][j];
born1[i][j] = a[i][j]/rho[i][j];
born2[i][j] = 6.0*c[i][j];
born3[i][j] = 8.0*d[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0)
+ d[i][j]/pow(cut_lj[i][j],8.0);
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
d[j][i] = d[i][j];
rhoinv[j][i] = rhoinv[i][j];
sigma[j][i] = sigma[i][j];
born1[j][i] = born1[i][j];
born2[j][i] = born2[i][j];
born3[j][i] = born3[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulDSF::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&d[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulDSF::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&d[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulDSF::write_restart_settings(FILE *fp)
{
fwrite(&alpha,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulDSF::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&alpha,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBornCoulDSF::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,
a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBornCoulDSF::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j,
a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut_lj[i][j]);
}
/* ----------------------------------------------------------------------
only the pair part is calculated here
------------------------------------------------------------------------- */
double PairBornCoulDSF::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,prefactor,rexp;
double forcecoul,forceborn,phicoul,phiborn;
double erfcc,erfcd,arg;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = factor_coul * force->qqrd2e * atom->q[i]*atom->q[j]/r;
arg = alpha * r ;
erfcd = MathSpecial::expmsq(arg);
erfcc = MathSpecial::my_erfcx(arg) * erfcd;
forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS*erfcd +
r*f_shift) * r;
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fforce = (forcecoul + factor_lj*forceborn) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
phicoul = prefactor * (erfcc - r*e_shift - rsq*f_shift);
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv
+ d[itype][jtype]*r2inv*r6inv - offset[itype][jtype];
eng += factor_lj*phiborn;
}
return eng;
}
diff --git a/src/pair_born_coul_wolf.cpp b/src/pair_born_coul_wolf.cpp
index bad0c5ed3..fbec4f3da 100644
--- a/src/pair_born_coul_wolf.cpp
+++ b/src/pair_born_coul_wolf.cpp
@@ -1,492 +1,492 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Yongfeng Zhang (INL), yongfeng.zhang@inl.gov
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_born_coul_wolf.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBornCoulWolf::PairBornCoulWolf(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
single_enable = 0;
}
/* ---------------------------------------------------------------------- */
PairBornCoulWolf::~PairBornCoulWolf()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(sigma);
memory->destroy(c);
memory->destroy(d);
memory->destroy(rhoinv);
memory->destroy(born1);
memory->destroy(born2);
memory->destroy(born3);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBornCoulWolf::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,r2inv,r6inv,forcecoul,forceborn,factor_coul,factor_lj;
double prefactor;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
double erfcc,erfcd,v_sh,dvdrr,e_self,e_shift,f_shift,qisq;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
// self and shifted coulombic energy
e_self = v_sh = 0.0;
e_shift = erfc(alf*cut_coul)/cut_coul;
f_shift = -(e_shift+ 2.0*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) /
cut_coul;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
qisq = qtmp*qtmp;
e_self = -(e_shift/2.0 + alf/MY_PIS) * qisq*qqrd2e;
if (eflag) ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0);
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = qqrd2e*qtmp*q[j]/r;
erfcc = erfc(alf*r);
erfcd = exp(-alf*alf*r*r);
v_sh = (erfcc - e_shift*r) * prefactor;
dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift;
forcecoul = dvdrr*rsq*prefactor;
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp((sigma[itype][jtype]-r)*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fpair = (forcecoul + factor_lj*forceborn) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq) {
ecoul = v_sh;
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv +
d[itype][jtype]*r6inv*r2inv - offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBornCoulWolf::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(c,n+1,n+1,"pair:c");
memory->create(d,n+1,n+1,"pair:d");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(born1,n+1,n+1,"pair:born1");
memory->create(born2,n+1,n+1,"pair:born2");
memory->create(born3,n+1,n+1,"pair:born3");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBornCoulWolf::settings(int narg, char **arg)
{
if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command");
alf = force->numeric(FLERR,arg[0]);
cut_lj_global = force->numeric(FLERR,arg[1]);
if (narg == 2) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[2]);
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBornCoulWolf::coeff(int narg, char **arg)
{
if (narg < 7 || narg > 8)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[5]);
double d_one = force->numeric(FLERR,arg[6]);
double cut_lj_one = cut_lj_global;
if (narg == 8) cut_lj_one = force->numeric(FLERR,arg[7]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
sigma[i][j] = sigma_one;
c[i][j] = c_one;
d[i][j] = d_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBornCoulWolf::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style born/coul/wolf requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBornCoulWolf::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
rhoinv[i][j] = 1.0/rho[i][j];
born1[i][j] = a[i][j]/rho[i][j];
born2[i][j] = 6.0*c[i][j];
born3[i][j] = 8.0*d[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0)
+ d[i][j]/pow(cut_lj[i][j],8.0);
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
d[j][i] = d[i][j];
rhoinv[j][i] = rhoinv[i][j];
sigma[j][i] = sigma[i][j];
born1[j][i] = born1[i][j];
born2[j][i] = born2[i][j];
born3[j][i] = born3[i][j];
offset[j][i] = offset[i][j];
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulWolf::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&d[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulWolf::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&d[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&d[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBornCoulWolf::write_restart_settings(FILE *fp)
{
fwrite(&alf,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBornCoulWolf::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&alf,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&alf,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBornCoulWolf::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,
a[i][i],rho[i][i],sigma[i][i],c[i][i],d[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBornCoulWolf::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g %g\n",i,j,
a[i][j],rho[i][j],sigma[i][j],c[i][j],d[i][j],cut_lj[i][j]);
}
/* ----------------------------------------------------------------------
only the pair part is calculated here
------------------------------------------------------------------------- */
double PairBornCoulWolf::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,prefactor,rexp;
double forcecoul,forceborn,phicoul,phiborn;
double e_shift,f_shift,dvdrr,erfcc,erfcd;
r2inv = 1.0/rsq;
e_shift = erfc(alf*cut_coul) / cut_coul;
f_shift = -(e_shift+2*alf/MY_PIS * exp(-alf*alf*cut_coul*cut_coul)) /
cut_coul;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = force->qqrd2e * atom->q[i]*atom->q[j]/r;
erfcc = erfc(alf*r);
erfcd = exp(-alf*alf*r*r);
dvdrr = (erfcc/rsq + 2.0*alf/MY_PIS * erfcd/r) + f_shift;
forcecoul = dvdrr*rsq*prefactor;
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forceborn = born1[itype][jtype]*r*rexp - born2[itype][jtype]*r6inv
+ born3[itype][jtype]*r2inv*r6inv;
} else forceborn = 0.0;
fforce = (forcecoul + factor_lj*forceborn) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq) {
phicoul = prefactor * (erfcc-e_shift*r);
if (factor_coul < 1.0) phicoul -= (1.0-factor_coul)*prefactor;
eng += phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phiborn = a[itype][jtype]*rexp - c[itype][jtype]*r6inv
+ d[itype][jtype]*r2inv*r6inv - offset[itype][jtype];
eng += factor_lj*phiborn;
}
return eng;
}
diff --git a/src/pair_buck.cpp b/src/pair_buck.cpp
index e4da772e0..ac7ac0aeb 100644
--- a/src/pair_buck.cpp
+++ b/src/pair_buck.cpp
@@ -1,409 +1,409 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_buck.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBuck::PairBuck(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairBuck::~PairBuck()
{
if (copymode) return;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(c);
memory->destroy(rhoinv);
memory->destroy(buck1);
memory->destroy(buck2);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBuck::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forcebuck,factor_lj;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
fpair = factor_lj*forcebuck*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBuck::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut_lj");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(c,n+1,n+1,"pair:c");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(buck1,n+1,n+1,"pair:buck1");
memory->create(buck2,n+1,n+1,"pair:buck2");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBuck::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBuck::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[4]);
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
c[i][j] = c_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBuck::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
rhoinv[i][j] = 1.0/rho[i][j];
buck1[i][j] = a[i][j]/rho[i][j];
buck2[i][j] = 6.0*c[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double rexp = exp(-cut[i][j]/rho[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0);
} else offset[i][j] = 0.0;
a[j][i] = a[i][j];
c[j][i] = c[i][j];
rhoinv[j][i] = rhoinv[i][j];
buck1[j][i] = buck1[i][j];
buck2[j][i] = buck2[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
etail_ij = 2.0*MY_PI*all[0]*all[1]*
(a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]*
(-a[i][j]*exp(-rc/rho1)*
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuck::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuck::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuck::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuck::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBuck::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBuck::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,
a[i][j],rho[i][j],c[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairBuck::single(int i, int j, int itype, int jtype,
double rsq, double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,forcebuck,phibuck;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
fforce = factor_lj*forcebuck*r2inv;
phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
return factor_lj*phibuck;
}
/* ---------------------------------------------------------------------- */
void *PairBuck::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"a") == 0) return (void *) a;
if (strcmp(str,"c") == 0) return (void *) c;
return NULL;
}
diff --git a/src/pair_buck_coul_cut.cpp b/src/pair_buck_coul_cut.cpp
index c052c3100..2764a8e4e 100644
--- a/src/pair_buck_coul_cut.cpp
+++ b/src/pair_buck_coul_cut.cpp
@@ -1,472 +1,472 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Eduardo Bringa (LLNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "pair_buck_coul_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairBuckCoulCut::PairBuckCoulCut(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairBuckCoulCut::~PairBuckCoulCut()
{
if (!copymode) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(a);
memory->destroy(rho);
memory->destroy(c);
memory->destroy(rhoinv);
memory->destroy(buck1);
memory->destroy(buck2);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairBuckCoulCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,r2inv,r6inv,forcecoul,forcebuck,factor_coul,factor_lj;
double r,rexp;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r = sqrt(rsq);
if (rsq < cut_coulsq[itype][jtype])
forcecoul = qqrd2e * qtmp*q[j]/r;
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
} else forcebuck = 0.0;
fpair = (factor_coul*forcecoul + factor_lj*forcebuck) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype])
ecoul = factor_coul * qqrd2e * qtmp*q[j]/r;
else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBuckCoulCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(a,n+1,n+1,"pair:a");
memory->create(rho,n+1,n+1,"pair:rho");
memory->create(c,n+1,n+1,"pair:c");
memory->create(rhoinv,n+1,n+1,"pair:rhoinv");
memory->create(buck1,n+1,n+1,"pair:buck1");
memory->create(buck2,n+1,n+1,"pair:buck2");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBuckCoulCut::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairBuckCoulCut::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double rho_one = force->numeric(FLERR,arg[3]);
if (rho_one <= 0) error->all(FLERR,"Incorrect args for pair coefficients");
double c_one = force->numeric(FLERR,arg[4]);
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 6) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[5]);
if (narg == 7) cut_coul_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
rho[i][j] = rho_one;
c[i][j] = c_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairBuckCoulCut::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style buck/coul/cut requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairBuckCoulCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
rhoinv[i][j] = 1.0/rho[i][j];
buck1[i][j] = a[i][j]/rho[i][j];
buck2[i][j] = 6.0*c[i][j];
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double rexp = exp(-cut_lj[i][j]/rho[i][j]);
offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0);
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
a[j][i] = a[i][j];
c[j][i] = c[i][j];
rhoinv[j][i] = rhoinv[i][j];
buck1[j][i] = buck1[i][j];
buck2[j][i] = buck2[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double rho1 = rho[i][j];
double rho2 = rho1*rho1;
double rho3 = rho2*rho1;
double rc = cut_lj[i][j];
double rc2 = rc*rc;
double rc3 = rc2*rc;
etail_ij = 2.0*MY_PI*all[0]*all[1]*
(a[i][j]*exp(-rc/rho1)*rho1*(rc2 + 2.0*rho1*rc + 2.0*rho2) -
c[i][j]/(3.0*rc3));
ptail_ij = (-1/3.0)*2.0*MY_PI*all[0]*all[1]*
(-a[i][j]*exp(-rc/rho1)*
(rc3 + 3.0*rho1*rc2 + 6.0*rho2*rc + 6.0*rho3) + 2.0*c[i][j]/rc3);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckCoulCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&rho[i][j],sizeof(double),1,fp);
fwrite(&c[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckCoulCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&rho[i][j],sizeof(double),1,fp);
fread(&c[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&rho[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&c[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairBuckCoulCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairBuckCoulCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairBuckCoulCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,a[i][i],rho[i][i],c[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairBuckCoulCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g %g\n",i,j,
a[i][j],rho[i][j],c[i][j],cut_lj[i][j],cut_coul[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairBuckCoulCut::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,rexp,forcecoul,forcebuck,phicoul,phibuck;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
r = sqrt(rsq);
rexp = exp(-r*rhoinv[itype][jtype]);
forcebuck = buck1[itype][jtype]*r*rexp - buck2[itype][jtype]*r6inv;
} else forcebuck = 0.0;
fforce = (factor_coul*forcecoul + factor_lj*forcebuck) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
eng += factor_coul*phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
phibuck = a[itype][jtype]*rexp - c[itype][jtype]*r6inv -
offset[itype][jtype];
eng += factor_lj*phibuck;
}
return eng;
}
diff --git a/src/pair_lj96_cut.cpp b/src/pair_lj96_cut.cpp
index f4b2747d4..83fc5bcdd 100644
--- a/src/pair_lj96_cut.cpp
+++ b/src/pair_lj96_cut.cpp
@@ -1,722 +1,722 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Chuanfu Luo (luochuanfu@gmail.com)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj96_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJ96Cut::PairLJ96Cut(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 1;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJ96Cut::~PairLJ96Cut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJ96Cut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJ96Cut::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
jtype = type[j];
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJ96Cut::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
jtype = type[j];
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJ96Cut::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r3inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
if (eflag) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
evdwl = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (vflag) {
if (rsq <= cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
} else if (rsq < cut_in_on_sq)
fpair = factor_lj*forcelj*r2inv;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJ96Cut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJ96Cut::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJ96Cut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_one = cut_global;
if (narg == 5) cut_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJ96Cut::init_style()
{
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJ96Cut::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJ96Cut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
lj1[i][j] = 36.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],9.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,9.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && cut[i][j] < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig3 = sigma[i][j]*sigma[i][j]*sigma[i][j];
double sig6 = sig3*sig3;
double rc3 = cut[i][j]*cut[i][j]*cut[i][j];
double rc6 = rc3*rc3;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig3 - 2.0*rc3) / (6.0*rc6);
ptail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (3.0*sig3 - 4.0*rc3) / (6.0*rc6);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJ96Cut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJ96Cut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJ96Cut::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJ96Cut::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJ96Cut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJ96Cut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJ96Cut::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r3inv,r6inv,forcelj,philj;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
r3inv = sqrt(r6inv);
forcelj = r6inv * (lj1[itype][jtype]*r3inv - lj2[itype][jtype]);
fforce = factor_lj*forcelj*r2inv;
philj = r6inv*(lj3[itype][jtype]*r3inv-lj4[itype][jtype]) -
offset[itype][jtype];
return factor_lj*philj;
}
diff --git a/src/pair_lj_cut.cpp b/src/pair_lj_cut.cpp
index a3ebf414c..7f838061f 100644
--- a/src/pair_lj_cut.cpp
+++ b/src/pair_lj_cut.cpp
@@ -1,725 +1,725 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJCut::PairLJCut(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 1;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJCut::~PairLJCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forcelj,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairLJCut::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
jtype = type[j];
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCut::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
jtype = type[j];
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCut::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forcelj,factor_lj,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
if (eflag) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (vflag) {
if (rsq <= cut_in_off_sq) {
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj*r2inv;
} else if (rsq < cut_in_on_sq)
fpair = factor_lj*forcelj*r2inv;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCut::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_one = cut_global;
if (narg == 5) cut_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCut::init_style()
{
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairLJCut::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && cut[i][j] < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut[i][j]*cut[i][j]*cut[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCut::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCut::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,forcelj,philj;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fforce = factor_lj*forcelj*r2inv;
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
return factor_lj*philj;
}
/* ---------------------------------------------------------------------- */
void *PairLJCut::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
return NULL;
}
diff --git a/src/pair_lj_cut_coul_cut.cpp b/src/pair_lj_cut_coul_cut.cpp
index 0d62c43dc..85cf9dc97 100644
--- a/src/pair_lj_cut_coul_cut.cpp
+++ b/src/pair_lj_cut_coul_cut.cpp
@@ -1,471 +1,471 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_coul_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJCutCoulCut::PairLJCutCoulCut(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJCutCoulCut::~PairLJCutCoulCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(cut_coul);
memory->destroy(cut_coulsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = qqrd2e * qtmp*q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fpair = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_coulsq[itype][jtype])
ecoul = factor_coul * qqrd2e * qtmp*q[j]*sqrt(r2inv);
else ecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutCoulCut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(cut_coul,n+1,n+1,"pair:cut_coul");
memory->create(cut_coulsq,n+1,n+1,"pair:cut_coulsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutCoulCut::settings(int narg, char **arg)
{
if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
cut_lj_global = force->numeric(FLERR,arg[0]);
if (narg == 1) cut_coul_global = cut_lj_global;
else cut_coul_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_lj[i][j] = cut_lj_global;
cut_coul[i][j] = cut_coul_global;
}
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutCoulCut::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 6)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
double cut_coul_one = cut_coul_global;
if (narg >= 5) cut_coul_one = cut_lj_one = force->numeric(FLERR,arg[4]);
if (narg == 6) cut_coul_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
cut_coul[i][j] = cut_coul_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutCoulCut::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/cut requires atom attribute q");
neighbor->request(this,instance_me);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutCoulCut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
cut_coul[i][j] = mix_distance(cut_coul[i][i],cut_coul[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul[i][j]);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
cut_coulsq[i][j] = cut_coul[i][j] * cut_coul[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
cut_coulsq[j][i] = cut_coulsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulCut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
fwrite(&cut_coul[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulCut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
fread(&cut_coul[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulCut::write_restart_settings(FILE *fp)
{
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulCut::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJCutCoulCut::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJCutCoulCut::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut_lj[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJCutCoulCut::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,forcecoul,forcelj,phicoul,philj;
r2inv = 1.0/rsq;
if (rsq < cut_coulsq[itype][jtype])
forcecoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
else forcecoul = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
fforce = (factor_coul*forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_coulsq[itype][jtype]) {
phicoul = force->qqrd2e * atom->q[i]*atom->q[j]*sqrt(r2inv);
eng += factor_coul*phicoul;
}
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutCoulCut::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
return NULL;
}
diff --git a/src/pair_lj_cut_coul_dsf.cpp b/src/pair_lj_cut_coul_dsf.cpp
index 09293a6f4..5d95d06ed 100644
--- a/src/pair_lj_cut_coul_dsf.cpp
+++ b/src/pair_lj_cut_coul_dsf.cpp
@@ -1,481 +1,481 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Trung Dac Nguyen (ORNL)
References: Fennell and Gezelter, JCP 124, 234104 (2006)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_cut_coul_dsf.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "math_const.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define EWALD_F 1.12837917
#define EWALD_P 0.3275911
#define A1 0.254829592
#define A2 -0.284496736
#define A3 1.421413741
#define A4 -1.453152027
#define A5 1.061405429
/* ---------------------------------------------------------------------- */
PairLJCutCoulDSF::PairLJCutCoulDSF(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
}
/* ---------------------------------------------------------------------- */
PairLJCutCoulDSF::~PairLJCutCoulDSF()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut_lj);
memory->destroy(cut_ljsq);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJCutCoulDSF::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double r,rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj;
double prefactor,erfcc,erfcd,t;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
double *special_coul = force->special_coul;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
if (eflag) {
double e_self = -(e_shift/2.0 + alpha/MY_PIS) * qtmp*qtmp*qqrd2e;
ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0);
}
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
factor_coul = special_coul[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = qqrd2e*qtmp*q[j]/r;
erfcd = exp(-alpha*alpha*r*r);
t = 1.0 / (1.0 + EWALD_P*alpha*r);
erfcc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * erfcd;
forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd +
r*f_shift) * r;
if (factor_coul < 1.0) forcecoul -= (1.0-factor_coul)*prefactor;
} else forcecoul = 0.0;
fpair = (forcecoul + factor_lj*forcelj) * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (rsq < cut_ljsq[itype][jtype]) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
} else evdwl = 0.0;
if (rsq < cut_coulsq) {
ecoul = prefactor * (erfcc - r*e_shift - rsq*f_shift);
if (factor_coul < 1.0) ecoul -= (1.0-factor_coul)*prefactor;
} else ecoul = 0.0;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut_lj,n+1,n+1,"pair:cut_lj");
memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::settings(int narg, char **arg)
{
if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command");
alpha = force->numeric(FLERR,arg[0]);
cut_lj_global = force->numeric(FLERR,arg[1]);
if (narg == 2) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[2]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j])
cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::coeff(int narg, char **arg)
{
if (narg < 4 || narg > 5)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double cut_lj_one = cut_lj_global;
if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
cut_lj[i][j] = cut_lj_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::init_style()
{
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/cut/coul/dsf requires atom attribute q");
neighbor->request(this,instance_me);
cut_coulsq = cut_coul * cut_coul;
double erfcc = erfc(alpha*cut_coul);
double erfcd = exp(-alpha*alpha*cut_coul*cut_coul);
f_shift = -(erfcc/cut_coulsq + 2.0/MY_PIS*alpha*erfcd/cut_coul);
e_shift = erfcc/cut_coul - f_shift*cut_coul;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJCutCoulDSF::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]);
}
double cut = MAX(cut_lj[i][j],cut_coul);
cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j];
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut_lj[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut_lj[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
cut_ljsq[j][i] = cut_ljsq[i][j];
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j];
double rc6 = rc3*rc3;
double rc9 = rc3*rc6;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (sig6 - 3.0*rc6) / (9.0*rc9);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] *
sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9);
}
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut_lj[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut_lj[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::write_restart_settings(FILE *fp)
{
fwrite(&alpha,sizeof(double),1,fp);
fwrite(&cut_lj_global,sizeof(double),1,fp);
fwrite(&cut_coul,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutCoulDSF::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&alpha,sizeof(double),1,fp);
fread(&cut_lj_global,sizeof(double),1,fp);
fread(&cut_coul,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
double PairLJCutCoulDSF::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r6inv,r,erfcc,erfcd,prefactor;
double forcecoul,forcelj,phicoul,philj;
r2inv = 1.0/rsq;
if (rsq < cut_ljsq[itype][jtype]) {
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
} else forcelj = 0.0;
if (rsq < cut_coulsq) {
r = sqrt(rsq);
prefactor = factor_coul * force->qqrd2e * atom->q[i]*atom->q[j]/r;
erfcc = erfc(alpha*r);
erfcd = exp(-alpha*alpha*r*r);
forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd +
r*f_shift) * r;
} else forcecoul = 0.0;
fforce = (forcecoul + factor_lj*forcelj) * r2inv;
double eng = 0.0;
if (rsq < cut_ljsq[itype][jtype]) {
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
eng += factor_lj*philj;
}
if (rsq < cut_coulsq) {
phicoul = prefactor * (erfcc - r*e_shift - rsq*f_shift);
eng += phicoul;
}
return eng;
}
/* ---------------------------------------------------------------------- */
void *PairLJCutCoulDSF::extract(const char *str, int &dim)
{
if (strcmp(str,"cut_coul") == 0) {
dim = 0;
return (void *) &cut_coul;
}
return NULL;
}
diff --git a/src/pair_lj_expand.cpp b/src/pair_lj_expand.cpp
index 2fd780472..785733dcc 100644
--- a/src/pair_lj_expand.cpp
+++ b/src/pair_lj_expand.cpp
@@ -1,427 +1,427 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_lj_expand.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neigh_list.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairLJExpand::PairLJExpand(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairLJExpand::~PairLJExpand()
{
if (!copymode) {
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(shift);
memory->destroy(lj1);
memory->destroy(lj2);
memory->destroy(lj3);
memory->destroy(lj4);
memory->destroy(offset);
}
}
}
/* ---------------------------------------------------------------------- */
void PairLJExpand::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r6inv,forcelj,factor_lj;
double r,rshift,rshiftsq;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r = sqrt(rsq);
rshift = r - shift[itype][jtype];
rshiftsq = rshift*rshift;
r2inv = 1.0/rshiftsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fpair = factor_lj*forcelj/rshift/r;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLJExpand::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(shift,n+1,n+1,"pair:shift");
memory->create(lj1,n+1,n+1,"pair:lj1");
memory->create(lj2,n+1,n+1,"pair:lj2");
memory->create(lj3,n+1,n+1,"pair:lj3");
memory->create(lj4,n+1,n+1,"pair:lj4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJExpand::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLJExpand::coeff(int narg, char **arg)
{
if (narg < 5 || narg > 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double shift_one = force->numeric(FLERR,arg[4]);
double cut_one = cut_global;
if (narg == 6) cut_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
shift[i][j] = shift_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLJExpand::init_one(int i, int j)
{
// always mix shift arithmetically
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
shift[i][j] = 0.5 * (shift[i][i] + shift[j][j]);
}
lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0);
lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0));
} else offset[i][j] = 0.0;
lj1[j][i] = lj1[i][j];
lj2[j][i] = lj2[i][j];
lj3[j][i] = lj3[i][j];
lj4[j][i] = lj4[i][j];
shift[j][i] = shift[i][j];
offset[j][i] = offset[i][j];
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double sig2 = sigma[i][j]*sigma[i][j];
double sig6 = sig2*sig2*sig2;
double rc1 = cut[i][j];
double rc2 = rc1*rc1;
double rc3 = rc2*rc1;
double rc9 = rc3*rc3*rc3;
double shift1 = shift[i][j];
double shift2 = shift1*shift1;
double shift3 = shift2*shift1;
etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 *
((1.0/9.0 + 2.0*shift1/(10.0*rc1) + shift2/(11.0*rc2))*sig6/rc9 -
(1.0/3.0 + 2.0*shift1/(4.0*rc1) + shift2/(5.0*rc2))/rc3);
ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * sig6 *
((1.0/9.0 + 3.0*shift1/(10.0*rc1) +
3.0*shift2/(11.0*rc2) + shift3/(12.0*rc3))*2.0*sig6/rc9 -
(1.0/3.0 + 3.0*shift1/(4.0*rc1) +
3.0*shift2/(5.0*rc2) + shift3/(6.0*rc3))/rc3);
}
return cut[i][j] + shift[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJExpand::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&shift[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJExpand::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&shift[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&shift[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJExpand::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJExpand::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairLJExpand::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g %g %g\n",i,epsilon[i][i],sigma[i][i],shift[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairLJExpand::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g %g %g\n",i,j,
epsilon[i][j],sigma[i][j],shift[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairLJExpand::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r,rshift,rshiftsq,r2inv,r6inv,forcelj,philj;
r = sqrt(rsq);
rshift = r - shift[itype][jtype];
rshiftsq = rshift*rshift;
r2inv = 1.0/rshiftsq;
r6inv = r2inv*r2inv*r2inv;
forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]);
fforce = factor_lj*forcelj/rshift/r;
philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) -
offset[itype][jtype];
return factor_lj*philj;
}
/* ---------------------------------------------------------------------- */
void *PairLJExpand::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"delta") == 0) return (void *) shift;
return NULL;
}
diff --git a/src/pair_mie_cut.cpp b/src/pair_mie_cut.cpp
index 312fb7bc7..320f21248 100644
--- a/src/pair_mie_cut.cpp
+++ b/src/pair_mie_cut.cpp
@@ -1,738 +1,738 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Cassiano Aimoli (aimoli@gmail.com)
------------------------------------------------------------------------- */
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pair_mie_cut.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "integrate.h"
#include "respa.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
PairMIECut::PairMIECut(LAMMPS *lmp) : Pair(lmp)
{
respa_enable = 1;
}
/* ---------------------------------------------------------------------- */
PairMIECut::~PairMIECut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(gamR);
memory->destroy(gamA);
memory->destroy(Cmie);
memory->destroy(mie1);
memory->destroy(mie2);
memory->destroy(mie3);
memory->destroy(mie4);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairMIECut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_mie = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mie = special_mie[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fpair = factor_mie*forcemie*r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) -
offset[itype][jtype];
evdwl *= factor_mie;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairMIECut::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_mie = force->special_lj;
int newton_pair = force->newton_pair;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->firstneigh;
double cut_out_on = cut_respa[0];
double cut_out_off = cut_respa[1];
double cut_out_diff = cut_out_off - cut_out_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mie = special_mie[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq) {
jtype = type[j];
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fpair = factor_mie*forcemie*r2inv;
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 - rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairMIECut::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fpair;
double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_mie = force->special_lj;
int newton_pair = force->newton_pair;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->firstneigh;
double cut_in_off = cut_respa[0];
double cut_in_on = cut_respa[1];
double cut_out_on = cut_respa[2];
double cut_out_off = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_out_diff = cut_out_off - cut_out_on;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
double cut_out_on_sq = cut_out_on*cut_out_on;
double cut_out_off_sq = cut_out_off*cut_out_off;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mie = special_mie[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cut_out_off_sq && rsq > cut_in_off_sq) {
jtype = type[j];
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fpair = factor_mie*forcemie*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
fpair *= 1.0 + rsw*rsw*(2.0*rsw - 3.0);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairMIECut::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,rgamR,rgamA,forcemie,factor_mie,rsw;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_mie = force->special_lj;
int newton_pair = force->newton_pair;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
double cut_in_off = cut_respa[2];
double cut_in_on = cut_respa[3];
double cut_in_diff = cut_in_on - cut_in_off;
double cut_in_off_sq = cut_in_off*cut_in_off;
double cut_in_on_sq = cut_in_on*cut_in_on;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_mie = special_mie[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
if (rsq > cut_in_off_sq) {
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fpair = factor_mie*forcemie*r2inv;
if (rsq < cut_in_on_sq) {
rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
fpair *= rsw*rsw*(3.0 - 2.0*rsw);
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
}
if (eflag) {
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
evdwl = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) -
offset[itype][jtype];
evdwl *= factor_mie;
}
if (vflag) {
if (rsq <= cut_in_off_sq) {
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fpair = factor_mie*forcemie*r2inv;
} else if (rsq < cut_in_on_sq)
fpair = factor_mie*forcemie*r2inv;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairMIECut::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(epsilon,n+1,n+1,"pair:epsilon");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(gamR,n+1,n+1,"pair:gamR");
memory->create(gamA,n+1,n+1,"pair:gamA");
memory->create(Cmie,n+1,n+1,"pair:Cmie");
memory->create(mie1,n+1,n+1,"pair:mie1");
memory->create(mie2,n+1,n+1,"pair:mie2");
memory->create(mie3,n+1,n+1,"pair:mie3");
memory->create(mie4,n+1,n+1,"pair:mie4");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairMIECut::settings(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
cut_global = force->numeric(FLERR,arg[0]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairMIECut::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 7)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double epsilon_one = force->numeric(FLERR,arg[2]);
double sigma_one = force->numeric(FLERR,arg[3]);
double gamR_one = force->numeric(FLERR,arg[4]);
double gamA_one = force->numeric(FLERR,arg[5]);
double cut_one = cut_global;
if (narg == 7) cut_one = force->numeric(FLERR,arg[6]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
epsilon[i][j] = epsilon_one;
sigma[i][j] = sigma_one;
gamR[i][j] = gamR_one;
gamA[i][j] = gamA_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairMIECut::init_style()
{
// request regular or rRESPA neighbor lists
int irequest;
if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) {
int respa = 0;
if (((Respa *) update->integrate)->level_inner >= 0) respa = 1;
if (((Respa *) update->integrate)->level_middle >= 0) respa = 2;
if (respa == 0) irequest = neighbor->request(this,instance_me);
else if (respa == 1) {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
} else {
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 1;
neighbor->requests[irequest]->respainner = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 2;
neighbor->requests[irequest]->respamiddle = 1;
irequest = neighbor->request(this,instance_me);
neighbor->requests[irequest]->id = 3;
neighbor->requests[irequest]->respaouter = 1;
}
} else irequest = neighbor->request(this,instance_me);
// set rRESPA cutoffs
if (strstr(update->integrate_style,"respa") &&
((Respa *) update->integrate)->level_inner >= 0)
cut_respa = ((Respa *) update->integrate)->cutoff;
else cut_respa = NULL;
}
/* ----------------------------------------------------------------------
neighbor callback to inform pair style of neighbor list to use
regular or rRESPA
------------------------------------------------------------------------- */
void PairMIECut::init_list(int id, NeighList *ptr)
{
if (id == 0) list = ptr;
else if (id == 1) listinner = ptr;
else if (id == 2) listmiddle = ptr;
else if (id == 3) listouter = ptr;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairMIECut::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j],
sigma[i][i],sigma[j][j]);
sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]);
gamR[i][j] = mix_distance(gamR[i][i],gamR[j][j]);
gamA[i][j] = mix_distance(gamA[i][i],gamA[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
gamA[j][i] = gamA[i][j];
gamR[j][i] = gamR[i][j];
Cmie[i][j] = (gamR[i][j]/(gamR[i][j]-gamA[i][j]) *
pow((gamR[i][j]/gamA[i][j]),
(gamA[i][j]/(gamR[i][j]-gamA[i][j]))));
mie1[i][j] = Cmie[i][j] * gamR[i][j]* epsilon[i][j] *
pow(sigma[i][j],gamR[i][j]);
mie2[i][j] = Cmie[i][j] * gamA[i][j] * epsilon[i][j] *
pow(sigma[i][j],gamA[i][j]);
mie3[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamR[i][j]);
mie4[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamA[i][j]);
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double ratio = sigma[i][j] / cut[i][j];
offset[i][j] = Cmie[i][j] * epsilon[i][j] *
(pow(ratio,gamR[i][j]) - pow(ratio,gamA[i][j]));
} else offset[i][j] = 0.0;
mie1[j][i] = mie1[i][j];
mie2[j][i] = mie2[i][j];
mie3[j][i] = mie3[i][j];
mie4[j][i] = mie4[i][j];
offset[j][i] = offset[i][j];
// check interior rRESPA cutoff
if (cut_respa && cut[i][j] < cut_respa[3])
error->all(FLERR,"Pair cutoff < Respa interior cutoff");
// compute I,J contribution to long-range tail correction
// count total # of atoms of type I and J via Allreduce
if (tail_flag) {
int *type = atom->type;
int nlocal = atom->nlocal;
double count[2],all[2];
count[0] = count[1] = 0.0;
for (int k = 0; k < nlocal; k++) {
if (type[k] == i) count[0] += 1.0;
if (type[k] == j) count[1] += 1.0;
}
MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world);
double siggamA = pow(sigma[i][j],gamA[i][j]);
double siggamR = pow(sigma[i][j],gamR[i][j]);
double rcgamA = pow(cut[i][j],(gamA[i][j]-3.0));
double rcgamR = pow(cut[i][j],(gamR[i][j]-3.0));
etail_ij = Cmie[i][j]*2.0*MY_PI*all[0]*all[1]*epsilon[i][j]*
(siggamR/((gamR[i][j]-3.0)*rcgamR)-siggamA/((gamA[i][j]-3.0)*rcgamA));
ptail_ij = Cmie[i][j]*2.0*MY_PI*all[0]*all[1]*epsilon[i][j]/3.0*
((gamR[i][j]/(gamR[i][j]-3.0))*siggamR/rcgamR-
(gamA[i][j]/(gamA[i][j]-3.0))*siggamA/rcgamA);
}
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairMIECut::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&epsilon[i][j],sizeof(double),1,fp);
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&gamR[i][j],sizeof(double),1,fp);
fwrite(&gamA[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairMIECut::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&epsilon[i][j],sizeof(double),1,fp);
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&gamR[i][j],sizeof(double),1,fp);
fread(&gamA[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&gamR[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&gamA[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairMIECut::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
fwrite(&tail_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairMIECut::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
fread(&tail_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
MPI_Bcast(&tail_flag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
double PairMIECut::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_mie,
double &fforce)
{
double r2inv,rgamR,rgamA,forcemie,phimie;
r2inv = 1.0/rsq;
rgamA = pow(r2inv,(gamA[itype][jtype]/2.0));
rgamR = pow(r2inv,(gamR[itype][jtype]/2.0));
forcemie = (mie1[itype][jtype]*rgamR - mie2[itype][jtype]*rgamA);
fforce = factor_mie*forcemie*r2inv;
phimie = (mie3[itype][jtype]*rgamR - mie4[itype][jtype]*rgamA) -
offset[itype][jtype];
return factor_mie*phimie;
}
/* ---------------------------------------------------------------------- */
void *PairMIECut::extract(const char *str, int &dim)
{
dim = 2;
if (strcmp(str,"epsilon") == 0) return (void *) epsilon;
if (strcmp(str,"sigma") == 0) return (void *) sigma;
if (strcmp(str,"gamR") == 0) return (void *) gamR;
if (strcmp(str,"gamA") == 0) return (void *) gamA;
return NULL;
}
diff --git a/src/pair_table.cpp b/src/pair_table.cpp
index b36843ff4..782fb43f9 100644
--- a/src/pair_table.cpp
+++ b/src/pair_table.cpp
@@ -1,1060 +1,1065 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include <mpi.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "pair_table.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NONE,RLINEAR,RSQ,BMP};
#define MAXLINE 1024
#define EPSILONR 1.0e-6
/* ---------------------------------------------------------------------- */
PairTable::PairTable(LAMMPS *lmp) : Pair(lmp)
{
ntables = 0;
tables = NULL;
}
/* ---------------------------------------------------------------------- */
PairTable::~PairTable()
{
if (copymode) return;
for (int m = 0; m < ntables; m++) free_table(&tables[m]);
memory->sfree(tables);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(tabindex);
}
}
/* ---------------------------------------------------------------------- */
void PairTable::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,factor_lj,fraction,value,a,b;
char estr[128];
int *ilist,*jlist,*numneigh,**firstneigh;
Table *tb;
union_int_float_t rsq_lookup;
int tlm1 = tablength - 1;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_lj = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
tb = &tables[tabindex[itype][jtype]];
if (rsq < tb->innersq) {
sprintf(estr,"Pair distance < table inner cutoff: "
"ijtype %d %d dist %g",itype,jtype,sqrt(rsq));
error->one(FLERR,estr);
}
if (tabstyle == LOOKUP) {
itable = static_cast<int> ((rsq - tb->innersq) * tb->invdelta);
if (itable >= tlm1) {
sprintf(estr,"Pair distance > table outer cutoff: "
"ijtype %d %d dist %g",itype,jtype,sqrt(rsq));
error->one(FLERR,estr);
}
fpair = factor_lj * tb->f[itable];
} else if (tabstyle == LINEAR) {
itable = static_cast<int> ((rsq - tb->innersq) * tb->invdelta);
if (itable >= tlm1) {
sprintf(estr,"Pair distance > table outer cutoff: "
"ijtype %d %d dist %g",itype,jtype,sqrt(rsq));
error->one(FLERR,estr);
}
fraction = (rsq - tb->rsq[itable]) * tb->invdelta;
value = tb->f[itable] + fraction*tb->df[itable];
fpair = factor_lj * value;
} else if (tabstyle == SPLINE) {
itable = static_cast<int> ((rsq - tb->innersq) * tb->invdelta);
if (itable >= tlm1) {
sprintf(estr,"Pair distance > table outer cutoff: "
"ijtype %d %d dist %g",itype,jtype,sqrt(rsq));
error->one(FLERR,estr);
}
b = (rsq - tb->rsq[itable]) * tb->invdelta;
a = 1.0 - b;
value = a * tb->f[itable] + b * tb->f[itable+1] +
((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) *
tb->deltasq6;
fpair = factor_lj * value;
} else {
rsq_lookup.f = rsq;
itable = rsq_lookup.i & tb->nmask;
itable >>= tb->nshiftbits;
fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable];
value = tb->f[itable] + fraction*tb->df[itable];
fpair = factor_lj * value;
}
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
if (tabstyle == LOOKUP)
evdwl = tb->e[itable];
else if (tabstyle == LINEAR || tabstyle == BITMAP)
evdwl = tb->e[itable] + fraction*tb->de[itable];
else
evdwl = a * tb->e[itable] + b * tb->e[itable+1] +
((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) *
tb->deltasq6;
evdwl *= factor_lj;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairTable::allocate()
{
allocated = 1;
const int nt = atom->ntypes + 1;
memory->create(setflag,nt,nt,"pair:setflag");
memory->create(cutsq,nt,nt,"pair:cutsq");
memory->create(tabindex,nt,nt,"pair:tabindex");
memset(&setflag[0][0],0,nt*nt*sizeof(int));
memset(&cutsq[0][0],0,nt*nt*sizeof(double));
memset(&tabindex[0][0],0,nt*nt*sizeof(int));
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairTable::settings(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal pair_style command");
// new settings
if (strcmp(arg[0],"lookup") == 0) tabstyle = LOOKUP;
else if (strcmp(arg[0],"linear") == 0) tabstyle = LINEAR;
else if (strcmp(arg[0],"spline") == 0) tabstyle = SPLINE;
else if (strcmp(arg[0],"bitmap") == 0) tabstyle = BITMAP;
else error->all(FLERR,"Unknown table style in pair_style command");
tablength = force->inumeric(FLERR,arg[1]);
if (tablength < 2) error->all(FLERR,"Illegal number of pair table entries");
// optional keywords
// assert the tabulation is compatible with a specific long-range solver
int iarg = 2;
while (iarg < narg) {
if (strcmp(arg[iarg],"ewald") == 0) ewaldflag = 1;
else if (strcmp(arg[iarg],"pppm") == 0) pppmflag = 1;
else if (strcmp(arg[iarg],"msm") == 0) msmflag = 1;
else if (strcmp(arg[iarg],"dispersion") == 0) dispersionflag = 1;
else if (strcmp(arg[iarg],"tip4p") == 0) tip4pflag = 1;
else error->all(FLERR,"Illegal pair_style command");
iarg++;
}
// delete old tables, since cannot just change settings
for (int m = 0; m < ntables; m++) free_table(&tables[m]);
memory->sfree(tables);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(tabindex);
}
allocated = 0;
ntables = 0;
tables = NULL;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairTable::coeff(int narg, char **arg)
{
if (narg != 4 && narg != 5) error->all(FLERR,"Illegal pair_coeff command");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
int me;
MPI_Comm_rank(world,&me);
tables = (Table *)
memory->srealloc(tables,(ntables+1)*sizeof(Table),"pair:tables");
Table *tb = &tables[ntables];
null_table(tb);
if (me == 0) read_table(tb,arg[2],arg[3]);
bcast_table(tb);
// set table cutoff
if (narg == 5) tb->cut = force->numeric(FLERR,arg[4]);
else if (tb->rflag) tb->cut = tb->rhi;
else tb->cut = tb->rfile[tb->ninput-1];
// error check on table parameters
// insure cutoff is within table
// for BITMAP tables, file values can be in non-ascending order
if (tb->ninput <= 1) error->one(FLERR,"Invalid pair table length");
double rlo,rhi;
if (tb->rflag == 0) {
rlo = tb->rfile[0];
rhi = tb->rfile[tb->ninput-1];
} else {
rlo = tb->rlo;
rhi = tb->rhi;
}
if (tb->cut <= rlo || tb->cut > rhi)
error->all(FLERR,"Invalid pair table cutoff");
if (rlo <= 0.0) error->all(FLERR,"Invalid pair table cutoff");
// match = 1 if don't need to spline read-in tables
// this is only the case if r values needed by final tables
// exactly match r values read from file
// for tabstyle SPLINE, always need to build spline tables
tb->match = 0;
if (tabstyle == LINEAR && tb->ninput == tablength &&
tb->rflag == RSQ && tb->rhi == tb->cut) tb->match = 1;
if (tabstyle == BITMAP && tb->ninput == 1 << tablength &&
tb->rflag == BMP && tb->rhi == tb->cut) tb->match = 1;
if (tb->rflag == BMP && tb->match == 0)
error->all(FLERR,"Bitmapped table in file does not match requested table");
// spline read-in values and compute r,e,f vectors within table
if (tb->match == 0) spline_table(tb);
compute_table(tb);
// store ptr to table in tabindex
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
tabindex[i][j] = ntables;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Illegal pair_coeff command");
ntables++;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairTable::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
tabindex[j][i] = tabindex[i][j];
return tables[tabindex[i][j]].cut;
}
/* ----------------------------------------------------------------------
read a table section from a tabulated potential file
only called by proc 0
this function sets these values in Table:
ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi,ntablebits
------------------------------------------------------------------------- */
void PairTable::read_table(Table *tb, char *file, char *keyword)
{
char line[MAXLINE];
// open file
FILE *fp = force->open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open file %s",file);
error->one(FLERR,str);
}
// loop until section found with matching keyword
while (1) {
if (fgets(line,MAXLINE,fp) == NULL)
error->one(FLERR,"Did not find keyword in table file");
if (strspn(line," \t\n\r") == strlen(line)) continue; // blank line
if (line[0] == '#') continue; // comment
char *word = strtok(line," \t\n\r");
if (strcmp(word,keyword) == 0) break; // matching keyword
fgets(line,MAXLINE,fp); // no match, skip section
param_extract(tb,line);
fgets(line,MAXLINE,fp);
for (int i = 0; i < tb->ninput; i++) fgets(line,MAXLINE,fp);
}
// read args on 2nd line of section
// allocate table arrays for file values
fgets(line,MAXLINE,fp);
param_extract(tb,line);
memory->create(tb->rfile,tb->ninput,"pair:rfile");
memory->create(tb->efile,tb->ninput,"pair:efile");
memory->create(tb->ffile,tb->ninput,"pair:ffile");
// setup bitmap parameters for table to read in
tb->ntablebits = 0;
int masklo,maskhi,nmask,nshiftbits;
if (tb->rflag == BMP) {
while (1 << tb->ntablebits < tb->ninput) tb->ntablebits++;
if (1 << tb->ntablebits != tb->ninput)
error->one(FLERR,"Bitmapped table is incorrect length in table file");
init_bitmap(tb->rlo,tb->rhi,tb->ntablebits,masklo,maskhi,nmask,nshiftbits);
}
// read r,e,f table values from file
// if rflag set, compute r
// if rflag not set, use r from file
int itmp;
double rfile,rnew;
union_int_float_t rsq_lookup;
int rerror = 0;
int cerror = 0;
fgets(line,MAXLINE,fp);
for (int i = 0; i < tb->ninput; i++) {
if (NULL == fgets(line,MAXLINE,fp))
error->one(FLERR,"Premature end of file in pair table");
if (4 != sscanf(line,"%d %lg %lg %lg",
&itmp,&rfile,&tb->efile[i],&tb->ffile[i])) ++cerror;
rnew = rfile;
if (tb->rflag == RLINEAR)
rnew = tb->rlo + (tb->rhi - tb->rlo)*i/(tb->ninput-1);
else if (tb->rflag == RSQ) {
rnew = tb->rlo*tb->rlo +
(tb->rhi*tb->rhi - tb->rlo*tb->rlo)*i/(tb->ninput-1);
rnew = sqrt(rnew);
} else if (tb->rflag == BMP) {
rsq_lookup.i = i << nshiftbits;
rsq_lookup.i |= masklo;
if (rsq_lookup.f < tb->rlo*tb->rlo) {
rsq_lookup.i = i << nshiftbits;
rsq_lookup.i |= maskhi;
}
rnew = sqrtf(rsq_lookup.f);
}
if (tb->rflag && fabs(rnew-rfile)/rfile > EPSILONR) rerror++;
tb->rfile[i] = rnew;
}
// close file
fclose(fp);
// warn if force != dE/dr at any point that is not an inflection point
// check via secant approximation to dE/dr
// skip two end points since do not have surrounding secants
// inflection point is where curvature changes sign
double r,e,f,rprev,rnext,eprev,enext,fleft,fright;
int ferror = 0;
- for (int i = 1; i < tb->ninput-1; i++) {
- r = tb->rfile[i];
- rprev = tb->rfile[i-1];
- rnext = tb->rfile[i+1];
- e = tb->efile[i];
- eprev = tb->efile[i-1];
- enext = tb->efile[i+1];
- f = tb->ffile[i];
- fleft = - (e-eprev) / (r-rprev);
- fright = - (enext-e) / (rnext-r);
- if (f < fleft && f < fright) ferror++;
- if (f > fleft && f > fright) ferror++;
- //printf("Values %d: %g %g %g\n",i,r,e,f);
- //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f);
+
+ // bitmapped tables do not follow regular ordering, so we cannot check them here
+
+ if (tb->rflag != BMP) {
+ for (int i = 1; i < tb->ninput-1; i++) {
+ r = tb->rfile[i];
+ rprev = tb->rfile[i-1];
+ rnext = tb->rfile[i+1];
+ e = tb->efile[i];
+ eprev = tb->efile[i-1];
+ enext = tb->efile[i+1];
+ f = tb->ffile[i];
+ fleft = - (e-eprev) / (r-rprev);
+ fright = - (enext-e) / (rnext-r);
+ if (f < fleft && f < fright) ferror++;
+ if (f > fleft && f > fright) ferror++;
+ //printf("Values %d: %g %g %g\n",i,r,e,f);
+ //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f);
+ }
}
if (ferror) {
char str[128];
sprintf(str,"%d of %d force values in table are inconsistent with -dE/dr.\n"
" Should only be flagged at inflection points",ferror,tb->ninput);
error->warning(FLERR,str);
}
// warn if re-computed distance values differ from file values
if (rerror) {
char str[128];
sprintf(str,"%d of %d distance values in table with relative error\n"
" over %g to re-computed values",rerror,tb->ninput,EPSILONR);
error->warning(FLERR,str);
}
// warn if data was read incompletely, e.g. columns were missing
if (cerror) {
char str[128];
sprintf(str,"%d of %d lines in table were incomplete\n"
" or could not be parsed completely",cerror,tb->ninput);
error->warning(FLERR,str);
}
}
/* ----------------------------------------------------------------------
broadcast read-in table info from proc 0 to other procs
this function communicates these values in Table:
ninput,rfile,efile,ffile,rflag,rlo,rhi,fpflag,fplo,fphi
------------------------------------------------------------------------- */
void PairTable::bcast_table(Table *tb)
{
MPI_Bcast(&tb->ninput,1,MPI_INT,0,world);
int me;
MPI_Comm_rank(world,&me);
if (me > 0) {
memory->create(tb->rfile,tb->ninput,"pair:rfile");
memory->create(tb->efile,tb->ninput,"pair:efile");
memory->create(tb->ffile,tb->ninput,"pair:ffile");
}
MPI_Bcast(tb->rfile,tb->ninput,MPI_DOUBLE,0,world);
MPI_Bcast(tb->efile,tb->ninput,MPI_DOUBLE,0,world);
MPI_Bcast(tb->ffile,tb->ninput,MPI_DOUBLE,0,world);
MPI_Bcast(&tb->rflag,1,MPI_INT,0,world);
if (tb->rflag) {
MPI_Bcast(&tb->rlo,1,MPI_DOUBLE,0,world);
MPI_Bcast(&tb->rhi,1,MPI_DOUBLE,0,world);
}
MPI_Bcast(&tb->fpflag,1,MPI_INT,0,world);
if (tb->fpflag) {
MPI_Bcast(&tb->fplo,1,MPI_DOUBLE,0,world);
MPI_Bcast(&tb->fphi,1,MPI_DOUBLE,0,world);
}
}
/* ----------------------------------------------------------------------
build spline representation of e,f over entire range of read-in table
this function sets these values in Table: e2file,f2file
------------------------------------------------------------------------- */
void PairTable::spline_table(Table *tb)
{
memory->create(tb->e2file,tb->ninput,"pair:e2file");
memory->create(tb->f2file,tb->ninput,"pair:f2file");
double ep0 = - tb->ffile[0];
double epn = - tb->ffile[tb->ninput-1];
spline(tb->rfile,tb->efile,tb->ninput,ep0,epn,tb->e2file);
if (tb->fpflag == 0) {
tb->fplo = (tb->ffile[1] - tb->ffile[0]) / (tb->rfile[1] - tb->rfile[0]);
tb->fphi = (tb->ffile[tb->ninput-1] - tb->ffile[tb->ninput-2]) /
(tb->rfile[tb->ninput-1] - tb->rfile[tb->ninput-2]);
}
double fp0 = tb->fplo;
double fpn = tb->fphi;
spline(tb->rfile,tb->ffile,tb->ninput,fp0,fpn,tb->f2file);
}
/* ----------------------------------------------------------------------
extract attributes from parameter line in table section
format of line: N value R/RSQ/BITMAP lo hi FPRIME fplo fphi
N is required, other params are optional
------------------------------------------------------------------------- */
void PairTable::param_extract(Table *tb, char *line)
{
tb->ninput = 0;
tb->rflag = NONE;
tb->fpflag = 0;
char *word = strtok(line," \t\n\r\f");
while (word) {
if (strcmp(word,"N") == 0) {
word = strtok(NULL," \t\n\r\f");
tb->ninput = atoi(word);
} else if (strcmp(word,"R") == 0 || strcmp(word,"RSQ") == 0 ||
strcmp(word,"BITMAP") == 0) {
if (strcmp(word,"R") == 0) tb->rflag = RLINEAR;
else if (strcmp(word,"RSQ") == 0) tb->rflag = RSQ;
else if (strcmp(word,"BITMAP") == 0) tb->rflag = BMP;
word = strtok(NULL," \t\n\r\f");
tb->rlo = atof(word);
word = strtok(NULL," \t\n\r\f");
tb->rhi = atof(word);
} else if (strcmp(word,"FPRIME") == 0) {
tb->fpflag = 1;
word = strtok(NULL," \t\n\r\f");
tb->fplo = atof(word);
word = strtok(NULL," \t\n\r\f");
tb->fphi = atof(word);
} else {
printf("WORD: %s\n",word);
error->one(FLERR,"Invalid keyword in pair table parameters");
}
word = strtok(NULL," \t\n\r\f");
}
if (tb->ninput == 0) error->one(FLERR,"Pair table parameters did not set N");
}
/* ----------------------------------------------------------------------
compute r,e,f vectors from splined values
------------------------------------------------------------------------- */
void PairTable::compute_table(Table *tb)
{
int tlm1 = tablength-1;
// inner = inner table bound
// cut = outer table bound
// delta = table spacing in rsq for N-1 bins
double inner;
if (tb->rflag) inner = tb->rlo;
else inner = tb->rfile[0];
tb->innersq = inner*inner;
tb->delta = (tb->cut*tb->cut - tb->innersq) / tlm1;
tb->invdelta = 1.0/tb->delta;
// direct lookup tables
// N-1 evenly spaced bins in rsq from inner to cut
// e,f = value at midpt of bin
// e,f are N-1 in length since store 1 value at bin midpt
// f is converted to f/r when stored in f[i]
// e,f are never a match to read-in values, always computed via spline interp
if (tabstyle == LOOKUP) {
memory->create(tb->e,tlm1,"pair:e");
memory->create(tb->f,tlm1,"pair:f");
double r,rsq;
for (int i = 0; i < tlm1; i++) {
rsq = tb->innersq + (i+0.5)*tb->delta;
r = sqrt(rsq);
tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r);
tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r;
}
}
// linear tables
// N-1 evenly spaced bins in rsq from inner to cut
// rsq,e,f = value at lower edge of bin
// de,df values = delta from lower edge to upper edge of bin
// rsq,e,f are N in length so de,df arrays can compute difference
// f is converted to f/r when stored in f[i]
// e,f can match read-in values, else compute via spline interp
if (tabstyle == LINEAR) {
memory->create(tb->rsq,tablength,"pair:rsq");
memory->create(tb->e,tablength,"pair:e");
memory->create(tb->f,tablength,"pair:f");
memory->create(tb->de,tlm1,"pair:de");
memory->create(tb->df,tlm1,"pair:df");
double r,rsq;
for (int i = 0; i < tablength; i++) {
rsq = tb->innersq + i*tb->delta;
r = sqrt(rsq);
tb->rsq[i] = rsq;
if (tb->match) {
tb->e[i] = tb->efile[i];
tb->f[i] = tb->ffile[i]/r;
} else {
tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r);
tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r;
}
}
for (int i = 0; i < tlm1; i++) {
tb->de[i] = tb->e[i+1] - tb->e[i];
tb->df[i] = tb->f[i+1] - tb->f[i];
}
}
// cubic spline tables
// N-1 evenly spaced bins in rsq from inner to cut
// rsq,e,f = value at lower edge of bin
// e2,f2 = spline coefficient for each bin
// rsq,e,f,e2,f2 are N in length so have N-1 spline bins
// f is converted to f/r after e is splined
// e,f can match read-in values, else compute via spline interp
if (tabstyle == SPLINE) {
memory->create(tb->rsq,tablength,"pair:rsq");
memory->create(tb->e,tablength,"pair:e");
memory->create(tb->f,tablength,"pair:f");
memory->create(tb->e2,tablength,"pair:e2");
memory->create(tb->f2,tablength,"pair:f2");
tb->deltasq6 = tb->delta*tb->delta / 6.0;
double r,rsq;
for (int i = 0; i < tablength; i++) {
rsq = tb->innersq + i*tb->delta;
r = sqrt(rsq);
tb->rsq[i] = rsq;
if (tb->match) {
tb->e[i] = tb->efile[i];
tb->f[i] = tb->ffile[i]/r;
} else {
tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r);
tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r);
}
}
// ep0,epn = dh/dg at inner and at cut
// h(r) = e(r) and g(r) = r^2
// dh/dg = (de/dr) / 2r = -f/2r
double ep0 = - tb->f[0] / (2.0 * sqrt(tb->innersq));
double epn = - tb->f[tlm1] / (2.0 * tb->cut);
spline(tb->rsq,tb->e,tablength,ep0,epn,tb->e2);
// fp0,fpn = dh/dg at inner and at cut
// h(r) = f(r)/r and g(r) = r^2
// dh/dg = (1/r df/dr - f/r^2) / 2r
// dh/dg in secant approx = (f(r2)/r2 - f(r1)/r1) / (g(r2) - g(r1))
double fp0,fpn;
double secant_factor = 0.1;
if (tb->fpflag) fp0 = (tb->fplo/sqrt(tb->innersq) - tb->f[0]/tb->innersq) /
(2.0 * sqrt(tb->innersq));
else {
double rsq1 = tb->innersq;
double rsq2 = rsq1 + secant_factor*tb->delta;
fp0 = (splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq2)) /
sqrt(rsq2) - tb->f[0] / sqrt(rsq1)) / (secant_factor*tb->delta);
}
if (tb->fpflag && tb->cut == tb->rfile[tb->ninput-1]) fpn =
(tb->fphi/tb->cut - tb->f[tlm1]/(tb->cut*tb->cut)) / (2.0 * tb->cut);
else {
double rsq2 = tb->cut * tb->cut;
double rsq1 = rsq2 - secant_factor*tb->delta;
fpn = (tb->f[tlm1] / sqrt(rsq2) -
splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,sqrt(rsq1)) /
sqrt(rsq1)) / (secant_factor*tb->delta);
}
for (int i = 0; i < tablength; i++) tb->f[i] /= sqrt(tb->rsq[i]);
spline(tb->rsq,tb->f,tablength,fp0,fpn,tb->f2);
}
// bitmapped linear tables
// 2^N bins from inner to cut, spaced in bitmapped manner
// f is converted to f/r when stored in f[i]
// e,f can match read-in values, else compute via spline interp
if (tabstyle == BITMAP) {
double r;
union_int_float_t rsq_lookup;
int masklo,maskhi;
// linear lookup tables of length ntable = 2^n
// stored value = value at lower edge of bin
init_bitmap(inner,tb->cut,tablength,masklo,maskhi,tb->nmask,tb->nshiftbits);
int ntable = 1 << tablength;
int ntablem1 = ntable - 1;
memory->create(tb->rsq,ntable,"pair:rsq");
memory->create(tb->e,ntable,"pair:e");
memory->create(tb->f,ntable,"pair:f");
memory->create(tb->de,ntable,"pair:de");
memory->create(tb->df,ntable,"pair:df");
memory->create(tb->drsq,ntable,"pair:drsq");
union_int_float_t minrsq_lookup;
minrsq_lookup.i = 0 << tb->nshiftbits;
minrsq_lookup.i |= maskhi;
for (int i = 0; i < ntable; i++) {
rsq_lookup.i = i << tb->nshiftbits;
rsq_lookup.i |= masklo;
if (rsq_lookup.f < tb->innersq) {
rsq_lookup.i = i << tb->nshiftbits;
rsq_lookup.i |= maskhi;
}
r = sqrtf(rsq_lookup.f);
tb->rsq[i] = rsq_lookup.f;
if (tb->match) {
tb->e[i] = tb->efile[i];
tb->f[i] = tb->ffile[i]/r;
} else {
tb->e[i] = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r);
tb->f[i] = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r;
}
minrsq_lookup.f = MIN(minrsq_lookup.f,rsq_lookup.f);
}
tb->innersq = minrsq_lookup.f;
for (int i = 0; i < ntablem1; i++) {
tb->de[i] = tb->e[i+1] - tb->e[i];
tb->df[i] = tb->f[i+1] - tb->f[i];
tb->drsq[i] = 1.0/(tb->rsq[i+1] - tb->rsq[i]);
}
// get the delta values for the last table entries
// tables are connected periodically between 0 and ntablem1
tb->de[ntablem1] = tb->e[0] - tb->e[ntablem1];
tb->df[ntablem1] = tb->f[0] - tb->f[ntablem1];
tb->drsq[ntablem1] = 1.0/(tb->rsq[0] - tb->rsq[ntablem1]);
// get the correct delta values at itablemax
// smallest r is in bin itablemin
// largest r is in bin itablemax, which is itablemin-1,
// or ntablem1 if itablemin=0
// deltas at itablemax only needed if corresponding rsq < cut*cut
// if so, compute deltas between rsq and cut*cut
// if tb->match, data at cut*cut is unavailable, so we'll take
// deltas at itablemax-1 as a good approximation
double e_tmp,f_tmp;
int itablemin = minrsq_lookup.i & tb->nmask;
itablemin >>= tb->nshiftbits;
int itablemax = itablemin - 1;
if (itablemin == 0) itablemax = ntablem1;
int itablemaxm1 = itablemax - 1;
if (itablemax == 0) itablemaxm1 = ntablem1;
rsq_lookup.i = itablemax << tb->nshiftbits;
rsq_lookup.i |= maskhi;
if (rsq_lookup.f < tb->cut*tb->cut) {
if (tb->match) {
tb->de[itablemax] = tb->de[itablemaxm1];
tb->df[itablemax] = tb->df[itablemaxm1];
tb->drsq[itablemax] = tb->drsq[itablemaxm1];
} else {
rsq_lookup.f = tb->cut*tb->cut;
r = sqrtf(rsq_lookup.f);
e_tmp = splint(tb->rfile,tb->efile,tb->e2file,tb->ninput,r);
f_tmp = splint(tb->rfile,tb->ffile,tb->f2file,tb->ninput,r)/r;
tb->de[itablemax] = e_tmp - tb->e[itablemax];
tb->df[itablemax] = f_tmp - tb->f[itablemax];
tb->drsq[itablemax] = 1.0/(rsq_lookup.f - tb->rsq[itablemax]);
}
}
}
}
/* ----------------------------------------------------------------------
set all ptrs in a table to NULL, so can be freed safely
------------------------------------------------------------------------- */
void PairTable::null_table(Table *tb)
{
tb->rfile = tb->efile = tb->ffile = NULL;
tb->e2file = tb->f2file = NULL;
tb->rsq = tb->drsq = tb->e = tb->de = NULL;
tb->f = tb->df = tb->e2 = tb->f2 = NULL;
}
/* ----------------------------------------------------------------------
free all arrays in a table
------------------------------------------------------------------------- */
void PairTable::free_table(Table *tb)
{
memory->destroy(tb->rfile);
memory->destroy(tb->efile);
memory->destroy(tb->ffile);
memory->destroy(tb->e2file);
memory->destroy(tb->f2file);
memory->destroy(tb->rsq);
memory->destroy(tb->drsq);
memory->destroy(tb->e);
memory->destroy(tb->de);
memory->destroy(tb->f);
memory->destroy(tb->df);
memory->destroy(tb->e2);
memory->destroy(tb->f2);
}
/* ----------------------------------------------------------------------
spline and splint routines modified from Numerical Recipes
------------------------------------------------------------------------- */
void PairTable::spline(double *x, double *y, int n,
double yp1, double ypn, double *y2)
{
int i,k;
double p,qn,sig,un;
double *u = new double[n];
if (yp1 > 0.99e30) y2[0] = u[0] = 0.0;
else {
y2[0] = -0.5;
u[0] = (3.0/(x[1]-x[0])) * ((y[1]-y[0]) / (x[1]-x[0]) - yp1);
}
for (i = 1; i < n-1; i++) {
sig = (x[i]-x[i-1]) / (x[i+1]-x[i-1]);
p = sig*y2[i-1] + 2.0;
y2[i] = (sig-1.0) / p;
u[i] = (y[i+1]-y[i]) / (x[i+1]-x[i]) - (y[i]-y[i-1]) / (x[i]-x[i-1]);
u[i] = (6.0*u[i] / (x[i+1]-x[i-1]) - sig*u[i-1]) / p;
}
if (ypn > 0.99e30) qn = un = 0.0;
else {
qn = 0.5;
un = (3.0/(x[n-1]-x[n-2])) * (ypn - (y[n-1]-y[n-2]) / (x[n-1]-x[n-2]));
}
y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2] + 1.0);
for (k = n-2; k >= 0; k--) y2[k] = y2[k]*y2[k+1] + u[k];
delete [] u;
}
/* ---------------------------------------------------------------------- */
double PairTable::splint(double *xa, double *ya, double *y2a, int n, double x)
{
int klo,khi,k;
double h,b,a,y;
klo = 0;
khi = n-1;
while (khi-klo > 1) {
k = (khi+klo) >> 1;
if (xa[k] > x) khi = k;
else klo = k;
}
h = xa[khi]-xa[klo];
a = (xa[khi]-x) / h;
b = (x-xa[klo]) / h;
y = a*ya[klo] + b*ya[khi] +
((a*a*a-a)*y2a[klo] + (b*b*b-b)*y2a[khi]) * (h*h)/6.0;
return y;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairTable::write_restart(FILE *fp)
{
write_restart_settings(fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairTable::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairTable::write_restart_settings(FILE *fp)
{
fwrite(&tabstyle,sizeof(int),1,fp);
fwrite(&tablength,sizeof(int),1,fp);
fwrite(&ewaldflag,sizeof(int),1,fp);
fwrite(&pppmflag,sizeof(int),1,fp);
fwrite(&msmflag,sizeof(int),1,fp);
fwrite(&dispersionflag,sizeof(int),1,fp);
fwrite(&tip4pflag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairTable::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&tabstyle,sizeof(int),1,fp);
fread(&tablength,sizeof(int),1,fp);
fread(&ewaldflag,sizeof(int),1,fp);
fread(&pppmflag,sizeof(int),1,fp);
fread(&msmflag,sizeof(int),1,fp);
fread(&dispersionflag,sizeof(int),1,fp);
fread(&tip4pflag,sizeof(int),1,fp);
}
MPI_Bcast(&tabstyle,1,MPI_INT,0,world);
MPI_Bcast(&tablength,1,MPI_INT,0,world);
MPI_Bcast(&ewaldflag,1,MPI_INT,0,world);
MPI_Bcast(&pppmflag,1,MPI_INT,0,world);
MPI_Bcast(&msmflag,1,MPI_INT,0,world);
MPI_Bcast(&dispersionflag,1,MPI_INT,0,world);
MPI_Bcast(&tip4pflag,1,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
double PairTable::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
int itable;
double fraction,value,a,b,phi;
int tlm1 = tablength - 1;
Table *tb = &tables[tabindex[itype][jtype]];
if (rsq < tb->innersq) error->one(FLERR,"Pair distance < table inner cutoff");
if (tabstyle == LOOKUP) {
itable = static_cast<int> ((rsq-tb->innersq) * tb->invdelta);
if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff");
fforce = factor_lj * tb->f[itable];
} else if (tabstyle == LINEAR) {
itable = static_cast<int> ((rsq-tb->innersq) * tb->invdelta);
if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff");
fraction = (rsq - tb->rsq[itable]) * tb->invdelta;
value = tb->f[itable] + fraction*tb->df[itable];
fforce = factor_lj * value;
} else if (tabstyle == SPLINE) {
itable = static_cast<int> ((rsq-tb->innersq) * tb->invdelta);
if (itable >= tlm1) error->one(FLERR,"Pair distance > table outer cutoff");
b = (rsq - tb->rsq[itable]) * tb->invdelta;
a = 1.0 - b;
value = a * tb->f[itable] + b * tb->f[itable+1] +
((a*a*a-a)*tb->f2[itable] + (b*b*b-b)*tb->f2[itable+1]) *
tb->deltasq6;
fforce = factor_lj * value;
} else {
union_int_float_t rsq_lookup;
rsq_lookup.f = rsq;
itable = rsq_lookup.i & tb->nmask;
itable >>= tb->nshiftbits;
fraction = (rsq_lookup.f - tb->rsq[itable]) * tb->drsq[itable];
value = tb->f[itable] + fraction*tb->df[itable];
fforce = factor_lj * value;
}
if (tabstyle == LOOKUP)
phi = tb->e[itable];
else if (tabstyle == LINEAR || tabstyle == BITMAP)
phi = tb->e[itable] + fraction*tb->de[itable];
else
phi = a * tb->e[itable] + b * tb->e[itable+1] +
((a*a*a-a)*tb->e2[itable] + (b*b*b-b)*tb->e2[itable+1]) * tb->deltasq6;
return factor_lj*phi;
}
/* ----------------------------------------------------------------------
return the Coulomb cutoff for tabled potentials
called by KSpace solvers which require that all pairwise cutoffs be the same
loop over all tables not just those indexed by tabindex[i][j] since
no way to know which tables are active since pair::init() not yet called
------------------------------------------------------------------------- */
void *PairTable::extract(const char *str, int &dim)
{
if (strcmp(str,"cut_coul") != 0) return NULL;
if (ntables == 0) error->all(FLERR,"All pair coeffs are not set");
double cut_coul = tables[0].cut;
for (int m = 1; m < ntables; m++)
if (tables[m].cut != cut_coul)
error->all(FLERR,
"Pair table cutoffs must all be equal to use with KSpace");
dim = 0;
return &tables[0].cut;
}
diff --git a/src/pair_yukawa.cpp b/src/pair_yukawa.cpp
index 0e5fd36cd..2ba6633d9 100644
--- a/src/pair_yukawa.cpp
+++ b/src/pair_yukawa.cpp
@@ -1,338 +1,338 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include <math.h>
#include <stdlib.h>
#include "pair_yukawa.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairYukawa::PairYukawa(LAMMPS *lmp) : Pair(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
PairYukawa::~PairYukawa()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(rad);
memory->destroy(cut);
memory->destroy(a);
memory->destroy(offset);
}
}
/* ---------------------------------------------------------------------- */
void PairYukawa::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,r2inv,r,rinv,screening,forceyukawa,factor;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
int nlocal = atom->nlocal;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor = special_lj[sbmask(j)];
j &= NEIGHMASK;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
r2inv = 1.0/rsq;
r = sqrt(rsq);
rinv = 1.0/r;
screening = exp(-kappa*r);
forceyukawa = a[itype][jtype] * screening * (kappa + rinv);
fpair = factor*forceyukawa * r2inv;
f[i][0] += delx*fpair;
f[i][1] += dely*fpair;
f[i][2] += delz*fpair;
if (newton_pair || j < nlocal) {
f[j][0] -= delx*fpair;
f[j][1] -= dely*fpair;
f[j][2] -= delz*fpair;
}
if (eflag) {
evdwl = a[itype][jtype] * screening * rinv - offset[itype][jtype];
evdwl *= factor;
}
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairYukawa::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(rad,n+1,"pair:rad");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(a,n+1,n+1,"pair:a");
memory->create(offset,n+1,n+1,"pair:offset");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairYukawa::settings(int narg, char **arg)
{
if (narg != 2) error->all(FLERR,"Illegal pair_style command");
kappa = force->numeric(FLERR,arg[0]);
cut_global = force->numeric(FLERR,arg[1]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairYukawa::coeff(int narg, char **arg)
{
if (narg < 3 || narg > 4)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
double a_one = force->numeric(FLERR,arg[2]);
double cut_one = cut_global;
if (narg == 4) cut_one = force->numeric(FLERR,arg[3]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
a[i][j] = a_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairYukawa::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
a[i][j] = mix_energy(a[i][i],a[j][j],1.0,1.0);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
- if (offset_flag) {
+ if (offset_flag && (cut[i][j] > 0.0)) {
double screening = exp(-kappa * cut[i][j]);
offset[i][j] = a[i][j] * screening / cut[i][j];
} else offset[i][j] = 0.0;
a[j][i] = a[i][j];
offset[j][i] = offset[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairYukawa::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&a[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairYukawa::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&a[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&a[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairYukawa::write_restart_settings(FILE *fp)
{
fwrite(&kappa,sizeof(double),1,fp);
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairYukawa::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&kappa,sizeof(double),1,fp);
fread(&cut_global,sizeof(double),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&kappa,1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void PairYukawa::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
fprintf(fp,"%d %g\n",i,a[i][i]);
}
/* ----------------------------------------------------------------------
proc 0 writes all pairs to data file
------------------------------------------------------------------------- */
void PairYukawa::write_data_all(FILE *fp)
{
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
fprintf(fp,"%d %d %g %g\n",i,j,a[i][j],cut[i][j]);
}
/* ---------------------------------------------------------------------- */
double PairYukawa::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double r2inv,r,rinv,screening,forceyukawa,phi;
r2inv = 1.0/rsq;
r = sqrt(rsq);
rinv = 1.0/r;
screening = exp(-kappa*r);
forceyukawa = a[itype][jtype] * screening * (kappa + rinv);
fforce = factor_lj*forceyukawa * r2inv;
phi = a[itype][jtype] * screening * rinv - offset[itype][jtype];
return factor_lj*phi;
}
diff --git a/src/version.h b/src/version.h
index 3fbe23832..c55566c88 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define LAMMPS_VERSION "6 Jul 2017"
+#define LAMMPS_VERSION "24 Jul 2017"

Event Timeline