Page MenuHomec4science

No OneTemporary

File Metadata

Created
Thu, Oct 3, 00:46
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/doc/Manual.html b/doc/Manual.html
index 5404e8d7f..db3489fb6 100644
--- a/doc/Manual.html
+++ b/doc/Manual.html
@@ -1,435 +1,435 @@
<HTML>
<HEAD>
<TITLE>LAMMPS-ICMS Users Manual</TITLE>
<META NAME="docnumber" CONTENT="24 Jan 2013 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>
<CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A>
</CENTER>
<HR>
<H1></H1>
<CENTER><H3>LAMMPS-ICMS Documentation
</H3></CENTER>
-<CENTER><H4>13 Jan 2014 version
+<CENTER><H4>17 Jan 2014 version
</H4></CENTER>
<H4>Version info:
</H4>
<P>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 <A HREF = "http://lammps.sandia.gov/bug.html">this page of
the WWW site</A>. 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).
</P>
<P>LAMMPS-ICMS is an experimental variant of LAMMPS with additional
features made available for testing before they will be submitted
for inclusion into the official LAMMPS tree. The source code is
based on the official LAMMPS svn repository mirror at the Institute
for Computational Molecular Science at Temple University and generally
kept up-to-date as much as possible. Sometimes, e.g. when additional
development work is needed to adapt the upstream changes into
LAMMPS-ICMS it can take longer until synchronization; and occasionally,
e.g. in case of the rewrite of the multi-threading support, the
development will be halted except for important bugfixes until
all features of LAMMPS-ICMS fully compatible with the upstream
version or replaced by alternate implementations.
</P>
<UL><LI>If you browse the HTML doc pages on the LAMMPS WWW site, they always
describe the most current version of upstream LAMMPS, but may be
missing some new features in LAMMPS-ICMS.
<LI>If you browse the HTML doc pages included in your tarball, they
describe the version you have, however, not all new features in
LAMMPS-ICMS are documented immediately.
<LI>The <A HREF = "Manual.pdf">PDF file</A> 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.
<LI>There is also a <A HREF = "Developer.pdf">Developer.pdf</A> file in the doc
directory, which describes the internal structure and algorithms of
LAMMPS.
</UL>
<P>LAMMPS stands for Large-scale Atomic/Molecular Massively Parallel
Simulator.
</P>
<P>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).
</P>
<P>The primary developers of LAMMPS are <A HREF = "http://www.sandia.gov/~sjplimp">Steve Plimpton</A>, Aidan
Thompson, and Paul Crozier who can be contacted at
sjplimp,athomps,pscrozi at sandia.gov. The <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> at
http://lammps.sandia.gov has more information about the code and its
uses.
</P>
<HR>
<P>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.
</P>
<P>Once you are familiar with LAMMPS, you may want to bookmark <A HREF = "Section_commands.html#comm">this
page</A> at Section_commands.html#comm since
it gives quick access to documentation for all LAMMPS commands.
</P>
<P><A HREF = "Manual.pdf">PDF file</A> of the entire manual, generated by
<A HREF = "http://www.easysw.com/htmldoc">htmldoc</A>
</P>
<OL><LI><A HREF = "Section_intro.html">Introduction</A>
<UL> 1.1 <A HREF = "Section_intro.html#intro_1">What is LAMMPS</A>
<BR>
1.2 <A HREF = "Section_intro.html#intro_2">LAMMPS features</A>
<BR>
1.3 <A HREF = "Section_intro.html#intro_3">LAMMPS non-features</A>
<BR>
1.4 <A HREF = "Section_intro.html#intro_4">Open source distribution</A>
<BR>
1.5 <A HREF = "Section_intro.html#intro_5">Acknowledgments and citations</A>
<BR></UL>
<LI><A HREF = "Section_start.html">Getting started</A>
<UL> 2.1 <A HREF = "Section_start.html#start_1">What's in the LAMMPS distribution</A>
<BR>
2.2 <A HREF = "Section_start.html#start_2">Making LAMMPS</A>
<BR>
2.3 <A HREF = "Section_start.html#start_3">Making LAMMPS with optional packages</A>
<BR>
2.4 <A HREF = "Section_start.html#start_4">Building LAMMPS via the Make.py script</A>
<BR>
2.5 <A HREF = "Section_start.html#start_5">Building LAMMPS as a library</A>
<BR>
2.6 <A HREF = "Section_start.html#start_6">Running LAMMPS</A>
<BR>
2.7 <A HREF = "Section_start.html#start_7">Command-line options</A>
<BR>
2.8 <A HREF = "Section_start.html#start_8">Screen output</A>
<BR>
2.9 <A HREF = "Section_start.html#start_9">Tips for users of previous versions</A>
<BR></UL>
<LI><A HREF = "Section_commands.html">Commands</A>
<UL> 3.1 <A HREF = "Section_commands.html#cmd_1">LAMMPS input script</A>
<BR>
3.2 <A HREF = "Section_commands.html#cmd_2">Parsing rules</A>
<BR>
3.3 <A HREF = "Section_commands.html#cmd_3">Input script structure</A>
<BR>
3.4 <A HREF = "Section_commands.html#cmd_4">Commands listed by category</A>
<BR>
3.5 <A HREF = "Section_commands.html#cmd_5">Commands listed alphabetically</A>
<BR></UL>
<LI><A HREF = "Section_packages.html">Packages</A>
<UL> 4.1 <A HREF = "Section_packages.html#pkg_1">Standard packages</A>
<BR>
4.2 <A HREF = "Section_packages.html#pkg_2">User packages</A>
<BR></UL>
<LI><A HREF = "Section_accelerate.html">Accelerating LAMMPS performance</A>
<UL> 5.1 <A HREF = "Section_accelerate.html#acc_1">Measuring performance</A>
<BR>
5.2 <A HREF = "Section_accelerate.html#acc_2">General strategies</A>
<BR>
5.3 <A HREF = "Section_accelerate.html#acc_3">Packages with optimized styles</A>
<BR>
5.4 <A HREF = "Section_accelerate.html#acc_4">OPT package</A>
<BR>
5.5 <A HREF = "Section_accelerate.html#acc_5">USER-OMP package</A>
<BR>
5.6 <A HREF = "Section_accelerate.html#acc_6">GPU package</A>
<BR>
5.7 <A HREF = "Section_accelerate.html#acc_7">USER-CUDA package</A>
<BR>
5.8 <A HREF = "Section_accelerate.html#acc_8">Comparison of GPU and USER-CUDA packages</A>
<BR></UL>
<LI><A HREF = "Section_howto.html">How-to discussions</A>
<UL> 6.1 <A HREF = "Section_howto.html#howto_1">Restarting a simulation</A>
<BR>
6.2 <A HREF = "Section_howto.html#howto_2">2d simulations</A>
<BR>
6.3 <A HREF = "Section_howto.html#howto_3">CHARMM and AMBER force fields</A>
<BR>
6.4 <A HREF = "Section_howto.html#howto_4">Running multiple simulations from one input script</A>
<BR>
6.5 <A HREF = "Section_howto.html#howto_5">Multi-replica simulations</A>
<BR>
6.6 <A HREF = "Section_howto.html#howto_6">Granular models</A>
<BR>
6.7 <A HREF = "Section_howto.html#howto_7">TIP3P water model</A>
<BR>
6.8 <A HREF = "Section_howto.html#howto_8">TIP4P water model</A>
<BR>
6.9 <A HREF = "Section_howto.html#howto_9">SPC water model</A>
<BR>
6.10 <A HREF = "Section_howto.html#howto_10">Coupling LAMMPS to other codes</A>
<BR>
6.11 <A HREF = "Section_howto.html#howto_11">Visualizing LAMMPS snapshots</A>
<BR>
6.12 <A HREF = "Section_howto.html#howto_12">Triclinic (non-orthogonal) simulation boxes</A>
<BR>
6.13 <A HREF = "Section_howto.html#howto_13">NEMD simulations</A>
<BR>
6.14 <A HREF = "Section_howto.html#howto_14">Finite-size spherical and aspherical particles</A>
<BR>
6.15 <A HREF = "Section_howto.html#howto_15">Output from LAMMPS (thermo, dumps, computes, fixes, variables)</A>
<BR>
6.16 <A HREF = "Section_howto.html#howto_16">Thermostatting, barostatting, and compute temperature</A>
<BR>
6.17 <A HREF = "Section_howto.html#howto_17">Walls</A>
<BR>
6.18 <A HREF = "Section_howto.html#howto_18">Elastic constants</A>
<BR>
6.19 <A HREF = "Section_howto.html#howto_19">Library interface to LAMMPS</A>
<BR>
6.20 <A HREF = "Section_howto.html#howto_20">Calculating thermal conductivity</A>
<BR>
6.21 <A HREF = "Section_howto.html#howto_21">Calculating viscosity</A>
<BR></UL>
<LI><A HREF = "Section_example.html">Example problems</A>
<LI><A HREF = "Section_perf.html">Performance & scalability</A>
<LI><A HREF = "Section_tools.html">Additional tools</A>
<LI><A HREF = "Section_modify.html">Modifying & extending LAMMPS</A>
<UL> 10.1 <A HREF = "Section_modify.html#mod_1">Atom styles</A>
<BR>
10.2 <A HREF = "Section_modify.html#mod_2">Bond, angle, dihedral, improper potentials</A>
<BR>
10.3 <A HREF = "Section_modify.html#mod_3">Compute styles</A>
<BR>
10.4 <A HREF = "Section_modify.html#mod_4">Dump styles</A>
<BR>
10.5 <A HREF = "Section_modify.html#mod_5">Dump custom output options</A>
<BR>
10.6 <A HREF = "Section_modify.html#mod_6">Fix styles</A>
<BR>
10.7 <A HREF = "Section_modify.html#mod_7">Input script commands</A>
<BR>
10.8 <A HREF = "Section_modify.html#mod_8">Kspace computations</A>
<BR>
10.9 <A HREF = "Section_modify.html#mod_9">Minimization styles</A>
<BR>
10.10 <A HREF = "Section_modify.html#mod_10">Pairwise potentials</A>
<BR>
10.11 <A HREF = "Section_modify.html#mod_11">Region styles</A>
<BR>
10.12 <A HREF = "Section_modify.html#mod_12">Body styles</A>
<BR>
10.13 <A HREF = "Section_modify.html#mod_13">Thermodynamic output options</A>
<BR>
10.14 <A HREF = "Section_modify.html#mod_14">Variable options</A>
<BR>
10.15 <A HREF = "Section_modify.html#mod_15">Submitting new features for inclusion in LAMMPS</A>
<BR></UL>
<LI><A HREF = "Section_python.html">Python interface</A>
<UL> 11.1 <A HREF = "Section_python.html#py_1">Building LAMMPS as a shared library</A>
<BR>
11.2 <A HREF = "Section_python.html#py_2">Installing the Python wrapper into Python</A>
<BR>
11.3 <A HREF = "Section_python.html#py_3">Extending Python with MPI to run in parallel</A>
<BR>
11.4 <A HREF = "Section_python.html#py_4">Testing the Python-LAMMPS interface</A>
<BR>
11.5 <A HREF = "Section_python.html#py_5">Using LAMMPS from Python</A>
<BR>
11.6 <A HREF = "Section_python.html#py_6">Example Python scripts that use LAMMPS</A>
<BR></UL>
<LI><A HREF = "Section_errors.html">Errors</A>
<UL> 12.1 <A HREF = "Section_errors.html#err_1">Common problems</A>
<BR>
12.2 <A HREF = "Section_errors.html#err_2">Reporting bugs</A>
<BR>
12.3 <A HREF = "Section_errors.html#err_3">Error & warning messages</A>
<BR></UL>
<LI><A HREF = "Section_history.html">Future and history</A>
<UL> 13.1 <A HREF = "Section_history.html#hist_1">Coming attractions</A>
<BR>
13.2 <A HREF = "Section_history.html#hist_2">Past versions</A>
<BR></UL>
</OL>
</BODY>
</HTML>
diff --git a/doc/Manual.txt b/doc/Manual.txt
index 857c924ce..de4d8f18a 100644
--- a/doc/Manual.txt
+++ b/doc/Manual.txt
@@ -1,273 +1,273 @@
<HEAD>
<TITLE>LAMMPS-ICMS Users Manual</TITLE>
<META NAME="docnumber" CONTENT="24 Jan 2013 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>
"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-ICMS Documentation :c,h3
-13 Jan 2014 version :c,h4
+17 Jan 2014 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. 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).
LAMMPS-ICMS is an experimental variant of LAMMPS with additional
features made available for testing before they will be submitted
for inclusion into the official LAMMPS tree. The source code is
based on the official LAMMPS svn repository mirror at the Institute
for Computational Molecular Science at Temple University and generally
kept up-to-date as much as possible. Sometimes, e.g. when additional
development work is needed to adapt the upstream changes into
LAMMPS-ICMS it can take longer until synchronization; and occasionally,
e.g. in case of the rewrite of the multi-threading support, the
development will be halted except for important bugfixes until
all features of LAMMPS-ICMS fully compatible with the upstream
version or replaced by alternate implementations.
If you browse the HTML doc pages on the LAMMPS WWW site, they always
describe the most current version of upstream LAMMPS, but may be
missing some new features in LAMMPS-ICMS. :ulb,l
If you browse the HTML doc pages included in your tarball, they
describe the version you have, however, not all new features in
LAMMPS-ICMS are documented immediately. :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. :ule,l
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 primary developers of LAMMPS are "Steve Plimpton"_sjp, Aidan
Thompson, and Paul Crozier who can be contacted at
sjplimp,athomps,pscrozi at sandia.gov. The "LAMMPS WWW Site"_lws at
http://lammps.sandia.gov has more information about the code and its
uses.
:link(bug,http://lammps.sandia.gov/bug.html)
:link(sjp,http://www.sandia.gov/~sjplimp)
: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://www.easysw.com/htmldoc
"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 via the Make.py script"_start_4 :b
2.5 "Building LAMMPS as a library"_start_5 :b
2.6 "Running LAMMPS"_start_6 :b
2.7 "Command-line options"_start_7 :b
2.8 "Screen output"_start_8 :b
2.9 "Tips for users of previous versions"_start_9 :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 "General strategies"_acc_2 :b
5.3 "Packages with optimized styles"_acc_3 :b
5.4 "OPT package"_acc_4 :b
5.5 "USER-OMP package"_acc_5 :b
5.6 "GPU package"_acc_6 :b
5.7 "USER-CUDA package"_acc_7 :b
5.8 "Comparison of GPU and USER-CUDA packages"_acc_8 :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 :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 "Building LAMMPS as a shared library"_py_1 :ulb,b
11.2 "Installing the Python wrapper into Python"_py_2 :b
11.3 "Extending Python with MPI to run in parallel"_py_3 :b
11.4 "Testing the Python-LAMMPS interface"_py_4 :b
11.5 "Using LAMMPS from Python"_py_5 :b
11.6 "Example Python scripts that use LAMMPS"_py_6 :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(acc_5,Section_accelerate.html#acc_5)
:link(acc_6,Section_accelerate.html#acc_6)
:link(acc_7,Section_accelerate.html#acc_7)
:link(acc_8,Section_accelerate.html#acc_8)
: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(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)
</BODY>
diff --git a/doc/Section_accelerate.html b/doc/Section_accelerate.html
index 3310eec99..f526ee076 100644
--- a/doc/Section_accelerate.html
+++ b/doc/Section_accelerate.html
@@ -1,721 +1,722 @@
<HTML>
<CENTER><A HREF = "Section_packages.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> -
<A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_howto.html">Next
Section</A>
</CENTER>
<HR>
<H3>5. Accelerating LAMMPS performance
</H3>
<P>This section describes various methods for improving LAMMPS
performance for different classes of problems running on different
kinds of machines.
</P>
5.1 <A HREF = "#acc_1">Measuring performance</A><BR>
5.2 <A HREF = "#acc_2">General strategies</A><BR>
5.3 <A HREF = "#acc_3">Packages with optimized styles</A><BR>
5.4 <A HREF = "#acc_4">OPT package</A><BR>
5.5 <A HREF = "#acc_5">USER-OMP package</A><BR>
5.6 <A HREF = "#acc_6">GPU package</A><BR>
5.7 <A HREF = "#acc_7">USER-CUDA package</A><BR>
5.8 <A HREF = "#acc_8">Comparison of GPU and USER-CUDA packages</A> <BR>
<HR>
<HR>
<H4><A NAME = "acc_1"></A>5.1 Measuring performance
</H4>
<P>Before trying to make your simulation run faster, you should
understand how it currently performs and where the bottlenecks are.
</P>
<P>The best way to do this is run the your system (actual number of
atoms) for a modest number of timesteps (say 100, or a few 100 at
most) 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 or timesteps
to get accurate timings; you can simply extrapolate from short runs.
</P>
<P>For the set of runs, look at the timing data printed to the screen and
log file at the end of each LAMMPS run. <A HREF = "Section_start.html#start_8">This
section</A> of the manual has an overview.
</P>
<P>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.
</P>
<P>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.
</P>
<P>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.
</P>
<HR>
<H4><A NAME = "acc_2"></A>5.2 General strategies
</H4>
<P>NOTE: this sub-section is still a work in progress
</P>
<P>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
-intially 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 your problem and your machine. There is no substitute for
-simply trying them out.
+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.
</P>
<UL><LI>rRESPA
<LI>2-FFT PPPM
<LI>Staggered PPPM
<LI>single vs double PPPM
<LI>partial charge PPPM
<LI>verlet/split
<LI>processor mapping via processors numa command
<LI>load-balancing: balance and fix balance
<LI>processor command for layout
<LI>OMP when lots of cores
</UL>
<P>2-FFT PPPM, also called <I>analytic differentiation</I> or <I>ad</I> PPPM, uses
2 FFTs instead of the 4 FFTs used by the default <I>ik differentiation</I>
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.
</P>
<P>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.
</P>
<CENTER><IMG SRC = "JPG/rhodo_staggered.jpg">
</CENTER>
<P>IMPORTANT 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.
</P>
<HR>
<H4><A NAME = "acc_3"></A>5.3 Packages with optimized styles
</H4>
<P>Accelerated versions of various <A HREF = "pair_style.html">pair_style</A>,
<A HREF = "fix.html">fixes</A>, <A HREF = "compute.html">computes</A>, and other commands have
been added to LAMMPS, which will typically run faster than the
standard non-accelerated versions, if you have the appropriate
hardware on your system.
</P>
<P>The accelerated styles have the same name as the standard styles,
except that a suffix is appended. Otherwise, the syntax for the
command is identical, their functionality is the same, and the
numerical results it produces should also be identical, except for
precision and round-off issues.
</P>
<P>For example, all of these variants of the basic Lennard-Jones pair
style exist in LAMMPS:
</P>
<UL><LI><A HREF = "pair_lj.html">pair_style lj/cut</A>
<LI><A HREF = "pair_lj.html">pair_style lj/cut/opt</A>
<LI><A HREF = "pair_lj.html">pair_style lj/cut/omp</A>
<LI><A HREF = "pair_lj.html">pair_style lj/cut/gpu</A>
<LI><A HREF = "pair_lj.html">pair_style lj/cut/cuda</A>
</UL>
<P>Assuming you have built LAMMPS with the appropriate package, these
styles can be invoked by specifying them explicitly in your input
script. Or you can use the <A HREF = "Section_start.html#start_7">-suffix command-line
switch</A> to invoke the accelerated versions
automatically, without changing your input script. The
<A HREF = "suffix.html">suffix</A> command allows you to set a suffix explicitly and
to turn off/on the comand-line switch setting, both from within your
input script.
</P>
<P>Styles with an "opt" suffix are part of the OPT package and typically
speed-up the pairwise calculations of your simulation by 5-25%.
</P>
<P>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.
</P>
<P>Styles with a "gpu" or "cuda" suffix are part of the GPU or USER-CUDA
packages, and can be run on NVIDIA GPUs associated with your CPUs.
The speed-up due to GPU usage depends on a variety of factors, as
discussed below.
</P>
<P>To see what styles are currently available in each of the accelerated
packages, see <A HREF = "Section_commands.html#cmd_5">Section_commands 5</A> of the
manual. A list of accelerated styles is included in the pair, fix,
compute, and kspace sections.
</P>
<P>The following sections explain:
</P>
<UL><LI>what hardware and software the accelerated styles require
<LI>how to build LAMMPS with the accelerated packages in place
<LI>what changes (if any) are needed in your input scripts
<LI>guidelines for best performance
<LI>speed-ups you can expect
</UL>
<P>The final section compares and contrasts the GPU and USER-CUDA
packages, since they are both designed to use NVIDIA GPU hardware.
</P>
<HR>
<H4><A NAME = "acc_4"></A>5.4 OPT package
</H4>
<P>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.
</P>
<P>The procedure for building LAMMPS with the OPT package is simple. It
is the same as for any other package which has no additional library
dependencies:
</P>
<PRE>make yes-opt
make machine
</PRE>
<P>If your input script uses one of the OPT pair styles,
you can run it as follows:
</P>
<PRE>lmp_machine -sf opt < in.script
mpirun -np 4 lmp_machine -sf opt < in.script
</PRE>
<P>You should see a reduction in the "Pair time" printed out at the end
of the run. On most machines and problems, this will typically be a 5
to 20% savings.
</P>
<HR>
<H4><A NAME = "acc_5"></A>5.5 USER-OMP package
</H4>
<P>The USER-OMP package was developed by Axel Kohlmeyer at Temple University.
It provides multi-threaded versions of most pair styles, all dihedral
styles and a few fixes in LAMMPS. The package currently uses the OpenMP
interface which requires using a specific compiler flag in the makefile
to enable multiple threads; without this flag the corresponding pair
styles will still be compiled and work, but do not support multi-threading.
</P>
<P><B>Building LAMMPS with the USER-OMP package:</B>
</P>
<P>The procedure for building LAMMPS with the USER-OMP package is simple.
You have to edit your machine specific makefile to add the flag to
enable OpenMP support to the CCFLAGS and LINKFLAGS variables. For the
GNU compilers for example this flag is called <I>-fopenmp</I>. Check your
compiler documentation to find out which flag you need to add.
The rest of the compilation is the same as for any other package which
has no additional library dependencies:
</P>
<PRE>make yes-user-omp
make machine
</PRE>
<P>Please note that this will only install accelerated versions
of styles that are already installed, so you want to install
this package as the last package, or else you may be missing
some accelerated styles. If you plan to uninstall some package,
you should first uninstall the USER-OMP package then the other
package and then re-install USER-OMP, to make sure that there
are no orphaned <I>omp</I> style files present, which would lead to
compilation errors.
</P>
<P>If your input script uses one of regular styles that are also
exist as an OpenMP version in the USER-OMP package you can run
it as follows:
</P>
<PRE>env OMP_NUM_THREADS=4 lmp_serial -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>
<P>The value of the environment variable OMP_NUM_THREADS determines how
many threads per MPI task are launched. All three examples above use
a total of 4 CPU cores. For different MPI implementations the method
to pass the OMP_NUM_THREADS environment variable to all processes is
different. Two different variants, one for MPICH and OpenMPI, respectively
are shown above. Please check the documentation of your MPI installation
for additional details. Alternatively, the value provided by OMP_NUM_THREADS
can be overridded with the <A HREF = "package.html">package omp</A> command.
Depending on which styles are accelerated in your input, you should
see a reduction in the "Pair time" and/or "Bond time" and "Loop time"
printed out at the end of the run. The optimal ratio of MPI to OpenMP
can vary a lot and should always be confirmed through some benchmark
runs for the current system and on the current machine.
</P>
<P><B>Restrictions:</B>
</P>
<P>None of the pair styles in the USER-OMP package support the "inner",
"middle", "outer" options for r-RESPA integration, only the "pair"
option is supported.
</P>
<P><B>Parallel efficiency and performance tips:</B>
</P>
<P>In most simple cases the MPI parallelization in LAMMPS is more
efficient than multi-threading implemented in the USER-OMP package.
Also the parallel efficiency varies between individual styles.
On the other hand, in many cases you still want to use the <I>omp</I> version
- even when compiling or running without OpenMP support - since they
all contain optimizations similar to those in the OPT package, which
can result in serial speedup.
</P>
<P>Using multi-threading is most effective under the following circumstances:
</P>
<UL><LI>Individual compute nodes have a significant number of CPU cores
but the CPU itself has limited memory bandwidth, e.g. 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
nodes is faster. Running in hybrid MPI+OpenMP mode will reduce the
inter-node communication bandwidth contention in the same way,
but offers and additional speedup from utilizing the otherwise
idle CPU cores.
<LI>The interconnect used for MPI communication is not able to provide
sufficient bandwidth for a large number of MPI tasks per node.
This applies for example to running over gigabit ethernet or
on Cray XT4 or XT5 series supercomputers. Same as in the aforementioned
case this effect worsens with using an increasing number of nodes.
<LI>The input is a system that has an inhomogeneous particle density
which cannot be mapped well to the domain decomposition scheme
that LAMMPS employs. While this can be to some degree alleviated
through using the <A HREF = "processors.html">processors</A> keyword, multi-threading
provides a parallelism that parallelizes over the number of particles
not their distribution in space.
<LI>Finally, multi-threaded styles can improve performance when running
LAMMPS in "capability mode", i.e. near the point where the MPI
parallelism scales out. This can happen in particular when using
as kspace style for long-range electrostatics. Here the scaling
of the kspace style is the performance limiting factor and using
multi-threaded styles allows to operate the kspace style at the
limit of scaling and then increase performance parallelizing
the real space calculations with hybrid MPI+OpenMP. Sometimes
additional speedup can be achived by increasing the real-space
coulomb cutoff and thus reducing the work in the kspace part.
</UL>
<P>The best parallel efficiency from <I>omp</I> styles is typically
achieved when there is at least one MPI task per physical
processor, i.e. socket or die.
</P>
<P>Using threads on hyper-threading enabled cores is usually
counterproductive, as the cost in additional memory bandwidth
requirements is not offset by the gain in CPU utilization
through hyper-threading.
</P>
<P>A description of the multi-threading strategy and some performance
examples are <A HREF = "http://sites.google.com/site/akohlmey/software/lammps-icms/lammps-icms-tms2011-talk.pdf?attredirects=0&d=1">presented here</A>
</P>
<HR>
<H4><A NAME = "acc_6"></A>5.6 GPU package
</H4>
<P>The GPU package was developed by Mike Brown at ORNL. It provides GPU
versions of several pair styles and for long-range Coulombics via the
PPPM command. It has the following features:
</P>
<UL><LI>The package is designed to exploit common GPU hardware configurations
where one or more GPUs are coupled with many cores of a multi-core
CPUs, e.g. within a node of a parallel machine.
<LI>Atom-based data (e.g. coordinates, forces) moves back-and-forth
between the CPU(s) and GPU every timestep.
<LI>Neighbor lists can be constructed on the CPU or on the GPU
<LI>The charge assignement 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.
<LI>Asynchronous force computations can be performed simultaneously on the
CPU(s) and GPU.
<LI>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.
</UL>
<P>NOTE:
discuss 3 precisions
if change, also have to re-link with LAMMPS
always use newton off
expt with differing numbers of CPUs vs GPU - can't tell what is fastest
give command line switches in examples
</P>
<P>I am not very clear to the meaning of "Max Mem / Proc"
in the "GPU Time Info (average)".
Is it the maximal of GPU memory used by one CPU core?
</P>
<P>It is the maximum memory used at one time on the GPU for data storage by
a single MPI process. - Mike
</P>
<P><B>Hardware and software requirements:</B>
</P>
<P>To use this package, you currently need to have specific NVIDIA
hardware and install specific NVIDIA CUDA software on your system:
</P>
<UL><LI>Check if you have an NVIDIA card: cat /proc/driver/nvidia/cards/0
<LI>Go to http://www.nvidia.com/object/cuda_get.html
<LI>Install a driver and toolkit appropriate for your system (SDK is not necessary)
<LI>Follow the instructions in lammps/lib/gpu/README to build the library (see below)
<LI>Run lammps/lib/gpu/nvc_get_devices to list supported devices and properties
</UL>
<P><B>Building LAMMPS with the GPU package:</B>
</P>
<P>As with other packages that include a separately compiled library, you
need to first build the GPU library, before building LAMMPS itself.
General instructions for doing this are in <A HREF = "Section_start.html#start_3">this
section</A> of the manual. For this package,
do the following, using a Makefile in lib/gpu appropriate for your
system:
</P>
<PRE>cd lammps/lib/gpu
make -f Makefile.linux
(see further instructions in lammps/lib/gpu/README)
</PRE>
<P>If you are successful, you will produce the file lib/libgpu.a.
</P>
<P>Now you are ready to build LAMMPS with the GPU package installed:
</P>
<PRE>cd lammps/src
make yes-gpu
make machine
</PRE>
<P>Note that the lo-level Makefile (e.g. src/MAKE/Makefile.linux) has
these settings: gpu_SYSINC, gpu_SYSLIB, gpu_SYSPATH. These need to be
set appropriately to include the paths and settings for the CUDA
system software on your machine. See src/MAKE/Makefile.g++ for an
example.
</P>
<P><B>GPU configuration</B>
</P>
<P>When using GPUs, you are restricted to one physical GPU per LAMMPS
process, which is an MPI process running on a single core or
processor. Multiple MPI processes (CPU cores) can share a single GPU,
and in many cases it will be more efficient to run this way.
</P>
<P><B>Input script requirements:</B>
</P>
<P>Additional input script requirements to run pair or PPPM styles with a
<I>gpu</I> suffix are as follows:
</P>
<UL><LI>To invoke specific styles from the GPU package, you can either append
"gpu" to the style name (e.g. pair_style lj/cut/gpu), or use the
<A HREF = "Section_start.html#start_7">-suffix command-line switch</A>, or use the
<A HREF = "suffix.html">suffix</A> command.
<LI>The <A HREF = "newton.html">newton pair</A> setting must be <I>off</I>.
<LI>The <A HREF = "package.html">package gpu</A> command must be used near the beginning
of your script to control the GPU selection and initialization
settings. It also has an option to enable asynchronous splitting of
force computations between the CPUs and GPUs.
</UL>
<P>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
</P>
<PRE>package gpu force/neigh 0 1 -1
</PRE>
<P>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.
</P>
<P><B>Timing output:</B>
</P>
<P>As described by the <A HREF = "package.html">package gpu</A> 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 <A HREF = "bond_style.html">bond</A>,
<A HREF = "angle_style.html">angle</A>, <A HREF = "dihedral_style.html">dihedral</A>,
<A HREF = "improper_style.html">improper</A>, and <A HREF = "kspace_style.html">long-range</A>
calculations will not be included in the "Pair" time.
</P>
<P>When the <I>mode</I> 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.
</P>
<P><B>Performance tips:</B>
</P>
<P>Generally speaking, for best performance, you should use multiple CPUs
per GPU, as provided my most multi-core CPU/GPU configurations.
</P>
<P>Because of the large number of cores within each GPU device, it may be
more efficient to run on fewer processes per GPU when the number of
particles per MPI process is small (100's of particles); this can be
necessary to keep the GPU cores busy.
</P>
<P>See the lammps/lib/gpu/README file for instructions on how to build
the GPU library for single, mixed, or double precision. The latter
requires that your GPU card support double precision.
</P>
<HR>
<H4><A NAME = "acc_7"></A>5.7 USER-CUDA package
</H4>
<P>The USER-CUDA package was developed by Christian Trott at U Technology
Ilmenau in Germany. It provides NVIDIA GPU versions of many pair
styles, many fixes, a few computes, and for long-range Coulombics via
the PPPM command. It has the following features:
</P>
<UL><LI>The package is designed to allow an entire LAMMPS calculation, for
many timesteps, to run entirely on the GPU (except for inter-processor
MPI communication), so that atom-based data (e.g. coordinates, forces)
do not have to move back-and-forth between the CPU and GPU.
<LI>The speed-up advantage of this approach is typically better when the
number of atoms per GPU is large
<LI>Data will stay on the GPU until a timestep where a non-GPU-ized fix or
compute is invoked. Whenever a non-GPU operation occurs (fix,
compute, output), data automatically moves back to the CPU as needed.
This may incur a performance penalty, but should otherwise work
transparently.
<LI>Neighbor lists for GPU-ized pair styles are constructed on the
GPU.
<LI>The package only supports use of a single CPU (core) with each
GPU.
</UL>
<P><B>Hardware and software requirements:</B>
</P>
<P>To use this package, you need to have specific NVIDIA hardware and
install specific NVIDIA CUDA software on your system.
</P>
<P>Your NVIDIA GPU needs to support Compute Capability 1.3. This list may
help you to find out the Compute Capability of your card:
</P>
<P>http://en.wikipedia.org/wiki/Comparison_of_Nvidia_graphics_processing_units
</P>
<P>Install the Nvidia Cuda Toolkit in version 3.2 or higher and the
corresponding GPU drivers. The Nvidia Cuda SDK is not required for
LAMMPSCUDA but we recommend it be installed. You can then make sure
that its sample projects can be compiled without problems.
</P>
<P><B>Building LAMMPS with the USER-CUDA package:</B>
</P>
<P>As with other packages that include a separately compiled library, you
need to first build the USER-CUDA library, before building LAMMPS
itself. General instructions for doing this are in <A HREF = "Section_start.html#start_3">this
section</A> of the manual. For this package,
do the following, using settings in the lib/cuda Makefiles appropriate
for your system:
</P>
<UL><LI>Go to the lammps/lib/cuda directory
<LI>If your <I>CUDA</I> toolkit is not installed in the default system directoy
<I>/usr/local/cuda</I> edit the file <I>lib/cuda/Makefile.common</I>
accordingly.
<LI>Type "make OPTIONS", where <I>OPTIONS</I> are one or more of the following
options. The settings will be written to the
<I>lib/cuda/Makefile.defaults</I> and used in the next step.
<PRE><I>precision=N</I> to set the precision level
N = 1 for single precision (default)
N = 2 for double precision
N = 3 for positions in double precision
N = 4 for positions and velocities in double precision
<I>arch=M</I> to set GPU compute capability
M = 20 for CC2.0 (GF100/110, e.g. C2050,GTX580,GTX470) (default)
M = 21 for CC2.1 (GF104/114, e.g. GTX560, GTX460, GTX450)
M = 13 for CC1.3 (GF200, e.g. C1060, GTX285)
<I>prec_timer=0/1</I> to use hi-precision timers
0 = do not use them (default)
1 = use these timers
this is usually only useful for Mac machines
<I>dbg=0/1</I> to activate debug mode
0 = no debug mode (default)
1 = yes debug mode
this is only useful for developers
<I>cufft=1</I> to determine usage of CUDA FFT library
0 = no CUFFT support (default)
in the future other CUDA-enabled FFT libraries might be supported
</PRE>
<LI>Type "make" to build the library. If you are successful, you will
produce the file lib/libcuda.a.
</UL>
<P>Now you are ready to build LAMMPS with the USER-CUDA package installed:
</P>
<PRE>cd lammps/src
make yes-user-cuda
make machine
</PRE>
<P>Note that the LAMMPS build references the lib/cuda/Makefile.common
file to extract setting specific CUDA settings. So it is important
that you have first built the cuda library (in lib/cuda) using
settings appropriate to your system.
</P>
<P><B>Input script requirements:</B>
</P>
<P>Additional input script requirements to run styles with a <I>cuda</I>
suffix are as follows:
</P>
<UL><LI>To invoke specific styles from the USER-CUDA package, you can either
append "cuda" to the style name (e.g. pair_style lj/cut/cuda), or use
the <A HREF = "Section_start.html#start_7">-suffix command-line switch</A>, or use
the <A HREF = "suffix.html">suffix</A> command. One exception is that the
<A HREF = "kspace_style.html">kspace_style pppm/cuda</A> command has to be requested
explicitly.
<LI>To use the USER-CUDA package with its default settings, no additional
command is needed in your input script. This is because when LAMMPS
starts up, it detects if it has been built with the USER-CUDA package.
See the <A HREF = "Section_start.html#start_7">-cuda command-line switch</A> for
more details.
<LI>To change settings for the USER-CUDA package at run-time, the <A HREF = "package.html">package
cuda</A> command can be used near the beginning of your
input script. See the <A HREF = "package.html">package</A> command doc page for
details.
</UL>
<P><B>Performance tips:</B>
</P>
<P>The USER-CUDA package offers more speed-up relative to CPU performance
when the number of atoms per GPU is large, e.g. on the order of tens
or hundreds of 1000s.
</P>
<P>As noted above, this package will continue to run a simulation
entirely on the GPU(s) (except for inter-processor MPI communication),
for multiple timesteps, until a CPU calculation is required, either by
a fix or compute that is non-GPU-ized, or until output is performed
(thermo or dump snapshot or restart file). The less often this
occurs, the faster your simulation will run.
</P>
<HR>
<HR>
<H4><A NAME = "acc_8"></A>5.8 Comparison of GPU and USER-CUDA packages
</H4>
<P>Both the GPU and USER-CUDA packages accelerate a LAMMPS calculation
using NVIDIA hardware, but they do it in different ways.
</P>
<P>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.
</P>
<P><B>Guidelines for using each package optimally:</B>
</P>
<UL><LI>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. The USER-CUDA
package does not allow this; you can only use one CPU per GPU.
<LI>The GPU package moves per-atom data (coordinates, forces)
back-and-forth between the CPU and GPU every timestep. The USER-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
USER-CUDA package can be very low, causing it to run faster than the
GPU package.
<LI>The GPU package is often faster than the USER-CUDA package, if the
number of atoms per GPU is "small". The crossover point, in terms of
atoms/GPU at which the USER-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.
<LI>Both packages compute bonded interactions (bonds, angles, etc) on the
CPU. This means a model with bonds will force the USER-CUDA package
to transfer per-atom data back-and-forth between the CPU and GPU every
timestep. 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.
<LI>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.
</UL>
<P><B>Differences between the two packages:</B>
</P>
<UL><LI>The GPU package accelerates only pair force, neighbor list, and PPPM
calculations. The USER-CUDA package currently supports a wider range
of pair styles and can also accelerate many fix styles and some
compute styles, as well as neighbor list and PPPM calculations.
<LI>The USER-CUDA package does not support acceleration for minimization.
<LI>The USER-CUDA package does not support hybrid pair styles.
<LI>The USER-CUDA package can order atoms in the neighbor list differently
from run to run resulting in a different order for force accumulation.
<LI>The USER-CUDA package has a limit on the number of atom types that can be
used in a simulation.
<LI>The GPU package requires neighbor lists to be built on the CPU when using
exclusion lists or a triclinic simulation box.
<LI>The GPU package uses more GPU memory than the USER-CUDA package. This
is generally not a problem since typical runs are computation-limited
rather than memory-limited.
</UL>
<P><B>Examples:</B>
</P>
<P>The LAMMPS distribution has two directories with sample input scripts
for the GPU and USER-CUDA packages.
</P>
<UL><LI>lammps/examples/gpu = GPU package files
<LI>lammps/examples/USER/cuda = USER-CUDA package files
</UL>
<P>These contain input scripts for identical systems, so they can be used
to benchmark the performance of both packages on your system.
</P>
</HTML>
diff --git a/doc/Section_accelerate.txt b/doc/Section_accelerate.txt
index e4765d864..a58747342 100644
--- a/doc/Section_accelerate.txt
+++ b/doc/Section_accelerate.txt
@@ -1,721 +1,722 @@
"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.
5.1 "Measuring performance"_#acc_1
5.2 "General strategies"_#acc_2
5.3 "Packages with optimized styles"_#acc_3
5.4 "OPT package"_#acc_4
5.5 "USER-OMP package"_#acc_5
5.6 "GPU package"_#acc_6
5.7 "USER-CUDA package"_#acc_7
5.8 "Comparison of GPU and USER-CUDA packages"_#acc_8 :all(b)
: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, or a few 100 at
most) 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 or 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.
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 sub-section 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
-intially 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 your problem and your machine. There is no substitute for
-simply trying them out.
+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
processor mapping via processors numa command
load-balancing: balance and fix balance
processor command for layout
OMP when lots of cores :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)
IMPORTANT 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, if you have the appropriate
hardware on your system.
The accelerated styles have the same name as the standard styles,
except that a suffix is appended. Otherwise, the syntax for the
command is identical, their functionality is the same, and the
numerical results it produces should also be identical, except for
precision and round-off issues.
For example, all of these variants of the basic Lennard-Jones pair
style exist in LAMMPS:
"pair_style lj/cut"_pair_lj.html
"pair_style lj/cut/opt"_pair_lj.html
"pair_style lj/cut/omp"_pair_lj.html
"pair_style lj/cut/gpu"_pair_lj.html
"pair_style lj/cut/cuda"_pair_lj.html :ul
Assuming you have built LAMMPS with the appropriate package, these
styles can be invoked by specifying them explicitly in your input
script. Or you can use the "-suffix command-line
switch"_Section_start.html#start_7 to invoke the accelerated versions
automatically, without changing your input script. The
"suffix"_suffix.html command allows you to set a suffix explicitly and
to turn off/on the comand-line switch setting, both from within your
input script.
Styles with an "opt" suffix are part of the OPT package and typically
speed-up the pairwise calculations of your simulation by 5-25%.
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.
Styles with a "gpu" or "cuda" suffix are part of the GPU or USER-CUDA
packages, and can be run on NVIDIA GPUs associated with your CPUs.
The speed-up due to GPU usage depends on a variety of factors, as
discussed below.
To see what styles are currently available in each of the accelerated
packages, see "Section_commands 5"_Section_commands.html#cmd_5 of the
manual. A list of accelerated styles is included in the pair, fix,
compute, and kspace sections.
The following sections explain:
what hardware and software the accelerated styles require
how to build LAMMPS with the accelerated packages in place
what changes (if any) are needed in your input scripts
guidelines for best performance
speed-ups you can expect :ul
The final section compares and contrasts the GPU and USER-CUDA
packages, since they are both designed to use NVIDIA GPU hardware.
:line
5.4 OPT package :h4,link(acc_4)
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.
The procedure for building LAMMPS with the OPT package is simple. It
is the same as for any other package which has no additional library
dependencies:
make yes-opt
make machine :pre
If your input script uses one of the OPT pair styles,
you can run it as follows:
lmp_machine -sf opt < in.script
mpirun -np 4 lmp_machine -sf opt < in.script :pre
You should see a reduction in the "Pair time" printed out at the end
of the run. On most machines and problems, this will typically be a 5
to 20% savings.
:line
5.5 USER-OMP package :h4,link(acc_5)
The USER-OMP package was developed by Axel Kohlmeyer at Temple University.
It provides multi-threaded versions of most pair styles, all dihedral
styles and a few fixes in LAMMPS. The package currently uses the OpenMP
interface which requires using a specific compiler flag in the makefile
to enable multiple threads; without this flag the corresponding pair
styles will still be compiled and work, but do not support multi-threading.
[Building LAMMPS with the USER-OMP package:]
The procedure for building LAMMPS with the USER-OMP package is simple.
You have to edit your machine specific makefile to add the flag to
enable OpenMP support to the CCFLAGS and LINKFLAGS variables. For the
GNU compilers for example this flag is called {-fopenmp}. Check your
compiler documentation to find out which flag you need to add.
The rest of the compilation is the same as for any other package which
has no additional library dependencies:
make yes-user-omp
make machine :pre
Please note that this will only install accelerated versions
of styles that are already installed, so you want to install
this package as the last package, or else you may be missing
some accelerated styles. If you plan to uninstall some package,
you should first uninstall the USER-OMP package then the other
package and then re-install USER-OMP, to make sure that there
are no orphaned {omp} style files present, which would lead to
compilation errors.
If your input script uses one of regular styles that are also
exist as an OpenMP version in the USER-OMP package you can run
it as follows:
env OMP_NUM_THREADS=4 lmp_serial -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
The value of the environment variable OMP_NUM_THREADS determines how
many threads per MPI task are launched. All three examples above use
a total of 4 CPU cores. For different MPI implementations the method
to pass the OMP_NUM_THREADS environment variable to all processes is
different. Two different variants, one for MPICH and OpenMPI, respectively
are shown above. Please check the documentation of your MPI installation
for additional details. Alternatively, the value provided by OMP_NUM_THREADS
can be overridded with the "package omp"_package.html command.
Depending on which styles are accelerated in your input, you should
see a reduction in the "Pair time" and/or "Bond time" and "Loop time"
printed out at the end of the run. The optimal ratio of MPI to OpenMP
can vary a lot and should always be confirmed through some benchmark
runs for the current system and on the current machine.
[Restrictions:]
Only a few of the pair styles in the USER-OMP package support the "inner",
"middle", "outer" options for r-RESPA integration, even if the regular
version does. For those only the "pair" option is supported.
When using styles from the GPU package, they can only be used on the
outermost RESPA level.
[Parallel efficiency and performance tips:]
In most simple cases the MPI parallelization in LAMMPS is more
efficient than multi-threading implemented in the USER-OMP package.
Also the parallel efficiency varies between individual styles.
On the other hand, in many cases you still want to use the {omp} version
- even when compiling or running without OpenMP support - since they
all contain optimizations similar to those in the OPT package, which
can result in serial speedup.
Using multi-threading is most 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. 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
nodes is faster. Running in hybrid MPI+OpenMP mode will reduce the
inter-node communication bandwidth contention in the same way,
but offers and additional speedup from utilizing the otherwise
idle CPU cores. :ulb,l
The interconnect used for MPI communication is not able to provide
sufficient bandwidth for a large number of MPI tasks per node.
This applies for example to running over gigabit ethernet or
on Cray XT4 or XT5 series supercomputers. Same as in the aforementioned
case this effect worsens with using an increasing number of nodes. :l
The input is a system that has an inhomogeneous particle density
which cannot be mapped well to the domain decomposition scheme
that LAMMPS employs. While this can be to some degree alleviated
through using the "processors"_processors.html keyword, multi-threading
provides a parallelism that parallelizes over the number of particles
not their distribution in space. :l
Finally, multi-threaded styles can improve performance when running
LAMMPS in "capability mode", i.e. near the point where the MPI
parallelism scales out. This can happen in particular when using
as kspace style for long-range electrostatics. Here the scaling
of the kspace style is the performance limiting factor and using
multi-threaded styles allows to operate the kspace style at the
limit of scaling and then increase performance parallelizing
the real space calculations with hybrid MPI+OpenMP. Sometimes
additional speedup can be achived by increasing the real-space
coulomb cutoff and thus reducing the work in the kspace part. :l,ule
The best parallel efficiency from {omp} styles is typically
achieved when there is at least one MPI task per physical
processor, i.e. socket or die.
Using threads on hyper-threading enabled cores is usually
counterproductive, as the cost in additional memory bandwidth
requirements is not offset by the gain in CPU utilization
through hyper-threading.
A description of the multi-threading strategy 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
:line
5.6 GPU package :h4,link(acc_6)
The GPU package was developed by Mike Brown at ORNL. It provides GPU
versions of several pair styles and for long-range Coulombics via the
PPPM command. It has the following features:
The package is designed to exploit common GPU hardware configurations
where one or more GPUs are coupled with many cores of a 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 constructed on the CPU or on the GPU :l
The charge assignement 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
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
NOTE:
discuss 3 precisions
if change, also have to re-link with LAMMPS
always use newton off
expt with differing numbers of CPUs vs GPU - can't tell what is fastest
give command line switches in examples
I am not very clear to the meaning of "Max Mem / Proc"
in the "GPU Time Info (average)".
Is it the maximal of GPU memory used by one CPU core?
It is the maximum memory used at one time on the GPU for data storage by
a single MPI process. - Mike
[Hardware and software requirements:]
To use this package, you currently need to have specific NVIDIA
hardware and install specific NVIDIA CUDA software on your system:
Check if you have an NVIDIA card: cat /proc/driver/nvidia/cards/0
Go to http://www.nvidia.com/object/cuda_get.html
Install a driver and toolkit appropriate for your system (SDK is not necessary)
Follow the instructions in lammps/lib/gpu/README to build the library (see below)
Run lammps/lib/gpu/nvc_get_devices to list supported devices and properties :ul
[Building LAMMPS with the GPU package:]
As with other packages that include a separately compiled library, you
need to first build the GPU library, before building LAMMPS itself.
General instructions for doing this are in "this
section"_Section_start.html#start_3 of the manual. For this package,
do the following, using a Makefile in lib/gpu appropriate for your
system:
cd lammps/lib/gpu
make -f Makefile.linux
(see further instructions in lammps/lib/gpu/README) :pre
If you are successful, you will produce the file lib/libgpu.a.
Now you are ready to build LAMMPS with the GPU package installed:
cd lammps/src
make yes-gpu
make machine :pre
Note that the lo-level Makefile (e.g. src/MAKE/Makefile.linux) has
these settings: gpu_SYSINC, gpu_SYSLIB, gpu_SYSPATH. These need to be
set appropriately to include the paths and settings for the CUDA
system software on your machine. See src/MAKE/Makefile.g++ for an
example.
[GPU configuration]
When using GPUs, you are restricted to one physical GPU per LAMMPS
process, which is an MPI process running on a single core or
processor. Multiple MPI processes (CPU cores) can share a single GPU,
and in many cases it will be more efficient to run this way.
[Input script requirements:]
Additional input script requirements to run pair or PPPM styles with a
{gpu} suffix are as follows:
To invoke specific styles from the GPU package, you can either append
"gpu" to the style name (e.g. pair_style lj/cut/gpu), or use the
"-suffix command-line switch"_Section_start.html#start_7, or use the
"suffix"_suffix.html command. :ulb,l
The "newton pair"_newton.html setting must be {off}. :l
The "package gpu"_package.html command must be used near the beginning
of your script to control the GPU selection and initialization
settings. It also has an option to enable asynchronous splitting of
force computations between the CPUs and GPUs. :l,ule
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
package gpu force/neigh 0 1 -1 :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.
[Timing output:]
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.
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.
[Performance tips:]
Generally speaking, for best performance, you should use multiple CPUs
per GPU, as provided my most multi-core CPU/GPU configurations.
Because of the large number of cores within each GPU device, it may be
more efficient to run on fewer processes per GPU when the number of
particles per MPI process is small (100's of particles); this can be
necessary to keep the GPU cores busy.
See the lammps/lib/gpu/README file for instructions on how to build
the GPU library for single, mixed, or double precision. The latter
requires that your GPU card support double precision.
:line
5.7 USER-CUDA package :h4,link(acc_7)
The USER-CUDA package was developed by Christian Trott at U Technology
Ilmenau in Germany. It provides NVIDIA GPU versions of many pair
styles, many fixes, a few computes, and for long-range Coulombics via
the PPPM command. It has the following features:
The package is designed to allow an entire LAMMPS calculation, for
many timesteps, to run entirely on the GPU (except for inter-processor
MPI communication), so that atom-based data (e.g. coordinates, forces)
do not have to move back-and-forth between the CPU and GPU. :ulb,l
The speed-up advantage of this approach is typically better when the
number of atoms per GPU is large :l
Data will stay on the GPU until a timestep where a non-GPU-ized fix or
compute is invoked. Whenever a non-GPU operation occurs (fix,
compute, output), data automatically moves back to the CPU as needed.
This may incur a performance penalty, but should otherwise work
transparently. :l
Neighbor lists for GPU-ized pair styles are constructed on the
GPU. :l
The package only supports use of a single CPU (core) with each
GPU. :l,ule
[Hardware and software requirements:]
To use this package, you need to have specific NVIDIA hardware and
install specific NVIDIA CUDA software on your system.
Your NVIDIA GPU needs to support Compute Capability 1.3. This list may
help you to find out the Compute Capability of your card:
http://en.wikipedia.org/wiki/Comparison_of_Nvidia_graphics_processing_units
Install the Nvidia Cuda Toolkit in version 3.2 or higher and the
corresponding GPU drivers. The Nvidia Cuda SDK is not required for
LAMMPSCUDA but we recommend it be installed. You can then make sure
that its sample projects can be compiled without problems.
[Building LAMMPS with the USER-CUDA package:]
As with other packages that include a separately compiled library, you
need to first build the USER-CUDA library, before building LAMMPS
itself. General instructions for doing this are in "this
section"_Section_start.html#start_3 of the manual. For this package,
do the following, using settings in the lib/cuda Makefiles appropriate
for your system:
Go to the lammps/lib/cuda directory :ulb,l
If your {CUDA} toolkit is not installed in the default system directoy
{/usr/local/cuda} edit the file {lib/cuda/Makefile.common}
accordingly. :l
Type "make OPTIONS", where {OPTIONS} are one or more of the following
options. The settings will be written to the
{lib/cuda/Makefile.defaults} and used in the next step. :l
{precision=N} to set the precision level
N = 1 for single precision (default)
N = 2 for double precision
N = 3 for positions in double precision
N = 4 for positions and velocities in double precision
{arch=M} to set GPU compute capability
M = 20 for CC2.0 (GF100/110, e.g. C2050,GTX580,GTX470) (default)
M = 21 for CC2.1 (GF104/114, e.g. GTX560, GTX460, GTX450)
M = 13 for CC1.3 (GF200, e.g. C1060, GTX285)
{prec_timer=0/1} to use hi-precision timers
0 = do not use them (default)
1 = use these timers
this is usually only useful for Mac machines
{dbg=0/1} to activate debug mode
0 = no debug mode (default)
1 = yes debug mode
this is only useful for developers
{cufft=1} to determine usage of CUDA FFT library
0 = no CUFFT support (default)
in the future other CUDA-enabled FFT libraries might be supported :pre
Type "make" to build the library. If you are successful, you will
produce the file lib/libcuda.a. :l,ule
Now you are ready to build LAMMPS with the USER-CUDA package installed:
cd lammps/src
make yes-user-cuda
make machine :pre
Note that the LAMMPS build references the lib/cuda/Makefile.common
file to extract setting specific CUDA settings. So it is important
that you have first built the cuda library (in lib/cuda) using
settings appropriate to your system.
[Input script requirements:]
Additional input script requirements to run styles with a {cuda}
suffix are as follows:
To invoke specific styles from the USER-CUDA package, you can either
append "cuda" to the style name (e.g. pair_style lj/cut/cuda), or use
the "-suffix command-line switch"_Section_start.html#start_7, or use
the "suffix"_suffix.html command. One exception is that the
"kspace_style pppm/cuda"_kspace_style.html command has to be requested
explicitly. :ulb,l
To use the USER-CUDA package with its default settings, no additional
command is needed in your input script. This is because when LAMMPS
starts up, it detects if it has been built with the USER-CUDA package.
See the "-cuda command-line switch"_Section_start.html#start_7 for
more details. :l
To change settings for the USER-CUDA package at run-time, the "package
cuda"_package.html command can be used near the beginning of your
input script. See the "package"_package.html command doc page for
details. :l,ule
[Performance tips:]
The USER-CUDA package offers more speed-up relative to CPU performance
when the number of atoms per GPU is large, e.g. on the order of tens
or hundreds of 1000s.
As noted above, this package will continue to run a simulation
entirely on the GPU(s) (except for inter-processor MPI communication),
for multiple timesteps, until a CPU calculation is required, either by
a fix or compute that is non-GPU-ized, or until output is performed
(thermo or dump snapshot or restart file). The less often this
occurs, the faster your simulation will run.
:line
:line
5.8 Comparison of GPU and USER-CUDA packages :h4,link(acc_8)
Both the GPU and USER-CUDA 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. The USER-CUDA
package does not allow this; you can only use one CPU per GPU. :ulb,l
The GPU package moves per-atom data (coordinates, forces)
back-and-forth between the CPU and GPU every timestep. The USER-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
USER-CUDA package can be very low, causing it to run faster than the
GPU package. :l
The GPU package is often faster than the USER-CUDA package, if the
number of atoms per GPU is "small". The crossover point, in terms of
atoms/GPU at which the USER-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. This means a model with bonds will force the USER-CUDA package
to transfer per-atom data back-and-forth between the CPU and GPU every
timestep. 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. The USER-CUDA package currently supports a wider range
of pair styles and can also accelerate many fix styles and some
compute styles, as well as neighbor list and PPPM calculations. :ulb,l
The USER-CUDA package does not support acceleration for minimization. :l
The USER-CUDA package does not support hybrid pair styles. :l
The USER-CUDA package can order atoms in the neighbor list differently
from run to run resulting in a different order for force accumulation. :l
The USER-CUDA package has a limit on the number of atom types that can be
used in a simulation. :l
The GPU package requires neighbor lists to be built on the CPU when using
exclusion lists or a triclinic simulation box. :l
The GPU package uses more GPU memory than the USER-CUDA package. This
is generally not a problem since typical runs are computation-limited
rather than memory-limited. :l,ule
[Examples:]
The LAMMPS distribution has two directories with sample input scripts
for the GPU and USER-CUDA packages.
lammps/examples/gpu = GPU package files
lammps/examples/USER/cuda = USER-CUDA package files :ul
These contain input scripts for identical systems, so they can be used
to benchmark the performance of both packages on your system.
diff --git a/doc/Section_start.html b/doc/Section_start.html
index e4f42bcca..032115203 100644
--- a/doc/Section_start.html
+++ b/doc/Section_start.html
@@ -1,1438 +1,1443 @@
<HTML>
<CENTER><A HREF = "Section_intro.html">Previous Section</A> - <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> - <A HREF = "Section_commands.html">Next Section</A>
</CENTER>
<HR>
<H3>2. Getting Started
</H3>
<P>This section describes how to build and run LAMMPS, for both new and
experienced users.
</P>
2.1 <A HREF = "#start_1">What's in the LAMMPS distribution</A><BR>
2.2 <A HREF = "#start_2">Making LAMMPS</A><BR>
2.3 <A HREF = "#start_3">Making LAMMPS with optional packages</A><BR>
2.4 <A HREF = "#start_4">Building LAMMPS via the Make.py script</A><BR>
2.5 <A HREF = "#start_5">Building LAMMPS as a library</A><BR>
2.6 <A HREF = "#start_6">Running LAMMPS</A><BR>
2.7 <A HREF = "#start_7">Command-line options</A><BR>
2.8 <A HREF = "#start_8">Screen output</A><BR>
2.9 <A HREF = "#start_9">Tips for users of previous versions</A> <BR>
<HR>
<HR>
<H4><A NAME = "start_1"></A>2.1 What's in the LAMMPS distribution
</H4>
<P>When you download LAMMPS you will need to unzip and untar the
downloaded file with the following commands, after placing the file in
an appropriate directory.
</P>
<PRE>gunzip lammps*.tar.gz
tar xvf lammps*.tar
</PRE>
<P>This will create a LAMMPS directory containing two files and several
sub-directories:
</P>
<DIV ALIGN=center><TABLE BORDER=1 >
<TR><TD >README</TD><TD > text file</TD></TR>
<TR><TD >LICENSE</TD><TD > the GNU General Public License (GPL)</TD></TR>
<TR><TD >bench</TD><TD > benchmark problems</TD></TR>
<TR><TD >doc</TD><TD > documentation</TD></TR>
<TR><TD >examples</TD><TD > simple test problems</TD></TR>
<TR><TD >potentials</TD><TD > embedded atom method (EAM) potential files</TD></TR>
<TR><TD >src</TD><TD > source files</TD></TR>
<TR><TD >tools</TD><TD > pre- and post-processing tools
</TD></TR></TABLE></DIV>
<P>If you download one of the Windows executables from the download page,
then you just get a single file:
</P>
<PRE>lmp_windows.exe
</PRE>
<P>Skip to the <A HREF = "#start_6">Running LAMMPS</A> sections for info on how to
launch these executables on a Windows box.
</P>
<P>The Windows executables for serial or parallel only include certain
packages and bug-fixes/upgrades listed on <A HREF = "http://lammps.sandia.gov/bug.html">this
page</A> up to a certain date, as
stated on the download page. If you want something with more packages
or that is more current, you'll have to download the source tarball
and build it yourself from source code using Microsoft Visual Studio,
as described in the next section.
</P>
<HR>
<H4><A NAME = "start_2"></A>2.2 Making LAMMPS
</H4>
<P>This section has the following sub-sections:
</P>
<UL><LI><A HREF = "#start_2_1">Read this first</A>
<LI><A HREF = "#start_2_2">Steps to build a LAMMPS executable</A>
<LI><A HREF = "#start_2_3">Common errors that can occur when making LAMMPS</A>
<LI><A HREF = "#start_2_4">Additional build tips</A>
<LI><A HREF = "#start_2_5">Building for a Mac</A>
<LI><A HREF = "#start_2_6">Building for Windows</A>
</UL>
<HR>
<A NAME = "start_2_1"></A><B><I>Read this first:</I></B>
<P>Building LAMMPS can be non-trivial. You may need to edit a makefile,
there are compiler options to consider, additional libraries can be
used (MPI, FFT, JPEG, PNG), LAMMPS packages may be included or
excluded, some of these packages use auxiliary libraries which need to
be pre-built, etc.
</P>
<P>Please read this section 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
compiling, linking, and run problems that users have 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.
</P>
<P>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 a question to the <A HREF = "http://lammps.sandia.gov/mail.html">LAMMPS mail
list</A>.
</P>
<P>If you succeed in building LAMMPS on a new kind of machine, for which
there isn't a similar Makefile for in the src/MAKE directory, send it
to the developers and we can include it in the LAMMPS distribution.
</P>
<HR>
<A NAME = "start_2_2"></A><B><I>Steps to build a LAMMPS executable:</I></B>
<P><B>Step 0</B>
</P>
<P>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 machines. From within the src
directory, type "make" or "gmake". You should see a list of available
choices. If one of those is the machine and options you want, you can
type a command like:
</P>
<PRE>make linux
or
gmake mac
</PRE>
<P>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.
</P>
<P>If you get no errors and an executable like lmp_linux or lmp_mac is
produced, you're done; it's your lucky day.
</P>
<P>Note that by default only a few of LAMMPS optional packages are
installed. To build LAMMPS with optional packages, see <A HREF = "#start_3">this
section</A> below.
</P>
<P><B>Step 1</B>
</P>
<P>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 src/MAKE/Makefile.* 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.
</P>
<P><B>Step 2</B>
</P>
<P>Change the first line of src/MAKE/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".
</P>
<P><B>Step 3</B>
</P>
<P>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 mpicc 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 commercial Intel icc
compiler, which can be downloaded from <A HREF = "http://www.intel.com/software/products/noncom">Intel's compiler site</A>.
</P>
<P>If building a C++ code on your machine requires additional libraries,
then you should list them as part of the LIB variable.
</P>
<P>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++ 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.
</P>
<P><B>Step 4</B>
</P>
<P>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).
</P>
<P>The LMP_INC variable is used to include options that turn on ifdefs
within the LAMMPS code. The options that are currently recogized are:
</P>
<UL><LI>-DLAMMPS_GZIP
<LI>-DLAMMPS_JPEG
<LI>-DLAMMPS_PNG
<LI>-DLAMMPS_FFMPEG
<LI>-DLAMMPS_MEMALIGN
<LI>-DLAMMPS_XDR
<LI>-DLAMMPS_SMALLBIG
<LI>-DLAMMPS_BIGBIG
<LI>-DLAMMPS_SMALLSMALL
<LI>-DLAMMPS_LONGLONG_TO_LONG
<LI>-DPACK_ARRAY
<LI>-DPACK_POINTER
<LI>-DPACK_MEMCPY
</UL>
<P>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.
</P>
<P>If you use -DLAMMPS_JPEG, the <A HREF = "dump_image.html">dump image</A> 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 <A HREF = "dump.html">dump image</A> 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.
</P>
<P>If you use -DLAMMPS_FFMPEG, the <A HREF = "dump_image.html">dump movie</A> 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.
</P>
<P>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.
</P>
<P>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 <A HREF = "dump.html">dump</A> command for details.
</P>
-<P>Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG,
--D-DLAMMPS_SMALLSMALL settings. The default is -DLAMMPS_SMALLBIG.
-These settings refer to use of 4-byte (small) vs 8-byte (big) integers
+<P>Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG, -D-
+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
-with more than 2 billion atoms or to allow moving atoms to wrap back
-through a periodic box more than 512 times. The only reason to use
-the SMALLSMALL setting is if your machine does not support 64-bit
-integers. See the <A HREF = "#start_2_4">Additional build tips</A> section below
-for more details.
+(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. The only reason to use the SMALLSMALL setting is
+if your machine does not support 64-bit integers. See the <A HREF = "#start_2_4">Additional
+build tips</A> section below for more details.
</P>
<P>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.
</P>
<P>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
<A HREF = "kspace_style.html">kspace_style</A> command for info about PPPM. See
Step 6 below for info about building LAMMPS with an FFT library.
</P>
<P><B>Step 5</B>
</P>
<P>The 3 MPI variables are used to specify an MPI library to build LAMMPS
with.
</P>
<P>If you want LAMMPS to run in parallel, you must have an MPI library
installed on your platform. If you use an MPI-wrapped compiler, such
as "mpicc" to build LAMMPS, you should be able to leave these 3
variables blank; the MPI wrapper knows where to find the needed files.
If not, and MPI is installed on your system in the usual place (under
/usr/local), you also may not need to specify these 3 variables. 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 MPI which the compiler has no trouble finding.
</P>
<P>Failing this, with these 3 variables you can 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).
</P>
<P>If you are installing MPI yourself, we recommend Argonne's MPICH2
or OpenMPI. MPICH can be downloaded from the <A HREF = "http://www.mcs.anl.gov/research/projects/mpich2/">Argonne MPI
site</A>. OpenMPI can
be downloaded from the <A HREF = "http://www.open-mpi.org">OpenMPI site</A>.
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.
</P>
<P>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 the
src/MAKE/Makefile.serial file 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. To build from the src
directory, type "make stubs", or from the 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.
</P>
<P>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.
</P>
<P><B>Step 6</B>
</P>
<P>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
<A HREF = "kspace_style.html">kspace_style</A> command.
</P>
<P>LAMMPS supports various open-source or vendor-supplied FFT libraries
for this purpose. If you leave these 3 variables blank, LAMMPS will
use the open-source <A HREF = "http://kissfft.sf.net">KISS FFT library</A>, 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.
</P>
<P>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, SCSL, FFTW2, and FFTW3. Legacy options are: INTEL, SGI,
ACML, and T3E. For backward compatability, using -DFFT_FFTW will use
the FFTW2 library. Using -DFFT_NONE will use the KISS library
described above.
</P>
<P>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.
</P>
<P>FFTW is a fast, portable library that should also work on any
platform. You can download it from
<A HREF = "http://www.fftw.org">www.fftw.org</A>. 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.
Note that on some platforms FFTW2 has been pre-installed, and uses
renamed files indicating the precision it was compiled with,
e.g. sfftw.h, or dfftw.h instead of fftw.h. In this case, you can
specify an additional define variable for FFT_INC called -DFFTW_SIZE,
which will select the correct include file. In this case, for FFT_LIB
you must also manually specify the correct library, namely -lsfftw or
-ldfftw.
</P>
<P>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.
</P>
<P><B>Step 7</B>
</P>
<P>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 <A HREF = "dump_image.html">dump
image</A> 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.
</P>
<P>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.
</P>
<P>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.
</P>
<P>As before, if these header and library files are in the usual place on
your machine, you may not need to set these variables.
</P>
<P><B>Step 8</B>
</P>
<P>Note that by default only a few of LAMMPS optional packages are
installed. To build LAMMPS with optional packages, see <A HREF = "#start_3">this
section</A> below, before proceeding to Step 9.
</P>
<P><B>Step 9</B>
</P>
<P>That's it. Once you have a correct Makefile.foo, you have installed
the optional LAMMPS packages you want to include in your build, and
you have pre-built any other needed libraries (e.g. MPI, FFT, package
libraries), all you need to do from the src directory is type
something like this:
</P>
<PRE>make foo
or
gmake foo
</PRE>
<P>You should get the executable lmp_foo when the build is complete.
</P>
<HR>
<A NAME = "start_2_3"></A><B><I>Errors that can occur when making LAMMPS:</I></B>
<P>IMPORTANT NOTE: 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 source files. When a make fails, there is
usually a very simple reason, which you or a local expert will need to
fix.
</P>
<P>Here are two non-obvious errors that can occur:
</P>
<P>(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.
</P>
<PRE>make makelist
make -f Makefile.list linux
gmake -f Makefile.list mac
</PRE>
<P>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.
</P>
<P>(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.
</P>
<HR>
<A NAME = "start_2_4"></A><B><I>Additional build tips:</I></B>
<P>(1) Building LAMMPS for multiple platforms.
</P>
<P>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.
</P>
<P>(2) Cleaning up.
</P>
<P>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.
</P>
<P>(3) Changing the LAMMPS size limits via -DLAMMPS_SMALLBIG or
--DLAMMPS_BIBIG or -DLAMMPS_SMALLSMALL
+-DLAMMPS_BIGBIG or -DLAMMPS_SMALLSMALL
</P>
<P>As explained above, any of these 3 settings can be specified on the
LMP_INC line in your low-level src/MAKE/Makefile.foo.
</P>
<P>The default is -DLAMMPS_SMALLBIG which allows for systems with up to
-2^63 atoms and timesteps (about 9 billion billion). The atom limit is
-for atomic systems that do not require atom IDs. For molecular
-models, which require atom IDs, the limit is 2^31 atoms (about 2
-billion). With this setting, image flags are stored in 32-bit
-integers, which means for 3 dimensions that atoms can only wrap around
-a periodic box at most 512 times. If atoms move through the periodic
-box more than this limit, 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 <A HREF = "compute_msd.html">compute msd</A>
-command, to be faulty.
-</P>
-<P>To allow for larger molecular systems or larger image flags, compile
-with -DLAMMPS_BIGBIG. This enables molecular systems with up to 2^63
-atoms (about 9 billion billion). And image flags will not "roll over"
-until they reach 2^20 = 1048576.
-</P>
-<P>IMPORTANT NOTE: As of 6/2012, the BIGBIG setting does not yet enable
-molecular systems to grow as large as 2^63. Only the image flag roll
-over is currently affected by this compile option.
+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.
+</P>
+<P>Likewise, with this setting, the 3 image flags for each atom (see the
+<A HREF = "dump.html">dump</A> 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 <A HREF = "compute_msd.html">compute
+msd</A> command, to be faulty.
+</P>
+<P>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.
</P>
<P>If your system does not support 8-byte integers, you will need to
-compile with the -DLAMMPS_SMALLSMALL setting. This will restrict your
-total number of atoms (for atomic or molecular models) and timesteps
+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.
</P>
-<P>Note that in src/lmptype.h there are also settings for the MPI data
-types associated with the integers that store atom IDs and total
-system sizes. These need to be consistent with the associated C data
-types, or else LAMMPS will generate a run-time error.
-</P>
-<P>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 restriction 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.
+<P>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.
+</P>
+<P>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.
</P>
<HR>
<A NAME = "start_2_5"></A><B><I>Building for a Mac:</I></B>
<P>OS X is BSD Unix, so it should just work. See the
src/MAKE/Makefile.mac file.
</P>
<HR>
<A NAME = "start_2_6"></A><B><I>Building for Windows:</I></B>
<P>The LAMMPS download page has an option to download both a serial and
parallel pre-built Windows exeutable. See the <A HREF = "#start_6">Running
LAMMPS</A> section for instructions for running these
executables on a Windows box.
</P>
<P>The pre-built executables are built with a subset of the available
pacakges; see the download page for the list. If you want
a Windows version with specific packages included and excluded,
you can build it yourself.
</P>
<P>One way to do this is install and use cygwin to build LAMMPS with a
standard Linus make, just as you would on any Linux box; see
src/MAKE/Makefile.cygwin.
</P>
<P>The other way to do this is using Visual Studio and project files.
See the src/WINDOWS directory and its README.txt file for instructions
on both a basic build and a customized build with pacakges you select.
</P>
<HR>
<H4><A NAME = "start_3"></A>2.3 Making LAMMPS with optional packages
</H4>
<P>This section has the following sub-sections:
</P>
<UL><LI><A HREF = "#start_3_1">Package basics</A>
<LI><A HREF = "#start_3_2">Including/excluding packages</A>
<LI><A HREF = "#start_3_3">Packages that require extra libraries</A>
<LI><A HREF = "#start_3_4">Additional Makefile settings for extra libraries</A>
</UL>
<HR>
<A NAME = "start_3_1"></A><B><I>Package basics:</I></B>
<P>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. You
can see the list of all packages by typing "make package" from within
the src directory of the LAMMPS distribution.
</P>
<P>If you use a command in a LAMMPS input script that is specific to a
particular 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 also type
</P>
<PRE>lmp_machine -h
</PRE>
<P>to run your executable with the optional <A HREF = "#start_7">-h command-line
switch</A> for "help", which will list the styles and commands
known to your executable.
</P>
<P>There are two kinds of packages in LAMMPS, standard and user packages.
More information about the contents of standard and user packages is
given in <A HREF = "Section_packages.html">Section_packages</A> of the manual. The
difference between standard and user packages is as follows:
</P>
<P>Standard packages are supported by the LAMMPS developers and are
written in a syntax and style consistent with the rest of LAMMPS.
This means we will answer questions about them, debug and fix them if
necessary, and keep them compatible with future changes to LAMMPS.
</P>
<P>User packages have been contributed by users, and always begin with
the user prefix. If they are a single command (single file), they are
typically in the user-misc package. Otherwise, they are a a set of
files grouped together which add a specific functionality to the code.
</P>
<P>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 will likely need to contact the contributor directly to
get help. Information on how to submit additions you make to LAMMPS
as a user-contributed package is given in <A HREF = "Section_modify.html#mod_15">this
section</A> of the documentation.
</P>
<P>Some packages (both standard and user) require additional libraries.
See more details below.
</P>
<HR>
<A NAME = "start_3_2"></A><B><I>Including/excluding packages:</I></B>
<P>To use or not use a package you must include or exclude it before
building LAMMPS. From the src directory, this is typically as simple
as:
</P>
<PRE>make yes-colloid
make g++
</PRE>
<P>or
</P>
<PRE>make no-manybody
make g++
</PRE>
<P>IMPORTANT NOTE: You should NOT include/exclude packages and build
LAMMPS in a single make command by using multiple targets, e.g. make
yes-colloid g++. 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 during the same command.
</P>
<P>Some packages have individual files that depend on other packages
being included. 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.
</P>
<P>The reason to exclude packages is if you will never run certain kinds
of simulations. For some packages, this will keep you from having to
build auxiliary libraries (see below), and will also produce a smaller
executable which may run a bit faster.
</P>
<P>When you download a LAMMPS tarball, these packages are pre-installed
in the src directory: KSPACE, MANYBODY,MOLECULE. When you download
LAMMPS source files from the SVN or Git repositories, no packages are
pre-installed.
</P>
<P>Packages are included or excluded by typing "make yes-name" or "make
no-name", 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 "make yes-standard", "make
no-standard", "make yes-user", "make no-user", "make yes-all" or "make
no-all" to include/exclude various sets of packages. Type "make
package" to see the all of the package-related make options.
</P>
<P>IMPORTANT NOTE: Inclusion/exclusion of 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 seen or not seen when LAMMPS is built. After
you have included or excluded a package, you must re-build LAMMPS.
</P>
<P>Additional package-related make options exist to help manage LAMMPS
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 WWW site.
</P>
<P>Typing "make package-update" will overwrite src files with files from
the package sub-directories if the package has been included. It
should be used after a patch is installed, 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.
</P>
<P>Typing "make package-status" will show which packages are currently
included. Of those that are included, it will list files that are
different in the src directory and package sub-directory. Typing
"make package-diff" lists all differences between these files. Again,
type "make package" to see all of the package-related make options.
</P>
<HR>
<A NAME = "start_3_3"></A><B><I>Packages that require extra libraries:</I></B>
<P>A few of the standard and user packages require additional auxiliary
libraries. They must be compiled first, before LAMMPS is built. If
you get a LAMMPS build error about a missing library, this is likely
the reason. See the <A HREF = "Section_packages.html">Section_packages</A> doc page
for a list of packages that have auxiliary libraries.
</P>
<P>Code for some of these auxiliary libraries is included in the LAMMPS
distribution under the lib directory. Examples are the USER-ATC and
MEAM packages. Some auxiliary libraries are not included with LAMMPS;
to use the associated package you must download and install the
auxiliary library yourself. Examples are the KIM and VORONOI and
USER-MOLFILE packages.
</P>
<P>For libraries with provided source code, each lib directory has a
README file (e.g. lib/reax/README) with instructions on how to build
that library. Typically this is done by typing something like:
</P>
<PRE>make -f Makefile.g++
</PRE>
<P>If one of the provided Makefiles is not
appropriate for your system you will need to edit or add one.
Note that all the Makefiles have a setting for EXTRAMAKE at
the top that names a Makefile.lammps.* file.
</P>
<P>If successful, this will produce 2 files in the lib directory:
</P>
<PRE>libpackage.a
Makefile.lammps
</PRE>
<P>The Makefile.lammps file is a copy of the EXTRAMAKE file specified
in the Makefile you used.
</P>
<P>You MUST insure that the settings in Makefile.lammps are appropriate
for your system. If they are not, the LAMMPS build will fail.
</P>
<P>As explained in the lib/package/README files, they are used to specify
additional system libraries and their locations so that LAMMPS can
build with the auxiliary library. For example, if the MEAM or REAX
packages are used, the auxiliary libraries consist of F90 code, build
with a F90 complier. To link that library with LAMMPS (a C++ code)
via whatever C++ compiler LAMMPS is built with, typically requires
additional Fortran-to-C libraries be included in the link. Another
example are the BLAS and LAPACK libraries needed to use the USER-ATC
or USER-AWPMD packages.
</P>
<P>For libraries without provided source code, see the
src/package/Makefile.lammps file for information on where to find the
library and how to build it. E.g. the file src/KIM/Makefile.lammps or
src/VORONOI/Makefile.lammps or src/UESR-MOLFILE/Makefile.lammps.
These files serve the same purpose as the lib/package/Makefile.lammps
files described above. The files have settings needed when LAMMPS is
built to link with the corresponding auxiliary library. Again, you
MUST insure that the settings in src/package/Makefile.lammps are
appropriate for your system and where you installed the auxiliary
library. If they are not, the LAMMPS build will fail.
</P>
<HR>
<H4><A NAME = "start_4"></A>2.4 Building LAMMPS via the Make.py script
</H4>
<P>The src directory includes a Make.py script, written
in Python, which can be used to automate various steps
of the build process.
</P>
<P>You can run the script from the src directory by typing either:
</P>
<PRE>Make.py
python Make.py
</PRE>
<P>which will give you info about the tool. For the former to work, you
may need to edit the 1st line of the script to point to your local
Python. And you may need to insure the script is executable:
</P>
<PRE>chmod +x Make.py
</PRE>
<P>The following options are supported as switches:
</P>
<UL><LI>-i file1 file2 ...
<LI>-p package1 package2 ...
<LI>-u package1 package2 ...
<LI>-e package1 arg1 arg2 package2 ...
<LI>-o dir
<LI>-b machine
<LI>-s suffix1 suffix2 ...
<LI>-l dir
<LI>-j N
<LI>-h switch1 switch2 ...
</UL>
<P>Help on any switch can be listed by using -h, e.g.
</P>
<PRE>Make.py -h -i -p
</PRE>
<P>At a hi-level, these are the kinds of package management
and build tasks that can be performed easily, using
the Make.py tool:
</P>
<UL><LI>install/uninstall packages and build the associated external libs (use -p and -u and -e)
<LI>install packages needed for one or more input scripts (use -i and -p)
<LI>build LAMMPS, either in the src dir or new dir (use -b)
<LI>create a new dir with only the source code needed for one or more input scripts (use -i and -o)
</UL>
<P>The last bullet can be useful when you wish to build a stripped-down
version of LAMMPS to run a specific script(s). Or when you wish to
move the minimal amount of files to another platform for a remote
LAMMPS build.
</P>
<P>Note that using Make.py is not a substitute for insuring you have a
valid src/MAKE/Makefile.foo for your system, or that external library
Makefiles in any lib/* directories you use are also valid for your
system. But once you have done that, you can use Make.py to quickly
include/exclude the packages and external libraries needed by your
input scripts.
</P>
<HR>
<H4><A NAME = "start_5"></A>2.5 Building LAMMPS as a library
</H4>
<P>LAMMPS can be built as either a static or shared library, which can
then be called from another application or a scripting language. See
<A HREF = "Section_howto.html#howto_10">this section</A> for more info on coupling
LAMMPS to other codes. See <A HREF = "Section_python.html">this section</A> for
more info on wrapping and running LAMMPS from Python.
</P>
<H5><B>Static library:</B>
</H5>
<P>To build LAMMPS as a static library (*.a file on Linux), type
</P>
<PRE>make makelib
make -f Makefile.lib foo
</PRE>
<P>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. Note that
inclusion or exclusion of any desired optional packages should be done
before typing "make makelib". The first "make" command will create a
current Makefile.lib with all the file names in your src dir. The
second "make" command will use it to build LAMMPS as a static library,
using 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.
</P>
<H5><B>Shared library:</B>
</H5>
<P>To build LAMMPS as a shared library (*.so file on Linux), which can be
dynamically loaded, e.g. from Python, type
</P>
<PRE>make makeshlib
make -f Makefile.shlib foo
</PRE>
<P>where foo is the machine name. This kind of library is required when
wrapping LAMMPS with Python; see <A HREF = "Section_python.html">Section_python</A>
for details. Again, note that inclusion or exclusion of any desired
optional packages should be done before typing "make makelib". The
first "make" command will create a current Makefile.shlib with all the
file names in your src dir. The second "make" command will use it to
build LAMMPS as a shared library, using the SHFLAGS and SHLIBFLAGS
settings in src/MAKE/Makefile.foo. 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 the Python wrapper uses
by default.
</P>
<P>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/packges, since they are always built as shared libraries with the
-fPIC switch. However, if a library like MPI or FFTW does not exist
as a shared library, the second make command will generate an error.
This means you will need to install a shared library version of the
package. The build instructions for the library should tell you how
to do this.
</P>
<P>As an example, here is how to build and install the <A HREF = "http://www-unix.mcs.anl.gov/mpi">MPICH
library</A>, a popular open-source version of MPI, distributed by
Argonne National Labs, as a shared library in the default
/usr/local/lib location:
</P>
<PRE>./configure --enable-shared
make
make install
</PRE>
<P>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.
</P>
<H5><B>Additional requirement for using a shared library:</B>
</H5>
<P>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.
</P>
<P>For the csh or tcsh shells, you would add something like this to your
~/.cshrc file:
</P>
<PRE>setenv LD_LIBRARY_PATH $<I>LD_LIBRARY_PATH</I>:/home/sjplimp/lammps/src
</PRE>
<H5><B>Calling the LAMMPS library:</B>
</H5>
<P>Either flavor of library (static or shared0 allows one or more LAMMPS
objects to be instantiated from the calling program.
</P>
<P>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.
</P>
<P>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.
</P>
<P>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 <A HREF = "Section_howto.html#howto_10">Section_howto 10</A> of the
manual. See <A HREF = "Section_python.html">Section_python</A> of the manual for a
description of the Python wrapper provided with LAMMPS that operates
through the LAMMPS library interface.
</P>
<P>The files src/library.cpp and library.h define the C-style API for
using LAMMPS as a library. See <A HREF = "Section_howto.html#howto_19">Section_howto
19</A> of the manual for a description of the
interface and how to extend it for your needs.
</P>
<HR>
<H4><A NAME = "start_6"></A>2.6 Running LAMMPS
</H4>
<P>By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux
< in.file. This means you first create an input script (e.g. in.file)
containing the desired commands. <A HREF = "Section_commands.html">This section</A>
describes how input scripts are structured and what commands they
contain.
</P>
<P>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.
</P>
<P>Here is how you might run a standard Lennard-Jones benchmark on a
Linux box, using mpirun to launch a parallel job:
</P>
<PRE>cd src
make linux
cp lmp_linux ../bench
cd ../bench
mpirun -np 4 lmp_linux < in.lj
</PRE>
<P>See <A HREF = "http://lammps.sandia.gov/bench.html">this page</A> for timings for this and the other benchmarks
on various platforms.
</P>
<HR>
<P>On a Windows box, you can skip making LAMMPS and simply download an
executable, as described above, though the pre-packaged executables
include only certain packages.
</P>
<P>To run a LAMMPS executable on a Windows machine, first decide whether
you want to download the non-MPI (serial) or the MPI (parallel)
version of the executable. Download and save the version you have
chosen.
</P>
<P>For the non-MPI version, follow these steps:
</P>
<UL><LI>Get a command prompt by going to Start->Run... ,
then typing "cmd".
<LI>Move to the directory where you have saved lmp_win_no-mpi.exe
(e.g. by typing: cd "Documents").
<LI>At the command prompt, type "lmp_win_no-mpi -in in.lj", replacing in.lj
with the name of your LAMMPS input script.
</UL>
<P>For the MPI version, which allows you to run LAMMPS under Windows on
multiple processors, follow these steps:
</P>
<UL><LI>Download and install
<A HREF = "http://www.mcs.anl.gov/research/projects/mpich2/downloads/index.php?s=downloads">MPICH2</A>
for Windows.
<LI>You'll need to use the mpiexec.exe and smpd.exe files from the MPICH2 package. Put them in
same directory (or path) as the LAMMPS Windows executable.
<LI>Get a command prompt by going to Start->Run... ,
then typing "cmd".
<LI>Move to the directory where you have saved lmp_win_mpi.exe
(e.g. by typing: cd "Documents").
<LI>Then type something like this: "mpiexec -np 4 -localonly lmp_win_mpi -in in.lj",
replacing in.lj with the name of your LAMMPS input script.
<LI>Note that you may need to provide smpd with a passphrase --- it doesn't matter what you
type.
<LI>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.
<LI>Alternatively, you can still use this executable to run on a single processor by
typing something like: "lmp_win_mpi -in in.lj".
</UL>
<HR>
<P>The screen output from LAMMPS is described in the next section. As it
runs, LAMMPS also writes a log.lammps file with the same information.
</P>
<P>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.
</P>
<P>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 <A HREF = "Section_errors.html">Section_errors</A> 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.
</P>
<P>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.
</P>
<P>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.
</P>
<HR>
<H4><A NAME = "start_7"></A>2.7 Command-line options
</H4>
<P>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:
</P>
<UL><LI>-c or -cuda
<LI>-e or -echo
<LI>-i or -in
<LI>-h or -help
<LI>-l or -log
<LI>-nc or -nocite
<LI>-p or -partition
<LI>-pl or -plog
<LI>-ps or -pscreen
<LI>-r or -restart
<LI>-ro or -reorder
<LI>-sc or -screen
<LI>-sf or -suffix
<LI>-v or -var
</UL>
<P>For example, lmp_ibm might be launched as follows:
</P>
<PRE>mpirun -np 16 lmp_ibm -v f tmp.out -l my.log -sc none < in.alloy
mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy
</PRE>
<P>Here are the details on the options:
</P>
<PRE>-cuda on/off
</PRE>
<P>Explicitly enable or disable CUDA support, as provided by the
USER-CUDA package. If LAMMPS is built with this package, as described
above in <A HREF = "#start_3">Section 2.3</A>, then by default LAMMPS will run in
CUDA mode. If this switch is set to "off", then it will not, even if
it was built with the USER-CUDA package, which means you can run
standard LAMMPS or with the GPU package for testing or benchmarking
purposes. The only reason to set the switch to "on", is to check if
LAMMPS was built with the USER-CUDA package, since an error will be
generated if it was not.
</P>
<PRE>-echo style
</PRE>
<P>Set the style of command echoing. The style can be <I>none</I> or <I>screen</I>
or <I>log</I> or <I>both</I>. 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 <I>log</I>. The echo style can also be
set by using the <A HREF = "echo.html">echo</A> command in the input script itself.
</P>
<PRE>-in file
</PRE>
<P>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 input script from stdin - e.g. lmp_linux < in.run.
This is a required switch when running LAMMPS in multi-partition mode,
since multiple processors cannot all read from stdin.
</P>
<PRE>-help
</PRE>
<P>Print a list of options compiled into this executable for each LAMMPS
style (atom_style, fix, compute, pair_style, bond_style, etc). This
can help you know if the command you want to use was included via the
appropriate package. LAMMPS will print the info and immediately exit
if this switch is used.
</P>
<PRE>-log file
</PRE>
<P>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
<A HREF = "log.html">log</A> command in the input script will override this setting.
Option -plog will override the name of the partition log files file.N.
</P>
<PRE>-nocite
</PRE>
<P>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 <A HREF = "http://lammps.sandia.gov/cite.html">citation page</A> for more
details.
</P>
<PRE>-partition 8x2 4 5 ...
</PRE>
<P>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.
</P>
<P>Running with multiple partitions can e useful for running
<A HREF = "Section_howto.html#howto_5">multi-replica simulations</A>, 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.
</P>
<P>To run multiple independent simulatoins from one input script, using
multiple partitions, see <A HREF = "Section_howto.html#howto_4">Section_howto 4</A>
of the manual. World- and universe-style <A HREF = "variable.html">variables</A>
are useful in this context.
</P>
<PRE>-plog file
</PRE>
<P>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.
</P>
<PRE>-pscreen file
</PRE>
<P>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.
</P>
<PRE>-restart restartfile datafile keyword value ...
</PRE>
<P>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:
</P>
<PRE>read_restart restartfile
write_data datafile keyword value ...
</PRE>
<P>Note that the specified restartfile and datafile can have wild-card
characters ("*",%") as described by the
<A HREF = "read_restart.html">read_restart</A> and <A HREF = "write_data.html">write_data</A>
commands. But a filename such as file.* will need to be enclosed in
quotes to avoid shell expansion of the "*" character.
</P>
<P>Also note that following datafile, the same optional keyword/value
pairs can be listed as used by the <A HREF = "write_data.html">write_data</A>
command.
</P>
<PRE>-reorder nth N
-reorder custom filename
</PRE>
<P>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 <A HREF = "run_style.html">run_style verlet/split</A> 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 <A HREF = "Section_accelerate.html">Section_accelerate</A> doc pages for
more details.
</P>
<P>If the keyword <I>nth</I> is used with a setting <I>N</I>, then it means every
Nth processor will be moved to the end of the ranking. This is useful
when using the <A HREF = "run_style.html">run_style verlet/split</A> 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
</P>
<PRE>0 1 2 3 4 5 6 7 8 9 10 11
</PRE>
<P>to
</P>
<PRE>0 1 2 4 5 6 8 9 10 3 7 11
</PRE>
<P>so that the processors in each partition will be
</P>
<PRE>0 1 2 4 5 6 8 9 10
3 7 11
</PRE>
<P>See the "processors" command for how to insure processors from each
partition could then be grouped optimally for quad-core nodes.
</P>
<P>If the keyword is <I>custom</I>, 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:
</P>
<PRE>I J
</PRE>
<P>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.
</P>
<P>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 <A HREF = "processors">processors out</A> command for how to output
info on the final assignment of physical processors to the LAMMPS
simulation domain.
</P>
<PRE>-screen file
</PRE>
<P>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.
</P>
<PRE>-suffix style
</PRE>
<P>Use variants of various styles if they exist. The specified style can
be <I>opt</I>, <I>omp</I>, <I>gpu</I>, or <I>cuda</I>. These refer to optional packages that
LAMMPS can be built with, as described above in <A HREF = "#start_3">Section
2.3</A>. The "opt" style corrsponds to the OPT package, the
"omp" style to the USER-OMP package, the "gpu" style to the GPU
package, and the "cuda" style to the USER-CUDA package.
</P>
<P>As an example, all of the packages provide a <A HREF = "pair_lj.html">pair_style
lj/cut</A> variant, with style names lj/cut/opt, lj/cut/omp,
lj/cut/gpu, or lj/cut/cuda. A variant styles can be specified
explicitly in your input script, e.g. pair_style lj/cut/gpu. If the
-suffix switch is used, you do not need to modify your input script.
The specified suffix (opt,omp,gpu,cuda) is automatically appended
whenever your input script command creates a new
<A HREF = "atom_style.html">atom</A>, <A HREF = "pair_style.html">pair</A>, <A HREF = "fix.html">fix</A>,
<A HREF = "compute.html">compute</A>, or <A HREF = "run_style.html">run</A> style. If the variant
version does not exist, the standard version is created.
</P>
<P>For the GPU package, using this command-line switch also invokes the
default GPU settings, as if the command "package gpu force/neigh 0 0
1" were used at the top of your input script. These settings can be
changed by using the <A HREF = "package.html">package gpu</A> command in your script
if desired.
</P>
<P>For the OMP package, using this command-line switch also invokes the
default OMP settings, as if the command "package omp *" were used at
the top of your input script. These settings can be changed by using
the <A HREF = "package.html">package omp</A> command in your script if desired.
</P>
<P>The <A HREF = "suffix.html">suffix</A> command can also set a suffix and it can also
turn off/on any suffix setting made via the command line.
</P>
<PRE>-var name value1 value2 ...
</PRE>
<P>Specify a variable that will be defined for substitution purposes when
the input script is read. "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 <A HREF = "variable.html">index-style
variable</A> 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 <A HREF = "variable.html">variable</A> command for more info on
defining index and other kinds of variables and <A HREF = "Section_commands.html#cmd_2">this
section</A> for more info on using variables
in input scripts.
</P>
<P>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.
</P>
<HR>
<H4><A NAME = "start_8"></A>2.8 LAMMPS screen output
</H4>
<P>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:
</P>
<PRE>Loop time of 49.002 on 2 procs for 2004 atoms
</PRE>
<PRE>Pair time (%) = 35.0495 (71.5267)
Bond time (%) = 0.092046 (0.187841)
Kspce time (%) = 6.42073 (13.103)
Neigh time (%) = 2.73485 (5.5811)
Comm time (%) = 1.50291 (3.06703)
Outpt time (%) = 0.013799 (0.0281601)
Other time (%) = 2.13669 (4.36041)
</PRE>
<PRE>Nlocal: 1002 ave, 1015 max, 989 min
Histogram: 1 0 0 0 0 0 0 0 0 1
Nghost: 8720 ave, 8724 max, 8716 min
Histogram: 1 0 0 0 0 0 0 0 0 1
Neighs: 354141 ave, 361422 max, 346860 min
Histogram: 1 0 0 0 0 0 0 0 0 1
</PRE>
<PRE>Total # of neighbors = 708282
Ave neighs/atom = 353.434
Ave special neighs/atom = 2.34032
Number of reneighborings = 42
Dangerous reneighborings = 2
</PRE>
<P>The first section gives the breakdown of the CPU run time (in seconds)
into major categories. The second 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.
</P>
<P>The last section gives aggregate statistics for pair-wise neighbors
and special neighbors that LAMMPS keeps track of (see the
<A HREF = "special_bonds.html">special_bonds</A> 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
<A HREF = "neigh_modify.html">neigh_modify</A> 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.
</P>
<P>If an energy minimization was performed via the
<A HREF = "minimize.html">minimize</A> command, additional information is printed,
e.g.
</P>
<PRE>Minimization stats:
E initial, next-to-last, final = -0.895962 -2.94193 -2.94342
Gradient 2-norm init/final= 1920.78 20.9992
Gradient inf-norm init/final= 304.283 9.61216
Iterations = 36
Force evaluations = 177
</PRE>
<P>The first 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.
The last 2 lines are 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.
</P>
<P>If a <A HREF = "kspace_style.html">kspace_style</A> long-range Coulombics solve was
performed during the run (PPPM, Ewald), then additional information is
printed, e.g.
</P>
<PRE>FFT time (% of Kspce) = 0.200313 (8.34477)
FFT Gflps 3d 1d-only = 2.31074 9.19989
</PRE>
<P>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.
</P>
<HR>
<H4><A NAME = "start_9"></A>2.9 Tips for users of previous LAMMPS versions
</H4>
<P>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 <A HREF = "Section_history.html">Section_history</A>. The F90 and F77 versions
(2001 and 99) are also freely distributed as open-source codes; check
the <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> 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.
</P>
<P>If you are a previous user of LAMMPS 2001, these are the most
significant changes you will notice in C++ LAMMPS:
</P>
<P>(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).
</P>
<P>(2) All the functionality of LAMMPS 2001 is included in C++ LAMMPS,
but you may need to specify the relevant commands in different ways.
</P>
<P>(3) The format of the data file can be streamlined for some problems.
See the <A HREF = "read_data.html">read_data</A> command for details. The data file
section "Nonbond Coeff" has been renamed to "Pair Coeff" in C++ LAMMPS.
</P>
<P>(4) Binary restart files written by LAMMPS 2001 cannot be read by C++
LAMMPS with a <A HREF = "read_restart.html">read_restart</A> 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 <I>restart2data</I> 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 <A HREF = "read_data.html">read_data</A> command to read it in.
</P>
<P>(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.
</P>
</HTML>
diff --git a/doc/Section_start.txt b/doc/Section_start.txt
index b11648ffe..8f1b624fc 100644
--- a/doc/Section_start.txt
+++ b/doc/Section_start.txt
@@ -1,1427 +1,1432 @@
"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.4 "Building LAMMPS via the Make.py script"_#start_4
2.5 "Building LAMMPS as a library"_#start_5
2.6 "Running LAMMPS"_#start_6
2.7 "Command-line options"_#start_7
2.8 "Screen output"_#start_8
2.9 "Tips for users of previous versions"_#start_9 :all(b)
:line
:line
2.1 What's in the LAMMPS distribution :h4,link(start_1)
When you download LAMMPS you will need to unzip and untar the
downloaded file with the following commands, after placing the file in
an appropriate directory.
gunzip lammps*.tar.gz
tar xvf lammps*.tar :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=:)
If you download one of the Windows executables from the download page,
then you just get a single file:
lmp_windows.exe :pre
Skip to the "Running LAMMPS"_#start_6 sections for info on how to
launch these executables on a Windows box.
The Windows executables for serial or parallel only include certain
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 something with more packages
or that is more current, you'll have to download the source tarball
and build it yourself from source code using Microsoft Visual Studio,
as described in the next section.
:line
2.2 Making LAMMPS :h4,link(start_2)
This section has the following sub-sections:
"Read this first"_#start_2_1
"Steps to build a LAMMPS executable"_#start_2_2
"Common errors that can occur when making LAMMPS"_#start_2_3
"Additional build tips"_#start_2_4
"Building for a Mac"_#start_2_5
"Building for Windows"_#start_2_6 :ul
:line
[{Read this first:}] :link(start_2_1)
Building LAMMPS can be non-trivial. You may need to edit a makefile,
there are compiler options to consider, additional libraries can be
used (MPI, FFT, JPEG, PNG), LAMMPS packages may be included or
excluded, some of these packages use auxiliary libraries which need to
be pre-built, etc.
Please read this section 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
compiling, linking, and run problems that users have 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 a question 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 Makefile for in the src/MAKE directory, send it
to the developers and we can include it in the LAMMPS distribution.
:line
[{Steps to build a LAMMPS executable:}] :link(start_2_2)
[Step 0]
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 machines. From within the src
directory, type "make" or "gmake". You should see a list of available
choices. If one of those is the machine and options you want, you can
type a command like:
make linux
or
gmake mac :pre
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_linux or lmp_mac is
produced, 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]
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 src/MAKE/Makefile.* 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.
[Step 2]
Change the first line of src/MAKE/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]
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 mpicc 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 commercial 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.
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++ 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]
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
-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.
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.
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,
--D-DLAMMPS_SMALLSMALL settings. The default is -DLAMMPS_SMALLBIG.
-These settings refer to use of 4-byte (small) vs 8-byte (big) integers
+Use at most one of the -DLAMMPS_SMALLBIG, -DLAMMPS_BIGBIG, -D-
+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
-with more than 2 billion atoms or to allow moving atoms to wrap back
-through a periodic box more than 512 times. The only reason to use
-the SMALLSMALL setting is if your machine does not support 64-bit
-integers. See the "Additional build tips"_#start_2_4 section below
-for more details.
+(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. The only reason to use the SMALLSMALL setting is
+if your machine does not support 64-bit integers. See the "Additional
+build tips"_#start_2_4 section below for more details.
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.
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]
The 3 MPI variables are used to specify an MPI library to build LAMMPS
with.
If you want LAMMPS to run in parallel, you must have an MPI library
installed on your platform. If you use an MPI-wrapped compiler, such
as "mpicc" to build LAMMPS, you should be able to leave these 3
variables blank; the MPI wrapper knows where to find the needed files.
If not, and MPI is installed on your system in the usual place (under
/usr/local), you also may not need to specify these 3 variables. 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 MPI which the compiler has no trouble finding.
Failing this, with these 3 variables you can 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 the
src/MAKE/Makefile.serial file 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. To build from the src
directory, type "make stubs", or from the 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]
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 various 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, SCSL, FFTW2, and FFTW3. Legacy options are: INTEL, SGI,
ACML, and T3E. For backward compatability, using -DFFT_FFTW will use
the FFTW2 library. Using -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.
FFTW is a fast, portable library that should also work on any
platform. 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.
Note that on some platforms FFTW2 has been pre-installed, and uses
renamed files indicating the precision it was compiled with,
e.g. sfftw.h, or dfftw.h instead of fftw.h. In this case, you can
specify an additional define variable for FFT_INC called -DFFTW_SIZE,
which will select the correct include file. In this case, for FFT_LIB
you must also manually specify the correct library, namely -lsfftw or
-ldfftw.
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.
[Step 7]
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]
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]
That's it. Once you have a correct Makefile.foo, you have installed
the optional LAMMPS packages you want to include in your build, and
you have pre-built any other needed libraries (e.g. MPI, FFT, package
libraries), all you need to do from the src directory is type
something like this:
make foo
or
gmake foo :pre
You should get the executable lmp_foo when the build is complete.
:line
[{Errors that can occur when making LAMMPS:}] :link(start_2_3)
IMPORTANT NOTE: 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 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:}] :link(start_2_4)
(1) Building LAMMPS for multiple platforms.
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.
(2) Cleaning up.
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.
(3) Changing the LAMMPS size limits via -DLAMMPS_SMALLBIG or
--DLAMMPS_BIBIG or -DLAMMPS_SMALLSMALL
+-DLAMMPS_BIGBIG or -DLAMMPS_SMALLSMALL
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 timesteps (about 9 billion billion). The atom limit is
-for atomic systems that do not require atom IDs. For molecular
-models, which require atom IDs, the limit is 2^31 atoms (about 2
-billion). With this setting, image flags are stored in 32-bit
-integers, which means for 3 dimensions that atoms can only wrap around
-a periodic box at most 512 times. If atoms move through the periodic
-box more than this limit, 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 molecular systems or larger image flags, compile
-with -DLAMMPS_BIGBIG. This enables molecular systems with up to 2^63
-atoms (about 9 billion billion). And image flags will not "roll over"
-until they reach 2^20 = 1048576.
-
-IMPORTANT NOTE: As of 6/2012, the BIGBIG setting does not yet enable
-molecular systems to grow as large as 2^63. Only the image flag roll
-over is currently affected by this compile option.
+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 your
-total number of atoms (for atomic or molecular models) and timesteps
+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 also settings for the MPI data
-types associated with the integers that store atom IDs and total
-system sizes. These need to be consistent with the associated C data
-types, or else LAMMPS will generate a run-time error.
-
-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 restriction 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.
+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:}] :link(start_2_5)
OS X is BSD Unix, so it should just work. See the
src/MAKE/Makefile.mac file.
:line
[{Building for Windows:}] :link(start_2_6)
The LAMMPS download page has an option to download both a serial and
parallel pre-built Windows exeutable. See the "Running
LAMMPS"_#start_6 section for instructions for running these
executables on a Windows box.
The pre-built executables are built with a subset of the available
pacakges; see the download page for the list. If you want
a Windows version with specific packages included and excluded,
you can build it yourself.
One way to do this is install and use cygwin to build LAMMPS with a
standard Linus make, just as you would on any Linux box; see
src/MAKE/Makefile.cygwin.
The other way to do this is using Visual Studio and project files.
See the src/WINDOWS directory and its README.txt file for instructions
on both a basic build and a customized build with pacakges you select.
:line
2.3 Making LAMMPS with optional packages :h4,link(start_3)
This section has the following sub-sections:
"Package basics"_#start_3_1
"Including/excluding packages"_#start_3_2
"Packages that require extra libraries"_#start_3_3
"Additional Makefile settings for extra libraries"_#start_3_4 :ul
:line
[{Package basics:}] :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. You
can see the list of all packages by typing "make package" from within
the src directory of the LAMMPS distribution.
If you use a command in a LAMMPS input script that is specific to a
particular 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 also 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
known to your executable.
There are two kinds of packages in LAMMPS, standard and user packages.
More information about the contents of standard and user packages is
given in "Section_packages"_Section_packages.html of the manual. The
difference between standard and user packages is as follows:
Standard packages are supported by the LAMMPS developers and are
written in a syntax and style consistent with the rest of LAMMPS.
This means we 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 always begin with
the user prefix. If they are a single command (single file), they are
typically in the user-misc package. Otherwise, they are a a set of
files grouped together which add a specific functionality to the code.
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 will likely need to contact the contributor directly to
get help. Information on how to submit additions you make to LAMMPS
as a user-contributed package is given in "this
section"_Section_modify.html#mod_15 of the documentation.
Some packages (both standard and user) require additional libraries.
See more details below.
:line
[{Including/excluding packages:}] :link(start_3_2)
To use or not use a package you must include or exclude it before
building LAMMPS. From the src directory, this is typically as simple
as:
make yes-colloid
make g++ :pre
or
make no-manybody
make g++ :pre
IMPORTANT NOTE: You should NOT include/exclude packages and build
LAMMPS in a single make command by using multiple targets, e.g. make
yes-colloid g++. 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 during the same command.
Some packages have individual files that depend on other packages
being included. 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.
The reason to exclude packages is if you will never run certain kinds
of simulations. For some packages, this will keep you from having to
build auxiliary libraries (see below), and will also produce a smaller
executable which may run a bit faster.
When you download a LAMMPS tarball, these packages are pre-installed
in the src directory: KSPACE, MANYBODY,MOLECULE. When you download
LAMMPS source files from the SVN or Git repositories, no packages are
pre-installed.
Packages are included or excluded by typing "make yes-name" or "make
no-name", 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 "make yes-standard", "make
no-standard", "make yes-user", "make no-user", "make yes-all" or "make
no-all" to include/exclude various sets of packages. Type "make
package" to see the all of the package-related make options.
IMPORTANT NOTE: Inclusion/exclusion of 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 seen or not seen when LAMMPS is built. After
you have included or excluded a package, you must re-build LAMMPS.
Additional package-related make options exist to help manage LAMMPS
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 WWW site.
Typing "make package-update" will overwrite src files with files from
the package sub-directories if the package has been included. It
should be used after a patch is installed, 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-status" will show which packages are currently
included. Of those that are included, it will list files that are
different in the src directory and package sub-directory. Typing
"make package-diff" lists all differences between these files. Again,
type "make package" to see all of the package-related make options.
:line
[{Packages that require extra libraries:}] :link(start_3_3)
A few of the standard and user packages require additional auxiliary
libraries. They must be compiled first, before LAMMPS is built. If
you get a LAMMPS build error about a missing library, this is likely
the reason. See the "Section_packages"_Section_packages.html doc page
for a list of packages that have auxiliary libraries.
Code for some of these auxiliary libraries is included in the LAMMPS
distribution under the lib directory. Examples are the USER-ATC and
MEAM packages. Some auxiliary libraries are not included with LAMMPS;
to use the associated package you must download and install the
auxiliary library yourself. Examples are the KIM and VORONOI and
USER-MOLFILE packages.
For libraries with provided source code, each lib directory has a
README file (e.g. lib/reax/README) with instructions on how to build
that library. Typically this is done by typing something like:
make -f Makefile.g++ :pre
If one of the provided Makefiles is not
appropriate for your system you will need to edit or add one.
Note that all the Makefiles have a setting for EXTRAMAKE at
the top that names a Makefile.lammps.* file.
If successful, this will produce 2 files in the lib directory:
libpackage.a
Makefile.lammps :pre
The Makefile.lammps file is a copy of the EXTRAMAKE file specified
in the Makefile you used.
You MUST insure that the settings in Makefile.lammps are appropriate
for your system. If they are not, the LAMMPS build will fail.
As explained in the lib/package/README files, they are used to specify
additional system libraries and their locations so that LAMMPS can
build with the auxiliary library. For example, if the MEAM or REAX
packages are used, the auxiliary libraries consist of F90 code, build
with a F90 complier. To link that library with LAMMPS (a C++ code)
via whatever C++ compiler LAMMPS is built with, typically requires
additional Fortran-to-C libraries be included in the link. Another
example are the BLAS and LAPACK libraries needed to use the USER-ATC
or USER-AWPMD packages.
For libraries without provided source code, see the
src/package/Makefile.lammps file for information on where to find the
library and how to build it. E.g. the file src/KIM/Makefile.lammps or
src/VORONOI/Makefile.lammps or src/UESR-MOLFILE/Makefile.lammps.
These files serve the same purpose as the lib/package/Makefile.lammps
files described above. The files have settings needed when LAMMPS is
built to link with the corresponding auxiliary library. Again, you
MUST insure that the settings in src/package/Makefile.lammps are
appropriate for your system and where you installed the auxiliary
library. If they are not, the LAMMPS build will fail.
:line
2.4 Building LAMMPS via the Make.py script :h4,link(start_4)
The src directory includes a Make.py script, written
in Python, which can be used to automate various steps
of the build process.
You can run the script from the src directory by typing either:
Make.py
python Make.py :pre
which will give you info about the tool. For the former to work, you
may need to edit the 1st line of the script to point to your local
Python. And you may need to insure the script is executable:
chmod +x Make.py :pre
The following options are supported as switches:
-i file1 file2 ...
-p package1 package2 ...
-u package1 package2 ...
-e package1 arg1 arg2 package2 ...
-o dir
-b machine
-s suffix1 suffix2 ...
-l dir
-j N
-h switch1 switch2 ... :ul
Help on any switch can be listed by using -h, e.g.
Make.py -h -i -p :pre
At a hi-level, these are the kinds of package management
and build tasks that can be performed easily, using
the Make.py tool:
install/uninstall packages and build the associated external libs (use -p and -u and -e)
install packages needed for one or more input scripts (use -i and -p)
build LAMMPS, either in the src dir or new dir (use -b)
create a new dir with only the source code needed for one or more input scripts (use -i and -o) :ul
The last bullet can be useful when you wish to build a stripped-down
version of LAMMPS to run a specific script(s). Or when you wish to
move the minimal amount of files to another platform for a remote
LAMMPS build.
Note that using Make.py is not a substitute for insuring you have a
valid src/MAKE/Makefile.foo for your system, or that external library
Makefiles in any lib/* directories you use are also valid for your
system. But once you have done that, you can use Make.py to quickly
include/exclude the packages and external libraries needed by your
input scripts.
:line
2.5 Building LAMMPS as a library :h4,link(start_5)
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 makelib
make -f Makefile.lib foo :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. Note that
inclusion or exclusion of any desired optional packages should be done
before typing "make makelib". The first "make" command will create a
current Makefile.lib with all the file names in your src dir. The
second "make" command will use it to build LAMMPS as a static library,
using 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.
[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 makeshlib
make -f Makefile.shlib foo :pre
where foo is the machine name. This kind of library is required when
wrapping LAMMPS with Python; see "Section_python"_Section_python.html
for details. Again, note that inclusion or exclusion of any desired
optional packages should be done before typing "make makelib". The
first "make" command will create a current Makefile.shlib with all the
file names in your src dir. The second "make" command will use it to
build LAMMPS as a shared library, using the SHFLAGS and SHLIBFLAGS
settings in src/MAKE/Makefile.foo. 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 the Python wrapper uses
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/packges, since they are always built as shared libraries with the
-fPIC switch. However, if a library like MPI or FFTW does not exist
as a shared library, the second make command will generate an error.
This means you will need to install a shared library version of the
package. The build instructions for the library should tell you how
to do this.
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 shared0 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_howto 10"_Section_howto.html#howto_10 of the
manual. See "Section_python"_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_howto
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.6 Running LAMMPS :h4,link(start_6)
By default, LAMMPS runs by reading commands from stdin; e.g. lmp_linux
< in.file. This means you first create an input script (e.g. in.file)
containing the desired commands. "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.lj :pre
See "this page"_bench for timings for this and the other benchmarks
on various platforms.
:link(bench,http://lammps.sandia.gov/bench.html)
:line
On a Windows box, you can skip making LAMMPS and simply download an
executable, as described above, though the pre-packaged executables
include only certain packages.
To run a LAMMPS executable on a Windows machine, first decide whether
you want to download the non-MPI (serial) or the MPI (parallel)
version of the executable. Download and save the version you have
chosen.
For the non-MPI version, follow these steps:
Get a command prompt by going to Start->Run... ,
then typing "cmd". :ulb,l
Move to the directory where you have saved lmp_win_no-mpi.exe
(e.g. by typing: cd "Documents"). :l
At the command prompt, type "lmp_win_no-mpi -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
You'll need to use the mpiexec.exe and smpd.exe files from the MPICH2 package. Put them in
same directory (or path) as the LAMMPS Windows executable. :l
Get a command prompt by going to Start->Run... ,
then typing "cmd". :l
Move to the directory where you have saved lmp_win_mpi.exe
(e.g. by typing: cd "Documents"). :l
Then type something like this: "mpiexec -np 4 -localonly lmp_win_mpi -in in.lj",
replacing in.lj with the name of your LAMMPS input script. :l
Note that you may need to provide smpd with a passphrase --- it doesn't matter what you
type. :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
Alternatively, you can still use this executable to run on a single processor by
typing something like: "lmp_win_mpi -in in.lj". :l,ule
:line
The screen output from LAMMPS is described in the next section. 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_errors"_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.7 Command-line options :h4,link(start_7)
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:
-c or -cuda
-e or -echo
-i or -in
-h or -help
-l or -log
-nc or -nocite
-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.alloy
mpirun -np 16 lmp_ibm -var f tmp.out -log my.log -screen none < in.alloy :pre
Here are the details on the options:
-cuda on/off :pre
Explicitly enable or disable CUDA support, as provided by the
USER-CUDA package. If LAMMPS is built with this package, as described
above in "Section 2.3"_#start_3, then by default LAMMPS will run in
CUDA mode. If this switch is set to "off", then it will not, even if
it was built with the USER-CUDA package, which means you can run
standard LAMMPS or with the GPU package for testing or benchmarking
purposes. The only reason to set the switch to "on", is to check if
LAMMPS was built with the USER-CUDA package, since an error will be
generated if it was not.
-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.
-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 input script from stdin - e.g. lmp_linux < in.run.
This is a required switch when running LAMMPS in multi-partition mode,
since multiple processors cannot all read from stdin.
-help :pre
Print a list of options compiled into this executable for each LAMMPS
style (atom_style, fix, compute, pair_style, bond_style, etc). This
can help you know if the command you want to use was included via the
appropriate package. LAMMPS will print the info and immediately exit
if this switch is used.
-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.
-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_howto 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 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
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.
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_accelerate"_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 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 :pre
Use variants of various styles if they exist. The specified style can
be {opt}, {omp}, {gpu}, or {cuda}. These refer to optional packages that
LAMMPS can be built with, as described above in "Section
2.3"_#start_3. The "opt" style corrsponds to the OPT package, the
"omp" style to the USER-OMP package, the "gpu" style to the GPU
package, and the "cuda" style to the USER-CUDA package.
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, or lj/cut/cuda. A variant styles can be specified
explicitly in your input script, e.g. pair_style lj/cut/gpu. If the
-suffix switch is used, you do not need to modify your input script.
The specified suffix (opt,omp,gpu,cuda) 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 force/neigh 0 0
1" were used at the top of your input script. These settings can be
changed by using the "package gpu"_package.html command in your script
if desired.
For the OMP package, using this command-line switch also invokes the
default OMP settings, as if the command "package omp *" were used at
the top of your input script. These settings can be changed by using
the "package omp"_package.html command in your script if desired.
The "suffix"_suffix.html command can also set a suffix and it can also
turn off/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. "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.8 LAMMPS screen output :h4,link(start_8)
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 49.002 on 2 procs for 2004 atoms :pre
Pair time (%) = 35.0495 (71.5267)
Bond time (%) = 0.092046 (0.187841)
Kspce time (%) = 6.42073 (13.103)
Neigh time (%) = 2.73485 (5.5811)
Comm time (%) = 1.50291 (3.06703)
Outpt time (%) = 0.013799 (0.0281601)
Other time (%) = 2.13669 (4.36041) :pre
Nlocal: 1002 ave, 1015 max, 989 min
Histogram: 1 0 0 0 0 0 0 0 0 1
Nghost: 8720 ave, 8724 max, 8716 min
Histogram: 1 0 0 0 0 0 0 0 0 1
Neighs: 354141 ave, 361422 max, 346860 min
Histogram: 1 0 0 0 0 0 0 0 0 1 :pre
Total # of neighbors = 708282
Ave neighs/atom = 353.434
Ave special neighs/atom = 2.34032
Number of reneighborings = 42
Dangerous reneighborings = 2 :pre
The first section gives the breakdown of the CPU run time (in seconds)
into major categories. The second 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:
E initial, next-to-last, final = -0.895962 -2.94193 -2.94342
Gradient 2-norm init/final= 1920.78 20.9992
Gradient inf-norm init/final= 304.283 9.61216
Iterations = 36
Force evaluations = 177 :pre
The first 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.
The last 2 lines are 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.9 Tips for users of previous LAMMPS versions :h4,link(start_9)
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_history"_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/atom_modify.html b/doc/atom_modify.html
index 2eaa729fb..4a15940e7 100644
--- a/doc/atom_modify.html
+++ b/doc/atom_modify.html
@@ -1,138 +1,177 @@
<HTML>
-<CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A>
+<CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS
+Commands</A>
</CENTER>
<HR>
<H3>atom_modify command
</H3>
<P><B>Syntax:</B>
</P>
<PRE>atom_modify keyword values ...
</PRE>
<UL><LI>one or more keyword/value pairs may be appended
-<LI>keyword = <I>map</I> or <I>first</I> or <I>sort</I>
+<LI>keyword = <I>id</I> or <I>map</I> or <I>first</I> or <I>sort</I>
-<PRE> <I>map</I> value = <I>array</I> or <I>hash</I>
- <I>first</I> value = group-ID = group whose atoms will appear first in internal atom lists
- <I>sort</I> values = Nfreq binsize
- Nfreq = sort atoms spatially every this many time steps
- binsize = bin size for spatial sorting (distance units)
+<PRE> <I>id</I> value = <I>yes</I> or <I>no</I>
+ <I>map</I> value = <I>array</I> or <I>hash</I>
+ <I>first</I> value = group-ID = group whose atoms will appear first in internal atom lists
+ <I>sort</I> values = Nfreq binsize
+ Nfreq = sort atoms spatially every this many time steps
+ binsize = bin size for spatial sorting (distance units)
</PRE>
</UL>
<P><B>Examples:</B>
</P>
<PRE>atom_modify map hash
atom_modify map array sort 10000 2.0
atom_modify first colloid
</PRE>
<P><B>Description:</B>
</P>
-<P>Modify properties of the atom style selected within LAMMPS.
+<P>Modify certain attributes of atoms defined and stored within LAMMPS,
+in addition to what is specified by the <A HREF = "atom_style.html">atom_style</A>
+command. The <I>id</I> and <I>map</I> keywords must be specified before a
+simulation box is defined; other keywords can be specified any time.
+</P>
+<P>The <I>id</I> keyword determines whether non-zero atom IDs can be assigned
+to each atom. If the value is <I>yes</I>, which is the default, IDs are
+assigned, whether you use the <A HREF = "create_atoms.html">create atoms</A> or
+<A HREF = "read_data.html">read_data</A> or <A HREF = "read_restart.html">read_restart</A>
+commands to initialize atoms. If atom IDs are used, they must all be
+positive integers. They should also be unique, though LAMMPS does not
+check for this. Typically they should also be consecutively numbered
+(from 1 to Natoms), though this is not required. Molecular <A HREF = "atom_style.html">atom
+styles</A> are those that store bond topology information
+(styles bond, angle, molecular, full). These styles require atom IDs
+since the IDs are used to encode the topology. Some other LAMMPS
+commands also require the use of atom IDs. E.g. some many-body pair
+styles use them to avoid double computation of the I-J interaction
+between two atoms.
+</P>
+<P>The only reason not to use atom IDs is if you are running an atomic
+simulation so large that IDs cannot be uniquely assigned. For a
+default LAMMPS build this limit is 2^31 or about 2 billion atoms.
+However, even in this case, you can use 64-bit atom IDs, allowing 2^63
+or about 9e18 atoms, if you build LAMMPS with the - DLAMMPS_BIGBIG
+switch. This is described in <A HREF = "Section_start.html#start_2">Section 2.2</A>
+of the manual. If atom IDs are not used, they must be specified as 0
+for all atoms, e.g. in a data or restart file.
</P>
<P>The <I>map</I> keyword determines how atom ID lookup is done for molecular
-problems. Lookups are performed by bond (angle, etc) routines in
+atom styles. Lookups are performed by bond (angle, etc) routines in
LAMMPS to find the local atom index associated with a global atom ID.
-When the <I>array</I> value is used, each processor stores a lookup table
-of length N, where N is the total # of atoms in the system. This is
-the fastest method for most simulations, but a processor can run out
-of memory to store the table for very large simulations. The <I>hash</I>
-value uses a hash table to perform the lookups. This method can be
-slightly slower than the <I>array</I> method, but its memory cost is
-proportional to N/P on each processor, where P is the total number of
-processors running the simulation.
+</P>
+<P>When the <I>array</I> value is used, each processor stores a lookup table
+of length N, where N is the largest atom ID in the system. This is a
+fast, simple method for many simulations, but requires too much memory
+for large simulations. The <I>hash</I> value uses a hash table to perform
+the lookups. This can be slightly slower than the <I>array</I> method, but
+its memory cost is proportional to the number of atoms owned by a
+processor, i.e. N/P when N is the total number of atoms in the system
+and P is the number of processors.
+</P>
+<P>When this setting is not specified in your input script, LAMMPS
+creates a map, if one is needed, as an array or hash. See the
+discussion of default values below for how LAMMPS chooses which kind
+of map to build. Note that atomic systems do not normally need to
+create a map. However, even in this case some LAMMPS commands will
+create a map to find atoms (and then destroy it), or require a
+permanent map. An example of the former is the <A HREF = "velocity.html">velocity loop
+all</A> command, which uses a map when looping over all
+atoms and insuring the same velocity values are assigned to an atom
+ID, no matter which processor owns it.
</P>
<P>The <I>first</I> keyword allows a <A HREF = "group.html">group</A> to be specified whose
atoms will be maintained as the first atoms in each processor's list
of owned atoms. This in only useful when the specified group is a
small fraction of all the atoms, and there are other operations LAMMPS
is performing that will be sped-up significantly by being able to loop
over the smaller set of atoms. Otherwise the reordering required by
this option will be a net slow-down. The <A HREF = "neigh_modify.html">neigh_modify
include</A> and <A HREF = "communicate.html">communicate group</A>
commands are two examples of commands that require this setting to
work efficiently. Several <A HREF = "fix.html">fixes</A>, most notably time
integration fixes like <A HREF = "fix_nve.html">fix nve</A>, also take advantage of
this setting if the group they operate on is the group specified by
this command. Note that specifying "all" as the group-ID effectively
turns off the <I>first</I> option.
</P>
<P>It is OK to use the <I>first</I> keyword with a group that has not yet been
defined, e.g. to use the atom_modify first command at the beginning of
your input script. LAMMPS does not use the group until a simullation
is run.
</P>
<P>The <I>sort</I> keyword turns on a spatial sorting or reordering of atoms
within each processor's sub-domain every <I>Nfreq</I> timesteps. If
<I>Nfreq</I> is set to 0, then sorting is turned off. Sorting can improve
cache performance and thus speed-up a LAMMPS simulation, as discussed
in a paper by <A HREF = "#Meloni">(Meloni)</A>. Its efficacy depends on the problem
size (atoms/processor), how quickly the system becomes disordered, and
various other factors. As a general rule, sorting is typically more
effective at speeding up simulations of liquids as opposed to solids.
In tests we have done, the speed-up can range from zero to 3-4x.
</P>
<P>Reordering is peformed every <I>Nfreq</I> timesteps during a dynamics run
or iterations during a minimization. More precisely, reordering
occurs at the first reneighboring that occurs after the target
timestep. The reordering is performed locally by each processor,
using bins of the specified <I>binsize</I>. If <I>binsize</I> is set to 0.0,
then a binsize equal to half the <A HREF = "neighbor.html">neighbor</A> cutoff
distance (force cutoff plus skin distance) is used, which is a
reasonable value. After the atoms have been binned, they are
reordered so that atoms in the same bin are adjacent to each other in
the processor's 1d list of atoms.
</P>
<P>The goal of this procedure is for atoms to put atoms close to each
other in the processor's one-dimensional list of atoms that are also
near to each other spatially. This can improve cache performance when
pairwise intereractions and neighbor lists are computed. Note that if
bins are too small, there will be few atoms/bin. Likewise if bins are
too large, there will be many atoms/bin. In both cases, the goal of
cache locality will be undermined.
</P>
<P>IMPORTANT NOTE: Running a simulation with sorting on versus off should
not change the simulation results in a statistical sense. However, a
different ordering will induce round-off differences, which will lead
to diverging trajectories over time when comparing two simluations.
Various commands, particularly those which use random numbers
(e.g. <A HREF = "velocity.html">velocity create</A>, and <A HREF = "fix_langevin.html">fix
langevin</A>), may generate (statistically identical)
results which depend on the order in which atoms are processed. The
order of atoms in a <A HREF = "dump.html">dump</A> file will also typically change
if sorting is enabled.
</P>
<P><B>Restrictions:</B>
</P>
-<P>The map keyword can only be used before the simulation box is defined
-by a <A HREF = "read_data.html">read_data</A> or <A HREF = "create_box.html">create_box</A>
-command.
-</P>
<P>The <I>first</I> and <I>sort</I> options cannot be used together. Since sorting
is on by default, it will be turned off if the <I>first</I> keyword is
used with a group-ID that is not "all".
</P>
<P><B>Related commands:</B> none
</P>
<P><B>Default:</B>
</P>
-<P>By default, atomic (non-molecular) problems do not allocate maps. For
-molecular problems, the option default is map = array. By default, a
-"first" group is not defined. By default, sorting is enabled with a
-frequency of 1000 and a binsize of 0.0, which means the neighbor
+<P>By default, <I>id</I> is yes. By default, atomic systems (no bond topology
+info) do not use a map. For molecular systems (with bond topology
+info), a map is used. The default map style is array if no atom ID is
+larger than 1 million, otherwise the default is hash. By default, a
+"first" group is not defined. By default, sorting is enabled with a
+frequency of 1000 and a binsize of 0.0, which means the neighbor
cutoff will be used to set the bin size.
</P>
<HR>
<A NAME = "Meloni"></A>
<P><B>(Meloni)</B> Meloni, Rosati and Colombo, J Chem Phys, 126, 121102 (2007).
</P>
</HTML>
diff --git a/doc/atom_modify.txt b/doc/atom_modify.txt
index b3992bb41..e738ba427 100644
--- a/doc/atom_modify.txt
+++ b/doc/atom_modify.txt
@@ -1,129 +1,168 @@
-"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+"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
atom_modify command :h3
[Syntax:]
atom_modify keyword values ... :pre
one or more keyword/value pairs may be appended :ulb,l
-keyword = {map} or {first} or {sort} :l
- {map} value = {array} or {hash}
- {first} value = group-ID = group whose atoms will appear first in internal atom lists
- {sort} values = Nfreq binsize
- Nfreq = sort atoms spatially every this many time steps
- binsize = bin size for spatial sorting (distance units) :pre
+keyword = {id} or {map} or {first} or {sort} :l
+ {id} value = {yes} or {no}
+ {map} value = {array} or {hash}
+ {first} value = group-ID = group whose atoms will appear first in internal atom lists
+ {sort} values = Nfreq binsize
+ Nfreq = sort atoms spatially every this many time steps
+ binsize = bin size for spatial sorting (distance units) :pre
:ule
[Examples:]
atom_modify map hash
atom_modify map array sort 10000 2.0
atom_modify first colloid :pre
[Description:]
-Modify properties of the atom style selected within LAMMPS.
+Modify certain attributes of atoms defined and stored within LAMMPS,
+in addition to what is specified by the "atom_style"_atom_style.html
+command. The {id} and {map} keywords must be specified before a
+simulation box is defined; other keywords can be specified any time.
+
+The {id} keyword determines whether non-zero atom IDs can be assigned
+to each atom. If the value is {yes}, which is the default, IDs are
+assigned, whether you use the "create atoms"_create_atoms.html or
+"read_data"_read_data.html or "read_restart"_read_restart.html
+commands to initialize atoms. If atom IDs are used, they must all be
+positive integers. They should also be unique, though LAMMPS does not
+check for this. Typically they should also be consecutively numbered
+(from 1 to Natoms), though this is not required. Molecular "atom
+styles"_atom_style.html are those that store bond topology information
+(styles bond, angle, molecular, full). These styles require atom IDs
+since the IDs are used to encode the topology. Some other LAMMPS
+commands also require the use of atom IDs. E.g. some many-body pair
+styles use them to avoid double computation of the I-J interaction
+between two atoms.
+
+The only reason not to use atom IDs is if you are running an atomic
+simulation so large that IDs cannot be uniquely assigned. For a
+default LAMMPS build this limit is 2^31 or about 2 billion atoms.
+However, even in this case, you can use 64-bit atom IDs, allowing 2^63
+or about 9e18 atoms, if you build LAMMPS with the - DLAMMPS_BIGBIG
+switch. This is described in "Section 2.2"_Section_start.html#start_2
+of the manual. If atom IDs are not used, they must be specified as 0
+for all atoms, e.g. in a data or restart file.
The {map} keyword determines how atom ID lookup is done for molecular
-problems. Lookups are performed by bond (angle, etc) routines in
+atom styles. Lookups are performed by bond (angle, etc) routines in
LAMMPS to find the local atom index associated with a global atom ID.
+
When the {array} value is used, each processor stores a lookup table
-of length N, where N is the total # of atoms in the system. This is
-the fastest method for most simulations, but a processor can run out
-of memory to store the table for very large simulations. The {hash}
-value uses a hash table to perform the lookups. This method can be
-slightly slower than the {array} method, but its memory cost is
-proportional to N/P on each processor, where P is the total number of
-processors running the simulation.
+of length N, where N is the largest atom ID in the system. This is a
+fast, simple method for many simulations, but requires too much memory
+for large simulations. The {hash} value uses a hash table to perform
+the lookups. This can be slightly slower than the {array} method, but
+its memory cost is proportional to the number of atoms owned by a
+processor, i.e. N/P when N is the total number of atoms in the system
+and P is the number of processors.
+
+When this setting is not specified in your input script, LAMMPS
+creates a map, if one is needed, as an array or hash. See the
+discussion of default values below for how LAMMPS chooses which kind
+of map to build. Note that atomic systems do not normally need to
+create a map. However, even in this case some LAMMPS commands will
+create a map to find atoms (and then destroy it), or require a
+permanent map. An example of the former is the "velocity loop
+all"_velocity.html command, which uses a map when looping over all
+atoms and insuring the same velocity values are assigned to an atom
+ID, no matter which processor owns it.
The {first} keyword allows a "group"_group.html to be specified whose
atoms will be maintained as the first atoms in each processor's list
of owned atoms. This in only useful when the specified group is a
small fraction of all the atoms, and there are other operations LAMMPS
is performing that will be sped-up significantly by being able to loop
over the smaller set of atoms. Otherwise the reordering required by
this option will be a net slow-down. The "neigh_modify
include"_neigh_modify.html and "communicate group"_communicate.html
commands are two examples of commands that require this setting to
work efficiently. Several "fixes"_fix.html, most notably time
integration fixes like "fix nve"_fix_nve.html, also take advantage of
this setting if the group they operate on is the group specified by
this command. Note that specifying "all" as the group-ID effectively
turns off the {first} option.
It is OK to use the {first} keyword with a group that has not yet been
defined, e.g. to use the atom_modify first command at the beginning of
your input script. LAMMPS does not use the group until a simullation
is run.
The {sort} keyword turns on a spatial sorting or reordering of atoms
within each processor's sub-domain every {Nfreq} timesteps. If
{Nfreq} is set to 0, then sorting is turned off. Sorting can improve
cache performance and thus speed-up a LAMMPS simulation, as discussed
in a paper by "(Meloni)"_#Meloni. Its efficacy depends on the problem
size (atoms/processor), how quickly the system becomes disordered, and
various other factors. As a general rule, sorting is typically more
effective at speeding up simulations of liquids as opposed to solids.
In tests we have done, the speed-up can range from zero to 3-4x.
Reordering is peformed every {Nfreq} timesteps during a dynamics run
or iterations during a minimization. More precisely, reordering
occurs at the first reneighboring that occurs after the target
timestep. The reordering is performed locally by each processor,
using bins of the specified {binsize}. If {binsize} is set to 0.0,
then a binsize equal to half the "neighbor"_neighbor.html cutoff
distance (force cutoff plus skin distance) is used, which is a
reasonable value. After the atoms have been binned, they are
reordered so that atoms in the same bin are adjacent to each other in
the processor's 1d list of atoms.
The goal of this procedure is for atoms to put atoms close to each
other in the processor's one-dimensional list of atoms that are also
near to each other spatially. This can improve cache performance when
pairwise intereractions and neighbor lists are computed. Note that if
bins are too small, there will be few atoms/bin. Likewise if bins are
too large, there will be many atoms/bin. In both cases, the goal of
cache locality will be undermined.
IMPORTANT NOTE: Running a simulation with sorting on versus off should
not change the simulation results in a statistical sense. However, a
different ordering will induce round-off differences, which will lead
to diverging trajectories over time when comparing two simluations.
Various commands, particularly those which use random numbers
(e.g. "velocity create"_velocity.html, and "fix
langevin"_fix_langevin.html), may generate (statistically identical)
results which depend on the order in which atoms are processed. The
order of atoms in a "dump"_dump.html file will also typically change
if sorting is enabled.
[Restrictions:]
-The map keyword can only be used before the simulation box is defined
-by a "read_data"_read_data.html or "create_box"_create_box.html
-command.
-
The {first} and {sort} options cannot be used together. Since sorting
is on by default, it will be turned off if the {first} keyword is
used with a group-ID that is not "all".
[Related commands:] none
[Default:]
-By default, atomic (non-molecular) problems do not allocate maps. For
-molecular problems, the option default is map = array. By default, a
-"first" group is not defined. By default, sorting is enabled with a
-frequency of 1000 and a binsize of 0.0, which means the neighbor
+By default, {id} is yes. By default, atomic systems (no bond topology
+info) do not use a map. For molecular systems (with bond topology
+info), a map is used. The default map style is array if no atom ID is
+larger than 1 million, otherwise the default is hash. By default, a
+"first" group is not defined. By default, sorting is enabled with a
+frequency of 1000 and a binsize of 0.0, which means the neighbor
cutoff will be used to set the bin size.
:line
:link(Meloni)
[(Meloni)] Meloni, Rosati and Colombo, J Chem Phys, 126, 121102 (2007).
diff --git a/python/examples/in.simple b/python/examples/in.simple
index 5f6ebdc4f..3dc80bdfe 100644
--- a/python/examples/in.simple
+++ b/python/examples/in.simple
@@ -1,23 +1,25 @@
# 3d Lennard-Jones melt
units lj
atom_style atomic
atom_modify map array
lattice fcc 0.8442
region box block 0 4 0 4 0 4
create_box 1 box
create_atoms 1 box
mass 1 1.0
velocity all create 1.44 87287 loop geom
pair_style lj/cut 2.5
pair_coeff 1 1 1.0 1.0 2.5
neighbor 0.3 bin
neigh_modify delay 0 every 20 check no
fix 1 all nve
+variable fx atom fx
+
run 10
diff --git a/python/examples/simple.py b/python/examples/simple.py
index 5a6157f87..168ec94aa 100755
--- a/python/examples/simple.py
+++ b/python/examples/simple.py
@@ -1,50 +1,56 @@
#!/usr/bin/env python -i
# preceeding line should have path for Python on your machine
# simple.py
# Purpose: mimic operation of couple/simple/simple.cpp via Python
# Syntax: simple.py in.lammps
# in.lammps = LAMMPS input script
import sys
# parse command line
argv = sys.argv
if len(argv) != 2:
print "Syntax: simple.py in.lammps"
sys.exit()
infile = sys.argv[1]
me = 0
# uncomment if running in parallel via Pypar
#import pypar
#me = pypar.rank()
#nprocs = pypar.size()
from lammps import lammps
lmp = lammps()
# run infile one line at a time
lines = open(infile,'r').readlines()
for line in lines: lmp.command(line)
# run 10 more steps
# get coords from LAMMPS
# change coords of 1st atom
# put coords back into LAMMPS
# run a single step with changed coords
lmp.command("run 10")
x = lmp.gather_atoms("x",1,3)
epsilon = 0.1
x[0] += epsilon
lmp.scatter_atoms("x",1,3,x)
lmp.command("run 1");
+f = lmp.extract_atom("f",3)
+print "Force on 1 atom via extract_atom: ",f[0][0]
+
+fx = lmp.extract_variable("fx","all",1)
+print "Force on 1 atom via extract_variable:",fx[0]
+
# uncomment if running in parallel via Pypar
#print "Proc %d out of %d procs has" % (me,nprocs), lmp
#pypar.finalize()
diff --git a/src/CLASS2/dihedral_class2.cpp b/src/CLASS2/dihedral_class2.cpp
index aab7f3cd8..e4f58e056 100644
--- a/src/CLASS2/dihedral_class2.cpp
+++ b/src/CLASS2/dihedral_class2.cpp
@@ -1,957 +1,959 @@
/* ----------------------------------------------------------------------
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: Eric Simon (Cray)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "dihedral_class2.h"
#include "atom.h"
#include "neighbor.h"
#include "update.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.0000001
/* ---------------------------------------------------------------------- */
DihedralClass2::DihedralClass2(LAMMPS *lmp) : Dihedral(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
DihedralClass2::~DihedralClass2()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(setflag_d);
memory->destroy(setflag_mbt);
memory->destroy(setflag_ebt);
memory->destroy(setflag_at);
memory->destroy(setflag_aat);
memory->destroy(setflag_bb13t);
memory->destroy(k1);
memory->destroy(k2);
memory->destroy(k3);
memory->destroy(phi1);
memory->destroy(phi2);
memory->destroy(phi3);
memory->destroy(mbt_f1);
memory->destroy(mbt_f2);
memory->destroy(mbt_f3);
memory->destroy(mbt_r0);
memory->destroy(ebt_f1_1);
memory->destroy(ebt_f2_1);
memory->destroy(ebt_f3_1);
memory->destroy(ebt_r0_1);
memory->destroy(ebt_f1_2);
memory->destroy(ebt_f2_2);
memory->destroy(ebt_f3_2);
memory->destroy(ebt_r0_2);
memory->destroy(at_f1_1);
memory->destroy(at_f2_1);
memory->destroy(at_f3_1);
memory->destroy(at_theta0_1);
memory->destroy(at_f1_2);
memory->destroy(at_f2_2);
memory->destroy(at_f3_2);
memory->destroy(at_theta0_2);
memory->destroy(aat_k);
memory->destroy(aat_theta0_1);
memory->destroy(aat_theta0_2);
memory->destroy(bb13t_k);
memory->destroy(bb13t_r10);
memory->destroy(bb13t_r30);
}
}
/* ---------------------------------------------------------------------- */
void DihedralClass2::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,j,k,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral;
double r1mag2,r1,r2mag2,r2,r3mag2,r3;
double sb1,rb1,sb2,rb2,sb3,rb3,c0,r12c1;
double r12c2,costh12,costh13,costh23,sc1,sc2,s1,s2,c;
double cosphi,phi,sinphi,a11,a22,a33,a12,a13,a23,sx1,sx2;
double sx12,sy1,sy2,sy12,sz1,sz2,sz12,dphi1,dphi2,dphi3;
double de_dihedral,t1,t2,t3,t4,cos2phi,cos3phi,bt1,bt2;
double bt3,sumbte,db,sumbtf,at1,at2,at3,da,da1,da2,r1_0;
double r3_0,dr1,dr2,tk1,tk2,s12,sin2;
double dcosphidr[4][3],dphidr[4][3],dbonddr[3][4][3],dthetadr[2][4][3];
double fabcd[4][3];
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// distances
r1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
r1 = sqrt(r1mag2);
r2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
r2 = sqrt(r2mag2);
r3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
r3 = sqrt(r3mag2);
sb1 = 1.0/r1mag2;
rb1 = 1.0/r1;
sb2 = 1.0/r2mag2;
rb2 = 1.0/r2;
sb3 = 1.0/r3mag2;
rb3 = 1.0/r3;
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// angles
r12c1 = rb1*rb2;
r12c2 = rb2*rb3;
costh12 = (vb1x*vb2x + vb1y*vb2y + vb1z*vb2z) * r12c1;
costh13 = c0;
costh23 = (vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z) * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - costh12*costh12,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - costh23*costh23,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + costh12*costh23) * s12;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
cosphi = c;
phi = acos(c);
sinphi = sqrt(1.0 - c*c);
sinphi = MAX(sinphi,SMALL);
// addition by Andrew Jewett, Jan 2013
// adjust the sign of phi if necessary for negative input angles
// n123 = vb2 x vb1
double n123x = vb1y*vb2z - vb1z*vb2y;
double n123y = vb1z*vb2x - vb1x*vb2z;
double n123z = vb1x*vb2y - vb1y*vb2x;
double n123_dot_vb3 = n123x*vb3x + n123y*vb3y + n123z*vb3z;
if (n123_dot_vb3 > 0.0) {
phi = -phi;
sinphi = -sinphi;
}
a11 = -c*sb1*s1;
a22 = sb2 * (2.0*costh13*s12 - c*(s1+s2));
a33 = -c*sb3*s2;
a12 = r12c1 * (costh12*c*s1 + costh23*s12);
a13 = rb1*rb3*s12;
a23 = r12c2 * (-costh23*c*s2 - costh12*s12);
sx1 = a11*vb1x + a12*vb2x + a13*vb3x;
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sx12 = a13*vb1x + a23*vb2x + a33*vb3x;
sy1 = a11*vb1y + a12*vb2y + a13*vb3y;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sy12 = a13*vb1y + a23*vb2y + a33*vb3y;
sz1 = a11*vb1z + a12*vb2z + a13*vb3z;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
sz12 = a13*vb1z + a23*vb2z + a33*vb3z;
// set up d(cos(phi))/d(r) and dphi/dr arrays
dcosphidr[0][0] = -sx1;
dcosphidr[0][1] = -sy1;
dcosphidr[0][2] = -sz1;
dcosphidr[1][0] = sx2 + sx1;
dcosphidr[1][1] = sy2 + sy1;
dcosphidr[1][2] = sz2 + sz1;
dcosphidr[2][0] = sx12 - sx2;
dcosphidr[2][1] = sy12 - sy2;
dcosphidr[2][2] = sz12 - sz2;
dcosphidr[3][0] = -sx12;
dcosphidr[3][1] = -sy12;
dcosphidr[3][2] = -sz12;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
dphidr[i][j] = -dcosphidr[i][j] / sinphi;
// energy
dphi1 = phi - phi1[type];
dphi2 = 2.0*phi - phi2[type];
dphi3 = 3.0*phi - phi3[type];
if (eflag) edihedral = k1[type]*(1.0 - cos(dphi1)) +
k2[type]*(1.0 - cos(dphi2)) +
k3[type]*(1.0 - cos(dphi3));
de_dihedral = k1[type]*sin(dphi1) + 2.0*k2[type]*sin(dphi2) +
3.0*k3[type]*sin(dphi3);
// torsion forces on all 4 atoms
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] = de_dihedral*dphidr[i][j];
// set up d(bond)/d(r) array
// dbonddr(i,j,k) = bond i, atom j, coordinate k
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++)
dbonddr[i][j][k] = 0.0;
// bond1
dbonddr[0][0][0] = vb1x / r1;
dbonddr[0][0][1] = vb1y / r1;
dbonddr[0][0][2] = vb1z / r1;
dbonddr[0][1][0] = -vb1x / r1;
dbonddr[0][1][1] = -vb1y / r1;
dbonddr[0][1][2] = -vb1z / r1;
// bond2
dbonddr[1][1][0] = vb2x / r2;
dbonddr[1][1][1] = vb2y / r2;
dbonddr[1][1][2] = vb2z / r2;
dbonddr[1][2][0] = -vb2x / r2;
dbonddr[1][2][1] = -vb2y / r2;
dbonddr[1][2][2] = -vb2z / r2;
// bond3
dbonddr[2][2][0] = vb3x / r3;
dbonddr[2][2][1] = vb3y / r3;
dbonddr[2][2][2] = vb3z / r3;
dbonddr[2][3][0] = -vb3x / r3;
dbonddr[2][3][1] = -vb3y / r3;
dbonddr[2][3][2] = -vb3z / r3;
// set up d(theta)/d(r) array
// dthetadr(i,j,k) = angle i, atom j, coordinate k
for (i = 0; i < 2; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++)
dthetadr[i][j][k] = 0.0;
t1 = costh12 / r1mag2;
t2 = costh23 / r2mag2;
t3 = costh12 / r2mag2;
t4 = costh23 / r3mag2;
// angle12
dthetadr[0][0][0] = sc1 * ((t1 * vb1x) - (vb2x * r12c1));
dthetadr[0][0][1] = sc1 * ((t1 * vb1y) - (vb2y * r12c1));
dthetadr[0][0][2] = sc1 * ((t1 * vb1z) - (vb2z * r12c1));
dthetadr[0][1][0] = sc1 * ((-t1 * vb1x) + (vb2x * r12c1) +
(-t3 * vb2x) + (vb1x * r12c1));
dthetadr[0][1][1] = sc1 * ((-t1 * vb1y) + (vb2y * r12c1) +
(-t3 * vb2y) + (vb1y * r12c1));
dthetadr[0][1][2] = sc1 * ((-t1 * vb1z) + (vb2z * r12c1) +
(-t3 * vb2z) + (vb1z * r12c1));
dthetadr[0][2][0] = sc1 * ((t3 * vb2x) - (vb1x * r12c1));
dthetadr[0][2][1] = sc1 * ((t3 * vb2y) - (vb1y * r12c1));
dthetadr[0][2][2] = sc1 * ((t3 * vb2z) - (vb1z * r12c1));
// angle23
dthetadr[1][1][0] = sc2 * ((t2 * vb2x) + (vb3x * r12c2));
dthetadr[1][1][1] = sc2 * ((t2 * vb2y) + (vb3y * r12c2));
dthetadr[1][1][2] = sc2 * ((t2 * vb2z) + (vb3z * r12c2));
dthetadr[1][2][0] = sc2 * ((-t2 * vb2x) - (vb3x * r12c2) +
(t4 * vb3x) + (vb2x * r12c2));
dthetadr[1][2][1] = sc2 * ((-t2 * vb2y) - (vb3y * r12c2) +
(t4 * vb3y) + (vb2y * r12c2));
dthetadr[1][2][2] = sc2 * ((-t2 * vb2z) - (vb3z * r12c2) +
(t4 * vb3z) + (vb2z * r12c2));
dthetadr[1][3][0] = -sc2 * ((t4 * vb3x) + (vb2x * r12c2));
dthetadr[1][3][1] = -sc2 * ((t4 * vb3y) + (vb2y * r12c2));
dthetadr[1][3][2] = -sc2 * ((t4 * vb3z) + (vb2z * r12c2));
// mid-bond/torsion coupling
// energy on bond2 (middle bond)
cos2phi = cos(2.0*phi);
cos3phi = cos(3.0*phi);
bt1 = mbt_f1[type] * cosphi;
bt2 = mbt_f2[type] * cos2phi;
bt3 = mbt_f3[type] * cos3phi;
sumbte = bt1 + bt2 + bt3;
db = r2 - mbt_r0[type];
if (eflag) edihedral += db * sumbte;
// force on bond2
bt1 = -mbt_f1[type] * sinphi;
bt2 = -2.0 * mbt_f2[type] * sin(2.0*phi);
bt3 = -3.0 * mbt_f3[type] * sin(3.0*phi);
sumbtf = bt1 + bt2 + bt3;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[1][i][j];
// end-bond/torsion coupling
// energy on bond1 (first bond)
bt1 = ebt_f1_1[type] * cosphi;
bt2 = ebt_f2_1[type] * cos2phi;
bt3 = ebt_f3_1[type] * cos3phi;
sumbte = bt1 + bt2 + bt3;
db = r1 - ebt_r0_1[type];
if (eflag) edihedral += db * (bt1+bt2+bt3);
// force on bond1
bt1 = ebt_f1_1[type] * sinphi;
bt2 = 2.0 * ebt_f2_1[type] * sin(2.0*phi);
bt3 = 3.0 * ebt_f3_1[type] * sin(3.0*phi);
sumbtf = bt1 + bt2 + bt3;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] -= db*sumbtf*dphidr[i][j] + sumbte*dbonddr[0][i][j];
// end-bond/torsion coupling
// energy on bond3 (last bond)
bt1 = ebt_f1_2[type] * cosphi;
bt2 = ebt_f2_2[type] * cos2phi;
bt3 = ebt_f3_2[type] * cos3phi;
sumbte = bt1 + bt2 + bt3;
db = r3 - ebt_r0_2[type];
if (eflag) edihedral += db * (bt1+bt2+bt3);
// force on bond3
bt1 = -ebt_f1_2[type] * sinphi;
bt2 = -2.0 * ebt_f2_2[type] * sin(2.0*phi);
bt3 = -3.0 * ebt_f3_2[type] * sin(3.0*phi);
sumbtf = bt1 + bt2 + bt3;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] += db*sumbtf*dphidr[i][j] + sumbte*dbonddr[2][i][j];
// angle/torsion coupling
// energy on angle1
at1 = at_f1_1[type] * cosphi;
at2 = at_f2_1[type] * cos2phi;
at3 = at_f3_1[type] * cos3phi;
sumbte = at1 + at2 + at3;
da = acos(costh12) - at_theta0_1[type];
if (eflag) edihedral += da * (at1+at2+at3);
// force on angle1
bt1 = at_f1_1[type] * sinphi;
bt2 = 2.0 * at_f2_1[type] * sin(2.0*phi);
bt3 = 3.0 * at_f3_1[type] * sin(3.0*phi);
sumbtf = bt1 + bt2 + bt3;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] -= da*sumbtf*dphidr[i][j] + sumbte*dthetadr[0][i][j];
// energy on angle2
at1 = at_f1_2[type] * cosphi;
at2 = at_f2_2[type] * cos2phi;
at3 = at_f3_2[type] * cos3phi;
sumbte = at1 + at2 + at3;
da = acos(costh23) - at_theta0_2[type];
if (eflag) edihedral += da * (at1+at2+at3);
// force on angle2
bt1 = -at_f1_2[type] * sinphi;
bt2 = -2.0 * at_f2_2[type] * sin(2.0*phi);
bt3 = -3.0 * at_f3_2[type] * sin(3.0*phi);
sumbtf = bt1 + bt2 + bt3;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] += da*sumbtf*dphidr[i][j] + sumbte*dthetadr[1][i][j];
// angle/angle/torsion coupling
da1 = acos(costh12) - aat_theta0_1[type];
da2 = acos(costh23) - aat_theta0_2[type];
if (eflag) edihedral += aat_k[type]*da1*da2*cosphi;
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] -= aat_k[type] *
(cosphi * (da2*dthetadr[0][i][j] - da1*dthetadr[1][i][j]) +
sinphi * da1*da2*dphidr[i][j]);
// bond1/bond3 coupling
if (fabs(bb13t_k[type]) > SMALL) {
r1_0 = bb13t_r10[type];
r3_0 = bb13t_r30[type];
dr1 = r1 - r1_0;
dr2 = r3 - r3_0;
tk1 = -bb13t_k[type] * dr1 / r3;
tk2 = -bb13t_k[type] * dr2 / r1;
if (eflag) edihedral += bb13t_k[type]*dr1*dr2;
fabcd[0][0] += tk2 * vb1x;
fabcd[0][1] += tk2 * vb1y;
fabcd[0][2] += tk2 * vb1z;
fabcd[1][0] -= tk2 * vb1x;
fabcd[1][1] -= tk2 * vb1y;
fabcd[1][2] -= tk2 * vb1z;
fabcd[2][0] -= tk1 * vb3x;
fabcd[2][1] -= tk1 * vb3y;
fabcd[2][2] -= tk1 * vb3z;
fabcd[3][0] += tk1 * vb3x;
fabcd[3][1] += tk1 * vb3y;
fabcd[3][2] += tk1 * vb3z;
}
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += fabcd[0][0];
f[i1][1] += fabcd[0][1];
f[i1][2] += fabcd[0][2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += fabcd[1][0];
f[i2][1] += fabcd[1][1];
f[i2][2] += fabcd[1][2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += fabcd[2][0];
f[i3][1] += fabcd[2][1];
f[i3][2] += fabcd[2][2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += fabcd[3][0];
f[i4][1] += fabcd[3][1];
f[i4][2] += fabcd[3][2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,
fabcd[0],fabcd[2],fabcd[3],
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralClass2::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(k1,n+1,"dihedral:k1");
memory->create(k2,n+1,"dihedral:k2");
memory->create(k3,n+1,"dihedral:k3");
memory->create(phi1,n+1,"dihedral:phi1");
memory->create(phi2,n+1,"dihedral:phi2");
memory->create(phi3,n+1,"dihedral:phi3");
memory->create(mbt_f1,n+1,"dihedral:mbt_f1");
memory->create(mbt_f2,n+1,"dihedral:mbt_f2");
memory->create(mbt_f3,n+1,"dihedral:mbt_f3");
memory->create(mbt_r0,n+1,"dihedral:mbt_r0");
memory->create(ebt_f1_1,n+1,"dihedral:ebt_f1_1");
memory->create(ebt_f2_1,n+1,"dihedral:ebt_f2_1");
memory->create(ebt_f3_1,n+1,"dihedral:ebt_f3_1");
memory->create(ebt_r0_1,n+1,"dihedral:ebt_r0_1");
memory->create(ebt_f1_2,n+1,"dihedral:ebt_f1_2");
memory->create(ebt_f2_2,n+1,"dihedral:ebt_f2_2");
memory->create(ebt_f3_2,n+1,"dihedral:ebt_f3_2");
memory->create(ebt_r0_2,n+1,"dihedral:ebt_r0_2");
memory->create(at_f1_1,n+1,"dihedral:at_f1_1");
memory->create(at_f2_1,n+1,"dihedral:at_f2_1");
memory->create(at_f3_1,n+1,"dihedral:at_f3_1");
memory->create(at_theta0_1,n+1,"dihedral:at_theta0_1");
memory->create(at_f1_2,n+1,"dihedral:at_f1_2");
memory->create(at_f2_2,n+1,"dihedral:at_f2_2");
memory->create(at_f3_2,n+1,"dihedral:at_f3_2");
memory->create(at_theta0_2,n+1,"dihedral:at_theta0_2");
memory->create(aat_k,n+1,"dihedral:aat_k");
memory->create(aat_theta0_1,n+1,"dihedral:aat_theta0_1");
memory->create(aat_theta0_2,n+1,"dihedral:aat_theta0_2");
memory->create(bb13t_k,n+1,"dihedral:bb13t_k");
memory->create(bb13t_r10,n+1,"dihedral:bb13t_r10");
memory->create(bb13t_r30,n+1,"dihedral:bb13t_r30");
memory->create(setflag,n+1,"dihedral:setflag");
memory->create(setflag_d,n+1,"dihedral:setflag_d");
memory->create(setflag_mbt,n+1,"dihedral:setflag_mbt");
memory->create(setflag_ebt,n+1,"dihedral:setflag_ebt");
memory->create(setflag_at,n+1,"dihedral:setflag_at");
memory->create(setflag_aat,n+1,"dihedral:setflag_aat");
memory->create(setflag_bb13t,n+1,"dihedral:setflag_bb13t");
for (int i = 1; i <= n; i++)
setflag[i] = setflag_d[i] = setflag_mbt[i] = setflag_ebt[i] =
setflag_at[i] = setflag_aat[i] = setflag_bb13t[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more types
arg1 = "mbt" -> MiddleBondTorsion coeffs
arg1 = "ebt" -> EndBondTorsion coeffs
arg1 = "at" -> AngleTorsion coeffs
arg1 = "aat" -> AngleAngleTorsion coeffs
arg1 = "bb13" -> BondBond13Torsion coeffs
arg1 -> Dihedral coeffs
------------------------------------------------------------------------- */
void DihedralClass2::coeff(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Invalid coeffs for this dihedral style");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
int count = 0;
if (strcmp(arg[1],"mbt") == 0) {
if (narg != 6) error->all(FLERR,"Incorrect args for dihedral coefficients");
double f1_one = force->numeric(FLERR,arg[2]);
double f2_one = force->numeric(FLERR,arg[3]);
double f3_one = force->numeric(FLERR,arg[4]);
double r0_one = force->numeric(FLERR,arg[5]);
for (int i = ilo; i <= ihi; i++) {
mbt_f1[i] = f1_one;
mbt_f2[i] = f2_one;
mbt_f3[i] = f3_one;
mbt_r0[i] = r0_one;
setflag_mbt[i] = 1;
count++;
}
} else if (strcmp(arg[1],"ebt") == 0) {
if (narg != 10) error->all(FLERR,"Incorrect args for dihedral coefficients");
double f1_1_one = force->numeric(FLERR,arg[2]);
double f2_1_one = force->numeric(FLERR,arg[3]);
double f3_1_one = force->numeric(FLERR,arg[4]);
double f1_2_one = force->numeric(FLERR,arg[5]);
double f2_2_one = force->numeric(FLERR,arg[6]);
double f3_2_one = force->numeric(FLERR,arg[7]);
double r0_1_one = force->numeric(FLERR,arg[8]);
double r0_2_one = force->numeric(FLERR,arg[9]);
for (int i = ilo; i <= ihi; i++) {
ebt_f1_1[i] = f1_1_one;
ebt_f2_1[i] = f2_1_one;
ebt_f3_1[i] = f3_1_one;
ebt_f1_2[i] = f1_2_one;
ebt_f2_2[i] = f2_2_one;
ebt_f3_2[i] = f3_2_one;
ebt_r0_1[i] = r0_1_one;
ebt_r0_2[i] = r0_2_one;
setflag_ebt[i] = 1;
count++;
}
} else if (strcmp(arg[1],"at") == 0) {
if (narg != 10) error->all(FLERR,"Incorrect args for dihedral coefficients");
double f1_1_one = force->numeric(FLERR,arg[2]);
double f2_1_one = force->numeric(FLERR,arg[3]);
double f3_1_one = force->numeric(FLERR,arg[4]);
double f1_2_one = force->numeric(FLERR,arg[5]);
double f2_2_one = force->numeric(FLERR,arg[6]);
double f3_2_one = force->numeric(FLERR,arg[7]);
double theta0_1_one = force->numeric(FLERR,arg[8]);
double theta0_2_one = force->numeric(FLERR,arg[9]);
// convert theta0's from degrees to radians
for (int i = ilo; i <= ihi; i++) {
at_f1_1[i] = f1_1_one;
at_f2_1[i] = f2_1_one;
at_f3_1[i] = f3_1_one;
at_f1_2[i] = f1_2_one;
at_f2_2[i] = f2_2_one;
at_f3_2[i] = f3_2_one;
at_theta0_1[i] = theta0_1_one/180.0 * MY_PI;
at_theta0_2[i] = theta0_2_one/180.0 * MY_PI;
setflag_at[i] = 1;
count++;
}
} else if (strcmp(arg[1],"aat") == 0) {
if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients");
double k_one = force->numeric(FLERR,arg[2]);
double theta0_1_one = force->numeric(FLERR,arg[3]);
double theta0_2_one = force->numeric(FLERR,arg[4]);
// convert theta0's from degrees to radians
for (int i = ilo; i <= ihi; i++) {
aat_k[i] = k_one;
aat_theta0_1[i] = theta0_1_one/180.0 * MY_PI;
aat_theta0_2[i] = theta0_2_one/180.0 * MY_PI;
setflag_aat[i] = 1;
count++;
}
} else if (strcmp(arg[1],"bb13") == 0) {
if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients");
double k_one = force->numeric(FLERR,arg[2]);
double r10_one = force->numeric(FLERR,arg[3]);
double r30_one = force->numeric(FLERR,arg[4]);
for (int i = ilo; i <= ihi; i++) {
bb13t_k[i] = k_one;
bb13t_r10[i] = r10_one;
bb13t_r30[i] = r30_one;
setflag_bb13t[i] = 1;
count++;
}
} else {
if (narg != 7) error->all(FLERR,"Incorrect args for dihedral coefficients");
double k1_one = force->numeric(FLERR,arg[1]);
double phi1_one = force->numeric(FLERR,arg[2]);
double k2_one = force->numeric(FLERR,arg[3]);
double phi2_one = force->numeric(FLERR,arg[4]);
double k3_one = force->numeric(FLERR,arg[5]);
double phi3_one = force->numeric(FLERR,arg[6]);
// convert phi's from degrees to radians
for (int i = ilo; i <= ihi; i++) {
k1[i] = k1_one;
phi1[i] = phi1_one/180.0 * MY_PI;
k2[i] = k2_one;
phi2[i] = phi2_one/180.0 * MY_PI;
k3[i] = k3_one;
phi3[i] = phi3_one/180.0 * MY_PI;
setflag_d[i] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
for (int i = ilo; i <= ihi; i++)
if (setflag_d[i] == 1 && setflag_mbt[i] == 1 && setflag_ebt[i] == 1 &&
setflag_at[i] == 1 && setflag_aat[i] == 1 && setflag_bb13t[i] == 1)
setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralClass2::write_restart(FILE *fp)
{
fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&phi1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&phi2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&phi3[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralClass2::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&phi1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&phi2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&phi3[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&mbt_f1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&mbt_f2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&mbt_f3[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&mbt_r0[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f1_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f2_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f3_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_r0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f1_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f2_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_f3_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&ebt_r0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f1_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f2_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f3_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f1_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f2_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_f3_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&at_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&aat_k[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&aat_theta0_1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&aat_theta0_2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&bb13t_k[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&bb13t_r10[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&bb13t_r30[1],sizeof(double),atom->ndihedraltypes,fp);
}
MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&phi1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&phi2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&phi3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&mbt_f1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&mbt_f2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&mbt_f3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&mbt_r0[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_r0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&ebt_r0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f1_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f2_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f3_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f1_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f2_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_f3_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&at_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aat_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aat_theta0_1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aat_theta0_2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&bb13t_k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&bb13t_r10[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&bb13t_r30[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void DihedralClass2::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g %g %g %g\n",
i,k1[i],phi1[i],k2[i],phi2[i],k3[i],phi3[i]);
fprintf(fp,"\nAngleAngleTorsion Coeffs\n\n");
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g\n",i,aat_k[i],
aat_theta0_1[i]*180.0/MY_PI,aat_theta0_2[i]*180.0/MY_PI);
fprintf(fp,"\nEndBondTorsion Coeffs\n\n");
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i,
ebt_f1_1[i],ebt_f2_1[i],ebt_f3_1[i],
ebt_f1_2[i],ebt_f2_2[i],ebt_f3_2[i],
ebt_r0_1[i],ebt_r0_2[i]);
fprintf(fp,"\nMiddleBondTorsion Coeffs\n\n");
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,mbt_f1[i],mbt_f2[i],mbt_f3[i],mbt_r0[i]);
fprintf(fp,"\nBondBond13 Coeffs\n\n");
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g\n",i,bb13t_k[i],bb13t_r10[i],bb13t_r30[i]);
fprintf(fp,"\nAngleTorsion Coeffs\n\n");
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g %g %g %g %g %g\n",i,
at_f1_1[i],at_f2_1[i],at_f3_1[i],
at_f1_2[i],at_f2_2[i],at_f3_2[i],
at_theta0_1[i]*180.0/MY_PI,at_theta0_2[i]*180.0/MY_PI);
}
diff --git a/src/CLASS2/improper_class2.cpp b/src/CLASS2/improper_class2.cpp
index 628a10630..b4ccd77e7 100644
--- a/src/CLASS2/improper_class2.cpp
+++ b/src/CLASS2/improper_class2.cpp
@@ -1,856 +1,857 @@
/* ----------------------------------------------------------------------
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: Eric Simon (Cray)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "improper_class2.h"
#include "atom.h"
#include "neighbor.h"
#include "update.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperClass2::ImproperClass2(LAMMPS *lmp) : Improper(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
ImproperClass2::~ImproperClass2()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(setflag_i);
memory->destroy(setflag_aa);
memory->destroy(k0);
memory->destroy(chi0);
memory->destroy(aa_k1);
memory->destroy(aa_k2);
memory->destroy(aa_k3);
memory->destroy(aa_theta0_1);
memory->destroy(aa_theta0_2);
memory->destroy(aa_theta0_3);
}
}
/* ---------------------------------------------------------------------- */
void ImproperClass2::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,j,k,n,type;
double eimproper;
double delr[3][3],rmag[3],rinvmag[3],rmag2[3];
double theta[3],costheta[3],sintheta[3];
double cossqtheta[3],sinsqtheta[3],invstheta[3];
double rABxrCB[3],rDBxrAB[3],rCBxrDB[3];
double ddelr[3][4],dr[3][4][3],dinvr[3][4][3];
double dthetadr[3][4][3],dinvsth[3][4][3];
double dinv3r[4][3],dinvs3r[3][4][3];
double drCBxrDB[3],rCBxdrDB[3],drDBxrAB[3],rDBxdrAB[3];
double drABxrCB[3],rABxdrCB[3];
double dot1,dot2,dd[3];
double fdot[3][4][3],ftmp,invs3r[3],inv3r;
double t,tt1,tt3,sc1;
double dotCBDBAB,dotDBABCB,dotABCBDB;
double chi,deltachi,d2chi,cossin2;
double drAB[3][4][3],drCB[3][4][3],drDB[3][4][3];
double dchi[3][4][3],dtotalchi[4][3];
double schiABCD,chiABCD,schiCBDA,chiCBDA,schiDBAC,chiDBAC;
double fabcd[4][3];
eimproper = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++) {
dthetadr[i][j][k] = 0.0;
drAB[i][j][k] = 0.0;
drCB[i][j][k] = 0.0;
drDB[i][j][k] = 0.0;
}
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
if (k0[type] == 0.0) continue;
// difference vectors
delr[0][0] = x[i1][0] - x[i2][0];
delr[0][1] = x[i1][1] - x[i2][1];
delr[0][2] = x[i1][2] - x[i2][2];
delr[1][0] = x[i3][0] - x[i2][0];
delr[1][1] = x[i3][1] - x[i2][1];
delr[1][2] = x[i3][2] - x[i2][2];
delr[2][0] = x[i4][0] - x[i2][0];
delr[2][1] = x[i4][1] - x[i2][1];
delr[2][2] = x[i4][2] - x[i2][2];
// bond lengths and associated values
for (i = 0; i < 3; i++) {
rmag2[i] = delr[i][0]*delr[i][0] + delr[i][1]*delr[i][1] +
delr[i][2]*delr[i][2];
rmag[i] = sqrt(rmag2[i]);
rinvmag[i] = 1.0/rmag[i];
}
// angle ABC, CBD, ABD
costheta[0] = (delr[0][0]*delr[1][0] + delr[0][1]*delr[1][1] +
delr[0][2]*delr[1][2]) / (rmag[0]*rmag[1]);
costheta[1] = (delr[1][0]*delr[2][0] + delr[1][1]*delr[2][1] +
delr[1][2]*delr[2][2]) / (rmag[1]*rmag[2]);
costheta[2] = (delr[0][0]*delr[2][0] + delr[0][1]*delr[2][1] +
delr[0][2]*delr[2][2]) / (rmag[0]*rmag[2]);
// angle error check
for (i = 0; i < 3; i++) {
if (costheta[i] == -1.0) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,
- "Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
}
for (i = 0; i < 3; i++) {
if (costheta[i] > 1.0) costheta[i] = 1.0;
if (costheta[i] < -1.0) costheta[i] = -1.0;
theta[i] = acos(costheta[i]);
cossqtheta[i] = costheta[i]*costheta[i];
sintheta[i] = sin(theta[i]);
invstheta[i] = 1.0/sintheta[i];
sinsqtheta[i] = sintheta[i]*sintheta[i];
}
// cross & dot products
cross(delr[0],delr[1],rABxrCB);
cross(delr[2],delr[0],rDBxrAB);
cross(delr[1],delr[2],rCBxrDB);
dotCBDBAB = dot(rCBxrDB,delr[0]);
dotDBABCB = dot(rDBxrAB,delr[1]);
dotABCBDB = dot(rABxrCB,delr[2]);
t = rmag[0] * rmag[1] * rmag[2];
inv3r = 1.0/t;
invs3r[0] = invstheta[1] * inv3r;
invs3r[1] = invstheta[2] * inv3r;
invs3r[2] = invstheta[0] * inv3r;
// chi ABCD, CBDA, DBAC
// final chi is average of three
schiABCD = dotCBDBAB * invs3r[0];
chiABCD = asin(schiABCD);
schiCBDA = dotDBABCB * invs3r[1];
chiCBDA = asin(schiCBDA);
schiDBAC = dotABCBDB * invs3r[2];
chiDBAC = asin(schiDBAC);
chi = (chiABCD + chiCBDA + chiDBAC) / 3.0;
deltachi = chi - chi0[type];
d2chi = deltachi * deltachi;
// energy
if (eflag) eimproper = k0[type]*d2chi;
// forces
// define d(delr)
// i = bond AB/CB/DB, j = atom A/B/C/D
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
ddelr[i][j] = 0.0;
ddelr[0][0] = 1.0;
ddelr[0][1] = -1.0;
ddelr[1][1] = -1.0;
ddelr[1][2] = 1.0;
ddelr[2][1] = -1.0;
ddelr[2][3] = 1.0;
// compute d(|r|)/dr and d(1/|r|)/dr for each direction, bond and atom
// define d(r) for each r
// i = bond AB/CB/DB, j = atom A/B/C/D, k = X/Y/Z
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++) {
dr[i][j][k] = delr[i][k] * ddelr[i][j] / rmag[i];
dinvr[i][j][k] = -dr[i][j][k] / rmag2[i];
}
// compute d(1 / (|r_AB| * |r_CB| * |r_DB|) / dr
// i = atom A/B/C/D, j = X/Y/Z
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
dinv3r[i][j] = rinvmag[1] * (rinvmag[2] * dinvr[0][i][j] +
rinvmag[0] * dinvr[2][i][j]) +
rinvmag[2] * rinvmag[0] * dinvr[1][i][j];
// compute d(theta)/d(r) for 3 angles
// angleABC
tt1 = costheta[0] / rmag2[0];
tt3 = costheta[0] / rmag2[1];
sc1 = 1.0 / sqrt(1.0 - cossqtheta[0]);
dthetadr[0][0][0] = sc1 * ((tt1 * delr[0][0]) -
(delr[1][0] * rinvmag[0] * rinvmag[1]));
dthetadr[0][0][1] = sc1 * ((tt1 * delr[0][1]) -
(delr[1][1] * rinvmag[0] * rinvmag[1]));
dthetadr[0][0][2] = sc1 * ((tt1 * delr[0][2]) -
(delr[1][2] * rinvmag[0] * rinvmag[1]));
dthetadr[0][1][0] = -sc1 * ((tt1 * delr[0][0]) -
(delr[1][0] * rinvmag[0] * rinvmag[1]) +
(tt3 * delr[1][0]) -
(delr[0][0] * rinvmag[0] * rinvmag[1]));
dthetadr[0][1][1] = -sc1 * ((tt1 * delr[0][1]) -
(delr[1][1] * rinvmag[0] * rinvmag[1]) +
(tt3 * delr[1][1]) -
(delr[0][1] * rinvmag[0] * rinvmag[1]));
dthetadr[0][1][2] = -sc1 * ((tt1 * delr[0][2]) -
(delr[1][2] * rinvmag[0] * rinvmag[1]) +
(tt3 * delr[1][2]) -
(delr[0][2] * rinvmag[0] * rinvmag[1]));
dthetadr[0][2][0] = sc1 * ((tt3 * delr[1][0]) -
(delr[0][0] * rinvmag[0] * rinvmag[1]));
dthetadr[0][2][1] = sc1 * ((tt3 * delr[1][1]) -
(delr[0][1] * rinvmag[0] * rinvmag[1]));
dthetadr[0][2][2] = sc1 * ((tt3 * delr[1][2]) -
(delr[0][2] * rinvmag[0] * rinvmag[1]));
// angleCBD
tt1 = costheta[1] / rmag2[1];
tt3 = costheta[1] / rmag2[2];
sc1 = 1.0 / sqrt(1.0 - cossqtheta[1]);
dthetadr[1][2][0] = sc1 * ((tt1 * delr[1][0]) -
(delr[2][0] * rinvmag[1] * rinvmag[2]));
dthetadr[1][2][1] = sc1 * ((tt1 * delr[1][1]) -
(delr[2][1] * rinvmag[1] * rinvmag[2]));
dthetadr[1][2][2] = sc1 * ((tt1 * delr[1][2]) -
(delr[2][2] * rinvmag[1] * rinvmag[2]));
dthetadr[1][1][0] = -sc1 * ((tt1 * delr[1][0]) -
(delr[2][0] * rinvmag[1] * rinvmag[2]) +
(tt3 * delr[2][0]) -
(delr[1][0] * rinvmag[2] * rinvmag[1]));
dthetadr[1][1][1] = -sc1 * ((tt1 * delr[1][1]) -
(delr[2][1] * rinvmag[1] * rinvmag[2]) +
(tt3 * delr[2][1]) -
(delr[1][1] * rinvmag[2] * rinvmag[1]));
dthetadr[1][1][2] = -sc1 * ((tt1 * delr[1][2]) -
(delr[2][2] * rinvmag[1] * rinvmag[2]) +
(tt3 * delr[2][2]) -
(delr[1][2] * rinvmag[2] * rinvmag[1]));
dthetadr[1][3][0] = sc1 * ((tt3 * delr[2][0]) -
(delr[1][0] * rinvmag[2] * rinvmag[1]));
dthetadr[1][3][1] = sc1 * ((tt3 * delr[2][1]) -
(delr[1][1] * rinvmag[2] * rinvmag[1]));
dthetadr[1][3][2] = sc1 * ((tt3 * delr[2][2]) -
(delr[1][2] * rinvmag[2] * rinvmag[1]));
// angleABD
tt1 = costheta[2] / rmag2[0];
tt3 = costheta[2] / rmag2[2];
sc1 = 1.0 / sqrt(1.0 - cossqtheta[2]);
dthetadr[2][0][0] = sc1 * ((tt1 * delr[0][0]) -
(delr[2][0] * rinvmag[0] * rinvmag[2]));
dthetadr[2][0][1] = sc1 * ((tt1 * delr[0][1]) -
(delr[2][1] * rinvmag[0] * rinvmag[2]));
dthetadr[2][0][2] = sc1 * ((tt1 * delr[0][2]) -
(delr[2][2] * rinvmag[0] * rinvmag[2]));
dthetadr[2][1][0] = -sc1 * ((tt1 * delr[0][0]) -
(delr[2][0] * rinvmag[0] * rinvmag[2]) +
(tt3 * delr[2][0]) -
(delr[0][0] * rinvmag[2] * rinvmag[0]));
dthetadr[2][1][1] = -sc1 * ((tt1 * delr[0][1]) -
(delr[2][1] * rinvmag[0] * rinvmag[2]) +
(tt3 * delr[2][1]) -
(delr[0][1] * rinvmag[2] * rinvmag[0]));
dthetadr[2][1][2] = -sc1 * ((tt1 * delr[0][2]) -
(delr[2][2] * rinvmag[0] * rinvmag[2]) +
(tt3 * delr[2][2]) -
(delr[0][2] * rinvmag[2] * rinvmag[0]));
dthetadr[2][3][0] = sc1 * ((tt3 * delr[2][0]) -
(delr[0][0] * rinvmag[2] * rinvmag[0]));
dthetadr[2][3][1] = sc1 * ((tt3 * delr[2][1]) -
(delr[0][1] * rinvmag[2] * rinvmag[0]));
dthetadr[2][3][2] = sc1 * ((tt3 * delr[2][2]) -
(delr[0][2] * rinvmag[2] * rinvmag[0]));
// compute d( 1 / sin(theta))/dr
// i = angle, j = atom, k = direction
for (i = 0; i < 3; i++) {
cossin2 = -costheta[i] / sinsqtheta[i];
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++)
dinvsth[i][j][k] = cossin2 * dthetadr[i][j][k];
}
// compute d(1 / sin(theta) * |r_AB| * |r_CB| * |r_DB|)/dr
// i = angle, j = atom
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++) {
dinvs3r[0][i][j] = (invstheta[1] * dinv3r[i][j]) +
(inv3r * dinvsth[1][i][j]);
dinvs3r[1][i][j] = (invstheta[2] * dinv3r[i][j]) +
(inv3r * dinvsth[2][i][j]);
dinvs3r[2][i][j] = (invstheta[0] * dinv3r[i][j]) +
(inv3r * dinvsth[0][i][j]);
}
// drCB(i,j,k), etc
// i = vector X'/Y'/Z', j = atom A/B/C/D, k = direction X/Y/Z
for (i = 0; i < 3; i++) {
drCB[i][1][i] = -1.0;
drAB[i][1][i] = -1.0;
drDB[i][1][i] = -1.0;
drDB[i][3][i] = 1.0;
drCB[i][2][i] = 1.0;
drAB[i][0][i] = 1.0;
}
// d((r_CB x r_DB) dot r_AB)
// r_CB x d(r_DB)
// d(r_CB) x r_DB
// (r_CB x d(r_DB)) + (d(r_CB) x r_DB)
// (r_CB x d(r_DB)) + (d(r_CB) x r_DB) dot r_AB
// d(r_AB) dot (r_CB x r_DB)
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++) {
cross(delr[1],drDB[i][j],rCBxdrDB);
cross(drCB[i][j],delr[2],drCBxrDB);
for (k = 0; k < 3; k++) dd[k] = rCBxdrDB[k] + drCBxrDB[k];
dot1 = dot(dd,delr[0]);
dot2 = dot(rCBxrDB,drAB[i][j]);
fdot[0][j][i] = dot1 + dot2;
}
// d((r_DB x r_AB) dot r_CB)
// r_DB x d(r_AB)
// d(r_DB) x r_AB
// (r_DB x d(r_AB)) + (d(r_DB) x r_AB)
// (r_DB x d(r_AB)) + (d(r_DB) x r_AB) dot r_CB
// d(r_CB) dot (r_DB x r_AB)
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++) {
cross(delr[2],drAB[i][j],rDBxdrAB);
cross(drDB[i][j],delr[0],drDBxrAB);
for (k = 0; k < 3; k++) dd[k] = rDBxdrAB[k] + drDBxrAB[k];
dot1 = dot(dd,delr[1]);
dot2 = dot(rDBxrAB,drCB[i][j]);
fdot[1][j][i] = dot1 + dot2;
}
// d((r_AB x r_CB) dot r_DB)
// r_AB x d(r_CB)
// d(r_AB) x r_CB
// (r_AB x d(r_CB)) + (d(r_AB) x r_CB)
// (r_AB x d(r_CB)) + (d(r_AB) x r_CB) dot r_DB
// d(r_DB) dot (r_AB x r_CB)
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++) {
cross(delr[0],drCB[i][j],rABxdrCB);
cross(drAB[i][j],delr[1],drABxrCB);
for (k = 0; k < 3; k++) dd[k] = rABxdrCB[k] + drABxrCB[k];
dot1 = dot(dd,delr[2]);
dot2 = dot(rABxrCB,drDB[i][j]);
fdot[2][j][i] = dot1 + dot2;
}
// force on each atom
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++) {
ftmp = (fdot[0][i][j] * invs3r[0]) +
(dinvs3r[0][i][j] * dotCBDBAB);
dchi[0][i][j] = ftmp / cos(chiABCD);
ftmp = (fdot[1][i][j] * invs3r[1]) +
(dinvs3r[1][i][j] * dotDBABCB);
dchi[1][i][j] = ftmp / cos(chiCBDA);
ftmp = (fdot[2][i][j] * invs3r[2]) +
(dinvs3r[2][i][j] * dotABCBDB);
dchi[2][i][j] = ftmp / cos(chiDBAC);
dtotalchi[i][j] = (dchi[0][i][j]+dchi[1][i][j]+dchi[2][i][j]) / 3.0;
}
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] = -2.0*k0[type] * deltachi*dtotalchi[i][j];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += fabcd[0][0];
f[i1][1] += fabcd[0][1];
f[i1][2] += fabcd[0][2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += fabcd[1][0];
f[i2][1] += fabcd[1][1];
f[i2][2] += fabcd[1][2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += fabcd[2][0];
f[i3][1] += fabcd[2][1];
f[i3][2] += fabcd[2][2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += fabcd[3][0];
f[i4][1] += fabcd[3][1];
f[i4][2] += fabcd[3][2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,
fabcd[0],fabcd[2],fabcd[3],
delr[0][0],delr[0][1],delr[0][2],
delr[1][0],delr[1][1],delr[1][2],
delr[2][0]-delr[1][0],delr[2][1]-delr[1][1],
delr[2][2]-delr[1][2]);
}
// compute angle-angle interactions
angleangle(eflag,vflag);
}
/* ---------------------------------------------------------------------- */
void ImproperClass2::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k0,n+1,"improper:k0");
memory->create(chi0,n+1,"improper:chi0");
memory->create(aa_k1,n+1,"improper:aa_k1");
memory->create(aa_k2,n+1,"improper:aa_k2");
memory->create(aa_k3,n+1,"improper:aa_k3");
memory->create(aa_theta0_1,n+1,"improper:aa_theta0_1");
memory->create(aa_theta0_2,n+1,"improper:aa_theta0_2");
memory->create(aa_theta0_3,n+1,"improper:aa_theta0_3");
memory->create(setflag,n+1,"improper:setflag");
memory->create(setflag_i,n+1,"improper:setflag_i");
memory->create(setflag_aa,n+1,"improper:setflag_aa");
for (int i = 1; i <= n; i++)
setflag[i] = setflag_i[i] = setflag_aa[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more types
arg1 = "aa" -> AngleAngle coeffs
else arg1 -> improper coeffs
------------------------------------------------------------------------- */
void ImproperClass2::coeff(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
int count = 0;
if (strcmp(arg[1],"aa") == 0) {
if (narg != 8) error->all(FLERR,"Incorrect args for improper coefficients");
double k1_one = force->numeric(FLERR,arg[2]);
double k2_one = force->numeric(FLERR,arg[3]);
double k3_one = force->numeric(FLERR,arg[4]);
double theta0_1_one = force->numeric(FLERR,arg[5]);
double theta0_2_one = force->numeric(FLERR,arg[6]);
double theta0_3_one = force->numeric(FLERR,arg[7]);
// convert theta0's from degrees to radians
for (int i = ilo; i <= ihi; i++) {
aa_k1[i] = k1_one;
aa_k2[i] = k2_one;
aa_k3[i] = k3_one;
aa_theta0_1[i] = theta0_1_one/180.0 * MY_PI;
aa_theta0_2[i] = theta0_2_one/180.0 * MY_PI;
aa_theta0_3[i] = theta0_3_one/180.0 * MY_PI;
setflag_aa[i] = 1;
count++;
}
} else {
if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients");
double k0_one = force->numeric(FLERR,arg[1]);
double chi0_one = force->numeric(FLERR,arg[2]);
// convert chi0 from degrees to radians
for (int i = ilo; i <= ihi; i++) {
k0[i] = k0_one;
chi0[i] = chi0_one/180.0 * MY_PI;
setflag_i[i] = 1;
count++;
}
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
for (int i = ilo; i <= ihi; i++)
if (setflag_i[i] == 1 && setflag_aa[i] == 1) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperClass2::write_restart(FILE *fp)
{
fwrite(&k0[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&chi0[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperClass2::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k0[1],sizeof(double),atom->nimpropertypes,fp);
fread(&chi0[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_k1[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_k2[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_k3[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_theta0_1[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_theta0_2[1],sizeof(double),atom->nimpropertypes,fp);
fread(&aa_theta0_3[1],sizeof(double),atom->nimpropertypes,fp);
}
MPI_Bcast(&k0[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&chi0[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_k1[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_k2[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_k3[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_theta0_1[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_theta0_2[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&aa_theta0_3[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
angle-angle interactions within improper
------------------------------------------------------------------------- */
void ImproperClass2::angleangle(int eflag, int vflag)
{
int i1,i2,i3,i4,i,j,k,n,type;
double eimproper;
double delxAB,delyAB,delzAB,rABmag2,rAB;
double delxBC,delyBC,delzBC,rBCmag2,rBC;
double delxBD,delyBD,delzBD,rBDmag2,rBD;
double costhABC,thetaABC,costhABD;
double thetaABD,costhCBD,thetaCBD,dthABC,dthCBD,dthABD;
double sc1,t1,t3,r12;
double dthetadr[3][4][3],fabcd[4][3];
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
// difference vectors
delxAB = x[i1][0] - x[i2][0];
delyAB = x[i1][1] - x[i2][1];
delzAB = x[i1][2] - x[i2][2];
delxBC = x[i3][0] - x[i2][0];
delyBC = x[i3][1] - x[i2][1];
delzBC = x[i3][2] - x[i2][2];
delxBD = x[i4][0] - x[i2][0];
delyBD = x[i4][1] - x[i2][1];
delzBD = x[i4][2] - x[i2][2];
// bond lengths
rABmag2 = delxAB*delxAB + delyAB*delyAB + delzAB*delzAB;
rAB = sqrt(rABmag2);
rBCmag2 = delxBC*delxBC + delyBC*delyBC + delzBC*delzBC;
rBC = sqrt(rBCmag2);
rBDmag2 = delxBD*delxBD + delyBD*delyBD + delzBD*delzBD;
rBD = sqrt(rBDmag2);
// angle ABC, ABD, CBD
costhABC = (delxAB*delxBC + delyAB*delyBC + delzAB*delzBC) / (rAB * rBC);
if (costhABC > 1.0) costhABC = 1.0;
if (costhABC < -1.0) costhABC = -1.0;
thetaABC = acos(costhABC);
costhABD = (delxAB*delxBD + delyAB*delyBD + delzAB*delzBD) / (rAB * rBD);
if (costhABD > 1.0) costhABD = 1.0;
if (costhABD < -1.0) costhABD = -1.0;
thetaABD = acos(costhABD);
costhCBD = (delxBC*delxBD + delyBC*delyBD + delzBC*delzBD) /(rBC * rBD);
if (costhCBD > 1.0) costhCBD = 1.0;
if (costhCBD < -1.0) costhCBD = -1.0;
thetaCBD = acos(costhCBD);
dthABC = thetaABC - aa_theta0_1[type];
dthABD = thetaABD - aa_theta0_2[type];
dthCBD = thetaCBD - aa_theta0_3[type];
// energy
if (eflag) eimproper = aa_k2[type] * dthABC * dthABD +
aa_k1[type] * dthABC * dthCBD +
aa_k3[type] * dthABD * dthCBD;
// d(theta)/d(r) array
// angle i, atom j, coordinate k
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
for (k = 0; k < 3; k++)
dthetadr[i][j][k] = 0.0;
// angle ABC
sc1 = sqrt(1.0/(1.0 - costhABC*costhABC));
t1 = costhABC / rABmag2;
t3 = costhABC / rBCmag2;
r12 = 1.0 / (rAB * rBC);
dthetadr[0][0][0] = sc1 * ((t1 * delxAB) - (delxBC * r12));
dthetadr[0][0][1] = sc1 * ((t1 * delyAB) - (delyBC * r12));
dthetadr[0][0][2] = sc1 * ((t1 * delzAB) - (delzBC * r12));
dthetadr[0][1][0] = sc1 * ((-t1 * delxAB) + (delxBC * r12) +
(-t3 * delxBC) + (delxAB * r12));
dthetadr[0][1][1] = sc1 * ((-t1 * delyAB) + (delyBC * r12) +
(-t3 * delyBC) + (delyAB * r12));
dthetadr[0][1][2] = sc1 * ((-t1 * delzAB) + (delzBC * r12) +
(-t3 * delzBC) + (delzAB * r12));
dthetadr[0][2][0] = sc1 * ((t3 * delxBC) - (delxAB * r12));
dthetadr[0][2][1] = sc1 * ((t3 * delyBC) - (delyAB * r12));
dthetadr[0][2][2] = sc1 * ((t3 * delzBC) - (delzAB * r12));
// angle CBD
sc1 = sqrt(1.0/(1.0 - costhCBD*costhCBD));
t1 = costhCBD / rBCmag2;
t3 = costhCBD / rBDmag2;
r12 = 1.0 / (rBC * rBD);
dthetadr[1][2][0] = sc1 * ((t1 * delxBC) - (delxBD * r12));
dthetadr[1][2][1] = sc1 * ((t1 * delyBC) - (delyBD * r12));
dthetadr[1][2][2] = sc1 * ((t1 * delzBC) - (delzBD * r12));
dthetadr[1][1][0] = sc1 * ((-t1 * delxBC) + (delxBD * r12) +
(-t3 * delxBD) + (delxBC * r12));
dthetadr[1][1][1] = sc1 * ((-t1 * delyBC) + (delyBD * r12) +
(-t3 * delyBD) + (delyBC * r12));
dthetadr[1][1][2] = sc1 * ((-t1 * delzBC) + (delzBD * r12) +
(-t3 * delzBD) + (delzBC * r12));
dthetadr[1][3][0] = sc1 * ((t3 * delxBD) - (delxBC * r12));
dthetadr[1][3][1] = sc1 * ((t3 * delyBD) - (delyBC * r12));
dthetadr[1][3][2] = sc1 * ((t3 * delzBD) - (delzBC * r12));
// angle ABD
sc1 = sqrt(1.0/(1.0 - costhABD*costhABD));
t1 = costhABD / rABmag2;
t3 = costhABD / rBDmag2;
r12 = 1.0 / (rAB * rBD);
dthetadr[2][0][0] = sc1 * ((t1 * delxAB) - (delxBD * r12));
dthetadr[2][0][1] = sc1 * ((t1 * delyAB) - (delyBD * r12));
dthetadr[2][0][2] = sc1 * ((t1 * delzAB) - (delzBD * r12));
dthetadr[2][1][0] = sc1 * ((-t1 * delxAB) + (delxBD * r12) +
(-t3 * delxBD) + (delxAB * r12));
dthetadr[2][1][1] = sc1 * ((-t1 * delyAB) + (delyBD * r12) +
(-t3 * delyBD) + (delyAB * r12));
dthetadr[2][1][2] = sc1 * ((-t1 * delzAB) + (delzBD * r12) +
(-t3 * delzBD) + (delzAB * r12));
dthetadr[2][3][0] = sc1 * ((t3 * delxBD) - (delxAB * r12));
dthetadr[2][3][1] = sc1 * ((t3 * delyBD) - (delyAB * r12));
dthetadr[2][3][2] = sc1 * ((t3 * delzBD) - (delzAB * r12));
// angleangle forces
for (i = 0; i < 4; i++)
for (j = 0; j < 3; j++)
fabcd[i][j] = -
((aa_k1[type] *
(dthABC*dthetadr[1][i][j] + dthCBD*dthetadr[0][i][j])) +
(aa_k2[type] *
(dthABC*dthetadr[2][i][j] + dthABD*dthetadr[0][i][j])) +
(aa_k3[type] *
(dthABD*dthetadr[1][i][j] + dthCBD*dthetadr[2][i][j])));
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += fabcd[0][0];
f[i1][1] += fabcd[0][1];
f[i1][2] += fabcd[0][2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += fabcd[1][0];
f[i2][1] += fabcd[1][1];
f[i2][2] += fabcd[1][2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += fabcd[2][0];
f[i3][1] += fabcd[2][1];
f[i3][2] += fabcd[2][2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += fabcd[3][0];
f[i4][1] += fabcd[3][1];
f[i4][2] += fabcd[3][2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,
fabcd[0],fabcd[2],fabcd[3],
delxAB,delyAB,delzAB,delxBC,delyBC,delzBC,delxBD,delyBD,delzBD);
}
}
/* ----------------------------------------------------------------------
cross product: c = a x b
------------------------------------------------------------------------- */
void ImproperClass2::cross(double *a, double *b, double *c)
{
c[0] = a[1]*b[2] - a[2]*b[1];
c[1] = a[2]*b[0] - a[0]*b[2];
c[2] = a[0]*b[1] - a[1]*b[0];
}
/* ----------------------------------------------------------------------
dot product of a dot b
------------------------------------------------------------------------- */
double ImproperClass2::dot(double *a, double *b)
{
return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void ImproperClass2::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nimpropertypes; i++)
fprintf(fp,"%d %g %g\n",i,k0[i],chi0[i]);
fprintf(fp,"\nAngleAngle Coeffs\n\n");
for (int i = 1; i <= atom->nimpropertypes; i++)
fprintf(fp,"%d %g %g %g %g %g %g\n",i,aa_k1[i],aa_k2[i],aa_k3[i],
aa_theta0_1[i]*180.0/MY_PI,aa_theta0_2[i]*180.0/MY_PI,
aa_theta0_3[i]*180.0/MY_PI);
}
diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp
index 59d8b5e8e..08067d567 100644
--- a/src/DIPOLE/atom_vec_dipole.cpp
+++ b/src/DIPOLE/atom_vec_dipole.cpp
@@ -1,914 +1,912 @@
/* ----------------------------------------------------------------------
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 "atom_vec_dipole.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
mass_type = 1;
comm_x_only = 0;
comm_f_only = 1;
size_forward = 6;
size_reverse = 3;
size_border = 11;
size_velocity = 3;
size_data_atom = 9;
size_data_vel = 4;
xcol_data = 4;
atom->q_flag = atom->mu_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecDipole::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
q = memory->grow(atom->q,nmax,"atom:q");
mu = memory->grow(atom->mu,nmax,4,"atom:mu");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecDipole::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
q = atom->q; mu = atom->mu;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecDipole::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
q[j] = q[i];
mu[j][0] = mu[i][0];
mu[j][1] = mu[i][1];
mu[j][2] = mu[i][2];
mu[j][3] = mu[i][3];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecDipole::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecDipole::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecDipole::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
buf[m++] = mu[j][0];
buf[m++] = mu[j][1];
buf[m++] = mu[j][2];
buf[m++] = mu[j][3];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecDipole::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
mu[i][3] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecDipole::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
mu[i][3] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
q[i] = buf[m++];
mu[i][0] = buf[m++];
mu[i][1] = buf[m++];
mu[i][2] = buf[m++];
mu[i][3] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack all atom quantities for shipping to another proc
xyz must be 1st 3 values, so that comm::exchange can test on them
------------------------------------------------------------------------- */
int AtomVecDipole::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = q[i];
buf[m++] = mu[i][0];
buf[m++] = mu[i][1];
buf[m++] = mu[i][2];
buf[m++] = mu[i][3];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecDipole::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
q[nlocal] = buf[m++];
mu[nlocal][0] = buf[m++];
mu[nlocal][1] = buf[m++];
mu[nlocal][2] = buf[m++];
mu[nlocal][3] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecDipole::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 16 * nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecDipole::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = q[i];
buf[m++] = mu[i][0];
buf[m++] = mu[i][1];
buf[m++] = mu[i][2];
buf[m++] = mu[i][3];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecDipole::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
q[nlocal] = buf[m++];
mu[nlocal][0] = buf[m++];
mu[nlocal][1] = buf[m++];
mu[nlocal][2] = buf[m++];
mu[nlocal][3] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecDipole::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
q[nlocal] = 0.0;
mu[nlocal][0] = 0.0;
mu[nlocal][1] = 0.0;
mu[nlocal][2] = 0.0;
mu[nlocal][3] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecDipole::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
q[nlocal] = atof(values[2]);
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mu[nlocal][0] = atof(values[6]);
mu[nlocal][1] = atof(values[7]);
mu[nlocal][2] = atof(values[8]);
mu[nlocal][3] = sqrt(mu[nlocal][0]*mu[nlocal][0] +
mu[nlocal][1]*mu[nlocal][1] +
mu[nlocal][2]*mu[nlocal][2]);
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecDipole::data_atom_hybrid(int nlocal, char **values)
{
q[nlocal] = atof(values[0]);
mu[nlocal][0] = atof(values[1]);
mu[nlocal][1] = atof(values[2]);
mu[nlocal][2] = atof(values[3]);
mu[nlocal][3] = sqrt(mu[nlocal][0]*mu[nlocal][0] +
mu[nlocal][1]*mu[nlocal][1] +
mu[nlocal][2]*mu[nlocal][2]);
return 4;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecDipole::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = q[i];
buf[i][3] = x[i][0];
buf[i][4] = x[i][1];
buf[i][5] = x[i][2];
buf[i][6] = mu[i][0];
buf[i][7] = mu[i][1];
buf[i][8] = mu[i][2];
buf[i][9] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][10] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][11] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecDipole::pack_data_hybrid(int i, double *buf)
{
buf[0] = q[i];
buf[1] = mu[i][0];
buf[2] = mu[i][1];
buf[3] = mu[i][2];
return 4;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecDipole::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e "
+ fprintf(fp,TAGINT_FORMAT \
+ " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e "
"%-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4],
buf[i][5],buf[i][6],buf[i][7],buf[i][8],
(int) ubuf(buf[i][9]).i,(int) ubuf(buf[i][10]).i,
(int) ubuf(buf[i][11]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecDipole::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2],buf[3]);
return 4;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecDipole::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("q")) bytes += memory->usage(q,nmax);
if (atom->memcheck("mu")) bytes += memory->usage(mu,nmax,4);
return bytes;
}
diff --git a/src/DIPOLE/atom_vec_dipole.h b/src/DIPOLE/atom_vec_dipole.h
index 1aec00580..216cca512 100644
--- a/src/DIPOLE/atom_vec_dipole.h
+++ b/src/DIPOLE/atom_vec_dipole.h
@@ -1,88 +1,89 @@
/* -*- 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 ATOM_CLASS
AtomStyle(dipole,AtomVecDipole)
#else
#ifndef LMP_ATOM_VEC_DIPOLE_H
#define LMP_ATOM_VEC_DIPOLE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecDipole : public AtomVec {
public:
AtomVecDipole(class LAMMPS *);
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *q,**mu,**omega,**torque;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/FLD/pair_lubricateU.cpp b/src/FLD/pair_lubricateU.cpp
index 40761fcea..146b033aa 100644
--- a/src/FLD/pair_lubricateU.cpp
+++ b/src/FLD/pair_lubricateU.cpp
@@ -1,2125 +1,2124 @@
/* ----------------------------------------------------------------------
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: Amit Kumar and Michael Bybee (UIUC)
------------------------------------------------------------------------- */
#include "mpi.h"
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_lubricateU.h"
#include "atom.h"
#include "atom_vec.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "domain.h"
#include "update.h"
#include "math_const.h"
#include "modify.h"
#include "fix.h"
#include "fix_deform.h"
#include "fix_wall.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
-
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOL 1E-4 // tolerance for conjugate gradient
// same as fix_wall.cpp
enum{EDGE,CONSTANT,VARIABLE};
/* ---------------------------------------------------------------------- */
PairLubricateU::PairLubricateU(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
// pair lubricateU cannot compute virial as F dot r
// due to how drag forces are applied to atoms
// correct method is how per-atom virial does it
no_virial_fdotr_compute = 1;
nmax = 0;
fl = Tl = xl = NULL;
cgmax = 0;
bcg = xcg = rcg = rcg1 = pcg = RU = NULL;
// set comm size needed by this Pair
comm_forward = 6;
}
/* ---------------------------------------------------------------------- */
PairLubricateU::~PairLubricateU()
{
memory->destroy(fl);
memory->destroy(Tl);
memory->destroy(xl);
memory->destroy(bcg);
memory->destroy(xcg);
memory->destroy(rcg);
memory->destroy(rcg1);
memory->destroy(pcg);
memory->destroy(RU);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
memory->destroy(cut_inner);
}
}
/* ----------------------------------------------------------------------
It first has to solve for the velocity of the particles such that
the net force on the particles is zero. NOTE: it has to be the last
type of pair interaction specified in the input file. Also, it
assumes that no other types of interactions, like k-space, is
present. As already mentioned, the net force on the particles after
this pair interaction would be identically zero.
---------------------------------------------------------------------- */
void PairLubricateU::compute(int eflag, int vflag)
{
int i,j;
double **x = atom->x;
double **f = atom->f;
double **torque = atom->torque;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int nall = nlocal + nghost;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
// skip compute() if called from integrate::setup()
// this is b/c do not want compute() to update velocities twice on a restart
// when restarting, call compute on step N (last step of prev run),
// again on step N (setup of restart run),
// then on step N+1 (first step of restart)
// so this is one extra time which leads to bad dynamics
if (update->setupflag) return;
// grow per-atom arrays if necessary
// need to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(fl);
memory->destroy(Tl);
memory->destroy(xl);
nmax = atom->nmax;
memory->create(fl,nmax,3,"pair:fl");
memory->create(Tl,nmax,3,"pair:Tl");
memory->create(xl,nmax,3,"pair:xl");
}
// Added to implement midpoint integration scheme
// Save force, torque found so far. Also save the positions
for (i=0;i<nlocal+nghost;i++) {
for (j=0;j<3;j++) {
fl[i][j] = f[i][j];
Tl[i][j] = torque[i][j];
xl[i][j] = x[i][j];
}
}
// Stage one of Midpoint method
// Solve for velocities based on intial positions
stage_one();
// find positions at half the timestep and store in xl
intermediates(nall,xl);
// store back the saved forces and torques in original arrays
for(i=0;i<nlocal+nghost;i++) {
for(j=0;j<3;j++) {
f[i][j] = fl[i][j];
torque[i][j] = Tl[i][j];
}
}
// stage two: this will give the final velocities
stage_two(xl);
}
/* ------------------------------------------------------------------------
Stage one of midpoint method
------------------------------------------------------------------------- */
void PairLubricateU::stage_one()
{
int i,j,ii,inum,itype;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int newton_pair = force->newton_pair;
int *ilist;
double radi;
inum = list->inum;
ilist = list->ilist;
if (6*inum > cgmax) {
memory->destroy(bcg);
memory->destroy(xcg);
memory->destroy(rcg);
memory->destroy(rcg1);
memory->destroy(pcg);
memory->destroy(RU);
cgmax = 6*inum;
memory->create(bcg,cgmax,"pair:bcg");
memory->create(xcg,cgmax,"pair:bcg");
memory->create(rcg,cgmax,"pair:bcg");
memory->create(rcg1,cgmax,"pair:bcg");
memory->create(pcg,cgmax,"pair:bcg");
memory->create(RU,cgmax,"pair:bcg");
}
double alpha,beta;
double normi,error,normig;
double send[2],recv[2],rcg_dot_rcg;
// First compute R_FE*E
compute_RE();
// Reverse communication of forces and torques to
// accumulate the net force on each of the particles
if (newton_pair) comm->reverse_comm();
// CONJUGATE GRADIENT
// Find the right hand side= -ve of all forces/torques
// b = 6*Npart in overall size
for(ii = 0; ii < inum; ii++) {
i = ilist[ii];
for (j = 0; j < 3; j++) {
bcg[6*ii+j] = -f[i][j];
bcg[6*ii+j+3] = -torque[i][j];
}
}
// Start solving the equation : F^H = -F^P -F^B - F^H_{Ef}
// Store initial guess for velocity and angular-velocities/angular momentum
// NOTE velocities and angular velocities are assumed relative to the fluid
for (ii=0;ii<inum;ii++)
for (j=0;j<3;j++) {
xcg[6*ii+j] = 0.0;
xcg[6*ii+j+3] = 0.0;
}
// Copy initial guess to the global arrays to be acted upon by R_{FU}
// and returned by f and torque arrays
copy_vec_uo(inum,xcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
// Find initial residual
compute_RU();
// reverse communication of forces and torques
if (newton_pair) comm->reverse_comm();
copy_uo_vec(inum,f,torque,RU);
for (i=0;i<6*inum;i++)
rcg[i] = bcg[i] - RU[i];
// Set initial conjugate direction
for (i=0;i<6*inum;i++)
pcg[i] = rcg[i];
// Find initial norm of the residual or norm of the RHS (either is fine)
normi = dot_vec_vec(6*inum,bcg,bcg);
MPI_Allreduce(&normi,&normig,1,MPI_DOUBLE,MPI_SUM,world);
// Loop until convergence
do {
// find R*p
copy_vec_uo(inum,pcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
compute_RU();
// reverse communication of forces and torques
if (newton_pair) comm->reverse_comm();
copy_uo_vec(inum,f,torque,RU);
// Find alpha
send[0] = dot_vec_vec(6*inum,rcg,rcg);
send[1] = dot_vec_vec(6*inum,RU,pcg);
MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,world);
alpha = recv[0]/recv[1];
rcg_dot_rcg = recv[0];
// Find new x
for (i=0;i<6*inum;i++)
xcg[i] = xcg[i] + alpha*pcg[i];
// find new residual
for (i=0;i<6*inum;i++)
rcg1[i] = rcg[i] - alpha*RU[i];
// find beta
send[0] = dot_vec_vec(6*inum,rcg1,rcg1);
MPI_Allreduce(send,recv,1,MPI_DOUBLE,MPI_SUM,world);
beta = recv[0]/rcg_dot_rcg;
// Find new conjugate direction
for (i=0;i<6*inum;i++)
pcg[i] = rcg1[i] + beta*pcg[i];
for (i=0;i<6*inum;i++)
rcg[i] = rcg1[i];
// Find relative error
error = sqrt(recv[0]/normig);
} while (error > TOL);
// update the final converged velocities in respective arrays
copy_vec_uo(inum,xcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
// Find actual particle's velocities from relative velocities
// Only non-zero component of fluid's vel : vx=gdot*y and wz=-gdot/2
for (ii=0;ii<inum;ii++) {
i = ilist[ii];
itype = type[i];
radi = radius[i];
v[i][0] = v[i][0] + gdot*x[i][1];
omega[i][2] = omega[i][2] - gdot/2.0;
}
}
/*---------------------------------------------------------------
Finds the position of the particles at half the time step
----------------------------------------------------------------*/
void PairLubricateU::intermediates(int nall, double **xl)
{
int i;
double **x = atom->x;
double **v = atom->v;
double dtv = update->dt;
for (i=0;i<nall;i++) {
xl[i][0] = x[i][0] + 0.5*dtv*v[i][0];
xl[i][1] = x[i][1] + 0.5*dtv*v[i][1];
xl[i][2] = x[i][2] + 0.5*dtv*v[i][2];
}
}
/* ------------------------------------------------------------------------
Stage one of midpoint method
------------------------------------------------------------------------- */
void PairLubricateU::stage_two(double **x)
{
int i,j,ii,inum,itype;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int newton_pair = force->newton_pair;
int *ilist;
double radi;
inum = list->inum;
ilist = list->ilist;
double alpha,beta;
double normi,error,normig;
double send[2],recv[2],rcg_dot_rcg;
// First compute R_FE*E
compute_RE(x);
// Reverse communication of forces and torques to
// accumulate the net force on each of the particles
if (newton_pair) comm->reverse_comm();
// CONJUGATE GRADIENT
// Find the right hand side= -ve of all forces/torques
// b = 6*Npart in overall size
for(ii = 0; ii < inum; ii++) {
i = ilist[ii];
for (j = 0; j < 3; j++) {
bcg[6*ii+j] = -f[i][j];
bcg[6*ii+j+3] = -torque[i][j];
}
}
// Start solving the equation : F^H = -F^P -F^B - F^H_{Ef}
// Store initial guess for velocity and angular-velocities/angular momentum
// NOTE velocities and angular velocities are assumed relative to the fluid
for (ii=0;ii<inum;ii++)
for (j=0;j<3;j++) {
xcg[6*ii+j] = 0.0;
xcg[6*ii+j+3] = 0.0;
}
// Copy initial guess to the global arrays to be acted upon by R_{FU}
// and returned by f and torque arrays
copy_vec_uo(inum,xcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
// Find initial residual
compute_RU(x);
// reverse communication of forces and torques
if (newton_pair) comm->reverse_comm();
copy_uo_vec(inum,f,torque,RU);
for (i=0;i<6*inum;i++)
rcg[i] = bcg[i] - RU[i];
// Set initial conjugate direction
for (i=0;i<6*inum;i++)
pcg[i] = rcg[i];
// Find initial norm of the residual or norm of the RHS (either is fine)
normi = dot_vec_vec(6*inum,bcg,bcg);
MPI_Allreduce(&normi,&normig,1,MPI_DOUBLE,MPI_SUM,world);
// Loop until convergence
do {
// find R*p
copy_vec_uo(inum,pcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
compute_RU(x);
// reverse communication of forces and torques
if (newton_pair) comm->reverse_comm();
copy_uo_vec(inum,f,torque,RU);
// Find alpha
send[0] = dot_vec_vec(6*inum,rcg,rcg);
send[1] = dot_vec_vec(6*inum,RU,pcg);
MPI_Allreduce(send,recv,2,MPI_DOUBLE,MPI_SUM,world);
alpha = recv[0]/recv[1];
rcg_dot_rcg = recv[0];
// Find new x
for (i=0;i<6*inum;i++)
xcg[i] = xcg[i] + alpha*pcg[i];
// find new residual
for (i=0;i<6*inum;i++)
rcg1[i] = rcg[i] - alpha*RU[i];
// find beta
send[0] = dot_vec_vec(6*inum,rcg1,rcg1);
MPI_Allreduce(send,recv,1,MPI_DOUBLE,MPI_SUM,world);
beta = recv[0]/rcg_dot_rcg;
// Find new conjugate direction
for (i=0;i<6*inum;i++)
pcg[i] = rcg1[i] + beta*pcg[i];
for (i=0;i<6*inum;i++)
rcg[i] = rcg1[i];
// Find relative error
error = sqrt(recv[0]/normig);
} while (error > TOL);
// update the final converged velocities in respective arrays
copy_vec_uo(inum,xcg,v,omega);
// set velocities for ghost particles
comm->forward_comm_pair(this);
// Compute the viscosity/pressure
if (evflag) compute_Fh(x);
// Find actual particle's velocities from relative velocities
// Only non-zero component of fluid's vel : vx=gdot*y and wz=-gdot/2
for (ii=0;ii<inum;ii++) {
i = ilist[ii];
itype = type[i];
radi = radius[i];
v[i][0] = v[i][0] + gdot*x[i][1];
omega[i][2] = omega[i][2] - gdot/2.0;
}
}
/* ------------------------------------------------------------------------
This function computes the final hydrodynamic force once the
velocities have converged.
------------------------------------------------------------------------- */
void PairLubricateU::compute_Fh(double **x)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz;
double rsq,r,h_sep,radi;
double vr1,vr2,vr3,vnnr,vn1,vn2,vn3;
double vt1,vt2,vt3;
int *ilist,*jlist,*numneigh,**firstneigh;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int newton_pair = force->newton_pair;
double vxmu2f = force->vxmu2f;
int overlaps = 0;
double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// This section of code adjusts R0/RT0/RS0 if necessary due to changes
// in the volume fraction as a result of fix deform or moving walls
double dims[3], wallcoord;
if (flagVF) // Flag for volume fraction corrections
if (flagdeform || flagwall == 2){ // Possible changes in volume fraction
if (flagdeform && !flagwall)
for (j = 0; j < 3; j++)
dims[j] = domain->prd[j];
else if (flagwall == 2 || (flagdeform && flagwall == 1)){
double wallhi[3], walllo[3];
for (int j = 0; j < 3; j++){
wallhi[j] = domain->prd[j];
walllo[j] = 0;
}
for (int m = 0; m < wallfix->nwall; m++){
int dim = wallfix->wallwhich[m] / 2;
int side = wallfix->wallwhich[m] % 2;
if (wallfix->xstyle[m] == VARIABLE){
wallcoord = input->variable->compute_equal(wallfix->xindex[m]);
}
else wallcoord = wallfix->coord0[m];
if (side == 0) walllo[dim] = wallcoord;
else wallhi[dim] = wallcoord;
}
for (int j = 0; j < 3; j++)
dims[j] = wallhi[j] - walllo[j];
}
double vol_T = dims[0]*dims[1]*dims[2];
double vol_f = vol_P/vol_T;
if (flaglog == 0) {
// R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f);
// RT0 = 8*MY_PI*mu*pow(rad,3);
RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*
(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f);
} else {
// R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f);
// RT0 = 8*MY_PI*mu*pow(rad,3)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f);
RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*
(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f);
}
}
// end of R0 adjustment code
// Set force to zero which is the final value after this pair interaction
for (i=0;i<nlocal+nghost;i++)
for (j=0;j<3;j++) {
f[i][j] = 0.0;
torque[i][j] = 0.0;
}
// reverse communication of forces and torques
if (newton_pair) comm->reverse_comm(); // not really needed
// Find additional contribution from the stresslets
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];
// Find the contribution to stress from isotropic RS0
// Set psuedo force to obtain the required contribution
// need to set delx and fy only
fx = 0.0; delx = radi;
fy = vxmu2f*RS0*gdot/2.0/radi; dely = 0.0;
fz = 0.0; delz = 0.0;
if (evflag)
ev_tally_xyz(i,i,nlocal,newton_pair,0.0,0.0,-fx,-fy,-fz,delx,dely,delz);
// Find angular velocity
wi[0] = omega[i][0];
wi[1] = omega[i][1];
wi[2] = omega[i][2];
if (!flagHI) continue;
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]) {
r = sqrt(rsq);
// Use omega directly if it exists, else angmom
// angular momentum = I*omega = 2/5 * M*R^2 * omega
wj[0] = omega[j][0];
wj[1] = omega[j][1];
wj[2] = omega[j][2];
// loc of the point of closest approach on particle i from its cente
xl[0] = -delx/r*radi;
xl[1] = -dely/r*radi;
xl[2] = -delz/r*radi;
// velocity at the point of closest approach on both particles
// v = v + omega_cross_xl
// particle i
vi[0] = v[i][0] + (wi[1]*xl[2] - wi[2]*xl[1]);
vi[1] = v[i][1] + (wi[2]*xl[0] - wi[0]*xl[2]);
vi[2] = v[i][2] + (wi[0]*xl[1] - wi[1]*xl[0]);
// particle j
vj[0] = v[j][0] - (wj[1]*xl[2] - wj[2]*xl[1]);
vj[1] = v[j][1] - (wj[2]*xl[0] - wj[0]*xl[2]);
vj[2] = v[j][2] - (wj[0]*xl[1] - wj[1]*xl[0]);
// Relative velocity at the point of closest approach
// include contribution from Einf of the fluid
vr1 = vi[0] - vj[0] -
2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]);
vr2 = vi[1] - vj[1] -
2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]);
vr3 = vi[2] - vj[2] -
2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]);
// Normal component (vr.n)n
vnnr = (vr1*delx + vr2*dely + vr3*delz)/r;
vn1 = vnnr*delx/r;
vn2 = vnnr*dely/r;
vn3 = vnnr*delz/r;
// Tangential component vr - (vr.n)n
vt1 = vr1 - vn1;
vt2 = vr2 - vn2;
vt3 = vr3 - vn3;
// Find the scalar resistances a_sq, a_sh and a_pu
h_sep = r - 2.0*radi;
// check for overlaps
if (h_sep < 0.0) overlaps++;
// If less than the minimum gap use the minimum gap instead
if (r < cut_inner[itype][jtype])
h_sep = cut_inner[itype][jtype] - 2.0*radi;
// Scale h_sep by radi
h_sep = h_sep/radi;
// Scalar resistances
if (flaglog) {
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep));
a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep));
} else
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep);
// Find force due to squeeze type motion
fx = a_sq*vn1;
fy = a_sq*vn2;
fz = a_sq*vn3;
// Find force due to all shear kind of motions
if (flaglog) {
fx = fx + a_sh*vt1;
fy = fy + a_sh*vt2;
fz = fz + a_sh*vt3;
}
// Scale forces to obtain in appropriate units
fx = vxmu2f*fx;
fy = vxmu2f*fy;
fz = vxmu2f*fz;
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
0.0,0.0,-fx,-fy,-fz,delx,dely,delz);
}
}
}
}
/* ----------------------------------------------------------------------
computes R_FU * U
---------------------------------------------------------------------- */
void PairLubricateU::compute_RU()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz;
double rsq,r,h_sep,radi;
double vr1,vr2,vr3,vnnr,vn1,vn2,vn3;
double vt1,vt2,vt3,wdotn,wt1,wt2,wt3;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int newton_pair = force->newton_pair;
double vxmu2f = force->vxmu2f;
int overlaps = 0;
double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh,a_pu;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// This section of code adjusts R0/RT0/RS0 if necessary due to changes
// in the volume fraction as a result of fix deform or moving walls
double dims[3], wallcoord;
if (flagVF) // Flag for volume fraction corrections
if (flagdeform || flagwall == 2){ // Possible changes in volume fraction
if (flagdeform && !flagwall)
for (j = 0; j < 3; j++)
dims[j] = domain->prd[j];
else if (flagwall == 2 || (flagdeform && flagwall == 1)){
double wallhi[3], walllo[3];
for (int j = 0; j < 3; j++){
wallhi[j] = domain->prd[j];
walllo[j] = 0;
}
for (int m = 0; m < wallfix->nwall; m++){
int dim = wallfix->wallwhich[m] / 2;
int side = wallfix->wallwhich[m] % 2;
if (wallfix->xstyle[m] == VARIABLE){
wallcoord = input->variable->compute_equal(wallfix->xindex[m]);
}
else wallcoord = wallfix->coord0[m];
if (side == 0) walllo[dim] = wallcoord;
else wallhi[dim] = wallcoord;
}
for (int j = 0; j < 3; j++)
dims[j] = wallhi[j] - walllo[j];
}
double vol_T = dims[0]*dims[1]*dims[2];
double vol_f = vol_P/vol_T;
if (flaglog == 0) {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0);
// RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f);
} else {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f);
// RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f);
}
}
// end of R0 adjustment code
// Initialize f to zero
for (i=0;i<nlocal+nghost;i++)
for (j=0;j<3;j++) {
f[i][j] = 0.0;
torque[i][j] = 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];
radi = radius[i];
jlist = firstneigh[i];
jnum = numneigh[i];
// Find angular velocity
wi[0] = omega[i][0];
wi[1] = omega[i][1];
wi[2] = omega[i][2];
// Contribution due to the isotropic terms
f[i][0] += -vxmu2f*R0*v[i][0];
f[i][1] += -vxmu2f*R0*v[i][1];
f[i][2] += -vxmu2f*R0*v[i][2];
torque[i][0] += -vxmu2f*RT0*wi[0];
torque[i][1] += -vxmu2f*RT0*wi[1];
torque[i][2] += -vxmu2f*RT0*wi[2];
if (!flagHI) continue;
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]) {
r = sqrt(rsq);
// Use omega directly if it exists, else angmom
// angular momentum = I*omega = 2/5 * M*R^2 * omega
wj[0] = omega[j][0];
wj[1] = omega[j][1];
wj[2] = omega[j][2];
// loc of the point of closest approach on particle i from its center
xl[0] = -delx/r*radi;
xl[1] = -dely/r*radi;
xl[2] = -delz/r*radi;
// velocity at the point of closest approach on both particles
// v = v + omega_cross_xl
// particle i
vi[0] = v[i][0] + (wi[1]*xl[2] - wi[2]*xl[1]);
vi[1] = v[i][1] + (wi[2]*xl[0] - wi[0]*xl[2]);
vi[2] = v[i][2] + (wi[0]*xl[1] - wi[1]*xl[0]);
// particle j
vj[0] = v[j][0] - (wj[1]*xl[2] - wj[2]*xl[1]);
vj[1] = v[j][1] - (wj[2]*xl[0] - wj[0]*xl[2]);
vj[2] = v[j][2] - (wj[0]*xl[1] - wj[1]*xl[0]);
// Find the scalar resistances a_sq and a_sh
h_sep = r - 2.0*radi;
// check for overlaps
if(h_sep < 0.0) overlaps++;
// If less than the minimum gap use the minimum gap instead
if (r < cut_inner[itype][jtype])
h_sep = cut_inner[itype][jtype] - 2.0*radi;
// Scale h_sep by radi
h_sep = h_sep/radi;
// Scalar resistances
if (flaglog) {
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep));
a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep));
a_pu = 8.0*MY_PI*mu*pow(radi,3.0)*(3.0/160.0*log(1.0/h_sep));
} else
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep);
// Relative velocity at the point of closest approach
vr1 = vi[0] - vj[0];
vr2 = vi[1] - vj[1];
vr3 = vi[2] - vj[2];
// Normal component (vr.n)n
vnnr = (vr1*delx + vr2*dely + vr3*delz)/r;
vn1 = vnnr*delx/r;
vn2 = vnnr*dely/r;
vn3 = vnnr*delz/r;
// Tangential component vr - (vr.n)n
vt1 = vr1 - vn1;
vt2 = vr2 - vn2;
vt3 = vr3 - vn3;
// Find force due to squeeze type motion
fx = a_sq*vn1;
fy = a_sq*vn2;
fz = a_sq*vn3;
// Find force due to all shear kind of motions
if (flaglog) {
fx = fx + a_sh*vt1;
fy = fy + a_sh*vt2;
fz = fz + a_sh*vt3;
}
// Scale forces to obtain in appropriate units
fx = vxmu2f*fx;
fy = vxmu2f*fy;
fz = vxmu2f*fz;
// Add to the total forc
f[i][0] -= fx;
f[i][1] -= fy;
f[i][2] -= fz;
if (newton_pair || j < nlocal) {
f[j][0] += fx;
f[j][1] += fy;
f[j][2] += fz;
}
// Find torque due to this force
if (flaglog) {
tx = xl[1]*fz - xl[2]*fy;
ty = xl[2]*fx - xl[0]*fz;
tz = xl[0]*fy - xl[1]*fx;
// Why a scale factor ?
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if(newton_pair || j < nlocal) {
torque[j][0] -= vxmu2f*tx;
torque[j][1] -= vxmu2f*ty;
torque[j][2] -= vxmu2f*tz;
}
// Torque due to a_pu
wdotn = ((wi[0]-wj[0])*delx +
(wi[1]-wj[1])*dely + (wi[2]-wj[2])*delz)/r;
wt1 = (wi[0]-wj[0]) - wdotn*delx/r;
wt2 = (wi[1]-wj[1]) - wdotn*dely/r;
wt3 = (wi[2]-wj[2]) - wdotn*delz/r;
tx = a_pu*wt1;
ty = a_pu*wt2;
tz = a_pu*wt3;
// add to total
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if (newton_pair || j < nlocal) {
torque[j][0] += vxmu2f*tx;
torque[j][1] += vxmu2f*ty;
torque[j][2] += vxmu2f*tz;
}
}
}
}
}
}
/* ----------------------------------------------------------------------
computes R_FU * U
---------------------------------------------------------------------- */
void PairLubricateU::compute_RU(double **x)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz;
double rsq,r,h_sep,radi;
double vr1,vr2,vr3,vnnr,vn1,vn2,vn3;
double vt1,vt2,vt3,wdotn,wt1,wt2,wt3;
int *ilist,*jlist,*numneigh,**firstneigh;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int newton_pair = force->newton_pair;
double vxmu2f = force->vxmu2f;
int overlaps = 0;
double vi[3],vj[3],wi[3],wj[3],xl[3],a_sq,a_sh,a_pu;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// This section of code adjusts R0/RT0/RS0 if necessary due to changes
// in the volume fraction as a result of fix deform or moving walls
double dims[3], wallcoord;
if (flagVF) // Flag for volume fraction corrections
if (flagdeform || flagwall == 2){ // Possible changes in volume fraction
if (flagdeform && !flagwall)
for (j = 0; j < 3; j++)
dims[j] = domain->prd[j];
else if (flagwall == 2 || (flagdeform && flagwall == 1)){
double wallhi[3], walllo[3];
for (int j = 0; j < 3; j++){
wallhi[j] = domain->prd[j];
walllo[j] = 0;
}
for (int m = 0; m < wallfix->nwall; m++){
int dim = wallfix->wallwhich[m] / 2;
int side = wallfix->wallwhich[m] % 2;
if (wallfix->xstyle[m] == VARIABLE){
wallcoord = input->variable->compute_equal(wallfix->xindex[m]);
}
else wallcoord = wallfix->coord0[m];
if (side == 0) walllo[dim] = wallcoord;
else wallhi[dim] = wallcoord;
}
for (int j = 0; j < 3; j++)
dims[j] = wallhi[j] - walllo[j];
}
double vol_T = dims[0]*dims[1]*dims[2];
double vol_f = vol_P/vol_T;
if (flaglog == 0) {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0);
// RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f);
} else {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f);
// RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f);
}
}
// end of R0 adjustment code
// Initialize f to zero
for (i=0;i<nlocal+nghost;i++)
for (j=0;j<3;j++) {
f[i][j] = 0.0;
torque[i][j] = 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];
radi = radius[i];
jlist = firstneigh[i];
jnum = numneigh[i];
// Find angular velocity
wi[0] = omega[i][0];
wi[1] = omega[i][1];
wi[2] = omega[i][2];
// Contribution due to the isotropic terms
f[i][0] += -vxmu2f*R0*v[i][0];
f[i][1] += -vxmu2f*R0*v[i][1];
f[i][2] += -vxmu2f*R0*v[i][2];
torque[i][0] += -vxmu2f*RT0*wi[0];
torque[i][1] += -vxmu2f*RT0*wi[1];
torque[i][2] += -vxmu2f*RT0*wi[2];
if (!flagHI) continue;
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]) {
r = sqrt(rsq);
// Use omega directly if it exists, else angmom
// angular momentum = I*omega = 2/5 * M*R^2 * omega
wj[0] = omega[j][0];
wj[1] = omega[j][1];
wj[2] = omega[j][2];
// loc of the point of closest approach on particle i from its center
xl[0] = -delx/r*radi;
xl[1] = -dely/r*radi;
xl[2] = -delz/r*radi;
// velocity at the point of closest approach on both particles
// v = v + omega_cross_xl
// particle i
vi[0] = v[i][0] + (wi[1]*xl[2] - wi[2]*xl[1]);
vi[1] = v[i][1] + (wi[2]*xl[0] - wi[0]*xl[2]);
vi[2] = v[i][2] + (wi[0]*xl[1] - wi[1]*xl[0]);
// particle j
vj[0] = v[j][0] - (wj[1]*xl[2] - wj[2]*xl[1]);
vj[1] = v[j][1] - (wj[2]*xl[0] - wj[0]*xl[2]);
vj[2] = v[j][2] - (wj[0]*xl[1] - wj[1]*xl[0]);
// Find the scalar resistances a_sq and a_sh
h_sep = r - 2.0*radi;
// check for overlaps
if(h_sep < 0.0) overlaps++;
// If less than the minimum gap use the minimum gap instead
if (r < cut_inner[itype][jtype])
h_sep = cut_inner[itype][jtype] - 2.0*radi;
// Scale h_sep by radi
h_sep = h_sep/radi;
// Scalar resistances
if (flaglog) {
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1.0/h_sep));
a_sh = 6.0*MY_PI*mu*radi*(1.0/6.0*log(1.0/h_sep));
a_pu = 8.0*MY_PI*mu*pow(radi,3.0)*(3.0/160.0*log(1.0/h_sep));
} else
a_sq = 6.0*MY_PI*mu*radi*(1.0/4.0/h_sep);
// Relative velocity at the point of closest approach
vr1 = vi[0] - vj[0];
vr2 = vi[1] - vj[1];
vr3 = vi[2] - vj[2];
// Normal component (vr.n)n
vnnr = (vr1*delx + vr2*dely + vr3*delz)/r;
vn1 = vnnr*delx/r;
vn2 = vnnr*dely/r;
vn3 = vnnr*delz/r;
// Tangential component vr - (vr.n)n
vt1 = vr1 - vn1;
vt2 = vr2 - vn2;
vt3 = vr3 - vn3;
// Find force due to squeeze type motion
fx = a_sq*vn1;
fy = a_sq*vn2;
fz = a_sq*vn3;
// Find force due to all shear kind of motions
if (flaglog) {
fx = fx + a_sh*vt1;
fy = fy + a_sh*vt2;
fz = fz + a_sh*vt3;
}
// Scale forces to obtain in appropriate units
fx = vxmu2f*fx;
fy = vxmu2f*fy;
fz = vxmu2f*fz;
// Add to the total force
f[i][0] -= fx;
f[i][1] -= fy;
f[i][2] -= fz;
if (newton_pair || j < nlocal) {
f[j][0] += fx;
f[j][1] += fy;
f[j][2] += fz;
}
// Find torque due to this force
if (flaglog) {
tx = xl[1]*fz - xl[2]*fy;
ty = xl[2]*fx - xl[0]*fz;
tz = xl[0]*fy - xl[1]*fx;
// Why a scale factor ?
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if(newton_pair || j < nlocal) {
torque[j][0] -= vxmu2f*tx;
torque[j][1] -= vxmu2f*ty;
torque[j][2] -= vxmu2f*tz;
}
// Torque due to a_pu
wdotn = ((wi[0]-wj[0])*delx +
(wi[1]-wj[1])*dely + (wi[2]-wj[2])*delz)/r;
wt1 = (wi[0]-wj[0]) - wdotn*delx/r;
wt2 = (wi[1]-wj[1]) - wdotn*dely/r;
wt3 = (wi[2]-wj[2]) - wdotn*delz/r;
tx = a_pu*wt1;
ty = a_pu*wt2;
tz = a_pu*wt3;
// add to total
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if (newton_pair || j < nlocal) {
torque[j][0] += vxmu2f*tx;
torque[j][1] += vxmu2f*ty;
torque[j][2] += vxmu2f*tz;
}
}
}
}
}
}
/* ----------------------------------------------------------------------
This computes R_{FE}*E , where E is the rate of strain of tensor which is
known apriori, as it depends only on the known fluid velocity.
So, this part of the hydrodynamic interaction can be pre computed and
transferred to the RHS
---------------------------------------------------------------------- */
void PairLubricateU::compute_RE()
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz;
double rsq,r,h_sep,radi;
double vr1,vr2,vr3,vnnr,vn1,vn2,vn3;
double vt1,vt2,vt3;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
double **f = atom->f;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
double vxmu2f = force->vxmu2f;
int overlaps = 0;
double xl[3],a_sq,a_sh,a_pu;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
if (!flagHI) return;
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];
// No contribution from isotropic terms due to E
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]) {
r = sqrt(rsq);
// loc of the point of closest approach on particle i from its center
xl[0] = -delx/r*radi;
xl[1] = -dely/r*radi;
xl[2] = -delz/r*radi;
// Find the scalar resistances a_sq and a_sh
h_sep = r - 2.0*radi;
// check for overlaps
if(h_sep < 0.0) overlaps++;
// If less than the minimum gap use the minimum gap instead
if (r < cut_inner[itype][jtype])
h_sep = cut_inner[itype][jtype] - 2.0*radi;
// Scale h_sep by radi
h_sep = h_sep/radi;
// Scalar resistance for Squeeze type motions
if (flaglog)
a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1/h_sep));
else
a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep);
// Scalar resistance for Shear type motions
if (flaglog) {
a_sh = 6*MY_PI*mu*radi*(1.0/6.0*log(1/h_sep));
a_pu = 8.0*MY_PI*mu*pow(radi,3.0)*(3.0/160.0*log(1.0/h_sep));
}
// Relative velocity at the point of closest approach due to Ef only
vr1 = -2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]);
vr2 = -2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]);
vr3 = -2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]);
// Normal component (vr.n)n
vnnr = (vr1*delx + vr2*dely + vr3*delz)/r;
vn1 = vnnr*delx/r;
vn2 = vnnr*dely/r;
vn3 = vnnr*delz/r;
// Tangential component vr - (vr.n)n
vt1 = vr1 - vn1;
vt2 = vr2 - vn2;
vt3 = vr3 - vn3;
// Find force due to squeeze type motion
fx = a_sq*vn1;
fy = a_sq*vn2;
fz = a_sq*vn3;
// Find force due to all shear kind of motions
if (flaglog) {
fx = fx + a_sh*vt1;
fy = fy + a_sh*vt2;
fz = fz + a_sh*vt3;
}
// Scale forces to obtain in appropriate units
fx = vxmu2f*fx;
fy = vxmu2f*fy;
fz = vxmu2f*fz;
// Add to the total forc
f[i][0] -= fx;
f[i][1] -= fy;
f[i][2] -= fz;
if (newton_pair || j < nlocal) {
f[j][0] += fx;
f[j][1] += fy;
f[j][2] += fz;
}
// Find torque due to this force
if (flaglog) {
tx = xl[1]*fz - xl[2]*fy;
ty = xl[2]*fx - xl[0]*fz;
tz = xl[0]*fy - xl[1]*fx;
// Why a scale factor ?
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if (newton_pair || j < nlocal) {
torque[j][0] -= vxmu2f*tx;
torque[j][1] -= vxmu2f*ty;
torque[j][2] -= vxmu2f*tz;
}
// NOTE No a_pu term needed as they add up to zero
}
}
}
}
int print_overlaps = 0;
if (print_overlaps && overlaps)
printf("Number of overlaps=%d\n",overlaps);
}
/* ----------------------------------------------------------------------
This computes R_{FE}*E , where E is the rate of strain of tensor which is
known apriori, as it depends only on the known fluid velocity.
So, this part of the hydrodynamic interaction can be pre computed and
transferred to the RHS
---------------------------------------------------------------------- */
void PairLubricateU::compute_RE(double **x)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,fx,fy,fz,tx,ty,tz;
double rsq,r,h_sep,radi;
double vr1,vr2,vr3,vnnr,vn1,vn2,vn3;
double vt1,vt2,vt3;
int *ilist,*jlist,*numneigh,**firstneigh;
double **f = atom->f;
double **torque = atom->torque;
double *radius = atom->radius;
int *type = atom->type;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
double vxmu2f = force->vxmu2f;
int overlaps = 0;
double xl[3],a_sq,a_sh,a_pu;
if (!flagHI) return;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
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];
// No contribution from isotropic terms due to E
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]) {
r = sqrt(rsq);
// loc of the point of closest approach on particle i from its center
xl[0] = -delx/r*radi;
xl[1] = -dely/r*radi;
xl[2] = -delz/r*radi;
// Find the scalar resistances a_sq and a_sh
h_sep = r - 2.0*radi;
// check for overlaps
if(h_sep < 0.0) overlaps++;
// If less than the minimum gap use the minimum gap instead
if (r < cut_inner[itype][jtype])
h_sep = cut_inner[itype][jtype] - 2.0*radi;
// Scale h_sep by radi
h_sep = h_sep/radi;
// Scalar resistance for Squeeze type motions
if (flaglog)
a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep + 9.0/40.0*log(1/h_sep));
else
a_sq = 6*MY_PI*mu*radi*(1.0/4.0/h_sep);
// Scalar resistance for Shear type motions
if (flaglog) {
a_sh = 6*MY_PI*mu*radi*(1.0/6.0*log(1/h_sep));
a_pu = 8.0*MY_PI*mu*pow(radi,3.0)*(3.0/160.0*log(1.0/h_sep));
}
// Relative velocity at the point of closest approach due to Ef only
vr1 = -2.0*(Ef[0][0]*xl[0] + Ef[0][1]*xl[1] + Ef[0][2]*xl[2]);
vr2 = -2.0*(Ef[1][0]*xl[0] + Ef[1][1]*xl[1] + Ef[1][2]*xl[2]);
vr3 = -2.0*(Ef[2][0]*xl[0] + Ef[2][1]*xl[1] + Ef[2][2]*xl[2]);
// Normal component (vr.n)n
vnnr = (vr1*delx + vr2*dely + vr3*delz)/r;
vn1 = vnnr*delx/r;
vn2 = vnnr*dely/r;
vn3 = vnnr*delz/r;
// Tangential component vr - (vr.n)n
vt1 = vr1 - vn1;
vt2 = vr2 - vn2;
vt3 = vr3 - vn3;
// Find force due to squeeze type motion
fx = a_sq*vn1;
fy = a_sq*vn2;
fz = a_sq*vn3;
// Find force due to all shear kind of motions
if (flaglog) {
fx = fx + a_sh*vt1;
fy = fy + a_sh*vt2;
fz = fz + a_sh*vt3;
}
// Scale forces to obtain in appropriate units
fx = vxmu2f*fx;
fy = vxmu2f*fy;
fz = vxmu2f*fz;
// Add to the total forc
f[i][0] -= fx;
f[i][1] -= fy;
f[i][2] -= fz;
if (newton_pair || j < nlocal) {
f[j][0] += fx;
f[j][1] += fy;
f[j][2] += fz;
}
// Find torque due to this force
if (flaglog) {
tx = xl[1]*fz - xl[2]*fy;
ty = xl[2]*fx - xl[0]*fz;
tz = xl[0]*fy - xl[1]*fx;
// Why a scale factor ?
torque[i][0] -= vxmu2f*tx;
torque[i][1] -= vxmu2f*ty;
torque[i][2] -= vxmu2f*tz;
if (newton_pair || j < nlocal) {
torque[j][0] -= vxmu2f*tx;
torque[j][1] -= vxmu2f*ty;
torque[j][2] -= vxmu2f*tz;
}
// NOTE No a_pu term needed as they add up to zero
}
}
}
}
int print_overlaps = 0;
if (print_overlaps && overlaps)
printf("Number of overlaps=%d\n",overlaps);
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLubricateU::allocate()
{
allocated = 1;
int n = atom->ntypes;
setflag = 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;
cutsq = memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cut,n+1,n+1,"pair:cut");
memory->create(cut_inner,n+1,n+1,"pair:cut_inner");
}
/*-----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLubricateU::settings(int narg, char **arg)
{
if (narg != 5 && narg != 7) error->all(FLERR,"Illegal pair_style command");
mu = force->numeric(FLERR,arg[0]);
flaglog = force->inumeric(FLERR,arg[1]);
cut_inner_global = force->numeric(FLERR,arg[2]);
cut_global = force->numeric(FLERR,arg[3]);
gdot = force->numeric(FLERR,arg[4]);
flagHI = flagVF = 1;
if (narg == 7) {
flagHI = force->inumeric(FLERR,arg[5]);
flagVF = force->inumeric(FLERR,arg[6]);
}
if (flaglog == 1 && flagHI == 0) {
error->warning(FLERR,"Cannot include log terms without 1/r terms; "
"setting flagHI to 1.");
flagHI = 1;
}
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i+1; j <= atom->ntypes; j++)
if (setflag[i][j]) {
cut_inner[i][j] = cut_inner_global;
cut[i][j] = cut_global;
}
}
// store the rate of strain tensor
Ef[0][0] = 0.0;
Ef[0][1] = 0.5*gdot;
Ef[0][2] = 0.0;
Ef[1][0] = 0.5*gdot;
Ef[1][1] = 0.0;
Ef[1][2] = 0.0;
Ef[2][0] = 0.0;
Ef[2][1] = 0.0;
Ef[2][2] = 0.0;
}
/*-----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLubricateU::coeff(int narg, char **arg)
{
if (narg != 2 && narg != 4)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
double cut_inner_one = cut_inner_global;
double cut_one = cut_global;
if (narg == 4) {
cut_inner_one = force->numeric(FLERR,arg[2]);
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++) {
cut_inner[i][j] = cut_inner_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 PairLubricateU::init_style()
{
if (!atom->sphere_flag)
error->all(FLERR,"Pair lubricateU requires atom style sphere");
if (comm->ghost_velocity == 0)
error->all(FLERR,"Pair lubricateU requires ghost atoms store velocity");
neighbor->request(this);
// require that atom radii are identical within each type
// require monodisperse system with same radii for all types
double radi, radtype;
for (int i = 1; i <= atom->ntypes; i++) {
if (!atom->radius_consistency(i,radtype))
error->all(FLERR,"Pair lubricateU requires monodisperse particles");
if (i > 1 && radtype != rad)
error->all(FLERR,"Pair lubricateU requires monodisperse particles");
radi = radtype;
}
// check for fix deform, if exists it must use "remap v"
// If box will change volume, set appropriate flag so that volume
// and v.f. corrections are re-calculated at every step.
//
// If available volume is different from box volume
// due to walls, set volume appropriately; if walls will
// move, set appropriate flag so that volume and v.f. corrections
// are re-calculated at every step.
flagdeform = flagwall = 0;
for (int i = 0; i < modify->nfix; i++){
if (strcmp(modify->fix[i]->style,"deform") == 0)
flagdeform = 1;
else if (strstr(modify->fix[i]->style,"wall") != NULL) {
if (flagwall)
error->all(FLERR,
"Cannot use multiple fix wall commands with "
"pair lubricateU");
flagwall = 1; // Walls exist
wallfix = (FixWall *) modify->fix[i];
if (wallfix->xflag) flagwall = 2; // Moving walls exist
}
}
// set the isotropic constants depending on the volume fraction
// vol_T = total volumeshearing = flagdeform = flagwall = 0;
double vol_T, wallcoord;
if (!flagwall) vol_T = domain->xprd*domain->yprd*domain->zprd;
else {
double wallhi[3], walllo[3];
for (int j = 0; j < 3; j++){
wallhi[j] = domain->prd[j];
walllo[j] = 0;
}
for (int m = 0; m < wallfix->nwall; m++){
int dim = wallfix->wallwhich[m] / 2;
int side = wallfix->wallwhich[m] % 2;
if (wallfix->xstyle[m] == VARIABLE){
wallfix->xindex[m] = input->variable->find(wallfix->xstr[m]);
//Since fix->wall->init happens after pair->init_style
wallcoord = input->variable->compute_equal(wallfix->xindex[m]);
}
else wallcoord = wallfix->coord0[m];
if (side == 0) walllo[dim] = wallcoord;
else wallhi[dim] = wallcoord;
}
vol_T = (wallhi[0] - walllo[0]) * (wallhi[1] - walllo[1]) *
(wallhi[2] - walllo[2]);
}
// assuming monodisperse spheres, vol_P = volume of the particles
double tmp = 0.0;
if (atom->radius) tmp = atom->radius[0];
MPI_Allreduce(&tmp,&rad,1,MPI_DOUBLE,MPI_MAX,world);
vol_P = atom->natoms * (4.0/3.0)*MY_PI*pow(rad,3.0);
// vol_f = volume fraction
double vol_f = vol_P/vol_T;
if (!flagVF) vol_f = 0;
// set the isotropic constant
if (flaglog == 0) {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.16*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0); // not actually needed
RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.33*vol_f + 2.80*vol_f*vol_f);
} else {
R0 = 6*MY_PI*mu*rad*(1.0 + 2.725*vol_f - 6.583*vol_f*vol_f);
RT0 = 8*MY_PI*mu*pow(rad,3.0)*(1.0 + 0.749*vol_f - 2.469*vol_f*vol_f);
RS0 = 20.0/3.0*MY_PI*mu*pow(rad,3.0)*(1.0 + 3.64*vol_f - 6.95*vol_f*vol_f);
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairLubricateU::init_one(int i, int j)
{
if (setflag[i][j] == 0) {
cut_inner[i][j] = mix_distance(cut_inner[i][i],cut_inner[j][j]);
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
}
cut_inner[j][i] = cut_inner[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLubricateU::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(&cut_inner[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLubricateU::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(&cut_inner[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&cut_inner[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLubricateU::write_restart_settings(FILE *fp)
{
fwrite(&mu,sizeof(double),1,fp);
fwrite(&flaglog,sizeof(int),1,fp);
fwrite(&cut_inner_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(&flagHI,sizeof(int),1,fp);
fwrite(&flagVF,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLubricateU::read_restart_settings(FILE *fp)
{
int me = comm->me;
if (me == 0) {
fread(&mu,sizeof(double),1,fp);
fread(&flaglog,sizeof(int),1,fp);
fread(&cut_inner_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(&flagHI,sizeof(int),1,fp);
fread(&flagVF,sizeof(int),1,fp);
}
MPI_Bcast(&mu,1,MPI_DOUBLE,0,world);
MPI_Bcast(&flaglog,1,MPI_INT,0,world);
MPI_Bcast(&cut_inner_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(&flagHI,1,MPI_INT,0,world);
MPI_Bcast(&flagVF,1,MPI_INT,0,world);
}
/*---------------------------------------------------------------------------*/
void PairLubricateU::copy_vec_uo(int inum, double *xcg,
double **v, double **omega)
{
int i,j,ii;
int *ilist;
int itype;
double radi;
double inertia;
double *rmass = atom->rmass;
int *type = atom->type;
ilist = list->ilist;
for (ii=0;ii<inum;ii++) {
i = ilist[ii];
itype = type[i];
radi = atom->radius[i];
inertia = 0.4*rmass[i]*radi*radi;
for (j=0;j<3;j++) {
v[i][j] = xcg[6*ii+j];
omega[i][j] = xcg[6*ii+j+3];
}
}
}
/*---------------------------------------------------------------------------*/
void PairLubricateU::copy_uo_vec(int inum, double **f, double **torque,
double *RU)
{
int i,j,ii;
int *ilist;
ilist = list->ilist;
for (ii=0;ii<inum;ii++) {
i = ilist[ii];
for (j=0;j<3;j++) {
RU[6*ii+j] = f[i][j];
RU[6*ii+j+3] = torque[i][j];
}
}
}
/* ---------------------------------------------------------------------- */
int PairLubricateU::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double **v = atom->v;
double **omega = atom->omega;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
return 6;
}
/* ---------------------------------------------------------------------- */
void PairLubricateU::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
double **v = atom->v;
double **omega = atom->omega;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
double PairLubricateU::dot_vec_vec(int N, double *x, double *y)
{
double dotp=0.0;
for (int i = 0; i < N; i++) dotp += x[i]*y[i];
return dotp;
}
diff --git a/src/GPU/fix_gpu.cpp b/src/GPU/fix_gpu.cpp
index 829a0b2df..776bdd0b6 100644
--- a/src/GPU/fix_gpu.cpp
+++ b/src/GPU/fix_gpu.cpp
@@ -1,264 +1,268 @@
/* ----------------------------------------------------------------------
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 LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG is not yet supported by the GPU package
+#endif
+
#include "string.h"
#include "stdlib.h"
#include "fix_gpu.h"
#include "atom.h"
#include "force.h"
#include "pair.h"
#include "pair_hybrid.h"
#include "pair_hybrid_overlay.h"
#include "respa.h"
#include "input.h"
#include "timer.h"
#include "modify.h"
#include "update.h"
#include "domain.h"
#include "universe.h"
#include "gpu_extra.h"
#include "neighbor.h"
#include "citeme.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
enum{GPU_FORCE, GPU_NEIGH, GPU_HYB_NEIGH};
extern int lmp_init_device(MPI_Comm world, MPI_Comm replica,
const int first_gpu, const int last_gpu,
const int gpu_mode, const double particle_split,
const int nthreads, const int t_per_atom,
const double cell_size, char *opencl_flags);
extern void lmp_clear_device();
extern double lmp_gpu_forces(double **f, double **tor, double *eatom,
double **vatom, double *virial, double &ecoul);
static const char cite_gpu_package[] =
"GPU package (short-range and long-range):\n\n"
"@Article{Brown11,\n"
" author = {W. M. Brown, P. Wang, S. J. Plimpton, A. N. Tharrington},\n"
" title = {Implementing Molecular Dynamics on Hybrid High Performance Computers - Short Range Forces},\n"
" journal = {Comp.~Phys.~Comm.},\n"
" year = 2011,\n"
" volume = 182,\n"
" pages = {898--911}\n"
"}\n\n"
"@Article{Brown12,\n"
" author = {W. M. Brown, A. Kohlmeyer, S. J. Plimpton, A. N. Tharrington},\n"
" title = {Implementing Molecular Dynamics on Hybrid High Performance Computers - Particle-Particle Particle-Mesh},\n"
" journal = {Comp.~Phys.~Comm.},\n"
" year = 2012,\n"
" volume = 183,\n"
" pages = {449--459}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
FixGPU::FixGPU(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_gpu_package);
if (lmp->cuda)
error->all(FLERR,"Cannot use fix GPU with USER-CUDA mode enabled");
if (narg < 7) error->all(FLERR,"Illegal fix GPU command");
if (strcmp(arg[1],"all") != 0) error->all(FLERR,"Illegal fix GPU command");
int first_gpu, last_gpu;
if (strcmp(arg[3],"force") == 0)
_gpu_mode = GPU_FORCE;
else if (strcmp(arg[3],"force/neigh") == 0) {
_gpu_mode = GPU_NEIGH;
if (domain->triclinic)
error->all(FLERR,"Cannot use force/neigh with triclinic box");
} else if (strcmp(arg[3],"force/hybrid_neigh") == 0) {
_gpu_mode = GPU_HYB_NEIGH;
if (domain->triclinic)
error->all(FLERR,
"Cannot use force/hybrid_neigh with triclinic box");
} else
error->all(FLERR,"Illegal fix GPU command");
first_gpu = force->inumeric(FLERR,arg[4]);
last_gpu = force->inumeric(FLERR,arg[5]);
_particle_split = force->numeric(FLERR,arg[6]);
if (_particle_split==0 || _particle_split>1)
error->all(FLERR,"Illegal fix GPU command");
int nthreads = 1;
int threads_per_atom = -1;
double cell_size = -1;
int iarg = 7;
char *opencl_flags = NULL;
while (iarg < narg) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix GPU command");
if (strcmp(arg[iarg],"threads_per_atom") == 0)
threads_per_atom = force->inumeric(FLERR,arg[iarg+1]);
else if (strcmp(arg[iarg],"nthreads") == 0)
nthreads = force->inumeric(FLERR,arg[iarg+1]);
else if (strcmp(arg[iarg],"cellsize") == 0)
cell_size = force->numeric(FLERR,arg[iarg+1]);
else if (strcmp(arg[iarg],"device") == 0)
opencl_flags = arg[iarg+1];
else
error->all(FLERR,"Illegal fix GPU command");
iarg += 2;
}
if (nthreads < 1)
error->all(FLERR,"Illegal fix GPU command");
#ifndef _OPENMP
if (nthreads > 1)
error->all(FLERR,"No OpenMP support compiled in");
#endif
int gpu_flag = lmp_init_device(universe->uworld, world, first_gpu, last_gpu,
_gpu_mode, _particle_split, nthreads,
threads_per_atom, cell_size, opencl_flags);
GPU_EXTRA::check_flag(gpu_flag,error,world);
}
/* ---------------------------------------------------------------------- */
FixGPU::~FixGPU()
{
lmp_clear_device();
}
/* ---------------------------------------------------------------------- */
int FixGPU::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= MIN_POST_FORCE;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixGPU::init()
{
// hybrid cannot be used with force/neigh option
if (_gpu_mode == GPU_NEIGH || _gpu_mode == GPU_HYB_NEIGH)
if (force->pair_match("hybrid",1) != NULL ||
force->pair_match("hybrid/overlay",1) != NULL)
error->all(FLERR,"Cannot use pair hybrid with GPU neighbor list builds");
if (_particle_split < 0)
if (force->pair_match("hybrid",1) != NULL ||
force->pair_match("hybrid/overlay",1) != NULL)
error->all(FLERR,"GPU 'split' must be positive for hybrid pair styles");
// Make sure fdotr virial is not accumulated multiple times
if (force->pair_match("hybrid",1) != NULL) {
PairHybrid *hybrid = (PairHybrid *) force->pair;
for (int i = 0; i < hybrid->nstyles; i++)
if (strstr(hybrid->keywords[i],"/gpu")==NULL)
force->pair->no_virial_fdotr_compute = 1;
} else if (force->pair_match("hybrid/overlay",1) != NULL) {
PairHybridOverlay *hybrid = (PairHybridOverlay *) force->pair;
for (int i = 0; i < hybrid->nstyles; i++)
if (strstr(hybrid->keywords[i],"/gpu")==NULL)
force->pair->no_virial_fdotr_compute = 1;
}
// r-RESPA support
if (strstr(update->integrate_style,"respa"))
_nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixGPU::setup(int vflag)
{
if (_gpu_mode == GPU_NEIGH || _gpu_mode == GPU_HYB_NEIGH)
if (neighbor->exclude_setting()!=0)
error->all(FLERR,
"Cannot use neigh_modify exclude with GPU neighbor builds");
if (strstr(update->integrate_style,"verlet"))
post_force(vflag);
else {
// In setup only, all forces calculated on gpu are put in the outer level
((Respa *) update->integrate)->copy_flevel_f(_nlevels_respa-1);
post_force(vflag);
((Respa *) update->integrate)->copy_f_flevel(_nlevels_respa-1);
}
}
/* ---------------------------------------------------------------------- */
void FixGPU::min_setup(int vflag)
{
post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixGPU::post_force(int vflag)
{
timer->stamp();
double lvirial[6];
for (int i = 0; i < 6; i++) lvirial[i] = 0.0;
double my_eng = lmp_gpu_forces(atom->f, atom->torque, force->pair->eatom,
force->pair->vatom, lvirial,
force->pair->eng_coul);
force->pair->eng_vdwl += my_eng;
force->pair->virial[0] += lvirial[0];
force->pair->virial[1] += lvirial[1];
force->pair->virial[2] += lvirial[2];
force->pair->virial[3] += lvirial[3];
force->pair->virial[4] += lvirial[4];
force->pair->virial[5] += lvirial[5];
if (force->pair->vflag_fdotr) force->pair->virial_fdotr_compute();
timer->stamp(Timer::PAIR);
}
/* ---------------------------------------------------------------------- */
void FixGPU::min_post_force(int vflag)
{
post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixGPU::post_force_respa(int vflag, int ilevel, int iloop)
{
post_force(vflag);
}
/* ---------------------------------------------------------------------- */
double FixGPU::memory_usage()
{
double bytes = 0.0;
// Memory usage currently returned by pair routine
return bytes;
}
diff --git a/src/GRANULAR/fix_pour.cpp b/src/GRANULAR/fix_pour.cpp
index 562edd42c..9a439d87d 100644
--- a/src/GRANULAR/fix_pour.cpp
+++ b/src/GRANULAR/fix_pour.cpp
@@ -1,969 +1,973 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "fix_pour.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "update.h"
#include "comm.h"
#include "molecule.h"
#include "modify.h"
#include "fix_gravity.h"
#include "domain.h"
#include "region.h"
#include "region_block.h"
#include "region_cylinder.h"
#include "random_park.h"
#include "math_extra.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
#define EPSILON 0.001
enum{ATOM,MOLECULE};
enum{ONE,RANGE,POLY};
/* ---------------------------------------------------------------------- */
FixPour::FixPour(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 6) error->all(FLERR,"Illegal fix pour command");
time_depend = 1;
if (!atom->radius_flag || !atom->rmass_flag)
error->all(FLERR,"Fix pour requires atom attributes radius, rmass");
// required args
ninsert = force->inumeric(FLERR,arg[3]);
ntype = force->inumeric(FLERR,arg[4]);
seed = force->inumeric(FLERR,arg[5]);
if (seed <= 0) error->all(FLERR,"Illegal fix pour command");
// read options from end of input line
options(narg-6,&arg[6]);
// error check on type
if (mode == ATOM && (ntype <= 0 || ntype > atom->ntypes))
error->all(FLERR,"Invalid atom type in fix pour command");
// error checks on region and its extent being inside simulation box
if (iregion == -1) error->all(FLERR,"Must specify a region in fix pour");
if (domain->regions[iregion]->bboxflag == 0)
error->all(FLERR,"Fix pour region does not support a bounding box");
if (domain->regions[iregion]->dynamic_check())
error->all(FLERR,"Fix pour region cannot be dynamic");
if (strcmp(domain->regions[iregion]->style,"block") == 0) {
region_style = 1;
xlo = ((RegBlock *) domain->regions[iregion])->xlo;
xhi = ((RegBlock *) domain->regions[iregion])->xhi;
ylo = ((RegBlock *) domain->regions[iregion])->ylo;
yhi = ((RegBlock *) domain->regions[iregion])->yhi;
zlo = ((RegBlock *) domain->regions[iregion])->zlo;
zhi = ((RegBlock *) domain->regions[iregion])->zhi;
if (xlo < domain->boxlo[0] || xhi > domain->boxhi[0] ||
ylo < domain->boxlo[1] || yhi > domain->boxhi[1] ||
zlo < domain->boxlo[2] || zhi > domain->boxhi[2])
error->all(FLERR,"Insertion region extends outside simulation box");
} else if (strcmp(domain->regions[iregion]->style,"cylinder") == 0) {
region_style = 2;
char axis = ((RegCylinder *) domain->regions[iregion])->axis;
xc = ((RegCylinder *) domain->regions[iregion])->c1;
yc = ((RegCylinder *) domain->regions[iregion])->c2;
rc = ((RegCylinder *) domain->regions[iregion])->radius;
zlo = ((RegCylinder *) domain->regions[iregion])->lo;
zhi = ((RegCylinder *) domain->regions[iregion])->hi;
if (axis != 'z')
error->all(FLERR,"Must use a z-axis cylinder with fix pour");
if (xc-rc < domain->boxlo[0] || xc+rc > domain->boxhi[0] ||
yc-rc < domain->boxlo[1] || yc+rc > domain->boxhi[1] ||
zlo < domain->boxlo[2] || zhi > domain->boxhi[2])
error->all(FLERR,"Insertion region extends outside simulation box");
} else error->all(FLERR,"Must use a block or cylinder region with fix pour");
if (region_style == 2 && domain->dimension == 2)
error->all(FLERR,
"Must use a block region with fix pour for 2d simulations");
// error check and further setup for mode = MOLECULE
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use fix_pour unless atoms have IDs");
if (mode == MOLECULE) {
if (onemol->xflag == 0)
error->all(FLERR,"Fix pour molecule must have coordinates");
if (onemol->typeflag == 0)
error->all(FLERR,"Fix pour molecule must have atom types");
if (ntype+onemol->maxtype <= 0 || ntype+onemol->maxtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix pour mol command");
// fix pour uses geoemetric center of molecule for insertion
onemol->compute_center();
}
if (rigidflag && mode == ATOM)
error->all(FLERR,"Cannot use fix pour rigid and not molecule");
if (shakeflag && mode == ATOM)
error->all(FLERR,"Cannot use fix pour shake and not molecule");
if (rigidflag && shakeflag)
error->all(FLERR,"Cannot use fix pour rigid and shake");
// setup of coords and imageflags array
if (mode == ATOM) natom = 1;
else natom = onemol->natoms;
memory->create(coords,natom,4,"pour:coords");
memory->create(imageflags,natom,"pour:imageflags");
// find current max atom and molecule IDs if necessary
if (idnext) find_maxid();
// random number generator, same for all procs
random = new RanPark(lmp,seed);
// allgather arrays
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
recvcounts = new int[nprocs];
displs = new int[nprocs];
// grav = gravity in distance/time^2 units
// assume grav = -magnitude at this point, enforce in init()
int ifix;
for (ifix = 0; ifix < modify->nfix; ifix++) {
if (strcmp(modify->fix[ifix]->style,"gravity") == 0) break;
if (strcmp(modify->fix[ifix]->style,"gravity/omp") == 0) break;
}
if (ifix == modify->nfix)
error->all(FLERR,"No fix gravity defined for fix pour");
grav = - ((FixGravity *) modify->fix[ifix])->magnitude * force->ftm2v;
// nfreq = timesteps between insertions
// should be time for a particle to fall from top of insertion region
// to bottom, taking into account that the region may be moving
// set these 2 eqs equal to each other, solve for smallest positive t
// x = zhi + vz*t + 1/2 grav t^2
// x = zlo + rate*t
// gives t = [-(vz-rate) - sqrt((vz-rate)^2 - 2*grav*(zhi-zlo))] / grav
// where zhi-zlo > 0, grav < 0, and vz & rate can be either > 0 or < 0
double v_relative,delta;
if (domain->dimension == 3) {
v_relative = vz - rate;
delta = zhi - zlo;
} else {
v_relative = vy - rate;
delta = yhi - ylo;
}
double t =
(-v_relative - sqrt(v_relative*v_relative - 2.0*grav*delta)) / grav;
nfreq = static_cast<int> (t/update->dt + 0.5);
// 1st insertion on next timestep
force_reneighbor = 1;
next_reneighbor = update->ntimestep + 1;
nfirst = next_reneighbor;
ninserted = 0;
// nper = # to insert each time
// depends on specified volume fraction
// volume = volume of insertion region
// volume_one = volume of inserted particle (with max possible radius)
// in 3d, insure dy >= 1, for quasi-2d simulations
double volume,volume_one;
if (domain->dimension == 3) {
if (region_style == 1) {
double dy = yhi - ylo;
if (dy < 1.0) dy = 1.0;
volume = (xhi-xlo) * dy * (zhi-zlo);
} else volume = MY_PI*rc*rc * (zhi-zlo);
if (mode == MOLECULE) {
double molradius = onemol->molradius;
volume_one = 4.0/3.0 * MY_PI * molradius*molradius*molradius;
} else if (dstyle == ONE || dstyle == RANGE) {
volume_one = 4.0/3.0 * MY_PI * radius_max*radius_max*radius_max;
} else if (dstyle == POLY) {
volume_one = 0.0;
for (int i = 0; i < npoly; i++)
volume_one += (4.0/3.0 * MY_PI *
radius_poly[i]*radius_poly[i]*radius_poly[i]) * frac_poly[i];
}
} else {
volume = (xhi-xlo) * (yhi-ylo);
if (mode == MOLECULE) {
double molradius = onemol->molradius;
volume_one = MY_PI * molradius*molradius;
} else if (dstyle == ONE || dstyle == RANGE) {
volume_one = MY_PI * radius_max*radius_max;
} else if (dstyle == POLY) {
volume_one = 0.0;
for (int i = 0; i < npoly; i++)
volume_one += (MY_PI * radius_poly[i]*radius_poly[i]) * frac_poly[i];
}
}
nper = static_cast<int> (volfrac*volume/volume_one);
int nfinal = update->ntimestep + 1 + (ninsert-1)/nper * nfreq;
// print stats
if (me == 0) {
if (screen)
fprintf(screen,
"Particle insertion: %d every %d steps, %d by step %d\n",
nper,nfreq,ninsert,nfinal);
if (logfile)
fprintf(logfile,
"Particle insertion: %d every %d steps, %d by step %d\n",
nper,nfreq,ninsert,nfinal);
}
}
/* ---------------------------------------------------------------------- */
FixPour::~FixPour()
{
delete random;
delete [] idrigid;
delete [] idshake;
delete [] radius_poly;
delete [] frac_poly;
memory->destroy(coords);
memory->destroy(imageflags);
delete [] recvcounts;
delete [] displs;
}
/* ---------------------------------------------------------------------- */
int FixPour::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixPour::init()
{
if (domain->triclinic)
error->all(FLERR,"Cannot use fix pour with triclinic box");
// insure gravity fix exists
// for 3d must point in -z, for 2d must point in -y
// else insertion cannot work
int ifix;
for (ifix = 0; ifix < modify->nfix; ifix++) {
if (strcmp(modify->fix[ifix]->style,"gravity") == 0) break;
if (strcmp(modify->fix[ifix]->style,"gravity/omp") == 0) break;
}
if (ifix == modify->nfix)
error->all(FLERR,"No fix gravity defined for fix pour");
double xgrav = ((FixGravity *) modify->fix[ifix])->xgrav;
double ygrav = ((FixGravity *) modify->fix[ifix])->ygrav;
double zgrav = ((FixGravity *) modify->fix[ifix])->zgrav;
if (domain->dimension == 3) {
if (fabs(xgrav) > EPSILON || fabs(ygrav) > EPSILON ||
fabs(zgrav+1.0) > EPSILON)
error->all(FLERR,"Gravity must point in -z to use with fix pour in 3d");
} else {
if (fabs(xgrav) > EPSILON || fabs(ygrav+1.0) > EPSILON ||
fabs(zgrav) > EPSILON)
error->all(FLERR,"Gravity must point in -y to use with fix pour in 2d");
}
double gnew = - ((FixGravity *) modify->fix[ifix])->magnitude * force->ftm2v;
if (gnew != grav)
error->all(FLERR,"Gravity changed since fix pour was created");
// if rigidflag defined, check for rigid/small fix
// its molecule template must be same as this one
fixrigid = NULL;
if (rigidflag) {
int ifix = modify->find_fix(idrigid);
if (ifix < 0) error->all(FLERR,"Fix pour rigid fix does not exist");
fixrigid = modify->fix[ifix];
int tmp;
if (onemol != (Molecule *) fixrigid->extract("onemol",tmp))
error->all(FLERR,
"Fix pour and fix rigid/small not using same molecule ID");
}
// if shakeflag defined, check for SHAKE fix
// its molecule template must be same as this one
fixshake = NULL;
if (shakeflag) {
int ifix = modify->find_fix(idshake);
if (ifix < 0) error->all(FLERR,"Fix pour shake fix does not exist");
fixshake = modify->fix[ifix];
int tmp;
if (onemol != (Molecule *) fixshake->extract("onemol",tmp))
error->all(FLERR,"Fix pour and fix shake not using same molecule ID");
}
}
/* ----------------------------------------------------------------------
perform particle insertion
------------------------------------------------------------------------- */
void FixPour::pre_exchange()
{
int i,j,m,flag,nlocalprev;
double r[3],rotmat[3][3],quat[4],vnew[3];
double *newcoord;
// just return if should not be called on this timestep
if (next_reneighbor != update->ntimestep) return;
// find current max atom and molecule IDs if necessary
if (!idnext) find_maxid();
// nnew = # of particles (atoms or molecules) to insert this timestep
int nnew = nper;
if (ninserted + nnew > ninsert) nnew = ninsert - ninserted;
// lo/hi current = z (or y) bounds of insertion region this timestep
int dimension = domain->dimension;
if (dimension == 3) {
lo_current = zlo + (update->ntimestep - nfirst) * update->dt * rate;
hi_current = zhi + (update->ntimestep - nfirst) * update->dt * rate;
} else {
lo_current = ylo + (update->ntimestep - nfirst) * update->dt * rate;
hi_current = yhi + (update->ntimestep - nfirst) * update->dt * rate;
}
// ncount = # of my atoms that overlap the insertion region
// nprevious = total of ncount across all procs
int ncount = 0;
for (i = 0; i < atom->nlocal; i++)
if (overlap(i)) ncount++;
int nprevious;
MPI_Allreduce(&ncount,&nprevious,1,MPI_INT,MPI_SUM,world);
// xmine is for my atoms
// xnear is for atoms from all procs + atoms to be inserted
double **xmine,**xnear;
memory->create(xmine,ncount,4,"fix_pour:xmine");
memory->create(xnear,nprevious+nnew*natom,4,"fix_pour:xnear");
int nnear = nprevious;
// setup for allgatherv
int n = 4*ncount;
MPI_Allgather(&n,1,MPI_INT,recvcounts,1,MPI_INT,world);
displs[0] = 0;
for (int iproc = 1; iproc < nprocs; iproc++)
displs[iproc] = displs[iproc-1] + recvcounts[iproc-1];
// load up xmine array
double **x = atom->x;
double *radius = atom->radius;
ncount = 0;
for (i = 0; i < atom->nlocal; i++)
if (overlap(i)) {
xmine[ncount][0] = x[i][0];
xmine[ncount][1] = x[i][1];
xmine[ncount][2] = x[i][2];
xmine[ncount][3] = radius[i];
ncount++;
}
// perform allgatherv to acquire list of nearby particles on all procs
double *ptr = NULL;
if (ncount) ptr = xmine[0];
MPI_Allgatherv(ptr,4*ncount,MPI_DOUBLE,
xnear[0],recvcounts,displs,MPI_DOUBLE,world);
// insert new particles into xnear list, one by one
// check against all nearby atoms and previously inserted ones
// if there is an overlap then try again at same z (3d) or y (2d) coord
// else insert by adding to xnear list
// max = maximum # of insertion attempts for all particles
// h = height, biased to give uniform distribution in time of insertion
// for MOLECULE mode:
// coords = coords of all atoms in particle
// perform random rotation around center pt
// apply PBC so final coords are inside box
// store image flag modified due to PBC
int success;
double radtmp,delx,dely,delz,rsq,radsum,rn,h;
double coord[3],xcm[3];
int nfix = modify->nfix;
Fix **fix = modify->fix;
AtomVec *avec = atom->avec;
double denstmp,vxtmp,vytmp,vztmp;
double *sublo = domain->sublo;
double *subhi = domain->subhi;
int attempt = 0;
int maxiter = nnew * maxattempt;
int ntotal = nprevious + nnew*natom;
while (nnear < ntotal) {
rn = random->uniform();
h = hi_current - rn*rn * (hi_current-lo_current);
if (mode == ATOM) radtmp = radius_sample();
success = 0;
while (attempt < maxiter) {
attempt++;
xyz_random(h,coord);
if (mode == ATOM) {
coords[0][0] = coord[0];
coords[0][1] = coord[1];
coords[0][2] = coord[2];
coords[0][3] = radtmp;
imageflags[0] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
} else {
if (dimension == 3) {
r[0] = random->uniform() - 0.5;
r[1] = random->uniform() - 0.5;
r[2] = random->uniform() - 0.5;
} else {
r[0] = r[1] = 0.0;
r[2] = 1.0;
}
double theta = random->uniform() * MY_2PI;
MathExtra::norm3(r);
MathExtra::axisangle_to_quat(r,theta,quat);
MathExtra::quat_to_mat(quat,rotmat);
for (i = 0; i < natom; i++) {
MathExtra::matvec(rotmat,onemol->dx[i],coords[i]);
coords[i][0] += coord[0];
coords[i][1] += coord[1];
coords[i][2] += coord[2];
// coords[3] = particle radius
// default to 0.5, if radii not defined in Molecule
// same as atom->avec->create_atom(), invoked below
if (onemol->radiusflag) coords[i][3] = onemol->radius[i];
else coords[i][3] = 0.5;
imageflags[i] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
domain->remap(coords[i],imageflags[i]);
}
}
// if any pair of atoms overlap, try again
// use minimum_image() to account for PBC
for (m = 0; m < natom; m++) {
for (i = 0; i < nnear; i++) {
delx = coords[m][0] - xnear[i][0];
dely = coords[m][1] - xnear[i][1];
delz = coords[m][2] - xnear[i][2];
domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
radsum = coords[m][3] + xnear[i][3];
if (rsq <= radsum*radsum) break;
}
if (i < nnear) break;
}
if (m == natom) {
success = 1;
break;
}
}
if (!success) break;
// proceed with insertion
nlocalprev = atom->nlocal;
// add all atoms in particle to xnear
for (m = 0; m < natom; m++) {
xnear[nnear][0] = coords[m][0];
xnear[nnear][1] = coords[m][1];
xnear[nnear][2] = coords[m][2];
xnear[nnear][3] = coords[m][3];
nnear++;
}
// choose random velocity for new particle
// used for every atom in molecule
// z velocity set to what velocity would be if particle
// had fallen from top of insertion region
// this gives continuous stream of atoms
// solution for v from these 2 eqs, after eliminate t:
// v = vz + grav*t
// coord[2] = hi_current + vz*t + 1/2 grav t^2
if (dimension == 3) {
vnew[0] = vxlo + random->uniform() * (vxhi-vxlo);
vnew[1] = vylo + random->uniform() * (vyhi-vylo);
vnew[2] = -sqrt(vz*vz + 2.0*grav*(coord[2]-hi_current));
} else {
vnew[0] = vxlo + random->uniform() * (vxhi-vxlo);
vnew[1] = -sqrt(vy*vy + 2.0*grav*(coord[1]-hi_current));
vnew[2] = 0.0;
}
// check if new atoms are in my sub-box or above it if I am highest proc
// if so, add atom to my list via create_atom()
// initialize additional info about the atoms
// set group mask to "all" plus fix group
for (m = 0; m < natom; m++) {
if (mode == ATOM)
denstmp = density_lo + random->uniform() * (density_hi-density_lo);
newcoord = coords[m];
flag = 0;
if (newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1] &&
newcoord[2] >= sublo[2] && newcoord[2] < subhi[2]) flag = 1;
else if (dimension == 3 && newcoord[2] >= domain->boxhi[2] &&
comm->myloc[2] == comm->procgrid[2]-1 &&
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1]) flag = 1;
else if (dimension == 2 && newcoord[1] >= domain->boxhi[1] &&
comm->myloc[1] == comm->procgrid[1]-1 &&
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0]) flag = 1;
if (flag) {
if (mode == ATOM) atom->avec->create_atom(ntype,coords[m]);
else atom->avec->create_atom(ntype+onemol->type[m],coords[m]);
int n = atom->nlocal - 1;
atom->tag[n] = maxtag_all + m+1;
if (mode == MOLECULE && atom->molecule_flag)
atom->molecule[n] = maxmol_all+1;
atom->mask[n] = 1 | groupbit;
atom->image[n] = imageflags[m];
atom->v[n][0] = vnew[0];
atom->v[n][1] = vnew[1];
atom->v[n][2] = vnew[2];
if (mode == ATOM) {
radtmp = newcoord[3];
atom->radius[n] = radtmp;
atom->rmass[n] = 4.0*MY_PI/3.0 * radtmp*radtmp*radtmp * denstmp;
} else atom->add_molecule_atom(onemol,m,n,maxtag_all);
for (j = 0; j < nfix; j++)
if (fix[j]->create_attribute) fix[j]->set_arrays(n);
}
}
// FixRigidSmall::set_molecule stores rigid body attributes
// coord is new position of geometric center of mol, not COM
// FixShake::set_molecule stores shake info for molecule
if (rigidflag)
fixrigid->set_molecule(nlocalprev,maxtag_all,coord,vnew,quat);
else if (shakeflag)
fixshake->set_molecule(nlocalprev,maxtag_all,coord,vnew,quat);
maxtag_all += natom;
if (mode == MOLECULE && atom->molecule_flag) maxmol_all++;
}
// warn if not successful with all insertions b/c too many attempts
int ninserted_atoms = nnear - nprevious;
int ninserted_mols = ninserted_atoms / natom;
ninserted += ninserted_mols;
if (ninserted_mols < nnew && me == 0)
error->warning(FLERR,"Less insertions than requested",0);
// reset global natoms,nbonds,etc
// increment maxtag_all and maxmol_all if necessary
// if global map exists, reset it now instead of waiting for comm
// since adding atoms messes up ghosts
if (ninserted_atoms) {
atom->natoms += ninserted_atoms;
+ if (atom->natoms < 0 || atom->natoms > MAXBIGINT)
+ error->all(FLERR,"Too many total atoms");
if (mode == MOLECULE) {
atom->nbonds += onemol->nbonds * ninserted_mols;
atom->nangles += onemol->nangles * ninserted_mols;
atom->ndihedrals += onemol->ndihedrals * ninserted_mols;
atom->nimpropers += onemol->nimpropers * ninserted_mols;
}
+ if (maxtag_all >= MAXTAGINT)
+ error->all(FLERR,"New atom IDs exceed maximum allowed ID");
if (atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
}
// free local memory
memory->destroy(xmine);
memory->destroy(xnear);
// next timestep to insert
if (ninserted < ninsert) next_reneighbor += nfreq;
else next_reneighbor = 0;
}
/* ----------------------------------------------------------------------
maxtag_all = current max atom ID for all atoms
maxmol_all = current max molecule ID for all atoms
------------------------------------------------------------------------- */
void FixPour::find_maxid()
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
- int max = 0;
+ tagint max = 0;
for (int i = 0; i < nlocal; i++) max = MAX(max,tag[i]);
- MPI_Allreduce(&max,&maxtag_all,1,MPI_INT,MPI_MAX,world);
+ MPI_Allreduce(&max,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world);
if (mode == MOLECULE && molecule) {
max = 0;
for (int i = 0; i < nlocal; i++) max = MAX(max,molecule[i]);
MPI_Allreduce(&max,&maxmol_all,1,MPI_INT,MPI_MAX,world);
}
}
/* ----------------------------------------------------------------------
check if particle i could overlap with a particle inserted into region
return 1 if yes, 0 if no
for ATOM mode, use delta with maximum size for inserted atoms
for MOLECULE mode, use delta with radius of inserted molecules
account for PBC in overlap decision via outside() and minimum_image()
------------------------------------------------------------------------- */
int FixPour::overlap(int i)
{
double delta;
if (mode == ATOM) delta = atom->radius[i] + radius_max;
else delta = atom->radius[i] + onemol->molradius;
double *boxlo = domain->boxlo;
double *boxhi = domain->boxhi;
double *prd = domain->prd;
int *periodicity = domain->periodicity;
double *x = atom->x[i];
if (domain->dimension == 3) {
if (region_style == 1) {
if (outside(0,x[0],xlo-delta,xhi+delta)) return 0;
if (outside(1,x[1],ylo-delta,yhi+delta)) return 0;
if (outside(2,x[2],lo_current-delta,hi_current+delta)) return 0;
} else {
double delx = x[0] - xc;
double dely = x[1] - yc;
double delz = 0.0;
domain->minimum_image(delx,dely,delz);
double rsq = delx*delx + dely*dely;
double r = rc + delta;
if (rsq > r*r) return 0;
if (outside(2,x[2],lo_current-delta,hi_current+delta)) return 0;
}
} else {
if (outside(0,x[0],xlo-delta,xhi+delta)) return 0;
if (outside(1,x[1],lo_current-delta,hi_current+delta)) return 0;
}
return 1;
}
/* ----------------------------------------------------------------------
check if value is inside/outside lo/hi bounds in dimension
account for PBC if needed
return 1 if value is outside, 0 if inside
------------------------------------------------------------------------- */
int FixPour::outside(int dim, double value, double lo, double hi)
{
double boxlo = domain->boxlo[dim];
double boxhi = domain->boxhi[dim];
if (domain->periodicity[dim]) {
if (lo < boxlo && hi > boxhi) {
return 0;
} else if (lo < boxlo) {
if (value > hi && value < lo + domain->prd[dim]) return 1;
} else if (hi > boxhi) {
if (value > hi - domain->prd[dim] && value < lo) return 1;
} else {
if (value < lo || value > hi) return 1;
}
}
if (value < lo || value > hi) return 1;
return 0;
}
/* ---------------------------------------------------------------------- */
void FixPour::xyz_random(double h, double *coord)
{
if (domain->dimension == 3) {
if (region_style == 1) {
coord[0] = xlo + random->uniform() * (xhi-xlo);
coord[1] = ylo + random->uniform() * (yhi-ylo);
coord[2] = h;
} else {
double r1,r2;
while (1) {
r1 = random->uniform() - 0.5;
r2 = random->uniform() - 0.5;
if (r1*r1 + r2*r2 < 0.25) break;
}
coord[0] = xc + 2.0*r1*rc;
coord[1] = yc + 2.0*r2*rc;
coord[2] = h;
}
} else {
coord[0] = xlo + random->uniform() * (xhi-xlo);
coord[1] = h;
coord[2] = 0.0;
}
}
/* ---------------------------------------------------------------------- */
double FixPour::radius_sample()
{
if (dstyle == ONE) return radius_one;
if (dstyle == RANGE) return radius_lo +
random->uniform()*(radius_hi-radius_lo);
double value = random->uniform();
int i = 0;
double sum = 0.0;
while (sum < value) {
sum += frac_poly[i];
i++;
}
return radius_poly[i-1];
}
/* ----------------------------------------------------------------------
parse optional parameters at end of input line
------------------------------------------------------------------------- */
void FixPour::options(int narg, char **arg)
{
// defaults
iregion = -1;
mode = ATOM;
rigidflag = 0;
idrigid = NULL;
shakeflag = 0;
idshake = NULL;
idnext = 0;
dstyle = ONE;
radius_max = radius_one = 0.5;
radius_poly = frac_poly = NULL;
density_lo = density_hi = 1.0;
volfrac = 0.25;
maxattempt = 50;
rate = 0.0;
vxlo = vxhi = vylo = vyhi = vy = vz = 0.0;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"region") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
iregion = domain->find_region(arg[iarg+1]);
if (iregion == -1) error->all(FLERR,"Fix pour region ID does not exist");
iarg += 2;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
int imol = atom->find_molecule(arg[iarg+1]);
if (imol == -1)
error->all(FLERR,"Molecule ID for fix pour does not exist");
mode = MOLECULE;
onemol = atom->molecules[imol];
iarg += 2;
} else if (strcmp(arg[iarg],"rigid") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
int n = strlen(arg[iarg+1]) + 1;
delete [] idrigid;
idrigid = new char[n];
strcpy(idrigid,arg[iarg+1]);
rigidflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"shake") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
int n = strlen(arg[iarg+1]) + 1;
delete [] idshake;
idshake = new char[n];
strcpy(idshake,arg[iarg+1]);
shakeflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"id") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
if (strcmp(arg[iarg+1],"max") == 0) idnext = 0;
else if (strcmp(arg[iarg+1],"next") == 0) idnext = 1;
else error->all(FLERR,"Illegal fix pour command");
iarg += 2;
} else if (strcmp(arg[iarg],"diam") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
if (strcmp(arg[iarg+1],"one") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix pour command");
dstyle = ONE;
radius_one = 0.5 * force->numeric(FLERR,arg[iarg+2]);
radius_max = radius_one;
iarg += 3;
} else if (strcmp(arg[iarg+1],"range") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal fix pour command");
dstyle = RANGE;
radius_lo = 0.5 * force->numeric(FLERR,arg[iarg+2]);
radius_hi = 0.5 * force->numeric(FLERR,arg[iarg+3]);
radius_max = radius_hi;
iarg += 4;
} else if (strcmp(arg[iarg+1],"poly") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix pour command");
dstyle = POLY;
npoly = force->inumeric(FLERR,arg[iarg+2]);
if (npoly <= 0) error->all(FLERR,"Illegal fix pour command");
if (iarg+3 + 2*npoly > narg)
error->all(FLERR,"Illegal fix pour command");
radius_poly = new double[npoly];
frac_poly = new double[npoly];
iarg += 3;
radius_max = 0.0;
for (int i = 0; i < npoly; i++) {
radius_poly[i] = 0.5 * force->numeric(FLERR,arg[iarg++]);
frac_poly[i] = force->numeric(FLERR,arg[iarg++]);
if (radius_poly[i] <= 0.0 || frac_poly[i] < 0.0)
error->all(FLERR,"Illegal fix pour command");
radius_max = MAX(radius_max,radius_poly[i]);
}
double sum = 0.0;
for (int i = 0; i < npoly; i++) sum += frac_poly[i];
if (sum != 1.0)
error->all(FLERR,"Fix pour polydisperse fractions do not sum to 1.0");
} else error->all(FLERR,"Illegal fix pour command");
} else if (strcmp(arg[iarg],"dens") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix pour command");
density_lo = force->numeric(FLERR,arg[iarg+1]);
density_hi = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"vol") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix pour command");
volfrac = force->numeric(FLERR,arg[iarg+1]);
maxattempt = force->inumeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"rate") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix pour command");
rate = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"vel") == 0) {
if (domain->dimension == 3) {
if (iarg+6 > narg) error->all(FLERR,"Illegal fix pour command");
vxlo = force->numeric(FLERR,arg[iarg+1]);
vxhi = force->numeric(FLERR,arg[iarg+2]);
vylo = force->numeric(FLERR,arg[iarg+3]);
vyhi = force->numeric(FLERR,arg[iarg+4]);
vz = force->numeric(FLERR,arg[iarg+5]);
iarg += 6;
} else {
if (iarg+4 > narg) error->all(FLERR,"Illegal fix pour command");
vxlo = force->numeric(FLERR,arg[iarg+1]);
vxhi = force->numeric(FLERR,arg[iarg+2]);
vy = force->numeric(FLERR,arg[iarg+3]);
vz = 0.0;
iarg += 4;
}
} else error->all(FLERR,"Illegal fix pour command");
}
}
/* ---------------------------------------------------------------------- */
void FixPour::reset_dt()
{
error->all(FLERR,"Cannot change timestep with fix pour");
}
/* ----------------------------------------------------------------------
extract particle radius for atom type = itype
------------------------------------------------------------------------- */
void *FixPour::extract(const char *str, int &itype)
{
if (strcmp(str,"radius") == 0) {
if (mode == ATOM) {
if (itype == ntype) oneradius = radius_max;
else oneradius = 0.0;
} else {
double *radius = onemol->radius;
int *type = onemol->type;
int natoms = onemol->natoms;
// check radii of matching types in Molecule
// default to 0.5, if radii not defined in Molecule
// same as atom->avec->create_atom(), invoked in pre_exchange()
oneradius = 0.0;
for (int i = 0; i < natoms; i++)
if (type[i] == itype-ntype) {
if (radius) oneradius = MAX(oneradius,radius[i]);
else oneradius = 0.5;
}
}
itype = 0;
return &oneradius;
}
return NULL;
}
diff --git a/src/GRANULAR/fix_pour.h b/src/GRANULAR/fix_pour.h
index c258315e2..7f613c2b1 100644
--- a/src/GRANULAR/fix_pour.h
+++ b/src/GRANULAR/fix_pour.h
@@ -1,163 +1,164 @@
/* -*- 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 FIX_CLASS
FixStyle(pour,FixPour)
#else
#ifndef LMP_FIX_POUR_H
#define LMP_FIX_POUR_H
#include "fix.h"
namespace LAMMPS_NS {
class FixPour : public Fix {
public:
FixPour(class LAMMPS *, int, char **);
~FixPour();
int setmask();
void init();
void pre_exchange();
void reset_dt();
void *extract(const char *, int &);
private:
int ninsert,ntype,seed;
int iregion,mode,idnext,dstyle,npoly,rigidflag,shakeflag;
double radius_one,radius_max;
double radius_lo,radius_hi;
double *radius_poly,*frac_poly;
double density_lo,density_hi;
double volfrac;
int maxattempt;
int region_style;
double rate;
double vxlo,vxhi,vylo,vyhi,vy,vz;
double xlo,xhi,ylo,yhi,zlo,zhi;
double xc,yc,rc;
double grav;
char *idrigid,*idshake;
class Molecule *onemol;
int natom;
double **coords;
imageint *imageflags;
class Fix *fixrigid,*fixshake;
double oneradius;
int me,nprocs;
int *recvcounts,*displs;
int nfreq,nfirst,ninserted,nper;
double lo_current,hi_current;
- int maxtag_all,maxmol_all;
+ tagint maxtag_all;
+ int maxmol_all;
class RanPark *random,*random2;
void find_maxid();
int overlap(int);
int outside(int, double, double, double);
void xyz_random(double, double *);
double radius_sample();
void options(int, char **);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Fix pour requires atom attributes radius, rmass
The atom style defined does not have these attributes.
E: Fix pour region ID does not exist
Self-explanatory.
E: Fix pour polydisperse fractions do not sum to 1.0
UNDOCUMENTED
E: Must specify a region in fix pour
The region keyword must be specified with this fix.
E: Fix pour region does not support a bounding box
Not all regions represent bounded volumes. You cannot use
such a region with the fix pour command.
E: Fix pour region cannot be dynamic
Only static regions can be used with fix pour.
E: Insertion region extends outside simulation box
Region specified with fix pour command extends outside the global
simulation box.
E: Must use a z-axis cylinder with fix pour
The axis of the cylinder region used with the fix pour command must
be oriented along the z dimension.
E: Must use a block or cylinder region with fix pour
Self-explanatory.
E: Must use a block region with fix pour for 2d simulations
Self-explanatory.
E: No fix gravity defined for fix pour
Cannot add poured particles without gravity to move them.
E: Cannot use fix pour with triclinic box
This feature is not yet supported.
E: Gravity must point in -z to use with fix pour in 3d
Gravity must be pointing "down" in a 3d box, i.e. theta = 180.0.
E: Gravity must point in -y to use with fix pour in 2d
Gravity must be pointing "down" in a 2d box.
E: Gravity changed since fix pour was created
Gravity must be static and not dynamic for use with fix pour.
W: Less insertions than requested
Less atom insertions occurred on this timestep due to the fix pour
command than were scheduled. This is probably because there were too
many overlaps detected.
E: Cannot change timestep with fix pour
This fix pre-computes some values based on the timestep, so it cannot
be changed during a simulation run.
*/
diff --git a/src/KSPACE/pair_lj_cut_tip4p_long.cpp b/src/KSPACE/pair_lj_cut_tip4p_long.cpp
index a6881c86f..05aa14e2c 100644
--- a/src/KSPACE/pair_lj_cut_tip4p_long.cpp
+++ b/src/KSPACE/pair_lj_cut_tip4p_long.cpp
@@ -1,602 +1,603 @@
/* ----------------------------------------------------------------------
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: Amalie Frischknecht and Ahmed Ismail (SNL)
simpler force assignment added by Rolf Isele-Holder (Aachen University)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_lj_cut_tip4p_long.h"
#include "angle.h"
#include "atom.h"
#include "bond.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "kspace.h"
#include "update.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
/* ---------------------------------------------------------------------- */
PairLJCutTIP4PLong::PairLJCutTIP4PLong(LAMMPS *lmp) :
PairLJCutCoulLong(lmp)
{
tip4pflag = 1;
single_enable = 0;
respa_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;
}
/* ---------------------------------------------------------------------- */
PairLJCutTIP4PLong::~PairLJCutTIP4PLong()
{
memory->destroy(hneigh);
memory->destroy(newsite);
}
/* ---------------------------------------------------------------------- */
void PairLJCutTIP4PLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable,key;
int n,vlist[6];
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double fraction,table;
double delxOM, delyOM, delzOM;
double r,r2inv,r6inv,forcecoul,forcelj,cforce;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc,ddotf;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],f1[3],v[6],xH1[3],xH2[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
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_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist) * (cut_coul+2.0*qdist);
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 atom I = water O, set x1 = offset charge site
// else x1 = x of atom I
if (itype == typeO) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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 / rsq;
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;
}
}
cforce = 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 - 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[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) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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) {
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 (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
}
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJCutTIP4PLong::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]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i+1; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJCutTIP4PLong::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style lj/cut/tip4p/long requires atom IDs");
if (!force->newton_pair)
error->all(FLERR,
"Pair style lj/cut/tip4p/long requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,
"Pair style lj/cut/tip4p/long 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");
PairLJCutCoulLong::init_style();
// 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 PairLJCutTIP4PLong::init_one(int i, int j)
{
double cut = PairLJCutCoulLong::init_one(i,j);
// 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/long");
if (i == typeH || j == typeH)
cut_ljsq[j][i] = cut_ljsq[i][j] = 0.0;
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJCutTIP4PLong::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);
fwrite(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJCutTIP4PLong::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);
fread(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),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);
MPI_Bcast(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairLJCutTIP4PLong::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];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
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 *PairLJCutTIP4PLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"qdist") == 0) return (void *) &qdist;
if (strcmp(str,"typeO") == 0) return (void *) &typeO;
if (strcmp(str,"typeH") == 0) return (void *) &typeH;
if (strcmp(str,"typeA") == 0) return (void *) &typeA;
if (strcmp(str,"typeB") == 0) return (void *) &typeB;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
/* ----------------------------------------------------------------------
memory usage of hneigh
------------------------------------------------------------------------- */
double PairLJCutTIP4PLong::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/KSPACE/pair_lj_long_tip4p_long.cpp b/src/KSPACE/pair_lj_long_tip4p_long.cpp
index 31623fc73..04723a27a 100644
--- a/src/KSPACE/pair_lj_long_tip4p_long.cpp
+++ b/src/KSPACE/pair_lj_long_tip4p_long.cpp
@@ -1,1617 +1,1621 @@
/* ----------------------------------------------------------------------
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: Amalie Frischknecht and Ahmed Ismail (SNL)
Rolf Isele-Holder (Aachen University)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_lj_long_tip4p_long.h"
#include "angle.h"
#include "atom.h"
#include "bond.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "kspace.h"
#include "update.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
/* ---------------------------------------------------------------------- */
PairLJLongTIP4PLong::PairLJLongTIP4PLong(LAMMPS *lmp) :
PairLJLongCoulLong(lmp)
{
dispersionflag = tip4pflag = 1;
single_enable = 0;
respa_enable = 1;
nmax = 0;
hneigh = NULL;
newsite = NULL;
// TIP4P cannot compute virial as F dot r
// due to find_M() finding bonded H atoms which are not near O atom
no_virial_fdotr_compute = 1;
}
/* ---------------------------------------------------------------------- */
PairLJLongTIP4PLong::~PairLJLongTIP4PLong()
{
memory->destroy(hneigh);
memory->destroy(newsite);
}
/* ---------------------------------------------------------------------- */
void PairLJLongTIP4PLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
int n,vlist[6];
int key;
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double fraction,table;
double r,r2inv,forcecoul,forcelj,cforce;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3];// f1[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
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_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist)*(cut_coul+2.0*qdist);
int order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int ni;
double *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
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) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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];
offseti = offset[itype];
lj1i = lj1[itype]; lj2i = lj2[itype]; lj3i = lj3[itype]; lj4i = lj4[itype];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
ni = sbmask(j);
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_ljsq[itype][jtype]) { // lj
r2inv = 1.0/rsq;
if (order6) { // long-range lj
if (!ndisptablebits || rsq <= tabinnerdispsq) {
register double rn = r2inv*r2inv*r2inv;
register double x2 = g2*rsq, a2 = 1.0/x2;
x2 = a2*exp(-x2)*lj4i[jtype];
if (ni == 0) {
forcelj =
(rn*=rn)*lj1i[jtype]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq;
if (eflag)
evdwl = rn*lj3i[jtype]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
forcelj = f*(rn *= rn)*lj1i[jtype]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[jtype];
if (eflag)
evdwl = f*rn*lj3i[jtype]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[jtype];
}
}
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) {
forcelj = (rn*=rn)*lj1i[jtype]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[jtype];
if (eflag) evdwl = rn*lj3i[jtype]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[jtype];
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
forcelj = f*(rn *= rn)*lj1i[jtype]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[jtype]+t*lj2i[jtype];
if (eflag) evdwl = f*rn*lj3i[jtype]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[jtype]+t*lj4i[jtype];
}
}
}
else { // cut lj
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) {
forcelj = rn*(rn*lj1i[jtype]-lj2i[jtype]);
if (eflag) evdwl = rn*(rn*lj3i[jtype]-lj4i[jtype])-offseti[jtype];
}
else { // special case
register double f = special_lj[ni];
forcelj = f*rn*(rn*lj1i[jtype]-lj2i[jtype]);
if (eflag)
evdwl = f * (rn*(rn*lj3i[jtype]-lj4i[jtype])-offseti[jtype]);
}
}
forcelj *= 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 (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)
// ADDITIONAL REQEUST REQUIRED HERE!!!!!
if (rsq < cut_coulsqplus) {
if (itype == typeO || jtype == typeO) {
if (jtype == typeO) {
if (hneigh[j][0] < 0) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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;
}
// test current rsq against cutoff and compute Coulombic force
if (rsq < cut_coulsq && order1) {
r2inv = 1.0 / rsq;
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;
}
}
cforce = forcecoul * r2inv;
//if (evflag) ev_tally(i,j,nlocal,newton_pair,
// evdwl,0.0,cforce,delx,dely,delz);
// 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 += 1;
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[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) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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) {
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 (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
}
}
/* --------------------------------------------------------------------- */
void PairLJLongTIP4PLong::compute_inner()
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double r,r2inv,forcecoul,forcelj,cforce;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3];// f1[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq, qri;
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;
// 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;
// atom->nmax > nmax will occur during setup
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_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist)*(cut_coul+2.0*qdist);
int order1 = ewald_order&(1<<1);
int ni;
double *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
inum = listinner->inum;
ilist = listinner->ilist;
numneigh = listinner->numneigh;
firstneigh = listinner->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 && order1) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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];
offseti = offset[itype];
lj1i = lj1[itype]; lj2i = lj2[itype]; lj3i = lj3[itype]; lj4i = lj4[itype];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
ni = sbmask(j);
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_ljsq[itype][jtype] && rsq < cut_out_off_sq ) { // lj
r2inv = 1.0/rsq;
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) forcelj = rn*(rn*lj1i[jtype]-lj2i[jtype]);
else { // special case
register double f = special_lj[ni];
forcelj = f*rn*(rn*lj1i[jtype]-lj2i[jtype]);
}
if (rsq > cut_out_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
forcelj *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
forcelj *= 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;
}
// adjust rsq and delxyz for off-site O charge(s)
// ADDITIONAL REQEUST REQUIRED HERE!!!!!
if (rsq < cut_coulsqplus && order1) {
if (itype == typeO || jtype == typeO) {
if (jtype == typeO) {
if (hneigh[j][0] < 0) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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;
}
// test current rsq against cutoff and compute Coulombic force
if (rsq < cut_coulsq && rsq < cut_out_off_sq) {
r2inv = 1.0 / rsq;
qri = qqrd2e*qtmp;
if (ni == 0) forcecoul = qri*q[j]*sqrt(r2inv);
else {
forcecoul = qri*q[j]*sqrt(r2inv)*special_coul[ni];
}
if (rsq > cut_out_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
forcecoul *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
cforce = forcecoul * r2inv;
//if (evflag) ev_tally(i,j,nlocal,newton_pair,
// evdwl,0.0,cforce,delx,dely,delz);
// 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
if (itype != typeO) {
f[i][0] += delx * cforce;
f[i][1] += dely * cforce;
f[i][2] += delz * cforce;
} else {
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[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 (jtype != typeO) {
f[j][0] -= delx * cforce;
f[j][1] -= dely * cforce;
f[j][2] -= delz * cforce;
} else {
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];
}
}
}
}
}
}
/* --------------------------------------------------------------------- */
void PairLJLongTIP4PLong::compute_middle()
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double r,r2inv,forcecoul,forcelj,cforce;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3];// f1[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq,qri;
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;
// 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;
double **f = atom->f;
double **x = atom->x;
double *q = atom->q;
+ tagint *tag = atom->tag;
int *type = atom->type;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist)*(cut_coul+2.0*qdist);
int order1 = ewald_order&(1<<1);
int ni;
double *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
inum = listmiddle->inum;
ilist = listmiddle->ilist;
numneigh = listmiddle->numneigh;
firstneigh = listmiddle->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 && order1) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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];
offseti = offset[itype];
lj1i = lj1[itype]; lj2i = lj2[itype]; lj3i = lj3[itype]; lj4i = lj4[itype];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
ni = sbmask(j);
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_ljsq[itype][jtype] && rsq >= cut_in_off_sq && rsq <= cut_out_off_sq ) { // lj
r2inv = 1.0/rsq;
register double rn = r2inv*r2inv*r2inv;
if (ni == 0) forcelj = rn*(rn*lj1i[jtype]-lj2i[jtype]);
else { // special case
register double f = special_lj[ni];
forcelj = f*rn*(rn*lj1i[jtype]-lj2i[jtype]);
}
if (rsq < cut_in_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
forcelj *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
forcelj *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
forcelj *= 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;
}
// adjust rsq and delxyz for off-site O charge(s)
// ADDITIONAL REQEUST REQUIRED HERE!!!!!
if (rsq < cut_coulsqplus && order1) {
if (itype == typeO || jtype == typeO) {
if (jtype == typeO) {
if (hneigh[j][0] < 0) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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;
}
// test current rsq against cutoff and compute Coulombic force
if (rsq < cut_coulsq && rsq >= cut_in_off_sq && rsq <= cut_out_off_sq) {
r2inv = 1.0 / rsq;
qri = qqrd2e*qtmp;
if (ni == 0) forcecoul = qri*q[j]*sqrt(r2inv);
else {
forcecoul = qri*q[j]*sqrt(r2inv)*special_coul[ni];
}
if (rsq < cut_in_on_sq) { // switching
register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff;
forcecoul *= rsw*rsw*(3.0 - 2.0*rsw);
}
if (rsq > cut_out_on_sq) {
register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff;
forcecoul *= 1.0 + rsw*rsw*(2.0*rsw-3.0);
}
cforce = forcecoul * r2inv;
//if (evflag) ev_tally(i,j,nlocal,newton_pair,
// evdwl,0.0,cforce,delx,dely,delz);
// 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
if (itype != typeO) {
f[i][0] += delx * cforce;
f[i][1] += dely * cforce;
f[i][2] += delz * cforce;
} else {
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[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 (jtype != typeO) {
f[j][0] -= delx * cforce;
f[j][1] -= dely * cforce;
f[j][2] -= delz * cforce;
} else {
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];
}
}
}
}
}
}
/* --------------------------------------------------------------------- */
void PairLJLongTIP4PLong::compute_outer(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable;
int n,vlist[6];
int key;
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double fraction,table;
double r,r2inv,forcecoul,forcelj,cforce, respa_coul, respa_lj, frespa,fvirial;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],v[6],xH1[3],xH2[3];// f1[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq,qri;
int respa_flag;
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_coul = force->special_coul;
double *special_lj = force->special_lj;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist)*(cut_coul+2.0*qdist);
int order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6);
int ni;
double *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti;
double g2 = g_ewald_6*g_ewald_6, g6 = g2*g2*g2, g8 = g6*g2;
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;
inum = listouter->inum;
ilist = listouter->ilist;
numneigh = listouter->numneigh;
firstneigh = listouter->firstneigh;
// loop over neighbors of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
qtmp = q[i];
qri = qtmp*qqrd2e;
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
if (itype == typeO) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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];
offseti = offset[itype];
lj1i = lj1[itype]; lj2i = lj2[itype]; lj3i = lj3[itype]; lj4i = lj4[itype];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
ni = sbmask(j);
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];
respa_coul = 0;
respa_lj = 0;
if (rsq < cut_ljsq[itype][jtype]) { // lj
frespa = 1.0; // check whether and how to compute respa corrections
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);
}
r2inv = 1.0/rsq;
register double rn = r2inv*r2inv*r2inv;
if (respa_flag) respa_lj = ni == 0 ? // correct for respa
frespa*rn*(rn*lj1i[jtype]-lj2i[jtype]) :
frespa*rn*(rn*lj1i[jtype]-lj2i[jtype])*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[jtype];
if (ni == 0) {
forcelj =
(rn*=rn)*lj1i[jtype]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq-respa_lj;
if (eflag) evdwl = rn*lj3i[jtype]-g6*((a2+1.0)*a2+0.5)*x2;
}
else { // correct for special
register double f = special_lj[ni], t = rn*(1.0-f);
forcelj = f*(rn *= rn)*lj1i[jtype]-
g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[jtype]-respa_lj;
if (eflag)
evdwl = f*rn*lj3i[jtype]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[jtype];
}
}
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) {
forcelj = (rn*=rn)*lj1i[jtype]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[jtype]-respa_lj;
if (eflag) evdwl = rn*lj3i[jtype]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[jtype];
}
else { // special case
register double f = special_lj[ni], t = rn*(1.0-f);
forcelj = f*(rn *= rn)*lj1i[jtype]-(fdisptable[disp_k]+f_disp*dfdisptable[disp_k])*lj4i[jtype]+t*lj2i[jtype]-respa_lj;
if (eflag) evdwl = f*rn*lj3i[jtype]-(edisptable[disp_k]+f_disp*dedisptable[disp_k])*lj4i[jtype]+t*lj4i[jtype];
}
}
}
else { // cut form
if (ni == 0) {
forcelj = rn*(rn*lj1i[jtype]-lj2i[jtype])-respa_lj;
if (eflag) evdwl = rn*(rn*lj3i[jtype]-lj4i[jtype])-offseti[jtype];
}
else { // correct for special
register double f = special_lj[ni];
forcelj = f*rn*(rn*lj1i[jtype]-lj2i[jtype])-respa_lj;
if (eflag)
evdwl = f*(rn*(rn*lj3i[jtype]-lj4i[jtype])-offseti[jtype]);
}
}
forcelj *= 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 (evflag) {
fvirial = forcelj + respa_lj*r2inv;
ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fvirial,delx,dely,delz);
}
}
// adjust rsq and delxyz for off-site O charge(s)
// ADDITIONAL REQEUST REQUIRED HERE!!!!!
if (rsq < cut_coulsqplus) {
if (itype == typeO || jtype == typeO) {
if (jtype == typeO) {
if (hneigh[j][0] < 0) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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;
}
// test current rsq against cutoff and compute Coulombic force
if ((rsq < cut_coulsq) && order1) {
frespa = 1.0; // check whether and how to compute respa corrections
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);
}
r2inv = 1.0 / rsq;
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);
forcecoul = (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);
forcecoul = (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 = (t.f-rtable[k])*drtable[k], qiqj = qtmp*q[j];
if (ni == 0) {
forcecoul = 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]);
forcecoul = 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);
}
}
}
cforce = forcecoul * r2inv;
fvirial = (forcecoul + respa_coul) * 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 * fvirial;
v[1] = x[i][1] * dely * fvirial;
v[2] = x[i][2] * delz * fvirial;
v[3] = x[i][0] * dely * fvirial;
v[4] = x[i][0] * delz * fvirial;
v[5] = x[i][1] * delz * fvirial;
}
vlist[n++] = i;
} else {
key += 1;
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[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) {
fd[0] = delx*fvirial;
fd[1] = dely*fvirial;
fd[2] = delz*fvirial;
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];
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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 * fvirial;
v[1] -= x[j][1] * dely * fvirial;
v[2] -= x[j][2] * delz * fvirial;
v[3] -= x[j][0] * dely * fvirial;
v[4] -= x[j][0] * delz * fvirial;
v[5] -= x[j][1] * delz * fvirial;
}
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) {
fd[0] = -delx*fvirial;
fd[1] = -dely*fvirial;
fd[2] = -delz*fvirial;
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];
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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 (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
}
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLJLongTIP4PLong::settings(int narg, char **arg)
{
if (narg < 8 || narg > 9) error->all(FLERR,"Illegal pair_style command");
ewald_off = 0;
ewald_order = 0;
options(arg, 6);
options(++arg, 1);
if (!comm->me && ewald_order&(1<<6))
error->warning(FLERR,"Mixing forced for lj coefficients");
if (!comm->me && ewald_order==((1<<1)|(1<<6)))
error->warning(FLERR,
"Using largest cutoff for pair_style lj/long/tip4p/long");
if (!((ewald_order^ewald_off)&(1<<1)))
error->all(FLERR,
"Coulomb cut not supported in pair_style lj/long/tip4p/long");
typeO = force->inumeric(FLERR,arg[1]);
typeH = force->inumeric(FLERR,arg[2]);
typeB = force->inumeric(FLERR,arg[3]);
typeA = force->inumeric(FLERR,arg[4]);
qdist = force->numeric(FLERR,arg[5]);
cut_lj_global = force->numeric(FLERR,arg[6]);
if (narg == 8) cut_coul = cut_lj_global;
else cut_coul = force->numeric(FLERR,arg[7]);
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i+1; j <= atom->ntypes; j++)
if (setflag[i][j]) cut_lj[i][j] = cut_lj_global;
}
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairLJLongTIP4PLong::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style lj/long/tip4p/long requires atom IDs");
if (!force->newton_pair)
error->all(FLERR,"Pair style lj/long/tip4p/long requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,"Pair style lj/long/tip4p/long 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");
PairLJLongCoulLong::init_style();
// 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 PairLJLongTIP4PLong::init_one(int i, int j)
{
double cut = PairLJLongCoulLong::init_one(i,j);
// 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))
error->all(FLERR,"Water H epsilon must be 0.0 for "
"pair style lj/long/tip4p/long");
if (i == typeH || j == typeH)
cut_ljsq[j][i] = cut_ljsq[i][j] = 0.0;
return cut;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairLJLongTIP4PLong::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(&ncoultablebits,sizeof(int),1,fp);
fwrite(&tabinner,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairLJLongTIP4PLong::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(&ncoultablebits,sizeof(int),1,fp);
fread(&tabinner,sizeof(double),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(&ncoultablebits,1,MPI_INT,0,world);
MPI_Bcast(&tabinner,1,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairLJLongTIP4PLong::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];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
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 *PairLJLongTIP4PLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"qdist") == 0) return (void *) &qdist;
if (strcmp(str,"typeO") == 0) return (void *) &typeO;
if (strcmp(str,"typeH") == 0) return (void *) &typeH;
if (strcmp(str,"typeA") == 0) return (void *) &typeA;
if (strcmp(str,"typeB") == 0) return (void *) &typeB;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
const char *ids[] = {
"B", "sigma", "epsilon", "ewald_order", "ewald_cut", "cut_coul",
"ewald_mix", "cut_LJ", NULL};
void *ptrs[] = {
lj4, sigma, epsilon, &ewald_order, &cut_coul, &cut_coul,
&mix_flag, &cut_lj_global, NULL};
int i;
for (i=0; ids[i]&&strcmp(ids[i], str); ++i);
if (i <= 2) dim = 2;
else dim = 0;
return ptrs[i];
return NULL;
}
/* ----------------------------------------------------------------------
memory usage of hneigh
------------------------------------------------------------------------- */
double PairLJLongTIP4PLong::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/KSPACE/pair_tip4p_long.cpp b/src/KSPACE/pair_tip4p_long.cpp
index b6b6ef003..c08b42222 100644
--- a/src/KSPACE/pair_tip4p_long.cpp
+++ b/src/KSPACE/pair_tip4p_long.cpp
@@ -1,528 +1,529 @@
/* ----------------------------------------------------------------------
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: Amalie Frischknecht and Ahmed Ismail (SNL)
simpler force assignment added by Rolf Isele-Holder (Aachen University)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_tip4p_long.h"
#include "angle.h"
#include "atom.h"
#include "bond.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "kspace.h"
#include "update.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
/* ---------------------------------------------------------------------- */
PairTIP4PLong::PairTIP4PLong(LAMMPS *lmp) : PairCoulLong(lmp)
{
tip4pflag = 1;
single_enable = 0;
respa_enable = 0;
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;
}
/* ---------------------------------------------------------------------- */
PairTIP4PLong::~PairTIP4PLong()
{
memory->destroy(hneigh);
memory->destroy(newsite);
}
/* ---------------------------------------------------------------------- */
void PairTIP4PLong::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype,itable,key;
int n,vlist[6];
int iH1,iH2,jH1,jH2;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double fraction,table;
double delxOM, delyOM, delzOM;
double r,r2inv,forcecoul,cforce;
double factor_coul;
double grij,expm2,prefactor,t,erfc,ddotf;
double xiM[3],xjM[3],fO[3],fH[3],fd[3],f1[3],v[6],xH1[3],xH2[3];
double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
double rsq;
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_coul = force->special_coul;
int newton_pair = force->newton_pair;
double qqrd2e = force->qqrd2e;
double cut_coulsqplus = (cut_coul+2.0*qdist) * (cut_coul+2.0*qdist);
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 atom I = water O, set x1 = offset charge site
// else x1 = x of atom I
if (itype == typeO) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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_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];
// 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) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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 / rsq;
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;
}
}
cforce = 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 - 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[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) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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) {
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 (evflag) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
}
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairTIP4PLong::settings(int narg, char **arg)
{
if (narg != 6) 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_coul = force->numeric(FLERR,arg[5]);
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairTIP4PLong::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style tip4p/long requires atom IDs");
if (!force->newton_pair)
error->all(FLERR,
"Pair style tip4p/long requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,
"Pair style tip4p/long 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");
PairCoulLong::init_style();
// 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 PairTIP4PLong::init_one(int i, int j)
{
return PairCoulLong::init_one(i,j);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairTIP4PLong::write_restart_settings(FILE *fp)
{
PairCoulLong::write_restart_settings(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);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairTIP4PLong::read_restart_settings(FILE *fp)
{
PairCoulLong::read_restart_settings(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);
}
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);
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairTIP4PLong::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];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
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 *PairTIP4PLong::extract(const char *str, int &dim)
{
dim = 0;
if (strcmp(str,"qdist") == 0) return (void *) &qdist;
if (strcmp(str,"typeO") == 0) return (void *) &typeO;
if (strcmp(str,"typeH") == 0) return (void *) &typeH;
if (strcmp(str,"typeA") == 0) return (void *) &typeA;
if (strcmp(str,"typeB") == 0) return (void *) &typeB;
if (strcmp(str,"cut_coul") == 0) return (void *) &cut_coul;
return NULL;
}
/* ----------------------------------------------------------------------
memory usage of hneigh
------------------------------------------------------------------------- */
double PairTIP4PLong::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp
index f6555063d..be96881bc 100644
--- a/src/MANYBODY/pair_airebo.cpp
+++ b/src/MANYBODY/pair_airebo.cpp
@@ -1,4200 +1,4203 @@
/* ----------------------------------------------------------------------
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)
------------------------------------------------------------------------- */
#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 "neigh_request.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;
maxlocal = 0;
REBO_numneigh = NULL;
REBO_firstneigh = NULL;
ipage = NULL;
pgsize = oneatom = 0;
nC = nH = NULL;
manybody_flag = 1;
}
/* ----------------------------------------------------------------------
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);
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;
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) error->all(FLERR,"Illegal pair_style command");
cutlj = force->numeric(FLERR,arg[0]);
ljflag = torflag = 1;
if (narg == 3) {
ljflag = force->inumeric(FLERR,arg[1]);
torflag = force->inumeric(FLERR,arg[2]);
}
}
/* ----------------------------------------------------------------------
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);
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];
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;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
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,itag,jtag;
+ 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;
- int *tag = atom->tag;
+ 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) 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,itag,jtag;
+ 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,sigcut,sigmin,sigwid;
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;
sigcut = 0.0;
sigmin = 0.0;
sigwid = 0.0;
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ 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
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;
}
done = 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 wik = 0.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 wkm = 0.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
sigwid = 0.84;
sigcut = 3.0;
sigmin = sigcut - sigwid;
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) / rij / swidth;
} else {
slw = 1.0;
dslw = 0.0;
}
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) 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 {
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,itag,jtag;
+ 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;
- int *tag = atom->tag;
+ 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) 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,aaa1,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 = pow(1.0+Etmp+PijS,-0.5);
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 = pow(1.0+Etmp+PjiS,-0.5);
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);
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);
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);
sink2i = 1.0/(sin321*sin321);
rik2i = 1.0/(r21mag*r21mag);
if (sin321 != 0.0) {
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);
sinl2i = 1.0/(sin234*sin234);
rjl2i = 1.0/(r34mag*r34mag);
if (sin234 != 0.0) {
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);
aaa1 = -prefactor*(1.0-square(om1234)) *
(1.0-tspjik)*(1.0-tspijl);
aaa2 = aaa1*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);
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);
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
------------------------------------------------------------------------- */
double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag,
double VA, double rij0[3], double rij0mag,
double **f, int vflag_atom)
{
int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4;
int atomi,atomj,itype,jtype,ktype,ltype,ntype;
double rik[3], rjl[3], rkn[3],rknmag,dNki;
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;
double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC;
double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3];
double dN2[2],dN3[3];
double dcosijldrj[3],dcosijldrl[3],dcosjikdrj[3],dwjl;
double Tij,crosskij[3],crosskijmag;
double crossijl[3],crossijlmag,omkijl;
double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3];
double bij,tmp3pij,tmp3pji,Stb,dStb;
double r32[3],r32mag,cos321;
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,aaa1,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 dNlj;
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 F12[3],F23[3],F34[3],F31[3],F24[3];
double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4];
double rji[3],rki[3],rlj[3],r13[3],r43[3];
double **x = atom->x;
int *type = atom->type;
atomi = i;
atomj = j;
itype = map[type[atomi]];
jtype = map[type[atomj]];
wij = Sp(rij0mag,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));
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 = pow(1.0+Etmp+PijS,-0.5);
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));
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 = pow(1.0+Etmp+PjiS,-0.5);
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) {
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) {
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]));
cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) /
(rijmag*rikmag);
cos321 = MIN(cos321,1.0);
cos321 = MAX(cos321,-1.0);
rjk[0] = rik[0]-rij[0];
rjk[1] = rik[1]-rij[1];
rjk[2] = rik[2]-rij[2];
rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
rij2 = rijmag*rijmag;
rik2 = rikmag*rikmag;
costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag;
tspjik = Sp2(costmp,thmin,thmax,dtsjik);
if (sqrt(1.0 - cos321*cos321) > sqrt(TOL)) {
wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik);
REBO_neighs_j = REBO_firstneigh[j];
for (l = 0; l < REBO_numneigh[j]; l++) {
atoml = REBO_neighs_j[l];
ltype = map[type[atoml]];
if (!(atoml == atomi || atoml == atomk)) {
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]);
cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) /
(rijmag*rjlmag);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
ril[0] = rij[0]+rjl[0];
ril[1] = rij[1]+rjl[1];
ril[2] = rij[2]+rjl[2];
ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]);
rijrjl = 2.0*rijmag*rjlmag;
rjl2 = rjlmag*rjlmag;
costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag;
tspijl = Sp2(costmp,thmin,thmax,dtsijl);
if (sqrt(1.0 - cos234*cos234) > sqrt(TOL)) {
wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS);
crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]);
crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]);
crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]);
crosskijmag = sqrt(crosskij[0]*crosskij[0] +
crosskij[1]*crosskij[1] +
crosskij[2]*crosskij[2]);
crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]);
crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]);
crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]);
crossijlmag = sqrt(crossijl[0]*crossijl[0] +
crossijl[1]*crossijl[1] +
crossijl[2]*crossijl[2]);
omkijl = -1.0*(((crosskij[0]*crossijl[0]) +
(crosskij[1]*crossijl[1]) +
(crosskij[2]*crossijl[2])) /
(crosskijmag*crossijlmag));
Etmp += ((1.0-square(omkijl))*wik*wjl) *
(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];
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));
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 = 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));
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);
}
}
}
// 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);
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[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/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);
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);
sink2i = 1.0/(sin321*sin321);
rik2i = 1.0/(r21mag*r21mag);
if (sin321 != 0.0) {
rr = (rijmag*rijmag)-(r21mag*r21mag);
rjk[0] = r21[0]-rij[0];
rjk[1] = r21[1]-rij[1];
rjk[2] = r21[2]-rij[2];
rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]);
rijrik = 2.0*rijmag*r21mag;
rik2 = r21mag*r21mag;
dctik = (-rr+rjk2)/(rijrik*rik2);
dctij = (rr+rjk2)/(rijrik*rijmag*rijmag);
dctjk = -2.0/rijrik;
w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21);
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 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) +
(rij[2]*r34[2]))/(rijmag*r34mag);
cos234 = MIN(cos234,1.0);
cos234 = MAX(cos234,-1.0);
sin234 = sqrt(1.0 - cos234*cos234);
sinl2i = 1.0/(sin234*sin234);
rjl2i = 1.0/(r34mag*r34mag);
if (sin234 != 0.0) {
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;
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);
aaa1 = -prefactor*(1.0-square(om1234)) *
(1.0-tspjik)*(1.0-tspijl);
aaa2 = aaa1*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);
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);
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,i,done;
double Pij,coeffs[16];
for (i = 0; i < 16; i++) coeffs[i]=0.0;
x = 0;
y = 0;
dN2[0] = 0.0;
dN2[1] = 0.0;
done = 0;
// if inputs are out of bounds set them back to a point in bounds
if (typei == 0 && typej == 0) {
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];
if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
Pij = PCCf[(int) NijC][(int) NijH];
dN2[0] = PCCdfdx[(int) NijC][(int) NijH];
dN2[1] = PCCdfdy[(int) NijC][(int) NijH];
done = 1;
}
if (done == 0) {
x = (int) (floor(NijC));
y = (int) (floor(NijH));
for (i = 0; i<16; i++) coeffs[i] = pCC[x][y][i];
Pij = Spbicubic(NijC,NijH,coeffs,dN2);
}
}
// if inputs are out of bounds set them back to a point in bounds
if (typei == 0 && typej == 1){
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];
if (fabs(NijC-floor(NijC)) < TOL && fabs(NijH-floor(NijH)) < TOL) {
Pij = PCHf[(int) NijC][(int) NijH];
dN2[0] = PCHdfdx[(int) NijC][(int) NijH];
dN2[1] = PCHdfdy[(int) NijC][(int) NijH];
done = 1;
}
if (done == 0) {
x = (int) (floor(NijC));
y = (int) (floor(NijH));
for (i = 0; i<16; i++) coeffs[i] = pCH[x][y][i];
Pij = Spbicubic(NijC,NijH,coeffs,dN2);
}
}
if (typei == 1 && typej == 0) {
Pij = 0.0;
dN2[0] = 0.0;
dN2[1] = 0.0;
}
if (typei == 1 && typej == 1) {
Pij = 0.0;
dN2[0] = 0.0;
dN2[1] = 0.0;
}
return Pij;
}
/* ----------------------------------------------------------------------
PiRC spline
------------------------------------------------------------------------- */
double PairAIREBO::piRCSpline(double Nij, double Nji, double Nijconj,
int typei, int typej, double dN3[3])
{
int x,y,z,i,done;
double piRC,coeffs[64];
x=0;
y=0;
z=0;
i=0;
done=0;
for (i=0; i<64; i++) coeffs[i]=0.0;
if (typei==0 && typej==0) {
//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];
if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
fabs(Nijconj-floor(Nijconj))<TOL) {
piRC=piCCf[(int) Nij][(int) Nji][(int) Nijconj];
dN3[0]=piCCdfdx[(int) Nij][(int) Nji][(int) Nijconj];
dN3[1]=piCCdfdy[(int) Nij][(int) Nji][(int) Nijconj];
dN3[2]=piCCdfdz[(int) Nij][(int) Nji][(int) Nijconj];
done=1;
}
if (done==0) {
for (i=0; i<piCCdom[0][1]; i++)
if (Nij>=(double) i && Nij<=(double) i+1 || Nij==(double) i) x=i;
for (i=0; i<piCCdom[1][1]; i++)
if (Nji>=(double) i && Nji<=(double) i+1 || Nji==(double) i) y=i;
for (i=0; i<piCCdom[2][1]; i++)
if (Nijconj>=(double) i && Nijconj<=(double) i+1 ||
Nijconj==(double) i) z=i;
for (i=0; i<64; i++) coeffs[i]=piCC[x][y][z][i];
piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
}
}
// CH interaction
if (typei==0 && typej==1 || typei==1 && typej==0) {
// if the inputs are out of bounds set them back to a point in bounds
if (Nij<piCHdom[0][0] || Nij>piCHdom[0][1] ||
Nji<piCHdom[1][0] || Nji>piCHdom[1][1] ||
Nijconj<piCHdom[2][0] || Nijconj>piCHdom[2][1]) {
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];
}
if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
fabs(Nijconj-floor(Nijconj))<TOL) {
piRC=piCHf[(int) Nij][(int) Nji][(int) Nijconj];
dN3[0]=piCHdfdx[(int) Nij][(int) Nji][(int) Nijconj];
dN3[1]=piCHdfdy[(int) Nij][(int) Nji][(int) Nijconj];
dN3[2]=piCHdfdz[(int) Nij][(int) Nji][(int) Nijconj];
done=1;
}
if (done==0) {
for (i=0; i<piCHdom[0][1]; i++)
if (Nij>=i && Nij<=i+1) x=i;
for (i=0; i<piCHdom[1][1]; i++)
if (Nji>=i && Nji<=i+1) y=i;
for (i=0; i<piCHdom[2][1]; i++)
if (Nijconj>=i && Nijconj<=i+1) z=i;
for (i=0; i<64; i++) coeffs[i]=piCH[x][y][z][i];
piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
}
}
if (typei==1 && typej==1) {
if (Nij<piHHdom[0][0] || Nij>piHHdom[0][1] ||
Nji<piHHdom[1][0] || Nji>piHHdom[1][1] ||
Nijconj<piHHdom[2][0] || Nijconj>piHHdom[2][1]) {
Nij=0.0;
Nji=0.0;
Nijconj=0.0;
}
if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
fabs(Nijconj-floor(Nijconj))<TOL) {
piRC=piHHf[(int) Nij][(int) Nji][(int) Nijconj];
dN3[0]=piHHdfdx[(int) Nij][(int) Nji][(int) Nijconj];
dN3[1]=piHHdfdy[(int) Nij][(int) Nji][(int) Nijconj];
dN3[2]=piHHdfdz[(int) Nij][(int) Nji][(int) Nijconj];
done=1;
}
if (done==0) {
for (i=0; i<piHHdom[0][1]; i++)
if (Nij>=i && Nij<=i+1) x=i;
for (i=0; i<piHHdom[1][1]; i++)
if (Nji>=i && Nji<=i+1) y=i;
for (i=0; i<piHHdom[2][1]; i++)
if (Nijconj>=i && Nijconj<=i+1) z=i;
for (i=0; i<64; i++) coeffs[i]=piHH[x][y][z][i];
piRC=Sptricubic(Nij,Nji,Nijconj,coeffs,dN3);
}
}
return piRC;
}
/* ----------------------------------------------------------------------
Tij spline
------------------------------------------------------------------------- */
double PairAIREBO::TijSpline(double Nij, double Nji,
double Nijconj, double dN3[3])
{
int x,y,z,i,done;
double Tijf,coeffs[64];
x=0;
y=0;
z=0;
i=0;
Tijf=0.0;
done=0;
for (i=0; i<64; i++) coeffs[i]=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];
if (fabs(Nij-floor(Nij))<TOL && fabs(Nji-floor(Nji))<TOL &&
fabs(Nijconj-floor(Nijconj))<TOL) {
Tijf=Tf[(int) Nij][(int) Nji][(int) Nijconj];
dN3[0]=Tdfdx[(int) Nij][(int) Nji][(int) Nijconj];
dN3[1]=Tdfdy[(int) Nij][(int) Nji][(int) Nijconj];
dN3[2]=Tdfdz[(int) Nij][(int) Nji][(int) Nijconj];
done=1;
}
if (done==0) {
for (i=0; i<Tijdom[0][1]; i++)
if (Nij>=i && Nij<=i+1) x=i;
for (i=0; i<Tijdom[1][1]; i++)
if (Nji>=i && Nji<=i+1) y=i;
for (i=0; i<Tijdom[2][1]; i++)
if (Nijconj>=i && Nijconj<=i+1) z=i;
for (i=0; i<64; i++) coeffs[i]=Tijc[x][y][z][i];
Tijf=Sptricubic(Nij,Nji,Nijconj,coeffs,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;
MPI_Comm_rank(world,&me);
// read file on proc 0
if (me == 0) {
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
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);
// 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;
// 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);
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;
}
/* ----------------------------------------------------------------------
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;
PCCf[2][0] = -0.0276030;
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 (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;
}
/* ----------------------------------------------------------------------
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_bop.cpp b/src/MANYBODY/pair_bop.cpp
index 2f72fc8be..e9b41c237 100644
--- a/src/MANYBODY/pair_bop.cpp
+++ b/src/MANYBODY/pair_bop.cpp
@@ -1,9543 +1,9544 @@
/* ----------------------------------------------------------------------
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: D.K. Ward (donward@sandia.gov) and X.W. Zhou (Sandia)
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
The formulation for this work follows (a) D.G. Pettifor, et al., Mat.
Sci. and Eng. A365, 2-13, (2004);(b) D.A. Murdick, et al., Phys.
Rev. B 73, 045206 (2006);(c) D.G. Pettifor and I.I. Oleinik., Phys
Rev. Lett. 84, 4124 (2000); (d) D.K. Ward, et al., Phys. Rev. B 85,
115206 (2012).
Copyright (2012) Sandia Corporation. Under the terms of Contract DE-
AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
rights in this software.
pairbop v 1.0 comes with no warranty of any kind. pairbop v 1.0 is a
copyrighted code that is distributed free-of-charge, under the terms
of the GNU Public License (GPL). See "Open-Source
Rules"_http://lammps.sandia.gov/open_source.html
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "mpi.h"
#include "pair_bop.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "force.h"
#include "timer.h"
#include "comm.h"
#include "domain.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "memory.h"
#include "error.h"
#include "math_special.h"
using namespace LAMMPS_NS;
using namespace MathSpecial;
#define MAXLINE 1024
#define EPSILON 1.0e-6
/* ---------------------------------------------------------------------- */
PairBOP::PairBOP(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
manybody_flag = 1;
map = NULL;
pi_a = NULL;
pro_delta = NULL;
pi_delta = NULL;
pi_p = NULL;
pi_c = NULL;
sigma_r0 = NULL;
pi_r0 = NULL;
phi_r0 = NULL;
sigma_rc = NULL;
pi_rc = NULL;
phi_rc = NULL;
r1 = NULL;
sigma_beta0 = NULL;
pi_beta0 = NULL;
phi0 = NULL;
sigma_n = NULL;
pi_n = NULL;
phi_m = NULL;
sigma_nc = NULL;
pi_nc = NULL;
phi_nc = NULL;
pro = NULL;
sigma_delta = NULL;
sigma_c = NULL;
sigma_a = NULL;
sigma_g0 = NULL;
sigma_g1 = NULL;
sigma_g2 = NULL;
sigma_g3 = NULL;
sigma_g4 = NULL;
sigma_f = NULL;
sigma_k = NULL;
small3 = NULL;
rcut = NULL;
dr = NULL;
rdr = NULL;
disij = NULL;
rij = NULL;
cosAng = NULL;
betaS = NULL;
dBetaS = NULL;
betaP = NULL;
dBetaP = NULL;
repul = NULL;
dRepul = NULL;
itypeSigBk = NULL;
nSigBk = NULL;
sigB = NULL;
sigB1 = NULL;
itypePiBk = NULL;
nPiBk = NULL;
piB = NULL;
pBetaS = NULL;
pBetaS1 = NULL;
pBetaS2 = NULL;
pBetaS3 = NULL;
pBetaS4 = NULL;
pBetaS5 = NULL;
pBetaS6 = NULL;
pBetaP = NULL;
pBetaP1 = NULL;
pBetaP2 = NULL;
pBetaP3 = NULL;
pBetaP4 = NULL;
pBetaP5 = NULL;
pBetaP6 = NULL;
pRepul = NULL;
pRepul1 = NULL;
pRepul2 = NULL;
pRepul3 = NULL;
pRepul4 = NULL;
pRepul5 = NULL;
pRepul6 = NULL;
FsigBO = NULL;
FsigBO1 = NULL;
FsigBO2 = NULL;
FsigBO3 = NULL;
FsigBO4 = NULL;
FsigBO5 = NULL;
FsigBO6 = NULL;
rcmin = NULL;
rcmax = NULL;
rcmaxp = NULL;
setflag = NULL;
cutsq = NULL;
cutghost = NULL;
ghostneigh = 1;
bt_sg=NULL;
bt_pi=NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairBOP::~PairBOP()
{
if(allocated) {
memory_theta_destroy();
if (otfly==0) memory->destroy(cos_index);
delete [] map;
memory->destroy(BOP_index);
memory->destroy(rcut);
memory->destroy(dr);
memory->destroy(rdr);
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
memory->destroy(pBetaS);
memory->destroy(pBetaS1);
memory->destroy(pBetaS2);
memory->destroy(pBetaS3);
memory->destroy(pBetaS4);
memory->destroy(pBetaS5);
memory->destroy(pBetaS6);
memory->destroy(pBetaP);
memory->destroy(pBetaP1);
memory->destroy(pBetaP2);
memory->destroy(pBetaP3);
memory->destroy(pBetaP4);
memory->destroy(pBetaP5);
memory->destroy(pBetaP6);
memory->destroy(pRepul);
memory->destroy(pRepul1);
memory->destroy(pRepul2);
memory->destroy(pRepul3);
memory->destroy(pRepul4);
memory->destroy(pRepul5);
memory->destroy(pRepul6);
memory->destroy(FsigBO);
memory->destroy(FsigBO1);
memory->destroy(FsigBO2);
memory->destroy(FsigBO3);
memory->destroy(FsigBO4);
memory->destroy(FsigBO5);
memory->destroy(FsigBO6);
if(table==0) {
memory->destroy(pi_a);
memory->destroy(pro_delta);
memory->destroy(pi_delta);
memory->destroy(pi_p);
memory->destroy(pi_c);
memory->destroy(sigma_r0);
memory->destroy(pi_r0);
memory->destroy(phi_r0);
memory->destroy(sigma_rc);
memory->destroy(pi_rc);
memory->destroy(phi_rc);
memory->destroy(r1);
memory->destroy(sigma_beta0);
memory->destroy(pi_beta0);
memory->destroy(phi0);
memory->destroy(sigma_n);
memory->destroy(pi_n);
memory->destroy(phi_m);
memory->destroy(sigma_nc);
memory->destroy(pi_nc);
memory->destroy(phi_nc);
memory->destroy(pro);
memory->destroy(sigma_delta);
memory->destroy(sigma_c);
memory->destroy(sigma_a);
memory->destroy(sigma_g0);
memory->destroy(sigma_g1);
memory->destroy(sigma_g2);
memory->destroy(sigma_g3);
memory->destroy(sigma_g4);
memory->destroy(sigma_f);
memory->destroy(sigma_k);
memory->destroy(small3);
}
else {
memory->destroy(pi_a);
memory->destroy(pro_delta);
memory->destroy(pi_delta);
memory->destroy(pi_p);
memory->destroy(pi_c);
memory->destroy(r1);
memory->destroy(pro);
memory->destroy(sigma_delta);
memory->destroy(sigma_c);
memory->destroy(sigma_a);
memory->destroy(sigma_g0);
memory->destroy(sigma_g1);
memory->destroy(sigma_g2);
memory->destroy(sigma_f);
memory->destroy(sigma_k);
memory->destroy(small3);
}
}
if(allocate_sigma) {
destroy_sigma();
}
if(allocate_pi) {
destroy_pi();
}
}
/* ---------------------------------------------------------------------- */
void PairBOP::compute(int eflag, int vflag)
{
int ago,delay,every;
int i,j,ii,jj,iij;
int n,inum,temp_ij,ks;
- int itype,jtype,i_tag,j_tag;
+ int itype,jtype;
+ tagint i_tag,j_tag;
int *ilist,*iilist,*numneigh;
int **firstneigh;
double dpr1,ps;
double ftmp1,ftmp2,ftmp3,dE;
double dis_ij[3],rsq_ij,r_ij;
double betaS_ij,dBetaS_ij;
double betaP_ij,dBetaP_ij;
double repul_ij,dRepul_ij;
double totE;
double **f = atom->f;
double **x = atom->x;
int *type = atom->type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
ago=neighbor->ago;
delay=neighbor->delay;
every=neighbor->every;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
// BOP Neighbor lists must be updated every time
// atoms are moved between processors
if ((ago ==0)||bop_step==0||(ago>=delay&&(ago%every)==0)||(nall>maxnall))
gneigh();
// For non on the fly calculations cos and derivatives
// are calculated in advance and stored
if(otfly==0) theta();
else theta_mod();
// Calculate Sigma Bond-Order
if(a_flag==1) {
if (otfly==0) sigmaBo_noa();
else sigmaBo_noa_otf();
}
else {
if (otfly==0) sigmaBo();
else sigmaBo_otf();
}
// Calculate Pi Bond-Order
if (otfly==0) PiBo();
else PiBo_otf();
n=0;
totE=0;
for (ii = 0; ii < inum; ii++) {
i=ilist[ii];
i_tag=tag[i];
itype=map[type[i]]+1;
iilist=firstneigh[i];
for(jj=0;jj<numneigh[i];jj++) {
temp_ij=BOP_index[i]+jj;
j=iilist[jj];
j_tag=tag[j];
jtype=map[type[j]]+1;
if(j_tag>=i_tag) {
if(otfly==0) {
if(neigh_flag[temp_ij]) {
dpr1=(dRepul[temp_ij]-2.0*dBetaS[temp_ij]*sigB[n]
-2.0*dBetaP[temp_ij]*piB[n])/rij[temp_ij];
ftmp1=dpr1*disij[0][temp_ij];
ftmp2=dpr1*disij[1][temp_ij];
ftmp3=dpr1*disij[2][temp_ij];
f[i][0]=f[i][0]+ftmp1;
f[i][1]=f[i][1]+ftmp2;
f[i][2]=f[i][2]+ftmp3;
f[j][0]=f[j][0]-ftmp1;
f[j][1]=f[j][1]-ftmp2;
f[j][2]=f[j][2]-ftmp3;
// add repulsive and bond order components to total energy
// (d) Eq.1
dE=-2.0*betaS[temp_ij]*sigB[n]-2.0*betaP[temp_ij]*piB[n];
totE+=dE+repul[temp_ij];
if(evflag) {
ev_tally_full(i,repul[temp_ij],dE,0.0,0.0,0.0,0.0);
ev_tally_full(j,repul[temp_ij],dE,0.0,0.0,0.0,0.0);
ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0,-ftmp1,-ftmp2,-ftmp3,
disij[0][temp_ij],disij[1][temp_ij],disij[2][temp_ij]);
}
n++;
}
}
else {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
dis_ij[0]=x[j][0]-x[i][0];
dis_ij[1]=x[j][1]-x[i][1];
dis_ij[2]=x[j][2]-x[i][2];
rsq_ij=dis_ij[0]*dis_ij[0]
+dis_ij[1]*dis_ij[1]
+dis_ij[2]*dis_ij[2];
r_ij=sqrt(rsq_ij);
if(r_ij<=rcut[iij]) {
ps=r_ij*rdr[iij]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ij=((pBetaS3[iij][ks-1]*ps+pBetaS2[iij][ks-1])*ps
+pBetaS1[iij][ks-1])*ps+pBetaS[iij][ks-1];
dBetaS_ij=(pBetaS6[iij][ks-1]*ps+pBetaS5[iij][ks-1])*ps
+pBetaS4[iij][ks-1];
betaP_ij=((pBetaP3[iij][ks-1]*ps+pBetaP2[iij][ks-1])*ps
+pBetaP1[iij][ks-1])*ps+pBetaP[iij][ks-1];
dBetaP_ij=(pBetaP6[iij][ks-1]*ps+pBetaP5[iij][ks-1])*ps
+pBetaP4[iij][ks-1];
repul_ij=((pRepul3[iij][ks-1]*ps+pRepul2[iij][ks-1])*ps
+pRepul1[iij][ks-1])*ps+pRepul[iij][ks-1];
dRepul_ij=(pRepul6[iij][ks-1]*ps+pRepul5[iij][ks-1])*ps
+pRepul4[iij][ks-1];
dpr1=(dRepul_ij-2.0*dBetaS_ij*sigB[n]
-2.0*dBetaP_ij*piB[n])/r_ij;
ftmp1=dpr1*dis_ij[0];
ftmp2=dpr1*dis_ij[1];
ftmp3=dpr1*dis_ij[2];
f[i][0]=f[i][0]+ftmp1;
f[i][1]=f[i][1]+ftmp2;
f[i][2]=f[i][2]+ftmp3;
f[j][0]=f[j][0]-ftmp1;
f[j][1]=f[j][1]-ftmp2;
f[j][2]=f[j][2]-ftmp3;
// add repulsive and bond order components to total energy
// (d) Eq. 1
dE=-2.0*betaS_ij*sigB[n]-2.0*betaP_ij*piB[n];
totE+=dE+repul_ij;
if(evflag) {
ev_tally_full(i,repul_ij,dE,0.0,0.0,0.0,0.0);
ev_tally_full(j,repul_ij,dE,0.0,0.0,0.0,0.0);
ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0,-ftmp1,-ftmp2,-ftmp3,
dis_ij[0],dis_ij[1],dis_ij[2]);
}
n++;
}
}
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
bop_step = 1;
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairBOP::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(rcut,npairs,"BOP:rcut");
memory->create(dr,npairs,"BOP:dr");
memory->create(rdr,npairs,"BOP:dr");
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");
memory->create(pBetaS,npairs,nr,"BOP:pBetaS");
memory->create(pBetaS1,npairs,nr,"BOP:pBetaS1");
memory->create(pBetaS2,npairs,nr,"BOP:pBetaS2");
memory->create(pBetaS3,npairs,nr,"BOP:pBetaS3");
memory->create(pBetaS4,npairs,nr,"BOP:pBetaS4");
memory->create(pBetaS5,npairs,nr,"BOP:pBetaS5");
memory->create(pBetaS6,npairs,nr,"BOP:pBetaS6");
memory->create(pBetaP,npairs,nr,"BOP:pBetaP");
memory->create(pBetaP1,npairs,nr,"BOP:pBetaP1");
memory->create(pBetaP2,npairs,nr,"BOP:pBetaP2");
memory->create(pBetaP3,npairs,nr,"BOP:pBetaP3");
memory->create(pBetaP4,npairs,nr,"BOP:pBetaP4");
memory->create(pBetaP5,npairs,nr,"BOP:pBetaP5");
memory->create(pBetaP6,npairs,nr,"BOP:pBetaP6");
memory->create(pRepul,npairs,nr,"BOP:pRepul");
memory->create(pRepul1,npairs,nr,"BOP:pRepul1");
memory->create(pRepul2,npairs,nr,"BOP:pRepul2");
memory->create(pRepul3,npairs,nr,"BOP:pRepul3");
memory->create(pRepul4,npairs,nr,"BOP:pRepul4");
memory->create(pRepul5,npairs,nr,"BOP:pRepul5");
memory->create(pRepul6,npairs,nr,"BOP:pRepul6");
memory->create(FsigBO,npairs,nBOt,"BOP:FsigBO");
memory->create(FsigBO1,npairs,nBOt,"BOP:FsigBO1");
memory->create(FsigBO2,npairs,nBOt,"BOP:FsigBO2");
memory->create(FsigBO3,npairs,nBOt,"BOP:FsigBO3");
memory->create(FsigBO4,npairs,nBOt,"BOP:FsigBO4");
memory->create(FsigBO5,npairs,nBOt,"BOP:FsigBO5");
memory->create(FsigBO6,npairs,nBOt,"BOP:FsigBO6");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairBOP::settings(int narg, char **arg)
{
table = 0;
otfly = 1;
a_flag = 0;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"table") == 0) {
table = 1;
iarg++;
} else if (strcmp(arg[iarg],"save") == 0) {
otfly = 0;
iarg++;
} else if (strcmp(arg[iarg],"sigmaoff") == 0) {
a_flag = 1;
iarg++;
} else error->all(FLERR,"Illegal pair_style command");
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs(Updated: D.K. Ward 05/06/10)
------------------------------------------------------------------------- */
void PairBOP::coeff(int narg, char **arg)
{
int i,j,n;
MPI_Comm_rank(world,&me);
map = new int[atom->ntypes+1];
if (narg < 3 + atom->ntypes)
error->all(FLERR,"Incorrect args for pair coefficients");
// ensure I,J args are * *
if (strcmp(arg[0],"*") != 0 || strcmp(arg[1],"*") != 0)
error->all(FLERR,"Incorrect args for pair coefficients");
// read the potential file
nr=2000;
nBOt=2000;
bop_step=0;
nb_pi=0;
nb_sg=0;
allocate_sigma=0;
allocate_pi=0;
allocate_neigh=0;
update_list=0;
if (table == 0) read_file(arg[2]);
else read_table(arg[2]);
if (table == 0) {
setPbetaS();
setPbetaP();
setPrepul();
setSign();
}
// match element names to BOP word types
if (me == 0) {
for (i = 3; i < narg; i++) {
if (strcmp(arg[i],"NULL") == 0) {
map[i-2] = -1;
continue;
}
for (j = 0; j < bop_types; j++)
if (strcmp(arg[i],words[j]) == 0) break;
map[i-2] = j;
}
}
MPI_Bcast(&map[1],atom->ntypes,MPI_INT,0,world);
if (me == 0) {
if (words) {
for (i = 0; i < bop_types; i++) delete [] words[i];
delete [] words;
}
}
// clear setflag since coeff() called once with I,J = * *
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 PairBOP::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style BOP requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style BOP requires newton pair on");
// check that user sets comm->cutghostuser to 3x the max BOP cutoff
if (comm->cutghostuser < 3.0*cutmax - EPSILON) {
char str[128];
sprintf(str,"Pair style bop requires comm ghost cutoff "
"at least 3x larger than %g",cutmax);
error->all(FLERR,str);
}
// need a full neighbor list and neighbors of ghosts
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->ghost = 1;
}
/* ---------------------------------------------------------------------- */
double PairBOP::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
int ii = map[i]+1;
int jj = map[j]+1;
int ij;
if (ii==jj) ij=ii-1;
else if (ii<jj) ij=ii*bop_types-ii*(ii+1)/2+jj-1;
else ij=jj*bop_types-jj*(jj+1)/2+ii-1;
cutghost[i][j] = rcut[ij];
cutghost[j][i] = cutghost[i][j];
cutsq[i][j] = rcut[ij]*rcut[ij];
cutsq[j][i] = cutsq[i][j];
return rcut[ij];
}
/* ----------------------------------------------------------------------
create BOP neighbor list from main neighbor list
BOP neighbor list stores neighbors of ghost atoms
BOP requires neighbor's of k if k is a neighbor of
j and j is a neighbor of i
------------------------------------------------------------------------- */
void PairBOP::gneigh()
{
int i,ii;
int *ilist,*numneigh;
int **firstneigh;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if(allocate_neigh==0) {
memory->create (BOP_index,nall,"BOP_index");
if (otfly==0) memory->create (cos_index,nall,"cos_index");
allocate_neigh=1;
}
else {
memory->grow (BOP_index,nall,"BOP_index");
if (otfly==0) memory->grow (cos_index,nall,"cos_index");
allocate_neigh=1;
}
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
if(bop_step==0) {
maxneigh=0;
maxnall=0;
}
neigh_total=0;
cos_total=0;
for (ii = 0; ii < nall; ii++) {
if(i<nlocal) {
i=ilist[ii];
if(numneigh[i]>maxneigh) maxneigh=numneigh[i];
}
else {
i=ii;
if(numneigh[i]>maxneigh) maxneigh=numneigh[i];
}
BOP_index[i]=neigh_total;
neigh_total+=numneigh[i];
if(otfly==0) {
cos_index[i]=cos_total;
cos_total+=numneigh[i]*(numneigh[i]-1)/2;
}
}
maxnall=nall;
}
/* ---------------------------------------------------------------------- */
void PairBOP::theta()
{
int i,j,k,ii,jj,kk;
int itype,jtype,i12;
int temp_ij,temp_ik,temp_ijk;
int n,nlocal,nall,ks;
int *ilist,*numneigh;
int *iilist;
int **firstneigh;
double rj2,rk2,rsq,ps;
double rj1k1,rj2k2,rj2k1,rj1k2;
double **x = atom->x;
int *type = atom->type;
nlocal = atom->nlocal;
nall = nlocal+atom->nghost;
ilist = list->ilist;
firstneigh = list->firstneigh;
numneigh = list->numneigh;
if(update_list!=0)
memory_theta_grow();
else
memory_theta_create();
for (ii = 0; ii < nall; ii++) {
if(ii<nlocal)
i= ilist[ii];
else
i=ii;
itype = map[type[i]]+1;
iilist=firstneigh[i];
for(jj=0;jj<numneigh[i];jj++) {
j=iilist[jj];
temp_ij=BOP_index[i]+jj;
jtype = map[type[j]]+1;
if(itype==jtype)
i12=itype-1;
else if(itype<jtype)
i12=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
i12=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
if(i12>=npairs) {
error->one(FLERR,"Too many atom pairs for pair bop");
}
disij[0][temp_ij]=x[j][0]-x[i][0];
disij[1][temp_ij]=x[j][1]-x[i][1];
disij[2][temp_ij]=x[j][2]-x[i][2];
rsq=disij[0][temp_ij]*disij[0][temp_ij]
+disij[1][temp_ij]*disij[1][temp_ij]
+disij[2][temp_ij]*disij[2][temp_ij];
rij[temp_ij]=sqrt(rsq);
if(rij[temp_ij]<=rcut[i12])
neigh_flag[temp_ij]=1;
else
neigh_flag[temp_ij]=0;
ps=rij[temp_ij]*rdr[i12]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS[temp_ij]=((pBetaS3[i12][ks-1]*ps+pBetaS2[i12][ks-1])*ps
+pBetaS1[i12][ks-1])*ps+pBetaS[i12][ks-1];
dBetaS[temp_ij]=(pBetaS6[i12][ks-1]*ps+pBetaS5[i12][ks-1])*ps
+pBetaS4[i12][ks-1];
betaP[temp_ij]=((pBetaP3[i12][ks-1]*ps+pBetaP2[i12][ks-1])*ps
+pBetaP1[i12][ks-1])*ps+pBetaP[i12][ks-1];
dBetaP[temp_ij]=(pBetaP6[i12][ks-1]*ps+pBetaP5[i12][ks-1])*ps
+pBetaP4[i12][ks-1];
repul[temp_ij]=((pRepul3[i12][ks-1]*ps+pRepul2[i12][ks-1])*ps
+pRepul1[i12][ks-1])*ps+pRepul[i12][ks-1];
dRepul[temp_ij]=(pRepul6[i12][ks-1]*ps+pRepul5[i12][ks-1])*ps
+pRepul4[i12][ks-1];
}
}
for (ii = 0; ii < nall; ii++) {
n=0;
if(ii<nlocal)
i= ilist[ii];
else
i=ii;
iilist=firstneigh[i];
for(jj=0;jj<numneigh[i];jj++) {
j=iilist[jj];
temp_ij=BOP_index[i]+jj;
rj2=rij[temp_ij]*rij[temp_ij];
for(kk=jj+1;kk<numneigh[i];kk++) {
if(cos_index[i]+n>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
temp_ik=BOP_index[i]+kk;
temp_ijk=cos_index[i]+n;
if(temp_ijk>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
rk2=rij[temp_ik]*rij[temp_ik];
rj1k1=rij[temp_ij]*rij[temp_ik];
rj2k2=rj1k1*rj1k1;
rj2k1=rj1k1*rij[temp_ij];
rj1k2=rj1k1*rij[temp_ik];
k=iilist[kk];
if(temp_ijk>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
cosAng[temp_ijk]=(disij[0][temp_ij]*disij[0][temp_ik]+disij[1][temp_ij]
*disij[1][temp_ik]+disij[2][temp_ij]*disij[2][temp_ik])/rj1k1;
dcAng[temp_ijk][0][0]=(disij[0][temp_ik]*rj1k1-cosAng[temp_ijk]
*disij[0][temp_ij]*rk2)/(rj2k2);
dcAng[temp_ijk][1][0]=(disij[1][temp_ik]*rj1k1-cosAng[temp_ijk]
*disij[1][temp_ij]*rk2)/(rj2k2);
dcAng[temp_ijk][2][0]=(disij[2][temp_ik]*rj1k1-cosAng[temp_ijk]
*disij[2][temp_ij]*rk2)/(rj2k2);
dcAng[temp_ijk][0][1]=(disij[0][temp_ij]*rj1k1-cosAng[temp_ijk]
*disij[0][temp_ik]*rj2)/(rj2k2);
dcAng[temp_ijk][1][1]=(disij[1][temp_ij]*rj1k1-cosAng[temp_ijk]
*disij[1][temp_ik]*rj2)/(rj2k2);
dcAng[temp_ijk][2][1]=(disij[2][temp_ij]*rj1k1-cosAng[temp_ijk]
*disij[2][temp_ik]*rj2)/(rj2k2);
n++;
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairBOP::theta_mod()
{
if(update_list!=0)
memory_theta_grow();
else
memory_theta_create();
}
/* ---------------------------------------------------------------------- */
/* The formulation differs slightly to avoid negative square roots
in the calculation of Sigma^(1/2) of (a) Eq. 6 and (b) Eq. 11 */
void PairBOP::sigmaBo()
{
int nb_t,new_n_tot;
int n,i,j,k,kp,m,pp,kkp;
int iij,ji,ki;
int itmp,jtmp,ktmp,ltmp,mtmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int ngi,ngj,ngk,nglkp,ngli,nglj,ngl;
int ngji,ngjk,nikj,ngki,ngkj,ngjkp;
int ngkpk,ngkpj,ngkkp,nglk;
int njik,nijk,nikkp,nkp,nijkp;
int nkikp,njikp,nk0;
int njkpk,nkjkp,njkkp;
int jNeik,kNeii,kNeij,kNeikp;
int kpNeij,kpNeik;
int new1,new2,nlocal;
int inum,*ilist,*iilist,*jlist,*klist,*kplist;
int **firstneigh,*numneigh;
int temp_ji,temp_ikp,temp_ki,temp_kkp;
int temp_ij,temp_ik,temp_jkp,temp_kk,temp_jk;
int ang_ijkp,ang_ikkp,ang_jkpk,ang_kjkp;
int ang_ijk,ang_ikj,ang_jikp,ang_jkkp;
int ang_jik,ang_kikp;
int nb_ij,nb_ik,nb_ikp;
int nb_jk,nb_jkp,nb_kkp;
int kp_nsearch,nsearch;
int sig_flag,setting,ncmp,ks;
int itype,jtype,ktype,kptype;
int bt_i,bt_j,bt_ij;
int kp_index,same_ikp,same_jkp;
int same_kkp;
double AA,BB,CC,DD,EE,EE1,FF;
double AAC,BBC,CCC,DDC,EEC,FFC,GGC;
double AACFF,UT,bndtmp,UTcom;
double amean,gmean0,gmean1,gmean2,ps;
double gfactor1,gprime1,gsqprime;
double gfactorsq,gfactor2,gprime2;
double gfactorsq2,gsqprime2;
double gfactor3,gprime3,gfactor,rfactor;
double drfactor,gfactor4,gprime4,agpdpr3;
double rfactor0,rfactorrt,rfactor1rt,rfactor1;
double rcm1,rcm2,gcm1,gcm2,gcm3;
double agpdpr1,agpdpr2,app1,app2,app3,app4;
double dsigB1,dsigB2;
double part0,part1,part2,part3,part4;
double psign,bndtmp0,pp1;
double bndtmp1,bndtmp2,bndtmp3,bndtmp4,bndtmp5;
double ftmp[3];
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
int *type = atom->type;
nlocal = atom->nlocal;
firstneigh = list->firstneigh;
numneigh = list->numneigh;
inum = list->inum;
ilist = list->ilist;
n=0;
//loop over all local atoms
if(nb_sg>16) {
nb_sg=16;
}
if(nb_sg==0) {
nb_sg=(maxneigh)*(maxneigh/2);
}
if(allocate_sigma) {
destroy_sigma();
}
create_sigma(nb_sg);
for(itmp=0;itmp<inum;itmp++) {
i = ilist[itmp];
i_tag=tag[i];
itype = map[type[i]]+1;
//j is loop over all neighbors of i
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
temp_ij=BOP_index[i]+jtmp;
if(neigh_flag[temp_ij]) {
for(m=0;m<nb_sg;m++) {
for(pp=0;pp<3;pp++) {
bt_sg[m].dAA[pp]=0.0;
bt_sg[m].dBB[pp]=0.0;
bt_sg[m].dCC[pp]=0.0;
bt_sg[m].dDD[pp]=0.0;
bt_sg[m].dEE[pp]=0.0;
bt_sg[m].dEE1[pp]=0.0;
bt_sg[m].dFF[pp]=0.0;
bt_sg[m].dAAC[pp]=0.0;
bt_sg[m].dBBC[pp]=0.0;
bt_sg[m].dCCC[pp]=0.0;
bt_sg[m].dDDC[pp]=0.0;
bt_sg[m].dEEC[pp]=0.0;
bt_sg[m].dFFC[pp]=0.0;
bt_sg[m].dGGC[pp]=0.0;
bt_sg[m].dUT[pp]=0.0;
bt_sg[m].dSigB1[pp]=0.0;
bt_sg[m].dSigB[pp]=0.0;
}
bt_sg[m].i=-1;
bt_sg[m].j=-1;
bt_sg[m].temp=-1;
}
nb_t=0;
iilist=firstneigh[i];
j=iilist[jtmp];
jlist=firstneigh[j];
for(ki=0;ki<numneigh[j];ki++) {
temp_ki=BOP_index[j]+ki;
if(x[jlist[ki]][0]==x[i][0]) {
if(x[jlist[ki]][1]==x[i][1]) {
if(x[jlist[ki]][2]==x[i][2]) {
break;
}
}
}
}
j_tag=tag[j];
jtype = map[type[j]]+1;
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ij].temp=temp_ij;
bt_sg[nb_ij].i=i;
bt_sg[nb_ij].j=j;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
for(ji=0;ji<numneigh[j];ji++) {
temp_ji=BOP_index[j]+ji;
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
nSigBk[n]=0;
//AA-EE1 are the components making up Eq. 30 (a)
AA=0.0;
BB=0.0;
CC=0.0;
DD=0.0;
EE=0.0;
EE1=0.0;
//FF is the Beta_sigma^2 term
FF=betaS[temp_ij]*betaS[temp_ij];
//agpdpr1 is derivative of FF w.r.t. r_ij
agpdpr1=2.0*betaS[temp_ij]*dBetaS[temp_ij]/rij[temp_ij];
//dXX derivatives are taken with respect to all pairs contributing to the energy
//nb_ij is derivative w.r.t. ij pair
bt_sg[nb_ij].dFF[0]=agpdpr1*disij[0][temp_ij];
bt_sg[nb_ij].dFF[1]=agpdpr1*disij[1][temp_ij];
bt_sg[nb_ij].dFF[2]=agpdpr1*disij[2][temp_ij];
//k is loop over all neighbors of i again with j neighbor of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
temp_ik=BOP_index[i]+ktmp;
if(neigh_flag[temp_ik]) {
if(ktmp!=jtmp) {
if(jtmp<ktmp) {
njik=jtmp*(2*numneigh[i]-jtmp-1)/2+(ktmp-jtmp)-1;
ngj=0;
ngk=1;
}
else {
njik=ktmp*(2*numneigh[i]-ktmp-1)/2+(jtmp-ktmp)-1;
ngj=1;
ngk=0;
}
k=iilist[ktmp];
ktype = map[type[k]]+1;
//find neighbor of k that is equal to i
klist=firstneigh[k];
for(kNeii=0;kNeii<numneigh[k];kNeii++) {
temp_ki=BOP_index[k]+kNeii;
if(x[klist[kNeii]][0]==x[i][0]) {
if(x[klist[kNeii]][1]==x[i][1]) {
if(x[klist[kNeii]][2]==x[i][2]) {
break;
}
}
}
}
//find neighbor of i that is equal to k
for(jNeik=0;jNeik<numneigh[j];jNeik++) {
temp_jk=BOP_index[j]+jNeik;
if(x[jlist[jNeik]][0]==x[k][0]) {
if(x[jlist[jNeik]][1]==x[k][1]) {
if(x[jlist[jNeik]][2]==x[k][2]) {
break;
}
}
}
}
//find neighbor of k that is equal to j
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
nk0=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nk0=nSigBk[n]-1;
itypeSigBk[n][nk0]=k;
}
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ik].temp=temp_ik;
bt_sg[nb_ik].i=i;
bt_sg[nb_ik].j=k;
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
ang_jik=cos_index[i]+njik;
gmean0=sigma_g0[jtype-1][itype-1][ktype-1];
gmean1=sigma_g1[jtype-1][itype-1][ktype-1];
gmean2=sigma_g2[jtype-1][itype-1][ktype-1];
amean=cosAng[ang_jik];
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gfactorsq=gfactor1*gfactor1;
gprime1=gmean1+2.0*gmean2*amean;
gsqprime=2.0*gfactor1*gprime1;
//AA is Eq. 34 (a) or Eq. 10 (c) for the i atom
//1st CC is Eq. 11 (c) for i atom where j & k=neighbor of i
AA=AA+gfactorsq*betaS[temp_ik]*betaS[temp_ik];
CC=CC+gfactorsq*betaS[temp_ik]*betaS[temp_ik]*betaS[temp_ik]*betaS[temp_ik];
//agpdpr1 is derivative of AA w.r.t. Beta(rik)
//agpdpr2 is derivative of CC 1st term w.r.t. Beta(rik)
//app1 is derivative of AA w.r.t. cos(theta_jik)
//app2 is derivative of CC 1st term w.r.t. cos(theta_jik)
agpdpr1=2.0*gfactorsq*betaS[temp_ik]*dBetaS[temp_ik]/rij[temp_ik];
agpdpr1=2.0*betaS[temp_ik]*betaS[temp_ik]*agpdpr1;
app1=betaS[temp_ik]*betaS[temp_ik]*gsqprime;
app1=betaS[temp_ik]*betaS[temp_ik]*app1;
bt_sg[nb_ij].dAA[0]+=
app1*dcAng[ang_jik][0][ngj];
bt_sg[nb_ij].dAA[1]+=
app1*dcAng[ang_jik][1][ngj];
bt_sg[nb_ij].dAA[2]+=
app1*dcAng[ang_jik][2][ngj];
bt_sg[nb_ij].dCC[0]+=
app2*dcAng[ang_jik][0][ngj];
bt_sg[nb_ij].dCC[1]+=
app2*dcAng[ang_jik][1][ngj];
bt_sg[nb_ij].dCC[2]+=
app2*dcAng[ang_jik][2][ngj];
bt_sg[nb_ik].dAA[0]+=
app1*dcAng[ang_jik][0][ngk]
+agpdpr1*disij[0][temp_ik];
bt_sg[nb_ik].dAA[1]+=
app1*dcAng[ang_jik][1][ngk]
+agpdpr1*disij[1][temp_ik];
bt_sg[nb_ik].dAA[2]+=
app1*dcAng[ang_jik][2][ngk]
+agpdpr1*disij[2][temp_ik];
bt_sg[nb_ik].dCC[0]+=
app2*dcAng[ang_jik][0][ngk]
+agpdpr2*disij[0][temp_ik];
bt_sg[nb_ik].dCC[1]+=
app2*dcAng[ang_jik][1][ngk]
+agpdpr2*disij[1][temp_ik];
bt_sg[nb_ik].dCC[2]+=
app2*dcAng[ang_jik][2][ngk]
+agpdpr2*disij[2][temp_ik];
//k' is loop over neighbors all neighbors of j with k a neighbor
//of i and j a neighbor of i and determine which k' is k
kp_index=0;
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
if(x[kp][0]==x[k][0]) {
if(x[kp][1]==x[k][1]) {
if(x[kp][2]==x[k][2]) {
kp_index=1;
break;
}
}
}
}
if(kp_index) {
//loop over neighbors of k
for(mtmp=0;mtmp<numneigh[k];mtmp++) {
kp=klist[mtmp];
if(x[kp][0]==x[j][0]) {
if(x[kp][1]==x[j][1]) {
if(x[kp][2]==x[j][2]) {
break;
}
}
}
}
if(ki<ltmp) {
nijk=ki*(2*numneigh[j]-ki-1)/2+(ltmp-ki)-1;
ngji=0;
ngjk=1;
}
else {
nijk=ltmp*(2*numneigh[j]-ltmp-1)/2+(ki-ltmp)-1;
ngji=1;
ngjk=0;
}
if(kNeii<mtmp) {
nikj=kNeii*(2*numneigh[k]-kNeii-1)/2+(mtmp-kNeii)-1;
ngki=0;
ngkj=1;
}
else {
nikj=mtmp*(2*numneigh[k]-mtmp-1)/2+(kNeii-mtmp)-1;
ngki=1;
ngkj=0;
}
ang_ijk=cos_index[j]+nijk;
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng[ang_ijk];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][jtype-1];
gmean1=sigma_g1[itype-1][ktype-1][jtype-1];
gmean2=sigma_g2[itype-1][ktype-1][jtype-1];
ang_ikj=cos_index[k]+nikj;
amean=cosAng[ang_ikj];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactor=betaS[temp_ik]*betaS[temp_jkp];
//EE1 is (b) Eq. 12
EE1=EE1+gfactor*rfactor;
//rcm2 is derivative of EE1 w.r.t Beta(r_jk')
//gcm1 is derivative of EE1 w.r.t cos(theta_jik)
//gcm2 is derivative of EE1 w.r.t cos(theta_ijk)
//gcm3 is derivative of EE1 w.r.t cos(theta_ikj)
rcm1=gfactor*betaS[temp_jkp]*dBetaS[temp_ik]/rij[temp_ik];
rcm2=gfactor*betaS[temp_ik]*dBetaS[temp_jkp]/rij[temp_jkp];
gcm1=rfactor*gprime1*gfactor2*gfactor3;
gcm2=rfactor*gfactor1*gprime2*gfactor3;
gcm3=rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dEE1[0]+=
gcm1*dcAng[ang_jik][0][ngj]
-gcm2*dcAng[ang_ijk][0][ngji];
bt_sg[nb_ij].dEE1[1]+=
gcm1*dcAng[ang_jik][1][ngj]
-gcm2*dcAng[ang_ijk][1][ngji];
bt_sg[nb_ij].dEE1[2]+=
gcm1*dcAng[ang_jik][2][ngj]
-gcm2*dcAng[ang_ijk][2][ngji];
bt_sg[nb_ik].dEE1[0]+=
gcm1*dcAng[ang_jik][0][ngk]
+rcm1*disij[0][temp_ik]
-gcm3*dcAng[ang_ikj][0][ngki];
bt_sg[nb_ik].dEE1[1]+=
gcm1*dcAng[ang_jik][1][ngk]
+rcm1*disij[1][temp_ik]
-gcm3*dcAng[ang_ikj][1][ngki];
bt_sg[nb_ik].dEE1[2]+=
gcm1*dcAng[ang_jik][2][ngk]
+rcm1*disij[2][temp_ik]
-gcm3*dcAng[ang_ikj][2][ngki];
bt_sg[nb_jk].dEE1[0]+=
gcm2*dcAng[ang_ijk][0][ngjk]
+rcm2*disij[0][temp_jkp]
-gcm3*dcAng[ang_ikj][0][ngkj];
bt_sg[nb_jk].dEE1[1]+=
gcm2*dcAng[ang_ijk][1][ngjk]
+rcm2*disij[1][temp_jkp]
-gcm3*dcAng[ang_ikj][1][ngkj];
bt_sg[nb_jk].dEE1[2]+=
gcm2*dcAng[ang_ijk][2][ngjk]
+rcm2*disij[2][temp_jkp]
-gcm3*dcAng[ang_ikj][2][ngkj];
}
// k and k' and j are all different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
if(neigh_flag[temp_ikp]) {
kp=iilist[ltmp];
kptype = map[type[kp]]+1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(jtmp<ltmp) {
njikp=jtmp*(2*numneigh[i]-jtmp-1)/2+(ltmp-jtmp)-1;
nglj=0;
ngl=1;
}
else {
njikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(jtmp-ltmp)-1;
nglj=1;
ngl=0;
}
if(ktmp<ltmp) {
nkikp=ktmp*(2*numneigh[i]-ktmp-1)/2+(ltmp-ktmp)-1;
nglk=0;
nglkp=1;
}
else {
nkikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(ktmp-ltmp)-1;
nglk=1;
nglkp=0;
}
ang_jikp=cos_index[i]+njikp;
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ikp].temp=temp_ikp;
bt_sg[nb_ikp].i=i;
bt_sg[nb_ikp].j=kp;
gmean0=sigma_g0[jtype-1][itype-1][kptype-1];
gmean1=sigma_g1[jtype-1][itype-1][kptype-1];
gmean2=sigma_g2[jtype-1][itype-1][kptype-1];
amean=cosAng[ang_jikp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][itype-1][kptype-1];
gmean1=sigma_g1[ktype-1][itype-1][kptype-1];
gmean2=sigma_g2[ktype-1][itype-1][kptype-1];
ang_kikp=cos_index[i]+nkikp;
amean=cosAng[ang_kikp];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS[temp_ik]*betaS[temp_ikp];
rfactor=rfactorrt*rfactorrt;
//2nd CC is second term of Eq. 11 (c) for i atom where j , k & k' =neighbor of i
CC=CC+2.0*gfactor*rfactor;
//agpdpr1 is derivative of CC 2nd term w.r.t. Beta(r_ik)
//agpdpr2 is derivative of CC 2nd term w.r.t. Beta(r_ik')
//app1 is derivative of CC 2nd term w.r.t. cos(theta_jik)
//app2 is derivative of CC 2nd term w.r.t. cos(theta_jik')
//app3 is derivative of CC 2nd term w.r.t. cos(theta_kik')
agpdpr1=4.0*gfactor*rfactorrt*betaS[temp_ikp]
*dBetaS[temp_ik]/rij[temp_ik];
agpdpr2=4.0*gfactor*rfactorrt*betaS[temp_ik]
*dBetaS[temp_ikp]/rij[temp_ikp];
app1=2.0*rfactor*gfactor2*gfactor3*gprime1;
app2=2.0*rfactor*gfactor1*gfactor3*gprime2;
app3=2.0*rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dCC[0]+=
app1*dcAng[ang_jik][0][ngj]
+app2*dcAng[ang_jikp][0][nglj];
bt_sg[nb_ij].dCC[1]+=
app1*dcAng[ang_jik][1][ngj]
+app2*dcAng[ang_jikp][1][nglj];
bt_sg[nb_ij].dCC[2]+=
app1*dcAng[ang_jik][2][ngj]
+app2*dcAng[ang_jikp][2][nglj];
bt_sg[nb_ik].dCC[0]+=
app1*dcAng[ang_jik][0][ngk]
+app3*dcAng[ang_kikp][0][nglk]
+agpdpr1*disij[0][temp_ik];
bt_sg[nb_ik].dCC[1]+=
app1*dcAng[ang_jik][1][ngk]
+app3*dcAng[ang_kikp][1][nglk]
+agpdpr1*disij[1][temp_ik];
bt_sg[nb_ik].dCC[2]+=
app1*dcAng[ang_jik][2][ngk]
+app3*dcAng[ang_kikp][2][nglk]
+agpdpr1*disij[2][temp_ik];
bt_sg[nb_ikp].dCC[0]+=
app2*dcAng[ang_jikp][0][ngl]
+app3*dcAng[ang_kikp][0][nglkp]
+agpdpr2*disij[0][temp_ikp];
bt_sg[nb_ikp].dCC[1]+=
app2*dcAng[ang_jikp][1][ngl]
+app3*dcAng[ang_kikp][1][nglkp]
+agpdpr2*disij[1][temp_ikp];
bt_sg[nb_ikp].dCC[2]+=
app2*dcAng[ang_jikp][2][ngl]
+app3*dcAng[ang_kikp][2][nglkp]
+agpdpr2*disij[2][temp_ikp];
}
}
}
// j and k are different neighbors of i and k' is a neighbor k not equal to i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
if(neigh_flag[temp_kkp]) {
kp=klist[ltmp];;
kptype = map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(kNeii<ltmp) {
nikkp=kNeii*(2*numneigh[k]-kNeii-1)/2+(ltmp-kNeii)-1;
nglkp=1;
ngli=0;
}
else {
nikkp=ltmp*(2*numneigh[k]-ltmp-1)/2+(kNeii-ltmp)-1;
nglkp=0;
ngli=1;
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
sig_flag=1;
nkp=nsearch;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
ang_ikkp=cos_index[k]+nikkp;
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng[ang_ikkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS[temp_ik]*betaS[temp_kkp];
rfactor=rfactorrt*rfactorrt;
//3rd CC is third term of Eq. 11 (c) for i atom
//where j , k =neighbor of i & k' =neighbor of k
CC=CC+gfactor*rfactor;
agpdpr1=2.0*gfactor*rfactorrt*betaS[temp_kkp]
*dBetaS[temp_ik]/rij[temp_ik];
agpdpr2=2.0*gfactor*rfactorrt*betaS[temp_ik]
*dBetaS[temp_kkp]/rij[temp_kkp];
app1=rfactor*gfactorsq2*gsqprime;
app2=rfactor*gfactorsq*gsqprime2;
bt_sg[nb_ij].dCC[0]+=
app1*dcAng[ang_jik][0][ngj];
bt_sg[nb_ij].dCC[1]+=
app1*dcAng[ang_jik][1][ngj];
bt_sg[nb_ij].dCC[2]+=
app1*dcAng[ang_jik][2][ngj];
bt_sg[nb_ik].dCC[0]+=
app1*dcAng[ang_jik][0][ngk]
+agpdpr1*disij[0][temp_ik]
-app2*dcAng[ang_ikkp][0][ngli];
bt_sg[nb_ik].dCC[1]+=
app1*dcAng[ang_jik][1][ngk]
+agpdpr1*disij[1][temp_ik]
-app2*dcAng[ang_ikkp][1][ngli];
bt_sg[nb_ik].dCC[2]+=
app1*dcAng[ang_jik][2][ngk]
+agpdpr1*disij[2][temp_ik]
-app2*dcAng[ang_ikkp][2][ngli];
bt_sg[nb_kkp].dCC[0]+=
app2*dcAng[ang_ikkp][0][nglkp]
+agpdpr2*disij[0][temp_kkp];
bt_sg[nb_kkp].dCC[1]+=
app2*dcAng[ang_ikkp][1][nglkp]
+agpdpr2*disij[1][temp_kkp];
bt_sg[nb_kkp].dCC[2]+=
app2*dcAng[ang_ikkp][2][nglkp]
+agpdpr2*disij[2][temp_kkp];
}
}
}
//j and k are different neighbors of i and k' is a neighbor j not equal to k
kplist=firstneigh[kp];
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
sig_flag=0;
temp_jkp=BOP_index[j]+ltmp;
if(neigh_flag[temp_jkp]) {
kp=jlist[ltmp];
kptype = map[type[kp]]+1;
same_jkp=0;
same_kkp=0;
for(kpNeij=0;kpNeij<numneigh[kp];kpNeij++) {
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
break;
}
}
}
}
for(kpNeik=0;kpNeik<numneigh[kp];kpNeik++) {
if(x[k][0]==x[kp][0]) {
if(x[k][1]==x[kp][1]) {
if(x[k][2]==x[kp][2]) {
same_kkp=1;
break;
}
}
}
}
if(!same_kkp&&!same_jkp) {
for(kNeikp=0;kNeikp<numneigh[k];kNeikp++) {
temp_kkp=BOP_index[k]+kNeikp;
kkp=klist[kNeikp];
if(x[kkp][0]==x[kp][0]) {
if(x[kkp][1]==x[kp][1]) {
if(x[kkp][2]==x[kp][2]) {
sig_flag=1;
break;
}
}
}
}
if(sig_flag==1) {
for(nsearch=0;nsearch<numneigh[kp];nsearch++) {
kp_nsearch=BOP_index[kp]+nsearch;
ncmp=kplist[nsearch];
if(x[ncmp][0]==x[j][0]) {
if(x[ncmp][1]==x[j][1]) {
if(x[ncmp][2]==x[j][2]) {
kpNeij=nsearch;
}
}
}
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
kpNeik=nsearch;
}
}
}
}
if(ji<ltmp) {
nijkp=(ji)*numneigh[j]-(ji+1)*(ji+2)/2+ltmp;
ngji=0;
ngjkp=1;
}
else {
nijkp=(ltmp)*numneigh[j]-(ltmp+1)*(ltmp+2)/2+ji;
ngji=1;
ngjkp=0;
}
if(kNeii<kNeikp) {
nikkp=(kNeii)*numneigh[k]-(kNeii+1)*(kNeii+2)/2+kNeikp;
ngki=0;
ngkkp=1;
}
else {
nikkp=(kNeikp)*numneigh[k]-(kNeikp+1)*(kNeikp+2)/2+kNeii;
ngki=1;
ngkkp=0;
}
if(kpNeij<kpNeik) {
njkpk=(kpNeij)*numneigh[kp]-(kpNeij+1)*(kpNeij+2)/2+kpNeik;
ngkpj=0;
ngkpk=1;
}
else {
njkpk=(kpNeik)*numneigh[kp]-(kpNeik+1)*(kpNeik+2)/2+kpNeij;
ngkpj=1;
ngkpk=0;
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
nkp=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
ang_ijkp=cos_index[j]+nijkp;
ang_ikkp=cos_index[k]+nikkp;
ang_jkpk=cos_index[kp]+njkpk;
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jkp].temp=temp_jkp;
bt_sg[nb_jkp].i=j;
bt_sg[nb_jkp].j=kp;
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng[ang_ijkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng[ang_ikkp];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[jtype-1][kptype-1][ktype-1];
gmean1=sigma_g1[jtype-1][kptype-1][ktype-1];
gmean2=sigma_g2[jtype-1][kptype-1][ktype-1];
amean=cosAng[ang_jkpk];
gfactor4=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime4=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3*gfactor4;
rfactor0=(betaS[temp_ik]+small2)*(betaS[temp_jkp]+small2)
*(betaS[temp_kkp]+small2);
rfactor=pow(rfactor0,2.0/3.0);
drfactor=2.0/3.0*pow(rfactor0,-1.0/3.0);
//EE is Eq. 25(notes)
EE=EE+gfactor*rfactor;
//agpdpr1 is derivative of agpdpr1 w.r.t. Beta(r_ik)
//agpdpr2 is derivative of agpdpr1 w.r.t. Beta(r_jk')
//agpdpr3 is derivative of agpdpr1 w.r.t. Beta(r_kk')
//app1 is derivative of agpdpr1 w.r.t. cos(theta_jik)
//app2 is derivative of agpdpr1 w.r.t. cos(theta_ijk')
//app3 is derivative of agpdpr1 w.r.t. cos(theta_ikk')
//app4 is derivative of agpdpr1 w.r.t. cos(theta_jk'k)
agpdpr1=gfactor*drfactor*(betaS[temp_jkp]+small2)*(betaS[temp_kkp]
+small2)*dBetaS[temp_ik]/rij[temp_ik];
agpdpr2=gfactor*drfactor*(betaS[temp_ik]+small2)*(betaS[temp_kkp]
+small2)*dBetaS[temp_jkp]/rij[temp_jkp];
agpdpr3=gfactor*drfactor*(betaS[temp_ik]+small2)*(betaS[temp_jkp]
+small2)*dBetaS[temp_kkp]/rij[temp_kkp];
app1=rfactor*gfactor2*gfactor3*gfactor4*gprime1;
app2=rfactor*gfactor1*gfactor3*gfactor4*gprime2;
app3=rfactor*gfactor1*gfactor2*gfactor4*gprime3;
app4=rfactor*gfactor1*gfactor2*gfactor3*gprime4;
bt_sg[nb_ij].dEE[0]+=
app1*dcAng[ang_jik][0][ngj]
-app2*dcAng[ang_ijkp][0][ngji];
bt_sg[nb_ij].dEE[1]+=
app1*dcAng[ang_jik][1][ngj]
-app2*dcAng[ang_ijkp][1][ngji];
bt_sg[nb_ij].dEE[2]+=
app1*dcAng[ang_jik][2][ngj]
-app2*dcAng[ang_ijkp][2][ngji];
bt_sg[nb_ik].dEE[0]+=
app1*dcAng[ang_jik][0][ngk]
+agpdpr1*disij[0][temp_ik]
-app3*dcAng[ang_ikkp][0][ngki];
bt_sg[nb_ik].dEE[1]+=
app1*dcAng[ang_jik][1][ngk]
+agpdpr1*disij[1][temp_ik]
-app3*dcAng[ang_ikkp][1][ngki];
bt_sg[nb_ik].dEE[2]+=
app1*dcAng[ang_jik][2][ngk]
+agpdpr1*disij[2][temp_ik]
-app3*dcAng[ang_ikkp][2][ngki];
bt_sg[nb_jkp].dEE[0]+=
app2*dcAng[ang_ijkp][0][ngjkp]
+agpdpr2*disij[0][temp_jkp]
-app4*dcAng[ang_jkpk][0][ngkpj];
bt_sg[nb_jkp].dEE[1]+=
app2*dcAng[ang_ijkp][1][ngjkp]
+agpdpr2*disij[1][temp_jkp]
-app4*dcAng[ang_jkpk][1][ngkpj];
bt_sg[nb_jkp].dEE[2]+=
app2*dcAng[ang_ijkp][2][ngjkp]
+agpdpr2*disij[2][temp_jkp]
-app4*dcAng[ang_jkpk][2][ngkpj];
bt_sg[nb_kkp].dEE[0]+=
app3*dcAng[ang_ikkp][0][ngkkp]
+agpdpr3*disij[0][temp_kkp]
-app4*dcAng[ang_jkpk][0][ngkpk];
bt_sg[nb_kkp].dEE[1]+=
app3*dcAng[ang_ikkp][1][ngkkp]
+agpdpr3*disij[1][temp_kkp]
-app4*dcAng[ang_jkpk][1][ngkpk];
bt_sg[nb_kkp].dEE[2]+=
app3*dcAng[ang_ikkp][2][ngkkp]
+agpdpr3*disij[2][temp_kkp]
-app4*dcAng[ang_jkpk][2][ngkpk];
}
}
}
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ji) {
if(ktmp<ji) {
njik=ktmp*(2*numneigh[j]-ktmp-1)/2+(ji-ktmp)-1;
ngi=1;
ngk=0;
}
else {
njik=ji*(2*numneigh[j]-ji-1)/2+(ktmp-ji)-1;
ngi=0;
ngk=1;
}
temp_jk=BOP_index[j]+ktmp;
if(neigh_flag[temp_jk]) {
k=jlist[ktmp];
ktype=map[type[k]]+1;
klist=firstneigh[k];
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
new1=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new1=nSigBk[n]-1;
itypeSigBk[n][new1]=k;
}
ang_ijk=cos_index[j]+njik;
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng[ang_ijk];
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime1=gmean1+2.0*gmean2*amean;
gfactorsq=gfactor1*gfactor1;
gsqprime=2.0*gfactor1*gprime1;
rfactor1rt=betaS[temp_jk]*betaS[temp_jk];
rfactor1=rfactor1rt*rfactor1rt;
//BB is Eq. 34 (a) or Eq. 10 (c) for the j atom
//1st DD is Eq. 11 (c) for j atom where i & k=neighbor of j
BB=BB+gfactorsq*rfactor1rt;
DD=DD+gfactorsq*rfactor1;
//agpdpr1 is derivative of BB w.r.t. Beta(r_jk)
//app1 is derivative of BB w.r.t. cos(theta_ijk)
agpdpr1=2.0*gfactorsq*betaS[temp_jk]*dBetaS[temp_jk]/rij[temp_jk];
app1=rfactor1rt*gsqprime;
bt_sg[nb_ij].dBB[0]-=
app1*dcAng[ang_ijk][0][ngi];
bt_sg[nb_ij].dBB[1]-=
app1*dcAng[ang_ijk][1][ngi];
bt_sg[nb_ij].dBB[2]-=
app1*dcAng[ang_ijk][2][ngi];
bt_sg[nb_ij].dDD[0]-=
app2*dcAng[ang_ijk][0][ngi];
bt_sg[nb_ij].dDD[1]-=
app2*dcAng[ang_ijk][1][ngi];
bt_sg[nb_ij].dDD[2]-=
app2*dcAng[ang_ijk][2][ngi];
bt_sg[nb_jk].dBB[0]+=
app1*dcAng[ang_ijk][0][ngk]
+agpdpr1*disij[0][temp_jk];
bt_sg[nb_jk].dBB[1]+=
app1*dcAng[ang_ijk][1][ngk]
+agpdpr1*disij[1][temp_jk];
bt_sg[nb_jk].dBB[2]+=
app1*dcAng[ang_ijk][2][ngk]
+agpdpr1*disij[2][temp_jk];
bt_sg[nb_jk].dDD[0]+=
app2*dcAng[ang_ijk][0][ngk]
+agpdpr2*disij[0][temp_jk];
bt_sg[nb_jk].dDD[1]+=
app2*dcAng[ang_ijk][1][ngk]
+agpdpr2*disij[1][temp_jk];
bt_sg[nb_jk].dDD[2]+=
app2*dcAng[ang_ijk][2][ngk]
+agpdpr2*disij[2][temp_jk];
//j is a neighbor of i, k and k' prime different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ji) {
temp_jkp=BOP_index[j]+ltmp;
if(neigh_flag[temp_jkp]) {
kp=jlist[ltmp];
kptype=map[type[kp]]+1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
break;
}
}
}
}
if(ji<ltmp) {
nijkp=ji*(2*numneigh[j]-ji-1)/2+(ltmp-ji)-1;
ngli=0;
ngl=1;
}
else {
nijkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ji-ltmp)-1;
ngli=1;
ngl=0;
}
if(ktmp<ltmp) {
nkjkp=ktmp*(2*numneigh[j]-ktmp-1)/2+(ltmp-ktmp)-1;
ngjk=0;
ngjkp=1;
}
else {
nkjkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ktmp-ltmp)-1;
ngjk=1;
ngjkp=0;
}
ang_ijkp=cos_index[j]+nijkp;
ang_kjkp=cos_index[j]+nkjkp;
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng[ang_ijkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][jtype-1][kptype-1];
gmean1=sigma_g1[ktype-1][jtype-1][kptype-1];
gmean2=sigma_g2[ktype-1][jtype-1][kptype-1];
amean=cosAng[ang_kjkp];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS[temp_jk]*betaS[temp_jkp];
rfactor=rfactorrt*rfactorrt;
//2nd DD is Eq. 11 (c) for j atom where i , k & k'=neighbor of j
DD=DD+2.0*gfactor*rfactor;
//agpdpr1 is derivative of DD w.r.t. Beta(r_jk)
//agpdpr2 is derivative of DD w.r.t. Beta(r_jk')
//app1 is derivative of DD w.r.t. cos(theta_ijk)
//app2 is derivative of DD w.r.t. cos(theta_ijkp)
//app3 is derivative of DD w.r.t. cos(theta_kjkp)
agpdpr1=4.0*gfactor*rfactorrt*betaS[temp_jkp]
*dBetaS[temp_jk]/rij[temp_jk];
agpdpr2=4.0*gfactor*rfactorrt*betaS[temp_jk]
*dBetaS[temp_jkp]/rij[temp_jkp];
app1=2.0*rfactor*gfactor2*gfactor3*gprime1;
app2=2.0*rfactor*gfactor1*gfactor3*gprime2;
app3=2.0*rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dDD[0]-=
app1*dcAng[ang_ijk][0][ngi]
+app2*dcAng[ang_ijkp][0][ngli];
bt_sg[nb_ij].dDD[1]-=
app1*dcAng[ang_ijk][1][ngi]
+app2*dcAng[ang_ijkp][1][ngli];
bt_sg[nb_ij].dDD[2]-=
app1*dcAng[ang_ijk][2][ngi]
+app2*dcAng[ang_ijkp][2][ngli];
bt_sg[nb_jk].dDD[0]+=
app1*dcAng[ang_ijk][0][ngk]
+app3*dcAng[ang_kjkp][0][ngjk]
+agpdpr1*disij[0][temp_jk];
bt_sg[nb_jk].dDD[1]+=
app1*dcAng[ang_ijk][1][ngk]
+app3*dcAng[ang_kjkp][1][ngjk]
+agpdpr1*disij[1][temp_jk];
bt_sg[nb_jk].dDD[2]+=
app1*dcAng[ang_ijk][2][ngk]
+app3*dcAng[ang_kjkp][2][ngjk]
+agpdpr1*disij[2][temp_jk];
bt_sg[nb_jkp].dDD[0]+=
app2*dcAng[ang_ijkp][0][ngl]
+app3*dcAng[ang_kjkp][0][ngjkp]
+agpdpr2*disij[0][temp_jkp];
bt_sg[nb_jkp].dDD[1]+=
app2*dcAng[ang_ijkp][1][ngl]
+app3*dcAng[ang_kjkp][1][ngjkp]
+agpdpr2*disij[1][temp_jkp];
bt_sg[nb_jkp].dDD[2]+=
app2*dcAng[ang_ijkp][2][ngl]
+app3*dcAng[ang_kjkp][2][ngjkp]
+agpdpr2*disij[2][temp_jkp];
}
}
}
//j is a neighbor of i, k is a neighbor of j not equal to i and k'
//is a neighbor of k not equal to j or i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
if(neigh_flag[temp_kkp]) {
kp=klist[ltmp];
kptype=map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
if(kNeij<ltmp) {
njkkp=kNeij*(2*numneigh[k]-kNeij-1)/2+(ltmp-kNeij)-1;
nglkp=1;
nglj=0;
}
else {
njkkp=ltmp*(2*numneigh[k]-ltmp-1)/2+(kNeij-ltmp)-1;
nglkp=0;
nglj=1;
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new2=nSigBk[n]-1;
itypeSigBk[n][new2]=kp;
}
ang_jkkp=cos_index[k]+njkkp;
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[jtype-1][ktype-1][kptype-1];
gmean1=sigma_g1[jtype-1][ktype-1][kptype-1];
gmean2=sigma_g2[jtype-1][ktype-1][kptype-1];
amean=cosAng[ang_jkkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS[temp_jk]*betaS[temp_kkp];
rfactor=rfactorrt*rfactorrt;
//3rd DD is Eq. 11 (c) for j atom where i & k=neighbor of j & k'=neighbor of k
DD=DD+gfactor*rfactor;
//agpdpr1 is derivative of DD 3rd term w.r.t. Beta(r_jk)
//agpdpr2 is derivative of DD 3rd term w.r.t. Beta(r_kk')
//app1 is derivative of DD 3rd term w.r.t. cos(theta_ijk)
//app2 is derivative of DD 3rd term w.r.t. cos(theta_jkkp)
agpdpr1=2.0*gfactor*rfactorrt*betaS[temp_kkp]
*dBetaS[temp_jk]/rij[temp_jk];
agpdpr2=2.0*gfactor*rfactorrt*betaS[temp_jk]
*dBetaS[temp_kkp]/rij[temp_kkp];
app1=rfactor*gfactorsq2*gsqprime;
app2=rfactor*gfactorsq*gsqprime2;
bt_sg[nb_ij].dDD[0]-=
app1*dcAng[ang_ijk][0][ngi];
bt_sg[nb_ij].dDD[1]-=
app1*dcAng[ang_ijk][1][ngi];
bt_sg[nb_ij].dDD[2]-=
app1*dcAng[ang_ijk][2][ngi];
bt_sg[nb_jk].dDD[0]+=
app1*dcAng[ang_ijk][0][ngk]
+agpdpr1*disij[0][temp_jk]
-app2*dcAng[ang_jkkp][0][nglj];
bt_sg[nb_jk].dDD[1]+=
app1*dcAng[ang_ijk][1][ngk]
+agpdpr1*disij[1][temp_jk]
-app2*dcAng[ang_jkkp][1][nglj];
bt_sg[nb_jk].dDD[2]+=
app1*dcAng[ang_ijk][2][ngk]
+agpdpr1*disij[2][temp_jk]
-app2*dcAng[ang_jkkp][2][nglj];
bt_sg[nb_kkp].dDD[0]+=
app2*dcAng[ang_jkkp][0][nglkp]
+agpdpr2*disij[0][temp_kkp];
bt_sg[nb_kkp].dDD[1]+=
app2*dcAng[ang_jkkp][1][nglkp]
+agpdpr2*disij[1][temp_kkp];
bt_sg[nb_kkp].dDD[2]+=
app2*dcAng[ang_jkkp][2][nglkp]
+agpdpr2*disij[2][temp_kkp];
}
}
}
}
}
}
sig_flag=0;
if(FF<=0.000001) {
sigB[n]=0.0;
sig_flag=1;
}
if(sig_flag==0) {
if(AA<0.0)
AA=0.0;
if(BB<0.0)
BB=0.0;
if(CC<0.0)
CC=0.0;
if(DD<0.0)
DD=0.0;
// AA and BB are the representations of (a) Eq. 34 and (b) Eq. 9
// for atoms i and j respectively
AAC=AA+BB;
BBC=AA*BB;
CCC=AA*AA+BB*BB;
DDC=CC+DD;
//EEC is a modified form of (a) Eq. 33
EEC=(DDC-CCC)/(AAC+2.0*small1);
AACFF=1.0/(AAC+2.0*small1);
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
bt_sg[m].dAAC[0]=bt_sg[m].dAA[0]
+bt_sg[m].dBB[0];
bt_sg[m].dAAC[1]=bt_sg[m].dAA[1]
+bt_sg[m].dBB[1];
bt_sg[m].dAAC[2]=bt_sg[m].dAA[2]
+bt_sg[m].dBB[2];
bt_sg[m].dBBC[0]=bt_sg[m].dAA[0]*BB
+AA*bt_sg[m].dBB[0];
bt_sg[m].dBBC[1]=bt_sg[m].dAA[1]*BB
+AA*bt_sg[m].dBB[1];
bt_sg[m].dBBC[2]=bt_sg[m].dAA[2]*BB
+AA*bt_sg[m].dBB[2];
bt_sg[m].dCCC[0]=2.0*AA*bt_sg[m].dAA[0]
+2.0*BB*bt_sg[m].dBB[0];
bt_sg[m].dCCC[1]=2.0*AA*bt_sg[m].dAA[1]
+2.0*BB*bt_sg[m].dBB[1];
bt_sg[m].dCCC[2]=2.0*AA*bt_sg[m].dAA[2]
+2.0*BB*bt_sg[m].dBB[2];
bt_sg[m].dDDC[0]=bt_sg[m].dCC[0]
+bt_sg[m].dDD[0];
bt_sg[m].dDDC[1]=bt_sg[m].dCC[1]
+bt_sg[m].dDD[1];
bt_sg[m].dDDC[2]=bt_sg[m].dCC[2]
+bt_sg[m].dDD[2];
bt_sg[m].dEEC[0]=(bt_sg[m].dDDC[0]
-bt_sg[m].dCCC[0]
-EEC*bt_sg[m].dAAC[0])*AACFF;
bt_sg[m].dEEC[1]=(bt_sg[m].dDDC[1]
-bt_sg[m].dCCC[1]
-EEC*bt_sg[m].dAAC[1])*AACFF;
bt_sg[m].dEEC[2]=(bt_sg[m].dDDC[2]
-bt_sg[m].dCCC[2]
-EEC*bt_sg[m].dAAC[2])*AACFF;
}
}
UT=EEC*FF+BBC+small3[iij];
UT=1.0/sqrt(UT);
// FFC is slightly modified form of (a) Eq. 31
// GGC is slightly modified form of (a) Eq. 32
// bndtmp is a slightly modified form of (a) Eq. 30 and (b) Eq. 8
FFC=BBC*UT;
GGC=EEC*UT;
bndtmp=(FF+sigma_delta[iij]*sigma_delta[iij])
+sigma_c[iij]*AAC+small4;
UTcom=-0.5*UT*UT*UT;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_sg[m].dUT[0]=UTcom*(bt_sg[m].dEEC[0]*FF
+EEC*bt_sg[m].dFF[0]+bt_sg[m].dBBC[0]);
bt_sg[m].dUT[1]=UTcom*(bt_sg[m].dEEC[1]*FF
+EEC*bt_sg[m].dFF[1]+bt_sg[m].dBBC[1]);
bt_sg[m].dUT[2]=UTcom*(bt_sg[m].dEEC[2]*FF
+EEC*bt_sg[m].dFF[2]+bt_sg[m].dBBC[2]);
bt_sg[m].dFFC[0]=bt_sg[m].dBBC[0]*UT
+BBC*bt_sg[m].dUT[0];
bt_sg[m].dFFC[1]=bt_sg[m].dBBC[1]*UT
+BBC*bt_sg[m].dUT[1];
bt_sg[m].dFFC[2]=bt_sg[m].dBBC[2]*UT
+BBC*bt_sg[m].dUT[2];
bt_sg[m].dGGC[0]=bt_sg[m].dEEC[0]*UT
+EEC*bt_sg[m].dUT[0];
bt_sg[m].dGGC[1]=bt_sg[m].dEEC[1]*UT
+EEC*bt_sg[m].dUT[1];
bt_sg[m].dGGC[2]=bt_sg[m].dEEC[2]*UT
+EEC*bt_sg[m].dUT[2];
}
}
psign=1.0;
if(1.0+sigma_a[iij]*GGC<0.0)
psign=-1.0;
bndtmp0=1.0/sqrt(bndtmp);
sigB1[n]=psign*betaS[temp_ij]*(1.0+sigma_a[iij]*GGC)*bndtmp0;
bndtmp=-0.5*bndtmp0*bndtmp0*bndtmp0;
bndtmp1=psign*(1.0+sigma_a[iij]*GGC)*bndtmp0+psign*betaS[temp_ij]
*(1.0+sigma_a[iij]*GGC)*bndtmp*2.0*betaS[temp_ij]*(1.0
+sigma_a[iij]*GGC)*(1.0+sigma_a[iij]*GGC);
bndtmp1=bndtmp1*dBetaS[temp_ij]/rij[temp_ij];
bndtmp2=psign*betaS[temp_ij]*(1.0+sigma_a[iij]*GGC)*bndtmp*sigma_c[iij];
bndtmp3=psign*betaS[temp_ij]*(1.0+sigma_a[iij]*GGC)
*bndtmp*sigma_c[iij]*sigma_a[iij];
bndtmp4=psign*betaS[temp_ij]*(1.0+sigma_a[iij]*GGC)
*bndtmp*sigma_c[iij]*sigma_a[iij]*(2.0+GGC);
bndtmp5=sigma_a[iij]*psign*betaS[temp_ij]*bndtmp0
+psign*betaS[temp_ij]*(1.0+sigma_a[iij]*GGC)*bndtmp
*(2.0*(FF+sigma_delta[iij]*sigma_delta[iij])*(1.0
+sigma_a[iij]*GGC)*sigma_a[iij]+sigma_c[iij]*sigma_a[iij]*FFC);
setting=0;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
if(temp_kk==temp_ij&&setting==0) {
bt_sg[m].dSigB1[0]=bndtmp1*disij[0][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=bndtmp1*disij[1][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=bndtmp1*disij[2][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
setting=1;
}
else if(temp_kk==temp_ji&&setting==0) {
bt_sg[m].dSigB1[0]=-bndtmp1*disij[0][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=-bndtmp1*disij[1][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=-bndtmp1*disij[2][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
setting=1;
}
else {
bt_sg[m].dSigB1[0]=(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
}
}
}
//This loop is to ensure there is not an error for atoms with no neighbors (deposition)
if(nb_t==0) {
if(j>i) {
bt_sg[0].dSigB1[0]=bndtmp1*disij[0][temp_ij];
bt_sg[0].dSigB1[1]=bndtmp1*disij[1][temp_ij];
bt_sg[0].dSigB1[2]=bndtmp1*disij[2][temp_ij];
}
else {
bt_sg[0].dSigB1[0]=-bndtmp1*disij[0][temp_ij];
bt_sg[0].dSigB1[1]=-bndtmp1*disij[1][temp_ij];
bt_sg[0].dSigB1[2]=-bndtmp1*disij[2][temp_ij];
}
for(pp=0;pp<3;pp++) {
bt_sg[0].dAA[pp]=0.0;
bt_sg[0].dBB[pp]=0.0;
bt_sg[0].dCC[pp]=0.0;
bt_sg[0].dDD[pp]=0.0;
bt_sg[0].dEE[pp]=0.0;
bt_sg[0].dEE1[pp]=0.0;
bt_sg[0].dFF[pp]=0.0;
bt_sg[0].dAAC[pp]=0.0;
bt_sg[0].dBBC[pp]=0.0;
bt_sg[0].dCCC[pp]=0.0;
bt_sg[0].dDDC[pp]=0.0;
bt_sg[0].dEEC[pp]=0.0;
bt_sg[0].dFFC[pp]=0.0;
bt_sg[0].dGGC[pp]=0.0;
bt_sg[0].dUT[pp]=0.0;
bt_sg[0].dSigB1[pp]=0.0;
bt_sg[0].dSigB[pp]=0.0;
}
bt_sg[0].i=i;
bt_sg[0].j=j;
bt_sg[0].temp=temp_ij;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
}
ps=sigB1[n]*rdBO+1.0;
ks=(int)ps;
if(nBOt-1<ks)
ks=nBOt-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
dsigB1=((FsigBO3[iij][ks-1]*ps+FsigBO2[iij][ks-1])*ps
+FsigBO1[iij][ks-1])*ps+FsigBO[iij][ks-1];
dsigB2=(FsigBO6[iij][ks-1]*ps+FsigBO5[iij][ks-1])*ps+FsigBO4[iij][ks-1];
part0=(FF+0.5*AAC+small5);
part1=(sigma_f[iij]-0.5)*sigma_k[iij];
part2=1.0-part1*EE1/part0;
part3=dsigB1*part1/part0;
part4=part3/part0*EE1;
// sigB is the final expression for (a) Eq. 6 and (b) Eq. 11
sigB[n]=dsigB1*part2;
pp1=2.0*betaS[temp_ij];
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
bt_ij=bt_sg[m].temp;
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
for(pp=0;pp<3;pp++) {
bt_sg[m].dSigB[pp]=dsigB2*part2*bt_sg[m].dSigB1[pp]
-part3*bt_sg[m].dEE1[pp]
+part4*(bt_sg[m].dFF[pp]
+0.5*bt_sg[m].dAAC[pp]);
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp1*bt_sg[m].dSigB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],disij[0][bt_ij],disij[1][bt_ij],disij[2][bt_ij]);
}
}
}
}
n++;
}
}
}
}
if(allocate_sigma)
destroy_sigma();
}
/* ---------------------------------------------------------------------- */
void PairBOP::sigmaBo_noa()
{
int nb_t,new_n_tot;
int n,i,j,k,kp,m,pp;
int iij,ji,ki;
int itmp,jtmp,ktmp,ltmp,mtmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int ngi,ngj,ngk,ngli,nglj,ngl;
int ngji,ngjk,nikj,ngki,ngkj;
int njik,nijk,nikkp,nkp,nijkp;
int nkikp,njikp,nk0,nkjkp,njkkp;
int jNeik,kNeii,kNeij;
int new1,new2,nlocal,nsearch;
int inum,*ilist,*iilist,*jlist,*klist;
int **firstneigh,*numneigh;
int temp_ji,temp_ikp,temp_ki,temp_kkp;
int temp_ij,temp_ik,temp_jkp,temp_kk,temp_jk;
int ang_ijkp,ang_ikkp,ang_kjkp;
int ang_ijk,ang_ikj,ang_jikp,ang_jkkp;
int ang_jik,ang_kikp;
int nb_ij,nb_ik,nb_jk;
int sig_flag,setting,ncmp,ks;
int itype,jtype,ktype,kptype;
int bt_i,bt_j,bt_ij;
int kp_index,same_ikp,same_jkp;
double AA,BB,CC,DD,EE1,FF;
double AAC,BBC,CCC,DDC,EEC;
double UT,bndtmp,UTcom;
double amean,gmean0,gmean1,gmean2,ps;
double gfactor1,gprime1,gsqprime;
double gfactorsq,gfactor2,gprime2;
double gfactorsq2,gsqprime2;
double gfactor3,gprime3,gfactor,rfactor;
double rfactorrt,rfactor1rt,rfactor1;
double rcm1,rcm2,gcm1,gcm2,gcm3;
double agpdpr1,app1;
double dsigB1,dsigB2;
double part0,part1,part2,part3,part4;
double psign,bndtmp0,pp1,bndtmp1,bndtmp2;
double ftmp[3];
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
int *type = atom->type;
nlocal = atom->nlocal;
firstneigh = list->firstneigh;
numneigh = list->numneigh;
inum = list->inum;
ilist = list->ilist;
n=0;
//loop over all local atoms
if(nb_sg>16) {
nb_sg=16;
}
if(nb_sg==0) {
nb_sg=(maxneigh)*(maxneigh/2);
}
if(allocate_sigma) {
destroy_sigma();
}
create_sigma(nb_sg);
for(itmp=0;itmp<inum;itmp++) {
i = ilist[itmp];
i_tag=tag[i];
itype = map[type[i]]+1;
//j is loop over all neighbors of i
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
temp_ij=BOP_index[i]+jtmp;
if(neigh_flag[temp_ij]) {
for(m=0;m<nb_sg;m++) {
for(pp=0;pp<3;pp++) {
bt_sg[m].dAA[pp]=0.0;
bt_sg[m].dBB[pp]=0.0;
bt_sg[m].dEE1[pp]=0.0;
bt_sg[m].dFF[pp]=0.0;
bt_sg[m].dAAC[pp]=0.0;
bt_sg[m].dSigB1[pp]=0.0;
bt_sg[m].dSigB[pp]=0.0;
}
bt_sg[m].i=-1;
bt_sg[m].j=-1;
}
nb_t=0;
iilist=firstneigh[i];
j=iilist[jtmp];
jlist=firstneigh[j];
for(ki=0;ki<numneigh[j];ki++) {
temp_ki=BOP_index[j]+ki;
if(x[jlist[ki]][0]==x[i][0]) {
if(x[jlist[ki]][1]==x[i][1]) {
if(x[jlist[ki]][2]==x[i][2]) {
break;
}
}
}
}
j_tag=tag[j];
jtype = map[type[j]]+1;
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ij].temp=temp_ij;
bt_sg[nb_ij].i=i;
bt_sg[nb_ij].j=j;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
for(ji=0;ji<numneigh[j];ji++) {
temp_ji=BOP_index[j]+ji;
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
nSigBk[n]=0;
//AA-EE1 are the components making up Eq. 30 (a)
AA=0.0;
BB=0.0;
CC=0.0;
DD=0.0;
EE1=0.0;
//FF is the Beta_sigma^2 term
FF=betaS[temp_ij]*betaS[temp_ij];
//agpdpr1 is derivative of FF w.r.t. r_ij
agpdpr1=2.0*betaS[temp_ij]*dBetaS[temp_ij]/rij[temp_ij];
//dXX derivatives are taken with respect to all pairs contributing to the energy
//nb_ij is derivative w.r.t. ij pair
bt_sg[nb_ij].dFF[0]=agpdpr1*disij[0][temp_ij];
bt_sg[nb_ij].dFF[1]=agpdpr1*disij[1][temp_ij];
bt_sg[nb_ij].dFF[2]=agpdpr1*disij[2][temp_ij];
//k is loop over all neighbors of i again with j neighbor of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
temp_ik=BOP_index[i]+ktmp;
if(neigh_flag[temp_ik]) {
if(ktmp!=jtmp) {
if(jtmp<ktmp) {
njik=jtmp*(2*numneigh[i]-jtmp-1)/2+(ktmp-jtmp)-1;
ngj=0;
ngk=1;
}
else {
njik=ktmp*(2*numneigh[i]-ktmp-1)/2+(jtmp-ktmp)-1;
ngj=1;
ngk=0;
}
k=iilist[ktmp];
ktype = map[type[k]]+1;
//find neighbor of k that is equal to i
klist=firstneigh[k];
for(kNeii=0;kNeii<numneigh[k];kNeii++) {
temp_ki=BOP_index[k]+kNeii;
if(x[klist[kNeii]][0]==x[i][0]) {
if(x[klist[kNeii]][1]==x[i][1]) {
if(x[klist[kNeii]][2]==x[i][2]) {
break;
}
}
}
}
//find neighbor of i that is equal to k
for(jNeik=0;jNeik<numneigh[j];jNeik++) {
temp_jk=BOP_index[j]+jNeik;
if(x[jlist[jNeik]][0]==x[k][0]) {
if(x[jlist[jNeik]][1]==x[k][1]) {
if(x[jlist[jNeik]][2]==x[k][2]) {
break;
}
}
}
}
//find neighbor of k that is equal to j
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
nk0=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nk0=nSigBk[n]-1;
itypeSigBk[n][nk0]=k;
}
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ik].temp=temp_ik;
bt_sg[nb_ik].i=i;
bt_sg[nb_ik].j=k;
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
ang_jik=cos_index[i]+njik;
if(ang_jik>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[jtype-1][itype-1][ktype-1];
gmean1=sigma_g1[jtype-1][itype-1][ktype-1];
gmean2=sigma_g2[jtype-1][itype-1][ktype-1];
amean=cosAng[ang_jik];
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gfactorsq=gfactor1*gfactor1;
gprime1=gmean1+2.0*gmean2*amean;
gsqprime=2.0*gfactor1*gprime1;
//AA is Eq. 34 (a) or Eq. 10 (c) for the i atom
//1st CC is Eq. 11 (c) for i atom where j & k=neighbor of i
AA=AA+gfactorsq*betaS[temp_ik]*betaS[temp_ik];
CC=CC+gfactorsq*betaS[temp_ik]*betaS[temp_ik]*betaS[temp_ik]*betaS[temp_ik];
//agpdpr1 is derivative of AA w.r.t. Beta(rik)
//agpdpr2 is derivative of CC 1st term w.r.t. Beta(rik)
//app1 is derivative of AA w.r.t. cos(theta_jik)
//app2 is derivative of CC 1st term w.r.t. cos(theta_jik)
agpdpr1=2.0*gfactorsq*betaS[temp_ik]*dBetaS[temp_ik]/rij[temp_ik];
app1=betaS[temp_ik]*betaS[temp_ik]*gsqprime;
bt_sg[nb_ij].dAA[0]+=
app1*dcAng[ang_jik][0][ngj];
bt_sg[nb_ij].dAA[1]+=
app1*dcAng[ang_jik][1][ngj];
bt_sg[nb_ij].dAA[2]+=
app1*dcAng[ang_jik][2][ngj];
bt_sg[nb_ik].dAA[0]+=
app1*dcAng[ang_jik][0][ngk]
+agpdpr1*disij[0][temp_ik];
bt_sg[nb_ik].dAA[1]+=
app1*dcAng[ang_jik][1][ngk]
+agpdpr1*disij[1][temp_ik];
bt_sg[nb_ik].dAA[2]+=
app1*dcAng[ang_jik][2][ngk]
+agpdpr1*disij[2][temp_ik];
//k' is loop over neighbors all neighbors of j with k a neighbor
//of i and j a neighbor of i and determine which k' is k
kp_index=0;
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
if(x[kp][0]==x[k][0]) {
if(x[kp][1]==x[k][1]) {
if(x[kp][2]==x[k][2]) {
kp_index=1;
break;
}
}
}
}
if(kp_index) {
//loop over neighbors of k
for(mtmp=0;mtmp<numneigh[k];mtmp++) {
kp=klist[mtmp];
if(x[kp][0]==x[j][0]) {
if(x[kp][1]==x[j][1]) {
if(x[kp][2]==x[j][2]) {
break;
}
}
}
}
if(ki<ltmp) {
nijk=ki*(2*numneigh[j]-ki-1)/2+(ltmp-ki)-1;
ngji=0;
ngjk=1;
}
else {
nijk=ltmp*(2*numneigh[j]-ltmp-1)/2+(ki-ltmp)-1;
ngji=1;
ngjk=0;
}
if(kNeii<mtmp) {
nikj=kNeii*(2*numneigh[k]-kNeii-1)/2+(mtmp-kNeii)-1;
ngki=0;
ngkj=1;
}
else {
nikj=mtmp*(2*numneigh[k]-mtmp-1)/2+(kNeii-mtmp)-1;
ngki=1;
ngkj=0;
}
ang_ijk=cos_index[j]+nijk;
if(ang_ijk>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng[ang_ijk];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][jtype-1];
gmean1=sigma_g1[itype-1][ktype-1][jtype-1];
gmean2=sigma_g2[itype-1][ktype-1][jtype-1];
ang_ikj=cos_index[k]+nikj;
if(ang_ikj>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
amean=cosAng[ang_ikj];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactor=betaS[temp_ik]*betaS[temp_jkp];
//EE1 is (b) Eq. 12
EE1=EE1+gfactor*rfactor;
//rcm2 is derivative of EE1 w.r.t Beta(r_jk')
//gcm1 is derivative of EE1 w.r.t cos(theta_jik)
//gcm2 is derivative of EE1 w.r.t cos(theta_ijk)
//gcm3 is derivative of EE1 w.r.t cos(theta_ikj)
rcm1=gfactor*betaS[temp_jkp]*dBetaS[temp_ik]/rij[temp_ik];
rcm2=gfactor*betaS[temp_ik]*dBetaS[temp_jkp]/rij[temp_jkp];
gcm1=rfactor*gprime1*gfactor2*gfactor3;
gcm2=rfactor*gfactor1*gprime2*gfactor3;
gcm3=rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dEE1[0]+=
gcm1*dcAng[ang_jik][0][ngj]
-gcm2*dcAng[ang_ijk][0][ngji];
bt_sg[nb_ij].dEE1[1]+=
gcm1*dcAng[ang_jik][1][ngj]
-gcm2*dcAng[ang_ijk][1][ngji];
bt_sg[nb_ij].dEE1[2]+=
gcm1*dcAng[ang_jik][2][ngj]
-gcm2*dcAng[ang_ijk][2][ngji];
bt_sg[nb_ik].dEE1[0]+=
gcm1*dcAng[ang_jik][0][ngk]
+rcm1*disij[0][temp_ik]
-gcm3*dcAng[ang_ikj][0][ngki];
bt_sg[nb_ik].dEE1[1]+=
gcm1*dcAng[ang_jik][1][ngk]
+rcm1*disij[1][temp_ik]
-gcm3*dcAng[ang_ikj][1][ngki];
bt_sg[nb_ik].dEE1[2]+=
gcm1*dcAng[ang_jik][2][ngk]
+rcm1*disij[2][temp_ik]
-gcm3*dcAng[ang_ikj][2][ngki];
bt_sg[nb_jk].dEE1[0]+=
gcm2*dcAng[ang_ijk][0][ngjk]
+rcm2*disij[0][temp_jkp]
-gcm3*dcAng[ang_ikj][0][ngkj];
bt_sg[nb_jk].dEE1[1]+=
gcm2*dcAng[ang_ijk][1][ngjk]
+rcm2*disij[1][temp_jkp]
-gcm3*dcAng[ang_ikj][1][ngkj];
bt_sg[nb_jk].dEE1[2]+=
gcm2*dcAng[ang_ijk][2][ngjk]
+rcm2*disij[2][temp_jkp]
-gcm3*dcAng[ang_ikj][2][ngkj];
}
// k and k' and j are all different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
if(neigh_flag[temp_ikp]) {
kp=iilist[ltmp];
kptype = map[type[kp]]+1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(jtmp<ltmp) {
njikp=jtmp*(2*numneigh[i]-jtmp-1)/2+(ltmp-jtmp)-1;
nglj=0;
ngl=1;
}
else {
njikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(jtmp-ltmp)-1;
nglj=1;
ngl=0;
}
if(ktmp<ltmp) {
nkikp=ktmp*(2*numneigh[i]-ktmp-1)/2+(ltmp-ktmp)-1;
}
else {
nkikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(ktmp-ltmp)-1;
}
ang_jikp=cos_index[i]+njikp;
if(ang_jikp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[jtype-1][itype-1][kptype-1];
gmean1=sigma_g1[jtype-1][itype-1][kptype-1];
gmean2=sigma_g2[jtype-1][itype-1][kptype-1];
amean=cosAng[ang_jikp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][itype-1][kptype-1];
gmean1=sigma_g1[ktype-1][itype-1][kptype-1];
gmean2=sigma_g2[ktype-1][itype-1][kptype-1];
ang_kikp=cos_index[i]+nkikp;
if(ang_kikp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
amean=cosAng[ang_kikp];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS[temp_ik]*betaS[temp_ikp];
rfactor=rfactorrt*rfactorrt;
//2nd CC is second term of Eq. 11 (c) for i atom where j , k & k' =neighbor of i
CC=CC+2.0*gfactor*rfactor;
}
}
}
// j and k are different neighbors of i and k' is a neighbor k not equal to i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
if(neigh_flag[temp_kkp]) {
kp=klist[ltmp];;
kptype = map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(kNeii<ltmp) {
nikkp=kNeii*(2*numneigh[k]-kNeii-1)/2+(ltmp-kNeii)-1;
ngli=0;
}
else {
nikkp=ltmp*(2*numneigh[k]-ltmp-1)/2+(kNeii-ltmp)-1;
ngli=1;
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
sig_flag=1;
nkp=nsearch;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
ang_ikkp=cos_index[k]+nikkp;
if(ang_ikkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng[ang_ikkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS[temp_ik]*betaS[temp_kkp];
rfactor=rfactorrt*rfactorrt;
//3rd CC is third term of Eq. 11 (c) for i atom
//where j , k =neighbor of i & k' =neighbor of k
CC=CC+gfactor*rfactor;
}
}
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ji) {
if(ktmp<ji) {
njik=ktmp*(2*numneigh[j]-ktmp-1)/2+(ji-ktmp)-1;
ngi=1;
ngk=0;
}
else {
njik=ji*(2*numneigh[j]-ji-1)/2+(ktmp-ji)-1;
ngi=0;
ngk=1;
}
temp_jk=BOP_index[j]+ktmp;
if(neigh_flag[temp_jk]) {
k=jlist[ktmp];
ktype=map[type[k]]+1;
klist=firstneigh[k];
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
new1=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new1=nSigBk[n]-1;
itypeSigBk[n][new1]=k;
}
ang_ijk=cos_index[j]+njik;
if(ang_ijk>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng[ang_ijk];
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime1=gmean1+2.0*gmean2*amean;
gfactorsq=gfactor1*gfactor1;
gsqprime=2.0*gfactor1*gprime1;
rfactor1rt=betaS[temp_jk]*betaS[temp_jk];
rfactor1=rfactor1rt*rfactor1rt;
//BB is Eq. 34 (a) or Eq. 10 (c) for the j atom
//1st DD is Eq. 11 (c) for j atom where i & k=neighbor of j
BB=BB+gfactorsq*rfactor1rt;
DD=DD+gfactorsq*rfactor1;
//agpdpr1 is derivative of BB w.r.t. Beta(r_jk)
//app1 is derivative of BB w.r.t. cos(theta_ijk)
agpdpr1=2.0*gfactorsq*betaS[temp_jk]*dBetaS[temp_jk]/rij[temp_jk];
app1=rfactor1rt*gsqprime;
bt_sg[nb_ij].dBB[0]-=
app1*dcAng[ang_ijk][0][ngi];
bt_sg[nb_ij].dBB[1]-=
app1*dcAng[ang_ijk][1][ngi];
bt_sg[nb_ij].dBB[2]-=
app1*dcAng[ang_ijk][2][ngi];
bt_sg[nb_jk].dBB[0]+=
app1*dcAng[ang_ijk][0][ngk]
+agpdpr1*disij[0][temp_jk];
bt_sg[nb_jk].dBB[1]+=
app1*dcAng[ang_ijk][1][ngk]
+agpdpr1*disij[1][temp_jk];
bt_sg[nb_jk].dBB[2]+=
app1*dcAng[ang_ijk][2][ngk]
+agpdpr1*disij[2][temp_jk];
//j is a neighbor of i, k and k' prime different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ji) {
temp_jkp=BOP_index[j]+ltmp;
if(neigh_flag[temp_jkp]) {
kp=jlist[ltmp];
kptype=map[type[kp]]+1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
break;
}
}
}
}
if(ji<ltmp) {
nijkp=ji*(2*numneigh[j]-ji-1)/2+(ltmp-ji)-1;
ngli=0;
ngl=1;
}
else {
nijkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ji-ltmp)-1;
ngli=1;
ngl=0;
}
if(ktmp<ltmp) {
nkjkp=ktmp*(2*numneigh[j]-ktmp-1)/2+(ltmp-ktmp)-1;
ngjk=0;
}
else {
nkjkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ktmp-ltmp)-1;
ngjk=1;
}
ang_ijkp=cos_index[j]+nijkp;
if(ang_ijkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
ang_kjkp=cos_index[j]+nkjkp;
if(ang_kjkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng[ang_ijkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][jtype-1][kptype-1];
gmean1=sigma_g1[ktype-1][jtype-1][kptype-1];
gmean2=sigma_g2[ktype-1][jtype-1][kptype-1];
amean=cosAng[ang_kjkp];
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS[temp_jk]*betaS[temp_jkp];
rfactor=rfactorrt*rfactorrt;
//2nd DD is Eq. 11 (c) for j atom where i , k & k'=neighbor of j
DD=DD+2.0*gfactor*rfactor;
}
}
}
//j is a neighbor of i, k is a neighbor of j not equal to i and k'
//is a neighbor of k not equal to j or i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
if(neigh_flag[temp_kkp]) {
kp=klist[ltmp];
kptype=map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
if(kNeij<ltmp) {
njkkp=kNeij*(2*numneigh[k]-kNeij-1)/2+(ltmp-kNeij)-1;
nglj=0;
}
else {
njkkp=ltmp*(2*numneigh[k]-ltmp-1)/2+(kNeij-ltmp)-1;
nglj=1;
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new2=nSigBk[n]-1;
itypeSigBk[n][new2]=kp;
}
ang_jkkp=cos_index[k]+njkkp;
if(ang_jkkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
gmean0=sigma_g0[jtype-1][ktype-1][kptype-1];
gmean1=sigma_g1[jtype-1][ktype-1][kptype-1];
gmean2=sigma_g2[jtype-1][ktype-1][kptype-1];
amean=cosAng[ang_jkkp];
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS[temp_jk]*betaS[temp_kkp];
rfactor=rfactorrt*rfactorrt;
//3rd DD is Eq. 11 (c) for j atom where i & k=neighbor of j & k'=neighbor of k
DD=DD+gfactor*rfactor;
}
}
}
}
}
}
sig_flag=0;
if(sig_flag==0) {
// AA and BB are the representations of (a) Eq. 34 and (b) Eq. 9
// for atoms i and j respectively
AAC=AA+BB;
BBC=AA*BB;
CCC=AA*AA+BB*BB;
DDC=CC+DD;
//EEC is a modified form of (a) Eq. 33
EEC=(DDC-CCC)/(AAC+2.0*small1);
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
bt_sg[m].dAAC[0]=bt_sg[m].dAA[0]
+bt_sg[m].dBB[0];
bt_sg[m].dAAC[1]=bt_sg[m].dAA[1]
+bt_sg[m].dBB[1];
bt_sg[m].dAAC[2]=bt_sg[m].dAA[2]
+bt_sg[m].dBB[2];
}
}
UT=EEC*FF+BBC+small3[iij];
UT=1.0/sqrt(UT);
// FFC is slightly modified form of (a) Eq. 31
// GGC is slightly modified form of (a) Eq. 32
// bndtmp is a slightly modified form of (a) Eq. 30 and (b) Eq. 8
bndtmp=(FF+sigma_delta[iij]*sigma_delta[iij])
+sigma_c[iij]*AAC+small4;
UTcom=-0.5*UT*UT*UT;
psign=1.0;
bndtmp0=1.0/sqrt(bndtmp);
sigB1[n]=psign*betaS[temp_ij]*bndtmp0;
bndtmp=-0.5*bndtmp0*bndtmp0*bndtmp0;
bndtmp1=psign*bndtmp0+psign*betaS[temp_ij]
*bndtmp*2.0*betaS[temp_ij];
bndtmp1=bndtmp1*dBetaS[temp_ij]/rij[temp_ij];
bndtmp2=psign*betaS[temp_ij]*bndtmp*sigma_c[iij];
setting=0;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
if(temp_kk==temp_ij&&setting==0) {
bt_sg[m].dSigB1[0]=bndtmp1*disij[0][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=bndtmp1*disij[1][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=bndtmp1*disij[2][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[2]);
setting=1;
}
else if(temp_kk==temp_ji&&setting==0) {
bt_sg[m].dSigB1[0]=-bndtmp1*disij[0][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=-bndtmp1*disij[1][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=-bndtmp1*disij[2][temp_ij]
+(bndtmp2*bt_sg[m].dAAC[2]);
setting=1;
}
else {
bt_sg[m].dSigB1[0]=(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=(bndtmp2*bt_sg[m].dAAC[2]);
}
}
}
//This loop is to ensure there is not an error for atoms with no neighbors (deposition)
if(nb_t==0) {
if(j>i) {
bt_sg[0].dSigB1[0]=bndtmp1*disij[0][temp_ij];
bt_sg[0].dSigB1[1]=bndtmp1*disij[1][temp_ij];
bt_sg[0].dSigB1[2]=bndtmp1*disij[2][temp_ij];
}
else {
bt_sg[0].dSigB1[0]=-bndtmp1*disij[0][temp_ij];
bt_sg[0].dSigB1[1]=-bndtmp1*disij[1][temp_ij];
bt_sg[0].dSigB1[2]=-bndtmp1*disij[2][temp_ij];
}
for(pp=0;pp<3;pp++) {
bt_sg[0].dAA[pp]=0.0;
bt_sg[0].dBB[pp]=0.0;
bt_sg[0].dEE1[pp]=0.0;
bt_sg[0].dFF[pp]=0.0;
bt_sg[0].dAAC[pp]=0.0;
bt_sg[0].dSigB[pp]=0.0;
}
bt_sg[0].i=i;
bt_sg[0].j=j;
bt_sg[0].temp=temp_ij;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
}
ps=sigB1[n]*rdBO+1.0;
ks=(int)ps;
if(nBOt-1<ks)
ks=nBOt-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
dsigB1=((FsigBO3[iij][ks-1]*ps+FsigBO2[iij][ks-1])*ps
+FsigBO1[iij][ks-1])*ps+FsigBO[iij][ks-1];
dsigB2=(FsigBO6[iij][ks-1]*ps+FsigBO5[iij][ks-1])*ps+FsigBO4[iij][ks-1];
part0=(FF+0.5*AAC+small5);
part1=(sigma_f[iij]-0.5)*sigma_k[iij];
part2=1.0-part1*EE1/part0;
part3=dsigB1*part1/part0;
part4=part3/part0*EE1;
// sigB is the final expression for (a) Eq. 6 and (b) Eq. 11
sigB[n]=dsigB1*part2;
pp1=2.0*betaS[temp_ij];
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
bt_ij=bt_sg[m].temp;
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
for(pp=0;pp<3;pp++) {
bt_sg[m].dSigB[pp]=dsigB2*part2*bt_sg[m].dSigB1[pp]
-part3*bt_sg[m].dEE1[pp]
+part4*(bt_sg[m].dFF[pp]
+0.5*bt_sg[m].dAAC[pp]);
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp1*bt_sg[m].dSigB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],disij[0][bt_ij],disij[1][bt_ij],disij[2][bt_ij]);
}
}
}
}
n++;
}
}
}
}
destroy_sigma();
}
/* ---------------------------------------------------------------------- */
/* The formulation differs slightly to avoid negative square roots
in the calculation of Theta_pi,ij of (a) Eq. 36 and (b) Eq. 18 */
void PairBOP::sigmaBo_otf()
{
int nb_t,new_n_tot;
int n,i,j,k,kp,m,pp,kpj,kpk,kkp;
int itmp,jtmp,ktmp,ltmp,mtmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int kp1,kp2,kp1type;
int iij,iik,ijk,ikkp,ji,iikp,ijkp;
int nkp;
int nk0;
int jNeik,kNeii,kNeij,kNeikp;
int kpNeij,kpNeik;
int new1,new2,nlocal;
int inum,*ilist,*iilist,*jlist,*klist,*kplist;
int **firstneigh,*numneigh;
int temp_ij,temp_ik,temp_jkp,temp_kk,temp_jk;
int temp_ji,temp_kpj,temp_kkp;
int temp_ikp,temp_kpk;
int nb_ij,nb_ik,nb_ikp;
int nb_jk,nb_jkp,nb_kkp;
int kp_nsearch,nsearch;
int sig_flag,setting,ncmp,ks;
int itype,jtype,ktype,kptype;
int bt_i,bt_j;
int same_ikp,same_jkp,same_kpk;
int same_jkpj,same_kkpk;
double AA,BB,CC,DD,EE,EE1,FF;
double AAC,BBC,CCC,DDC,EEC,FFC,GGC;
double AACFF,UT,bndtmp,UTcom;
double amean,gmean0,gmean1,gmean2,ps;
double gfactor1,gprime1,gsqprime;
double gfactorsq,gfactor2,gprime2;
double gfactorsq2,gsqprime2;
double gfactor3,gprime3,gfactor,rfactor;
double drfactor,gfactor4,gprime4,agpdpr3;
double rfactor0,rfactorrt,rfactor1rt,rfactor1;
double rcm1,rcm2,gcm1,gcm2,gcm3;
double agpdpr1,agpdpr2,app1,app2,app3,app4;
double dsigB1,dsigB2;
double part0,part1,part2,part3,part4;
double psign,bndtmp0,pp1;
double bndtmp1,bndtmp2,bndtmp3,bndtmp4,bndtmp5;
double dis_ij[3],rsq_ij,r_ij;
double betaS_ij,dBetaS_ij;
double betaP_ij,dBetaP_ij;
double dis_ik[3],rsq_ik,r_ik;
double betaS_ik,dBetaS_ik;
double betaP_ik,dBetaP_ik;
double dis_ikp[3],rsq_ikp,r_ikp;
double betaS_ikp,dBetaS_ikp;
double betaP_ikp,dBetaP_ikp;
double dis_jk[3],rsq_jk,r_jk;
double betaS_jk,dBetaS_jk;
double betaP_jk,dBetaP_jk;
double dis_jkp[3],rsq_jkp,r_jkp;
double betaS_jkp,dBetaS_jkp;
double betaP_jkp,dBetaP_jkp;
double dis_kkp[3],rsq_kkp,r_kkp;
double betaS_kkp,dBetaS_kkp;
double betaP_kkp,dBetaP_kkp;
double cosAng_jik,dcA_jik[3][2];
double cosAng_jikp,dcA_jikp[3][2];
double cosAng_kikp,dcA_kikp[3][2];
double cosAng_ijk,dcA_ijk[3][2];
double cosAng_ijkp,dcA_ijkp[3][2];
double cosAng_kjkp,dcA_kjkp[3][2];
double cosAng_ikj,dcA_ikj[3][2];
double cosAng_ikkp,dcA_ikkp[3][2];
double cosAng_jkkp,dcA_jkkp[3][2];
double cosAng_jkpk,dcA_jkpk[3][2];
double ftmp[3],xtmp[3];
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
int *type = atom->type;
nlocal = atom->nlocal;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
n=0;
if(nb_sg==0) {
nb_sg=(maxneigh)*(maxneigh/2);
}
if(allocate_sigma) {
destroy_sigma();
}
create_sigma(nb_sg);
for(itmp=0;itmp<inum;itmp++) {
i = ilist[itmp];
i_tag=tag[i];
itype = map[type[i]]+1;
//j is loop over all neighbors of i
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
for(m=0;m<nb_sg;m++) {
for(pp=0;pp<3;pp++) {
bt_sg[m].dAA[pp]=0.0;
bt_sg[m].dBB[pp]=0.0;
bt_sg[m].dCC[pp]=0.0;
bt_sg[m].dDD[pp]=0.0;
bt_sg[m].dEE[pp]=0.0;
bt_sg[m].dEE1[pp]=0.0;
bt_sg[m].dFF[pp]=0.0;
bt_sg[m].dAAC[pp]=0.0;
bt_sg[m].dBBC[pp]=0.0;
bt_sg[m].dCCC[pp]=0.0;
bt_sg[m].dDDC[pp]=0.0;
bt_sg[m].dEEC[pp]=0.0;
bt_sg[m].dFFC[pp]=0.0;
bt_sg[m].dGGC[pp]=0.0;
bt_sg[m].dUT[pp]=0.0;
bt_sg[m].dSigB1[pp]=0.0;
bt_sg[m].dSigB[pp]=0.0;
}
bt_sg[m].i=-1;
bt_sg[m].j=-1;
bt_sg[m].temp=-1;
}
nb_t=0;
iilist=firstneigh[i];
temp_ij=BOP_index[i]+jtmp;
j=iilist[jtmp];
jlist=firstneigh[j];
j_tag=tag[j];
jtype = map[type[j]]+1;
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ij].temp=temp_ij;
bt_sg[nb_ij].i=i;
bt_sg[nb_ij].j=j;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
for(ji=0;ji<numneigh[j];ji++) {
temp_ji=BOP_index[j]+ji;
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
dis_ij[0]=x[j][0]-x[i][0];
dis_ij[1]=x[j][1]-x[i][1];
dis_ij[2]=x[j][2]-x[i][2];
rsq_ij=dis_ij[0]*dis_ij[0]
+dis_ij[1]*dis_ij[1]
+dis_ij[2]*dis_ij[2];
r_ij=sqrt(rsq_ij);
if(r_ij<rcut[iij]) {
ps=r_ij*rdr[iij]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ij=((pBetaS3[iij][ks-1]*ps+pBetaS2[iij][ks-1])*ps
+pBetaS1[iij][ks-1])*ps+pBetaS[iij][ks-1];
dBetaS_ij=(pBetaS6[iij][ks-1]*ps+pBetaS5[iij][ks-1])*ps
+pBetaS4[iij][ks-1];
betaP_ij=((pBetaP3[iij][ks-1]*ps+pBetaP2[iij][ks-1])*ps
+pBetaP1[iij][ks-1])*ps+pBetaP[iij][ks-1];
dBetaP_ij=(pBetaP6[iij][ks-1]*ps+pBetaP5[iij][ks-1])*ps
+pBetaP4[iij][ks-1];
nSigBk[n]=0;
//AA-EE1 are the components making up Eq. 30 (a)
AA=0.0;
BB=0.0;
CC=0.0;
DD=0.0;
EE=0.0;
EE1=0.0;
//FF is the Beta_sigma^2 term
FF=betaS_ij*betaS_ij;
//agpdpr1 is derivative of FF w.r.t. r_ij
agpdpr1=2.0*betaS_ij*dBetaS_ij/r_ij;
//dXX derivatives are taken with respect to all pairs contributing to the energy
//nb_ij is derivative w.r.t. ij pair
bt_sg[nb_ij].dFF[0]=agpdpr1*dis_ij[0];
bt_sg[nb_ij].dFF[1]=agpdpr1*dis_ij[1];
bt_sg[nb_ij].dFF[2]=agpdpr1*dis_ij[2];
//k is loop over all neighbors of i again with j neighbor of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
temp_ik=BOP_index[i]+ktmp;
if(ktmp!=jtmp) {
k=iilist[ktmp];
klist=firstneigh[k];
ktype = map[type[k]]+1;
if(itype==ktype)
iik=itype-1;
else if(itype<ktype)
iik=itype*bop_types-itype*(itype+1)/2+ktype-1;
else
iik=ktype*bop_types-ktype*(ktype+1)/2+itype-1;
//find neighbor of k that is equal to i
for(kNeii=0;kNeii<numneigh[k];kNeii++) {
if(x[klist[kNeii]][0]==x[i][0]) {
if(x[klist[kNeii]][1]==x[i][1]) {
if(x[klist[kNeii]][2]==x[i][2]) {
break;
}
}
}
}
dis_ik[0]=x[k][0]-x[i][0];
dis_ik[1]=x[k][1]-x[i][1];
dis_ik[2]=x[k][2]-x[i][2];
rsq_ik=dis_ik[0]*dis_ik[0]
+dis_ik[1]*dis_ik[1]
+dis_ik[2]*dis_ik[2];
r_ik=sqrt(rsq_ik);
if(r_ik<=rcut[iik]) {
ps=r_ik*rdr[iik]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ik=((pBetaS3[iik][ks-1]*ps+pBetaS2[iik][ks-1])*ps
+pBetaS1[iik][ks-1])*ps+pBetaS[iik][ks-1];
dBetaS_ik=(pBetaS6[iik][ks-1]*ps+pBetaS5[iik][ks-1])*ps
+pBetaS4[iik][ks-1];
betaP_ik=((pBetaP3[iik][ks-1]*ps+pBetaP2[iik][ks-1])*ps
+pBetaP1[iik][ks-1])*ps+pBetaP[iik][ks-1];
dBetaP_ik=(pBetaP6[iik][ks-1]*ps+pBetaP5[iik][ks-1])*ps
+pBetaP4[iik][ks-1];
//find neighbor of i that is equal to k
for(jNeik=0;jNeik<numneigh[j];jNeik++) {
temp_jk=BOP_index[j]+jNeik;
if(x[jlist[jNeik]][0]==x[k][0]) {
if(x[jlist[jNeik]][1]==x[k][1]) {
if(x[jlist[jNeik]][2]==x[k][2]) {
break;
}
}
}
}
//find neighbor of k that is equal to j
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
dis_jk[0]=x[k][0]-x[j][0];
dis_jk[1]=x[k][1]-x[j][1];
dis_jk[2]=x[k][2]-x[j][2];
rsq_jk=dis_jk[0]*dis_jk[0]
+dis_jk[1]*dis_jk[1]
+dis_jk[2]*dis_jk[2];
r_jk=sqrt(rsq_jk);
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
nk0=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nk0=nSigBk[n]-1;
itypeSigBk[n][nk0]=k;
}
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ik].temp=temp_ik;
bt_sg[nb_ik].i=i;
bt_sg[nb_ik].j=k;
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
cosAng_jik=(dis_ij[0]*dis_ik[0]+dis_ij[1]*dis_ik[1]
+dis_ij[2]*dis_ik[2])/(r_ij*r_ik);
dcA_jik[0][0]=(dis_ik[0]*r_ij*r_ik-cosAng_jik
*dis_ij[0]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][0]=(dis_ik[1]*r_ij*r_ik-cosAng_jik
*dis_ij[1]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][0]=(dis_ik[2]*r_ij*r_ik-cosAng_jik
*dis_ij[2]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[0][1]=(dis_ij[0]*r_ij*r_ik-cosAng_jik
*dis_ik[0]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][1]=(dis_ij[1]*r_ij*r_ik-cosAng_jik
*dis_ik[1]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][1]=(dis_ij[2]*r_ij*r_ik-cosAng_jik
*dis_ik[2]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
gmean0=sigma_g0[jtype-1][itype-1][ktype-1];
gmean1=sigma_g1[jtype-1][itype-1][ktype-1];
gmean2=sigma_g2[jtype-1][itype-1][ktype-1];
amean=cosAng_jik;
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gfactorsq=gfactor1*gfactor1;
gprime1=gmean1+2.0*gmean2*amean;
gsqprime=2.0*gfactor1*gprime1;
//AA is Eq. 34 (a) or Eq. 10 (c) for the i atom
//1st CC is Eq. 11 (c) for i atom where j & k=neighbor of i
AA=AA+gfactorsq*betaS_ik*betaS_ik;
CC=CC+gfactorsq*betaS_ik*betaS_ik*betaS_ik*betaS_ik;
//agpdpr1 is derivative of AA w.r.t. Beta(rik)
//app1 is derivative of AA w.r.t. cos(theta_jik)
agpdpr1=2.0*gfactorsq*betaS_ik*dBetaS_ik/r_ik;
app1=betaS_ik*betaS_ik*gsqprime;
bt_sg[nb_ij].dAA[0]+=
app1*dcA_jik[0][0];
bt_sg[nb_ij].dAA[1]+=
app1*dcA_jik[1][0];
bt_sg[nb_ij].dAA[2]+=
app1*dcA_jik[2][0];
bt_sg[nb_ij].dCC[0]+=
app2*dcA_jik[0][0];
bt_sg[nb_ij].dCC[1]+=
app2*dcA_jik[1][0];
bt_sg[nb_ij].dCC[2]+=
app2*dcA_jik[2][0];
bt_sg[nb_ik].dAA[0]+=
app1*dcA_jik[0][1]
+agpdpr1*dis_ik[0];
bt_sg[nb_ik].dAA[1]+=
app1*dcA_jik[1][1]
+agpdpr1*dis_ik[1];
bt_sg[nb_ik].dAA[2]+=
app1*dcA_jik[2][1]
+agpdpr1*dis_ik[2];
bt_sg[nb_ik].dCC[0]+=
app2*dcA_jik[0][1]
+agpdpr2*dis_ik[0];
bt_sg[nb_ik].dCC[1]+=
app2*dcA_jik[1][1]
+agpdpr2*dis_ik[1];
bt_sg[nb_ik].dCC[2]+=
app2*dcA_jik[2][1]
+agpdpr2*dis_ik[2];
//k' is loop over neighbors all neighbors of j with k a neighbor
//of i and j a neighbor of i and determine which k' is k
same_kpk=0;
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
temp_jkp=BOP_index[j]+ltmp;
kp1=jlist[ltmp];
kp1type=map[type[kp1]]+1;
if(x[kp1][0]==x[k][0]) {
if(x[kp1][1]==x[k][1]) {
if(x[kp1][2]==x[k][2]) {
same_kpk=1;
break;
}
}
}
}
if(same_kpk){
//loop over neighbors of k
for(mtmp=0;mtmp<numneigh[k];mtmp++) {
temp_kpj=BOP_index[k]+mtmp;
kp2=klist[mtmp];
if(x[kp2][0]==x[k][0]) {
if(x[kp2][1]==x[k][1]) {
if(x[kp2][2]==x[k][2]) {
break;
}
}
}
}
if(jtype==ktype)
ijk=jtype-1;
else if(jtype < ktype)
ijk=jtype*bop_types-jtype*(jtype+1)/2+ktype-1;
else
ijk=ktype*bop_types-ktype*(ktype+1)/2+jtype-1;
if(jtype==kp1type)
ijkp=jtype-1;
else if(jtype<kp1type)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kp1type-1;
else
ijkp=kp1type*bop_types-kp1type*(kp1type+1)/2+jtype-1;
dis_jkp[0]=x[kp1][0]-x[j][0];
dis_jkp[1]=x[kp1][1]-x[j][1];
dis_jkp[2]=x[kp1][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
if(r_jkp<=rcut[ijkp]) {
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
cosAng_ijk=(-dis_ij[0]*dis_jk[0]-dis_ij[1]*dis_jk[1]
-dis_ij[2]*dis_jk[2])/(r_ij*r_jk);
dcA_ijk[0][0]=(dis_jk[0]*r_ij*r_jk-cosAng_ijk
*-dis_ij[0]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][0]=(dis_jk[1]*r_ij*r_jk-cosAng_ijk
*-dis_ij[1]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][0]=(dis_jk[2]*r_ij*r_jk-cosAng_ijk
*-dis_ij[2]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[0][1]=(-dis_ij[0]*r_ij*r_jk-cosAng_ijk
*dis_jk[0]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][1]=(-dis_ij[1]*r_ij*r_jk-cosAng_ijk
*dis_jk[1]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][1]=(-dis_ij[2]*r_ij*r_jk-cosAng_ijk
*dis_jk[2]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng_ijk;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][jtype-1];
gmean1=sigma_g1[itype-1][ktype-1][jtype-1];
gmean2=sigma_g2[itype-1][ktype-1][jtype-1];
cosAng_ikj=(dis_ik[0]*dis_jk[0]+dis_ik[1]*dis_jk[1]
+dis_ik[2]*dis_jk[2])/(r_ik*r_jk);
dcA_ikj[0][0]=(-dis_jk[0]*r_ik*r_jk-cosAng_ikj
*-dis_ik[0]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[1][0]=(-dis_jk[1]*r_ik*r_jk-cosAng_ikj
*-dis_ik[1]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[2][0]=(-dis_jk[2]*r_ik*r_jk-cosAng_ikj
*-dis_ik[2]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[0][1]=(-dis_ik[0]*r_ik*r_jk-cosAng_ikj
*-dis_jk[0]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[1][1]=(-dis_ik[1]*r_ik*r_jk-cosAng_ikj
*-dis_jk[1]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[2][1]=(-dis_ik[2]*r_ik*r_jk-cosAng_ikj
*-dis_jk[2]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
amean=cosAng_ikj;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactor=betaS_ik*betaS_jkp;
//EE1 is (b) Eq. 12
EE1=EE1+gfactor*rfactor;
//rcm1 is derivative of EE1 w.r.t Beta(r_ik)
//rcm2 is derivative of EE1 w.r.t Beta(r_jk')
//gcm1 is derivative of EE1 w.r.t cos(theta_jik)
//gcm2 is derivative of EE1 w.r.t cos(theta_ijk)
//gcm3 is derivative of EE1 w.r.t cos(theta_ikj)
rcm1=gfactor*betaS_jkp*dBetaS_ik/r_ik;
rcm2=gfactor*betaS_ik*dBetaS_jkp/r_jkp;
gcm1=rfactor*gprime1*gfactor2*gfactor3;
gcm2=rfactor*gfactor1*gprime2*gfactor3;
gcm3=rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dEE1[0]+=
gcm1*dcA_jik[0][0]
-gcm2*dcA_ijk[0][0];
bt_sg[nb_ij].dEE1[1]+=
gcm1*dcA_jik[1][0]
-gcm2*dcA_ijk[1][0];
bt_sg[nb_ij].dEE1[2]+=
gcm1*dcA_jik[2][0]
-gcm2*dcA_ijk[2][0];
bt_sg[nb_ik].dEE1[0]+=
gcm1*dcA_jik[0][1]
+rcm1*dis_ik[0]
-gcm3*dcA_ikj[0][0];
bt_sg[nb_ik].dEE1[1]+=
gcm1*dcA_jik[1][1]
+rcm1*dis_ik[1]
-gcm3*dcA_ikj[1][0];
bt_sg[nb_ik].dEE1[2]+=
gcm1*dcA_jik[2][1]
+rcm1*dis_ik[2]
-gcm3*dcA_ikj[2][0];
bt_sg[nb_jk].dEE1[0]+=
gcm2*dcA_ijk[0][1]
+rcm2*dis_jkp[0]
-gcm3*dcA_ikj[0][1];
bt_sg[nb_jk].dEE1[1]+=
gcm2*dcA_ijk[1][1]
+rcm2*dis_jkp[1]
-gcm3*dcA_ikj[1][1];
bt_sg[nb_jk].dEE1[2]+=
gcm2*dcA_ijk[2][1]
+rcm2*dis_jkp[2]
-gcm3*dcA_ikj[2][1];
}
}
// k and k' and j are all different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
kp=iilist[ltmp];;
kptype = map[type[kp]]+1;
if(itype==kptype)
iikp=itype-1;
else if(itype<kptype)
iikp=itype*bop_types-itype*(itype+1)/2+kptype-1;
else
iikp=kptype*bop_types-kptype*(kptype+1)/2+itype-1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
dis_ikp[0]=x[kp][0]-x[i][0];
dis_ikp[1]=x[kp][1]-x[i][1];
dis_ikp[2]=x[kp][2]-x[i][2];
rsq_ikp=dis_ikp[0]*dis_ikp[0]
+dis_ikp[1]*dis_ikp[1]
+dis_ikp[2]*dis_ikp[2];
r_ikp=sqrt(rsq_ikp);
if(r_ikp<=rcut[iikp]) {
ps=r_ikp*rdr[iikp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ikp=((pBetaS3[iikp][ks-1]*ps+pBetaS2[iikp][ks-1])*ps
+pBetaS1[iikp][ks-1])*ps+pBetaS[iikp][ks-1];
dBetaS_ikp=(pBetaS6[iikp][ks-1]*ps+pBetaS5[iikp][ks-1])*ps
+pBetaS4[iikp][ks-1];
betaP_ikp=((pBetaP3[iikp][ks-1]*ps+pBetaP2[iikp][ks-1])*ps
+pBetaP1[iikp][ks-1])*ps+pBetaP[iikp][ks-1];
dBetaP_ikp=(pBetaP6[iikp][ks-1]*ps+pBetaP5[iikp][ks-1])*ps
+pBetaP4[iikp][ks-1];
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ikp].temp=temp_ikp;
bt_sg[nb_ikp].i=i;
bt_sg[nb_ikp].j=kp;
gmean0=sigma_g0[jtype-1][itype-1][kptype-1];
gmean1=sigma_g1[jtype-1][itype-1][kptype-1];
gmean2=sigma_g2[jtype-1][itype-1][kptype-1];
cosAng_jikp=(dis_ij[0]*dis_ikp[0]+dis_ij[1]*dis_ikp[1]
+dis_ij[2]*dis_ikp[2])/(r_ij*r_ikp);
dcA_jikp[0][0]=(dis_ikp[0]*r_ij*r_ikp-cosAng_jikp
*dis_ij[0]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][0]=(dis_ikp[1]*r_ij*r_ikp-cosAng_jikp
*dis_ij[1]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][0]=(dis_ikp[2]*r_ij*r_ikp-cosAng_jikp
*dis_ij[2]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[0][1]=(dis_ij[0]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[0]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][1]=(dis_ij[1]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[1]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][1]=(dis_ij[2]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[2]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
cosAng_kikp=(dis_ik[0]*dis_ikp[0]+dis_ik[1]*dis_ikp[1]
+dis_ik[2]*dis_ikp[2])/(r_ik*r_ikp);
dcA_kikp[0][0]=(dis_ikp[0]*r_ik*r_ikp-cosAng_kikp
*dis_ik[0]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[1][0]=(dis_ikp[1]*r_ik*r_ikp-cosAng_kikp
*dis_ik[1]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[2][0]=(dis_ikp[2]*r_ik*r_ikp-cosAng_kikp
*dis_ik[2]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[0][1]=(dis_ik[0]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[0]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[1][1]=(dis_ik[1]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[1]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[2][1]=(dis_ik[2]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[2]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
amean=cosAng_jikp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][itype-1][kptype-1];
gmean1=sigma_g1[ktype-1][itype-1][kptype-1];
gmean2=sigma_g2[ktype-1][itype-1][kptype-1];
amean=cosAng_kikp;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS_ik*betaS_ikp;
rfactor=rfactorrt*rfactorrt;
//2nd CC is second term of Eq. 11 (c) for i atom where j , k & k' =neighbor of i
CC=CC+2.0*gfactor*rfactor;
//agpdpr1 is derivative of CC 2nd term w.r.t. Beta(r_ik)
//agpdpr2 is derivative of CC 2nd term w.r.t. Beta(r_ik')
//app1 is derivative of CC 2nd term w.r.t. cos(theta_jik)
//app2 is derivative of CC 2nd term w.r.t. cos(theta_jik')
//app3 is derivative of CC 2nd term w.r.t. cos(theta_kik')
agpdpr1=4.0*gfactor*rfactorrt*betaS_ikp
*dBetaS_ik/r_ik;
agpdpr2=4.0*gfactor*rfactorrt*betaS_ik
*dBetaS_ikp/r_ikp;
app1=2.0*rfactor*gfactor2*gfactor3*gprime1;
app2=2.0*rfactor*gfactor1*gfactor3*gprime2;
app3=2.0*rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dCC[0]+=
app1*dcA_jik[0][0]
+app2*dcA_jikp[0][0];
bt_sg[nb_ij].dCC[1]+=
app1*dcA_jik[1][0]
+app2*dcA_jikp[1][0];
bt_sg[nb_ij].dCC[2]+=
app1*dcA_jik[2][0]
+app2*dcA_jikp[2][0];
bt_sg[nb_ik].dCC[0]+=
app1*dcA_jik[0][1]
+app3*dcA_kikp[0][0]
+agpdpr1*dis_ik[0];
bt_sg[nb_ik].dCC[1]+=
app1*dcA_jik[1][1]
+app3*dcA_kikp[1][0]
+agpdpr1*dis_ik[1];
bt_sg[nb_ik].dCC[2]+=
app1*dcA_jik[2][1]
+app3*dcA_kikp[2][0]
+agpdpr1*dis_ik[2];
bt_sg[nb_ikp].dCC[0]=
app2*dcA_jikp[0][1]
+app3*dcA_kikp[0][1]
+agpdpr2*dis_ikp[0];
bt_sg[nb_ikp].dCC[1]=
app2*dcA_jikp[1][1]
+app3*dcA_kikp[1][1]
+agpdpr2*dis_ikp[1];
bt_sg[nb_ikp].dCC[2]=
app2*dcA_jikp[2][1]
+app3*dcA_kikp[2][1]
+agpdpr2*dis_ikp[2];
}
}
}
// j and k are different neighbors of i and k' is a neighbor k not equal to i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
kp=klist[ltmp];;
kptype = map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(ktype==kptype)
ikkp=ktype-1;
else if(ktype<kptype)
ikkp=ktype*bop_types-ktype*(ktype+1)/2+kptype-1;
else
ikkp=kptype*bop_types-kptype*(kptype+1)/2+ktype-1;
dis_kkp[0]=x[kp][0]-x[k][0];
dis_kkp[1]=x[kp][1]-x[k][1];
dis_kkp[2]=x[kp][2]-x[k][2];
rsq_kkp=dis_kkp[0]*dis_kkp[0]
+dis_kkp[1]*dis_kkp[1]
+dis_kkp[2]*dis_kkp[2];
r_kkp=sqrt(rsq_kkp);
if(r_kkp<=rcut[ikkp]) {
ps=r_kkp*rdr[ikkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_kkp=((pBetaS3[ikkp][ks-1]*ps+pBetaS2[ikkp][ks-1])*ps
+pBetaS1[ikkp][ks-1])*ps+pBetaS[ikkp][ks-1];
dBetaS_kkp=(pBetaS6[ikkp][ks-1]*ps+pBetaS5[ikkp][ks-1])*ps
+pBetaS4[ikkp][ks-1];
betaP_kkp=((pBetaP3[ikkp][ks-1]*ps+pBetaP2[ikkp][ks-1])*ps
+pBetaP1[ikkp][ks-1])*ps+pBetaP[ikkp][ks-1];
dBetaP_kkp=(pBetaP6[ikkp][ks-1]*ps+pBetaP5[ikkp][ks-1])*ps
+pBetaP4[ikkp][ks-1];
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
sig_flag=1;
nkp=nsearch;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
cosAng_ikkp=(-dis_ik[0]*dis_kkp[0]-dis_ik[1]*dis_kkp[1]
-dis_ik[2]*dis_kkp[2])/(r_ik*r_kkp);
dcA_ikkp[0][0]=(dis_kkp[0]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[0]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[1][0]=(dis_kkp[1]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[1]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[2][0]=(dis_kkp[2]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[2]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[0][1]=(-dis_ik[0]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[0]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[1][1]=(-dis_ik[1]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[1]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[2][1]=(-dis_ik[2]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[2]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng_ikkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS_ik*betaS_kkp;
rfactor=rfactorrt*rfactorrt;
//3rd CC is third term of Eq. 11 (c) for i atom
//where j , k =neighbor of i & k' =neighbor of k
CC=CC+gfactor*rfactor;
//agpdpr1 is derivative of CC 3rd term w.r.t. Beta(r_ik)
//agpdpr2 is derivative of CC 3rd term w.r.t. Beta(r_kk')
//app1 is derivative of CC 3rd term w.r.t. cos(theta_jik)
//app2 is derivative of CC 3rd term w.r.t. cos(theta_ikk')
agpdpr1=2.0*gfactor*rfactorrt*betaS_kkp
*dBetaS_ik/r_ik;
agpdpr2=2.0*gfactor*rfactorrt*betaS_ik
*dBetaS_kkp/r_kkp;
app1=rfactor*gfactorsq2*gsqprime;
app2=rfactor*gfactorsq*gsqprime2;
bt_sg[nb_ij].dCC[0]+=
app1*dcA_jik[0][0];
bt_sg[nb_ij].dCC[1]+=
app1*dcA_jik[1][0];
bt_sg[nb_ij].dCC[2]+=
app1*dcA_jik[2][0];
bt_sg[nb_ik].dCC[0]+=
app1*dcA_jik[0][1]
+agpdpr1*dis_ik[0]
-app2*dcA_ikkp[0][0];
bt_sg[nb_ik].dCC[1]+=
app1*dcA_jik[1][1]
+agpdpr1*dis_ik[1]
-app2*dcA_ikkp[1][0];
bt_sg[nb_ik].dCC[2]+=
app1*dcA_jik[2][1]
+agpdpr1*dis_ik[2]
-app2*dcA_ikkp[2][0];
bt_sg[nb_kkp].dCC[0]+=
app2*dcA_ikkp[0][1]
+agpdpr2*dis_kkp[0];
bt_sg[nb_kkp].dCC[1]+=
app2*dcA_ikkp[1][1]
+agpdpr2*dis_kkp[1];
bt_sg[nb_kkp].dCC[2]+=
app2*dcA_ikkp[2][1]
+agpdpr2*dis_kkp[2];
}
}
}
//j and k are different neighbors of i and k' is a neighbor j not equal to k
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
sig_flag=0;
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
kptype = map[type[kp]]+1;
kplist=firstneigh[kp];
same_kkpk=0;
same_jkpj=0;
for(kpNeij=0;kpNeij<numneigh[kp];kpNeij++) {
temp_kpj=BOP_index[kp]+kpNeij;
kpj=kplist[kpNeij];
if(x[j][0]==x[kpj][0]) {
if(x[j][1]==x[kpj][1]) {
if(x[j][2]==x[kpj][2]) {
same_jkpj=1;
break;
}
}
}
}
for(kpNeik=0;kpNeik<numneigh[kp];kpNeik++) {
temp_kpk=BOP_index[kp]+kpNeik;
kpk=kplist[kpNeik];
if(x[k][0]==x[kpk][0]) {
if(x[k][1]==x[kpk][1]) {
if(x[k][2]==x[kpk][2]) {
same_kkpk=1;
break;
}
}
}
}
if(!same_jkpj&&!same_kkpk) {
same_kkpk=0;
for(kNeikp=0;kNeikp<numneigh[k];kNeikp++) {
temp_kkp=BOP_index[k]+kNeikp;
kkp=kplist[kNeikp];
if(x[kp][0]==x[kkp][0]) {
if(x[kp][1]==x[kkp][1]) {
if(x[kp][2]==x[kkp][2]) {
sig_flag=1;
break;
}
}
}
}
if(sig_flag==1) {
for(nsearch=0;nsearch<numneigh[kp];nsearch++) {
kp_nsearch=BOP_index[kp]+nsearch;
ncmp=kplist[nsearch];
if(x[ncmp][0]==x[j][0]) {
if(x[ncmp][1]==x[j][1]) {
if(x[ncmp][2]==x[j][2]) {
kpNeij=nsearch;
}
}
}
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
kpNeik=nsearch;
}
}
}
}
if(jtype==kptype)
ijkp=jtype-1;
else if(jtype<kptype)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kptype-1;
else
ijkp=kptype*bop_types-kptype*(kptype+1)/2+jtype-1;
if(ktype==kptype)
ikkp=ktype-1;
else if(ktype<kptype)
ikkp=ktype*bop_types-ktype*(ktype+1)/2+kptype-1;
else
ikkp=kptype*bop_types-kptype*(kptype+1)/2+ktype-1;
dis_jkp[0]=x[kp][0]-x[j][0];
dis_jkp[1]=x[kp][1]-x[j][1];
dis_jkp[2]=x[kp][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
dis_kkp[0]=x[kp][0]-x[k][0];
dis_kkp[1]=x[kp][1]-x[k][1];
dis_kkp[2]=x[kp][2]-x[k][2];
rsq_kkp=dis_kkp[0]*dis_kkp[0]
+dis_kkp[1]*dis_kkp[1]
+dis_kkp[2]*dis_kkp[2];
r_kkp=sqrt(rsq_kkp);
ps=r_kkp*rdr[ikkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_kkp=((pBetaS3[ikkp][ks-1]*ps+pBetaS2[ikkp][ks-1])*ps
+pBetaS1[ikkp][ks-1])*ps+pBetaS[ikkp][ks-1];
dBetaS_kkp=(pBetaS6[ikkp][ks-1]*ps+pBetaS5[ikkp][ks-1])*ps
+pBetaS4[ikkp][ks-1];
betaP_kkp=((pBetaP3[ikkp][ks-1]*ps+pBetaP2[ikkp][ks-1])*ps
+pBetaP1[ikkp][ks-1])*ps+pBetaP[ikkp][ks-1];
dBetaP_kkp=(pBetaP6[ikkp][ks-1]*ps+pBetaP5[ikkp][ks-1])*ps
+pBetaP4[ikkp][ks-1];
cosAng_ijkp=(-dis_ij[0]*dis_jkp[0]-dis_ij[1]*dis_jkp[1]
-dis_ij[2]*dis_jkp[2])/(r_ij*r_jkp);
dcA_ijkp[0][0]=(dis_jkp[0]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[0]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][0]=(dis_jkp[1]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[1]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][0]=(dis_jkp[2]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[2]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[0][1]=(-dis_ij[0]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[0]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][1]=(-dis_ij[1]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[1]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][1]=(-dis_ij[2]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[2]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
cosAng_ikkp=(-dis_ik[0]*dis_kkp[0]-dis_ik[1]*dis_kkp[1]
-dis_ik[2]*dis_kkp[2])/(r_ik*r_kkp);
dcA_ikkp[0][0]=(dis_kkp[0]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[0]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[1][0]=(dis_kkp[1]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[1]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[2][0]=(dis_kkp[2]*r_ik*r_kkp-cosAng_ikkp
*-dis_ik[2]*r_kkp*r_kkp)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[0][1]=(-dis_ik[0]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[0]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[1][1]=(-dis_ik[1]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[1]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
dcA_ikkp[2][1]=(-dis_ik[2]*r_ik*r_kkp-cosAng_ikkp
*dis_kkp[2]*r_ik*r_ik)/(r_ik*r_ik*r_kkp*r_kkp);
cosAng_jkpk=(dis_jkp[0]*dis_kkp[0]+dis_jkp[1]*dis_kkp[1]
+dis_jkp[2]*dis_kkp[2])/(r_jkp*r_kkp);
dcA_jkpk[0][0]=(-dis_kkp[0]*r_jkp*r_kkp-cosAng_jkpk
*-dis_jkp[0]*r_kkp*r_kkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
dcA_jkpk[1][0]=(-dis_kkp[1]*r_jkp*r_kkp-cosAng_jkpk
*-dis_jkp[1]*r_kkp*r_kkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
dcA_jkpk[2][0]=(-dis_kkp[2]*r_jkp*r_kkp-cosAng_jkpk
*-dis_jkp[2]*r_kkp*r_kkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
dcA_jkpk[0][1]=(-dis_jkp[0]*r_jkp*r_kkp-cosAng_jkpk
*-dis_kkp[0]*r_jkp*r_jkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
dcA_jkpk[1][1]=(-dis_jkp[1]*r_jkp*r_kkp-cosAng_jkpk
*-dis_kkp[1]*r_jkp*r_jkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
dcA_jkpk[2][1]=(-dis_jkp[2]*r_jkp*r_kkp-cosAng_jkpk
*-dis_kkp[2]*r_jkp*r_jkp)/(r_jkp*r_jkp*r_kkp*r_kkp);
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
nkp=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
temp_kpk=BOP_index[kp]+kpNeik;
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jkp].temp=temp_jkp;
bt_sg[nb_jkp].i=j;
bt_sg[nb_jkp].j=kp;
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng_ijkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng_ikkp;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[jtype-1][kptype-1][ktype-1];
gmean1=sigma_g1[jtype-1][kptype-1][ktype-1];
gmean2=sigma_g2[jtype-1][kptype-1][ktype-1];
amean=cosAng_jkpk;
gfactor4=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime4=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3*gfactor4;
rfactor0=(betaS_ik+small2)*(betaS_jkp+small2)
*(betaS_kkp+small2);
rfactor=pow(rfactor0,2.0/3.0);
drfactor=2.0/3.0*pow(rfactor0,-1.0/3.0);
//EE is Eq. 25(notes)
EE=EE+gfactor*rfactor;
//agpdpr1 is derivative of agpdpr1 w.r.t. Beta(r_ik)
//agpdpr2 is derivative of agpdpr1 w.r.t. Beta(r_jk')
//agpdpr3 is derivative of agpdpr1 w.r.t. Beta(r_kk')
//app1 is derivative of agpdpr1 w.r.t. cos(theta_jik)
//app2 is derivative of agpdpr1 w.r.t. cos(theta_ijk')
//app3 is derivative of agpdpr1 w.r.t. cos(theta_ikk')
//app4 is derivative of agpdpr1 w.r.t. cos(theta_jk'k)
agpdpr1=gfactor*drfactor*(betaS_jkp+small2)*(betaS_kkp
+small2)*dBetaS_ik/r_ik;
agpdpr2=gfactor*drfactor*(betaS_ik+small2)*(betaS_kkp
+small2)*dBetaS_jkp/r_jkp;
agpdpr3=gfactor*drfactor*(betaS_ik+small2)*(betaS_jkp
+small2)*dBetaS_kkp/r_kkp;
app1=rfactor*gfactor2*gfactor3*gfactor4*gprime1;
app2=rfactor*gfactor1*gfactor3*gfactor4*gprime2;
app3=rfactor*gfactor1*gfactor2*gfactor4*gprime3;
app4=rfactor*gfactor1*gfactor2*gfactor3*gprime4;
bt_sg[nb_ij].dEE[0]+=
app1*dcA_jik[0][0]
-app2*dcA_ijkp[0][0];
bt_sg[nb_ij].dEE[1]+=
app1*dcA_jik[1][0]
-app2*dcA_ijkp[1][0];
bt_sg[nb_ij].dEE[2]+=
app1*dcA_jik[2][0]
-app2*dcA_ijkp[2][0];
bt_sg[nb_ik].dEE[0]+=
app1*dcA_jik[0][1]
+agpdpr1*dis_ik[0]
-app3*dcA_ikkp[0][0];
bt_sg[nb_ik].dEE[1]+=
app1*dcA_jik[1][1]
+agpdpr1*dis_ik[1]
-app3*dcA_ikkp[1][0];
bt_sg[nb_ik].dEE[2]+=
app1*dcA_jik[2][1]
+agpdpr1*dis_ik[2]
-app3*dcA_ikkp[2][0];
bt_sg[nb_jkp].dEE[0]+=
app2*dcA_ijkp[0][1]
+agpdpr2*dis_jkp[0]
-app4*dcA_jkpk[0][0];
bt_sg[nb_jkp].dEE[1]+=
app2*dcA_ijkp[1][1]
+agpdpr2*dis_jkp[1]
-app4*dcA_jkpk[1][0];
bt_sg[nb_jkp].dEE[2]+=
app2*dcA_ijkp[2][1]
+agpdpr2*dis_jkp[2]
-app4*dcA_jkpk[2][0];
bt_sg[nb_kkp].dEE[0]+=
app3*dcA_ikkp[0][1]
+agpdpr3*dis_kkp[0]
-app4*dcA_jkpk[0][1];
bt_sg[nb_kkp].dEE[1]+=
app3*dcA_ikkp[1][1]
+agpdpr3*dis_kkp[1]
-app4*dcA_jkpk[1][1];
bt_sg[nb_kkp].dEE[2]+=
app3*dcA_ikkp[2][1]
+agpdpr3*dis_kkp[2]
-app4*dcA_jkpk[2][1];
}
}
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ji) {
temp_jk=BOP_index[j]+ktmp;
k=jlist[ktmp];
klist=firstneigh[k];
ktype=map[type[k]]+1;
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
if(jtype==ktype)
ijk=jtype-1;
else if(jtype<ktype)
ijk=jtype*bop_types-jtype*(jtype+1)/2+ktype-1;
else
ijk=ktype*bop_types-ktype*(ktype+1)/2+jtype-1;
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
new1=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new1=nSigBk[n]-1;
itypeSigBk[n][new1]=k;
}
dis_jk[0]=x[k][0]-x[j][0];
dis_jk[1]=x[k][1]-x[j][1];
dis_jk[2]=x[k][2]-x[j][2];
rsq_jk=dis_jk[0]*dis_jk[0]
+dis_jk[1]*dis_jk[1]
+dis_jk[2]*dis_jk[2];
r_jk=sqrt(rsq_jk);
if(r_jk<=rcut[ijk]) {
ps=r_jk*rdr[ijk]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jk=((pBetaS3[ijk][ks-1]*ps+pBetaS2[ijk][ks-1])*ps
+pBetaS1[ijk][ks-1])*ps+pBetaS[ijk][ks-1];
dBetaS_jk=(pBetaS6[ijk][ks-1]*ps+pBetaS5[ijk][ks-1])*ps
+pBetaS4[ijk][ks-1];
betaP_jk=((pBetaP3[ijk][ks-1]*ps+pBetaP2[ijk][ks-1])*ps
+pBetaP1[ijk][ks-1])*ps+pBetaP[ijk][ks-1];
dBetaP_jk=(pBetaP6[ijk][ks-1]*ps+pBetaP5[ijk][ks-1])*ps
+pBetaP4[ijk][ks-1];
cosAng_ijk=(-dis_ij[0]*dis_jk[0]-dis_ij[1]*dis_jk[1]
-dis_ij[2]*dis_jk[2])/(r_ij*r_jk);
dcA_ijk[0][0]=(dis_jk[0]*r_ij*r_jk-cosAng_ijk
*-dis_ij[0]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][0]=(dis_jk[1]*r_ij*r_jk-cosAng_ijk
*-dis_ij[1]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][0]=(dis_jk[2]*r_ij*r_jk-cosAng_ijk
*-dis_ij[2]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[0][1]=(-dis_ij[0]*r_ij*r_jk-cosAng_ijk
*dis_jk[0]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][1]=(-dis_ij[1]*r_ij*r_jk-cosAng_ijk
*dis_jk[1]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][1]=(-dis_ij[2]*r_ij*r_jk-cosAng_ijk
*dis_jk[2]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng_ijk;
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime1=gmean1+2.0*gmean2*amean;
gfactorsq=gfactor1*gfactor1;
gsqprime=2.0*gfactor1*gprime1;
rfactor1rt=betaS_jk*betaS_jk;
rfactor1=rfactor1rt*rfactor1rt;
//BB is Eq. 34 (a) or Eq. 10 (c) for the j atom
//1st DD is Eq. 11 (c) for j atom where i & k=neighbor of j
BB=BB+gfactorsq*rfactor1rt;
DD=DD+gfactorsq*rfactor1;
//agpdpr1 is derivative of BB w.r.t. Beta(r_jk)
//app1 is derivative of BB w.r.t. cos(theta_ijk)
agpdpr1=2.0*gfactorsq*betaS_jk*dBetaS_jk/r_jk;
agpdpr2=2.0*rfactor1rt*agpdpr1;
app1=rfactor1rt*gsqprime;
app2=rfactor1rt*app1;
bt_sg[nb_ij].dBB[0]-=
app1*dcA_ijk[0][0];
bt_sg[nb_ij].dBB[1]-=
app1*dcA_ijk[1][0];
bt_sg[nb_ij].dBB[2]-=
app1*dcA_ijk[2][0];
bt_sg[nb_ij].dDD[0]-=
app2*dcA_ijk[0][0];
bt_sg[nb_ij].dDD[1]-=
app2*dcA_ijk[1][0];
bt_sg[nb_ij].dDD[2]-=
app2*dcA_ijk[2][0];
bt_sg[nb_jk].dBB[0]+=
app1*dcA_ijk[0][1]
+agpdpr1*dis_jk[0];
bt_sg[nb_jk].dBB[1]+=
app1*dcA_ijk[1][1]
+agpdpr1*dis_jk[1];
bt_sg[nb_jk].dBB[2]+=
app1*dcA_ijk[2][1]
+agpdpr1*dis_jk[2];
bt_sg[nb_jk].dDD[0]+=
app2*dcA_ijk[0][1]
+agpdpr2*dis_jk[0];
bt_sg[nb_jk].dDD[1]+=
app2*dcA_ijk[1][1]
+agpdpr2*dis_jk[1];
bt_sg[nb_jk].dDD[2]+=
app2*dcA_ijk[2][1]
+agpdpr2*dis_jk[2];
//j is a neighbor of i, k and k' prime different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ji) {
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
kptype=map[type[kp]]+1;
if(jtype==kptype)
ijkp=jtype-1;
else if(jtype<kptype)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kptype-1;
else
ijkp=kptype*bop_types-kptype*(kptype+1)/2+jtype-1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
break;
}
}
}
}
dis_jkp[0]=x[kp][0]-x[j][0];
dis_jkp[1]=x[kp][1]-x[j][1];
dis_jkp[2]=x[kp][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
if(r_jkp<=rcut[ijkp]) {
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
cosAng_ijkp=(-dis_ij[0]*dis_jkp[0]-dis_ij[1]*dis_jkp[1]
-dis_ij[2]*dis_jkp[2])/(r_ij*r_jkp);
dcA_ijkp[0][0]=(dis_jkp[0]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[0]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][0]=(dis_jkp[1]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[1]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][0]=(dis_jkp[2]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[2]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[0][1]=(-dis_ij[0]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[0]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][1]=(-dis_ij[1]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[1]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][1]=(-dis_ij[2]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[2]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
cosAng_kjkp=(dis_jk[0]*dis_jkp[0]+dis_jk[1]*dis_jkp[1]
+dis_jk[2]*dis_jkp[2])/(r_jk*r_jkp);
dcA_kjkp[0][0]=(dis_jkp[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[0]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][0]=(dis_jkp[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[1]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][0]=(dis_jkp[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[2]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[0][1]=(dis_jk[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[0]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][1]=(dis_jk[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[1]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][1]=(dis_jk[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[2]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jkp].temp=temp_jkp;
bt_sg[nb_jkp].i=j;
bt_sg[nb_jkp].j=kp;
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng_ijkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][jtype-1][kptype-1];
gmean1=sigma_g1[ktype-1][jtype-1][kptype-1];
gmean2=sigma_g2[ktype-1][jtype-1][kptype-1];
amean=cosAng_kjkp;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS_jk*betaS_jkp;
rfactor=rfactorrt*rfactorrt;
//2nd DD is Eq. 11 (c) for j atom where i , k & k'=neighbor of j
DD=DD+2.0*gfactor*rfactor;
//agpdpr1 is derivative of DD w.r.t. Beta(r_jk)
//agpdpr2 is derivative of DD w.r.t. Beta(r_jk')
//app1 is derivative of DD w.r.t. cos(theta_ijk)
//app2 is derivative of DD w.r.t. cos(theta_ijkp)
//app3 is derivative of DD w.r.t. cos(theta_kjkp)
agpdpr1=4.0*gfactor*rfactorrt*betaS_jkp
*dBetaS_jk/r_jk;
agpdpr2=4.0*gfactor*rfactorrt*betaS_jk
*dBetaS_jkp/r_jkp;
app1=2.0*rfactor*gfactor2*gfactor3*gprime1;
app2=2.0*rfactor*gfactor1*gfactor3*gprime2;
app3=2.0*rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dDD[0]-=
app1*dcA_ijk[0][0]
+app2*dcA_ijkp[0][0];
bt_sg[nb_ij].dDD[1]-=
app1*dcA_ijk[1][0]
+app2*dcA_ijkp[1][0];
bt_sg[nb_ij].dDD[2]-=
app1*dcA_ijk[2][0]
+app2*dcA_ijkp[2][0];
bt_sg[nb_jk].dDD[0]+=
app1*dcA_ijk[0][1]
+app3*dcA_kjkp[0][0]
+agpdpr1*dis_jk[0];
bt_sg[nb_jk].dDD[1]+=
app1*dcA_ijk[1][1]
+app3*dcA_kjkp[1][0]
+agpdpr1*dis_jk[1];
bt_sg[nb_jk].dDD[2]+=
app1*dcA_ijk[2][1]
+app3*dcA_kjkp[2][0]
+agpdpr1*dis_jk[2];
bt_sg[nb_jkp].dDD[0]+=
app2*dcA_ijkp[0][1]
+app3*dcA_kjkp[0][1]
+agpdpr2*dis_jkp[0];
bt_sg[nb_jkp].dDD[1]+=
app2*dcA_ijkp[1][1]
+app3*dcA_kjkp[1][1]
+agpdpr2*dis_jkp[1];
bt_sg[nb_jkp].dDD[2]+=
app2*dcA_ijkp[2][1]
+app3*dcA_kjkp[2][1]
+agpdpr2*dis_jkp[2];
}
}
}
//j is a neighbor of i, k is a neighbor of j not equal to i and k'
//is a neighbor of k not equal to j or i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
kp=klist[ltmp];
kptype=map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(ktype==kptype)
ikkp=ktype-1;
else if(ktype<kptype)
ikkp=ktype*bop_types-ktype*(ktype+1)/2+kptype-1;
else
ikkp=kptype*bop_types-kptype*(kptype+1)/2+ktype-1;
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new2=nSigBk[n]-1;
itypeSigBk[n][new2]=kp;
}
dis_kkp[0]=x[kp][0]-x[k][0];
dis_kkp[1]=x[kp][1]-x[k][1];
dis_kkp[2]=x[kp][2]-x[k][2];
rsq_kkp=dis_kkp[0]*dis_kkp[0]
+dis_kkp[1]*dis_kkp[1]
+dis_kkp[2]*dis_kkp[2];
r_kkp=sqrt(rsq_kkp);
if(r_kkp<=rcut[ikkp]) {
ps=r_kkp*rdr[ikkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_kkp=((pBetaS3[ikkp][ks-1]*ps+pBetaS2[ikkp][ks-1])*ps
+pBetaS1[ikkp][ks-1])*ps+pBetaS[ikkp][ks-1];
dBetaS_kkp=(pBetaS6[ikkp][ks-1]*ps+pBetaS5[ikkp][ks-1])*ps
+pBetaS4[ikkp][ks-1];
betaP_kkp=((pBetaP3[ikkp][ks-1]*ps+pBetaP2[ikkp][ks-1])*ps
+pBetaP1[ikkp][ks-1])*ps+pBetaP[ikkp][ks-1];
dBetaP_kkp=(pBetaP6[ikkp][ks-1]*ps+pBetaP5[ikkp][ks-1])*ps
+pBetaP4[ikkp][ks-1];
cosAng_jkkp=(-dis_jk[0]*dis_kkp[0]-dis_jk[1]*dis_kkp[1]
-dis_jk[2]*dis_kkp[2])/(r_jk*r_kkp);
dcA_jkkp[0][0]=(dis_kkp[0]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[0]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[1][0]=(dis_kkp[1]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[1]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[2][0]=(dis_kkp[2]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[2]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[0][1]=(-dis_jk[0]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[0]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[1][1]=(-dis_jk[1]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[1]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[2][1]=(-dis_jk[2]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[2]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[jtype-1][ktype-1][kptype-1];
gmean1=sigma_g1[jtype-1][ktype-1][kptype-1];
gmean2=sigma_g2[jtype-1][ktype-1][kptype-1];
amean=cosAng_jkkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS_jk*betaS_kkp;
rfactor=rfactorrt*rfactorrt;
//3rd DD is Eq. 11 (c) for j atom where i & k=neighbor of j & k'=neighbor of k
DD=DD+gfactor*rfactor;
//agpdpr1 is derivative of DD 3rd term w.r.t. Beta(r_jk)
//agpdpr2 is derivative of DD 3rd term w.r.t. Beta(r_kk')
//app1 is derivative of DD 3rd term w.r.t. cos(theta_ijk)
//app2 is derivative of DD 3rd term w.r.t. cos(theta_jkkp)
agpdpr1=2.0*gfactor*rfactorrt*betaS_kkp
*dBetaS_jk/r_jk;
agpdpr2=2.0*gfactor*rfactorrt*betaS_jk
*dBetaS_kkp/r_kkp;
app1=rfactor*gfactorsq2*gsqprime;
app2=rfactor*gfactorsq*gsqprime2;
bt_sg[nb_ij].dDD[0]-=
app1*dcA_ijk[0][0];
bt_sg[nb_ij].dDD[1]-=
app1*dcA_ijk[1][0];
bt_sg[nb_ij].dDD[2]-=
app1*dcA_ijk[2][0];
bt_sg[nb_jk].dDD[0]+=
app1*dcA_ijk[0][1]
+agpdpr1*dis_jk[0]
-app2*dcA_jkkp[0][0];
bt_sg[nb_jk].dDD[1]+=
app1*dcA_ijk[1][1]
+agpdpr1*dis_jk[1]
-app2*dcA_jkkp[1][0];
bt_sg[nb_jk].dDD[2]+=
app1*dcA_ijk[2][1]
+agpdpr1*dis_jk[2]
-app2*dcA_jkkp[2][0];
bt_sg[nb_kkp].dDD[0]+=
app2*dcA_jkkp[0][1]
+agpdpr2*dis_kkp[0];
bt_sg[nb_kkp].dDD[1]+=
app2*dcA_jkkp[1][1]
+agpdpr2*dis_kkp[1];
bt_sg[nb_kkp].dDD[2]+=
app2*dcA_jkkp[2][1]
+agpdpr2*dis_kkp[2];
}
}
}
}
}
}
sig_flag=0;
if(FF<=0.000001) {
sigB[n]=0.0;
sig_flag=1;
}
if(sig_flag==0) {
if(AA<0.0)
AA=0.0;
if(BB<0.0)
BB=0.0;
if(CC<0.0)
CC=0.0;
if(DD<0.0)
DD=0.0;
// AA and BB are the representations of (a) Eq. 34 and (b) Eq. 9
// for atoms i and j respectively
AAC=AA+BB;
BBC=AA*BB;
CCC=AA*AA+BB*BB;
DDC=CC+DD;
//EEC is a modified form of (a) Eq. 33
EEC=(DDC-CCC)/(AAC+2.0*small1);
AACFF=1.0/(AAC+2.0*small1);
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_sg[m].dAAC[0]=bt_sg[m].dAA[0]
+bt_sg[m].dBB[0];
bt_sg[m].dAAC[1]=bt_sg[m].dAA[1]
+bt_sg[m].dBB[1];
bt_sg[m].dAAC[2]=bt_sg[m].dAA[2]
+bt_sg[m].dBB[2];
bt_sg[m].dBBC[0]=bt_sg[m].dAA[0]*BB
+AA*bt_sg[m].dBB[0];
bt_sg[m].dBBC[1]=bt_sg[m].dAA[1]*BB
+AA*bt_sg[m].dBB[1];
bt_sg[m].dBBC[2]=bt_sg[m].dAA[2]*BB
+AA*bt_sg[m].dBB[2];
bt_sg[m].dCCC[0]=2.0*AA*bt_sg[m].dAA[0]
+2.0*BB*bt_sg[m].dBB[0];
bt_sg[m].dCCC[1]=2.0*AA*bt_sg[m].dAA[1]
+2.0*BB*bt_sg[m].dBB[1];
bt_sg[m].dCCC[2]=2.0*AA*bt_sg[m].dAA[2]
+2.0*BB*bt_sg[m].dBB[2];
bt_sg[m].dDDC[0]=bt_sg[m].dCC[0]
+bt_sg[m].dDD[0];
bt_sg[m].dDDC[1]=bt_sg[m].dCC[1]
+bt_sg[m].dDD[1];
bt_sg[m].dDDC[2]=bt_sg[m].dCC[2]
+bt_sg[m].dDD[2];
bt_sg[m].dEEC[0]=(bt_sg[m].dDDC[0]
-bt_sg[m].dCCC[0]
-EEC*bt_sg[m].dAAC[0])*AACFF;
bt_sg[m].dEEC[1]=(bt_sg[m].dDDC[1]
-bt_sg[m].dCCC[1]
-EEC*bt_sg[m].dAAC[1])*AACFF;
bt_sg[m].dEEC[2]=(bt_sg[m].dDDC[2]
-bt_sg[m].dCCC[2]
-EEC*bt_sg[m].dAAC[2])*AACFF;
}
}
UT=EEC*FF+BBC+small3[iij];
UT=1.0/sqrt(UT);
// FFC is slightly modified form of (a) Eq. 31
// GGC is slightly modified form of (a) Eq. 32
// bndtmp is a slightly modified form of (a) Eq. 30 and (b) Eq. 8
FFC=BBC*UT;
GGC=EEC*UT;
bndtmp=(FF+sigma_delta[iij]*sigma_delta[iij])*(1.0+sigma_a[iij]*GGC)
*(1.0+sigma_a[iij]*GGC)+sigma_c[iij]*(AAC+sigma_a[iij]*EE
+sigma_a[iij]*FFC*(2.0+GGC))+small4;
UTcom=-0.5*UT*UT*UT;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_sg[m].dUT[0]=UTcom*(bt_sg[m].dEEC[0]*FF
+EEC*bt_sg[m].dFF[0]+bt_sg[m].dBBC[0]);
bt_sg[m].dUT[1]=UTcom*(bt_sg[m].dEEC[1]*FF
+EEC*bt_sg[m].dFF[1]+bt_sg[m].dBBC[1]);
bt_sg[m].dUT[2]=UTcom*(bt_sg[m].dEEC[2]*FF
+EEC*bt_sg[m].dFF[2]+bt_sg[m].dBBC[2]);
bt_sg[m].dFFC[0]=bt_sg[m].dBBC[0]*UT
+BBC*bt_sg[m].dUT[0];
bt_sg[m].dFFC[1]=bt_sg[m].dBBC[1]*UT
+BBC*bt_sg[m].dUT[1];
bt_sg[m].dFFC[2]=bt_sg[m].dBBC[2]*UT
+BBC*bt_sg[m].dUT[2];
bt_sg[m].dGGC[0]=bt_sg[m].dEEC[0]*UT
+EEC*bt_sg[m].dUT[0];
bt_sg[m].dGGC[1]=bt_sg[m].dEEC[1]*UT
+EEC*bt_sg[m].dUT[1];
bt_sg[m].dGGC[2]=bt_sg[m].dEEC[2]*UT
+EEC*bt_sg[m].dUT[2];
}
}
psign=1.0;
if(1.0+sigma_a[iij]*GGC<0.0)
psign=-1.0;
bndtmp0=1.0/sqrt(bndtmp);
sigB1[n]=psign*betaS_ij*(1.0+sigma_a[iij]*GGC)*bndtmp0;
bndtmp=-0.5*bndtmp0*bndtmp0*bndtmp0;
bndtmp1=psign*(1.0+sigma_a[iij]*GGC)*bndtmp0+psign*betaS_ij
*(1.0+sigma_a[iij]*GGC)*bndtmp*2.0*betaS_ij*(1.0
+sigma_a[iij]*GGC)*(1.0+sigma_a[iij]*GGC);
bndtmp1=bndtmp1*dBetaS_ij/r_ij;
bndtmp2=psign*betaS_ij*(1.0+sigma_a[iij]*GGC)*bndtmp*sigma_c[iij];
bndtmp3=psign*betaS_ij*(1.0+sigma_a[iij]*GGC)
*bndtmp*sigma_c[iij]*sigma_a[iij];
bndtmp4=psign*betaS_ij*(1.0+sigma_a[iij]*GGC)
*bndtmp*sigma_c[iij]*sigma_a[iij]*(2.0+GGC);
bndtmp5=sigma_a[iij]*psign*betaS_ij*bndtmp0
+psign*betaS_ij*(1.0+sigma_a[iij]*GGC)*bndtmp
*(2.0*(FF+sigma_delta[iij]*sigma_delta[iij])*(1.0
+sigma_a[iij]*GGC)*sigma_a[iij]+sigma_c[iij]*sigma_a[iij]*FFC);
setting=0;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
if(temp_kk==temp_ij&&setting==0) {
bt_sg[m].dSigB1[0]=bndtmp1*dis_ij[0]
+(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=bndtmp1*dis_ij[1]
+(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=bndtmp1*dis_ij[2]
+(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
setting=1;
}
else if(temp_kk==temp_ji&&setting==0) {
bt_sg[m].dSigB1[0]=-bndtmp1*dis_ij[0]
+(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=-bndtmp1*dis_ij[1]
+(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=-bndtmp1*dis_ij[2]
+(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
setting=1;
}
else {
bt_sg[m].dSigB1[0]=(bndtmp2*bt_sg[m].dAAC[0]
+bndtmp3*bt_sg[m].dEE[0]
+bndtmp4*bt_sg[m].dFFC[0]
+bndtmp5*bt_sg[m].dGGC[0]);
bt_sg[m].dSigB1[1]=(bndtmp2*bt_sg[m].dAAC[1]
+bndtmp3*bt_sg[m].dEE[1]
+bndtmp4*bt_sg[m].dFFC[1]
+bndtmp5*bt_sg[m].dGGC[1]);
bt_sg[m].dSigB1[2]=(bndtmp2*bt_sg[m].dAAC[2]
+bndtmp3*bt_sg[m].dEE[2]
+bndtmp4*bt_sg[m].dFFC[2]
+bndtmp5*bt_sg[m].dGGC[2]);
}
}
}
//This loop is to ensure there is not an error for atoms with no neighbors (deposition)
if(nb_t==0) {
if(j>i) {
bt_sg[0].dSigB1[0]=bndtmp1*dis_ij[0];
bt_sg[0].dSigB1[1]=bndtmp1*dis_ij[1];
bt_sg[0].dSigB1[2]=bndtmp1*dis_ij[2];
}
else {
bt_sg[0].dSigB1[0]=-bndtmp1*dis_ij[0];
bt_sg[0].dSigB1[1]=-bndtmp1*dis_ij[1];
bt_sg[0].dSigB1[2]=-bndtmp1*dis_ij[2];
}
for(pp=0;pp<3;pp++) {
bt_sg[0].dAA[pp]=0.0;
bt_sg[0].dBB[pp]=0.0;
bt_sg[0].dCC[pp]=0.0;
bt_sg[0].dDD[pp]=0.0;
bt_sg[0].dEE[pp]=0.0;
bt_sg[0].dEE1[pp]=0.0;
bt_sg[0].dFF[pp]=0.0;
bt_sg[0].dAAC[pp]=0.0;
bt_sg[0].dBBC[pp]=0.0;
bt_sg[0].dCCC[pp]=0.0;
bt_sg[0].dDDC[pp]=0.0;
bt_sg[0].dEEC[pp]=0.0;
bt_sg[0].dFFC[pp]=0.0;
bt_sg[0].dGGC[pp]=0.0;
bt_sg[0].dUT[pp]=0.0;
bt_sg[0].dSigB1[pp]=0.0;
bt_sg[0].dSigB[pp]=0.0;
}
bt_sg[0].i=i;
bt_sg[0].j=j;
bt_sg[0].temp=temp_ij;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
}
ps=sigB1[n]*rdBO+1.0;
ks=(int)ps;
if(nBOt-1<ks)
ks=nBOt-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
dsigB1=((FsigBO3[iij][ks-1]*ps+FsigBO2[iij][ks-1])*ps
+FsigBO1[iij][ks-1])*ps+FsigBO[iij][ks-1];
dsigB2=(FsigBO6[iij][ks-1]*ps+FsigBO5[iij][ks-1])*ps+FsigBO4[iij][ks-1];
part0=(FF+0.5*AAC+small5);
part1=(sigma_f[iij]-0.5)*sigma_k[iij];
part2=1.0-part1*EE1/part0;
part3=dsigB1*part1/part0;
part4=part3/part0*EE1;
// sigB is the final expression for (a) Eq. 6 and (b) Eq. 11
sigB[n]=dsigB1*part2;
pp1=2.0*betaS_ij;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
xtmp[0]=x[bt_j][0]-x[bt_i][0];
xtmp[1]=x[bt_j][1]-x[bt_i][1];
xtmp[2]=x[bt_j][2]-x[bt_i][2];
for(pp=0;pp<3;pp++) {
bt_sg[m].dSigB[pp]=dsigB2*part2*bt_sg[m].dSigB1[pp]
-part3*bt_sg[m].dEE1[pp]
+part4*(bt_sg[m].dFF[pp]
+0.5*bt_sg[m].dAAC[pp]);
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp1*bt_sg[m].dSigB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],xtmp[0],xtmp[1],xtmp[2]);
}
}
}
}
n++;
}
}
}
}
destroy_sigma();
}
/* ---------------------------------------------------------------------- */
/* The formulation differs slightly to avoid negative square roots
in the calculation of Theta_pi,ij of (a) Eq. 36 and (b) Eq. 18
see (d) */
void PairBOP::sigmaBo_noa_otf()
{
int nb_t,new_n_tot;
int n,i,j,k,kp,m,pp;
int itmp,jtmp,ktmp,ltmp,mtmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int kp1,kp2,kp1type;
int iij,iik,ijk,ikkp,ji,iikp,ijkp;
int nkp;
int nk0;
int jNeik,kNeii,kNeij;
int new1,new2,nlocal;
int inum,*ilist,*iilist,*jlist,*klist;
int **firstneigh,*numneigh;
int temp_ij,temp_ik,temp_jkp,temp_kk,temp_jk;
int temp_ji,temp_kkp;
int nb_ij,nb_ik;
int nb_jk,nb_jkp,nb_kkp;
int nsearch;
int sig_flag,setting,ncmp,ks;
int itype,jtype,ktype,kptype;
int bt_i,bt_j,bt_ij;
int same_ikp,same_jkp,same_kpk;
double AA,BB,CC,DD,EE,EE1,FF;
double AAC,BBC,CCC,DDC,EEC,FFC,GGC;
double UT,bndtmp,UTcom;
double amean,gmean0,gmean1,gmean2,ps;
double gfactor1,gprime1,gsqprime;
double gfactorsq,gfactor2,gprime2;
double gfactorsq2,gsqprime2;
double gfactor3,gprime3,gfactor,rfactor;
double rfactorrt,rfactor1rt,rfactor1;
double rcm1,rcm2,gcm1,gcm2,gcm3;
double agpdpr1,app1;
double dsigB1,dsigB2;
double part0,part1,part2,part3,part4;
double psign,bndtmp0,pp1;
double bndtmp1,bndtmp2;
double dis_ij[3],rsq_ij,r_ij;
double betaS_ij,dBetaS_ij;
double betaP_ij,dBetaP_ij;
double dis_ik[3],rsq_ik,r_ik;
double betaS_ik,dBetaS_ik;
double betaP_ik,dBetaP_ik;
double dis_ikp[3],rsq_ikp,r_ikp;
double betaS_ikp,dBetaS_ikp;
double betaP_ikp,dBetaP_ikp;
double dis_jk[3],rsq_jk,r_jk;
double betaS_jk,dBetaS_jk;
double betaP_jk,dBetaP_jk;
double dis_jkp[3],rsq_jkp,r_jkp;
double betaS_jkp,dBetaS_jkp;
double betaP_jkp,dBetaP_jkp;
double dis_kkp[3],rsq_kkp,r_kkp;
double betaS_kkp,dBetaS_kkp;
double betaP_kkp,dBetaP_kkp;
double cosAng_jik,dcA_jik[3][2];
double cosAng_jikp;
double cosAng_kikp;
double cosAng_ijk,dcA_ijk[3][2];
double cosAng_ijkp,dcA_ijkp[3][2];
double cosAng_kjkp,dcA_kjkp[3][2];
double cosAng_ikj,dcA_ikj[3][2];
double cosAng_ikkp;
double cosAng_jkkp,dcA_jkkp[3][2];
double ftmp[3],xtmp[3];
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
int *type = atom->type;
nlocal = atom->nlocal;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
n=0;
if(nb_sg==0) {
nb_sg=4;
}
if(allocate_sigma) {
destroy_sigma();
}
create_sigma(nb_sg);
for(itmp=0;itmp<inum;itmp++) {
i = ilist[itmp];
i_tag=tag[i];
itype = map[type[i]]+1;
//j is loop over all neighbors of i
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
for(m=0;m<nb_sg;m++) {
for(pp=0;pp<3;pp++) {
bt_sg[m].dAA[pp]=0.0;
bt_sg[m].dBB[pp]=0.0;
bt_sg[m].dEE1[pp]=0.0;
bt_sg[m].dFF[pp]=0.0;
bt_sg[m].dAAC[pp]=0.0;
bt_sg[m].dSigB1[pp]=0.0;
bt_sg[m].dSigB[pp]=0.0;
}
bt_sg[m].i=-1;
bt_sg[m].j=-1;
}
nb_t=0;
iilist=firstneigh[i];
temp_ij=BOP_index[i]+jtmp;
j=iilist[jtmp];
jlist=firstneigh[j];
j_tag=tag[j];
jtype = map[type[j]]+1;
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ij].temp=temp_ij;
bt_sg[nb_ij].i=i;
bt_sg[nb_ij].j=j;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
for(ji=0;ji<numneigh[j];ji++) {
temp_ji=BOP_index[j]+ji;
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
dis_ij[0]=x[j][0]-x[i][0];
dis_ij[1]=x[j][1]-x[i][1];
dis_ij[2]=x[j][2]-x[i][2];
rsq_ij=dis_ij[0]*dis_ij[0]
+dis_ij[1]*dis_ij[1]
+dis_ij[2]*dis_ij[2];
r_ij=sqrt(rsq_ij);
if(r_ij<rcut[iij]) {
ps=r_ij*rdr[iij]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ij=((pBetaS3[iij][ks-1]*ps+pBetaS2[iij][ks-1])*ps
+pBetaS1[iij][ks-1])*ps+pBetaS[iij][ks-1];
dBetaS_ij=(pBetaS6[iij][ks-1]*ps+pBetaS5[iij][ks-1])*ps
+pBetaS4[iij][ks-1];
betaP_ij=((pBetaP3[iij][ks-1]*ps+pBetaP2[iij][ks-1])*ps
+pBetaP1[iij][ks-1])*ps+pBetaP[iij][ks-1];
dBetaP_ij=(pBetaP6[iij][ks-1]*ps+pBetaP5[iij][ks-1])*ps
+pBetaP4[iij][ks-1];
nSigBk[n]=0;
//AA-EE1 are the components making up Eq. 30 (a)
AA=0.0;
BB=0.0;
CC=0.0;
DD=0.0;
EE=0.0;
EE1=0.0;
//FF is the Beta_sigma^2 term
FF=betaS_ij*betaS_ij;
//agpdpr1 is derivative of FF w.r.t. r_ij
agpdpr1=2.0*betaS_ij*dBetaS_ij/r_ij;
//dXX derivatives are taken with respect to all pairs contributing to the energy
//nb_ij is derivative w.r.t. ij pair
bt_sg[nb_ij].dFF[0]=agpdpr1*dis_ij[0];
bt_sg[nb_ij].dFF[1]=agpdpr1*dis_ij[1];
bt_sg[nb_ij].dFF[2]=agpdpr1*dis_ij[2];
//k is loop over all neighbors of i again with j neighbor of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
temp_ik=BOP_index[i]+ktmp;
if(ktmp!=jtmp) {
k=iilist[ktmp];
klist=firstneigh[k];
ktype = map[type[k]]+1;
if(itype==ktype)
iik=itype-1;
else if(itype<ktype)
iik=itype*bop_types-itype*(itype+1)/2+ktype-1;
else
iik=ktype*bop_types-ktype*(ktype+1)/2+itype-1;
//find neighbor of k that is equal to i
for(kNeii=0;kNeii<numneigh[k];kNeii++) {
if(x[klist[kNeii]][0]==x[i][0]) {
if(x[klist[kNeii]][1]==x[i][1]) {
if(x[klist[kNeii]][2]==x[i][2]) {
break;
}
}
}
}
dis_ik[0]=x[k][0]-x[i][0];
dis_ik[1]=x[k][1]-x[i][1];
dis_ik[2]=x[k][2]-x[i][2];
rsq_ik=dis_ik[0]*dis_ik[0]
+dis_ik[1]*dis_ik[1]
+dis_ik[2]*dis_ik[2];
r_ik=sqrt(rsq_ik);
if(r_ik<=rcut[iik]) {
ps=r_ik*rdr[iik]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ik=((pBetaS3[iik][ks-1]*ps+pBetaS2[iik][ks-1])*ps
+pBetaS1[iik][ks-1])*ps+pBetaS[iik][ks-1];
dBetaS_ik=(pBetaS6[iik][ks-1]*ps+pBetaS5[iik][ks-1])*ps
+pBetaS4[iik][ks-1];
betaP_ik=((pBetaP3[iik][ks-1]*ps+pBetaP2[iik][ks-1])*ps
+pBetaP1[iik][ks-1])*ps+pBetaP[iik][ks-1];
dBetaP_ik=(pBetaP6[iik][ks-1]*ps+pBetaP5[iik][ks-1])*ps
+pBetaP4[iik][ks-1];
//find neighbor of i that is equal to k
for(jNeik=0;jNeik<numneigh[j];jNeik++) {
temp_jk=BOP_index[j]+jNeik;
if(x[jlist[jNeik]][0]==x[k][0]) {
if(x[jlist[jNeik]][1]==x[k][1]) {
if(x[jlist[jNeik]][2]==x[k][2]) {
break;
}
}
}
}
//find neighbor of k that is equal to j
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
dis_jk[0]=x[k][0]-x[j][0];
dis_jk[1]=x[k][1]-x[j][1];
dis_jk[2]=x[k][2]-x[j][2];
rsq_jk=dis_jk[0]*dis_jk[0]
+dis_jk[1]*dis_jk[1]
+dis_jk[2]*dis_jk[2];
r_jk=sqrt(rsq_jk);
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
nk0=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nk0=nSigBk[n]-1;
itypeSigBk[n][nk0]=k;
}
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_ik].temp=temp_ik;
bt_sg[nb_ik].i=i;
bt_sg[nb_ik].j=k;
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
cosAng_jik=(dis_ij[0]*dis_ik[0]+dis_ij[1]*dis_ik[1]
+dis_ij[2]*dis_ik[2])/(r_ij*r_ik);
dcA_jik[0][0]=(dis_ik[0]*r_ij*r_ik-cosAng_jik
*dis_ij[0]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][0]=(dis_ik[1]*r_ij*r_ik-cosAng_jik
*dis_ij[1]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][0]=(dis_ik[2]*r_ij*r_ik-cosAng_jik
*dis_ij[2]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[0][1]=(dis_ij[0]*r_ij*r_ik-cosAng_jik
*dis_ik[0]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][1]=(dis_ij[1]*r_ij*r_ik-cosAng_jik
*dis_ik[1]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][1]=(dis_ij[2]*r_ij*r_ik-cosAng_jik
*dis_ik[2]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
gmean0=sigma_g0[jtype-1][itype-1][ktype-1];
gmean1=sigma_g1[jtype-1][itype-1][ktype-1];
gmean2=sigma_g2[jtype-1][itype-1][ktype-1];
amean=cosAng_jik;
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gfactorsq=gfactor1*gfactor1;
gprime1=gmean1+2.0*gmean2*amean;
gsqprime=2.0*gfactor1*gprime1;
//AA is Eq. 34 (a) or Eq. 10 (c) for the i atom
//1st CC is Eq. 11 (c) for i atom where j & k=neighbor of i
AA=AA+gfactorsq*betaS_ik*betaS_ik;
CC=CC+gfactorsq*betaS_ik*betaS_ik*betaS_ik*betaS_ik;
//agpdpr1 is derivative of AA w.r.t. Beta(rik)
//app1 is derivative of AA w.r.t. cos(theta_jik)
agpdpr1=2.0*gfactorsq*betaS_ik*dBetaS_ik/r_ik;
app1=betaS_ik*betaS_ik*gsqprime;
bt_sg[nb_ij].dAA[0]+=
app1*dcA_jik[0][0];
bt_sg[nb_ij].dAA[1]+=
app1*dcA_jik[1][0];
bt_sg[nb_ij].dAA[2]+=
app1*dcA_jik[2][0];
bt_sg[nb_ik].dAA[0]+=
app1*dcA_jik[0][1]
+agpdpr1*dis_ik[0];
bt_sg[nb_ik].dAA[1]+=
app1*dcA_jik[1][1]
+agpdpr1*dis_ik[1];
bt_sg[nb_ik].dAA[2]+=
app1*dcA_jik[2][1]
+agpdpr1*dis_ik[2];
//k' is loop over neighbors all neighbors of j with k a neighbor
//of i and j a neighbor of i and determine which k' is k
same_kpk=0;
for(ltmp=0;ltmp<numneigh[j];ltmp++) {
temp_jkp=BOP_index[j]+ltmp;
kp1=jlist[ltmp];
kp1type=map[type[kp1]]+1;
if(x[kp1][0]==x[k][0]) {
if(x[kp1][1]==x[k][1]) {
if(x[kp1][2]==x[k][2]) {
same_kpk=1;
break;
}
}
}
}
if(same_kpk){
//loop over neighbors of k
for(mtmp=0;mtmp<numneigh[k];mtmp++) {
kp2=klist[mtmp];
if(x[kp2][0]==x[k][0]) {
if(x[kp2][1]==x[k][1]) {
if(x[kp2][2]==x[k][2]) {
break;
}
}
}
}
if(jtype==ktype)
ijk=jtype-1;
else if(jtype < ktype)
ijk=jtype*bop_types-jtype*(jtype+1)/2+ktype-1;
else
ijk=ktype*bop_types-ktype*(ktype+1)/2+jtype-1;
if(jtype==kp1type)
ijkp=jtype-1;
else if(jtype<kp1type)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kp1type-1;
else
ijkp=kp1type*bop_types-kp1type*(kp1type+1)/2+jtype-1;
dis_jkp[0]=x[kp1][0]-x[j][0];
dis_jkp[1]=x[kp1][1]-x[j][1];
dis_jkp[2]=x[kp1][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
if(r_jkp<=rcut[ijkp]) {
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
cosAng_ijk=(-dis_ij[0]*dis_jk[0]-dis_ij[1]*dis_jk[1]
-dis_ij[2]*dis_jk[2])/(r_ij*r_jk);
dcA_ijk[0][0]=(dis_jk[0]*r_ij*r_jk-cosAng_ijk
*-dis_ij[0]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][0]=(dis_jk[1]*r_ij*r_jk-cosAng_ijk
*-dis_ij[1]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][0]=(dis_jk[2]*r_ij*r_jk-cosAng_ijk
*-dis_ij[2]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[0][1]=(-dis_ij[0]*r_ij*r_jk-cosAng_ijk
*dis_jk[0]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][1]=(-dis_ij[1]*r_ij*r_jk-cosAng_ijk
*dis_jk[1]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][1]=(-dis_ij[2]*r_ij*r_jk-cosAng_ijk
*dis_jk[2]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng_ijk;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[itype-1][ktype-1][jtype-1];
gmean1=sigma_g1[itype-1][ktype-1][jtype-1];
gmean2=sigma_g2[itype-1][ktype-1][jtype-1];
cosAng_ikj=(dis_ik[0]*dis_jk[0]+dis_ik[1]*dis_jk[1]
+dis_ik[2]*dis_jk[2])/(r_ik*r_jk);
dcA_ikj[0][0]=(-dis_jk[0]*r_ik*r_jk-cosAng_ikj
*-dis_ik[0]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[1][0]=(-dis_jk[1]*r_ik*r_jk-cosAng_ikj
*-dis_ik[1]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[2][0]=(-dis_jk[2]*r_ik*r_jk-cosAng_ikj
*-dis_ik[2]*r_jk*r_jk)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[0][1]=(-dis_ik[0]*r_ik*r_jk-cosAng_ikj
*-dis_jk[0]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[1][1]=(-dis_ik[1]*r_ik*r_jk-cosAng_ikj
*-dis_jk[1]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
dcA_ikj[2][1]=(-dis_ik[2]*r_ik*r_jk-cosAng_ikj
*-dis_jk[2]*r_ik*r_ik)/(r_ik*r_ik*r_jk*r_jk);
amean=cosAng_ikj;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactor=betaS_ik*betaS_jkp;
//EE1 is (b) Eq. 12
EE1=EE1+gfactor*rfactor;
//rcm1 is derivative of EE1 w.r.t Beta(r_ik)
//rcm2 is derivative of EE1 w.r.t Beta(r_jk')
//gcm1 is derivative of EE1 w.r.t cos(theta_jik)
//gcm2 is derivative of EE1 w.r.t cos(theta_ijk)
//gcm3 is derivative of EE1 w.r.t cos(theta_ikj)
rcm1=gfactor*betaS_jkp*dBetaS_ik/r_ik;
rcm2=gfactor*betaS_ik*dBetaS_jkp/r_jkp;
gcm1=rfactor*gprime1*gfactor2*gfactor3;
gcm2=rfactor*gfactor1*gprime2*gfactor3;
gcm3=rfactor*gfactor1*gfactor2*gprime3;
bt_sg[nb_ij].dEE1[0]+=
gcm1*dcA_jik[0][0]
-gcm2*dcA_ijk[0][0];
bt_sg[nb_ij].dEE1[1]+=
gcm1*dcA_jik[1][0]
-gcm2*dcA_ijk[1][0];
bt_sg[nb_ij].dEE1[2]+=
gcm1*dcA_jik[2][0]
-gcm2*dcA_ijk[2][0];
bt_sg[nb_ik].dEE1[0]+=
gcm1*dcA_jik[0][1]
+rcm1*dis_ik[0]
-gcm3*dcA_ikj[0][0];
bt_sg[nb_ik].dEE1[1]+=
gcm1*dcA_jik[1][1]
+rcm1*dis_ik[1]
-gcm3*dcA_ikj[1][0];
bt_sg[nb_ik].dEE1[2]+=
gcm1*dcA_jik[2][1]
+rcm1*dis_ik[2]
-gcm3*dcA_ikj[2][0];
bt_sg[nb_jk].dEE1[0]+=
gcm2*dcA_ijk[0][1]
+rcm2*dis_jkp[0]
-gcm3*dcA_ikj[0][1];
bt_sg[nb_jk].dEE1[1]+=
gcm2*dcA_ijk[1][1]
+rcm2*dis_jkp[1]
-gcm3*dcA_ikj[1][1];
bt_sg[nb_jk].dEE1[2]+=
gcm2*dcA_ijk[2][1]
+rcm2*dis_jkp[2]
-gcm3*dcA_ikj[2][1];
}
}
// k and k' and j are all different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
kp=iilist[ltmp];;
kptype = map[type[kp]]+1;
if(itype==kptype)
iikp=itype-1;
else if(itype<kptype)
iikp=itype*bop_types-itype*(itype+1)/2+kptype-1;
else
iikp=kptype*bop_types-kptype*(kptype+1)/2+itype-1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
dis_ikp[0]=x[kp][0]-x[i][0];
dis_ikp[1]=x[kp][1]-x[i][1];
dis_ikp[2]=x[kp][2]-x[i][2];
rsq_ikp=dis_ikp[0]*dis_ikp[0]
+dis_ikp[1]*dis_ikp[1]
+dis_ikp[2]*dis_ikp[2];
r_ikp=sqrt(rsq_ikp);
if(r_ikp<=rcut[iikp]) {
ps=r_ikp*rdr[iikp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ikp=((pBetaS3[iikp][ks-1]*ps+pBetaS2[iikp][ks-1])*ps
+pBetaS1[iikp][ks-1])*ps+pBetaS[iikp][ks-1];
dBetaS_ikp=(pBetaS6[iikp][ks-1]*ps+pBetaS5[iikp][ks-1])*ps
+pBetaS4[iikp][ks-1];
betaP_ikp=((pBetaP3[iikp][ks-1]*ps+pBetaP2[iikp][ks-1])*ps
+pBetaP1[iikp][ks-1])*ps+pBetaP[iikp][ks-1];
dBetaP_ikp=(pBetaP6[iikp][ks-1]*ps+pBetaP5[iikp][ks-1])*ps
+pBetaP4[iikp][ks-1];
gmean0=sigma_g0[jtype-1][itype-1][kptype-1];
gmean1=sigma_g1[jtype-1][itype-1][kptype-1];
gmean2=sigma_g2[jtype-1][itype-1][kptype-1];
cosAng_jikp=(dis_ij[0]*dis_ikp[0]+dis_ij[1]*dis_ikp[1]
+dis_ij[2]*dis_ikp[2])/(r_ij*r_ikp);
cosAng_kikp=(dis_ik[0]*dis_ikp[0]+dis_ik[1]*dis_ikp[1]
+dis_ik[2]*dis_ikp[2])/(r_ik*r_ikp);
amean=cosAng_jikp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][itype-1][kptype-1];
gmean1=sigma_g1[ktype-1][itype-1][kptype-1];
gmean2=sigma_g2[ktype-1][itype-1][kptype-1];
amean=cosAng_kikp;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS_ik*betaS_ikp;
rfactor=rfactorrt*rfactorrt;
//2nd CC is second term of Eq. 11 (c) for i atom where j , k & k' =neighbor of i
CC=CC+2.0*gfactor*rfactor;
}
}
}
// j and k are different neighbors of i and k' is a neighbor k not equal to i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
kp=klist[ltmp];;
kptype = map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(ktype==kptype)
ikkp=ktype-1;
else if(ktype<kptype)
ikkp=ktype*bop_types-ktype*(ktype+1)/2+kptype-1;
else
ikkp=kptype*bop_types-kptype*(kptype+1)/2+ktype-1;
dis_kkp[0]=x[kp][0]-x[k][0];
dis_kkp[1]=x[kp][1]-x[k][1];
dis_kkp[2]=x[kp][2]-x[k][2];
rsq_kkp=dis_kkp[0]*dis_kkp[0]
+dis_kkp[1]*dis_kkp[1]
+dis_kkp[2]*dis_kkp[2];
r_kkp=sqrt(rsq_kkp);
if(r_kkp<=rcut[ikkp]) {
ps=r_kkp*rdr[ikkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_kkp=((pBetaS3[ikkp][ks-1]*ps+pBetaS2[ikkp][ks-1])*ps
+pBetaS1[ikkp][ks-1])*ps+pBetaS[ikkp][ks-1];
dBetaS_kkp=(pBetaS6[ikkp][ks-1]*ps+pBetaS5[ikkp][ks-1])*ps
+pBetaS4[ikkp][ks-1];
betaP_kkp=((pBetaP3[ikkp][ks-1]*ps+pBetaP2[ikkp][ks-1])*ps
+pBetaP1[ikkp][ks-1])*ps+pBetaP[ikkp][ks-1];
dBetaP_kkp=(pBetaP6[ikkp][ks-1]*ps+pBetaP5[ikkp][ks-1])*ps
+pBetaP4[ikkp][ks-1];
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
sig_flag=1;
nkp=nsearch;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
nkp=nSigBk[n]-1;
itypeSigBk[n][nkp]=kp;
}
cosAng_ikkp=(-dis_ik[0]*dis_kkp[0]-dis_ik[1]*dis_kkp[1]
-dis_ik[2]*dis_kkp[2])/(r_ik*r_kkp);
gmean0=sigma_g0[itype-1][ktype-1][kptype-1];
gmean1=sigma_g1[itype-1][ktype-1][kptype-1];
gmean2=sigma_g2[itype-1][ktype-1][kptype-1];
amean=cosAng_ikkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS_ik*betaS_kkp;
rfactor=rfactorrt*rfactorrt;
//3rd CC is third term of Eq. 11 (c) for i atom
//where j , k =neighbor of i & k' =neighbor of k
CC=CC+gfactor*rfactor;
}
}
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ji) {
temp_jk=BOP_index[j]+ktmp;
k=jlist[ktmp];
klist=firstneigh[k];
ktype=map[type[k]]+1;
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
if(jtype==ktype)
ijk=jtype-1;
else if(jtype<ktype)
ijk=jtype*bop_types-jtype*(jtype+1)/2+ktype-1;
else
ijk=ktype*bop_types-ktype*(ktype+1)/2+jtype-1;
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
new1=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new1=nSigBk[n]-1;
itypeSigBk[n][new1]=k;
}
dis_jk[0]=x[k][0]-x[j][0];
dis_jk[1]=x[k][1]-x[j][1];
dis_jk[2]=x[k][2]-x[j][2];
rsq_jk=dis_jk[0]*dis_jk[0]
+dis_jk[1]*dis_jk[1]
+dis_jk[2]*dis_jk[2];
r_jk=sqrt(rsq_jk);
if(r_jk<=rcut[ijk]) {
ps=r_jk*rdr[ijk]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jk=((pBetaS3[ijk][ks-1]*ps+pBetaS2[ijk][ks-1])*ps
+pBetaS1[ijk][ks-1])*ps+pBetaS[ijk][ks-1];
dBetaS_jk=(pBetaS6[ijk][ks-1]*ps+pBetaS5[ijk][ks-1])*ps
+pBetaS4[ijk][ks-1];
betaP_jk=((pBetaP3[ijk][ks-1]*ps+pBetaP2[ijk][ks-1])*ps
+pBetaP1[ijk][ks-1])*ps+pBetaP[ijk][ks-1];
dBetaP_jk=(pBetaP6[ijk][ks-1]*ps+pBetaP5[ijk][ks-1])*ps
+pBetaP4[ijk][ks-1];
cosAng_ijk=(-dis_ij[0]*dis_jk[0]-dis_ij[1]*dis_jk[1]
-dis_ij[2]*dis_jk[2])/(r_ij*r_jk);
dcA_ijk[0][0]=(dis_jk[0]*r_ij*r_jk-cosAng_ijk
*-dis_ij[0]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][0]=(dis_jk[1]*r_ij*r_jk-cosAng_ijk
*-dis_ij[1]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][0]=(dis_jk[2]*r_ij*r_jk-cosAng_ijk
*-dis_ij[2]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[0][1]=(-dis_ij[0]*r_ij*r_jk-cosAng_ijk
*dis_jk[0]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][1]=(-dis_ij[1]*r_ij*r_jk-cosAng_ijk
*dis_jk[1]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][1]=(-dis_ij[2]*r_ij*r_jk-cosAng_ijk
*dis_jk[2]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jk].temp=temp_jk;
bt_sg[nb_jk].i=j;
bt_sg[nb_jk].j=k;
gmean0=sigma_g0[itype-1][jtype-1][ktype-1];
gmean1=sigma_g1[itype-1][jtype-1][ktype-1];
gmean2=sigma_g2[itype-1][jtype-1][ktype-1];
amean=cosAng_ijk;
gfactor1=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime1=gmean1+2.0*gmean2*amean;
gfactorsq=gfactor1*gfactor1;
gsqprime=2.0*gfactor1*gprime1;
rfactor1rt=betaS_jk*betaS_jk;
rfactor1=rfactor1rt*rfactor1rt;
//BB is Eq. 34 (a) or Eq. 10 (c) for the j atom
//1st DD is Eq. 11 (c) for j atom where i & k=neighbor of j
BB=BB+gfactorsq*rfactor1rt;
DD=DD+gfactorsq*rfactor1;
//agpdpr1 is derivative of BB w.r.t. Beta(r_jk)
//app1 is derivative of BB w.r.t. cos(theta_ijk)
agpdpr1=2.0*gfactorsq*betaS_jk*dBetaS_jk/r_jk;
app1=rfactor1rt*gsqprime;
bt_sg[nb_ij].dBB[0]-=
app1*dcA_ijk[0][0];
bt_sg[nb_ij].dBB[1]-=
app1*dcA_ijk[1][0];
bt_sg[nb_ij].dBB[2]-=
app1*dcA_ijk[2][0];
bt_sg[nb_jk].dBB[0]+=
app1*dcA_ijk[0][1]
+agpdpr1*dis_jk[0];
bt_sg[nb_jk].dBB[1]+=
app1*dcA_ijk[1][1]
+agpdpr1*dis_jk[1];
bt_sg[nb_jk].dBB[2]+=
app1*dcA_ijk[2][1]
+agpdpr1*dis_jk[2];
//j is a neighbor of i, k and k' prime different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ji) {
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
kptype=map[type[kp]]+1;
if(jtype==kptype)
ijkp=jtype-1;
else if(jtype<kptype)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kptype-1;
else
ijkp=kptype*bop_types-kptype*(kptype+1)/2+jtype-1;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
break;
}
}
}
}
dis_jkp[0]=x[kp][0]-x[j][0];
dis_jkp[1]=x[kp][1]-x[j][1];
dis_jkp[2]=x[kp][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
if(r_jkp<=rcut[ijkp]) {
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
cosAng_ijkp=(-dis_ij[0]*dis_jkp[0]-dis_ij[1]*dis_jkp[1]
-dis_ij[2]*dis_jkp[2])/(r_ij*r_jkp);
dcA_ijkp[0][0]=(dis_jkp[0]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[0]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][0]=(dis_jkp[1]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[1]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][0]=(dis_jkp[2]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[2]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[0][1]=(-dis_ij[0]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[0]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][1]=(-dis_ij[1]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[1]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][1]=(-dis_ij[2]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[2]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
cosAng_kjkp=(dis_jk[0]*dis_jkp[0]+dis_jk[1]*dis_jkp[1]
+dis_jk[2]*dis_jkp[2])/(r_jk*r_jkp);
dcA_kjkp[0][0]=(dis_jkp[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[0]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][0]=(dis_jkp[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[1]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][0]=(dis_jkp[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[2]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[0][1]=(dis_jk[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[0]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][1]=(dis_jk[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[1]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][1]=(dis_jk[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[2]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_jkp].temp=temp_jkp;
bt_sg[nb_jkp].i=j;
bt_sg[nb_jkp].j=kp;
gmean0=sigma_g0[itype-1][jtype-1][kptype-1];
gmean1=sigma_g1[itype-1][jtype-1][kptype-1];
gmean2=sigma_g2[itype-1][jtype-1][kptype-1];
amean=cosAng_ijkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gmean0=sigma_g0[ktype-1][jtype-1][kptype-1];
gmean1=sigma_g1[ktype-1][jtype-1][kptype-1];
gmean2=sigma_g2[ktype-1][jtype-1][kptype-1];
amean=cosAng_kjkp;
gfactor3=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime3=gmean1+2.0*gmean2*amean;
gfactor=gfactor1*gfactor2*gfactor3;
rfactorrt=betaS_jk*betaS_jkp;
rfactor=rfactorrt*rfactorrt;
//2nd DD is Eq. 11 (c) for j atom where i , k & k'=neighbor of j
DD=DD+2.0*gfactor*rfactor;
}
}
}
//j is a neighbor of i, k is a neighbor of j not equal to i and k'
//is a neighbor of k not equal to j or i
for(ltmp=0;ltmp<numneigh[k];ltmp++) {
temp_kkp=BOP_index[k]+ltmp;
kp=klist[ltmp];
kptype=map[type[kp]]+1;
same_ikp=0;
same_jkp=0;
if(x[i][0]==x[kp][0]) {
if(x[i][1]==x[kp][1]) {
if(x[i][2]==x[kp][2]) {
same_ikp=1;
}
}
}
if(x[j][0]==x[kp][0]) {
if(x[j][1]==x[kp][1]) {
if(x[j][2]==x[kp][2]) {
same_jkp=1;
}
}
}
if(!same_ikp&&!same_jkp) {
if(ktype==kptype)
ikkp=ktype-1;
else if(ktype<kptype)
ikkp=ktype*bop_types-ktype*(ktype+1)/2+kptype-1;
else
ikkp=kptype*bop_types-kptype*(kptype+1)/2+ktype-1;
for(kNeij=0;kNeij<numneigh[k];kNeij++) {
if(x[klist[kNeij]][0]==x[j][0]) {
if(x[klist[kNeij]][1]==x[j][1]) {
if(x[klist[kNeij]][2]==x[j][2]) {
break;
}
}
}
}
sig_flag=0;
for(nsearch=0;nsearch<nSigBk[n];nsearch++) {
ncmp=itypeSigBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
new2=nsearch;
sig_flag=1;
break;
}
}
}
}
if(sig_flag==0) {
nSigBk[n]=nSigBk[n]+1;
new2=nSigBk[n]-1;
itypeSigBk[n][new2]=kp;
}
dis_kkp[0]=x[kp][0]-x[k][0];
dis_kkp[1]=x[kp][1]-x[k][1];
dis_kkp[2]=x[kp][2]-x[k][2];
rsq_kkp=dis_kkp[0]*dis_kkp[0]
+dis_kkp[1]*dis_kkp[1]
+dis_kkp[2]*dis_kkp[2];
r_kkp=sqrt(rsq_kkp);
if(r_kkp<=rcut[ikkp]) {
ps=r_kkp*rdr[ikkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_kkp=((pBetaS3[ikkp][ks-1]*ps+pBetaS2[ikkp][ks-1])*ps
+pBetaS1[ikkp][ks-1])*ps+pBetaS[ikkp][ks-1];
dBetaS_kkp=(pBetaS6[ikkp][ks-1]*ps+pBetaS5[ikkp][ks-1])*ps
+pBetaS4[ikkp][ks-1];
betaP_kkp=((pBetaP3[ikkp][ks-1]*ps+pBetaP2[ikkp][ks-1])*ps
+pBetaP1[ikkp][ks-1])*ps+pBetaP[ikkp][ks-1];
dBetaP_kkp=(pBetaP6[ikkp][ks-1]*ps+pBetaP5[ikkp][ks-1])*ps
+pBetaP4[ikkp][ks-1];
cosAng_jkkp=(-dis_jk[0]*dis_kkp[0]-dis_jk[1]*dis_kkp[1]
-dis_jk[2]*dis_kkp[2])/(r_jk*r_kkp);
dcA_jkkp[0][0]=(dis_kkp[0]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[0]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[1][0]=(dis_kkp[1]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[1]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[2][0]=(dis_kkp[2]*r_jk*r_kkp-cosAng_jkkp
*-dis_jk[2]*r_kkp*r_kkp)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[0][1]=(-dis_jk[0]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[0]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[1][1]=(-dis_jk[1]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[1]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
dcA_jkkp[2][1]=(-dis_jk[2]*r_jk*r_kkp-cosAng_jkkp
*dis_kkp[2]*r_jk*r_jk)/(r_jk*r_jk*r_kkp*r_kkp);
nb_kkp=nb_t;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
bt_sg[nb_kkp].temp=temp_kkp;
bt_sg[nb_kkp].i=k;
bt_sg[nb_kkp].j=kp;
gmean0=sigma_g0[jtype-1][ktype-1][kptype-1];
gmean1=sigma_g1[jtype-1][ktype-1][kptype-1];
gmean2=sigma_g2[jtype-1][ktype-1][kptype-1];
amean=cosAng_jkkp;
gfactor2=gmean0+gmean1*amean
+gmean2*amean*amean;
gprime2=gmean1+2.0*gmean2*amean;
gfactorsq2=gfactor2*gfactor2;
gsqprime2=2.0*gfactor2*gprime2;
gfactor=gfactorsq*gfactorsq2;
rfactorrt=betaS_jk*betaS_kkp;
rfactor=rfactorrt*rfactorrt;
//3rd DD is Eq. 11 (c) for j atom where i & k=neighbor of j & k'=neighbor of k
DD=DD+gfactor*rfactor;
}
}
}
}
}
}
sig_flag=0;
if(FF<=0.000001) {
sigB[n]=0.0;
sig_flag=1;
}
if(sig_flag==0) {
if(AA<0.0)
AA=0.0;
if(BB<0.0)
BB=0.0;
if(CC<0.0)
CC=0.0;
if(DD<0.0)
DD=0.0;
// AA and BB are the representations of (a) Eq. 34 and (b) Eq. 9
// for atoms i and j respectively
AAC=AA+BB;
BBC=AA*BB;
CCC=AA*AA+BB*BB;
DDC=CC+DD;
//EEC is a modified form of (a) Eq. 33
EEC=(DDC-CCC)/(AAC+2.0*small1);
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
bt_sg[m].dAAC[0]=bt_sg[m].dAA[0]
+bt_sg[m].dBB[0];
bt_sg[m].dAAC[1]=bt_sg[m].dAA[1]
+bt_sg[m].dBB[1];
bt_sg[m].dAAC[2]=bt_sg[m].dAA[2]
+bt_sg[m].dBB[2];
}
}
UT=EEC*FF+BBC+small3[iij];
UT=1.0/sqrt(UT);
// FFC is slightly modified form of (a) Eq. 31
// GGC is slightly modified form of (a) Eq. 32
// bndtmp is a slightly modified form of (a) Eq. 30 and (b) Eq. 8
FFC=BBC*UT;
GGC=EEC*UT;
bndtmp=(FF+sigma_delta[iij]*sigma_delta[iij])
+sigma_c[iij]*AAC+small4;
UTcom=-0.5*UT*UT*UT;
psign=1.0;
bndtmp0=1.0/sqrt(bndtmp);
sigB1[n]=psign*betaS_ij*bndtmp0;
bndtmp=-0.5*bndtmp0*bndtmp0*bndtmp0;
bndtmp1=psign*bndtmp0+psign*betaS_ij
*bndtmp*2.0*betaS_ij;
bndtmp1=bndtmp1*dBetaS_ij/r_ij;
bndtmp2=psign*betaS_ij*bndtmp*sigma_c[iij];
setting=0;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
if(temp_kk==temp_ij&&setting==0) {
bt_sg[m].dSigB1[0]=bndtmp1*dis_ij[0]
+(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=bndtmp1*dis_ij[1]
+(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=bndtmp1*dis_ij[2]
+(bndtmp2*bt_sg[m].dAAC[2]);
setting=1;
}
else if(temp_kk==temp_ji&&setting==0) {
bt_sg[m].dSigB1[0]=-bndtmp1*dis_ij[0]
+(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=-bndtmp1*dis_ij[1]
+(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=-bndtmp1*dis_ij[2]
+(bndtmp2*bt_sg[m].dAAC[2]);
setting=1;
}
else {
bt_sg[m].dSigB1[0]=(bndtmp2*bt_sg[m].dAAC[0]);
bt_sg[m].dSigB1[1]=(bndtmp2*bt_sg[m].dAAC[1]);
bt_sg[m].dSigB1[2]=(bndtmp2*bt_sg[m].dAAC[2]);
}
}
}
//This loop is to ensure there is not an error for atoms with no neighbors (deposition)
if(nb_t==0) {
if(j>i) {
bt_sg[0].dSigB1[0]=bndtmp1*dis_ij[0];
bt_sg[0].dSigB1[1]=bndtmp1*dis_ij[1];
bt_sg[0].dSigB1[2]=bndtmp1*dis_ij[2];
}
else {
bt_sg[0].dSigB1[0]=-bndtmp1*dis_ij[0];
bt_sg[0].dSigB1[1]=-bndtmp1*dis_ij[1];
bt_sg[0].dSigB1[2]=-bndtmp1*dis_ij[2];
}
for(pp=0;pp<3;pp++) {
bt_sg[0].dAA[pp]=0.0;
bt_sg[0].dBB[pp]=0.0;
bt_sg[0].dEE1[pp]=0.0;
bt_sg[0].dFF[pp]=0.0;
bt_sg[0].dAAC[pp]=0.0;
bt_sg[0].dSigB[pp]=0.0;
}
bt_sg[0].i=i;
bt_sg[0].j=j;
bt_sg[0].temp=temp_ij;
nb_t++;
if(nb_t>nb_sg) {
new_n_tot=nb_sg+maxneigh;
grow_sigma(nb_sg,new_n_tot);
nb_sg=new_n_tot;
}
}
ps=sigB1[n]*rdBO+1.0;
ks=(int)ps;
if(nBOt-1<ks)
ks=nBOt-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
dsigB1=((FsigBO3[iij][ks-1]*ps+FsigBO2[iij][ks-1])*ps
+FsigBO1[iij][ks-1])*ps+FsigBO[iij][ks-1];
dsigB2=(FsigBO6[iij][ks-1]*ps+FsigBO5[iij][ks-1])*ps+FsigBO4[iij][ks-1];
part0=(FF+0.5*AAC+small5);
part1=(sigma_f[iij]-0.5)*sigma_k[iij];
part2=1.0-part1*EE1/part0;
part3=dsigB1*part1/part0;
part4=part3/part0*EE1;
// sigB is the final expression for (a) Eq. 6 and (b) Eq. 11
sigB[n]=dsigB1*part2;
pp1=2.0*betaS_ij;
for(m=0;m<nb_t;m++) {
if((bt_sg[m].i>-1)&&(bt_sg[m].j>-1)) {
temp_kk=bt_sg[m].temp;
bt_ij=bt_sg[m].temp;
bt_i=bt_sg[m].i;
bt_j=bt_sg[m].j;
xtmp[0]=x[bt_j][0]-x[bt_i][0];
xtmp[1]=x[bt_j][1]-x[bt_i][1];
xtmp[2]=x[bt_j][2]-x[bt_i][2];
for(pp=0;pp<3;pp++) {
bt_sg[m].dSigB[pp]=dsigB2*part2*bt_sg[m].dSigB1[pp]
-part3*bt_sg[m].dEE1[pp]
+part4*(bt_sg[m].dFF[pp]
+0.5*bt_sg[m].dAAC[pp]);
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp1*bt_sg[m].dSigB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],xtmp[0],xtmp[1],xtmp[2]);
}
}
}
}
n++;
}
}
}
}
destroy_sigma();
}
/* ---------------------------------------------------------------------- */
void PairBOP::PiBo()
{
int new_n_tot;
int i,j,k,kp,m,n,pp,nb_t;
int iij,ji,ki;
int nsearch,ncmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int njik,ngj,ngk,nglj,ngl,ngi;
int nkjkp,nijkp,ngli,nkikp,njikp;
int itmp,ltmp,jtmp,ktmp;
int nlocal,pi_flag;
int inum,*ilist,*iilist,*jlist;
int **firstneigh,*numneigh;
int itype,jtype;
int temp_ij,temp_ik,temp_ikp;
int temp_ji,temp_jki,temp_jk,temp_jkp;
int ang_jikp,ang_kikp,ang_ijk;
int ang_ijkp,ang_kjkp,ang_jik;
int nb_ij,nb_ik,nb_jk,nb_ikp,nb_jkp;
int bt_ij,bt_i,bt_j;
double AA,BB,CC,DD,EE,FF;
double cosSq,sinFactor,cosFactor;
double cosSq1,dotV,BBrt,AB1,AB2;
double BBrtR,ABrtR,ABrtR1,ABrtR2;
double angFactor,angFactor1,angFactor2;
double angFactor3,angFactor4,angRfactor;
double dAngR1,dAngR2,agpdpr3;
double agpdpr1,agpdpr2,app1,app2,app3;
double betaCapSq1,dbetaCapSq1;
double betaCapSq2,dbetaCapSq2;
double betaCapSum,ftmp[3];
double dPiB1,dPiB2,dPiB3,pp2;
double **f = atom->f;
double **x = atom->x;
int *type = atom->type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_pair = force->newton_pair;
nlocal = atom->nlocal;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
n=0;
// Loop over all local atoms for i
if(nb_pi>16) {
nb_pi=16;
}
if(nb_pi==0) {
nb_pi=(maxneigh)*(maxneigh/2);
}
if(allocate_pi) {
destroy_pi();
}
create_pi(nb_pi);
for(itmp=0;itmp<inum;itmp++) {
nb_t=0;
i = ilist[itmp];
itype = map[type[i]]+1;
i_tag=tag[i];
// j is a loop over all neighbors of i
iilist=firstneigh[i];
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
temp_ij=BOP_index[i]+jtmp;
if(neigh_flag[temp_ij]) {
for(m=0;m<nb_pi;m++) {
for(pp=0;pp<3;pp++) {
bt_pi[m].dAA[pp]=0.0;
bt_pi[m].dBB[pp]=0.0;
bt_pi[m].dPiB[pp]=0.0;
}
bt_pi[m].i=-1;
bt_pi[m].j=-1;
}
j=iilist[jtmp];
jlist=firstneigh[j];
jtype=map[type[j]]+1;
j_tag=tag[j];
nb_t=0;
ftmp[0]=0.0;
ftmp[1]=0.0;
ftmp[2]=0.0;
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ij].i=i;
bt_pi[nb_ij].j=j;
bt_pi[nb_ij].temp=temp_ij;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
AA=0.0;
BB=0.0;
nPiBk[n]=0;
for(ji=0;ji<numneigh[j];ji++) {
temp_ji=BOP_index[j]+ji;
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
// j and k are different neighbors of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
if(ktmp!=jtmp) {
temp_ik=BOP_index[i]+ktmp;
if(neigh_flag[temp_ik]) {
k=iilist[ktmp];
if(jtmp<ktmp) {
njik=jtmp*(2*numneigh[i]-jtmp-1)/2+(ktmp-jtmp)-1;
ngj=0;
ngk=1;
}
else {
njik=ktmp*(2*numneigh[i]-ktmp-1)/2+(jtmp-ktmp)-1;
ngj=1;
ngk=0;
}
ang_jik=cos_index[i]+njik;
if(ang_jik>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ik].i=i;
bt_pi[nb_ik].j=k;
bt_pi[nb_ik].temp=temp_ik;
cosSq=cosAng[ang_jik]*cosAng[ang_jik];
sinFactor=.5*(1.0-cosSq)*pi_p[itype-1]*betaS[temp_ik];
cosFactor=.5*(1.0+cosSq)*betaP[temp_ik];
betaCapSq1=pi_p[itype-1]*betaS[temp_ik]*betaS[temp_ik]-betaP[temp_ik]
*betaP[temp_ik];
dbetaCapSq1=2.0*pi_p[itype-1]*betaS[temp_ik]*dBetaS[temp_ik]
-2.0*betaP[temp_ik]*dBetaP[temp_ik];
//AA is Eq. 37 (a) and Eq. 19 (b) or i atoms
//1st BB is first term of Eq. 38 (a) where j and k =neighbors i
AA=AA+sinFactor*betaS[temp_ik]+cosFactor*betaP[temp_ik];
BB=BB+.25*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*betaCapSq1;
//agpdpr1 is derivative of AA w.r.t. for atom i w.r.t. Beta(r_ik)
//agpdpr2 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik)
//app1 is derivative of AA w.r.t. for atom i w.r.t. cos(theta_jik)
//app2 is derivative of BB w.r.t. for atom i w.r.t. cos(theta_jik)
agpdpr1=(2.0*sinFactor*dBetaS[temp_ik]+2.0*cosFactor
*dBetaP[temp_ik])/rij[temp_ik];
app1=cosAng[ang_jik]*(-pi_p[itype-1]*betaS[temp_ik]*betaS[temp_ik]
+betaP[temp_ik]*betaP[temp_ik]);
app2=-(1.0-cosSq)*cosAng[ang_jik]*betaCapSq1*betaCapSq1;
agpdpr2=.5*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*dbetaCapSq1/rij[temp_ik];
itypePiBk[n][nPiBk[n]]=k;
bt_pi[nb_ij].dAA[0]+=
app1*dcAng[ang_jik][0][ngj];
bt_pi[nb_ij].dAA[1]+=
app1*dcAng[ang_jik][1][ngj];
bt_pi[nb_ij].dAA[2]+=
app1*dcAng[ang_jik][2][ngj];
bt_pi[nb_ij].dBB[0]+=
app2*dcAng[ang_jik][0][ngj];
bt_pi[nb_ij].dBB[1]+=
app2*dcAng[ang_jik][1][ngj];
bt_pi[nb_ij].dBB[2]+=
app2*dcAng[ang_jik][2][ngj];
bt_pi[nb_ik].dAA[0]+=
agpdpr1*disij[0][temp_ik]
+app1*dcAng[ang_jik][0][ngk];
bt_pi[nb_ik].dAA[1]+=
agpdpr1*disij[1][temp_ik]
+app1*dcAng[ang_jik][1][ngk];
bt_pi[nb_ik].dAA[2]+=
agpdpr1*disij[2][temp_ik]
+app1*dcAng[ang_jik][2][ngk];
bt_pi[nb_ik].dBB[0]+=
app2*dcAng[ang_jik][0][ngk]
+agpdpr2*disij[0][temp_ik];
bt_pi[nb_ik].dBB[1]+=
app2*dcAng[ang_jik][1][ngk]
+agpdpr2*disij[1][temp_ik];
bt_pi[nb_ik].dBB[2]+=
app2*dcAng[ang_jik][2][ngk]
+agpdpr2*disij[2][temp_ik];
// j and k and k' are different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
if(neigh_flag[temp_ikp]) {
kp=iilist[ltmp];
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
nkikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(ktmp-ltmp)-1;
if(jtmp<ltmp) {
njikp=jtmp*(2*numneigh[i]-jtmp-1)/2+(ltmp-jtmp)-1;
nglj=0;
ngl=1;
}
else {
njikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(jtmp-ltmp)-1;
nglj=1;
ngl=0;
}
ang_jikp=cos_index[i]+njikp;
if(ang_jikp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ikp].i=i;
bt_pi[nb_ikp].j=kp;
bt_pi[nb_ikp].temp=temp_ikp;
ang_kikp=cos_index[i]+nkikp;
if(ang_kikp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
betaCapSq2=pi_p[itype-1]*betaS[temp_ikp]*betaS[temp_ikp]
-betaP[temp_ikp]*betaP[temp_ikp];
dbetaCapSq2=2.0*pi_p[itype-1]*betaS[temp_ikp]*dBetaS[temp_ikp]
-2.0*betaP[temp_ikp]*dBetaP[temp_ikp];
cosSq1=cosAng[ang_jikp]*cosAng[ang_jikp];
angFactor=cosAng[ang_kikp]-cosAng[ang_jikp]*cosAng[ang_jik];
angFactor1=4.0*angFactor;
angFactor2=-angFactor1*cosAng[ang_jikp]
+2.0*cosAng[ang_jik]*(1.0-cosSq1);
angFactor3=-angFactor1*cosAng[ang_jik]
+2.0*cosAng[ang_jikp]*(1.0-cosSq);
angFactor4=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//2nd BB is third term of Eq. 38 (a) where j , k and k'=neighbors i
BB=BB+betaCapSum*angFactor4;
//agpdpr1 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik)
//agpdpr2 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik')
//app1 is derivative of BB 3rd term w.r.t. cos(theta_kik')
//app2 is derivative of BB 3rd term w.r.t. cos(theta_jik)
//app3 is derivative of BB 3rd term w.r.t. cos(theta_jik')
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
app3=betaCapSum*angFactor3;
agpdpr1=.5*angFactor4*dbetaCapSq1*betaCapSq2/rij[temp_ik];
agpdpr2=.5*angFactor4*betaCapSq1*dbetaCapSq2/rij[temp_ikp];
bt_pi[nb_ij].dBB[0]+=
app2*dcAng[ang_jik][0][ngj]
+app3*dcAng[ang_jikp][0][nglj];
bt_pi[nb_ij].dBB[1]+=
app2*dcAng[ang_jik][1][ngj]
+app3*dcAng[ang_jikp][1][nglj];
bt_pi[nb_ij].dBB[2]+=
app2*dcAng[ang_jik][2][ngj]
+app3*dcAng[ang_jikp][2][nglj];
bt_pi[nb_ik].dBB[0]+=
agpdpr1*disij[0][temp_ik]
+app1*dcAng[ang_kikp][0][1]
+app2*dcAng[ang_jik][0][ngk];
bt_pi[nb_ik].dBB[1]+=
agpdpr1*disij[1][temp_ik]
+app1*dcAng[ang_kikp][1][1]
+app2*dcAng[ang_jik][1][ngk];
bt_pi[nb_ik].dBB[2]+=
agpdpr1*disij[2][temp_ik]
+app1*dcAng[ang_kikp][2][1]
+app2*dcAng[ang_jik][2][ngk];
bt_pi[nb_ikp].dBB[0]+=
agpdpr2*disij[0][temp_ikp]
+app1*dcAng[ang_kikp][0][0]
+app3*dcAng[ang_jikp][0][ngl];
bt_pi[nb_ikp].dBB[1]+=
agpdpr2*disij[1][temp_ikp]
+app1*dcAng[ang_kikp][1][0]
+app3*dcAng[ang_jikp][1][ngl];
bt_pi[nb_ikp].dBB[2]+=
agpdpr2*disij[2][temp_ikp]
+app1*dcAng[ang_kikp][2][0]
+app3*dcAng[ang_jikp][2][ngl];
}
}
}
nPiBk[n]=nPiBk[n]+1;
}
}
}
//j is a neighbor of i and k is a neighbor of j and equal to i
for(ki=0;ki<numneigh[j];ki++) {
temp_jki=BOP_index[j]+ki;
k=jlist[ki];
if(x[k][0]==x[i][0]) {
if(x[k][1]==x[i][1]) {
if(x[k][2]==x[i][2]) {
break;
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ki) {
temp_jk=BOP_index[j]+ktmp;
if(neigh_flag[temp_jk]) {
k=jlist[ktmp];
pi_flag=0;
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
pi_flag=1;
break;
}
}
}
}
if(pi_flag==0) {
itypePiBk[n][nPiBk[n]]=k;
}
if(ktmp<ki) {
njik=ktmp*(2*numneigh[j]-ktmp-1)/2+(ki-ktmp)-1;
ngi=1;
ngk=0;
}
else {
njik=ki*(2*numneigh[j]-ki-1)/2+(ktmp-ki)-1;
ngi=0;
ngk=1;
}
ang_ijk=cos_index[j]+njik;
if(ang_ijk>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_jk].i=j;
bt_pi[nb_jk].j=k;
bt_pi[nb_jk].temp=temp_jk;
cosSq=cosAng[ang_ijk]*cosAng[ang_ijk];
sinFactor=.5*(1.0-cosSq)*pi_p[jtype-1]*betaS[temp_jk];
cosFactor=.5*(1.0+cosSq)*betaP[temp_jk];
betaCapSq1=pi_p[jtype-1]*betaS[temp_jk]*betaS[temp_jk]
-betaP[temp_jk]*betaP[temp_jk];
dbetaCapSq1=2.0*pi_p[jtype-1]*betaS[temp_jk]*dBetaS[temp_jk]
-2.0*betaP[temp_jk]*dBetaP[temp_jk];
//AA is Eq. 37 (a) and Eq. 19 (b) for j atoms
//3rd BB is 2nd term of Eq. 38 (a) where i and k =neighbors j
AA=AA+sinFactor*betaS[temp_jk]+cosFactor*betaP[temp_jk];
BB=BB+.25*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*betaCapSq1;
//agpdpr1 is derivative of AA for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB for atom j w.r.t. Beta(r_jk)
//app1 is derivative of AA for j atom w.r.t. cos(theta_ijk)
//app2 is derivative of BB 2nd term w.r.t. cos(theta_ijk)
agpdpr1=(2.0*sinFactor*dBetaS[temp_jk]+2.0*cosFactor
*dBetaP[temp_jk])/rij[temp_jk];
agpdpr2=.5*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*dbetaCapSq1/rij[temp_jk];
app1=cosAng[ang_ijk]*(-pi_p[jtype-1]*betaS[temp_jk]*betaS[temp_jk]
+betaP[temp_jk]*betaP[temp_jk]);
app2=-(1.0-cosSq)*cosAng[ang_ijk]*betaCapSq1*betaCapSq1;
bt_pi[nb_ij].dAA[0]-=
app1*dcAng[ang_ijk][0][ngi];
bt_pi[nb_ij].dAA[1]-=
app1*dcAng[ang_ijk][1][ngi];
bt_pi[nb_ij].dAA[2]-=
app1*dcAng[ang_ijk][2][ngi];
bt_pi[nb_ij].dBB[0]-=
app2*dcAng[ang_ijk][0][ngi];
bt_pi[nb_ij].dBB[1]-=
app2*dcAng[ang_ijk][1][ngi];
bt_pi[nb_ij].dBB[2]-=
app2*dcAng[ang_ijk][2][ngi];
bt_pi[nb_jk].dAA[0]+=
agpdpr1*disij[0][temp_jk]
+app1*dcAng[ang_ijk][0][ngk];
bt_pi[nb_jk].dAA[1]+=
agpdpr1*disij[1][temp_jk]
+app1*dcAng[ang_ijk][1][ngk];
bt_pi[nb_jk].dAA[2]+=
agpdpr1*disij[2][temp_jk]
+app1*dcAng[ang_ijk][2][ngk];
bt_pi[nb_jk].dBB[0]+=
app2*dcAng[ang_ijk][0][ngk]
+agpdpr2*disij[0][temp_jk];
bt_pi[nb_jk].dBB[1]+=
app2*dcAng[ang_ijk][1][ngk]
+agpdpr2*disij[1][temp_jk];
bt_pi[nb_jk].dBB[2]+=
app2*dcAng[ang_ijk][2][ngk]
+agpdpr2*disij[2][temp_jk];
//j is a neighbor of i and k and k' are different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ki) {
temp_jkp=BOP_index[j]+ltmp;
if(neigh_flag[temp_jkp]) {
kp=jlist[ltmp];
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
nkjkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ktmp-ltmp)-1;
if(ki<ltmp) {
nijkp=ki*(2*numneigh[j]-ki-1)/2+(ltmp-ki)-1;
ngli=0;
ngl=1;
}
else {
nijkp=ltmp*(2*numneigh[j]-ltmp-1)/2+(ki-ltmp)-1;
ngli=1;
ngl=0;
}
ang_ijkp=cos_index[j]+nijkp;
if(ang_ijkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
ang_kjkp=cos_index[j]+nkjkp;
if(ang_kjkp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_jkp].i=j;
bt_pi[nb_jkp].j=kp;
bt_pi[nb_jkp].temp=temp_jkp;
betaCapSq2=pi_p[jtype-1]*betaS[temp_jkp]*betaS[temp_jkp]
-betaP[temp_jkp]*betaP[temp_jkp];
dbetaCapSq2=2.0*pi_p[jtype-1]*betaS[temp_jkp]*dBetaS[temp_jkp]
-2.0*betaP[temp_jkp]*dBetaP[temp_jkp];
cosSq1=cosAng[ang_ijkp]*cosAng[ang_ijkp];
angFactor=cosAng[ang_kjkp]-cosAng[ang_ijkp]*cosAng[ang_ijk];
angFactor1=4.0*angFactor;
angFactor2=-angFactor1*cosAng[ang_ijkp]
+2.0*cosAng[ang_ijk]*(1.0-cosSq1);
angFactor3=-angFactor1*cosAng[ang_ijk]
+2.0*cosAng[ang_ijkp]*(1.0-cosSq);
angFactor4=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//4th BB is 4th term of Eq. 38 (a) where i , k and k' =neighbors j
BB=BB+betaCapSum*angFactor4;
//app1 is derivative of BB 4th term w.r.t. cos(theta_kjk')
//app2 is derivative of BB 4th term w.r.t. cos(theta_ijk)
//app3 is derivative of BB 4th term w.r.t. cos(theta_ijk')
//agpdpr1 is derivative of BB 4th term for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB 4th term for atom j w.r.t. Beta(r_jk')
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
app3=betaCapSum*angFactor3;
agpdpr1=.5*angFactor4*dbetaCapSq1*betaCapSq2/rij[temp_jk];
agpdpr2=.5*angFactor4*betaCapSq1*dbetaCapSq2/rij[temp_jkp];
bt_pi[nb_ij].dBB[0]-=
app3*dcAng[ang_ijkp][0][ngli]
+app2*dcAng[ang_ijk][0][ngi];
bt_pi[nb_ij].dBB[1]-=
app3*dcAng[ang_ijkp][1][ngli]
+app2*dcAng[ang_ijk][1][ngi];
bt_pi[nb_ij].dBB[2]-=
app3*dcAng[ang_ijkp][2][ngli]
+app2*dcAng[ang_ijk][2][ngi];
bt_pi[nb_jk].dBB[0]+=
agpdpr1*disij[0][temp_jk]
+app1*dcAng[ang_kjkp][0][1]
+app2*dcAng[ang_ijk][0][ngk];
bt_pi[nb_jk].dBB[1]+=
agpdpr1*disij[1][temp_jk]
+app1*dcAng[ang_kjkp][1][1]
+app2*dcAng[ang_ijk][1][ngk];
bt_pi[nb_jk].dBB[2]+=
agpdpr1*disij[2][temp_jk]
+app1*dcAng[ang_kjkp][2][1]
+app2*dcAng[ang_ijk][2][ngk];
bt_pi[nb_jkp].dBB[0]+=
agpdpr2*disij[0][temp_jkp]
+app1*dcAng[ang_kjkp][0][0]
+app3*dcAng[ang_ijkp][0][ngl];
bt_pi[nb_jkp].dBB[1]+=
agpdpr2*disij[1][temp_jkp]
+app1*dcAng[ang_kjkp][1][0]
+app3*dcAng[ang_ijkp][1][ngl];
bt_pi[nb_jkp].dBB[2]+=
agpdpr2*disij[2][temp_jkp]
+app1*dcAng[ang_kjkp][2][0]
+app3*dcAng[ang_ijkp][2][ngl];
}
}
}
//j and k' are different neighbors of i and k is a neighbor of j not equal to i
for(ltmp=0;ltmp<numneigh[i];ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
if(neigh_flag[temp_ikp]) {
kp=iilist[ltmp];
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(ltmp<jtmp) {
njikp=ltmp*(2*numneigh[i]-ltmp-1)/2+(jtmp-ltmp)-1;
ngl=1;
nglj=0;
}
else {
njikp=jtmp*(2*numneigh[i]-jtmp-1)/2+(ltmp-jtmp)-1;
ngl=0;
nglj=1;
}
ang_jikp=cos_index[i]+njikp;
if(ang_jikp>=cos_total) {
error->one(FLERR,"Too many atom triplets for pair bop");
}
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ikp].i=i;
bt_pi[nb_ikp].j=kp;
bt_pi[nb_ikp].temp=temp_ikp;
betaCapSq2=pi_p[itype-1]*betaS[temp_ikp]*betaS[temp_ikp]
-betaP[temp_ikp]*betaP[temp_ikp];
dbetaCapSq2=2.0*pi_p[itype-1]*betaS[temp_ikp]*dBetaS[temp_ikp]
-2.0*betaP[temp_ikp]*dBetaP[temp_ikp];
dotV=(disij[0][temp_jk]*disij[0][temp_ikp]+disij[1][temp_jk]
*disij[1][temp_ikp]+disij[2][temp_jk]*disij[2][temp_ikp])
/(rij[temp_jk]*rij[temp_ikp]);
cosSq1=cosAng[ang_jikp]*cosAng[ang_jikp];
angFactor=dotV+cosAng[ang_jikp]*cosAng[ang_ijk];
angRfactor=4.0*angFactor*dotV;
dAngR1=-angRfactor/rij[temp_jk];
dAngR2=-angRfactor/rij[temp_ikp];
angFactor1=4.0*angFactor*cosAng[ang_jikp]
+2.0*cosAng[ang_ijk]*(1.0-cosSq1);
angFactor2=4.0*angFactor*cosAng[ang_ijk]
+2.0*cosAng[ang_jikp]*(1.0-cosSq);
angFactor3=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//5th BB is 5th term of Eq. 38 (a) Eq. 21 (b) where i , k and k' =neighbors j
BB=BB+betaCapSum*angFactor3;
//app1 is derivative of BB 5th term w.r.t. cos(theta_ijk)
//app2 is derivative of BB 5th term w.r.t. cos(theta_jik')
//agpdpr1 is derivative of BB 5th term for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB 5th term for atom j w.r.t. Beta(r_ik')
//agpdpr3 is derivative of BB 5th term for atom j w.r.t. dot(r_ik',r_ij)
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
agpdpr1=(.5*angFactor3*dbetaCapSq1*betaCapSq2
+betaCapSum*dAngR1)/rij[temp_jk];
agpdpr2=(.5*angFactor3*betaCapSq1*dbetaCapSq2
+betaCapSum*dAngR2)/rij[temp_ikp];
agpdpr3=4.0*betaCapSum*angFactor/(rij[temp_ikp]*rij[temp_jk]);
bt_pi[nb_ij].dBB[0]+=
+app2*dcAng[ang_jikp][0][ngl]
-app1*dcAng[ang_ijk][0][ngi];
bt_pi[nb_ij].dBB[1]+=
+app2*dcAng[ang_jikp][1][ngl]
-app1*dcAng[ang_ijk][1][ngi];
bt_pi[nb_ij].dBB[2]+=
+app2*dcAng[ang_jikp][2][ngl]
-app1*dcAng[ang_ijk][2][ngi];
bt_pi[nb_ikp].dBB[0]+=
agpdpr2*disij[0][temp_ikp]
+agpdpr3*disij[0][temp_jk]
+app2*dcAng[ang_jikp][0][nglj];
bt_pi[nb_ikp].dBB[1]+=
agpdpr2*disij[1][temp_ikp]
+agpdpr3*disij[1][temp_jk]
+app2*dcAng[ang_jikp][1][nglj];
bt_pi[nb_ikp].dBB[2]+=
agpdpr2*disij[2][temp_ikp]
+agpdpr3*disij[2][temp_jk]
+app2*dcAng[ang_jikp][2][nglj];
bt_pi[nb_jk].dBB[0]+=
agpdpr1*disij[0][temp_jk]
+agpdpr3*disij[0][temp_ikp]
+app1*dcAng[ang_ijk][0][ngk];
bt_pi[nb_jk].dBB[1]+=
agpdpr1*disij[1][temp_jk]
+agpdpr3*disij[1][temp_ikp]
+app1*dcAng[ang_ijk][1][ngk];
bt_pi[nb_jk].dBB[2]+=
agpdpr1*disij[2][temp_jk]
+agpdpr3*disij[2][temp_ikp]
+app1*dcAng[ang_ijk][2][ngk];
}
}
}
if(pi_flag==0)
nPiBk[n]=nPiBk[n]+1;
}
}
}
CC=betaP[temp_ij]*betaP[temp_ij]+pi_delta[iij]*pi_delta[iij];
BBrt=sqrt(BB+small6);
AB1=CC+pi_c[iij]*(AA+BBrt)+small7;
AB2=CC+pi_c[iij]*(AA-BBrt+sqrt(small6))+small7;
BBrtR=1.0/BBrt;
ABrtR1=1.0/sqrt(AB1);
ABrtR2=1.0/sqrt(AB2);
// piB is similary formulation to (a) Eq. 36 and (b) Eq. 18
piB[n]=(ABrtR1+ABrtR2)*pi_a[iij]*betaP[temp_ij];
dPiB1=-.5*(cube(ABrtR1)+cube(ABrtR2))*pi_c[iij]*pi_a[iij]*betaP[temp_ij];
dPiB2=.25*BBrtR*(cube(ABrtR2)-cube(ABrtR1))*pi_c[iij]*pi_a[iij]*betaP[temp_ij];
dPiB3=((ABrtR1+ABrtR2)*pi_a[iij]-(cube(ABrtR1)+cube(ABrtR2))*pi_a[iij]
*betaP[temp_ij]*betaP[temp_ij])*dBetaP[temp_ij]/rij[temp_ij];
n++;
pp2=2.0*betaP[temp_ij];
for(m=0;m<nb_t;m++) {
bt_ij=bt_pi[m].temp;
bt_i=bt_pi[m].i;
bt_j=bt_pi[m].j;
for(pp=0;pp<3;pp++) {
bt_pi[m].dPiB[pp]=
+dPiB1*bt_pi[m].dAA[pp]
+dPiB2*bt_pi[m].dBB[pp];
ftmp[pp]=pp2*bt_pi[m].dPiB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],disij[0][bt_ij],disij[1][bt_ij],disij[2][bt_ij]);
}
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp2*dPiB3*disij[pp][temp_ij];
f[i][pp]-=ftmp[pp];
f[j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],disij[0][temp_ij],disij[1][temp_ij],disij[2][temp_ij]);
}
}
}
}
}
destroy_pi();
}
/* ---------------------------------------------------------------------- */
void PairBOP::PiBo_otf()
{
int new_n_tot;
int i,j,k,kp,m,n,pp,nb_t;
int iij,iik,iikp,ji,ki,ijkp,ijk;
int nsearch,ncmp;
- int i_tag,j_tag;
+ tagint i_tag,j_tag;
int itmp,ltmp,jtmp,ktmp;
int pi_flag,ks;
int nlocal;
int inum,*ilist,*iilist,*jlist;
int **firstneigh,*numneigh;
int itype,jtype,ktype,kptype;
int temp_ij,temp_ik,temp_ikp;
int temp_jk,temp_jkp;
int nb_ij,nb_ik,nb_jk,nb_ikp,nb_jkp;
int bt_i,bt_j;
double AA,BB,CC,DD,EE,FF;
double cosSq,sinFactor,cosFactor;
double cosSq1,dotV,BBrt,AB1,AB2;
double BBrtR,ABrtR,ABrtR1,ABrtR2;
double angFactor,angFactor1,angFactor2;
double angFactor3,angFactor4,angRfactor;
double dAngR1,dAngR2,agpdpr3;
double agpdpr1,agpdpr2,app1,app2,app3;
double betaCapSq1,dbetaCapSq1;
double betaCapSq2,dbetaCapSq2;
double betaCapSum,ps;
double ftmp[3],xtmp[3];
double dPiB1,dPiB2,dPiB3,pp2;
double dis_ij[3],rsq_ij,r_ij;
double betaP_ij,dBetaP_ij;
double dis_ik[3],rsq_ik,r_ik;
double betaS_ik,dBetaS_ik;
double betaP_ik,dBetaP_ik;
double dis_ikp[3],rsq_ikp,r_ikp;
double betaS_ikp,dBetaS_ikp;
double betaP_ikp,dBetaP_ikp;
double dis_jk[3],rsq_jk,r_jk;
double betaS_jk,dBetaS_jk;
double betaP_jk,dBetaP_jk;
double dis_jkp[3],rsq_jkp,r_jkp;
double betaS_jkp,dBetaS_jkp;
double betaP_jkp,dBetaP_jkp;
double cosAng_jik,dcA_jik[3][2];
double cosAng_jikp,dcA_jikp[3][2];
double cosAng_kikp,dcA_kikp[3][2];
double cosAng_ijk,dcA_ijk[3][2];
double cosAng_ijkp,dcA_ijkp[3][2];
double cosAng_kjkp,dcA_kjkp[3][2];
int newton_pair = force->newton_pair;
double **f = atom->f;
double **x = atom->x;
int *type = atom->type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
nlocal = atom->nlocal;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
inum = list->inum;
ilist = list->ilist;
n=0;
if(nb_pi>16) {
nb_pi=16;
}
if(nb_pi==0) {
nb_pi=(maxneigh)*(maxneigh/2);
}
// Loop over all local atoms for i
if(allocate_pi) {
destroy_pi();
}
create_pi(nb_pi);
for(itmp=0;itmp<inum;itmp++) {
nb_t=0;
i = ilist[itmp];
itype = map[type[i]]+1;
i_tag=tag[i];
// j is a loop over all neighbors of i
iilist=firstneigh[i];
for(jtmp=0;jtmp<numneigh[i];jtmp++) {
for(m=0;m<nb_pi;m++) {
for(pp=0;pp<3;pp++) {
bt_pi[m].dAA[pp]=0.0;
bt_pi[m].dBB[pp]=0.0;
bt_pi[m].dPiB[pp]=0.0;
}
bt_pi[m].i=-1;
bt_pi[m].j=-1;
}
temp_ij=BOP_index[i]+jtmp;
j=iilist[jtmp];
jlist=firstneigh[j];
jtype=map[type[j]]+1;
j_tag=tag[j];
nb_t=0;
ftmp[0]=0.0;
ftmp[1]=0.0;
ftmp[2]=0.0;
if(j_tag>=i_tag) {
if(itype==jtype)
iij=itype-1;
else if(itype<jtype)
iij=itype*bop_types-itype*(itype+1)/2+jtype-1;
else
iij=jtype*bop_types-jtype*(jtype+1)/2+itype-1;
AA=0.0;
BB=0.0;
nPiBk[n]=0;
for(ji=0;ji<numneigh[j];ji++) {
if(x[jlist[ji]][0]==x[i][0]) {
if(x[jlist[ji]][1]==x[i][1]) {
if(x[jlist[ji]][2]==x[i][2]) {
break;
}
}
}
}
nb_ij=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ij].i=i;
bt_pi[nb_ij].j=j;
bt_pi[nb_ij].temp=temp_ij;
dis_ij[0]=x[j][0]-x[i][0];
dis_ij[1]=x[j][1]-x[i][1];
dis_ij[2]=x[j][2]-x[i][2];
rsq_ij=dis_ij[0]*dis_ij[0]
+dis_ij[1]*dis_ij[1]
+dis_ij[2]*dis_ij[2];
r_ij=sqrt(rsq_ij);
if(r_ij<=rcut[iij]) {
ps=r_ij*rdr[iij]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaP_ij=((pBetaP3[iij][ks-1]*ps+pBetaP2[iij][ks-1])*ps
+pBetaP1[iij][ks-1])*ps+pBetaP[iij][ks-1];
dBetaP_ij=(pBetaP6[iij][ks-1]*ps+pBetaP5[iij][ks-1])*ps
+pBetaP4[iij][ks-1];
// j and k are different neighbors of i
for(ktmp=0;ktmp<numneigh[i];ktmp++) {
if(ktmp!=jtmp) {
temp_ik=BOP_index[i]+ktmp;
k=iilist[ktmp];
ktype=map[type[k]]+1;
if(itype==ktype)
iik=itype-1;
else if(itype<ktype)
iik=itype*bop_types-itype*(itype+1)/2+ktype-1;
else
iik=ktype*bop_types-ktype*(ktype+1)/2+itype-1;
dis_ik[0]=x[k][0]-x[i][0];
dis_ik[1]=x[k][1]-x[i][1];
dis_ik[2]=x[k][2]-x[i][2];
rsq_ik=dis_ik[0]*dis_ik[0]
+dis_ik[1]*dis_ik[1]
+dis_ik[2]*dis_ik[2];
r_ik=sqrt(rsq_ik);
if(r_ik<=rcut[iik]) {
ps=r_ik*rdr[iik]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ik=((pBetaS3[iik][ks-1]*ps+pBetaS2[iik][ks-1])*ps
+pBetaS1[iik][ks-1])*ps+pBetaS[iik][ks-1];
dBetaS_ik=(pBetaS6[iik][ks-1]*ps+pBetaS5[iik][ks-1])*ps
+pBetaS4[iik][ks-1];
betaP_ik=((pBetaP3[iik][ks-1]*ps+pBetaP2[iik][ks-1])*ps
+pBetaP1[iik][ks-1])*ps+pBetaP[iik][ks-1];
dBetaP_ik=(pBetaP6[iik][ks-1]*ps+pBetaP5[iik][ks-1])*ps
+pBetaP4[iik][ks-1];
cosAng_jik=(dis_ij[0]*dis_ik[0]+dis_ij[1]*dis_ik[1]
+dis_ij[2]*dis_ik[2])/(r_ij*r_ik);
dcA_jik[0][0]=(dis_ik[0]*r_ij*r_ik-cosAng_jik
*dis_ij[0]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][0]=(dis_ik[1]*r_ij*r_ik-cosAng_jik
*dis_ij[1]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][0]=(dis_ik[2]*r_ij*r_ik-cosAng_jik
*dis_ij[2]*r_ik*r_ik)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[0][1]=(dis_ij[0]*r_ij*r_ik-cosAng_jik
*dis_ik[0]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[1][1]=(dis_ij[1]*r_ij*r_ik-cosAng_jik
*dis_ik[1]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
dcA_jik[2][1]=(dis_ij[2]*r_ij*r_ik-cosAng_jik
*dis_ik[2]*r_ij*r_ij)/(r_ij*r_ij*r_ik*r_ik);
nb_ik=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ik].i=i;
bt_pi[nb_ik].j=k;
bt_pi[nb_ik].temp=temp_ik;
cosSq=cosAng_jik*cosAng_jik;
sinFactor=.5*(1.0-cosSq)*pi_p[itype-1]*betaS_ik;
cosFactor=.5*(1.0+cosSq)*betaP_ik;
betaCapSq1=pi_p[itype-1]*betaS_ik*betaS_ik-betaP_ik
*betaP_ik;
dbetaCapSq1=2.0*pi_p[itype-1]*betaS_ik*dBetaS_ik
-2.0*betaP_ik*dBetaP_ik;
//AA is Eq. 37 (a) and Eq. 19 (b) or i atoms
//1st BB is first term of Eq. 38 (a) where j and k =neighbors i
AA=AA+sinFactor*betaS_ik+cosFactor*betaP_ik;
BB=BB+.25*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*betaCapSq1;
//agpdpr1 is derivative of AA w.r.t. for atom i w.r.t. Beta(r_ik)
//agpdpr2 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik)
//app1 is derivative of AA w.r.t. for atom i w.r.t. cos(theta_jik)
//app2 is derivative of BB w.r.t. for atom i w.r.t. cos(theta_jik)
agpdpr1=(2.0*sinFactor*dBetaS_ik+2.0*cosFactor
*dBetaP_ik)/r_ik;
app1=cosAng_jik*(-pi_p[itype-1]*betaS_ik*betaS_ik
+betaP_ik*betaP_ik);
app2=-(1.0-cosSq)*cosAng_jik*betaCapSq1*betaCapSq1;
agpdpr2=.5*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*dbetaCapSq1/r_ik;
itypePiBk[n][nPiBk[n]]=k;
bt_pi[nb_ij].dAA[0]+=
app1*dcA_jik[0][0];
bt_pi[nb_ij].dAA[1]+=
app1*dcA_jik[1][0];
bt_pi[nb_ij].dAA[2]+=
app1*dcA_jik[2][0];
bt_pi[nb_ij].dBB[0]+=
app2*dcA_jik[0][0];
bt_pi[nb_ij].dBB[1]+=
app2*dcA_jik[1][0];
bt_pi[nb_ij].dBB[2]+=
app2*dcA_jik[2][0];
bt_pi[nb_ik].dAA[0]+=
agpdpr1*dis_ik[0]
+app1*dcA_jik[0][1];
bt_pi[nb_ik].dAA[1]+=
agpdpr1*dis_ik[1]
+app1*dcA_jik[1][1];
bt_pi[nb_ik].dAA[2]+=
agpdpr1*dis_ik[2]
+app1*dcA_jik[2][1];
bt_pi[nb_ik].dBB[0]+=
app2*dcA_jik[0][1]
+agpdpr2*dis_ik[0];
bt_pi[nb_ik].dBB[1]+=
app2*dcA_jik[1][1]
+agpdpr2*dis_ik[1];
bt_pi[nb_ik].dBB[2]+=
app2*dcA_jik[2][1]
+agpdpr2*dis_ik[2];
// j and k and k' are different neighbors of i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
kp=iilist[ltmp];
kptype=map[type[kp]]+1;
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(itype==kptype)
iikp=itype-1;
else if(itype<kptype)
iikp=itype*bop_types-itype*(itype+1)/2+kptype-1;
else
iikp=kptype*bop_types-kptype*(kptype+1)/2+itype-1;
dis_ikp[0]=x[kp][0]-x[i][0];
dis_ikp[1]=x[kp][1]-x[i][1];
dis_ikp[2]=x[kp][2]-x[i][2];
rsq_ikp=dis_ikp[0]*dis_ikp[0]
+dis_ikp[1]*dis_ikp[1]
+dis_ikp[2]*dis_ikp[2];
r_ikp=sqrt(rsq_ikp);
if(r_ikp<=rcut[iikp]) {
ps=r_ikp*rdr[iikp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ikp=((pBetaS3[iikp][ks-1]*ps+pBetaS2[iikp][ks-1])*ps
+pBetaS1[iikp][ks-1])*ps+pBetaS[iikp][ks-1];
dBetaS_ikp=(pBetaS6[iikp][ks-1]*ps+pBetaS5[iikp][ks-1])*ps
+pBetaS4[iikp][ks-1];
betaP_ikp=((pBetaP3[iikp][ks-1]*ps+pBetaP2[iikp][ks-1])*ps
+pBetaP1[iikp][ks-1])*ps+pBetaP[iikp][ks-1];
dBetaP_ikp=(pBetaP6[iikp][ks-1]*ps+pBetaP5[iikp][ks-1])*ps
+pBetaP4[iikp][ks-1];
cosAng_jikp=(dis_ij[0]*dis_ikp[0]+dis_ij[1]*dis_ikp[1]
+dis_ij[2]*dis_ikp[2])/(r_ij*r_ikp);
dcA_jikp[0][0]=(dis_ikp[0]*r_ij*r_ikp-cosAng_jikp
*dis_ij[0]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][0]=(dis_ikp[1]*r_ij*r_ikp-cosAng_jikp
*dis_ij[1]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][0]=(dis_ikp[2]*r_ij*r_ikp-cosAng_jikp
*dis_ij[2]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[0][1]=(dis_ij[0]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[0]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][1]=(dis_ij[1]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[1]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][1]=(dis_ij[2]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[2]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
cosAng_kikp=(dis_ik[0]*dis_ikp[0]+dis_ik[1]*dis_ikp[1]
+dis_ik[2]*dis_ikp[2])/(r_ik*r_ikp);
dcA_kikp[0][0]=(dis_ikp[0]*r_ik*r_ikp-cosAng_kikp
*dis_ik[0]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[1][0]=(dis_ikp[1]*r_ik*r_ikp-cosAng_kikp
*dis_ik[1]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[2][0]=(dis_ikp[2]*r_ik*r_ikp-cosAng_kikp
*dis_ik[2]*r_ikp*r_ikp)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[0][1]=(dis_ik[0]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[0]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[1][1]=(dis_ik[1]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[1]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
dcA_kikp[2][1]=(dis_ik[2]*r_ik*r_ikp-cosAng_kikp
*dis_ikp[2]*r_ik*r_ik)/(r_ik*r_ik*r_ikp*r_ikp);
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ikp].i=i;
bt_pi[nb_ikp].j=kp;
bt_pi[nb_ikp].temp=temp_ikp;
betaCapSq2=pi_p[itype-1]*betaS_ikp*betaS_ikp
-betaP_ikp*betaP_ikp;
dbetaCapSq2=2.0*pi_p[itype-1]*betaS_ikp*dBetaS_ikp
-2.0*betaP_ikp*dBetaP_ikp;
cosSq1=cosAng_jikp*cosAng_jikp;
angFactor=cosAng_kikp-cosAng_jikp*cosAng_jik;
angFactor1=4.0*angFactor;
angFactor2=-angFactor1*cosAng_jikp
+2.0*cosAng_jik*(1.0-cosSq1);
angFactor3=-angFactor1*cosAng_jik
+2.0*cosAng_jikp*(1.0-cosSq);
angFactor4=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//2nd BB is third term of Eq. 38 (a) where j , k and k'=neighbors i
BB=BB+betaCapSum*angFactor4;
//agpdpr1 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik)
//agpdpr2 is derivative of BB w.r.t. for atom i w.r.t. Beta(r_ik')
//app1 is derivative of BB 3rd term w.r.t. cos(theta_kik')
//app2 is derivative of BB 3rd term w.r.t. cos(theta_jik)
//app3 is derivative of BB 3rd term w.r.t. cos(theta_jik')
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
app3=betaCapSum*angFactor3;
agpdpr1=.5*angFactor4*dbetaCapSq1*betaCapSq2/r_ik;
agpdpr2=.5*angFactor4*betaCapSq1*dbetaCapSq2/r_ikp;
bt_pi[nb_ij].dBB[0]+=
app2*dcA_jik[0][0]
+app3*dcA_jikp[0][0];
bt_pi[nb_ij].dBB[1]+=
app2*dcA_jik[1][0]
+app3*dcA_jikp[1][0];
bt_pi[nb_ij].dBB[2]+=
app2*dcA_jik[2][0]
+app3*dcA_jikp[2][0];
bt_pi[nb_ik].dBB[0]+=
agpdpr1*dis_ik[0]
+app1*dcA_kikp[0][0]
+app2*dcA_jik[0][1];
bt_pi[nb_ik].dBB[1]+=
agpdpr1*dis_ik[1]
+app1*dcA_kikp[1][0]
+app2*dcA_jik[1][1];
bt_pi[nb_ik].dBB[2]+=
agpdpr1*dis_ik[2]
+app1*dcA_kikp[2][0]
+app2*dcA_jik[2][1];
bt_pi[nb_ikp].dBB[0]+=
agpdpr2*dis_ikp[0]
+app1*dcA_kikp[0][1]
+app3*dcA_jikp[0][1];
bt_pi[nb_ikp].dBB[1]+=
agpdpr2*dis_ikp[1]
+app1*dcA_kikp[1][1]
+app3*dcA_jikp[1][1];
bt_pi[nb_ikp].dBB[2]+=
agpdpr2*dis_ikp[2]
+app1*dcA_kikp[2][1]
+app3*dcA_jikp[2][1];
}
}
}
nPiBk[n]=nPiBk[n]+1;
}
}
}
//j is a neighbor of i and k is a neighbor of j and equal to i
for(ki=0;ki<numneigh[j];ki++) {
k=jlist[ki];
if(x[k][0]==x[i][0]) {
if(x[k][1]==x[i][1]) {
if(x[k][2]==x[i][2]) {
break;
}
}
}
}
//j is a neighbor of i and k is a neighbor of j not equal to i
for(ktmp=0;ktmp<numneigh[j];ktmp++) {
if(ktmp!=ki) {
temp_jk=BOP_index[j]+ktmp;
k=jlist[ktmp];
ktype=map[type[k]]+1;
pi_flag=0;
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[k][0]) {
if(x[ncmp][1]==x[k][1]) {
if(x[ncmp][2]==x[k][2]) {
pi_flag=1;
break;
}
}
}
}
if(pi_flag==0) {
itypePiBk[n][nPiBk[n]]=k;
}
if(jtype==ktype)
ijk=jtype-1;
else if(jtype<ktype)
ijk=jtype*bop_types-jtype*(jtype+1)/2+ktype-1;
else
ijk=ktype*bop_types-ktype*(ktype+1)/2+jtype-1;
dis_jk[0]=x[k][0]-x[j][0];
dis_jk[1]=x[k][1]-x[j][1];
dis_jk[2]=x[k][2]-x[j][2];
rsq_jk=dis_jk[0]*dis_jk[0]
+dis_jk[1]*dis_jk[1]
+dis_jk[2]*dis_jk[2];
r_jk=sqrt(rsq_jk);
if(r_jk<=rcut[ijk]) {
ps=r_jk*rdr[ijk]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jk=((pBetaS3[ijk][ks-1]*ps+pBetaS2[ijk][ks-1])*ps
+pBetaS1[ijk][ks-1])*ps+pBetaS[ijk][ks-1];
dBetaS_jk=(pBetaS6[ijk][ks-1]*ps+pBetaS5[ijk][ks-1])*ps
+pBetaS4[ijk][ks-1];
betaP_jk=((pBetaP3[ijk][ks-1]*ps+pBetaP2[ijk][ks-1])*ps
+pBetaP1[ijk][ks-1])*ps+pBetaP[ijk][ks-1];
dBetaP_jk=(pBetaP6[ijk][ks-1]*ps+pBetaP5[ijk][ks-1])*ps
+pBetaP4[ijk][ks-1];
cosAng_ijk=(-dis_ij[0]*dis_jk[0]-dis_ij[1]*dis_jk[1]
-dis_ij[2]*dis_jk[2])/(r_ij*r_jk);
dcA_ijk[0][0]=(dis_jk[0]*r_ij*r_jk-cosAng_ijk
*-dis_ij[0]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][0]=(dis_jk[1]*r_ij*r_jk-cosAng_ijk
*-dis_ij[1]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][0]=(dis_jk[2]*r_ij*r_jk-cosAng_ijk
*-dis_ij[2]*r_jk*r_jk)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[0][1]=(-dis_ij[0]*r_ij*r_jk-cosAng_ijk
*dis_jk[0]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[1][1]=(-dis_ij[1]*r_ij*r_jk-cosAng_ijk
*dis_jk[1]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
dcA_ijk[2][1]=(-dis_ij[2]*r_ij*r_jk-cosAng_ijk
*dis_jk[2]*r_ij*r_ij)/(r_ij*r_ij*r_jk*r_jk);
nb_jk=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_jk].i=j;
bt_pi[nb_jk].j=k;
bt_pi[nb_jk].temp=temp_jk;
cosSq=cosAng_ijk*cosAng_ijk;
sinFactor=.5*(1.0-cosSq)*pi_p[jtype-1]*betaS_jk;
cosFactor=.5*(1.0+cosSq)*betaP_jk;
betaCapSq1=pi_p[jtype-1]*betaS_jk*betaS_jk
-betaP_jk*betaP_jk;
dbetaCapSq1=2.0*pi_p[jtype-1]*betaS_jk*dBetaS_jk
-2.0*betaP_jk*dBetaP_jk;
//AA is Eq. 37 (a) and Eq. 19 (b) for j atoms
//3rd BB is 2nd term of Eq. 38 (a) where i and k =neighbors j
AA=AA+sinFactor*betaS_jk+cosFactor*betaP_jk;
BB=BB+.25*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*betaCapSq1;
agpdpr1=(2.0*sinFactor*dBetaS_jk+2.0*cosFactor
*dBetaP_jk)/r_jk;
//agpdpr1 is derivative of AA for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB for atom j w.r.t. Beta(r_jk)
//app1 is derivative of AA for j atom w.r.t. cos(theta_ijk)
//app2 is derivative of BB 2nd term w.r.t. cos(theta_ijk)
agpdpr2=.5*(1.0-cosSq)*(1.0-cosSq)*betaCapSq1*dbetaCapSq1/r_jk;
app1=cosAng_ijk*(-pi_p[jtype-1]*betaS_jk*betaS_jk
+betaP_jk*betaP_jk);
app2=-(1.0-cosSq)*cosAng_ijk*betaCapSq1*betaCapSq1;
bt_pi[nb_ij].dAA[0]-=
app1*dcA_ijk[0][0];
bt_pi[nb_ij].dAA[1]-=
app1*dcA_ijk[1][0];
bt_pi[nb_ij].dAA[2]-=
app1*dcA_ijk[2][0];
bt_pi[nb_ij].dBB[0]-=
app2*dcA_ijk[0][0];
bt_pi[nb_ij].dBB[1]-=
app2*dcA_ijk[1][0];
bt_pi[nb_ij].dBB[2]-=
app2*dcA_ijk[2][0];
bt_pi[nb_jk].dAA[0]+=
agpdpr1*dis_jk[0]
+app1*dcA_ijk[0][1];
bt_pi[nb_jk].dAA[1]+=
agpdpr1*dis_jk[1]
+app1*dcA_ijk[1][1];
bt_pi[nb_jk].dAA[2]+=
agpdpr1*dis_jk[2]
+app1*dcA_ijk[2][1];
bt_pi[nb_jk].dBB[0]+=
app2*dcA_ijk[0][1]
+agpdpr2*dis_jk[0];
bt_pi[nb_jk].dBB[1]+=
app2*dcA_ijk[1][1]
+agpdpr2*dis_jk[1];
bt_pi[nb_jk].dBB[2]+=
app2*dcA_ijk[2][1]
+agpdpr2*dis_jk[2];
//j is a neighbor of i and k and k' are different neighbors of j not equal to i
for(ltmp=0;ltmp<ktmp;ltmp++) {
if(ltmp!=ki) {
temp_jkp=BOP_index[j]+ltmp;
kp=jlist[ltmp];
kptype=map[type[kp]]+1;
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(jtype==kptype)
ijkp=jtype-1;
else if(jtype<kptype)
ijkp=jtype*bop_types-jtype*(jtype+1)/2+kptype-1;
else
ijkp=kptype*bop_types-kptype*(kptype+1)/2+jtype-1;
dis_jkp[0]=x[kp][0]-x[j][0];
dis_jkp[1]=x[kp][1]-x[j][1];
dis_jkp[2]=x[kp][2]-x[j][2];
rsq_jkp=dis_jkp[0]*dis_jkp[0]
+dis_jkp[1]*dis_jkp[1]
+dis_jkp[2]*dis_jkp[2];
r_jkp=sqrt(rsq_jkp);
if(r_jkp<=rcut[ijkp]) {
ps=r_jkp*rdr[ijkp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_jkp=((pBetaS3[ijkp][ks-1]*ps+pBetaS2[ijkp][ks-1])*ps
+pBetaS1[ijkp][ks-1])*ps+pBetaS[ijkp][ks-1];
dBetaS_jkp=(pBetaS6[ijkp][ks-1]*ps+pBetaS5[ijkp][ks-1])*ps
+pBetaS4[ijkp][ks-1];
betaP_jkp=((pBetaP3[ijkp][ks-1]*ps+pBetaP2[ijkp][ks-1])*ps
+pBetaP1[ijkp][ks-1])*ps+pBetaP[ijkp][ks-1];
dBetaP_jkp=(pBetaP6[ijkp][ks-1]*ps+pBetaP5[ijkp][ks-1])*ps
+pBetaP4[ijkp][ks-1];
cosAng_ijkp=(-dis_ij[0]*dis_jkp[0]-dis_ij[1]*dis_jkp[1]
-dis_ij[2]*dis_jkp[2])/(r_ij*r_jkp);
dcA_ijkp[0][0]=(dis_jkp[0]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[0]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][0]=(dis_jkp[1]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[1]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][0]=(dis_jkp[2]*r_ij*r_jkp-cosAng_ijkp
*-dis_ij[2]*r_jkp*r_jkp)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[0][1]=(-dis_ij[0]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[0]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[1][1]=(-dis_ij[1]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[1]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
dcA_ijkp[2][1]=(-dis_ij[2]*r_ij*r_jkp-cosAng_ijkp
*dis_jkp[2]*r_ij*r_ij)/(r_ij*r_ij*r_jkp*r_jkp);
cosAng_kjkp=(dis_jk[0]*dis_jkp[0]+dis_jk[1]*dis_jkp[1]
+dis_jk[2]*dis_jkp[2])/(r_jk*r_jkp);
dcA_kjkp[0][0]=(dis_jkp[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[0]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][0]=(dis_jkp[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[1]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][0]=(dis_jkp[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jk[2]*r_jkp*r_jkp)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[0][1]=(dis_jk[0]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[0]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[1][1]=(dis_jk[1]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[1]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
dcA_kjkp[2][1]=(dis_jk[2]*r_jk*r_jkp-cosAng_kjkp
*dis_jkp[2]*r_jk*r_jk)/(r_jk*r_jk*r_jkp*r_jkp);
nb_jkp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_jkp].i=j;
bt_pi[nb_jkp].j=kp;
bt_pi[nb_jkp].temp=temp_jkp;
betaCapSq2=pi_p[jtype-1]*betaS_jkp*betaS_jkp
-betaP_jkp*betaP_jkp;
dbetaCapSq2=2.0*pi_p[jtype-1]*betaS_jkp*dBetaS_jkp
-2.0*betaP_jkp*dBetaP_jkp;
cosSq1=cosAng_ijkp*cosAng_ijkp;
angFactor=cosAng_kjkp-cosAng_ijkp*cosAng_ijk;
angFactor1=4.0*angFactor;
angFactor2=-angFactor1*cosAng_ijkp
+2.0*cosAng_ijk*(1.0-cosSq1);
angFactor3=-angFactor1*cosAng_ijk
+2.0*cosAng_ijkp*(1.0-cosSq);
angFactor4=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//4th BB is 4th term of Eq. 38 (a) where i , k and k' =neighbors j
BB=BB+betaCapSum*angFactor4;
//app1 is derivative of BB 4th term w.r.t. cos(theta_kjk')
//app2 is derivative of BB 4th term w.r.t. cos(theta_ijk)
//app3 is derivative of BB 4th term w.r.t. cos(theta_ijk')
//agpdpr1 is derivative of BB 4th term for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB 4th term for atom j w.r.t. Beta(r_jk')
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
app3=betaCapSum*angFactor3;
agpdpr1=.5*angFactor4*dbetaCapSq1*betaCapSq2/r_jk;
agpdpr2=.5*angFactor4*betaCapSq1*dbetaCapSq2/r_jkp;
bt_pi[nb_ij].dBB[0]-=
app3*dcA_ijkp[0][0]
+app2*dcA_ijk[0][0];
bt_pi[nb_ij].dBB[1]-=
app3*dcA_ijkp[1][0]
+app2*dcA_ijk[1][0];
bt_pi[nb_ij].dBB[2]-=
app3*dcA_ijkp[2][0]
+app2*dcA_ijk[2][0];
bt_pi[nb_jk].dBB[0]+=
agpdpr1*dis_jk[0]
+app1*dcA_kjkp[0][0]
+app2*dcA_ijk[0][1];
bt_pi[nb_jk].dBB[1]+=
agpdpr1*dis_jk[1]
+app1*dcA_kjkp[1][0]
+app2*dcA_ijk[1][1];
bt_pi[nb_jk].dBB[2]+=
agpdpr1*dis_jk[2]
+app1*dcA_kjkp[2][0]
+app2*dcA_ijk[2][1];
bt_pi[nb_jkp].dBB[0]+=
agpdpr2*dis_jkp[0]
+app1*dcA_kjkp[0][1]
+app3*dcA_ijkp[0][1];
bt_pi[nb_jkp].dBB[1]+=
agpdpr2*dis_jkp[1]
+app1*dcA_kjkp[1][1]
+app3*dcA_ijkp[1][1];
bt_pi[nb_jkp].dBB[2]+=
agpdpr2*dis_jkp[2]
+app1*dcA_kjkp[2][1]
+app3*dcA_ijkp[2][1];
}
}
}
//j and k' are different neighbors of i and k is a neighbor of j not equal to i
for(ltmp=0;ltmp<numneigh[i];ltmp++) {
if(ltmp!=jtmp) {
temp_ikp=BOP_index[i]+ltmp;
kp=iilist[ltmp];
kptype=map[type[kp]]+1;
for(nsearch=0;nsearch<nPiBk[n];nsearch++) {
ncmp=itypePiBk[n][nsearch];
if(x[ncmp][0]==x[kp][0]) {
if(x[ncmp][1]==x[kp][1]) {
if(x[ncmp][2]==x[kp][2]) {
break;
}
}
}
}
if(itype==kptype)
iikp=itype-1;
else if(itype<kptype)
iikp=itype*bop_types-itype*(itype+1)/2+kptype-1;
else
iikp=kptype*bop_types-kptype*(kptype+1)/2+itype-1;
dis_ikp[0]=x[kp][0]-x[i][0];
dis_ikp[1]=x[kp][1]-x[i][1];
dis_ikp[2]=x[kp][2]-x[i][2];
rsq_ikp=dis_ikp[0]*dis_ikp[0]
+dis_ikp[1]*dis_ikp[1]
+dis_ikp[2]*dis_ikp[2];
r_ikp=sqrt(rsq_ikp);
if(r_ikp<=rcut[iikp]) {
ps=r_ikp*rdr[iikp]+1.0;
ks=(int)ps;
if(nr-1<ks)
ks=nr-1;
ps=ps-ks;
if(ps>1.0)
ps=1.0;
betaS_ikp=((pBetaS3[iikp][ks-1]*ps+pBetaS2[iikp][ks-1])*ps
+pBetaS1[iikp][ks-1])*ps+pBetaS[iikp][ks-1];
dBetaS_ikp=(pBetaS6[iikp][ks-1]*ps+pBetaS5[iikp][ks-1])*ps
+pBetaS4[iikp][ks-1];
betaP_ikp=((pBetaP3[iikp][ks-1]*ps+pBetaP2[iikp][ks-1])*ps
+pBetaP1[iikp][ks-1])*ps+pBetaP[iikp][ks-1];
dBetaP_ikp=(pBetaP6[iikp][ks-1]*ps+pBetaP5[iikp][ks-1])*ps
+pBetaP4[iikp][ks-1];
cosAng_jikp=(dis_ij[0]*dis_ikp[0]+dis_ij[1]*dis_ikp[1]
+dis_ij[2]*dis_ikp[2])/(r_ij*r_ikp);
dcA_jikp[0][0]=(dis_ikp[0]*r_ij*r_ikp-cosAng_jikp
*dis_ij[0]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][0]=(dis_ikp[1]*r_ij*r_ikp-cosAng_jikp
*dis_ij[1]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][0]=(dis_ikp[2]*r_ij*r_ikp-cosAng_jikp
*dis_ij[2]*r_ikp*r_ikp)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[0][1]=(dis_ij[0]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[0]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[1][1]=(dis_ij[1]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[1]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
dcA_jikp[2][1]=(dis_ij[2]*r_ij*r_ikp-cosAng_jikp
*dis_ikp[2]*r_ij*r_ij)/(r_ij*r_ij*r_ikp*r_ikp);
nb_ikp=nb_t;
nb_t++;
if(nb_t>nb_pi) {
new_n_tot=nb_pi+maxneigh;
grow_pi(nb_pi,new_n_tot);
nb_pi=new_n_tot;
}
bt_pi[nb_ikp].i=i;
bt_pi[nb_ikp].j=kp;
bt_pi[nb_ikp].temp=temp_ikp;
betaCapSq2=pi_p[itype-1]*betaS_ikp*betaS_ikp
-betaP_ikp*betaP_ikp;
dbetaCapSq2=2.0*pi_p[itype-1]*betaS_ikp*dBetaS_ikp
-2.0*betaP_ikp*dBetaP_ikp;
dotV=(dis_jk[0]*dis_ikp[0]+dis_jk[1]
*dis_ikp[1]+dis_jk[2]*dis_ikp[2])
/(r_jk*r_ikp);
cosSq1=cosAng_jikp*cosAng_jikp;
angFactor=dotV+cosAng_jikp*cosAng_ijk;
angRfactor=4.0*angFactor*dotV;
dAngR1=-angRfactor/r_jk;
dAngR2=-angRfactor/r_ikp;
angFactor1=4.0*angFactor*cosAng_jikp
+2.0*cosAng_ijk*(1.0-cosSq1);
angFactor2=4.0*angFactor*cosAng_ijk
+2.0*cosAng_jikp*(1.0-cosSq);
angFactor3=2.0*angFactor*angFactor-(1.0-cosSq)*(1.0-cosSq1);
betaCapSum=.5*betaCapSq1*betaCapSq2;
//5th BB is 5th term of Eq. 38 (a) Eq. 21 (b) where i , k and k' =neighbors j
BB=BB+betaCapSum*angFactor3;
//app1 is derivative of BB 5th term w.r.t. cos(theta_ijk)
//app2 is derivative of BB 5th term w.r.t. cos(theta_jik')
//agpdpr1 is derivative of BB 5th term for atom j w.r.t. Beta(r_jk)
//agpdpr2 is derivative of BB 5th term for atom j w.r.t. Beta(r_ik')
//agpdpr3 is derivative of BB 5th term for atom j w.r.t. dot(r_ik',r_ij)
app1=betaCapSum*angFactor1;
app2=betaCapSum*angFactor2;
agpdpr1=(.5*angFactor3*dbetaCapSq1*betaCapSq2
+betaCapSum*dAngR1)/r_jk;
agpdpr2=(.5*angFactor3*betaCapSq1*dbetaCapSq2
+betaCapSum*dAngR2)/r_ikp;
agpdpr3=4.0*betaCapSum*angFactor/(r_ikp*r_jk);
bt_pi[nb_ij].dBB[0]+=
+app2*dcA_jikp[0][0]
-app1*dcA_ijk[0][0];
bt_pi[nb_ij].dBB[1]+=
+app2*dcA_jikp[1][0]
-app1*dcA_ijk[1][0];
bt_pi[nb_ij].dBB[2]+=
+app2*dcA_jikp[2][0]
-app1*dcA_ijk[2][0];
bt_pi[nb_ikp].dBB[0]+=
agpdpr2*dis_ikp[0]
+agpdpr3*dis_jk[0]
+app2*dcA_jikp[0][1];
bt_pi[nb_ikp].dBB[1]+=
agpdpr2*dis_ikp[1]
+agpdpr3*dis_jk[1]
+app2*dcA_jikp[1][1];
bt_pi[nb_ikp].dBB[2]+=
agpdpr2*dis_ikp[2]
+agpdpr3*dis_jk[2]
+app2*dcA_jikp[2][1];
bt_pi[nb_jk].dBB[0]+=
agpdpr1*dis_jk[0]
+agpdpr3*dis_ikp[0]
+app1*dcA_ijk[0][1];
bt_pi[nb_jk].dBB[1]+=
agpdpr1*dis_jk[1]
+agpdpr3*dis_ikp[1]
+app1*dcA_ijk[1][1];
bt_pi[nb_jk].dBB[2]+=
agpdpr1*dis_jk[2]
+agpdpr3*dis_ikp[2]
+app1*dcA_ijk[2][1];
}
}
}
if(pi_flag==0)
nPiBk[n]=nPiBk[n]+1;
}
}
}
CC=betaP_ij*betaP_ij+pi_delta[iij]*pi_delta[iij];
BBrt=sqrt(BB+small6);
AB1=CC+pi_c[iij]*(AA+BBrt)+small7;
AB2=CC+pi_c[iij]*(AA-BBrt+sqrt(small6))+small7;
BBrtR=1.0/BBrt;
ABrtR1=1.0/sqrt(AB1);
ABrtR2=1.0/sqrt(AB2);
// piB is similary formulation to (a) Eq. 36 and (b) Eq. 18
piB[n]=(ABrtR1+ABrtR2)*pi_a[iij]*betaP_ij;
dPiB1=-.5*(cube(ABrtR1)+cube(ABrtR2))*pi_c[iij]*pi_a[iij]*betaP_ij;
dPiB2=.25*BBrtR*(cube(ABrtR2)-cube(ABrtR1))*pi_c[iij]*pi_a[iij]*betaP_ij;
dPiB3=((ABrtR1+ABrtR2)*pi_a[iij]-(cube(ABrtR1)+cube(ABrtR2))*pi_a[iij]
*betaP_ij*betaP_ij)*dBetaP_ij/r_ij;
n++;
pp2=2.0*betaP_ij;
for(m=0;m<nb_t;m++) {
bt_i=bt_pi[m].i;
bt_j=bt_pi[m].j;
xtmp[0]=x[bt_j][0]-x[bt_i][0];
xtmp[1]=x[bt_j][1]-x[bt_i][1];
xtmp[2]=x[bt_j][2]-x[bt_i][2];
for(pp=0;pp<3;pp++) {
bt_pi[m].dPiB[pp]=
+dPiB1*bt_pi[m].dAA[pp]
+dPiB2*bt_pi[m].dBB[pp];
ftmp[pp]=pp2*bt_pi[m].dPiB[pp];
f[bt_i][pp]-=ftmp[pp];
f[bt_j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(bt_i,bt_j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],xtmp[0],xtmp[1],xtmp[2]);
}
}
for(pp=0;pp<3;pp++) {
ftmp[pp]=pp2*dPiB3*dis_ij[pp];
f[i][pp]-=ftmp[pp];
f[j][pp]+=ftmp[pp];
}
if(evflag) {
ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0,ftmp[0],ftmp[1]
,ftmp[2],dis_ij[0],dis_ij[1],dis_ij[2]);
}
}
}
}
}
destroy_pi();
}
/* ----------------------------------------------------------------------
read BOP potential file
------------------------------------------------------------------------- */
void PairBOP::read_file(char *filename)
{
int i,j,k;
int ij,ii,jj;
int buf1;
int n;
double buf2;
char s[MAXLINE];
char buf[2];
MPI_Comm_rank(world,&me);
// read file on proc 0
rcore=0.1;
if (me == 0) {
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open BOP potential file %s",filename);
error->one(FLERR,str);
}
// read parameters
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&bop_types);
fclose(fp);
npairs=bop_types*(bop_types+1)/2;
}
MPI_Bcast(&bop_types,1,MPI_INT,0,world);
MPI_Bcast(&npairs,1,MPI_INT,0,world);
allocate();
memory->create(pi_a,npairs,"BOP:pi_a");
memory->create(pro_delta,bop_types,"BOP:pro_delta");
memory->create(pi_delta,npairs,"BOP:pi_delta");
memory->create(pi_p,bop_types,"BOP:pi_p");
memory->create(pi_c,npairs,"BOP:pi_c");
memory->create(sigma_r0,npairs,"BOP:sigma_r0");
memory->create(pi_r0,npairs,"BOP:pi_r0");
memory->create(phi_r0,npairs,"BOP:phi_r0");
memory->create(sigma_rc,npairs,"BOP:sigma_rc");
memory->create(pi_rc,npairs,"BOP:pi_rc");
memory->create(phi_rc,npairs,"BOP:phi_rc");
memory->create(r1,npairs,"BOP:r1");
memory->create(sigma_beta0,npairs,"BOP:sigma_beta0");
memory->create(pi_beta0,npairs,"BOP:pi_beta0");
memory->create(phi0,npairs,"BOP:phi0");
memory->create(sigma_n,npairs,"BOP:sigma_n");
memory->create(pi_n,npairs,"BOP:pi_n");
memory->create(phi_m,npairs,"BOP:phi_m");
memory->create(sigma_nc,npairs,"BOP:sigma_nc");
memory->create(pi_nc,npairs,"BOP:pi_nc");
memory->create(phi_nc,npairs,"BOP:phi_nc");
memory->create(pro,bop_types,"BOP:pro");
memory->create(sigma_delta,npairs,"BOP:sigma_delta");
memory->create(sigma_c,npairs,"BOP:sigma_c");
memory->create(sigma_a,npairs,"BOP:sigma_a");
memory->create(sigma_g0,bop_types
,bop_types,bop_types,"BOP:sigma_g0");
memory->create(sigma_g1,bop_types
,bop_types,bop_types,"BOP:sigma_g1");
memory->create(sigma_g2,bop_types
,bop_types,bop_types,"BOP:sigma_g2");
memory->create(sigma_g3,bop_types
,bop_types,bop_types,"BOP:sigma_g3");
memory->create(sigma_g4,bop_types
,bop_types,bop_types,"BOP:sigma_g4");
memory->create(sigma_f,npairs,"BOP:sigma_f");
memory->create(sigma_k,npairs,"BOP:sigma_k");
memory->create(small3,npairs,"BOP:small3");
if (me == 0) {
words = new char*[bop_types];
for(i=0;i<bop_types;i++) words[i]=NULL;
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open BOP potential file %s",filename);
error->one(FLERR,str);
}
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%d %lf %s",&buf1,&buf2,buf);
n= strlen(buf)+1;
words[i] = new char[n];
strcpy(words[i],buf);
}
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf%lf%lf",&small1,&small2,&small3g,&small4
,&small5,&small6,&small7);
fgets(s,MAXLINE,fp);
sscanf(s,"%d%lf%lf",&ncutoff,&rbig,&rsmall);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%d",&which,&alpha,&nfunc);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&alpha1,&beta1,&gamma1);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf",&alpha2,&beta2);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf",&alpha3,&beta3);
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&pro[i],&pro_delta[i],&pi_p[i]);
}
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
cutmax=0;
for(i=0;i<bop_types;i++) {
ii=i+1;
for(j=i;j<bop_types;j++) {
jj=j+1;
if(ii==jj)
ij=ii-1;
else if(ii<jj)
ij=ii*bop_types-ii*(ii+1)/2+jj-1;
else
ij=jj*bop_types-jj*(jj+1)/2+ii-1;
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf",&sigma_r0[ij],&sigma_rc[ij],&r1[ij],&rcut[ij]);
if(rcut[ij]>cutmax)
cutmax=rcut[ij];
pi_r0[ij]=sigma_r0[ij];
phi_r0[ij]=sigma_r0[ij];
pi_rc[ij]=sigma_rc[ij];
phi_rc[ij]=sigma_rc[ij];
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&phi_m[ij],&sigma_n[ij],&sigma_nc[ij]);
pi_n[ij]=sigma_n[ij];
pi_nc[ij]=sigma_nc[ij];
phi_nc[ij]=sigma_nc[ij];
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&phi0[ij],&sigma_beta0[ij],&pi_beta0[ij]);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&sigma_a[ij],&sigma_c[ij],&sigma_delta[ij]);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&pi_a[ij],&pi_c[ij],&pi_delta[ij]);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&sigma_f[ij],&sigma_k[ij],&small3[ij]);
}
}
fgets(s,MAXLINE,fp);
fgets(s,MAXLINE,fp);
for(i=0;i<bop_types;i++) {
for(j=0;j<bop_types;j++) {
for(k=j;k<bop_types;k++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&sigma_g0[j][i][k],&sigma_g1[j][i][k]
,&sigma_g2[j][i][k]);
sigma_g0[k][i][j]=sigma_g0[j][i][k];
sigma_g1[k][i][j]=sigma_g1[j][i][k];
sigma_g2[k][i][j]=sigma_g2[j][i][k];
}
}
}
for(i=0;i<npairs;i++) {
dr[i]=rcut[i]/(nr-1.0);
rdr[i]=1.0/dr[i];
}
fclose(fp);
}
MPI_Bcast(&small1,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small2,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small3g,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small4,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small5,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small6,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small7,1,MPI_DOUBLE,0,world);
MPI_Bcast(&ncutoff,1,MPI_INT,0,world);
MPI_Bcast(&rbig,1,MPI_DOUBLE,0,world);
MPI_Bcast(&rsmall,1,MPI_DOUBLE,0,world);
MPI_Bcast(&which,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world);
MPI_Bcast(&nfunc,1,MPI_INT,0,world);
MPI_Bcast(&alpha1,1,MPI_DOUBLE,0,world);
MPI_Bcast(&beta1,1,MPI_DOUBLE,0,world);
MPI_Bcast(&gamma1,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha2,1,MPI_DOUBLE,0,world);
MPI_Bcast(&beta2,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha3,1,MPI_DOUBLE,0,world);
MPI_Bcast(&beta3,1,MPI_DOUBLE,0,world);
MPI_Bcast(&pro[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&pro_delta[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_p[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_r0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_rc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&r1[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&rcut[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&cutmax,1,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_r0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&phi_r0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_rc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&phi_rc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&phi_m[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_n[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_nc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_n[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_nc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&phi_nc[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&phi0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_beta0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_beta0[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_a[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_c[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_delta[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_a[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_c[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_delta[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_f[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_k[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&small3[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g0[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g1[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g2[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g3[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g4[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&dr[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&rdr[0],npairs,MPI_DOUBLE,0,world);
}
/* ---------------------------------------------------------------------- */
void PairBOP::read_table(char *filename)
{
int i,j,k,n;
int buf1;
double buf2;
char s[MAXLINE],buf[2];
MPI_Comm_rank(world,&me);
if (me == 0) {
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open BOP potential file %s",filename);
error->one(FLERR,str);
}
fgets(s,MAXLINE,fp);
sscanf(s,"%d",&bop_types);
words = new char*[bop_types];
for(i=0;i<bop_types;i++) words[i]=NULL;
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%d %lf %s",&buf1,&buf2,buf);
n= strlen(buf)+1;
words[i] = new char[n];
strcpy(words[i],buf);
}
fgets(s,MAXLINE,fp);
sscanf(s,"%d %d",&nr,&nBOt);
fclose(fp);
npairs=bop_types*(bop_types+1)/2;
}
MPI_Bcast(&nr,1,MPI_INT,0,world);
MPI_Bcast(&nBOt,1,MPI_INT,0,world);
MPI_Bcast(&bop_types,1,MPI_INT,0,world);
MPI_Bcast(&npairs,1,MPI_INT,0,world);
memory->create(pi_a,npairs,"BOP:pi_a");
memory->create(pro_delta,bop_types,"BOP:pro_delta");
memory->create(pi_delta,npairs,"BOP:pi_delta");
memory->create(pi_p,bop_types,"BOP:pi_p");
memory->create(pi_c,npairs,"BOP:pi_c");
memory->create(r1,npairs,"BOP:r1");
memory->create(pro,bop_types,"BOP:pro");
memory->create(sigma_delta,npairs,"BOP:sigma_delta");
memory->create(sigma_c,npairs,"BOP:sigma_c");
memory->create(sigma_a,npairs,"BOP:sigma_a");
memory->create(sigma_g0,bop_types
,bop_types,bop_types,"BOP:sigma_g0");
memory->create(sigma_g1,bop_types
,bop_types,bop_types,"BOP:sigma_g1");
memory->create(sigma_g2,bop_types
,bop_types,bop_types,"BOP:sigma_g2");
memory->create(sigma_f,npairs,"BOP:sigma_f");
memory->create(sigma_k,npairs,"BOP:sigma_k");
memory->create(small3,npairs,"BOP:small3");
allocate();
if (me == 0) {
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open BOP potential file %s",filename);
error->one(FLERR,str);
}
for(i=0;i<bop_types+2;i++) {
fgets(s,MAXLINE,fp);
}
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf%lf%lf",&small1,&small2,&small3g
,&small4,&small5,&small6,&small7);
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf",&pi_p[i]);
}
cutmax=0;
for(i=0;i<npairs;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf",&rcut[i]);
if(rcut[i]>cutmax)
cutmax=rcut[i];
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf",&sigma_c[i],&sigma_a[i],&pi_c[i],&pi_a[i]);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf",&sigma_delta[i],&pi_delta[i]);
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&sigma_f[i],&sigma_k[i],&small3[i]);
}
for(i=0;i<bop_types;i++)
for(j=0;j<bop_types;j++)
for(k=0;k<bop_types;k++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf",&sigma_g0[i][j][k],&sigma_g1[i][j][k],&sigma_g2[i][j][k]);
}
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf",&pRepul[i][j],&pRepul[i][j+1]
,&pRepul[i][j+2],&pRepul[i][j+3],&pRepul[i][j+4]);
j+=4;
}
}
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf",&pBetaS[i][j],&pBetaS[i][j+1]
,&pBetaS[i][j+2],&pBetaS[i][j+3],&pBetaS[i][j+4]);
j+=4;
}
}
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf",&pBetaP[i][j],&pBetaP[i][j+1]
,&pBetaP[i][j+2],&pBetaP[i][j+3],&pBetaP[i][j+4]);
j+=4;
}
}
for(i=0;i<npairs;i++) {
for(j=0;j<nBOt;j++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf%lf%lf%lf%lf",&FsigBO[i][j],&FsigBO[i][j+1]
,&FsigBO[i][j+2],&FsigBO[i][j+3],&FsigBO[i][j+4]);
j+=4;
}
}
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf",&pro_delta[i]);
}
for(i=0;i<bop_types;i++) {
fgets(s,MAXLINE,fp);
sscanf(s,"%lf",&pro[i]);
}
for(i=0;i<npairs;i++) {
dr[i]=rcut[i]/((double)nr-1.0);
rdr[i]=1.0/dr[i];
}
dBO=1.0/((double)nBOt-1.0);
rdBO=1.0/(double)dBO;
for(i=0;i<npairs;i++) {
pBetaS1[i][0]=pBetaS[i][1]-pBetaS[i][0];
pBetaS1[i][1]=0.5*(pBetaS[i][2]-pBetaS[i][0]);
pBetaS1[i][nr-2]=0.5*(pBetaS[i][nr-1]-pBetaS[i][nr-3]);
pBetaS1[i][nr-1]=pBetaS[i][nr-1]-pBetaS[i][nr-2];
pBetaP1[i][0]=pBetaP[i][1]-pBetaP[i][0];
pBetaP1[i][1]=0.5*(pBetaP[i][2]-pBetaP[i][0]);
pBetaP1[i][nr-2]=0.5*(pBetaP[i][nr-1]-pBetaP[i][nr-3]);
pBetaP1[i][nr-1]=pBetaP[i][nr-1]-pBetaP[i][nr-2];
pRepul1[i][0]=pRepul[i][1]-pRepul[i][0];
pRepul1[i][1]=0.5*(pRepul[i][2]-pRepul[i][0]);
pRepul1[i][nr-2]=0.5*(pRepul[i][nr-1]-pRepul[i][nr-3]);
pRepul1[i][nr-1]=pRepul[i][nr-1]-pRepul[i][nr-2];
FsigBO1[i][0]=FsigBO[i][1]-FsigBO[i][0];
FsigBO1[i][1]=0.5*(FsigBO[i][2]-FsigBO[i][0]);
FsigBO1[i][nBOt-2]=0.5*(FsigBO[i][nBOt-1]-FsigBO[i][nBOt-3]);
FsigBO1[i][nBOt-1]=FsigBO[i][nBOt-1]-FsigBO[i][nBOt-2];
for(k=2;k<nr-2;k++) {
pBetaS1[i][k]=((pBetaS[i][k-2]-pBetaS[i][k+2])
+8.0*(pBetaS[i][k+1]-pBetaS[i][k-1]))/12.0;
pBetaP1[i][k]=((pBetaP[i][k-2]-pBetaP[i][k+2])
+8.0*(pBetaP[i][k+1]-pBetaP[i][k-1]))/12.0;
pRepul1[i][k]=((pRepul[i][k-2]-pRepul[i][k+2])
+8.0*(pRepul[i][k+1]-pRepul[i][k-1]))/12.0;
}
for(k=2;k<nr-2;k++) {
FsigBO1[i][k]=((FsigBO[i][k-2]-FsigBO[i][k+2])
+8.0*(FsigBO[i][k+1]-FsigBO[i][k-1]))/12.0;
}
for(k=0;k<nr-1;k++) {
pBetaS2[i][k]=3.0*(pBetaS[i][k+1]-pBetaS[i][k])
-2.0*pBetaS1[i][k]-pBetaS1[i][k+1];
pBetaS3[i][k]=pBetaS1[i][k]+pBetaS1[i][k+1]
-2.0*(pBetaS[i][k+1]-pBetaS[i][k]);
pBetaP2[i][k]=3.0*(pBetaP[i][k+1]-pBetaP[i][k])
-2.0*pBetaP1[i][k]-pBetaP1[i][k+1];
pBetaP3[i][k]=pBetaP1[i][k]+pBetaP1[i][k+1]
-2.0*(pBetaP[i][k+1]-pBetaP[i][k]);
pRepul2[i][k]=3.0*(pRepul[i][k+1]-pRepul[i][k])
-2.0*pRepul1[i][k]-pRepul1[i][k+1];
pRepul3[i][k]=pRepul1[i][k]+pRepul1[i][k+1]
-2.0*(pRepul[i][k+1]-pRepul[i][k]);
}
for(k=0;k<nBOt-1;k++) {
FsigBO2[i][k]=3.0*(FsigBO[i][k+1]-FsigBO[i][k])
-2.0*FsigBO1[i][k]-FsigBO1[i][k+1];
FsigBO3[i][k]=FsigBO1[i][k]+FsigBO1[i][k+1]
-2.0*(FsigBO[i][k+1]-FsigBO[i][k]);
}
pBetaS2[i][nr-1]=0.0;
pBetaS3[i][nr-1]=0.0;
pBetaP2[i][nr-1]=0.0;
pBetaP3[i][nr-1]=0.0;
pRepul2[i][nr-1]=0.0;
pRepul3[i][nr-1]=0.0;
FsigBO2[i][nBOt-1]=0.0;
FsigBO3[i][nBOt-1]=0.0;
for(k=0;k<nr;k++) {
pBetaS4[i][k]=pBetaS1[i][k]/dr[i];
pBetaS5[i][k]=2.0*pBetaS2[i][k]/dr[i];
pBetaS6[i][k]=3.0*pBetaS3[i][k]/dr[i];
pBetaP4[i][k]=pBetaP1[i][k]/dr[i];
pBetaP5[i][k]=2.0*pBetaP2[i][k]/dr[i];
pBetaP6[i][k]=3.0*pBetaP3[i][k]/dr[i];
pRepul4[i][k]=pRepul1[i][k]/dr[i];
pRepul5[i][k]=2.0*pRepul2[i][k]/dr[i];
pRepul6[i][k]=3.0*pRepul3[i][k]/dr[i];
}
for(k=0;k<nBOt;k++) {
FsigBO4[i][k]=FsigBO1[i][k]/dBO;
FsigBO5[i][k]=2.0*FsigBO2[i][k]/dBO;
FsigBO6[i][k]=3.0*FsigBO3[i][k]/dBO;
}
}
fclose(fp);
}
MPI_Bcast(&rdBO,1,MPI_DOUBLE,0,world);
MPI_Bcast(&dBO,1,MPI_DOUBLE,0,world);
MPI_Bcast(&bop_types,1,MPI_INT,0,world);
MPI_Bcast(&small1,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small2,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small3g,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small4,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small5,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small6,1,MPI_DOUBLE,0,world);
MPI_Bcast(&small7,1,MPI_DOUBLE,0,world);
MPI_Bcast(&pro[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&pro_delta[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_p[0],bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&r1[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&rcut[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&cutmax,1,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_a[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_c[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_delta[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_a[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_c[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pi_delta[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_f[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_k[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&small3[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g0[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g1[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma_g2[0][0][0],bop_types*bop_types*bop_types,MPI_DOUBLE,0,world);
MPI_Bcast(&dr[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&rdr[0],npairs,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS1[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS2[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS3[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS4[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS5[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaS6[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP1[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP2[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP3[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP4[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP5[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pBetaP6[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul1[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul2[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul3[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul4[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul5[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&pRepul6[0][0],npairs*nr,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO1[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO2[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO3[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO4[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO5[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
MPI_Bcast(&FsigBO6[0][0],npairs*nBOt,MPI_DOUBLE,0,world);
}
/* ---------------------------------------------------------------------- */
void PairBOP::setPbetaS()
{
int i,j,k;
double r,value,dvalue;
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
r=(double)j*dr[i];
if(r<rcore)
r=rcore;
if(ncutoff==3) {
if(r>=rcut[i])
pBetaS[i][j]=0.0;
else if(r<=r1[i]) {
value=betaSfunc(i,r);
dvalue=dBetaSfunc(i,r,value,1.0);
pBetaS[i][j]=value;
}
else {
value=betaSfunc(i,r1[i]);
dvalue=dBetaSfunc(i,r1[i],value,1.0);
pBetaS[i][j]=-(r-rcut[i])*(r-rcut[i])*(value*(2.0*r-3.0*r1[i]+rcut[i])
-dvalue*(r-r1[i])*(r1[i]-rcut[i]))/((r1[i]-rcut[i])
*(r1[i]-rcut[i])*(r1[i]-rcut[i]));
}
}
else {
if(r>=rcut[i])
pBetaS[i][j]=0.0;
else {
value=betaSfunc(i,r);
dvalue=dBetaSfunc(i,r,value,0.0);
pBetaS[i][j]=value*cutoff(r1[i],rcut[i],ncutoff,r);
}
}
}
pBetaS[i][nr-1]=0.0;
pBetaS1[i][0]=pBetaS[i][1]-pBetaS[i][0];
pBetaS1[i][1]=0.5*(pBetaS[i][2]-pBetaS[i][0]);
pBetaS1[i][nr-2]=0.5*(pBetaS[i][nr-1]-pBetaS[i][nr-3]);
pBetaS1[i][nr-1]=pBetaS[i][nr-1]-pBetaS[i][nr-2];
for(k=2;k<nr-2;k++) {
pBetaS1[i][k]=((pBetaS[i][k-2]-pBetaS[i][k+2])+8.0*(pBetaS[i][k+1]
-pBetaS[i][k-1]))/12.0;
}
for(k=0;k<nr-1;k++) {
pBetaS2[i][k]=3.0*(pBetaS[i][k+1]-pBetaS[i][k])-2.0*pBetaS1[i][k]-pBetaS1[i][k+1];
pBetaS3[i][k]=pBetaS1[i][k]+pBetaS1[i][k+1]-2.0*(pBetaS[i][k+1]-pBetaS[i][k]);
}
pBetaS2[i][nr-1]=0.0;
pBetaS3[i][nr-1]=0.0;
for(k=0;k<nr;k++) {
pBetaS4[i][k]=pBetaS1[i][k]/dr[i];
pBetaS5[i][k]=2.0*pBetaS2[i][k]/dr[i];
pBetaS6[i][k]=3.0*pBetaS3[i][k]/dr[i];
}
}
}
/* ---------------------------------------------------------------------- */
void PairBOP::setPbetaP()
{
int i,j,k;
double r,value,dvalue;
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
r=(double)j*dr[i];
if(r<rcore)
r=rcore;
if(ncutoff==3) {
if(r>=rcut[i])
pBetaP[i][j]=0.0;
else if(r<=r1[i]) {
value=betaPfunc(i,r);
dvalue=dBetaPfunc(i,r,value,0.0);
pBetaP[i][j]=value;
}
else {
value=betaPfunc(i,r1[i]);
dvalue=dBetaPfunc(i,r1[i],value,1.0);
pBetaP[i][j]=-(r-rcut[i])*(r-rcut[i])*(value*(2.0*r-3.0*r1[i]
+rcut[i])-dvalue*(r-r1[1])*(r1[i]-rcut[i]))/((r1[i]-rcut[i])
*(r1[i]-rcut[i])*(r1[i]-rcut[i]));
}
}
else {
if(r>=rcut[i])
pBetaP[i][j]=0.0;
else {
value=betaPfunc(i,r);
dvalue=dBetaPfunc(i,r,value,0.0);
pBetaP[i][j]=value*cutoff(r1[i],rcut[i],ncutoff,r);
}
}
}
pBetaP[i][nr-1]=0.0;
pBetaP1[i][0]=pBetaP[i][1]-pBetaP[i][0];
pBetaP1[i][1]=0.5*(pBetaP[i][2]-pBetaP[i][0]);
pBetaP1[i][nr-2]=0.5*(pBetaP[i][nr-1]-pBetaP[i][nr-3]);
pBetaP1[i][nr-1]=pBetaP[i][nr-1]-pBetaP[i][nr-2];
for(k=2;k<nr-2;k++)
pBetaP1[i][k]=((pBetaP[i][k-2]-pBetaP[i][k+2])+8.0*(pBetaP[i][k+1]
-pBetaP[i][k-1]))/12.0;
for(k=0;k<nr-1;k++) {
pBetaP2[i][k]=3.0*(pBetaP[i][k+1]-pBetaP[i][k])-2.0*pBetaP1[i][k]-pBetaP1[i][k+1];
pBetaP3[i][k]=pBetaP1[i][k]+pBetaP1[i][k+1]-2.0*(pBetaP[i][k+1]-pBetaP[i][k]);
}
pBetaP2[i][nr-1]=0.0;
pBetaP3[i][nr-1]=0.0;
for(k=0;k<nr;k++) {
pBetaP4[i][k]=pBetaP1[i][k]/dr[i];
pBetaP5[i][k]=2.0*pBetaP2[i][k]/dr[i];
pBetaP6[i][k]=3.0*pBetaP3[i][k]/dr[i];
}
}
}
/* ---------------------------------------------------------------------- */
void PairBOP::setPrepul()
{
int i,j,k;
double r,value,dvalue;
for(i=0;i<npairs;i++) {
for(j=0;j<nr;j++) {
r=(double)j*dr[i];
if(r<rcore)
r=rcore;
if(ncutoff==3) {
if(r>=rcut[i])
pRepul[i][j]=0.0;
else if(r<=r1[i]) {
value=repulfunc(i,r);
dvalue=dRepulfunc(i,r,value,0.0);
pRepul[i][j]=value;
}
else {
value=repulfunc(i,r1[i]);
dvalue=dRepulfunc(i,r1[i],value,1.0);
pRepul[i][j]=-(r-rcut[i])*(r-rcut[i])*(value*(2.0*r-3.0*r1[i]+rcut[i])
-dvalue*(r-r1[i])*(r1[i]-rcut[i]))/((r1[i]-rcut[i])
*(r1[i]-rcut[i])*(r1[i]-rcut[i]));
}
}
else {
if(r>=rcut[i])
pRepul[i][j]=0.0;
else {
value=repulfunc(i,r);
dvalue=dRepulfunc(i,r,value,0.0);
pRepul[i][j]=value*cutoff(r1[i],rcut[i],ncutoff,r);
}
}
}
pRepul[i][nr-1]=0.0;
pRepul1[i][0]=pRepul[i][1]-pRepul[i][0];
pRepul1[i][1]=0.5*(pRepul[i][2]-pRepul[i][0]);
pRepul1[i][nr-2]=0.5*(pRepul[i][nr-1]-pRepul[i][nr-3]);
pRepul1[i][nr-1]=pRepul[i][nr-1]-pRepul[i][nr-2];
for(k=2;k<nr-2;k++)
pRepul1[i][k]=((pRepul[i][k-2]-pRepul[i][k+2])+8.0*(pRepul[i][k+1]
-pRepul[i][k-1]))/12.0;
for(k=0;k<nr-1;k++) {
pRepul2[i][k]=3.0*(pRepul[i][k+1]-pRepul[i][k])-2.0*pRepul1[i][k]-pRepul1[i][k+1];
pRepul3[i][k]=pRepul1[i][k]+pRepul1[i][k+1]-2.0*(pRepul[i][k+1]-pRepul[i][k]);
}
pRepul2[i][nr-1]=0.0;
pRepul3[i][nr-1]=0.0;
for(k=0;k<nr;k++) {
pRepul4[i][k]=pRepul1[i][k]/dr[i];
pRepul5[i][k]=2.0*pRepul2[i][k]/dr[i];
pRepul6[i][k]=3.0*pRepul3[i][k]/dr[i];
}
}
}
/* ---------------------------------------------------------------------- */
double PairBOP::betaSfunc(int i,double r)
{
double temp_value;
if(nfunc==1) {
temp_value=pow(sigma_r0[i]/r,sigma_n[i])*exp(sigma_n[i]*pow(sigma_r0[i]
/sigma_rc[i],sigma_nc[i])-sigma_n[i]*pow(r/sigma_rc[i],sigma_nc[i]));
temp_value=sigma_beta0[i]*temp_value;
}
if(nfunc==2)
temp_value=sigma_beta0[i]*exp(-sigma_n[i]*r);
if(nfunc==3)
temp_value=sigma_beta0[i]/pow(r,sigma_n[i]);
return(temp_value);
}
/* ---------------------------------------------------------------------- */
double PairBOP::dBetaSfunc(int i,double r,double value,double dmore)
{
double temp_dvalue;
if(nfunc==1)
if(dmore==1.0)
temp_dvalue=-sigma_n[i]*value/r*(1.0+sigma_nc[i]
*pow(r/sigma_rc[i],sigma_nc[i]));
if(nfunc==2)
if(dmore==1.0)
temp_dvalue=-sigma_n[i]*value;
if(nfunc==3)
if(dmore==1.0)
temp_dvalue=-sigma_n[i]*value/r;
return(temp_dvalue);
}
/* ---------------------------------------------------------------------- */
double PairBOP::betaPfunc(int i,double r)
{
double temp_value;
if(nfunc==1) {
temp_value=pow(pi_r0[i]/r,pi_n[i])*exp(pi_n[i]*pow(pi_r0[i]
/pi_rc[i],pi_nc[i])-pi_n[i]*pow(r/pi_rc[i],pi_nc[i]));
temp_value=pi_beta0[i]*temp_value;
}
if(nfunc==2)
temp_value=pi_beta0[i]*exp(-pi_n[i]*r);
if(nfunc==3)
temp_value=pi_beta0[i]/pow(r,pi_n[i]);
return(temp_value);
}
/* ---------------------------------------------------------------------- */
double PairBOP::dBetaPfunc(int i,double r,double value,double dmore)
{
double temp_dvalue;
if(nfunc==1)
if(dmore==1.0)
temp_dvalue=-pi_n[i]*value/r*(1.0+pi_nc[i]*pow(r/pi_rc[i],pi_nc[i]));
if(nfunc==2)
if(dmore==1.0)
temp_dvalue=-pi_n[i]*value;
if(nfunc==3)
if(dmore==1.0)
temp_dvalue=-pi_n[i]*value/r;
return(temp_dvalue);
}
/* ---------------------------------------------------------------------- */
double PairBOP::repulfunc(int i,double r)
{
double temp_value;
if(nfunc==1) {
temp_value=pow(phi_r0[i]/r,phi_m[i])*exp(phi_m[i]*pow(phi_r0[i]/phi_rc[i]
,phi_nc[i])-phi_m[i]*pow(r/phi_rc[i],phi_nc[i]));
temp_value=phi0[i]*temp_value;
}
if(nfunc==2)
temp_value=phi0[i]*exp(-phi_m[i]*r);
if(nfunc==3)
temp_value=phi0[i]/pow(r,phi_m[i]);
return(temp_value);
}
/* ---------------------------------------------------------------------- */
double PairBOP::dRepulfunc(int i,double r,double value,double dmore)
{
double temp_dvalue;
if(nfunc==1)
if(dmore==1.0)
temp_dvalue=-phi_m[i]*value/r*(1.0+phi_nc[i]*pow(r/phi_rc[i],phi_nc[i]));
if(nfunc==2)
if(dmore==1.0)
temp_dvalue=-phi_m[i]*value;
if(nfunc==3)
if(dmore==1.0)
temp_dvalue=-phi_m[i]*value/r;
return(temp_dvalue);
}
/* ---------------------------------------------------------------------- */
void PairBOP::setSign()
{
int i,j,k;
double y0,tmp,xBO,fth,cs,bigF;
double epsilon,fsigma1,slope,sat;
dBO=1.0/(nBOt-1.0);
rdBO=1.0/dBO;
for(i=0;i<npairs;i++) {
for(j=0;j<nBOt;j++) {
xBO=(double)j*dBO;
if(which==1.0) {
fth=0.0;
if(xBO>alpha)
fth=4.0/3.0*(xBO-alpha);
if(sigma_f[i]<=fth)
FsigBO[i][j]=2.0*sigma_f[i];
else if(sigma_f[i]>=1.0-fth)
FsigBO[i][j]=2.0*(1.0-sigma_f[i]);
else {
cs=0.0;
if(xBO<alpha)
cs=32.0*(alpha-xBO);
bigF=(sigma_f[i]*(1.0-sigma_f[i])-fth*(1.0-fth))/square(1.0-2.0*fth);
FsigBO[i][j]=2.0*fth+2.0*bigF*(1.0-2.0*fth)*(1.0+bigF*(1.0-cs*bigF));
}
}
else if(which==2.0) {
epsilon=0.0000000001;
fsigma1=sigma_f[i];
if(fsigma1>0.5)
fsigma1=1.0-fsigma1;
y0=alpha1*pow(fsigma1,beta1)*pow(0.5-fsigma1,gamma1);
slope=(1.0-exp(-alpha2*pow(fsigma1,beta2)))/(1.0-exp(-alpha2*pow(0.5,beta2)));
sat=alpha3*fsigma1+beta3;
tmp=y0+slope*xBO+sat;
FsigBO[i][j]=(tmp-sqrt(tmp*tmp-4.0*(-epsilon*sqrt(1.0+slope*slope)
+y0*sat+slope*sat*xBO)))/2.0;
}
}
FsigBO1[i][0]=FsigBO[i][1]-FsigBO[i][0];
FsigBO1[i][1]=0.5*(FsigBO[i][2]-FsigBO[i][0]);
FsigBO1[i][nBOt-2]=0.5*(FsigBO[i][nBOt-1]-FsigBO[i][nBOt-3]);
FsigBO1[i][nBOt-1]=FsigBO[i][nBOt-1]-FsigBO[i][nBOt-2];
for(k=2;k<nBOt-2;k++)
FsigBO1[i][k]=((FsigBO[i][k-2]-FsigBO[i][k+2])+8.0*(FsigBO[i][k+1]
-FsigBO[i][k-1]))/12.0;
for(k=0;k<nBOt-1;k++) {
FsigBO2[i][k]=3.0*(FsigBO[i][k+1]-FsigBO[i][k])-2.0*FsigBO1[i][k]-FsigBO1[i][k+1];
FsigBO3[i][k]=FsigBO1[i][k]+FsigBO1[i][k+1]-2.0*(FsigBO[i][k+1]-FsigBO[i][k]);
}
FsigBO2[i][nBOt-1]=0.0;
FsigBO3[i][nBOt-1]=0.0;
for(k=0;k<nBOt;k++) {
FsigBO4[i][k]=FsigBO1[i][k]/dBO;
FsigBO5[i][k]=2.0*FsigBO2[i][k]/dBO;
FsigBO6[i][k]=3.0*FsigBO3[i][k]/dBO;
}
}
}
/* ---------------------------------------------------------------------- */
double PairBOP::cutoff(double rp,double vrcut,int mode,double r)
{
double tmp,tmp_beta,tmp_alpha,cut_store;
if(mode==1) {
tmp=(rsmall-rbig)*(r-rp)/(vrcut-rp)+rbig;
cut_store=(erfc(tmp)-erfc(rsmall))/(erfc(rbig)-erfc(rsmall));
}
else {
tmp_beta=log(log(rbig)/log(rsmall))/log(rp/vrcut);
tmp_alpha=-log(rbig)/pow(rp,tmp_beta);
cut_store=(exp(-tmp_alpha*pow(r,tmp_beta))-exp(-tmp_alpha*pow(vrcut
,tmp_beta)))/(exp(-tmp_alpha*pow(rp,tmp_beta))-exp(-tmp_alpha
*pow(vrcut,tmp_beta)));
}
return(cut_store);
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairBOP::memory_usage()
{
int nlocal,nghost,nall;
int n = atom->ntypes;
nlocal = atom->nlocal;
nghost = atom->nghost;
nall = nlocal + nghost;
double bytes = 0.0;
// rcut
bytes += npairs * sizeof (double);
// dr
bytes += npairs * sizeof (double);
// rdr
bytes += npairs * sizeof (double);
// setflag
bytes += (n+1) * (n+1) * sizeof (int);
// cutsq
bytes += (n+1) * (n+1) * sizeof (double);
// cutghost
bytes += (n+1) * (n+1) * sizeof (double);
// cutghost
bytes += (n+1) * (n+1) * sizeof (double);
// pBetaS
bytes += npairs * nr * sizeof (double);
// pBetaS1
bytes += npairs * nr * sizeof (double);
// pBetaS2
bytes += npairs * nr * sizeof (double);
// pBetaS3
bytes += npairs * nr * sizeof (double);
// pBetaS4
bytes += npairs * nr * sizeof (double);
// pBetaS5
bytes += npairs * nr * sizeof (double);
// pBetaS6
bytes += npairs * nr * sizeof (double);
// pBetaP
bytes += npairs * nr * sizeof (double);
// pBetaP1
bytes += npairs * nr * sizeof (double);
// pBetaP2
bytes += npairs * nr * sizeof (double);
// pBetaP3
bytes += npairs * nr * sizeof (double);
// pBetaP4
bytes += npairs * nr * sizeof (double);
// pBetaP5
bytes += npairs * nr * sizeof (double);
// pBetaP6
bytes += npairs * nr * sizeof (double);
// pRepul
bytes += npairs * nr * sizeof (double);
// pRepul1
bytes += npairs * nr * sizeof (double);
// pRepul2
bytes += npairs * nr * sizeof (double);
// pRepul3
bytes += npairs * nr * sizeof (double);
// pRepul4
bytes += npairs * nr * sizeof (double);
// pRepul5
bytes += npairs * nr * sizeof (double);
// pRepul6
bytes += npairs * nr * sizeof (double);
// FsigBO
bytes += npairs * nr * sizeof (double);
// FsigBO1
bytes += npairs * nr * sizeof (double);
// FsigBO2
bytes += npairs * nr * sizeof (double);
// FsigBO3
bytes += npairs * nr * sizeof (double);
// FsigBO4
bytes += npairs * nr * sizeof (double);
// FsigBO5
bytes += npairs * nr * sizeof (double);
// FsigBO6
bytes += npairs * nr * sizeof (double);
// itypeSigBk
bytes += neigh_total *neigh_ct* sizeof(int);
// nSigBk
bytes += neigh_total * sizeof(int);
// sigB
bytes += neigh_total * sizeof(int);
// sigB1
bytes += neigh_total * sizeof(int);
// nPiBk
bytes += neigh_total * sizeof(int);
// piB
bytes += neigh_total * sizeof(int);
// itypePiBk
bytes += neigh_total *neigh_ct* sizeof(int);
// BOP_index
bytes += nall * sizeof(double);
if(otfly==0) {
// cosAng
bytes += cos_total* sizeof(double);
// dcAng
bytes += cos_total * 3 * 2 * sizeof(double);
// disij
bytes += neigh_total * 3 * sizeof(double);
// rij
bytes += neigh_total * sizeof(double);
// betaS
bytes += neigh_total * sizeof(double);
// dBetaS
bytes += neigh_total * sizeof(double);
// betaP
bytes += neigh_total * sizeof(double);
// dBetaP
bytes += neigh_total * sizeof(double);
// repul
bytes += neigh_total * sizeof(double);
// dRepul
bytes += neigh_total * sizeof(double);
// cos_index
bytes += nall * sizeof(double);
}
// pi_a
bytes += npairs * sizeof(double);
// pro_delta
bytes += npairs * sizeof(double);
// pi_delta
bytes += npairs * sizeof(double);
// pi_p
bytes += npairs * sizeof(double);
// pi_c
bytes += npairs * sizeof(double);
// sigma_r0
bytes += npairs * sizeof(double);
// pi_r0
bytes += npairs * sizeof(double);
// phi_r0
bytes += npairs * sizeof(double);
// sigma_rc
bytes += npairs * sizeof(double);
// pi_rc
bytes += npairs * sizeof(double);
// pi_a
bytes += npairs * sizeof(double);
// pro_delta
bytes += npairs * sizeof(double);
// pi_delta
bytes += npairs * sizeof(double);
// pi_p
bytes += npairs * sizeof(double);
// pi_c
bytes += npairs * sizeof(double);
// sigma_r0
bytes += npairs * sizeof(double);
// pi_r0
bytes += npairs * sizeof(double);
// phi_r0
bytes += npairs * sizeof(double);
// sigma_rc
bytes += npairs * sizeof(double);
// pi_rc
bytes += npairs * sizeof(double);
// phi_rc
bytes += npairs * sizeof(double);
// r1
bytes += npairs * sizeof(double);
// sigma_beta0
bytes += npairs * sizeof(double);
// pi_beta0
bytes += npairs * sizeof(double);
// phi0
bytes += npairs * sizeof(double);
// sigma_n
bytes += npairs * sizeof(double);
// pi_n
bytes += npairs * sizeof(double);
// phi_m
bytes += npairs * sizeof(double);
// sigma_nc
bytes += npairs * sizeof(double);
// pi_nc
bytes += npairs * sizeof(double);
// phi_nc
bytes += npairs * sizeof(double);
// pro
bytes += npairs * sizeof(double);
// sigma_delta
bytes += npairs * sizeof(double);
// sigma_c
bytes += npairs * sizeof(double);
// sigma_a
bytes += npairs * sizeof(double);
// sigma_g0
bytes += bop_types * bop_types *bop_types * sizeof(double);
// sigma_g1
bytes += bop_types * bop_types *bop_types * sizeof(double);
// sigma_g2
bytes += bop_types * bop_types *bop_types * sizeof(double);
// sigma_g3
bytes += bop_types * bop_types *bop_types * sizeof(double);
// sigma_g4
bytes += bop_types * bop_types *bop_types * sizeof(double);
// sigma_f
bytes += npairs * sizeof(double);
// sigma_k
bytes += npairs * sizeof(double);
// small3
bytes += npairs * sizeof(double);
// bt_pi
bytes += maxneigh*(maxneigh/2) *sizeof(B_PI);
// bt_sigma
bytes += maxneigh*(maxneigh/2) *sizeof(B_SG);
return bytes;
}
/* ---------------------------------------------------------------------- */
void PairBOP::memory_theta_create()
{
int nlocal,nghost,nall;
nlocal = atom->nlocal;
nghost = atom->nghost;
nall = nlocal + nghost;
if(maxneigh<8)
neigh_ct=(maxneigh-1)*(maxneigh-1)*(maxneigh-1);
else
neigh_ct=(maxneigh-1)*(maxneigh-1);
memory->create(itypeSigBk,neigh_total
,neigh_ct,"itypeSigBk");
memory->create(nSigBk,neigh_total,"nSigBk");
memory->create(sigB,neigh_total,"sigB");
memory->create(sigB1,neigh_total,"sigB1");
memory->create(itypePiBk,neigh_total
,neigh_ct,"itypePiBk");
memory->create(nPiBk,neigh_total,"nPiBk");
memory->create(piB,neigh_total,"piB");
memory->create(neigh_flag,neigh_total,"neigh_flag");
if(otfly==0) {
memory->create(cosAng,cos_total,"BOP:cosAng");
memory->create(dcAng,cos_total*2,3,2,"BOP:dcAng");
memory->create(disij,3,neigh_total,"disij");
memory->create(rij,neigh_total,"rij");
memory->create(betaS,neigh_total,"betaS");
memory->create(dBetaS,neigh_total,"dBetaS");
memory->create(betaP,neigh_total,"betaP");
memory->create(dBetaP,neigh_total,"dBetaP");
memory->create(repul,neigh_total,"repul");
memory->create(dRepul,neigh_total,"dRepul");
}
update_list=1;
}
/* ---------------------------------------------------------------------- */
void PairBOP::memory_theta_grow()
{
int nlocal,nghost,nall;
nlocal = atom->nlocal;
nghost = atom->nghost;
nall = nlocal + nghost;
if(maxneigh<8)
neigh_ct=(maxneigh-1)*(maxneigh-1)*(maxneigh-1);
else
neigh_ct=(maxneigh-1)*(maxneigh-1);
memory->grow(itypeSigBk,neigh_total
,neigh_ct,"itypeSigBk");
memory->grow(nSigBk,neigh_total,"nSigBk");
memory->grow(sigB,neigh_total,"sigB");
memory->grow(sigB1,neigh_total,"sigB1");
memory->grow(itypePiBk,neigh_total
,neigh_ct,"itypePiBk");
memory->grow(nPiBk,neigh_total,"nPiBk");
memory->grow(piB,neigh_total,"piB");
memory->grow(neigh_flag,neigh_total,"neigh_flag");
if(otfly==0) {
memory->grow(cosAng,cos_total,"BOP:cosAng");
memory->grow(dcAng,cos_total*2,3,2,"BOP:dcAng");
memory->grow(disij,3,neigh_total,"disij");
memory->grow(rij,neigh_total,"rij");
memory->grow(betaS,neigh_total,"betaS");
memory->grow(dBetaS,neigh_total,"dBetaS");
memory->grow(betaP,neigh_total,"betaP");
memory->grow(dBetaP,neigh_total,"dBetaP");
memory->grow(repul,neigh_total,"repul");
memory->grow(dRepul,neigh_total,"dRepul");
}
update_list=1;
}
/* ---------------------------------------------------------------------- */
void PairBOP::memory_theta_destroy()
{
memory->destroy(itypeSigBk);
memory->destroy(nSigBk);
memory->destroy(sigB);
memory->destroy(sigB1);
memory->destroy(itypePiBk);
memory->destroy(nPiBk);
memory->destroy(piB);
memory->destroy(neigh_flag);
if(otfly==0) {
memory->destroy(cosAng);
memory->destroy(dcAng);
memory->destroy(disij);
memory->destroy(rij);
memory->destroy(betaS);
memory->destroy(dBetaS);
memory->destroy(betaP);
memory->destroy(dBetaP);
memory->destroy(repul);
memory->destroy(dRepul);
}
update_list=0;
}
/* ---------------------------------------------------------------------- */
void PairBOP::create_pi(int n_tot)
{
bt_pi = (B_PI *) memory->smalloc(n_tot*sizeof(B_PI),"BOP:bt_pi");
allocate_pi=1;
}
void PairBOP::create_sigma(int n_tot)
{
bt_sg = (B_SG *) memory->smalloc(n_tot*sizeof(B_SG),"BOP:bt_sg");
allocate_sigma=1;
}
void PairBOP::destroy_pi()
{
memory->destroy(bt_pi);
allocate_pi=0;
}
void PairBOP::destroy_sigma()
{
memory->destroy(bt_sg);
allocate_sigma=0;
}
/* ---------------------------------------------------------------------- */
void PairBOP::grow_pi(int n1, int n2)
{
int i,j;
B_PI *bt_temp;
bt_temp = (B_PI *) memory->smalloc(n1*sizeof(B_PI),"BOP:b_temp");
for(i=0;i<n1;i++) {
bt_temp[i].temp = bt_pi[i].temp;
bt_temp[i].i = bt_pi[i].i;
bt_temp[i].j = bt_pi[i].j;
for(j=0;j<3;j++) {
bt_temp[i].dAA[j] = bt_pi[i].dAA[j];
bt_temp[i].dBB[j] = bt_pi[i].dBB[j];
bt_temp[i].dPiB[j] = bt_pi[i].dPiB[j];
}
}
memory->destroy(bt_pi);
bt_pi=NULL;
bt_pi = (B_PI *) memory->smalloc(n2*sizeof(B_PI),"BOP:bt_pi");
for(i=0;i<n1;i++) {
bt_pi[i].temp = bt_temp[i].temp;
bt_pi[i].i = bt_temp[i].i;
bt_pi[i].j = bt_temp[i].j;
for(j=0;j<3;j++) {
bt_pi[i].dAA[j] = bt_temp[i].dAA[j];
bt_pi[i].dBB[j] = bt_temp[i].dBB[j];
bt_pi[i].dPiB[j] = bt_temp[i].dPiB[j];
}
}
for(i=n1;i<n2;i++) {
bt_pi[i].i = -1;
bt_pi[i].j = -1;
for(j=0;j<3;j++) {
bt_pi[i].dAA[j] = 0.0;
bt_pi[i].dBB[j] = 0.0;
bt_pi[i].dPiB[j] = 0.0;
}
}
memory->destroy(bt_temp);
}
/* ---------------------------------------------------------------------- */
void PairBOP::grow_sigma(int n1,int n2)
{
int i,j;
B_SG *bt_temp;
bt_temp = (B_SG *) memory->smalloc(n1*sizeof(B_SG),"BOP:bt_temp");
for(i=0;i<n1;i++) {
bt_temp[i].temp = bt_sg[i].temp;
bt_temp[i].i = bt_sg[i].i;
bt_temp[i].j = bt_sg[i].j;
for(j=0;j<3;j++) {
bt_temp[i].dAA[j] = bt_sg[i].dAA[j];
bt_temp[i].dBB[j] = bt_sg[i].dBB[j];
bt_temp[i].dCC[j] = bt_sg[i].dCC[j];
bt_temp[i].dDD[j] = bt_sg[i].dDD[j];
bt_temp[i].dEE[j] = bt_sg[i].dEE[j];
bt_temp[i].dEE1[j] = bt_sg[i].dEE1[j];
bt_temp[i].dFF[j] = bt_sg[i].dFF[j];
bt_temp[i].dAAC[j] = bt_sg[i].dAAC[j];
bt_temp[i].dBBC[j] = bt_sg[i].dBBC[j];
bt_temp[i].dCCC[j] = bt_sg[i].dCCC[j];
bt_temp[i].dDDC[j] = bt_sg[i].dDDC[j];
bt_temp[i].dEEC[j] = bt_sg[i].dEEC[j];
bt_temp[i].dFFC[j] = bt_sg[i].dFFC[j];
bt_temp[i].dGGC[j] = bt_sg[i].dGGC[j];
bt_temp[i].dUT[j] = bt_sg[i].dUT[j];
bt_temp[i].dSigB1[j] = bt_sg[i].dSigB1[j];
bt_temp[i].dSigB[j] = bt_sg[i].dSigB[j];
}
}
memory->destroy(bt_sg);
bt_sg=NULL;
bt_sg = (B_SG *) memory->smalloc(n2*sizeof(B_SG),"BOP:bt_sg");
for(i=0;i<n1;i++) {
bt_sg[i].temp = bt_temp[i].temp;
bt_sg[i].i = bt_temp[i].i;
bt_sg[i].j = bt_temp[i].j;
for(j=0;j<3;j++) {
bt_sg[i].dAA[j] = bt_temp[i].dAA[j];
bt_sg[i].dBB[j] = bt_temp[i].dBB[j];
bt_sg[i].dCC[j] = bt_temp[i].dCC[j];
bt_sg[i].dDD[j] = bt_temp[i].dDD[j];
bt_sg[i].dEE[j] = bt_temp[i].dEE[j];
bt_sg[i].dEE1[j] = bt_temp[i].dEE1[j];
bt_sg[i].dFF[j] = bt_temp[i].dFF[j];
bt_sg[i].dAAC[j] = bt_temp[i].dAAC[j];
bt_sg[i].dBBC[j] = bt_temp[i].dBBC[j];
bt_sg[i].dCCC[j] = bt_temp[i].dCCC[j];
bt_sg[i].dDDC[j] = bt_temp[i].dDDC[j];
bt_sg[i].dEEC[j] = bt_temp[i].dEEC[j];
bt_sg[i].dFFC[j] = bt_temp[i].dFFC[j];
bt_sg[i].dGGC[j] = bt_temp[i].dGGC[j];
bt_sg[i].dUT[j] = bt_temp[i].dUT[j];
bt_sg[i].dSigB1[j] = bt_temp[i].dSigB1[j];
bt_sg[i].dSigB[j] = bt_temp[i].dSigB[j];
}
}
for(i=n1;i<n2;i++) {
bt_sg[i].i = -1;
bt_sg[i].j = -1;
for(j=0;j<3;j++) {
bt_sg[i].dAA[j] = 0.0;
bt_sg[i].dBB[j] = 0.0;
bt_sg[i].dCC[j] = 0.0;
bt_sg[i].dDD[j] = 0.0;
bt_sg[i].dEE[j] = 0.0;
bt_sg[i].dEE1[j] = 0.0;
bt_sg[i].dFF[j] = 0.0;
bt_sg[i].dAAC[j] = 0.0;
bt_sg[i].dBBC[j] = 0.0;
bt_sg[i].dCCC[j] = 0.0;
bt_sg[i].dDDC[j] = 0.0;
bt_sg[i].dEEC[j] = 0.0;
bt_sg[i].dFFC[j] = 0.0;
bt_sg[i].dGGC[j] = 0.0;
bt_sg[i].dUT[j] = 0.0;
bt_sg[i].dSigB1[j] = 0.0;
bt_sg[i].dSigB[j] = 0.0;
}
}
memory->destroy(bt_temp);
}
diff --git a/src/MANYBODY/pair_comb.cpp b/src/MANYBODY/pair_comb.cpp
index 02096c000..7c18ccd3f 100644
--- a/src/MANYBODY/pair_comb.cpp
+++ b/src/MANYBODY/pair_comb.cpp
@@ -1,2131 +1,2133 @@
/* ----------------------------------------------------------------------
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: Tzu-Ray Shan (U Florida, present: tnshan@sandia.gov)
LAMMPS implementation of the Charge-optimized many-body (COMB) potential
based on the HELL MD program (Prof Simon Phillpot, UF, sphil@mse.ufl.edu)
and Aidan Thompson's Tersoff code in LAMMPS
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_comb.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "group.h"
#include "update.h"
#include "my_page.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define MAXLINE 1024
#define DELTA 4
#define PGDELTA 1
#define MAXNEIGH 24
/* ---------------------------------------------------------------------- */
PairComb::PairComb(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
nmax = 0;
NCo = NULL;
bbij = NULL;
nelements = 0;
elements = NULL;
nparams = 0;
maxparam = 0;
params = NULL;
elem2param = NULL;
intype = NULL;
fafb = NULL;
dfafb = NULL;
ddfafb = NULL;
phin = NULL;
dphin = NULL;
erpaw = NULL;
sht_num = NULL;
sht_first = NULL;
ipage = NULL;
pgsize = oneatom = 0;
// set comm size needed by this Pair
comm_forward = 1;
comm_reverse = 1;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairComb::~PairComb()
{
memory->destroy(NCo);
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->sfree(params);
memory->destroy(elem2param);
memory->destroy(intype);
memory->destroy(fafb);
memory->destroy(dfafb);
memory->destroy(ddfafb);
memory->destroy(phin);
memory->destroy(dphin);
memory->destroy(erpaw);
memory->destroy(bbij);
memory->destroy(sht_num);
memory->sfree(sht_first);
delete [] ipage;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
delete [] esm;
}
}
/* ---------------------------------------------------------------------- */
void PairComb::compute(int eflag, int vflag)
{
int i,j,k,ii,jj,kk,inum,jnum,iparam_i;
- int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk;
+ int itype,jtype,ktype,iparam_ij,iparam_ijk;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rsq,rsq1,rsq2;
double delr1[3],delr2[3],fi[3],fj[3],fk[3];
double zeta_ij,prefactor;
int *ilist,*jlist,*numneigh,**firstneigh;
int mr1,mr2,mr3;
int rsc,inty;
double elp_ij,filp[3],fjlp[3],fklp[3];
double iq,jq;
double yaself;
double potal,fac11,fac11e;
double vionij,fvionij,sr1,sr2,sr3,Eov,Fov;
int sht_jnum, *sht_jlist, nj;
evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = vflag_atom = 0;
// Build short range neighbor list
Short_neigh();
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
- int *tag = atom->tag;
+ 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;
yaself = vionij = fvionij = Eov = Fov = 0.0;
// self energy correction term: potal
potal_calc(potal,fac11,fac11e);
// loop over full neighbor list of my atoms
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];
iq = q[i];
NCo[i] = 0;
nj = 0;
iparam_i = elem2param[itype][itype][itype];
// self energy, only on i atom
yaself = self(&params[iparam_i],iq,potal);
if (evflag) ev_tally(i,i,nlocal,0,yaself,0.0,0.0,0.0,0.0,0.0);
// two-body interactions (long and short repulsive)
jlist = firstneigh[i];
jnum = numneigh[i];
sht_jlist = sht_first[i];
sht_jnum = sht_num[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] < x[i][2]) 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;
}
// Qj calculates 2-body Coulombic
jtype = map[type[j]];
jq = q[j];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
iparam_ij = elem2param[itype][jtype][jtype];
// long range q-dependent
if (rsq > params[iparam_ij].lcutsq) continue;
inty = intype[itype][jtype];
// polynomial three-point interpolation
tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3, itype);
// 1/r energy and forces
direct(inty,mr1,mr2,mr3,rsq,sr1,sr2,sr3,iq,jq,
potal,fac11,fac11e,vionij,fvionij);
// field correction to self energy
field(&params[iparam_ij],rsq,iq,jq,vionij,fvionij);
// polarization field
// sums up long range forces
f[i][0] += delx*fvionij;
f[i][1] += dely*fvionij;
f[i][2] += delz*fvionij;
f[j][0] -= delx*fvionij;
f[j][1] -= dely*fvionij;
f[j][2] -= delz*fvionij;
if (evflag)
ev_tally(i,j,nlocal,newton_pair,0.0,vionij,fvionij,delx,dely,delz);
// short range q-independent
if (rsq > params[iparam_ij].cutsq) continue;
repulsive(&params[iparam_ij],rsq,fpair,eflag,evdwl,iq,jq);
// repulsion is pure two-body, sums up pair repulsive forces
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 (evflag)
ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz);
}
// accumulate coordination number information
if (cor_flag) {
for (jj = 0; jj < sht_jnum; jj++) {
j = sht_jlist[jj];
jtype = map[type[j]];
iparam_ij = elem2param[itype][jtype][jtype];
if(params[iparam_ij].hfocor > 0.0 ) {
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = vec3_dot(delr1,delr1);
if (rsq1 > params[iparam_ij].cutsq) continue;
NCo[i] += 1;
}
}
}
// three-body interactions
// half i-j loop
for (jj = 0; jj < sht_jnum; jj++) {
j = sht_jlist[jj];
jtype = map[type[j]];
iparam_ij = elem2param[itype][jtype][jtype];
// this Qj for q-dependent BSi
jq = q[j];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = vec3_dot(delr1,delr1);
if (rsq1 > params[iparam_ij].cutsq) continue;
nj ++;
// accumulate bondorder zeta for each i-j interaction via loop over k
zeta_ij = 0.0;
cuo_flag1 = 0; cuo_flag2 = 0;
for (kk = 0; kk < sht_jnum; kk++) {
k = sht_jlist[kk];
if (j == k) continue;
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = vec3_dot(delr2,delr2);
if (rsq2 > params[iparam_ijk].cutsq) continue;
zeta_ij += zeta(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
if (params[iparam_ijk].hfocor == -2.0) cuo_flag1 = 1;
if (params[iparam_ijk].hfocor == -1.0) cuo_flag2 = 1;
}
if (cuo_flag1 && cuo_flag2) cuo_flag = 1;
else cuo_flag = 0;
force_zeta(&params[iparam_ij],eflag,i,nj,rsq1,zeta_ij,
iq,jq,fpair,prefactor,evdwl);
// over-coordination correction for HfO2
if (cor_flag && NCo[i] != 0)
Over_cor(&params[iparam_ij],rsq1,NCo[i],Eov, Fov);
evdwl += Eov;
fpair += Fov;
f[i][0] += delr1[0]*fpair;
f[i][1] += delr1[1]*fpair;
f[i][2] += delr1[2]*fpair;
f[j][0] -= delr1[0]*fpair;
f[j][1] -= delr1[1]*fpair;
f[j][2] -= delr1[2]*fpair;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,-fpair,-delr1[0],-delr1[1],-delr1[2]);
// attractive term via loop over k (3-body forces)
for (kk = 0; kk < sht_jnum; kk++) {
k = sht_jlist[kk];
if (j == k) continue;
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = vec3_dot(delr2,delr2);
if (rsq2 > params[iparam_ijk].cutsq) continue;
for (rsc = 0; rsc < 3; rsc++)
fi[rsc] = fj[rsc] = fk[rsc] = 0.0;
attractive(&params[iparam_ijk],prefactor,
rsq1,rsq2,delr1,delr2,fi,fj,fk);
// 3-body LP and BB correction and forces
elp_ij = elp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
flp(&params[iparam_ijk],rsq1,rsq2,delr1,delr2,filp,fjlp,fklp);
for (rsc = 0; rsc < 3; rsc++) {
fi[rsc] += filp[rsc];
fj[rsc] += fjlp[rsc];
fk[rsc] += fklp[rsc];
}
for (rsc = 0; rsc < 3; rsc++) {
f[i][rsc] += fi[rsc];
f[j][rsc] += fj[rsc];
f[k][rsc] += fk[rsc];
}
if (evflag)
ev_tally(i,j,nlocal,newton_pair,elp_ij,0.0,0.0,0.0,0.0,0.0);
if (vflag_atom) v_tally3(i,j,k,fj,fk,delr1,delr2);
}
}
if (cuo_flag) params[iparam_i].cutsq *= 0.65;
}
cuo_flag = 0;
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairComb::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");
map = new int[n+1];
esm = new double[n];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairComb::settings(int narg, char **arg)
{
if (narg > 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairComb::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
n = atom->ntypes;
// generate streitz-mintmire direct 1/r energy look-up table
if (comm->me == 0 && screen) fprintf(screen,"Pair COMB:\n");
if (comm->me == 0 && screen)
fprintf(screen," generating Coulomb integral lookup table ...\n");
sm_table();
if (cor_flag && comm->me == 0 && screen)
fprintf(screen," will apply over-coordination correction ...\n");
if (!cor_flag&& comm->me == 0 && screen)
fprintf(screen," will not apply over-coordination correction ...\n");
// clear setflag since coeff() called once with I,J = * *
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 PairComb::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style COMB requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style COMB requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,"Pair style COMB requires atom attribute q");
// ptr to QEQ fix
//for (i = 0; i < modify->nfix; i++)
// if (strcmp(modify->fix[i]->style,"qeq") == 0) break;
//if (i < modify->nfix) fixqeq = (FixQEQ *) modify->fix[i];
//else fixqeq = NULL;
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
// local Comb 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);
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairComb::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairComb::read_file(char *file)
{
int params_per_line = 49;
char **words = new char*[params_per_line+1];
memory->sfree(params);
params = NULL;
nparams = 0;
maxparam = 0;
// open file on proc 0
FILE *fp;
if (comm->me == 0) {
fp = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open COMB potential file %s",file);
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 n,nwords,ielement,jelement,kelement;
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,"Incorrect format in COMB 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next line
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].powerm = atof(words[3]);
params[nparams].c = atof(words[4]);
params[nparams].d = atof(words[5]);
params[nparams].h = atof(words[6]);
params[nparams].powern = atof(words[7]);
params[nparams].beta = atof(words[8]);
params[nparams].lam21 = atof(words[9]);
params[nparams].lam22 = atof(words[10]);
params[nparams].bigb1 = atof(words[11]);
params[nparams].bigb2 = atof(words[12]);
params[nparams].bigr = atof(words[13]);
params[nparams].bigd = atof(words[14]);
params[nparams].lam11 = atof(words[15]);
params[nparams].lam12 = atof(words[16]);
params[nparams].biga1 = atof(words[17]);
params[nparams].biga2 = atof(words[18]);
params[nparams].plp1 = atof(words[19]);
params[nparams].plp3 = atof(words[20]);
params[nparams].plp6 = atof(words[21]);
params[nparams].a123 = atof(words[22]);
params[nparams].aconf= atof(words[23]);
params[nparams].addrep = atof(words[24]);
params[nparams].romigb = atof(words[25]);
params[nparams].romigc = atof(words[26]);
params[nparams].romigd = atof(words[27]);
params[nparams].romiga = atof(words[28]);
params[nparams].QL1 = atof(words[29]);
params[nparams].QU1 = atof(words[30]);
params[nparams].DL1 = atof(words[31]);
params[nparams].DU1 = atof(words[32]);
params[nparams].QL2 = atof(words[33]);
params[nparams].QU2 = atof(words[34]);
params[nparams].DL2 = atof(words[35]);
params[nparams].DU2 = atof(words[36]);
params[nparams].chi = atof(words[37]);
params[nparams].dj = atof(words[38]);
params[nparams].dk = atof(words[39]);
params[nparams].dl = atof(words[40]);
params[nparams].dm = atof(words[41]);
params[nparams].esm1 = atof(words[42]);
params[nparams].cmn1 = atof(words[43]);
params[nparams].cml1 = atof(words[44]);
params[nparams].cmn2 = atof(words[45]);
params[nparams].cml2 = atof(words[46]);
params[nparams].coulcut = atof(words[47]);
params[nparams].hfocor = atof(words[48]);
params[nparams].powermint = int(params[nparams].powerm);
// parameter sanity checks
if (params[nparams].lam11 < 0.0 || params[nparams].lam12 < 0.0 ||
params[nparams].c < 0.0 || params[nparams].d < 0.0 ||
params[nparams].powern < 0.0 || params[nparams].beta < 0.0 ||
params[nparams].lam21 < 0.0 || params[nparams].lam22 < 0.0 ||
params[nparams].bigb1< 0.0 || params[nparams].bigb2< 0.0 ||
params[nparams].biga1< 0.0 || params[nparams].biga2< 0.0 ||
params[nparams].bigr < 0.0 || params[nparams].bigd < 0.0 ||
params[nparams].bigd > params[nparams].bigr ||
params[nparams].powerm - params[nparams].powermint != 0.0 ||
(params[nparams].powermint != 3 && params[nparams].powermint != 1) ||
params[nparams].plp1 < 0.0 || params[nparams].plp3 < 0.0 ||
params[nparams].plp6 < 0.0 ||
params[nparams].a123 > 360.0 || params[nparams].aconf < 0.0 ||
params[nparams].addrep < 0.0 || params[nparams].romigb < 0.0 ||
params[nparams].romigc < 0.0 || params[nparams].romigd < 0.0 ||
params[nparams].romiga < 0.0 ||
params[nparams].QL1 > 0.0 || params[nparams].QU1 < 0.0 ||
params[nparams].DL1 < 0.0 || params[nparams].DU1 > 0.0 ||
params[nparams].QL2 > 0.0 || params[nparams].QU2 < 0.0 ||
params[nparams].DL2 < 0.0 || params[nparams].DU2 > 0.0 ||
params[nparams].chi < 0.0 ||
// params[nparams].dj < 0.0 || params[nparams].dk < 0.0 ||
// params[nparams].dl < 0.0 || params[nparams].dm < 0.0 ||
params[nparams].esm1 < 0.0)
error->all(FLERR,"Illegal COMB parameter");
if (params[nparams].lam11 < params[nparams].lam21 ||
params[nparams].lam12 < params[nparams].lam22 ||
params[nparams].biga1< params[nparams].bigb1 ||
params[nparams].biga2< params[nparams].bigb2)
error->all(FLERR,"Illegal COMB parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairComb::setup()
{
int i,j,k,m,n;
// set elem2param for all element triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// compute parameter values derived from inputs
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].bigr + params[m].bigd;
params[m].cutsq = params[m].cut*params[m].cut;
params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern);
params[m].c2 = pow(2.0*params[m].powern*1.0e-8,-1.0/params[m].powern);
params[m].c3 = 1.0/params[m].c2;
params[m].c4 = 1.0/params[m].c1;
params[m].rlm1 = 0.5*(params[m].lam11+params[m].lam12)*params[m].romigc;
params[m].rlm2 = 0.5*(params[m].lam21+params[m].lam22)*params[m].romigd;
params[m].Qo1 = (params[m].QU1+params[m].QL1)/2.0; // (A22)
params[m].dQ1 = (params[m].QU1-params[m].QL1)/2.0; // (A21)
params[m].aB1 = 1.0 /
(1.0-pow(fabs(params[m].Qo1/params[m].dQ1),10.0)); // (A20)
params[m].bB1 = pow(fabs(params[m].aB1),0.1)/params[m].dQ1; // (A19)
params[m].nD1 = log(params[m].DU1/(params[m].DU1-params[m].DL1))/
log(params[m].QU1/(params[m].QU1-params[m].QL1));
params[m].bD1 = (pow((params[m].DL1-params[m].DU1),(1.0/params[m].nD1)))/
(params[m].QU1-params[m].QL1);
params[m].Qo2 = (params[m].QU2+params[m].QL2)/2.0; // (A22)
params[m].dQ2 = (params[m].QU2-params[m].QL2)/2.0; // (A21)
params[m].aB2 = 1.0 /
(1.0-pow(fabs(params[m].Qo2/params[m].dQ2),10.0)); // (A20)
params[m].bB2 = pow(fabs(params[m].aB2),0.1)/params[m].dQ2; // (A19)
params[m].nD2 = log(params[m].DU2/(params[m].DU2-params[m].DL2))/
log(params[m].QU2/(params[m].QU2-params[m].QL2));
params[m].bD2 = (pow((params[m].DL2-params[m].DU2),(1.0/params[m].nD2)))/
(params[m].QU2-params[m].QL2);
params[m].lcut = params[m].coulcut;
params[m].lcutsq = params[m].lcut*params[m].lcut;
params[m].gamma = 1.0; // for the change in pair_comb.h
}
// set cutmax to max of all params
cutmax = cutmin = 0.0;
cor_flag = 0;
for (m = 0; m < nparams; m++) {
if (params[m].cut > cutmax) cutmax = params[m].cut;
if (params[m].lcut > cutmax) cutmax = params[m].lcut;
if (params[m].cutsq > cutmin) cutmin = params[m].cutsq+0.2;
if (params[m].hfocor > 0.0001) cor_flag = 1;
}
}
/* ---------------------------------------------------------------------- */
void PairComb::repulsive(Param *param, double rsq, double &fforce,
int eflag, double &eng, double iq, double jq)
{
double r,tmp_fc,tmp_fc_d,tmp_exp,Di,Dj;
double bigA,Asi,Asj,vrcs,fvrcs,fforce_tmp;
double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j;
double romi = param->addrep;
double rrcs = param->bigr + param->bigd;
r = sqrt(rsq);
if (r > rrcs) return ;
tmp_fc = comb_fc(r,param);
tmp_fc_d = comb_fc_d(r,param);
tmp_exp = exp(-param->rlm1 * r);
arr1 = 2.22850; arr2 = 1.89350;
fc2j = comb_fc2(r);
fc3j = comb_fc3(r);
fcp2j = comb_fc2_d(r);
fcp3j = comb_fc3_d(r);
Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-iq)),param->nD1);
Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-jq)),param->nD2);
Asi = param->biga1 * exp(param->lam11*Di);
Asj = param->biga2 * exp(param->lam12*Dj);
if ( Asi > 0.0 && Asj > 0.0 )
bigA = sqrt(Asi*Asj)*param->romiga;
else
bigA = 0.0;
fforce = -bigA * tmp_exp * (tmp_fc_d - tmp_fc*param->rlm1) / r;
// additional repulsion for TiO2 and HfO2 (switch by cor_flag)
vrcs = 0.0; fvrcs = 0.0;
if (romi > 0.0) {
if (!cor_flag) {
vrcs = romi * pow((1.0-r/rrcs),2.0);
fvrcs= romi * 2.0 * (r/rrcs-1.0)/rrcs; }
else if (cor_flag) {
rslp = ((arr1-r)/(arr1-arr2));
rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2;
vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0;
fvrcs = fcp2j*fcp3j*romi*rslp*(-25.0*rslp2+7.50)/(arr1-arr2);
}
fforce_tmp = fforce*vrcs - (tmp_fc * bigA * tmp_exp * fvrcs);
fforce += fforce_tmp;
}
// eng = repulsive energy
if (eflag) eng = (tmp_fc * bigA * tmp_exp)*(1.0+vrcs);
}
/* ---------------------------------------------------------------------- */
double PairComb::zeta(Param *param, double rsqij, double rsqik,
double *delrij, double *delrik)
{
double rij,rik,costheta,arg,ex_delr;
rij = sqrt(rsqij);
if (rij > param->bigr+param->bigd) return 0.0;
rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
if (param->powermint == 3) arg = pow(param->rlm2 * (rij-rik),3.0);
else arg = param->rlm2 * (rij-rik);
if (arg > 69.0776) ex_delr = 1.e30;
else if (arg < -69.0776) ex_delr = 0.0;
else ex_delr = exp(arg);
return comb_fc(rik,param) * comb_gijk(costheta,param) * ex_delr;
}
/* ----------------------------------------------------------------------
Legendre polynomial bond angle correction to energy
------------------------------------------------------------------------- */
double PairComb::elp(Param *param, double rsqij, double rsqik,
double *delrij, double *delrik)
{
if (param->aconf > 1.0e-6 || param->plp1 > 1.0e-6 ||
param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
double rij,rik,costheta,lp1,lp3,lp6;
double rmu,rmu2,comtt,fcj,fck;
double pplp1 = param->plp1, pplp3 = param->plp3, pplp6 = param->plp6;
double c123 = cos(param->a123*MY_PI/180.0);
// cos(theta) of the i-j-k
// cutoff function of rik
rij = sqrt(rsqij);
rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
fcj = comb_fc(rij,param);
fck = comb_fc(rik,param);
rmu = costheta;
// Legendre Polynomial functions
if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
rmu2 = rmu*rmu;
lp1 = rmu; lp3 = 0.5*(5.0*rmu2*rmu-3.0*rmu);
lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0;
comtt = pplp1*lp1 + pplp3*lp3 + pplp6*lp6;
} else comtt = 0.0;
// bond-bending terms
if (param->aconf>1e-4) {
if (param->hfocor >= 0.0)
comtt += param->aconf *(rmu-c123)*(rmu-c123);
else if (param->hfocor < 0.0)
comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123));
}
return 0.5 * fcj * fck * comtt;
}
return 0.0;
}
/* ----------------------------------------------------------------------
Legendre polynomial bond angle correction to forces
------------------------------------------------------------------------- */
void PairComb::flp(Param *param, double rsqij, double rsqik,
double *delrij, double *delrik, double *drilp,
double *drjlp, double *drklp)
{
double ffj1,ffj2,ffk1,ffk2;
ffj1 = 0.0; ffj2 = 0.0; ffk1 = 0.0; ffk2 = 0.0;
if (param->aconf > 1.0e-4 || param->plp1 > 1.0e-6 ||
param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
double rij,rik,costheta,lp1,lp1_d,lp3,lp3_d,lp6,lp6_d;
double rmu,rmu2,comtt,comtt_d,com4k,com5,fcj,fck,fck_d;
double pplp1 = param->plp1;
double pplp3 = param->plp3;
double pplp6 = param->plp6;
double c123 = cos(param->a123*MY_PI/180.0);
// fck_d = derivative of cutoff function
rij = sqrt(rsqij); rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
fcj = comb_fc(rij,param);
fck = comb_fc(rik,param);
fck_d = comb_fc_d(rik,param);
rmu = costheta;
// Legendre Polynomial functions and derivatives
if (param->plp1 > 1.0e-6 || param->plp3 > 1.0e-6 || param->plp6 > 1.0e-6) {
rmu2 = rmu*rmu;
lp1 = rmu; lp3 = (2.5*rmu2*rmu-1.5*rmu);
lp6 = (231.0*rmu2*rmu2*rmu2-315.0*rmu2*rmu2+105.0*rmu2-5.0)/16.0;
lp1_d = 1.0;lp3_d = (7.5*rmu2-1.5);
lp6_d = (1386.0*rmu2*rmu2*rmu-1260.0*rmu2*rmu+210.0)/16.0;
comtt = pplp1*lp1 + pplp3*lp3 + pplp6*lp6;
comtt_d = pplp1*lp1_d + pplp3*lp3_d + pplp6*lp6_d;
} else {
comtt = 0.0;
comtt_d = 0.0;
}
// bond-bending terms derivatives
if (param->aconf > 1.0e-4) {
if (param->hfocor >= 0.0) {
comtt += param->aconf *(rmu-c123)*(rmu-c123);
comtt_d += 2.0*param->aconf*(rmu-c123);
} else if (param->hfocor < 0.0) {
comtt += param->aconf *(4.0-(rmu-c123)*(rmu-c123));
comtt_d += -2.0*param->aconf*(rmu-c123);
}
}
com4k = 2.0 * fcj * fck_d * comtt;
com5 = fcj * fck * comtt_d;
ffj1 =-0.5*(com5/(rij*rik));
ffj2 = 0.5*(com5*rmu/rsqij);
ffk1 = ffj1;
ffk2 = 0.5*(-com4k/rik+com5*rmu/rsqik);
} else {
ffj1 = 0.0; ffj2 = 0.0;
ffk1 = 0.0; ffk2 = 0.0;
}
// j-atom
vec3_scale(ffj1,delrik,drjlp); // (k,x[],y[]), y[]=k*x[]
vec3_scaleadd(ffj2,delrij,drjlp,drjlp); // (k,x[],y[],z[]), z[]=k*x[]+y[]
// k-atom
vec3_scale(ffk1,delrij,drklp);
vec3_scaleadd(ffk2,delrik,drklp,drklp);
// i-atom
vec3_add(drjlp,drklp,drilp); // (x[],y[],z[]), z[]=x[]+y[]
vec3_scale(-1.0,drilp,drilp);
}
/* ---------------------------------------------------------------------- */
void PairComb::force_zeta(Param *param, int eflag, int i, int j, double rsq,
double zeta_ij, double iq, double jq, double &fforce,
double &prefactor, double &eng)
{
double r,fa,fa_d,bij;
r = sqrt(rsq);
if (r > param->bigr+param->bigd) return;
fa = comb_fa(r,param,iq,jq);
fa_d = comb_fa_d(r,param,iq,jq);
bij = comb_bij(zeta_ij,param);
bbij[i][j] = bij;
// force
fforce = 0.5*bij*fa_d / r;
prefactor = -0.5*fa * comb_bij_d(zeta_ij,param);
// eng = attractive energy
if (eflag) eng = 0.5*bij*fa;
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc(double r, Param *param)
{
double comb_R = param->bigr;
double comb_D = param->bigd;
if (r < comb_R-comb_D) return 1.0;
if (r > comb_R+comb_D) return 0.0;
return 0.5*(1.0 - sin(MY_PI2*(r - comb_R)/comb_D));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc_d(double r, Param *param)
{
double comb_R = param->bigr;
double comb_D = param->bigd;
if (r < comb_R-comb_D) return 0.0;
if (r > comb_R+comb_D) return 0.0;
return -(MY_PI4/comb_D) * cos(MY_PI2*(r - comb_R)/comb_D);
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc2(double r)
{
double comb_R = 1.89350;
double comb_D = comb_R + 0.050;
if (r < comb_R) return 0.0;
if (r > comb_D) return 1.0;
return 0.5*(1.0 + cos(MY_PI*(r - comb_R)/(comb_D-comb_R)));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc2_d(double r)
{
double comb_R = 1.89350;
double comb_D = comb_R + 0.050;
if (r < comb_R) return 0.0;
if (r > comb_D) return 0.0;
return -(MY_PI2/(comb_D-comb_R)) * sin(MY_PI*(r - comb_R)/(comb_D-comb_R));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc3(double r)
{
double comb_R = 2.51350;
double comb_D = comb_R + 0.050;
if (r < comb_R) return 1.0;
if (r > comb_D) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(r - comb_R)/(comb_D-comb_R)));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fc3_d(double r)
{
double comb_R = 2.51350;
double comb_D = comb_R + 0.050;
if (r < comb_R) return 0.0;
if (r > comb_D) return 0.0;
return -(MY_PI2/(comb_D-comb_R)) * sin(MY_PI*(r - comb_R)/(comb_D-comb_R));
}
/* ---------------------------------------------------------------------- */
double PairComb::self(Param *param, double qi, double selfpot)
{
double self_tmp, cmin, cmax, qmin, qmax;
double s1=param->chi, s2=param->dj, s3=param->dk, s4=param->dl, s5=param->dm;
self_tmp = 0.0;
qmin = param->QL1*0.90;
qmax = param->QU1*0.90;
cmin = cmax = 1000.0;
self_tmp = qi*(s1+qi*(s2+selfpot+qi*(s3+qi*(s4+qi*qi*s5))));
if (qi < qmin) self_tmp += cmin * pow((qi-qmin),4.0);
if (qi > qmax) self_tmp += cmax * pow((qi-qmax),4.0);
return self_tmp;
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fa(double r, Param *param, double iq, double jq)
{
double bigB,Bsi,Bsj;
double qi,qj,Di,Dj;
if (r > param->bigr + param->bigd) return 0.0;
qi = iq; qj = jq;
Di = Dj = Bsi = Bsj = bigB = 0.0;
Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
Bsi = param->bigb1 * exp(param->lam21*Di)*
(param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
Bsj = param->bigb2 * exp(param->lam22*Dj)*
(param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb;
else bigB = 0.0;
return -bigB * exp(-param->rlm2 * r) * comb_fc(r,param);
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_fa_d(double r, Param *param, double iq, double jq)
{
double bigB,Bsi,Bsj;
double qi,qj,Di,Dj;
if (r > param->bigr + param->bigd) return 0.0;
qi = iq; qj = jq;
Di = Dj = Bsi = Bsj = bigB = 0.0;
Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
Bsi = param->bigb1 * exp(param->lam21*Di)*
(param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
Bsj = param->bigb2 * exp(param->lam22*Dj)*
(param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
if (Bsi > 0.0 && Bsj > 0.0) bigB = sqrt(Bsi*Bsj)*param->romigb;
else bigB = 0.0;
return bigB * exp(-param->rlm2 * r) *
(param->rlm2 * comb_fc(r,param) - comb_fc_d(r,param));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_bij(double zeta, Param *param)
{
double tmp = param->beta * zeta;
if (tmp > param->c1) return 1.0/sqrt(tmp);
if (tmp > param->c2)
return (1.0 - pow(tmp,-1.0*param->powern) / (2.0*param->powern))/sqrt(tmp);
if (tmp < param->c4) return 1.0;
if (tmp < param->c3)
return 1.0 - pow(tmp,param->powern)/(2.0*param->powern);
return pow(1.0 + pow(tmp,param->powern), -1.0/(2.0*param->powern));
}
/* ---------------------------------------------------------------------- */
double PairComb::comb_bij_d(double zeta, Param *param)
{
double tmp = param->beta * zeta;
if (tmp > param->c1) return param->beta * -0.5*pow(tmp,-1.5);
if (tmp > param->c2)
return param->beta * (-0.5*pow(tmp,-1.5) *
(1.0 - 0.5*(1.0 + 1.0/(2.0*param->powern)) *
pow(tmp,-param->powern)));
if (tmp < param->c4) return 0.0;
if (tmp < param->c3)
return -0.5*param->beta * pow(tmp,param->powern-1.0);
double tmp_n = pow(tmp,param->powern);
return -0.5 * pow(1.0+tmp_n, -1.0-(1.0/(2.0*param->powern)))*tmp_n / zeta;
}
/* ---------------------------------------------------------------------- */
void PairComb::attractive(Param *param, double prefactor,
double rsqij, double rsqik,
double *delrij, double *delrik,
double *fi, double *fj, double *fk)
{
double rij_hat[3],rik_hat[3];
double rij,rijinv,rik,rikinv;
rij = sqrt(rsqij);
rijinv = 1.0/rij;
vec3_scale(rijinv,delrij,rij_hat);
rik = sqrt(rsqik);
rikinv = 1.0/rik;
vec3_scale(rikinv,delrik,rik_hat);
comb_zetaterm_d(prefactor,rij_hat,rij,rik_hat,rik,fi,fj,fk,param);
}
/* ---------------------------------------------------------------------- */
void PairComb::comb_zetaterm_d(double prefactor, double *rij_hat, double rij,
double *rik_hat, double rik, double *dri,
double *drj, double *drk, Param *param)
{
double gijk,gijk_d,ex_delr,ex_delr_d,fc,dfc,cos_theta,tmp;
double dcosdri[3],dcosdrj[3],dcosdrk[3];
fc = comb_fc(rik,param);
dfc = comb_fc_d(rik,param);
if (param->powermint == 3) tmp = pow(param->rlm2 * (rij-rik),3.0);
else tmp = param->rlm2 * (rij-rik);
if (tmp > 69.0776) ex_delr = 1.e30;
else if (tmp < -69.0776) ex_delr = 0.0;
else ex_delr = exp(tmp); // ex_delr is Ygexp
if (param->powermint == 3)
ex_delr_d = 3.0*pow(param->rlm2,3.0) * pow(rij-rik,2.0)*ex_delr; // com3
else ex_delr_d = param->rlm2 * ex_delr; // com3
cos_theta = vec3_dot(rij_hat,rik_hat);
gijk = comb_gijk(cos_theta,param);
gijk_d = comb_gijk_d(cos_theta,param);
costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk);
// compute the derivative wrt Ri
// dri = -dfc*gijk*ex_delr*rik_hat;
// dri += fc*gijk_d*ex_delr*dcosdri;
// dri += fc*gijk*ex_delr_d*(rik_hat - rij_hat);
// (k,x[],y[]), y[]=k*x[]
// (k,x[],y[],z[]), z[]=k*x[]+y[]
vec3_scale(-dfc*gijk*ex_delr,rik_hat,dri);
vec3_scaleadd(fc*gijk_d*ex_delr,dcosdri,dri,dri);
vec3_scaleadd(fc*gijk*ex_delr_d,rik_hat,dri,dri);
vec3_scaleadd(-fc*gijk*ex_delr_d,rij_hat,dri,dri);
vec3_scale(prefactor,dri,dri);
// compute the derivative wrt Rj
// drj = fc*gijk_d*ex_delr*dcosdrj;
// drj += fc*gijk*ex_delr_d*rij_hat;
vec3_scale(fc*gijk_d*ex_delr,dcosdrj,drj);
vec3_scaleadd(fc*gijk*ex_delr_d,rij_hat,drj,drj);
vec3_scale(prefactor,drj,drj);
// compute the derivative wrt Rk
// drk = dfc*gijk*ex_delr*rik_hat;
// drk += fc*gijk_d*ex_delr*dcosdrk;
// drk += -fc*gijk*ex_delr_d*rik_hat;
vec3_scale(dfc*gijk*ex_delr,rik_hat,drk);
vec3_scaleadd(fc*gijk_d*ex_delr,dcosdrk,drk,drk);
vec3_scaleadd(-fc*gijk*ex_delr_d,rik_hat,drk,drk);
vec3_scale(prefactor,drk,drk);
}
/* ---------------------------------------------------------------------- */
void PairComb::costheta_d(double *rij_hat, double rij,
double *rik_hat, double rik,
double *dri, double *drj, double *drk)
{
// first element is devative wrt Ri, second wrt Rj, third wrt Rk
double cos_theta = vec3_dot(rij_hat,rik_hat);
vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj);
vec3_scale(1.0/rij,drj,drj);
vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk);
vec3_scale(1.0/rik,drk,drk);
vec3_add(drj,drk,dri);
vec3_scale(-1.0,dri,dri);
}
/* ---------------------------------------------------------------------- */
void PairComb::sm_table()
{
int i,j,k,m,nntypes,ncoul;
int inty, itype, jtype;
int iparam_i, iparam_ij, iparam_ji;
double r,dra,drin,rc,z,zr,zrc,ea,eb,ea3,eb3,alf;
double exp2er,exp2ersh,fafash,dfafash,F1,dF1,ddF1,E1,E2,E3,E4;
double exp2ear,exp2ebr,exp2earsh,exp2ebrsh,fafbsh,dfafbsh;
int n = atom->ntypes;
int nmax = atom->nmax;
dra = 0.001; // lookup table step size
drin = 0.1; // starting distance of 1/r
rc = cutmax;
alf = 0.20;
nntypes = int((n+1)*n/2); // interaction types
ncoul = int((rc-drin)/dra)+1;
// allocate arrays
memory->create(intype,n,n,"pair:intype");
memory->create(fafb,ncoul,nntypes,"pair:fafb");
memory->create(dfafb,ncoul,nntypes,"pair:dfafb");
memory->create(ddfafb,ncoul,nntypes,"pair:ddfafb");
memory->create(phin,ncoul,nntypes,"pair:phin");
memory->create(dphin,ncoul,nntypes,"pair:dphin");
memory->create(erpaw,25000,2,"pair:erpaw");
memory->create(NCo,nmax,"pair:NCo");
memory->create(bbij,nmax,MAXNEIGH,"pair:bbij");
memory->create(sht_num,nmax,"pair:sht_num");
sht_first = (int **) memory->smalloc(nmax*sizeof(int *),"pair:sht_first");
// set interaction number: 0-0=0, 1-1=1, 0-1=1-0=2
m = 0; k = n;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (j == i) {
intype[i][j] = m;
m += 1;
} else if (j != i && j > i) {
intype[i][j] = k;
k += 1;
} else if (j != i && j < i) {
intype[i][j] = intype[j][i];
}
}
}
// default arrays to zero
for (i = 0; i < ncoul; i ++) {
for (j = 0; j < nntypes; j ++) {
fafb[i][j] = 0.0;
dfafb[i][j] = 0.0;
ddfafb[i][j] = 0.0;
phin[i][j] = 0.0;
dphin[i][j] = 0.0;
}
}
// direct 1/r energy with Slater 1S orbital overlap
for (i = 0; i < n; i++) {
r = drin;
itype = params[i].ielement;
iparam_i = elem2param[itype][itype][itype];
z = params[iparam_i].esm1;
for (j = 0; j < ncoul; j++) {
exp2er = exp(-2.0 * z * r);
phin[j][i] = 1.0 - exp2er * (1.0 + 2.0 * z * r * (1.0 + z * r));
dphin[j][i] = (4.0 * exp2er * z * z * z * r * r);
r += dra;
}
}
for (i = 0; i < n; i ++) {
for (j = 0; j < n; j ++) {
r = drin;
if (j == i) {
itype = params[i].ielement;
inty = intype[itype][itype];
iparam_i = elem2param[itype][itype][itype];
z = params[iparam_i].esm1;
zrc = z * rc;
exp2ersh = exp(-2.0 * zrc);
fafash = -exp2ersh * (1.0 / rc +
z * (11.0/8.0 + 3.0/4.0*zrc + zrc*zrc/6.0));
dfafash = exp2ersh * (1.0/(rc*rc) + 2.0*z/rc +
z*z*(2.0 + 7.0/6.0*zrc + zrc*zrc/3.0));
for (k = 0; k < ncoul; k ++) {
zr = z * r;
exp2er = exp(-2.0*zr);
F1 = -exp2er * (1.0 / r +
z * (11.0/8.0 + 3.0/4.0*zr + zr*zr/6.0));
dF1 = exp2er * (1.0/(r*r) + 2.0*z/r +
z*z*(2.0 + 7.0/6.0*zr + zr*zr/3.0));
ddF1 = -exp2er * (2.0/(r*r*r) + 4.0*z/(r*r) -
z*z*z/3.0*(17.0/2.0 + 5.0*zr + 2.0*zr*zr));
fafb[k][inty] = F1-fafash-(r-rc)*dfafash;
dfafb[k][inty] = (dF1 - dfafash);
ddfafb[k][inty] = ddF1;
r += dra;
}
} else if (j != i) {
itype = params[i].ielement;
jtype = params[j].ielement;
inty = intype[itype][jtype];
iparam_ij = elem2param[itype][jtype][jtype];
ea = params[iparam_ij].esm1;
ea3 = ea*ea*ea;
iparam_ji = elem2param[jtype][itype][itype];
eb = params[iparam_ji].esm1;
eb3 = eb*eb*eb;
E1 = ea*eb3*eb/((ea+eb)*(ea+eb)*(ea-eb)*(ea-eb));
E2 = eb*ea3*ea/((ea+eb)*(ea+eb)*(eb-ea)*(eb-ea));
E3 = (3.0*ea*ea*eb3*eb-eb3*eb3) /
((ea+eb)*(ea+eb)*(ea+eb)*(ea-eb)*(ea-eb)*(ea-eb));
E4 = (3.0*eb*eb*ea3*ea-ea3*ea3) /
((ea+eb)*(ea+eb)*(ea+eb)*(eb-ea)*(eb-ea)*(eb-ea));
exp2earsh = exp(-2.0*ea*rc);
exp2ebrsh = exp(-2.0*eb*rc);
fafbsh = -exp2earsh*(E1 + E3/rc)-exp2ebrsh*(E2 + E4/rc);
dfafbsh =
exp2earsh*(2.0*ea*(E1+E3/rc)+E3/(rc*rc)) +
exp2ebrsh*(2.0*eb*(E2+E4/rc)+E4/(rc*rc));
for (k = 0; k < ncoul; k ++) {
exp2ear = exp(-2.0*ea*r);
exp2ebr = exp(-2.0*eb*r);
fafb[k][inty] =
- exp2ear*(E1+E3/r) - exp2ebr*(E2+E4/r)
- fafbsh - (r-rc) * dfafbsh;
dfafb[k][inty] = (exp2ear*(2.0*ea*(E1+E3/r) + E3/(r*r))
+ exp2ebr*(2.0*eb*(E2+E4/r) + E4/(r*r))- dfafbsh);
ddfafb[k][inty] = (- exp2ear*(E3/(r*r)*(1.0/r+2.0*ea/r+2.0/(r*r))
+ 2.0*ea*(E1+E3/r))-
exp2ebr*(E4/(r*r)
*(1.0/r+2.0*eb/r+2.0/(r*r)) +
2.0*eb*(E2+E4/r)));
r += dra;
}
}
}
}
for (i = 0; i < 25000; i ++) {
r = dra * i + drin;
erpaw[i][0] = erfc(r*alf);
erpaw[i][1] = exp(-r*r*alf*alf);
}
}
/* ---------------------------------------------------------------------- */
void PairComb::potal_calc(double &calc1, double &calc2, double &calc3)
{
double alf,rcoul,esucon;
int m;
rcoul = 0.0;
for (m = 0; m < nparams; m++)
if (params[m].lcut > rcoul) rcoul = params[m].lcut;
alf = 0.20;
esucon = force->qqr2e;
calc2 = (erfc(rcoul*alf)/rcoul/rcoul+2.0*alf/MY_PIS*
exp(-alf*alf*rcoul*rcoul)/rcoul)*esucon/rcoul;
calc3 = (erfc(rcoul*alf)/rcoul)*esucon;
calc1 = -(alf/MY_PIS*esucon+calc3*0.5);
}
/* ---------------------------------------------------------------------- */
void PairComb::tri_point(double rsq, int &mr1, int &mr2,
int &mr3, double &sr1, double &sr2,
double &sr3, int &itype)
{
double r, rin, dr, dd, rr1, rridr, rridr2;
rin = 0.10; dr = 0.0010;
r = sqrt(rsq);
if (r < rin + 2.0*dr) r = rin + 2.0*dr;
if (r > cutmax - 2.0*dr) r = cutmax - 2.0*dr;
rridr = (r-rin)/dr;
mr1 = int(rridr)-1;
dd = rridr - float(mr1);
if (dd > 0.5) mr1 += 1;
mr2 = mr1 + 1;
mr3 = mr2 + 1;
rr1 = float(mr1)*dr;
rridr = (r - rin - rr1)/dr;
rridr2 = rridr * rridr;
sr1 = (rridr2 - rridr) * 0.50;
sr2 = 1.0 - rridr2;
sr3 = (rridr2 + rridr) * 0.50;
}
/* ---------------------------------------------------------------------- */
void PairComb::direct(int inty, int mr1, int mr2, int mr3, double rsq,
double sr1, double sr2, double sr3,
double iq, double jq,
double potal, double fac11, double fac11e,
double &pot_tmp, double &pot_d)
{
double r,erfcc,fafbn1,potij,sme2,esucon;
double r3,erfcd,dfafbn1,smf2,dvdrr,alf,alfdpi;
r = sqrt(rsq);
r3 = r * rsq;
alf = 0.20;
alfdpi = 2.0*alf/MY_PIS;
esucon = force->qqr2e;
pot_tmp = 0.0;
pot_d = 0.0;
// 1/r energy
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
potij = (erfcc/r * esucon - fac11e);
sme2 = potij + fafbn1 * esucon;
pot_tmp = 1.0 * iq * jq *sme2;
// 1/r force (wrt r)
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
dfafbn1= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
smf2 = dvdrr - dfafbn1 * esucon/r;
pot_d = 1.0 * iq * jq * smf2;
}
/* ---------------------------------------------------------------------- */
void PairComb::field(Param *param, double rsq, double iq,double jq,
double &vionij,double &fvionij)
{
double r,r5,r6,rc,rc5,rc6,rf5,drf6,smpn,smpl,rfx1,rfx2;
double cmi1,cmi2,cmj1,cmj2;
r = sqrt(rsq);
r5 = r*r*r*r*r;
r6 = r5 * r;
rc = param->lcut;
rc5 = rc*rc*rc*rc*rc;
rc6 = rc5 * rc;
cmi1 = param->cmn1;
cmi2 = param->cmn2;
cmj1 = param->cml1;
cmj2 = param->cml2;
rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6;
drf6 = 5.0/rc6 - 5.0/r6;
// field correction energy
smpn = rf5*jq*(cmi1+jq*cmi2);
smpl = rf5*iq*(cmj1+iq*cmj2);
vionij += 1.0 * (smpn + smpl);
// field correction force
rfx1 = jq*drf6*(cmi1+jq*cmi2)/r;
rfx2 = iq*drf6*(cmj1+iq*cmj2)/r;
fvionij -= 1.0 * (rfx1 + rfx2);
}
/* ---------------------------------------------------------------------- */
double PairComb::yasu_char(double *qf_fix, int &igroup)
{
- int i,j,ii,jj,jnum,itag,jtag;
+ int i,j,ii,jj,jnum;
int itype,jtype,iparam_i,iparam_ij;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp;
double rsq1,delr1[3];
int *ilist,*jlist,*numneigh,**firstneigh;
double iq,jq,fqi,fqj,fqij,fqjj;
double potal,fac11,fac11e,sr1,sr2,sr3;
int mr1,mr2,mr3,inty,nj;
double **x = atom->x;
double *q = atom->q;
int *type = atom->type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
int *mask = atom->mask;
int groupbit = group->bitmask[igroup];
qf = qf_fix;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit)
qf[i] = 0.0;
}
// communicating charge force to all nodes, first forward then reverse
comm->forward_comm_pair(this);
// self energy correction term: potal
potal_calc(potal,fac11,fac11e);
// loop over full neighbor list of my atoms
fqi = fqj = fqij = fqjj = 0.0;
for (ii = 0; ii < inum; ii ++) {
i = ilist[ii];
itag = tag[i];
nj = 0;
if (mask[i] & groupbit) {
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
iq = q[i];
iparam_i = elem2param[itype][itype][itype];
// charge force from self energy
fqi = qfo_self(&params[iparam_i],iq,potal);
// two-body interactions
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] < x[i][2]) 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]];
jq = q[j];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = vec3_dot(delr1,delr1);
iparam_ij = elem2param[itype][jtype][jtype];
// long range q-dependent
if (rsq1 > params[iparam_ij].lcutsq) continue;
inty = intype[itype][jtype];
// polynomial three-point interpolation
tri_point(rsq1,mr1,mr2,mr3,sr1,sr2,sr3,itype);
// 1/r charge forces
qfo_direct(inty,mr1,mr2,mr3,rsq1,sr1,sr2,sr3,fac11e,fqij);
fqi += jq * fqij; qf[j] += iq * fqij;
// field correction to self energy and charge force
qfo_field(&params[iparam_ij],rsq1,iq,jq,fqij,fqjj);
fqi += fqij;
qf[j] += fqjj;
}
// three-body interactions
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = map[type[j]];
jq = q[j];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = vec3_dot(delr1,delr1);
iparam_ij = elem2param[itype][jtype][jtype];
if (rsq1 > params[iparam_ij].cutsq) continue;
nj ++;
// charge force in Aij and Bij
qfo_short(&params[iparam_ij],i,nj,rsq1,iq,jq,fqij,fqjj);
fqi += fqij; qf[j] += fqjj;
}
qf[i] += fqi;
}
}
comm->reverse_comm_pair(this);
// sum charge force on each node and return it
double eneg = 0.0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit)
eneg += qf[i];
}
double enegtot;
MPI_Allreduce(&eneg,&enegtot,1,MPI_DOUBLE,MPI_SUM,world);
return enegtot;
}
/* ---------------------------------------------------------------------- */
double PairComb::qfo_self(Param *param, double qi, double selfpot)
{
double self_d,cmin,cmax,qmin,qmax;
double s1 = param->chi;
double s2 = param->dj;
double s3 = param->dk;
double s4 = param->dl;
double s5 = param->dm;
self_d = 0.0;
qmin = param->QL1*0.90;
qmax = param->QU1*0.90;
cmin = cmax = 1000.0;
self_d = s1+qi*(2.0*(s2+selfpot)+qi*(3.0*s3+qi*(4.0*s4+qi*qi*6.0*s5)));
if (qi < qmin) {
// char str[128];
// sprintf(str,"Pair COMB charge %.10f with force %.10f hit min barrier",
// qi,self_d);
// error->warning(FLERR,str,0);
self_d += 4.0 * cmin * pow((qi-qmin),3.0);
}
if (qi > qmax) {
// char str[128];
// sprintf(str,"Pair COMB charge %.10f with force %.10f hit max barrier",
// qi,self_d);
// error->warning(FLERR,str,0);
self_d += 4.0 * cmax * pow((qi-qmax),3.0);
}
return self_d;
}
/* ---------------------------------------------------------------------- */
void PairComb::qfo_direct(int inty, int mr1, int mr2, int mr3,
double rsq, double sr1, double sr2,
double sr3, double fac11e, double &fqij)
{
double r, erfcc, fafbn1, vm, esucon;
r = sqrt(rsq);
esucon=force->qqr2e;
// 1/r force (wrt q)
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
fafbn1= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
vm = (erfcc/r * esucon - fac11e);
fqij = 1.0 * (vm+esucon*fafbn1);
}
/* ---------------------------------------------------------------------- */
void PairComb::qfo_field(Param *param, double rsq,double iq,double jq,
double &fqij, double &fqjj)
{
double r,r5,r6,rc,rc5,rc6;
double cmi1,cmi2,cmj1,cmj2,rf5;
fqij = fqjj = 0.0;
r = sqrt(rsq);
r5 = r*r*r*r*r;
r6 = r5 * r;
rc = param->lcut;
rc5 = rc*rc*rc*rc*rc;
rc6 = rc5 * rc;
cmi1 = param->cmn1;
cmi2 = param->cmn2;
cmj1 = param->cml1;
cmj2 = param->cml2;
rf5 = 1.0/r5 - 1.0/rc5 + 5.0*(r-rc)/rc6;
// field correction charge force
fqij = 1.0 * rf5 * (cmj1 + 2.0 * iq * cmj2);
fqjj = 1.0 * rf5 * (cmi1 + 2.0 * jq * cmi2);
}
/* ---------------------------------------------------------------------- */
void PairComb::qfo_short(Param *param, int i, int j, double rsq,
double iq, double jq, double &fqij, double &fqjj)
{
double r,tmp_fc,tmp_fc_d,tmp_exp1,tmp_exp2;
double bigA,Asi,Asj,vrcs;
double romi = param->addrep,rrcs = param->bigr + param->bigd;
double qi,qj,Di,Dj,bigB,Bsi,Bsj;
double QUchi,QOchi,QUchj,QOchj,YYDiqp,YYDjqp;
double YYAsiqp,YYAsjqp,YYBsiqp,YYBsjqp;
double caj,cbj,bij,cfqr,cfqs;
double romie = param->romiga;
double romib = param->romigb;
double ca1,ca2,ca3,ca4;
double rslp,rslp2,rslp4,arr1,arr2,fc2j,fc3j,fcp2j,fcp3j;
qi = iq; qj = jq; r = sqrt(rsq);
Di = Dj = Asi = Asj = bigA = Bsi = Bsj = bigB = 0.0;
QUchi = QOchi = QUchj = QOchj = YYDiqp = YYDjqp =0.0;
YYAsiqp = YYAsjqp = YYBsiqp = YYBsjqp = 0.0;
caj = cbj = vrcs = cfqr = cfqs = 0.0;
tmp_fc = comb_fc(r,param);
tmp_fc_d = comb_fc_d(r,param);
tmp_exp1 = exp(-param->rlm1 * r);
tmp_exp2 = exp(-param->rlm2 * r);
bij = bbij[i][j]; //comb_bij(zeta_ij,param);
arr1 = 2.22850; arr2 = 1.89350;
fc2j = comb_fc2(r);
fc3j = comb_fc3(r);
fcp2j = comb_fc2_d(r);
fcp3j = comb_fc3_d(r);
vrcs = 0.0;
if (romi > 0.0) {
if (!cor_flag) vrcs = romi * pow((1.0-r/rrcs),2.0);
else if (cor_flag) {
rslp = ((arr1-r)/(arr1-arr2));
rslp2 = rslp * rslp; rslp4 = rslp2 * rslp2;
vrcs = fc2j * fc3j * romi * ((50.0*rslp4-30.0*rslp2+4.50))/8.0;
}
}
Di = param->DU1 + pow(fabs(param->bD1*(param->QU1-qi)),param->nD1);
Dj = param->DU2 + pow(fabs(param->bD2*(param->QU2-qj)),param->nD2);
Asi = param->biga1 * exp(param->lam11*Di);
Asj = param->biga2 * exp(param->lam12*Dj);
Bsi = param->bigb1 * exp(param->lam21*Di)*
(param->aB1-fabs(pow(param->bB1*(qi-param->Qo1),10.0)));
Bsj = param->bigb2 * exp(param->lam22*Dj)*
(param->aB2-fabs(pow(param->bB2*(qj-param->Qo2),10.0)));
QUchi = (param->QU1-qi)*param->bD1;
QUchj = (param->QU2-qj)*param->bD2;
QOchi = (qi-param->Qo1)*param->bB1;
QOchj = (qj-param->Qo2)*param->bB2;
if (QUchi == 0.0) YYDiqp = 0.0;
else YYDiqp = -param->nD1 * QUchi * param->bD1 *
pow(fabs(QUchi),(param->nD1-2.0));
if (QUchj == 0.0) YYDjqp = 0.0;
else YYDjqp = -param->nD2 * QUchj * param->bD2 *
pow(fabs(QUchj),(param->nD2-2.0));
YYAsiqp = Asi * param->lam11 * YYDiqp;
YYAsjqp = Asj * param->lam12 * YYDjqp;
if (QOchi == 0.0)
YYBsiqp=Bsi*param->lam21*YYDiqp;
else
YYBsiqp=Bsi*param->lam21*YYDiqp-param->bigb1*exp(param->lam21*Di)*
10.0*QOchi*param->bB1*pow(fabs(QOchi),(10.0-2.0));
if (QOchj == 0.0)
YYBsjqp=Bsj*param->lam22*YYDjqp;
else
YYBsjqp=Bsj*param->lam22*YYDjqp-param->bigb2*exp(param->lam22*Dj)*
10.0*QOchj*param->bB2*pow(fabs(QOchj),(10.0-2.0));
if (Asi > 0.0 && Asj > 0.0) caj = 1.0/(2.0*sqrt(Asi*Asj)) * romie;
else caj = 0.0;
if (Bsi > 0.0 && Bsj > 0.0) cbj = 1.0/(2.0*sqrt(Bsi*Bsj)) * romib ;
else cbj = 0.0;
cfqr = 0.50 * tmp_fc * (1.0 + vrcs); // 0.5 b/c full atom loop
cfqs = -0.50 * tmp_fc * bij;
ca1 = Asj * caj * YYAsiqp;
ca2 = Bsj * cbj * YYBsiqp;
ca3 = Asi * caj * YYAsjqp;
ca4 = Bsi * cbj * YYBsjqp;
fqij = cfqr * tmp_exp1 * ca1;
fqij += cfqs * tmp_exp2 * ca2;
fqjj = cfqr * tmp_exp1 * ca3;
fqjj += cfqs * tmp_exp2 * ca4;
}
/* ---------------------------------------------------------------------- */
void PairComb::Over_cor(Param *param, double rsq1, int NCoi,
double &Eov, double &Fov)
{
double ECo,BCo,tmp_fc,tmp_fc_d;
double r = sqrt(rsq1);
int NCon = NCoi - 7;
tmp_fc = comb_fc(r,param);
tmp_fc_d = comb_fc(r,param);
Eov = 0.0; Fov = 0.0;
ECo = param->hfocor;
BCo = 0.1;
if (NCon >= 0.20) {
Eov = tmp_fc * ECo * NCon/(1.0+exp(BCo*NCon));
Fov = -(tmp_fc_d*Eov + tmp_fc*ECo/(1.0+exp(BCo*NCon)) -
(tmp_fc*ECo*NCon*BCo*exp(BCo*NCon)) /
((1.0+exp(BCo*NCon))*(1.0+exp(BCo*NCon))));
Fov /= r;
}
}
/* ---------------------------------------------------------------------- */
int PairComb::pack_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++] = qf[j];
}
return 1;
}
/* ---------------------------------------------------------------------- */
void PairComb::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n ;
for (i = first; i < last; i++) qf[i] = buf[m++];
}
/* ---------------------------------------------------------------------- */
int PairComb::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++] = qf[i];
return 1;
}
/* ---------------------------------------------------------------------- */
void PairComb::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
qf[j] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void PairComb::Short_neigh()
{
int nj,itype,jtype,iparam_ij;
int inum,jnum,i,j,ii,jj;
int *neighptrj,*ilist,*jlist,*numneigh;
int **firstneigh;
double xtmp,ytmp,ztmp,rr,rsq,delrj[3];
double **x = atom->x;
int *type = atom->type;
int nlocal = atom->nlocal;
int ntype = atom->ntypes;
if (atom->nmax > nmax) {
memory->sfree(sht_first);
nmax = atom->nmax;
sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
"pair:sht_first");
memory->grow(sht_num,nmax,"pair:sht_num");
memory->grow(NCo,nmax,"pair:NCo");
memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij");
}
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// create Comb neighbor list
ipage->reset();
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = type[i];
nj = 0;
neighptrj = ipage->vget();
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;
jtype = type[j];
delrj[0] = xtmp - x[j][0];
delrj[1] = ytmp - x[j][1];
delrj[2] = ztmp - x[j][2];
rsq = vec3_dot(delrj,delrj);
if (rsq > cutmin) continue;
neighptrj[nj++] = j;
}
sht_first[i] = neighptrj;
sht_num[i] = nj;
ipage->vgot(nj);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairComb::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += nmax * sizeof(int);
bytes += nmax * sizeof(int *);
for (int i = 0; i < comm->nthreads; i++)
bytes += ipage[i].size();
bytes += nmax * sizeof(int);
bytes += MAXNEIGH*nmax * sizeof(double);
return bytes;
}
diff --git a/src/MANYBODY/pair_comb3.cpp b/src/MANYBODY/pair_comb3.cpp
index afc0adf02..2d6bf9f9e 100644
--- a/src/MANYBODY/pair_comb3.cpp
+++ b/src/MANYBODY/pair_comb3.cpp
@@ -1,4058 +1,4058 @@
/* ----------------------------------------------------------------------
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 (Sandia, tnshan@sandia.gov)
Updates and debug: Tao Liang (U Florida, liang75@ufl.edu)
Dundar Yilmaz (dundar.yilmaz@zirve.edu.tr)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_comb3.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "group.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define MAXLINE 1024
#define DELTA 4
#define PGDELTA 1
#define MAXNEIGH 24
/* ---------------------------------------------------------------------- */
PairComb3::PairComb3(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
ghostneigh = 1;
nmax = 0;
NCo = NULL;
bbij = NULL;
nelements = 0;
elements = NULL;
nparams = 0;
maxparam = 0;
params = NULL;
elem2param = NULL;
intype = NULL;
afb = NULL;
dafb = NULL;
fafb = NULL;
dfafb = NULL;
ddfafb = NULL;
phin = NULL;
dphin = NULL;
erpaw = NULL;
vvdw = NULL;
vdvdw = NULL;
dpl = NULL;
xcctmp = NULL;
xchtmp = NULL;
xcotmp = NULL;
sht_num = NULL;
sht_first = NULL;
ipage = NULL;
pgsize = oneatom = 0;
cflag = 0;
// set comm size needed by this Pair
comm_forward = 1;
comm_reverse = 1;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairComb3::~PairComb3()
{
memory->destroy(NCo);
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->sfree(params);
memory->destroy(elem2param);
memory->destroy(afb);
memory->destroy(dpl);
memory->destroy(dafb);
memory->destroy(fafb);
memory->destroy(phin);
memory->destroy(bbij);
memory->destroy(vvdw);
memory->destroy(vdvdw);
memory->destroy(dphin);
memory->destroy(erpaw);
memory->destroy(dfafb);
memory->destroy(ddfafb);
memory->destroy(xcctmp);
memory->destroy(xchtmp);
memory->destroy(xcotmp);
memory->destroy(intype);
memory->destroy(sht_num);
memory->sfree(sht_first);
delete [] ipage;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
delete [] map;
delete [] esm;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::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];
esm = new double[n];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairComb3::settings(int narg, char **arg)
{
if (strcmp(arg[0],"polar_on") == 0) {
pol_flag = 1;
if (comm->me == 0) fprintf(screen,
" PairComb3: polarization is on \n");
} else if (strcmp(arg[0],"polar_off") == 0) {
pol_flag = 0;
if (comm->me == 0) fprintf(screen,
" PairComb3: polarization is off \n");
} else {
error->all(FLERR,"Illegal pair_style command");
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairComb3::coeff(int narg, char **arg)
{
int i,j,n;
double r;
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 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],"C") == 0) && (cflag == 0)) {
if( comm->me == 0) fprintf(screen,
" PairComb3: Found C: reading additional library file \n");
read_lib();
cflag = 1;
}
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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
n = atom->ntypes;
// generate Wolf 1/r energy and van der Waals look-up tables
tables();
// clear setflag since coeff() called once with I,J = * *
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 PairComb3::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style COMB3 requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style COMB3 requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,"Pair style COMB3 requires atom attribute q");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->ghost = 1;
// local Comb 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);
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairComb3::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
cutghost[j][i] = cutghost[i][j] = cutmax;
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairComb3::read_lib()
{
unsigned int maxlib = 1024;
int i,j,k,l,n,nwords,m;
int ii,jj,kk,ll,mm,iii;
double tmp;
char s[maxlib];
char **words1 = new char*[80];
char **words2 = new char*[70];
MPI_Comm_rank(world,&comm->me);
// open libraray file on proc 0
if(comm->me == 0) {
FILE *fp = fopen("lib.comb3","r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open COMB3 C library file \n");
error->one(FLERR,str);
}
// read and store at the same time
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ccutoff[0] = atof(words1[0]);
ccutoff[1] = atof(words1[1]);
ccutoff[2] = atof(words1[2]);
ccutoff[3] = atof(words1[3]);
ccutoff[4] = atof(words1[4]);
ccutoff[5] = atof(words1[5]);
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ch_a[0] = atof(words1[0]);
ch_a[1] = atof(words1[1]);
ch_a[2] = atof(words1[2]);
ch_a[3] = atof(words1[3]);
ch_a[4] = atof(words1[4]);
ch_a[5] = atof(words1[5]);
ch_a[6] = atof(words1[6]);
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
nsplpcn = atoi(words1[0]);
nsplrad = atoi(words1[1]);
nspltor = atoi(words1[2]);
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
maxx = atoi(words1[0]);
maxy = atoi(words1[1]);
maxz = atoi(words1[2]);
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
maxxc = atoi(words1[0]);
maxyc = atoi(words1[1]);
maxconj = atoi(words1[2]);
for (l=0; l<nsplpcn; l++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
maxxcn[l] = atoi(words1[1]);
vmaxxcn[l] = atof(words1[2]);
dvmaxxcn[l] = atof(words1[3]);
}
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ntab = atoi(words1[0]);
for (i=0; i<ntab+1; i++){
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
pang[i] = atof(words1[1]);
dpang[i] = atof(words1[2]);
ddpang[i] = atof(words1[3]);
}
for (l=0; l<nsplpcn; l++)
for (i=0; i<maxx+1; i++)
for (j=0; j<maxy+1; j++)
for (k=0; k<maxz+1; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3]);
pcn_grid[ll][ii][jj][kk] = atof(words1[4]);
pcn_gridx[ll][ii][jj][kk] = atof(words1[5]);
pcn_gridy[ll][ii][jj][kk] = atof(words1[6]);
pcn_gridz[ll][ii][jj][kk] = atof(words1[7]);
}
for (l=0; l<nsplpcn; l++)
for (i=0; i<maxx; i++)
for (j=0; j<maxy; j++)
for (k=0; k<maxz; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3]);
for(iii=0; iii<2; iii++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
for(m=0; m<32 ; m++) {
mm=iii*32+m;
pcn_cubs[ll][ii][jj][kk][mm] = atof(words1[m]);
}
}
}
for (l=0; l<nsplrad; l++)
for (i=0; i<maxxc+1; i++)
for (j=0; j<maxyc+1; j++)
for (k=0; k<maxconj; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3])-1;
rad_grid[ll][ii][jj][kk] = atof(words1[4]);
rad_gridx[ll][ii][jj][kk] = atof(words1[5]);
rad_gridy[ll][ii][jj][kk] = atof(words1[6]);
rad_gridz[ll][ii][jj][kk] = atof(words1[7]);
}
for (l=0; l<nsplrad; l++)
for (i=0; i<maxxc; i++)
for (j=0; j<maxyc; j++)
for (k=0; k<maxconj-1; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3])-1;
for (iii=0; iii<2; iii++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
for(m=0; m<32 ; m++){
mm=iii*32+m;
rad_spl[ll][ii][jj][kk][mm] = atof(words1[m]);
}
}
}
for (l=0; l<nspltor; l++)
for (i=0; i<maxxc+1; i++)
for (j=0; j<maxyc+1; j++)
for (k=0; k<maxconj; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3])-1;
tor_grid[ll][ii][jj][kk] = atof(words1[4]);
tor_gridx[ll][ii][jj][kk] = atof(words1[5]);
tor_gridy[ll][ii][jj][kk] = atof(words1[6]);
tor_gridz[ll][ii][jj][kk] = atof(words1[7]);
}
for (l=0; l<nspltor; l++)
for (i=0; i<maxxc; i++)
for (j=0; j<maxyc; j++)
for (k=0; k<maxconj-1; k++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
ll = atoi(words1[0])-1;
ii = atoi(words1[1]);
jj = atoi(words1[2]);
kk = atoi(words1[3])-1;
for(iii=0; iii<2; iii++) {
fgets(s,maxlib,fp);
nwords = 0;
words1[nwords++] = strtok(s," \t\n\r\f");
while (words1[nwords++] = strtok(NULL," \t\n\r\f"))continue;
for (m=0; m<32 ; m++){
mm=iii*32+m;
tor_spl[ll][ii][jj][kk][mm] = atof(words1[m]);
}
}
}
fclose(fp);
}
k = 0;
for (i=0; i<4; i++)
for (j=0; j<4; j++) {
iin2[k][0] = i;
iin2[k][1] = j;
k ++;
}
l = 0;
for (i=0; i<4; i++)
for (j=0; j<4; j++)
for (k=0; k<4; k++) {
iin3[l][0] = i;
iin3[l][1] = j;
iin3[l][2] = k;
l ++;
}
MPI_Bcast(&ccutoff[0],6,MPI_DOUBLE,0,world);
MPI_Bcast(&ch_a[0],7,MPI_DOUBLE,0,world);
MPI_Bcast(&nsplpcn,1,MPI_INT,0,world);
MPI_Bcast(&nsplrad,1,MPI_INT,0,world);
MPI_Bcast(&nspltor,1,MPI_INT,0,world);
MPI_Bcast(&maxx,1,MPI_INT,0,world);
MPI_Bcast(&maxy,1,MPI_INT,0,world);
MPI_Bcast(&maxz,1,MPI_INT,0,world);
MPI_Bcast(&maxxc,1,MPI_INT,0,world);
MPI_Bcast(&maxyc,1,MPI_INT,0,world);
MPI_Bcast(&maxconj,1,MPI_INT,0,world);
MPI_Bcast(&maxxcn,4,MPI_INT,0,world);
MPI_Bcast(&vmaxxcn,4,MPI_DOUBLE,0,world);
MPI_Bcast(&dvmaxxcn,4,MPI_DOUBLE,0,world);
MPI_Bcast(&ntab,1,MPI_INT,0,world);
MPI_Bcast(&pang[0],20001,MPI_DOUBLE,0,world);
MPI_Bcast(&dpang[0],20001,MPI_DOUBLE,0,world);
MPI_Bcast(&ddpang[0],20001,MPI_DOUBLE,0,world);
MPI_Bcast(&pcn_grid[0][0][0][0],500,MPI_DOUBLE,0,world);
MPI_Bcast(&pcn_gridx[0][0][0][0],500,MPI_DOUBLE,0,world);
MPI_Bcast(&pcn_gridy[0][0][0][0],500,MPI_DOUBLE,0,world);
MPI_Bcast(&pcn_gridz[0][0][0][0],500,MPI_DOUBLE,0,world);
MPI_Bcast(&pcn_cubs[0][0][0][0][0],16384,MPI_DOUBLE,0,world);
MPI_Bcast(&rad_grid[0][0][0][0],825,MPI_DOUBLE,0,world);
MPI_Bcast(&rad_gridx[0][0][0][0],825,MPI_DOUBLE,0,world);
MPI_Bcast(&rad_gridy[0][0][0][0],825,MPI_DOUBLE,0,world);
MPI_Bcast(&rad_gridz[0][0][0][0],825,MPI_DOUBLE,0,world);
MPI_Bcast(&rad_spl[0][0][0][0][0],30720,MPI_DOUBLE,0,world);
MPI_Bcast(&tor_grid[0][0][0][0],275,MPI_DOUBLE,0,world);
MPI_Bcast(&tor_gridx[0][0][0][0],275,MPI_DOUBLE,0,world);
MPI_Bcast(&tor_gridy[0][0][0][0],275,MPI_DOUBLE,0,world);
MPI_Bcast(&tor_gridz[0][0][0][0],275,MPI_DOUBLE,0,world);
MPI_Bcast(&tor_spl[0][0][0][0][0],10240,MPI_DOUBLE,0,world);
MPI_Bcast(&iin2[0][0],32,MPI_INT,0,world);
MPI_Bcast(&iin3[0][0],192,MPI_INT,0,world);
}
/* ---------------------------------------------------------------------- */
void PairComb3::read_file(char *file)
{
int params_per_line = 74;
char **words = new char*[params_per_line+1];
if (params) delete [] params;
params = NULL;
nparams = 0;
// open file on proc 0
FILE *fp;
if (comm->me == 0) {
fp = fopen(file,"r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open COMB3 potential file %s",file);
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 n,nwords,ielement,jelement,kelement;
char line[MAXLINE],*ptr;
int eof = 0;
nwords=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,"Incorrect format in COMB3 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next line
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].ielementgp = atoi(words[3]);
params[nparams].jelementgp = atoi(words[4]);
params[nparams].kelementgp = atoi(words[5]);
params[nparams].ang_flag = atoi(words[6]);
params[nparams].pcn_flag = atoi(words[7]);
params[nparams].rad_flag = atoi(words[8]);
params[nparams].tor_flag = atoi(words[9]);
params[nparams].vdwflag = atof(words[10]);
params[nparams].powerm = atof(words[11]);
params[nparams].veps = atof(words[12]);
params[nparams].vsig = atof(words[13]);
params[nparams].paaa = atof(words[14]);
params[nparams].pbbb = atof(words[15]);
params[nparams].lami = atof(words[16]);
params[nparams].alfi = atof(words[17]);
params[nparams].powern = atof(words[18]);
params[nparams].QL = atof(words[19]);
params[nparams].QU = atof(words[20]);
params[nparams].DL = atof(words[21]);
params[nparams].DU = atof(words[22]);
params[nparams].qmin = atof(words[23]);
params[nparams].qmax = atof(words[24]);
params[nparams].chi = atof(words[25]);
params[nparams].dj = atof(words[26]);
params[nparams].dk = atof(words[27]);
params[nparams].dl = atof(words[28]);
params[nparams].esm = atof(words[29]);
params[nparams].cmn1 = atof(words[30]);
params[nparams].cmn2 = atof(words[31]);
params[nparams].pcmn1 = atof(words[32]);
params[nparams].pcmn2 = atof(words[33]);
params[nparams].coulcut = atof(words[34]);
params[nparams].polz = atof(words[35]);
params[nparams].curl = atof(words[36]);
params[nparams].curlcut1 = atof(words[37]);
params[nparams].curlcut2 = atof(words[38]);
params[nparams].curl0 = atof(words[39]);
params[nparams].alpha1 = atof(words[40]);
params[nparams].bigB1 = atof(words[41]);
params[nparams].alpha2 = atof(words[42]);
params[nparams].bigB2 = atof(words[43]);
params[nparams].alpha3 = atof(words[44]);
params[nparams].bigB3 = atof(words[45]);
params[nparams].lambda = atof(words[46]);
params[nparams].bigA = atof(words[47]);
params[nparams].beta = atof(words[48]);
params[nparams].bigr = atof(words[49]);
params[nparams].bigd = atof(words[50]);
params[nparams].pcos6 = atof(words[51]);
params[nparams].pcos5 = atof(words[52]);
params[nparams].pcos4 = atof(words[53]);
params[nparams].pcos3 = atof(words[54]);
params[nparams].pcos2 = atof(words[55]);
params[nparams].pcos1 = atof(words[56]);
params[nparams].pcos0 = atof(words[57]);
params[nparams].pcna = atof(words[58]);
params[nparams].pcnb = atof(words[59]);
params[nparams].pcnc = atof(words[60]);
params[nparams].pcnd = atof(words[61]);
params[nparams].plp1 = atof(words[62]);
params[nparams].plp2 = atof(words[63]);
params[nparams].plp3 = atof(words[64]);
params[nparams].plp4 = atof(words[65]);
params[nparams].plp5 = atof(words[66]);
params[nparams].plp6 = atof(words[67]);
params[nparams].addrep = atof(words[68]);
params[nparams].pbb1=atof(words[69]);
params[nparams].pbb2=atof(words[70]);
params[nparams].ptork1=atof(words[71]);
params[nparams].ptork2=atof(words[72]);
params[nparams].pcross = atof(words[73]);
params[nparams].powermint = int(params[nparams].powerm);
// parameter sanity checks
if (params[nparams].lambda < 0.0 || params[nparams].powern < 0.0 ||
params[nparams].beta < 0.0 || params[nparams].alpha1 < 0.0 ||
params[nparams].bigB1< 0.0 || params[nparams].bigA< 0.0 ||
params[nparams].bigB2< 0.0 || params[nparams].alpha2 <0.0 ||
params[nparams].bigB3< 0.0 || params[nparams].alpha3 <0.0 ||
params[nparams].bigr < 0.0 || params[nparams].bigd < 0.0 ||
params[nparams].bigd > params[nparams].bigr ||
params[nparams].powerm - params[nparams].powermint != 0.0 ||
params[nparams].addrep < 0.0 || params[nparams].powermint < 1.0 ||
params[nparams].QL > 0.0 || params[nparams].QU < 0.0 ||
params[nparams].DL < 0.0 || params[nparams].DU > 0.0 ||
params[nparams].pcross < 0.0 ||
params[nparams].esm < 0.0 || params[nparams].veps < 0.0 ||
params[nparams].vsig < 0.0 || params[nparams].vdwflag < 0.0
)
error->all(FLERR,"Illegal COMB3 parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairComb3::setup()
{
int i,j,k,m,n;
// set elem2param for all element triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// compute parameter values derived from inputs
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].bigr + params[m].bigd;
params[m].cutsq = params[m].cut*params[m].cut;
params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern);
params[m].c2 = pow(2.0*params[m].powern*1.00e-8,-1.0/params[m].powern);
params[m].c3 = 1.0/params[m].c2;
params[m].c4 = 1.0/params[m].c1;
params[m].Qo = (params[m].QU+params[m].QL)/2.0; // (A22)
params[m].dQ = (params[m].QU-params[m].QL)/2.0; // (A21)
params[m].aB = 1.0 /
(1.0-pow(fabs(params[m].Qo/params[m].dQ),10)); // (A20)
params[m].bB = pow(fabs(params[m].aB),0.1)/params[m].dQ; // (A19)
params[m].nD = log(params[m].DU/(params[m].DU-params[m].DL))/
log(params[m].QU/(params[m].QU-params[m].QL));
params[m].bD = (pow((params[m].DL-params[m].DU),(1.0/params[m].nD)))/
(params[m].QU-params[m].QL);
params[m].lcut = params[m].coulcut;
params[m].lcutsq = params[m].lcut*params[m].lcut;
}
// set cutmax to max of all params
cutmin = cutmax = 0.0;
polar = 0;
for (m = 0; m < nparams; m++) {
if (params[m].cutsq > cutmin) cutmin = params[m].cutsq + 2.0;
if (params[m].lcut > cutmax) cutmax = params[m].lcut;
}
chicut1 = 7.0;
chicut2 = cutmax;
}
/* ---------------------------------------------------------------------- */
void PairComb3::Short_neigh()
{
int n,nj,*neighptrj,icontrol;
int iparam_ij,iparam_ji,iparam_jk,*ilist,*jlist,*numneigh,**firstneigh;
int inum,jnum,i,j,k,l,ii,jj,kk,ll,itype,jtype,ktype,ltype;
- int itag, jtag;
+ tagint itag,jtag;
double rr1,rr2,rsq1,rsq2,delrj[3],delrk[3];
int sht_knum,*sht_klist;
double **x = atom->x;
- int *tag = atom->tag;
int *type = atom->type;
int ntype = atom->ntypes;
int nlocal = atom->nlocal;
int *klist,knum;
if (atom->nmax > nmax) {
memory->sfree(sht_first);
nmax = atom->nmax;
sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
"pair:sht_first");
memory->grow(dpl,nmax,3,"pair:dpl");
memory->grow(xcctmp,nmax,"pair:xcctmp");
memory->grow(xchtmp,nmax,"pair:xchtmp");
memory->grow(xcotmp,nmax,"pair:xcotmp");
memory->grow(NCo,nmax,"pair:NCo");
memory->grow(sht_num,nmax,"pair:sht_num");
memory->grow(bbij,nmax,MAXNEIGH,"pair:bbij");
}
inum = list->inum + list->gnum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// create COMB neighbor list
ipage->reset();
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
- itag = tag[i];
dpl[i][0] = dpl[i][1] = dpl[i][2] = 0.0;
nj = 0;
neighptrj = ipage->vget();
itype = map[type[i]];
jlist = firstneigh[i];
jnum = numneigh[i];
NCo[i] = 0.0;
xcctmp[i] = 0.0;
xchtmp[i] = 0.0;
xcotmp[i] = 0.0;
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
- jtag = tag[j];
delrj[0] = x[i][0] - x[j][0];
delrj[1] = x[i][1] - x[j][1];
delrj[2] = x[i][2] - x[j][2];
rsq1 = vec3_dot(delrj,delrj);
jtype = map[type[j]];
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
if (rsq1 > cutmin) continue;
neighptrj[nj++] = j;
rr1 = sqrt(rsq1);
NCo[i] += comb_fc(rr1,&params[iparam_ij]) * params[iparam_ij].pcross;
icontrol = params[iparam_ij].jelementgp;
if( icontrol == 1)
xcctmp[i] += comb_fc(rr1,&params[iparam_ij]) * params[iparam_ij].pcross;
if (icontrol == 2)
xchtmp[i] += comb_fc(rr1,&params[iparam_ij]) * params[iparam_ij].pcross;
if (icontrol == 3)
xcotmp[i] += comb_fc(rr1,&params[iparam_ij]) * params[iparam_ij].pcross;
}
sht_first[i] = neighptrj;
sht_num[i] = nj;
ipage->vgot(nj);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
// communicating coordination number to all nodes
pack_flag = 2;
comm->forward_comm_pair(this);
}
/* ---------------------------------------------------------------------- */
void PairComb3::compute(int eflag, int vflag)
{
- int i,ii,k,kk,j,jj,im,inum,jnum,itag,jtag,itype,jtype,ktype;
+ int i,ii,k,kk,j,jj,im,inum,jnum,itype,jtype,ktype;
int iparam_i,iparam_ij,iparam_ji;
int iparam_ijk,iparam_jik,iparam_ikj,iparam_jli,iparam_jki,iparam_ikl;
int sht_jnum,*sht_jlist,sht_lnum,*sht_llist;
int sht_mnum,*sht_mlist,sht_pnum,*sht_plist;
int *ilist,*jlist,*numneigh,**firstneigh,mr1,mr2,mr3,inty,nj;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair;
double rr,rsq,rsq1,rsq2,rsq3,iq,jq,yaself;
double fqi,fqij,eng_tmp,vionij,fvionij,sr1,sr2,sr3;
double zeta_ij,prefac_ij1,prefac_ij2,prefac_ij3,prefac_ij4,prefac_ij5;
double zeta_ji,prefac_ji1,prefac_ji2,prefac_ji3,prefac_ji4,prefac_ji5;
double delrj[3],delrk[3],delri[3],fi[3],fj[3],fk[3],fl[3];
double elp_ij,elp_ji,filp[3],fjlp[3],fklp[3],fllp[3];
double potal,fac11,fac11e;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
int ntype = atom->ntypes;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
// coordination terms
int n;
double xcn, ycn, xcccnij, xchcnij, xcocnij;
double kcn, lcn;
int torindx;
// torsion and radical variables
int l, ll, ltype, m, mm, mtype, p, pp, ptype;
int iparam_jil, iparam_ijl, iparam_ki, iparam_lj,iparam_jk;
int iparam_jl, iparam_ik, iparam_km, iparam_lp;
double kconjug, lconjug, kradtot, lradtot;
double delrl[3], delrm[3], delrp[3], ddprx[3], srmu;
double zet_addi,zet_addj;
double rikinv,rjlinv,rik_hat[3],rjl_hat[3];
evdwl = ecoul = eng_tmp = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = vflag_atom = 0;
// Build short range neighbor list
Short_neigh();
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
yaself = vionij = fvionij = fpair = 0.0;
// self energy correction term: potal
potal_calc(potal,fac11,fac11e);
// generate initial dipole tensor
if (pol_flag )
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
itype = map[type[i]];
iq = q[i];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[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] < x[i][2]) 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]];
jq = q[j];
delrj[0] = x[j][0] - x[i][0];
delrj[1] = x[j][1] - x[i][1];
delrj[2] = x[j][2] - x[i][2];
rsq = vec3_dot(delrj,delrj);
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
if (rsq > params[iparam_ij].lcutsq) continue;
tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3);
dipole_init(&params[iparam_ij],&params[iparam_ji],fac11,delrj
,rsq,mr1,mr2,mr3,sr1,sr2,sr3,iq,jq,i,j);
}
}
// loop over full neighbor list of my atoms
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];
iq = q[i];
nj = 0;
iparam_i = elem2param[itype][itype][itype];
// self energy, only on i atom
yaself = self(&params[iparam_i],iq);
// dipole self energy
if (pol_flag)
yaself += dipole_self(&params[iparam_i],i);
if (evflag) ev_tally(i,i,nlocal,0,0.0,yaself,0.0,0.0,0.0,0.0);
// two-body interactions (long:R + A, short: only R)
jlist = firstneigh[i];
jnum = numneigh[i];
sht_jlist = sht_first[i];
sht_jnum = sht_num[i];
// long range interactions
for (jj = 0; jj < jnum; jj++) {
j = jlist[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] < x[i][2]) 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]];
jq = q[j];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
if (rsq > params[iparam_ij].lcutsq) continue;
inty = intype[itype][jtype];
// three-point interpolation
tri_point(rsq, mr1, mr2, mr3, sr1, sr2, sr3);
// Q-indenpendent: van der Waals
vdwaals(inty,mr1,mr2,mr3,rsq,sr1,sr2,sr3,eng_tmp,fpair);
evdwl = eng_tmp;
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 (evflag)
ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz);
// Q-dependent: Coulombic, field, polarization
// 1/r energy and forces
direct(&params[iparam_ij], &params[iparam_ji],
mr1, mr2, mr3, rsq, sr1, sr2, sr3, iq, jq,
fac11, fac11e, eng_tmp, fvionij, i, j);
vionij = eng_tmp;
// field correction to self energy
field(&params[iparam_ij], &params[iparam_ji],rsq,iq,jq,
eng_tmp,fvionij);
vionij += eng_tmp;
// sums up long range Q-dependent forces (excluding dipole)
f[i][0] += delx*fvionij;
f[i][1] += dely*fvionij;
f[i][2] += delz*fvionij;
f[j][0] -= delx*fvionij;
f[j][1] -= dely*fvionij;
f[j][2] -= delz*fvionij;
// sums up long range Q-dependent energies (excluding dipole)
if (evflag)
ev_tally(i,j,nlocal,newton_pair,0.0,vionij,fvionij,delx,dely,delz);
// polarization field
if (pol_flag) {
dipole_calc(&params[iparam_ij], &params[iparam_ji],fac11,
delx,dely,delz,rsq,mr1,mr2,mr3,
sr1,sr2,sr3,iq,jq,i,j,eng_tmp,fvionij,ddprx);
vionij = eng_tmp;
// sums up dipole energies
if (evflag)
ev_tally(i,j,nlocal,newton_pair,0.0,vionij,fvionij,delx,dely,delz);
// sums up dipole forces
f[i][0] += (ddprx[0] + delx*fvionij);
f[i][1] += (ddprx[1] + dely*fvionij);
f[i][2] += (ddprx[2] + delz*fvionij);
f[j][0] -= (ddprx[0] + delx*fvionij);
f[j][1] -= (ddprx[1] + dely*fvionij);
f[j][2] -= (ddprx[2] + delz*fvionij);
}
if (rsq > params[iparam_ij].cutsq) continue;
repulsive(&params[iparam_ij], &params[iparam_ji], rsq,
fpair, eflag, eng_tmp, iq, jq);
evdwl = eng_tmp;
// repulsion is pure two-body, sums up pair repulsive forces
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 (evflag)
ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,fpair,delx,dely,delz);
}
// many-body interactions: start of short-range
xcn = NCo[i];
for (jj = 0; jj < sht_jnum; jj++) {
j = sht_jlist[jj];
sht_llist = sht_first[j];
sht_lnum = sht_num[j];
jtag = tag[j];
if ( jtag <= itag ) continue ;
ycn = NCo[j];
jtype = map[type[j]];
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
delrj[0] = x[j][0] - xtmp;
delrj[1] = x[j][1] - ytmp;
delrj[2] = x[j][2] - ztmp;
rsq1 = vec3_dot(delrj,delrj);
if (rsq1 > params[iparam_ij].cutsq) continue;
nj ++;
// this Qj for q-dependent BSi
jq = q[j];
// accumulate bondorder zeta for each i-j interaction via k and l loops
zeta_ij = 0.0;
bbtor = 0.0;
kconjug = 0.0;
for (kk = 0; kk < sht_jnum; kk++) { // kk is neighbor of ii
k = sht_jlist[kk];
if (j == k) continue;
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
iparam_ikj = elem2param[itype][ktype][jtype];
iparam_jik = elem2param[jtype][itype][ktype];
iparam_ik = elem2param[itype][ktype][ktype];
delrk[0] = x[k][0] - xtmp;
delrk[1] = x[k][1] - ytmp;
delrk[2] = x[k][2] - ztmp;
rsq2 = vec3_dot(delrk,delrk);
if (rsq2 > params[iparam_ik].cutsq) continue;
// 3-body zeta in bond order
zeta_ij += zeta(&params[iparam_ijk], &params[iparam_ik],
rsq1, rsq2, delrj, delrk, i, xcn);
// radical initialization: apply only to CC,CO,OC bonds
if (params[iparam_ij].rad_flag > 0 &&
params[iparam_ik].ielementgp == 1 &&
params[iparam_ik].jelementgp == 1) {
iparam_ki = elem2param[ktype][itype][itype];
kcn=NCo[k];
kconjug += rad_init(rsq2,&params[iparam_ki],i,kradtot,kcn);
}
// torsion: i-j-k-l: apply to all C-C bonds
if( params[iparam_ij].tor_flag != 0 ) {
srmu = vec3_dot(delrj,delrk)/(sqrt(rsq1*rsq2));
srmu = sqrt(1.0-srmu*srmu);
if(srmu > 0.1) {
for (ll = 0; ll < sht_lnum; ll++) { // ll is neighbor of jj
l = sht_llist[ll];
if(l==i || l==j || l==k) continue;
ltype = map[type[l]];
delrl[0] = x[l][0] - x[j][0];
delrl[1] = x[l][1] - x[j][1];
delrl[2] = x[l][2] - x[j][2];
rsq3 = vec3_dot(delrl,delrl);
iparam_jl = elem2param[jtype][ltype][ltype];
if (rsq3 > params[iparam_jl].cutsq) continue;
iparam_ikl = elem2param[itype][ktype][ltype];
torindx = params[iparam_ij].tor_flag;
bbtor += bbtor1(torindx, &params[iparam_ikl],&params[iparam_jl],
rsq1,rsq2,rsq3,delrj,delrk,delrl,srmu);
}
}
}
}
zeta_ji = 0.0;
lconjug = 0.0;
for (ll = 0; ll < sht_lnum; ll++) {
l = sht_llist[ll];
if (l == i) continue;
ltype = map[type[l]];
iparam_jil = elem2param[jtype][itype][ltype];
iparam_ijl = elem2param[itype][jtype][ltype];
iparam_jl = elem2param[jtype][ltype][ltype];
iparam_lj = elem2param[ltype][jtype][jtype];
delrk[0] = x[l][0] - x[j][0];
delrk[1] = x[l][1] - x[j][1];
delrk[2] = x[l][2] - x[j][2];
rsq2 = vec3_dot(delrk,delrk);
delrl[0] = x[l][0] - x[j][0];
delrl[1] = x[l][1] - x[j][1];
delrl[2] = x[l][2] - x[j][2];
rsq2 = vec3_dot(delrl,delrl);
if (rsq2 > params[iparam_jl].cutsq) continue;
vec3_scale(-1,delrj,delrl); // ji_hat is -(ij_hat)
zeta_ji += zeta(&params[iparam_jil], &params[iparam_jl]
, rsq1, rsq2, delrl, delrk, j, ycn);
// radical initialization: apply only to CC,CO,OC bonds
if(params[iparam_ji].rad_flag > 0
&& params[iparam_jl].ielementgp == 1
&& params[iparam_jl].jelementgp == 1) {
iparam_lj = elem2param[ltype][jtype][jtype];
lcn=NCo[l];
lconjug += rad_init(rsq2,&params[iparam_lj],j,lradtot,lcn);
}
}
force_zeta(&params[iparam_ij], &params[iparam_ji],
rsq1, xcn, ycn, zeta_ij, zeta_ji, fpair,
prefac_ij1, prefac_ij2, prefac_ij3, prefac_ij4, prefac_ij5,
prefac_ji1, prefac_ji2, prefac_ji3, prefac_ji4, prefac_ji5,
eflag, eng_tmp, iq, jq, i, j, nj, bbtor, kconjug, lconjug);
evdwl = eng_tmp;
selflp(&params[iparam_ij],&params[iparam_ji],rsq1,eng_tmp,fpair);
evdwl += eng_tmp;
f[i][0] += delrj[0]*fpair;
f[i][1] += delrj[1]*fpair;
f[i][2] += delrj[2]*fpair;
f[j][0] -= delrj[0]*fpair;
f[j][1] -= delrj[1]*fpair;
f[j][2] -= delrj[2]*fpair;
if (evflag) ev_tally(i,j,nlocal,newton_pair,evdwl,0.0,-fpair,-delrj[0],-delrj[1],-delrj[2]);
// attractive term via loop over k (3-body forces: i-j-k)
zet_addi=0;
zet_addj=0;
for (kk = 0; kk < sht_jnum; kk++) {
k = sht_jlist[kk];
if (j == k) continue;
sht_mlist = sht_first[k];
sht_mnum = sht_num[k];
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
iparam_ikj = elem2param[itype][ktype][jtype];
iparam_jki = elem2param[jtype][ktype][itype];
iparam_jik = elem2param[jtype][itype][ktype];
iparam_ik = elem2param[itype][ktype][ktype];
delrk[0] = x[k][0] - xtmp;
delrk[1] = x[k][1] - ytmp;
delrk[2] = x[k][2] - ztmp;
rsq2 = vec3_dot(delrk,delrk);
if (rsq2 > params[iparam_ik].cutsq) continue;
// BO-dependent 3-body E & F
attractive(&params[iparam_ijk], &params[iparam_jik],&params[iparam_ikj],
prefac_ij1, prefac_ij2, prefac_ij3, prefac_ij4, prefac_ij5,
rsq1,rsq2,delrj,delrk,fi,fj,fk,i,xcn);
elp_ij = elp(&params[iparam_ijk],&params[iparam_ikj],rsq1,rsq2,delrj,delrk,zet_addi);
flp(&params[iparam_ijk],&params[iparam_ikj],rsq1,rsq2,delrj,delrk,filp,fjlp,fklp);
// Sums up i-j-k forces: LP contribution
for (im = 0; im < 3; im++) {
fi[im] += filp[im];
fj[im] += fjlp[im];
fk[im] += fklp[im];
}
// Sums up i-j-k forces: Tallies into global force vector
for (im = 0; im < 3; im++) {
f[i][im] += fi[im];
f[j][im] += fj[im];
f[k][im] += fk[im];
}
// torsion and radical: apply to all C-C bonds
if( params[iparam_ijk].tor_flag != 0 && fabs(ptorr)>1.0e-8) {
srmu = vec3_dot(delrj,delrk)/(sqrt(rsq1*rsq2));
srmu = sqrt(1.0-srmu*srmu);
if(srmu > 0.1) {
for (ll = 0; ll < sht_lnum; ll++) { // ll is neighbor of jj
l = sht_llist[ll];
if (l==i||l==j||l==k) continue;
ltype = map[type[l]];
delrl[0] = x[l][0] - x[j][0];
delrl[1] = x[l][1] - x[j][1];
delrl[2] = x[l][2] - x[j][2];
rsq3 = vec3_dot(delrl,delrl);
iparam_jl = elem2param[jtype][ltype][ltype];
if (rsq3 > params[iparam_jl].cutsq) continue;
iparam_ikl = elem2param[itype][ktype][ltype];
torindx = params[iparam_ij].tor_flag;
tor_force(torindx, &params[iparam_ikl], &params[iparam_jl],srmu,
rsq1,rsq2,rsq3,delrj,delrk,delrl);
for (im = 0; im < 3; im++) {
f[i][im] += fi_tor[im];
f[j][im] += fj_tor[im];
f[k][im] += fk_tor[im];
f[l][im] += fl_tor[im];
}
}
}
}
if( params[iparam_ijk].rad_flag>=1 &&
params[iparam_ijk].ielementgp==1 &&
params[iparam_ijk].kelementgp==1) {
iparam_ki = elem2param[ktype][itype][itype];
kcn=NCo[k];
double rik=sqrt(rsq2);
kradtot = -comb_fc(rik,&params[iparam_ki])*params[iparam_ki].pcross+kcn;
rad_forceik(&params[iparam_ki],rsq2,delrk,kconjug,kradtot);
for (im = 0; im < 3; im++) {
f[i][im] += fi_rad[im];
f[k][im] += fk_rad[im];
}
if (fabs(radtmp) > 1.0e-12) {
for (mm = 0; mm < sht_mnum; mm++) { // mm is neighbor of kk
m = sht_mlist[mm];
if (m == k) continue;
mtype = map[type[m]];
delrm[0] = x[m][0] - x[k][0];
delrm[1] = x[m][1] - x[k][1];
delrm[2] = x[m][2] - x[k][2];
rsq3 = vec3_dot(delrm,delrm);
iparam_km = elem2param[ktype][mtype][mtype];
iparam_ki = elem2param[ktype][itype][itype];
if (rsq3 > params[iparam_km].cutsq) continue;
rad_force(&params[iparam_km],rsq3,delrm,radtmp);
for (im = 0; im < 3; im++) {
f[k][im] += fj_rad[im];
f[m][im] += fk_rad[im];
}
}
}
}
if (evflag)
ev_tally(i,j,nlocal,newton_pair,elp_ij,0.0,0.0,0.0,0.0,0.0);
if (vflag_atom)
v_tally3(i,j,k,fj,fk,delrj,delrk);
} // k-loop
// attractive term via loop over l (3-body forces: j-i-l)
for (ll = 0; ll < sht_lnum; ll++) {
l = sht_llist[ll];
if (l == i) continue;
sht_plist = sht_first[l];
sht_pnum = sht_num[l];
ltype = map[type[l]];
iparam_jil = elem2param[jtype][itype][ltype];
iparam_jli = elem2param[jtype][ltype][itype];
iparam_ijl = elem2param[itype][jtype][ltype];
iparam_jl = elem2param[jtype][ltype][ltype];
delrk[0] = x[l][0] - x[j][0];
delrk[1] = x[l][1] - x[j][1];
delrk[2] = x[l][2] - x[j][2];
delri[0] = x[i][0] - x[j][0];
delri[1] = x[i][1] - x[j][1];
delri[2] = x[i][2] - x[j][2];
rsq2 = vec3_dot(delrk,delrk);
if (rsq2 > params[iparam_jl].cutsq) continue;
vec3_scale(-1,delrj,delrl);
attractive(&params[iparam_jil],&params[iparam_ijl],&params[iparam_jli],
prefac_ji1,prefac_ji2,prefac_ji3,prefac_ji4,prefac_ji5,
rsq1,rsq2,delrl,delrk,fj,fi,fl,j,ycn);
// BO-independent 3-body j-i-l LP and BB correction and forces
elp_ji = elp(&params[iparam_jil],&params[iparam_jli],rsq1,rsq2,delrl,delrk,zet_addj);
flp(&params[iparam_jil],&params[iparam_jli],rsq1,rsq2,delrl,delrk,fjlp,filp,fllp);
if (evflag)
ev_tally(j,i,nlocal,newton_pair,elp_ji,0.0,0.0,0.0,0.0,0.0);
// BO-dependent 3-body E & F
for (im = 0; im < 3; im++) {
fj[im] += fjlp[im];
fi[im] += filp[im];
fl[im] += fllp[im];
}
// Sums up j-i-l forces: Tallies into global force vector
for (im = 0; im < 3; im++) {
f[j][im] += fj[im];
f[i][im] += fi[im];
f[l][im] += fl[im];
}
// radical i-j-l-p: apply to all CC,CO,OC bonds
if( params[iparam_jil].rad_flag >= 1 &&
params[iparam_jil].ielementgp == 1 &&
params[iparam_jil].kelementgp == 1 ) {
iparam_lj = elem2param[ltype][jtype][jtype];
lcn=NCo[l];
double rjl=sqrt(rsq2);
lradtot=-comb_fc(rjl,&params[iparam_lj])*params[iparam_lj].pcross +lcn;
rad_forceik(&params[iparam_lj],rsq2,delrk,lconjug,lradtot);
for (im = 0; im < 3; im++) {
f[j][im] += fi_rad[im];
f[l][im] += fk_rad[im];
}
if (fabs(radtmp)>1.0e-12) {
for (pp = 0; pp < sht_pnum; pp++) { // pp is neighbor of ll
p = sht_plist[pp];
if (p == l) continue;
ptype = map[type[p]];
delrp[0] = x[p][0] - x[l][0];
delrp[1] = x[p][1] - x[l][1];
delrp[2] = x[p][2] - x[l][2];
rsq3 = vec3_dot(delrp,delrp);
iparam_lp = elem2param[ltype][ptype][ptype];
if (rsq3 > params[iparam_lp].cutsq) continue;
vec3_scale(-1,delrj,delrj);
rad_force(&params[iparam_lp],rsq3,delrp,radtmp);
vec3_scale(-1,delrj,delrj);
for (im = 0; im < 3; im++) {
f[l][im] += fj_rad[im];
f[p][im] += fk_rad[im];
}
}
}
}
if (vflag_atom)
v_tally3(j,i,l,fi,fl,delrl,delrk);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairComb3::repulsive(Param *parami, Param *paramj, double rsq,
double &fforce,int eflag, double &eng, double iq, double jq)
{
double r,tmp_fc,tmp_fc_d,tmp_exp,Di,Dj;
double caj,vrcs,fvrcs,fforce_tmp;
double LamDiLamDj,fcdA,rlm1,bigA;
double romi = parami->addrep;
double rrcs = parami->bigr + parami->bigd;
r = sqrt(rsq);
if (r > rrcs) return ;
tmp_fc = comb_fc(r,parami);
tmp_fc_d = comb_fc_d(r,parami);
Di = parami->DU + pow(fabs(parami->bD*(parami->QU-iq)),parami->nD);
Dj = paramj->DU + pow(fabs(paramj->bD*(paramj->QU-jq)),paramj->nD);
bigA = parami->bigA;
rlm1 = parami->lambda;
fcdA = tmp_fc_d - tmp_fc * rlm1;
LamDiLamDj = exp(0.5*(parami->lami*Di+paramj->lami*Dj)-rlm1*r);
caj = bigA * LamDiLamDj;
fforce = -caj * fcdA;
// additional repulsion
vrcs = 1.0; fvrcs = 0.0;
if (romi > 0.0) {
vrcs += romi * pow((1.0-r/rrcs),2.0);
fvrcs = romi * 2.0 * (r/rrcs-1.0)/rrcs;
fforce = fforce*vrcs - caj * tmp_fc * vrcs * fvrcs;
}
fforce /= r;
// eng = repulsive energy
eng = caj * tmp_fc * vrcs;
}
/* ---------------------------------------------------------------------- */
double PairComb3::zeta(Param *parami, Param *paramj, double rsqij,
double rsqik, double *delrij, double *delrik, int i, double xcn)
{
double rij,rik,costheta,arg,ex_delr,rlm3;
rij = sqrt(rsqij);
if (rij > parami->bigr+parami->bigd) return 0.0;
rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
rlm3 = parami->beta;
arg = pow(rlm3*(rij-rik),int(parami->powermint));
if (arg > 69.0776) ex_delr = 1.e30;
else if (arg < -69.0776) ex_delr = 0.0;
else ex_delr = exp(arg);
return comb_fc(rik,paramj) * comb_gijk(costheta,parami,xcn) * ex_delr;
}
/* ---------------------------------------------------------------------- */
void PairComb3::selflp(Param *parami, Param *paramj, double rsq,
double &eng, double &force)
{
double r,comtti,comttj,fcj,fcj_d;
double lp1,lp2,lp3,lp4,lp5,lp6;
r=sqrt(rsq);
fcj=comb_fc(r,parami);
fcj_d=comb_fc_d(r,parami);
comtti = comttj = 0.0;
if (fabs(parami->plp1) > 1.0e-6 || fabs(parami->plp2) > 1.0e-6
|| fabs(parami->plp3) > 1.0e-6 || fabs(parami->plp4) > 1.0e-6
|| fabs(parami->plp5) > 1.0e-6 || fabs(parami->plp6) > 1.0e-6 ) {
double pilp1 = parami->plp1, pilp2 = parami->plp2, pilp3 = parami->plp3;
double pilp4 = parami->plp4, pilp5 = parami->plp5, pilp6 = parami->plp6;
comtti = pilp1 + pilp2 + pilp3 + pilp4 + pilp5 + pilp6;
}
if (fabs(paramj->plp1) > 1.0e-6 || fabs(paramj->plp2) > 1.0e-6
|| fabs(paramj->plp3) > 1.0e-6 || fabs(paramj->plp4) > 1.0e-6
|| fabs(paramj->plp5) > 1.0e-6 || fabs(paramj->plp6) > 1.0e-6) {
double pjlp1 = paramj->plp1, pjlp2 = paramj->plp2, pjlp3 = paramj->plp3;
double pjlp4 = paramj->plp4, pjlp5 = paramj->plp5, pjlp6 = paramj->plp6;
comttj = pjlp1 + pjlp2 + pjlp3 + pjlp4 + pjlp5 + pjlp6;
}
eng = 0.5 * fcj * (comtti + comttj);
force += 0.5 * fcj_d * (comtti + comttj)/r;
}
/* ---------------------------------------------------------------------- */
double PairComb3::elp(Param *paramj, Param *paramk, double rsqij, double rsqik,
double *delrij, double *delrik , double &zet_add)
{
int con_flag, plp_flag;
con_flag = plp_flag = 0;
if (fabs(paramj->pbb2) > 1.0e-6) con_flag = 1;
if (fabs(paramj->plp1) > 1.0e-6 || fabs(paramj->plp2) > 1.0e-6
|| fabs(paramj->plp3) > 1.0e-6 || fabs(paramj->plp4) > 1.0e-6
|| fabs(paramj->plp5) > 1.0e-6 || fabs(paramj->plp6) > 1.0e-6 )
plp_flag = 1;
if(con_flag || plp_flag) {
double rij,rik,costheta,lp1,lp2,lp3,lp4,lp5,lp6;
double rmu,rmu2,rmu3,rmu4,rmu5,rmu6,comtt,fcj,fck,fcj_d;
double pplp1 = paramj->plp1, pplp2 = paramj->plp2, pplp3 = paramj->plp3;
double pplp4 = paramj->plp4, pplp5 = paramj->plp5, pplp6 = paramj->plp6;
rij = sqrt(rsqij);
rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
fcj = comb_fc(rij,paramj);
fcj_d = comb_fc_d(rij,paramj);
fck = comb_fc(rik,paramk);
rmu = costheta;
// Legendre Polynomial functions
if (plp_flag) {
rmu2 = rmu *rmu; rmu3 = rmu2*rmu; rmu4 = rmu3*rmu;
rmu5 = rmu4*rmu; rmu6 = rmu5*rmu;
lp1 = pplp1*rmu;
lp2 = pplp2*0.5*(3.0*rmu2-1.0);
lp3 = pplp3*0.5*(5.0*rmu3-3.0*rmu);
lp4 = pplp4*(35.0*rmu4-30.0*rmu2+3.0)/8.0;
lp5 = pplp5*(63.0*rmu5-70.0*rmu3+15.0*rmu)/8.0;
lp6 = pplp6*(231.0*rmu6-315.0*rmu4+105.0*rmu2-5.0)/16.0;
comtt = lp1 + lp2 + lp3 + lp4 + lp5 + lp6;
}
else {comtt = 0.0;}
// bond-bending terms
if (con_flag) {
double c123 = paramj->pbb1;
comtt += paramj->pbb2 *(rmu-c123)*(rmu-c123);
}
return 0.5 * fck * comtt *fcj;
}
return 0.0;
}
/*---------------------------------------------------------------------- */
void PairComb3::flp(Param *paramij,Param *paramik, double rsqij, double rsqik,
double *delrij, double *delrik, double *drilp,
double *drjlp, double *drklp)
{
int con_flag, plp_flag;
double ffj1,ffj2,ffk1,ffk2,com5k;
con_flag = plp_flag = 0;
ffj1 = 0.0; ffj2 = 0.0; ffk1 = 0.0; ffk2 = 0.0;
if (fabs(paramij->pbb2) > 1.0e-6) con_flag = 1;
if (fabs(paramij->plp1) > 1.0e-6 || fabs(paramij->plp2) > 1.0e-6
|| fabs(paramij->plp3) > 1.0e-6 || fabs(paramij->plp4) > 1.0e-6
|| fabs(paramij->plp5) > 1.0e-6 || fabs(paramij->plp6) > 1.0e-6 )
plp_flag=1;
if(con_flag || plp_flag) {
double rij,rik,costheta;
double rmu,comtt,comtt_d,com4k,com5,fcj,fcj_d,fck,fck_d;
rij = sqrt(rsqij); rik = sqrt(rsqik);
costheta = vec3_dot(delrij,delrik) / (rij*rik);
fcj = comb_fc(rij,paramij);
fck = comb_fc(rik,paramik);
fcj_d = comb_fc_d(rij,paramij);
fck_d = comb_fc_d(rik,paramik);
rmu = costheta;
// Legendre Polynomial functions and derivatives
if (plp_flag) {
double lp1,lp2,lp3,lp4,lp5,lp6;
double lp1_d,lp2_d,lp3_d,lp4_d,lp5_d,lp6_d;
double rmu2, rmu3, rmu4, rmu5, rmu6;
double pplp1 = paramij->plp1, pplp2 = paramij->plp2, pplp3 = paramij->plp3;
double pplp4 = paramij->plp4, pplp5 = paramij->plp5, pplp6 = paramij->plp6;
rmu2 = rmu *rmu; rmu3 = rmu2*rmu;
rmu4 = rmu3*rmu; rmu5 = rmu4*rmu; rmu6 = rmu5*rmu;
lp1 = pplp1*rmu;
lp2 = pplp2*0.5*(3.0*rmu2-1.0);
lp3 = pplp3*0.5*(5.0*rmu3-3.0*rmu);
lp4 = pplp4*(35.0*rmu4-30.0*rmu2+3.0)/8.0;
lp5 = pplp5*(63.0*rmu5-70.0*rmu3+15.0*rmu)/8.0;
lp6 = pplp6*(231.0*rmu6-315.0*rmu4+105.0*rmu2-5.0)/16.0;
lp1_d = pplp1;
lp2_d = pplp2*3.0*rmu;
lp3_d = pplp3*(7.5*rmu2-1.5);
lp4_d = pplp4*(140.0*rmu3-60.0*rmu)/8.0;
lp5_d = pplp5*(315.0*rmu4-210.0*rmu2+15.0)/8.0;
lp6_d = pplp6*(1386.0*rmu5-1260.0*rmu3+210.0)/16.0;
comtt = lp1 + lp2 + lp3 + lp4 + lp5 + lp6;
comtt_d = lp1_d + lp2_d + lp3_d + lp4_d + lp5_d + lp6_d;
} else {
comtt = 0.0;
comtt_d = 0.0;
}
// bond-bending terms derivatives
if (con_flag) {
double c123 = paramij->pbb1;
comtt += paramij->pbb2 *(rmu-c123)*(rmu-c123);
comtt_d += 2.0*paramij->pbb2*(rmu-c123);
}
com4k = fcj * fck_d * comtt;
com5 = fcj * fck * comtt_d;
com5k = fck * comtt * fcj_d;
ffj1 = 0.5*(-com5/(rij*rik));
ffj2 = 0.5*(com5*rmu/rsqij-com5k/rij);
ffk1 = ffj1;
ffk2 = 0.5*(-com4k/rik+com5*rmu/rsqik);
} else {
ffj1 = 0.0; ffj2 = 0.0;
ffk1 = 0.0; ffk2 = 0.0;
}
// j-atom
vec3_scale(ffj1,delrik,drjlp);
vec3_scaleadd(ffj2,delrij,drjlp,drjlp);
// k-atom
vec3_scale(ffk1,delrij,drklp);
vec3_scaleadd(ffk2,delrik,drklp,drklp);
// i-atom
vec3_add(drjlp,drklp,drilp);
vec3_scale(-1.0,drilp,drilp);
}
/* ---------------------------------------------------------------------- */
void PairComb3::force_zeta(Param *parami, Param *paramj, double rsq,
double xcn, double ycn, double &zeta_ij, double &zeta_ji, double &fforce,
double &prefac_ij1, double &prefac_ij2, double &prefac_ij3,
double &prefac_ij4, double &prefac_ij5,
double &prefac_ji1, double &prefac_ji2, double &prefac_ji3,
double &prefac_ji4, double &prefac_ji5,
int eflag, double &eng, double iq, double jq,
int i, int j, int nj, double bbtor, double kconjug, double lconjug)
{
double r,att_eng,att_force,bij; // att_eng is -cbj
double boij, dbij1, dbij2, dbij3, dbij4, dbij5;
double boji, dbji1, dbji2, dbji3, dbji4, dbji5;
double pradx, prady;
+
int inti=parami->ielement;
int intj=paramj->ielement;
- int *tag=atom->tag;
- int itag=tag[i];
- int jtag=tag[j];
+ tagint *tag=atom->tag;
+ tagint itag=tag[i];
+ tagint jtag=tag[j];
r = sqrt(rsq);
if (r > parami->bigr + parami->bigd) return;
comb_fa(r, parami, paramj, iq, jq, att_eng, att_force);
comb_bij_d(zeta_ij,parami,r,i,boij,dbij1,dbij2,dbij3,dbij4,dbij5,xcn);
comb_bij_d(zeta_ji,paramj,r,j,boji,dbji1,dbji2,dbji3,dbji4,dbji5,ycn);
bij = 0.5*(boij + boji);
// radical energy
if ( parami->rad_flag>0 ) {
rad_calc( r, parami, paramj, kconjug, lconjug, i, j, xcn, ycn);
bij += brad[0];
pradx = brad[1]*att_eng;
prady = brad[2]*att_eng;
brad[3] = 1.0 * brad[3]*att_eng;
}
// torsion energy
if ( parami->tor_flag!=0) {
tor_calc( r, parami, paramj, kconjug, lconjug, i, j, xcn, ycn);
bij += btor[0] * bbtor;
ptorr = att_eng * btor[0];
pradx += 1.0 * btor[1] * bbtor * att_eng;
prady += 1.0 * btor[2] * bbtor * att_eng;
brad[3]+= 1.0 * btor[3] * bbtor * att_eng;
}
fforce = 1.0*bij*att_force/r; // divide by r will done compute
bbij[i][nj] = bij;
prefac_ij1 = -0.5*att_eng*dbij1; // prefac_ij1 = -pfij
prefac_ij2 = -0.5*att_eng*dbij2; // prefac_ij2 = -pfij1
prefac_ij3 = -0.5*att_eng*dbij3; // prefac_ij3 = -pfij2
prefac_ij4 = -0.5*att_eng*dbij4; // prefac_ij4 = -pfij3
prefac_ij5 = -0.5*att_eng*dbij5; // prefac_ij5 = -pfij4
prefac_ji1 = -0.5*att_eng*dbji1; // prefac_ji1 = -pfji
prefac_ji2 = -0.5*att_eng*dbji2; // prefac_ji2 = -pfji1
prefac_ji3 = -0.5*att_eng*dbji3; // prefac_ji3 = -pfji2
prefac_ji4 = -0.5*att_eng*dbji4; // prefac_ji4 = -pfji3
prefac_ji5 = -0.5*att_eng*dbji5; // prefac_ji5 = -pfji4
// combines com6 & com7 below
if ( parami->rad_flag>0 || parami->tor_flag!=0 ) {
prefac_ij2-=pradx;
prefac_ji2-=prady;
}
// eng = attraction energy
if (eflag) eng = 1.0*bij*att_eng;
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fc(double r, Param *param)
{
double r_inn = param->bigr - param->bigd;
double r_out = param->bigr + param->bigd;
if (r <= r_inn) return 1.0;
if (r >= r_out) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(r-r_inn)/(r_out-r_inn)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fc_d(double r, Param *param)
{
double r_inn = param->bigr - param->bigd;
double r_out = param->bigr + param->bigd;
if (r <= r_inn) return 0.0;
if (r >= r_out) return 0.0;
return -MY_PI2/(r_out-r_inn)*sin(MY_PI*(r-r_inn)/(r_out-r_inn));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fccc(double xcn)
{
double cut1 = ccutoff[0];
double cut2 = ccutoff[1];
if (xcn <= cut1) return 1.0;
if (xcn >= cut2) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(xcn-cut1)/(cut2-cut1)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fccc_d(double xcn)
{
double cut1 = ccutoff[0];
double cut2 = ccutoff[1];
if (xcn <= cut1) return 0.0;
if (xcn >= cut2) return 0.0;
return -MY_PI2/(cut2-cut1)*sin(MY_PI*(xcn-cut1)/(cut2-cut1));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fcch(double xcn)
{
double cut1 = ccutoff[2];
double cut2 = ccutoff[3];
if (xcn <= cut1) return 1.0;
if (xcn >= cut2) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(xcn-cut1)/(cut2-cut1)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fcch_d(double xcn)
{
double cut1 = ccutoff[2];
double cut2 = ccutoff[3];
if (xcn <= cut1) return 0.0;
if (xcn >= cut2) return 0.0;
return -MY_PI2/(cut2-cut1)*sin(MY_PI*(xcn-cut1)/(cut2-cut1));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fccch(double xcn)
{
double cut1 = ccutoff[4];
double cut2 = ccutoff[5];
if (xcn <= cut1) return 1.0;
if (xcn >= cut2) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(xcn-cut1)/(cut2-cut1)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fccch_d(double xcn)
{
double cut1 = ccutoff[4];
double cut2 = ccutoff[5];
if (xcn <= cut1) return 0.0;
if (xcn >= cut2) return 0.0;
return -MY_PI2/(cut2-cut1)*sin(MY_PI*(xcn-cut1)/(cut2-cut1));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fcsw(double rsq)
{
double r = sqrt(rsq);
if (r <= chicut1) return 1.0;
if (r >= chicut2) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(r-chicut1)/(chicut2-chicut1)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::self(Param *param, double qi)
{
double self_tmp, cmin, cmax, qmin, qmax;
double s1=param->chi, s2=param->dj, s3=param->dk, s4=param->dl;
self_tmp = 0.0;
qmin = param->qmin;
qmax = param->qmax;
cmin = cmax = 100.0;
self_tmp = qi*(s1+qi*(s2+qi*(s3+qi*s4)));
if (qi < qmin) self_tmp += cmin * pow((qi-qmin),4);
if (qi > qmax) self_tmp += cmax * pow((qi-qmax),4);
return self_tmp;
}
/* ---------------------------------------------------------------------- */
void PairComb3::comb_fa(double r, Param *parami, Param *paramj, double iq,
double jq, double &att_eng, double &att_force)
{
double bigB,Bsi,FBsi;
double qi,qj,Di,Dj;
double AlfDiAlfDj, YYBn, YYBj;
double rlm2 = parami->alpha1;
double alfij1= parami->alpha1;
double alfij2= parami->alpha2;
double alfij3= parami->alpha3;
double pbij1= parami->bigB1;
double pbij2= parami->bigB2;
double pbij3= parami->bigB3;
if (r > parami->bigr + parami->bigd) Bsi = 0.0;
qi = iq; qj = jq;
Di = Dj = Bsi = FBsi = bigB = 0.0;
Di = parami->DU + pow(fabs(parami->bD*(parami->QU-qi)),parami->nD);
Dj = paramj->DU + pow(fabs(paramj->bD*(paramj->QU-qj)),paramj->nD);
YYBn = (parami->aB-fabs(pow(parami->bB*(qi-parami->Qo),10)));
YYBj = (paramj->aB-fabs(pow(paramj->bB*(qj-paramj->Qo),10)));
if (YYBn*YYBj > 0.0 ) {
AlfDiAlfDj = exp(0.5*(parami->alfi*Di+paramj->alfi*Dj));
Bsi = (pbij1*exp(-alfij1*r)+pbij2*exp(-alfij2*r)+pbij3*exp(-alfij3*r))*
sqrt(YYBn*YYBj)*AlfDiAlfDj; // Bsi is cbj
att_eng = -Bsi * comb_fc(r,parami);
att_force = -(Bsi*comb_fc_d(r,parami)-comb_fc(r,parami)*sqrt(YYBn*YYBj)*
AlfDiAlfDj*(alfij1*pbij1*exp(-alfij1*r)+
alfij2*pbij2*exp(-alfij2*r)+alfij3*pbij3*exp(-alfij3*r)));
} else {
att_eng = 0.0;
att_force = 0.0;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::comb_bij_d(double zet, Param *param, double r, int i,
double &tbij, double &tbij1, double &tbij2,
double &tbij3, double &tbij4, double &tbij5, double xcn)
{
double pcorn,dpcorn,dxccij,dxchij,dxcoij;
double zeta = zet;
double zetang,tmp_tbij, pow_n;
pcorn = dpcorn = dxccij = dxchij = dxcoij = 0.0;
coord(param,r,i,pcorn,dpcorn,dxccij,dxchij,dxcoij,xcn); // coordination term
zetang=zeta;
pow_n=param->powern;
zeta = pow(zetang,pow_n)+pcorn;
tmp_tbij=pow_n*pow(zetang,(pow_n-1.0));
if ((1.0 + zeta) < 0.1 ){
zeta=0.1-1.0;
tbij = pow(1.0 + zeta, -0.5/pow_n);
tbij1=0.0;
}
else if (zeta > param->c1) {
tbij = pow(zeta,-0.5/pow_n);
tbij1 = -0.5/pow_n*pow(zeta,(-0.5/pow_n-1.0));
} else if (zeta > param->c2) {
tbij = pow(zeta,-0.5/pow_n)-0.5/pow_n*pow(zeta,(-0.5/pow_n-1.0));
tbij1 = -0.5/pow_n/zeta;
} else if (fabs(zeta) < param->c4) {
tbij = 1.0;
tbij1 = 0.0;
} else if (fabs(zeta) < param->c3) {
tbij = 1.0 - zeta/(2.0*pow_n);
tbij1 = -1/(2.0*pow_n);
} else {
tbij = pow(1.0 + zeta, -0.5/pow_n);
tbij1 = -0.5/pow_n * pow(1.0 + zeta,(-1.0-0.5/pow_n));
}
tbij2 = tbij1 * dpcorn;
tbij3 = tbij1 * dxccij;
tbij4 = tbij1 * dxchij;
tbij5 = tbij1 * dxcoij;
tbij1 = tbij1 * tmp_tbij;
}
/* ---------------------------------------------------------------------- */
void PairComb3::coord(Param *param, double r, int i,
double &pcorn, double &dpcorn, double &dxccij,
double &dxchij, double &dxcoij, double xcn)
{
int n,nn,ixmin,iymin,izmin;
double xcntot,xcccn,xchcn,xcocn;
int tri_flag= param-> pcn_flag;
int iele_gp= param->ielementgp;
int jele_gp= param->jelementgp;
int kele_gp= param->kelementgp;
double pan = param->pcna;
double pbn = param->pcnb;
double pcn = param->pcnc;
double pdn = param->pcnd;
xcccn = xchcn = xcocn = 0.0;
xcccn = xcctmp[i];
xchcn = xchtmp[i];
xcocn = xcotmp[i];
xcntot = -comb_fc(r,param)*param->pcross + xcn;
pcorn = dpcorn = dxccij = dxchij = dxcoij = 0.0;
pcorn = 0.0; dpcorn = 0.0;
if(xcntot < 0.0) xcntot = 0.0;
if (tri_flag>0) {
if(jele_gp==1) xcccn = xcccn-comb_fc(r,param)*param->pcross;
if(jele_gp==2) xchcn = xchcn-comb_fc(r,param)*param->pcross;
if(jele_gp==3) xcocn = xcocn-comb_fc(r,param)*param->pcross;
if(xcccn < 0.0) xcccn = 0.0;
if(xchcn < 0.0) xchcn = 0.0;
if(xcocn < 0.0) xcocn = 0.0;
if(xcccn > maxx) xcccn = maxx;
if(xchcn > maxy) xchcn = maxy;
if(xcocn > maxz) xcocn = maxz;
double xcntritot=xcccn+xchcn+xcocn;
if(xcntritot > maxxcn[tri_flag-1]) {
pcorn = vmaxxcn[tri_flag-1]+(xcntot-maxxcn[tri_flag-1])*dvmaxxcn[tri_flag-1];
dxccij = dxchij = dxcoij = dvmaxxcn[tri_flag-1];
}
else {
ixmin=int(xcccn+1.0e-12);
iymin=int(xchcn+1.0e-12);
izmin=int(xcocn+1.0e-12);
if (fabs(float(ixmin)-xcccn)>1.0e-8 ||
fabs(float(iymin)-xchcn)>1.0e-8 ||
fabs(float(izmin)-xcocn)>1.0e-8) {
cntri_int(tri_flag,xcccn,xchcn,xcocn,ixmin,iymin,izmin,
pcorn,dxccij,dxchij,dxcoij,param);
}
else {
pcorn = pcn_grid[tri_flag-1][ixmin][iymin][izmin];
dxccij = pcn_gridx[tri_flag-1][ixmin][iymin][izmin];
dxchij = pcn_gridy[tri_flag-1][ixmin][iymin][izmin];
dxcoij = pcn_gridz[tri_flag-1][ixmin][iymin][izmin];
}
}
} else {
pcorn = pan*xcntot+pbn*exp(pcn*xcntot)+pdn;
dpcorn = pan+pbn*pcn*exp(pcn*xcntot);
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::cntri_int(int tri_flag, double xval, double yval,
double zval, int ixmin, int iymin, int izmin, double &vval,
double &dvalx, double &dvaly, double &dvalz, Param *param)
{
int i, j, k;
double x;
vval = 0.0; dvalx = 0.0; dvaly = 0.0; dvalz = 0.0;
if(ixmin >= maxx-1) { ixmin=maxx-1; }
if(iymin >= maxy-1) { iymin=maxy-1; }
if(izmin >= maxz-1) { izmin=maxz-1; }
for (j=0; j<64; j++) {
x = pcn_cubs[tri_flag-1][ixmin][iymin][izmin][j]
*pow(xval,iin3[j][0])*pow(yval,iin3[j][1])
*pow(zval,iin3[j][2]);
vval += x;
if(xval>1.0e-8) {dvalx += x*iin3[j][0]/xval;}
if(yval>1.0e-8) {dvaly += x*iin3[j][1]/yval;}
if(zval>1.0e-8) {dvalz += x*iin3[j][2]/zval;}
}
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_gijk(double costheta, Param *param, double nco_tmp)
{
double rmu1 = costheta;
double rmu2 = rmu1*rmu1;
double rmu3 = rmu2*rmu1;
double rmu4 = rmu3*rmu1;
double rmu5 = rmu4*rmu1;
double rmu6 = rmu5*rmu1;
double co6 = param->pcos6*rmu6;
double co5 = param->pcos5*rmu5;
double co4 = param->pcos4*rmu4;
double co3 = param->pcos3*rmu3;
double co2 = param->pcos2*rmu2;
double co1 = param->pcos1*rmu1;
double co0 = param->pcos0;
double pcross = param->pcross;
double gmu;
if (param->ang_flag==1) {
double qtheta, gmu1, gmu2, rrmu, astep;
int k;
qtheta = comb_fccc(nco_tmp);
astep = 2.0/ntab;
rrmu = (rmu1+1.0)/astep;
k = int(rrmu);
gmu1 = co6+co5+co4+co3+co2+co1+co0;
gmu2 = pang[k]+(pang[k+1]-pang[k])*(rrmu-k);
gmu = gmu2+qtheta*(gmu1-gmu2);
return gmu*pcross;
} else if (param->ang_flag==2){
double qtheta, gmu1, gmu2;
double ch6 = ch_a[6]*rmu6;
double ch5 = ch_a[5]*rmu5;
double ch4 = ch_a[4]*rmu4;
double ch3 = ch_a[3]*rmu3;
double ch2 = ch_a[2]*rmu2;
double ch1 = ch_a[1]*rmu1;
double ch0 = ch_a[0];
qtheta = comb_fccch(nco_tmp);
gmu1 = co6+co5+co4+co3+co2+co1+co0;
gmu2 = ch6+ch5+ch4+ch3+ch2+ch1+ch0;
gmu = gmu2+qtheta*(gmu1-gmu2);
return gmu*pcross;
} else {
gmu = co6+co5+co4+co3+co2+co1+co0;
return gmu*pcross;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::comb_gijk_d(double costheta, Param *param, double nco_tmp,
double &gijk_d, double &com3jk)
{
double rmu1 = costheta;
double rmu2 = rmu1*rmu1;
double rmu3 = rmu2*rmu1;
double rmu4 = rmu3*rmu1;
double rmu5 = rmu4*rmu1;
double rmu6 = rmu5*rmu1;
double co6 = param->pcos6; //*rmu5*6.0;
double co5 = param->pcos5; //*rmu4*5.0;
double co4 = param->pcos4; //*rmu3*4.0;
double co3 = param->pcos3; //*rmu2*3.0;
double co2 = param->pcos2; //*rmu1*2.0;
double co1 = param->pcos1;
double co0 = param->pcos0;
double pcross = param->pcross;
gijk_d = com3jk = 0.0;
if (param->ang_flag==1) {
double qtheta, dqtheta, gmu1, gmu2, dgmu1,dgmu2, rrmu, astep;
int k;
qtheta = comb_fccc(nco_tmp);
dqtheta = comb_fccc_d(nco_tmp);
astep = 2.0/ntab;
rrmu = (rmu1+1.0)/astep;
k = int(rrmu);
gmu1 =rmu6*co6+rmu5*co5+rmu4*co4
+rmu3*co3+rmu2*co2+rmu1*co1+co0;
dgmu1 =6.0*rmu5*co6+5.0*rmu4*co5+4.0*rmu3*co4
+3.0*rmu2*co3+2.0*rmu1*co2+co1;
gmu2 = pang[k]+(pang[k+1]-pang[k])*(rrmu-k);
dgmu2 = dpang[k]+(dpang[k+1]-dpang[k])*(rrmu-k);
gijk_d = pcross*(dgmu2+qtheta*(dgmu1-dgmu2));
com3jk = dqtheta * (gmu1-gmu2);
} else if(param->ang_flag==2) {
double qtheta, dqtheta, gmu1, gmu2, dgmu1,dgmu2;
double ch6 = ch_a[6];
double ch5 = ch_a[5];
double ch4 = ch_a[4];
double ch3 = ch_a[3];
double ch2 = ch_a[2];
double ch1 = ch_a[1];
double ch0 = ch_a[0];
qtheta = comb_fccch(nco_tmp);
dqtheta = comb_fccch_d(nco_tmp);
gmu1 =rmu6*co6+rmu5*co5+rmu4*co4
+rmu3*co3+rmu2*co2+rmu1*co1+co0;
dgmu1 =6.0*rmu5*co6+5.0*rmu4*co5+4.0*rmu3*co4
+3.0*rmu2*co3+2.0*rmu1*co2+co1;
gmu2 =rmu6*ch6+rmu5*ch5+rmu4*ch4
+rmu3*ch3+rmu2*ch2+rmu1*ch1+ch0;
dgmu2 =6.0*rmu5*ch6+5.0*rmu4*ch5+4.0*rmu3*ch4
+3.0*rmu2*ch3+2.0*rmu1*ch2+ch1;
gijk_d = pcross*(dgmu2+qtheta*(dgmu1-dgmu2));
com3jk = dqtheta * (gmu1-gmu2);
} else {
gijk_d = pcross*(6.0*rmu5*co6+5.0*rmu4*co5+4.0*rmu3*co4
+3.0*rmu2*co3+2.0*rmu1*co2+co1);
com3jk = 0.0;
}
}
/*------------------------------------------------------------------------- */
void PairComb3::attractive(Param *parami, Param *paramj , Param *paramk, double prefac_ij1,
double prefac_ij2, double prefac_ij3, double prefac_ij4,
double prefac_ij5, double rsqij, double rsqik, double *delrij,
double *delrik, double *fi, double *fj,double *fk, int i, double xcn)
{
double rij_hat[3],rik_hat[3];
double rij,rijinv,rik,rikinv;
rij = sqrt(rsqij);
rijinv = 1.0/rij;
vec3_scale(rijinv,delrij,rij_hat);
rik = sqrt(rsqik);
rikinv = 1.0/rik;
vec3_scale(rikinv,delrik,rik_hat);
comb_zetaterm_d(prefac_ij1, prefac_ij2, prefac_ij3, prefac_ij4, prefac_ij5,
rij_hat, rij,rik_hat, rik, fi, fj, fk, parami, paramj, paramk,xcn);
}
/* ---------------------------------------------------------------------- */
void PairComb3::comb_zetaterm_d(double prefac_ij1, double prefac_ij2,
double prefac_ij3, double prefac_ij4, double prefac_ij5,
double *rij_hat, double rij, double *rik_hat, double rik, double *dri,
double *drj, double *drk, Param *parami, Param *paramj, Param *paramk, double xcn)
{
double gijk,gijk_d,ex_delr,ex_delr_d,fc_i,fc_k,dfc_j,dfc,cos_theta,tmp,rlm3;
double dcosdri[3],dcosdrj[3],dcosdrk[3],dfc_i,dfc_k;
double dbij1, dbij2, dbij3, dbij4, com6, com7, com3j, com3k, com3jk;
int mint = int(parami->powermint);
double pcrossi = parami->pcross;
double pcrossj = paramj->pcross;
double pcrossk = paramk->pcross;
int icontrol = parami->pcn_flag;
fc_i = comb_fc(rij,parami);
dfc_i = comb_fc_d(rij,parami);
fc_k = comb_fc(rik,paramk);
dfc_k = comb_fc_d(rik,paramk);
dfc_j = comb_fc_d(rij,paramj);
rlm3 = parami->beta;
tmp = pow(rlm3*(rij-rik),mint);
if (tmp > 69.0776) ex_delr = 1.e30;
else if (tmp < -69.0776) ex_delr = 0.0;
else ex_delr = exp(tmp);
ex_delr *= pcrossi;
cos_theta = vec3_dot(rij_hat,rik_hat);
gijk = comb_gijk(cos_theta,parami,xcn);
comb_gijk_d(cos_theta,parami,xcn,gijk_d,com3jk);
costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk);
// com6 & com7
if(icontrol > 0){
if(parami->kelementgp==1) {com6 = prefac_ij3*pcrossk*dfc_k;}
if(parami->kelementgp==2) {com6 = prefac_ij4*pcrossk*dfc_k;}
if(parami->kelementgp==3) {com6 = prefac_ij5*pcrossk*dfc_k;}
if(parami->rad_flag>=1 || parami->tor_flag!=0)
{com6+=prefac_ij2*pcrossk*dfc_k;}
} else {
com6 = prefac_ij2*pcrossi*dfc_k;
}
if (parami->ang_flag==1 || parami->ang_flag==2) {
com3j = com3jk*ex_delr*pcrossk*pcrossj*fc_k*dfc_i;
com3k = com3jk*ex_delr*pcrossk*pcrossk*fc_k*dfc_k;
} else {
com3j = 0.0;
com3k = 0.0;
}
ex_delr_d = mint*pow(rlm3,mint)*pow((rij-rik),(mint-1))*ex_delr; // com3
vec3_scale(-dfc_k*gijk*ex_delr,rik_hat,dri); // com1
vec3_scaleadd(fc_k*gijk_d*ex_delr,dcosdri,dri,dri); // com2
vec3_scaleadd(fc_k*gijk*ex_delr_d,rik_hat,dri,dri); // com3 cont'd
vec3_scaleadd(-fc_k*gijk*ex_delr_d,rij_hat,dri,dri); // com3 sums j
vec3_scaleadd(-com3k,rik_hat,dri,dri); // com3k
vec3_scaleadd(-com3j,rij_hat,dri,dri); // com3j
vec3_scale(prefac_ij1,dri,dri);
vec3_scaleadd(-com6,rik_hat,dri,dri); // com6
vec3_scale(fc_k*gijk_d*ex_delr,dcosdrj,drj); // com2
vec3_scaleadd(fc_k*gijk*ex_delr_d,rij_hat,drj,drj); // com3 cont'd
vec3_scaleadd(com3j,rij_hat,drj,drj); // com3j
vec3_scale(prefac_ij1,drj,drj);
vec3_scale(dfc_k*gijk*ex_delr,rik_hat,drk); // com1
vec3_scaleadd(fc_k*gijk_d*ex_delr,dcosdrk,drk,drk); // com2
vec3_scaleadd(-fc_k*gijk*ex_delr_d,rik_hat,drk,drk); // com3 cont'd
vec3_scaleadd(com3k,rik_hat,drk,drk); // com3k
vec3_scale(prefac_ij1,drk,drk);
vec3_scaleadd(com6,rik_hat,drk,drk); // com6
}
/* ---------------------------------------------------------------------- */
void PairComb3::costheta_d(double *rij_hat, double rij, double *rik_hat,
double rik, double *dri, double *drj, double *drk)
{
double cos_theta = vec3_dot(rij_hat,rik_hat);
vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj);
vec3_scale(1.0/rij,drj,drj);
vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk);
vec3_scale(1.0/rik,drk,drk);
vec3_add(drj,drk,dri);
vec3_scale(-1.0,dri,dri);
}
/* ---------------------------------------------------------------------- */
void PairComb3::tables()
{
int i,j,k,m, nntypes, ncoul,nnbuf, ncoul_lim, inty, itype, jtype;
int iparam_i, iparam_ij, iparam_ji, it, jt;
double r,dra,drin,drbuf,rc,z,zr,zrc,ea,eb,ea3,eb3,alf;
double exp2er,exp2ersh,fafash,dfafash,F1,dF1,ddF1,E1,E2,E3,E4;
double exp2ear,exp2ebr,exp2earsh,exp2ebrsh,fafbsh,dfafbsh;
double afbshift, dafbshift, exp2ershift;
int n = nelements;
int *type = atom->type;
int nlocal = atom->nlocal;
dra = 0.001;
drin = 0.100;
drbuf = 0.100;
nnbuf = int(drbuf/dra) +1;
rc = cutmax;
alf = 0.20;
nmax = atom->nmax;
nntypes = int((n+1)*n/2.0)+1;
ncoul = int((rc-drin)/dra)+ nnbuf;
ncoul_lim = int(ncoul * 1.20);
// allocate arrays
memory->create(intype,n,n,"pair:intype");
memory->create(erpaw,ncoul_lim,3,"pair:erpaw");
memory->create(fafb,ncoul_lim,nntypes,"pair:fafb");
memory->create(dfafb,ncoul_lim,nntypes,"pair:dfafb");
memory->create(ddfafb,ncoul_lim,nntypes,"pair:ddfafb");
memory->create(phin,ncoul_lim,nntypes,"pair:phin");
memory->create(dphin,ncoul_lim,nntypes,"pair:dphin");
memory->create(afb,ncoul_lim,nntypes,"pair:afb");
memory->create(dafb,ncoul_lim,nntypes,"pair:dafb");
memory->create(vvdw,ncoul,nntypes,"pair:vvdw");
memory->create(vdvdw,ncoul,nntypes,"pair:vdvdw");
memory->create(dpl,nmax,3,"pair:dpl");
memory->create(bbij,nmax,MAXNEIGH,"pair:bbij");
memory->create(xcctmp,nmax,"pair:xcctmp");
memory->create(xchtmp,nmax,"pair:xchtmp");
memory->create(xcotmp,nmax,"pair:xcotmp");
memory->create(NCo,nmax,"pair:NCo");
memory->create(sht_num,nmax,"pair:sht_num");
sht_first = (int **) memory->smalloc(nmax*sizeof(int *),
"pair:sht_first");
// set interaction number: 0-0=0, 1-1=1, 0-1=1-0=2
m = 0; k = n;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (j == i) {
intype[i][j] = m;
m += 1;
} else if (j != i && j > i) {
intype[i][j] = k;
k += 1;
} else if (j != i && j < i) {
intype[i][j] = intype[j][i];
}
}
}
// default arrays to zero
for (i = 0; i < ncoul; i ++) {
for (j = 0; j < nntypes; j ++) {
fafb[i][j] = 0.0;
dfafb[i][j] = 0.0;
ddfafb[i][j] = 0.0;
phin[i][j] = 0.0;
dphin[i][j] = 0.0;
afb[i][j] = 0.0;
dafb[i][j] = 0.0;
}
}
// direct 1/r energy with Slater 1S orbital overlap
for (i = 0; i < n; i++) {
r = drin - dra;
itype = i;
iparam_i = elem2param[itype][itype][itype];
z = params[iparam_i].esm;
exp2ershift = exp(-2.0*z*rc);
afbshift = -exp2ershift*(z+1.0/rc);
dafbshift = exp2ershift*(2.0*z*z+2.0*z/rc+1.0/(rc*rc));
for (j = 0; j < ncoul; j++) {
exp2er = exp(-2.0 * z * r);
phin[j][i] = 1.0 - exp2er * (1.0 + 2.0 * z * r * (1.0 + z * r));
dphin[j][i] = (4.0 * exp2er * z * z * z * r * r);
afb[j][i] = -exp2er*(z+1.0/r)-afbshift-(r-rc)*dafbshift;
dafb[j][i] = -(exp2er*(2.0*z*z+2.0*z/r+1.0/(r*r))-dafbshift);
r += dra;
}
}
for (i = 0; i < n; i ++) {
for (j = 0; j < n; j ++) {
r = drin - dra;
if (j == i) {
itype = i;
inty = intype[itype][itype];
iparam_i = elem2param[itype][itype][itype];
z = params[iparam_i].esm;
zrc = z * rc;
exp2ersh = exp(-2.0 * zrc);
fafash = -exp2ersh * (1.0 / rc +
z * (11.0/8.0 + 3.0/4.0*zrc + zrc*zrc/6.0));
dfafash = exp2ersh * (1.0/(rc*rc) + 2.0*z/rc +
z*z*(2.0 + 7.0/6.0*zrc + zrc*zrc/3.0));
for (k = 0; k < ncoul; k ++) {
zr = z * r;
exp2er = exp(-2.0*zr);
F1 = -exp2er * (1.0 / r +
z * (11.0/8.0 + 3.0/4.0*zr + zr*zr/6.0));
dF1 = exp2er * (1.0/(r*r) + 2.0*z/r +
z*z*(2.0 + 7.0/6.0*zr + zr*zr/3.0));
ddF1 = -exp2er * (2.0/(r*r*r) + 4.0*z/(r*r) + 4.0*z*z/r +
z*z*z/3.0*(17.0/2.0 + 5.0*zr + 2.0*zr*zr));
fafb[k][inty] = F1-fafash-(r-rc)*dfafash;
dfafb[k][inty] = -(dF1 - dfafash);
ddfafb[k][inty] = ddF1;
r += dra;
}
} else if (j != i) {
itype = i;
jtype = j;
inty = intype[itype][jtype];
iparam_ij = elem2param[itype][jtype][jtype];
ea = params[iparam_ij].esm;
ea3 = ea*ea*ea;
iparam_ji = elem2param[jtype][itype][itype];
eb = params[iparam_ji].esm;
eb3 = eb*eb*eb;
E1 = ea*eb3*eb/((ea+eb)*(ea+eb)*(ea-eb)*(ea-eb));
E2 = eb*ea3*ea/((ea+eb)*(ea+eb)*(eb-ea)*(eb-ea));
E3 = (3.0*ea*ea*eb3*eb-eb3*eb3) /
((ea+eb)*(ea+eb)*(ea+eb)*(ea-eb)*(ea-eb)*(ea-eb));
E4 = (3.0*eb*eb*ea3*ea-ea3*ea3) /
((ea+eb)*(ea+eb)*(ea+eb)*(eb-ea)*(eb-ea)*(eb-ea));
exp2earsh = exp(-2.0*ea*rc);
exp2ebrsh = exp(-2.0*eb*rc);
fafbsh = -exp2earsh*(E1 + E3/rc)-exp2ebrsh*(E2 + E4/rc);
dfafbsh =
exp2earsh*(2.0*ea*(E1+E3/rc)+E3/(rc*rc)) +
exp2ebrsh*(2.0*eb*(E2+E4/rc)+E4/(rc*rc));
for (k = 0; k < ncoul; k ++) {
exp2ear = exp(-2.0*ea*r);
exp2ebr = exp(-2.0*eb*r);
fafb[k][inty] =
- exp2ear*(E1+E3/r) - exp2ebr*(E2+E4/r)
- fafbsh - (r-rc) * dfafbsh;
dfafb[k][inty] = -(exp2ear*(2.0*ea*(E1+E3/r) + E3/(r*r))
+ exp2ebr*(2.0*eb*(E2+E4/r) + E4/(r*r))- dfafbsh);
ddfafb[k][inty] = -exp2ear*(4.0*ea*ea*(E1+E3/r)+4.0*ea*E3/(r*r)
+2.0*E3/(r*r*r))
-exp2ebr*(4.0*eb*eb*(E2+E4/r)+4.0*eb*E4/(r*r)
+2.0*E4/(r*r*r));
r += dra;
}
}
}
}
for (i = 0; i < ncoul_lim; i ++) {
r = dra * (i-1) + drin;
erpaw[i][0] = erfc(r*alf);
erpaw[i][1] = exp(-r*r*alf*alf);
}
// end wolf summation
// van der Waals
int ii,jj;
double **rvdw, *cc2, *cc3, *vrc, *rrc;
double r6, r7, r12, r13, rf6, rf12, drf7, drf13;
double drcc, temp6, temp7, temp12, temp13;
double vsigt, vepst, vdwt, dvdwt;
vrc = new double[13];
rrc = new double[13];
cc2 = new double[nntypes];
cc3 = new double[nntypes];
memory->create(rvdw,2,nntypes,"pair:rvdw");
vrc[0] = rc;
for (i=1; i<13; i++) {
vrc[i] = vrc[i-1] * vrc[0];
}
// generate spline coefficients for CC, CH, HH vdw
for (ii = 0; ii < n; ii ++) {
for (jj = ii; jj < n; jj ++) {
itype = ii;
jtype = jj;
inty = intype[itype][jtype];
iparam_ij = elem2param[itype][jtype][jtype];
// parameter check: eps > 0
if(params[iparam_ij].vdwflag > 0) {
if(params[iparam_ij].vdwflag==1){
rvdw[0][inty] = params[iparam_ij].bigr + params[iparam_ij].bigd;
}
else {
rvdw[0][inty] = params[iparam_ij].bigr - params[iparam_ij].bigd;
}
rvdw[1][inty] = params[iparam_ij].vsig * 0.950;
// radius check: outter radius vs. sigma
if( rvdw[0][inty] > rvdw[1][inty] )
error->all(FLERR,"Error in vdw spline: inner radius > outter radius");
rrc[0] = rvdw[1][inty];
for (i=1; i<13; i++)
rrc[i] = rrc[i-1] * rrc[0];
drcc = rrc[0] - rvdw[0][inty];
temp6 = 1.0/rrc[5]-1.0/vrc[5]+6.0*(rrc[0]-vrc[0])/vrc[6];
temp7 = 6.0*(1.0/vrc[6]-1.0/rrc[6]);
temp12 = 1.0/rrc[11]-1.0/vrc[11]+(rrc[0]-vrc[0])*12.0/vrc[12];
temp13 = 12.0*(1.0/vrc[12]-1.0/rrc[12]);
vsigt = params[iparam_ij].vsig;
vepst = params[iparam_ij].veps;
vsigt = vsigt*vsigt*vsigt*vsigt*vsigt*vsigt;
vdwt = vepst*(vsigt*vsigt*temp12-vsigt*temp6);
dvdwt = vepst*(vsigt*vsigt*temp13-vsigt*temp7);
cc2[inty] = (3.0/drcc*vdwt-dvdwt)/drcc;
cc3[inty] = (vdwt/(drcc*drcc)-cc2[inty] )/drcc;
}
}
}
// generate vdw look-up table
for (ii = 0; ii < n; ii ++) {
for (jj = ii; jj < n; jj ++) {
itype = ii;
jtype = jj;
inty = intype[itype][jtype];
iparam_ij = elem2param[itype][jtype][jtype];
r = drin;
for (k = 0; k < ncoul; k ++) {
r6 = r*r*r*r*r*r;
r7 = r6 * r;
rf6 = 1.0/r6-1.0/vrc[5]+(r-vrc[0])*6.0/vrc[6];
drf7 = 6.0*(1.0/vrc[6]-1.0/r7);
vsigt = params[iparam_ij].vsig;
vepst = params[iparam_ij].veps;
vsigt = vsigt*vsigt*vsigt*vsigt*vsigt*vsigt;
if(params[iparam_ij].vdwflag>0) {
if(r <= rvdw[0][inty]) {
vvdw[k][inty] = 0.0;
vdvdw[k][inty] = 0.0;
}
else if ( r > rvdw[0][inty] && r <= rvdw[1][inty]) {
drcc = r-rvdw[0][inty];
vvdw[k][inty] = drcc*drcc*(drcc*cc3[inty]+cc2[inty]);
vdvdw[k][inty] = drcc*(3.0*drcc*cc3[inty]+2.0*cc2[inty]);
} else {
r12 = r6*r6;
r13 = r6*r7;
rf12 = 1.0/r12-1.0/vrc[11]+(r-vrc[0])*12.0/vrc[12];
drf13= 12.0*(1.0/vrc[12]-1.0/r13);
vvdw[k][inty] = vepst*(vsigt*vsigt*rf12-vsigt*rf6);
vdvdw[k][inty] = vepst*(vsigt*vsigt*drf13-vsigt*drf7);
}
} else {
vvdw[k][inty]=0.0;
vdvdw[k][inty]=0.0;
}
r += dra;
}
}
}
delete [] vrc;
delete [] rrc;
delete [] cc2;
delete [] cc3;
memory->destroy(rvdw);
}
/* ---------------------------------------------------------------------- */
void PairComb3::potal_calc(double &calc1, double &calc2, double &calc3)
{
double alf,rcoul,esucon;
int m;
rcoul = 0.0;
for (m = 0; m < nparams; m++)
if (params[m].lcut > rcoul) rcoul = params[m].lcut;
alf = 0.20;
esucon = force->qqr2e;
calc2 = (erfc(rcoul*alf)/rcoul/rcoul+2.0*alf/MY_PIS*
exp(-alf*alf*rcoul*rcoul)/rcoul)*esucon/rcoul;
calc3 = (erfc(rcoul*alf)/rcoul)*esucon;
calc1 = -(alf/MY_PIS*esucon+calc3*0.5);
}
/* ---------------------------------------------------------------------- */
void PairComb3::tri_point(double rsq, int &mr1, int &mr2,
int &mr3, double &sr1, double &sr2, double &sr3)
{
double r, rin, dr, dd, rr1, rridr, rridr2;
rin = 0.1000; dr = 0.0010;
r = sqrt(rsq);
if (r < rin + 2.0*dr) r = rin + 2.0*dr;
if (r > cutmax - 2.0*dr) r = cutmax - 2.0*dr;
rridr = (r-rin)/dr;
mr1 = int(rridr) ;
dd = rridr - float(mr1);
if (dd > 0.5) mr1 += 1;
rr1 = float(mr1)*dr;
rridr = (r - rin - rr1)/dr;
rridr2 = rridr * rridr;
sr1 = (rridr2 - rridr) * 0.50;
sr2 = 1.0 - rridr2;
sr3 = (rridr2 + rridr) * 0.50;
mr2 = mr1 + 1;
mr3 = mr1 + 2;
}
/* ---------------------------------------------------------------------- */
void PairComb3::vdwaals(int inty, int mr1, int mr2, int mr3, double rsq,
double sr1, double sr2, double sr3,
double &eng, double &fforce)
{
double r = sqrt(rsq);
eng = 1.0*(sr1*vvdw[mr1-1][inty]+sr2*vvdw[mr2-1][inty]+sr3*vvdw[mr3-1][inty]);
fforce = -1.0/r*(sr1*vdvdw[mr1-1][inty]+sr2*vdvdw[mr2-1][inty]+sr3*vdvdw[mr3-1][inty]);
}
/* ---------------------------------------------------------------------- */
void PairComb3::direct(Param *parami, Param *paramj, int mr1,
int mr2, int mr3, double rsq, double sr1, double sr2, double sr3,
double iq, double jq, double fac11, double fac11e,
double &pot_tmp, double &for_tmp, int i, int j)
{
double r,erfcc,fafbnl,potij,chrij,esucon;
double r3,erfcd,dfafbnl,smf2,dvdrr,ddvdrr,alf,alfdpi;
double afbn,afbj,sme1n,sme1j,sme1,sme2,dafbn, dafbj,smf1n,smf1j;
double curli = parami->curl;
double curlj = paramj->curl;
int inti = parami->ielement;
int intj = paramj->ielement;
int inty = intype[inti][intj];
double curlcutij1 = parami->curlcut1;
double curlcutij2 = parami->curlcut2;
double curlcutji1 = paramj->curlcut1;
double curlcutji2 = paramj->curlcut2;
double curlij0 = parami->curl0;
double curlji0 = paramj->curl0;
double curlij1,curlji1,dcurlij,dcurlji;
double fcp1j,xcoij,xcoji;
int icurl, jcurl;
int ielegp = parami->ielementgp;
int jelegp = paramj->ielementgp;
r = sqrt(rsq);
r3 = r * rsq;
alf = 0.20;
alfdpi = 2.0*alf/MY_PIS;
esucon = force->qqr2e;
pot_tmp = for_tmp = 0.0;
icurl=jcurl=0;
if(ielegp==2 && curli>curlij0) {
icurl=1;
curlij1=curli;
}
if(jelegp==2 && curlj>curlji0) {
jcurl=1;
curlji1=curlj;
}
if(icurl==1 || jcurl ==1) {
xcoij = xcotmp[i];
xcoji = xcotmp[j];
fcp1j = comb_fc_d(r,parami);
if(icurl==1) {
curli=curlij1+(curlij0-curlij1)*comb_fc_curl(xcoij,parami);
dcurlij=fcp1j*(curlij0-curlij1)*comb_fc_curl_d(xcoij,parami);
}
if(jcurl==1) {
curlj=curlji1+(curlji0-curlji1)*comb_fc_curl(xcoji,paramj);
dcurlji=fcp1j*(curlji0-curlji1)*comb_fc_curl_d(xcoji,paramj);
}
}
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
afbn = sr1*afb[mr1][inti] + sr2*afb[mr2][inti] + sr3*afb[mr3][inti];
afbj = sr1*afb[mr1][intj] + sr2*afb[mr2][intj] + sr3*afb[mr3][intj];
fafbnl= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
potij = (erfcc/r * esucon - fac11e);
sme1n = iq*curlj*(afbn-fafbnl)*esucon;
sme1j = jq*curli*(afbj-fafbnl)*esucon;
sme1 = sme1n + sme1j;
sme2 = (potij + fafbnl * esucon) * iq * jq;
pot_tmp = 1.0 * (sme1+sme2);
// 1/r force (wrt r)
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
dafbn = sr1*dafb[mr1][inti] + sr2*dafb[mr2][inti] + sr3*dafb[mr3][inti];
dafbj = sr1*dafb[mr1][intj] + sr2*dafb[mr2][intj] + sr3*dafb[mr3][intj];
dfafbnl= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
ddvdrr = (2.0*erfcc/r3 + 2.0*alfdpi*erfcd*(1.0/rsq+alf*alf))*esucon;
smf1n = iq * curlj * (dafbn-dfafbnl)*esucon/r;
smf1j = jq * curli * (dafbj-dfafbnl)*esucon/r;
if(jcurl==1 && ielegp == 3 && dcurlji != 0.0){
smf1n += dcurlji*iq*(afbn-fafbnl)*esucon/r;
}
if(icurl==1 && jelegp == 3 && dcurlij != 0.0){
smf1j += dcurlij*jq*(afbj-fafbnl)*esucon/r;
}
smf2 = dvdrr + dfafbnl * esucon/r;
for_tmp = 1.0 * iq * jq * smf2 + smf1n + smf1j;
}
/* ---------------------------------------------------------------------- */
void PairComb3::field(Param *parami, Param *paramj, double rsq, double iq,
double jq, double &eng_tmp,double &for_tmp)
{
double r,r3,r4,r5,r6,rc,rc2,rc3,rc4,rc5,rc6;
double cmi1,cmi2,cmj1,cmj2,pcmi1,pcmi2,pcmj1,pcmj2;
double rf3i,rcf3i,rf5i,rcf5i;
double drf3i,drcf3i,drf5i,drcf5i;
double rf3,rf5,drf4,drf6;
double smpn,smpl,rfx1,rfx2;
r = sqrt(rsq);
r3 = r * r * r;
r4 = r3 * r;
r5 = r4 * r;
r6 = r5 * r;
rc = parami->lcut;
rc2 = rc * rc;
rc3 = rc*rc*rc;
rc4 = rc3 * rc;
rc5 = rc4 * rc;
rc6 = rc5 * rc;
cmi1 = parami->cmn1;
cmi2 = parami->cmn2;
cmj1 = paramj->cmn1;
cmj2 = paramj->cmn2;
pcmi1 = parami->pcmn1;
pcmi2 = parami->pcmn2;
pcmj1 = paramj->pcmn1;
pcmj2 = paramj->pcmn2;
rf3i = r3/(pow(r3,2)+pow(pcmi1,3));
rcf3i = rc3/(pow(rc3,2)+pow(pcmi1,3));
rf5i = r5/(pow(r5,2)+pow(pcmi2,5));
rcf5i = rc5/(pow(rc5,2)+pow(pcmi2,5));
drf3i = 3/r*rf3i-6*rsq*rf3i*rf3i;
drcf3i = 3/rc*rcf3i-6*rc2*rcf3i*rcf3i;
drf5i = 5/r*rf5i-10*r4*rf5i*rf5i;
drcf5i = 5/rc*rcf5i-10*rc4*rcf5i*rcf5i;
rf3 = rf3i-rcf3i-(r-rc)*drcf3i;
rf5 = rf5i-rcf5i-(r-rc)*drcf5i;
drf4 = drf3i - drcf3i;
drf6 = drf5i - drcf5i;
// field correction energy
smpn = jq*(cmi1*rf3+jq*cmi2*rf5);
smpl = iq*(cmj1*rf3+iq*cmj2*rf5);
eng_tmp = 1.0 * (smpn + smpl);
// field correction force
rfx1 = jq*(cmi1*drf4+jq*cmi2*drf6)/r;
rfx2 = iq*(cmj1*drf4+iq*cmj2*drf6)/r;
for_tmp -= 1.0 * (rfx1 + rfx2);
}
/* ---------------------------------------------------------------------- */
double PairComb3::rad_init(double rsq2,Param *param,int i,
double &radtot, double cnconj)
{
int n;
double r, fc1k, radcut,radcut1,radcut2;
r = sqrt(rsq2);
fc1k = comb_fc(r,param);
radtot = -fc1k * param->pcross + cnconj;
radcut = comb_fcch(radtot);
return fc1k * param->pcross * radcut;
}
/* ---------------------------------------------------------------------- */
void PairComb3::rad_calc(double r, Param *parami, Param *paramj,
double kconjug, double lconjug, int i, int j, double xcn, double ycn)
{
int ixmin, iymin, izmin, n;
int radindx;
double xrad, yrad, zcon, vrad, pradx, prady, pradz;
vrad = pradx = prady = pradz = 0.0;
xrad = -comb_fc(r,parami)*parami->pcross + xcn;
yrad = -comb_fc(r,paramj)*paramj->pcross + ycn;
zcon = 1.0 + pow(kconjug,2) + pow(lconjug,2);
if(xrad < 0.0) xrad = 0.0;
if(yrad < 0.0) yrad = 0.0;
if(zcon < 1.0) zcon = 1.0;
if(xrad > maxxc) xrad = maxxc;
if(yrad > maxyc) yrad = maxyc;
if(zcon > maxconj) zcon = maxconj;
ixmin = int(xrad+1.0e-12);
iymin = int(yrad+1.0e-12);
izmin = int(zcon+1.0e-12);
radindx=parami->rad_flag-1;
if (fabs(float(ixmin)-xrad)>1.0e-8 ||
fabs(float(iymin)-yrad)>1.0e-8 ||
fabs(float(izmin)-zcon)>1.0e-8) {
rad_int(radindx,xrad,yrad,zcon,ixmin,iymin,izmin,
vrad,pradx,prady,pradz);
} else {
vrad = rad_grid[radindx][ixmin][iymin][izmin-1];
pradx = rad_gridx[radindx][ixmin][iymin][izmin-1];
prady = rad_gridy[radindx][ixmin][iymin][izmin-1];
pradz = rad_gridz[radindx][ixmin][iymin][izmin-1];
}
brad[0] = vrad;
brad[1] = pradx;
brad[2] = prady;
brad[3] = pradz;
}
/* ---------------------------------------------------------------------- */
void PairComb3::rad_int(int radindx,double xrad, double yrad, double zcon, int l,
int m, int n, double &vrad, double &pradx, double &prady,
double &pradz)
{
int j;
double x;
vrad = pradx = prady = pradz = 0.0;
if(l >= maxxc-1) { l=maxxc-1;}
if(m >= maxyc-1) { m=maxyc-1; }
if(n >= maxconj-1) { n=maxconj-1;}
for (j=0; j<64; j++) {
x = rad_spl[radindx][l][m][n-1][j] * pow(xrad,iin3[j][0])
* pow(yrad,iin3[j][1]) * pow(zcon,iin3[j][2]);
vrad += x;
if(xrad > 1.0e-8) pradx += x*iin3[j][0]/xrad;
if(yrad > 1.0e-8) prady += x*iin3[j][1]/yrad;
if(zcon > 1.0e-8) pradz += x*iin3[j][2]/zcon;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::rad_forceik(Param *paramk, double rsq2, double *delrk,
double conjug, double radtot)
{
int nm;
double rik, fc1k, fcp1k;
double pradk, ffkk2, fktmp[3];
double radcut = comb_fcch(radtot);
double dradcut = comb_fcch_d(radtot);
for (nm=0; nm<3; nm++) {
fi_rad[nm] = fk_rad[nm] = 0.0;
}
radtmp =0.0;
rik = sqrt(rsq2);
fc1k = comb_fc(rik, paramk);
fcp1k = comb_fc_d(rik,paramk);
pradk = brad[3]*fcp1k*radcut*paramk->pcross*2.0*conjug;
radtmp= brad[3]*fc1k*dradcut*paramk->pcross*2.0*conjug;
ffkk2 = -pradk/rik;
for (nm=0; nm<3; nm++) {
fktmp[nm] = - ffkk2 * delrk[nm];
}
for (nm=0; nm<3; nm++) {
fi_rad[nm] = fktmp[nm];
fk_rad[nm] = -fktmp[nm];
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::rad_force(Param *paramm, double rsq3,
double *delrm, double dpradk)
{
int nm;
double rkm, fc1m, fcp1m;
double comkm, ffmm2, fkm[3];
for (nm=0; nm<3; nm++) {
fj_rad[nm] = fk_rad[nm] = 0.0;
fkm[nm]=0.0;
}
rkm = sqrt(rsq3);
fc1m = comb_fc(rkm, paramm);
fcp1m = comb_fc_d(rkm, paramm);
comkm = dpradk * fcp1m * paramm->pcross;
ffmm2 = -comkm/rkm;
for (nm=0; nm<3; nm++) {
fkm[nm] = -ffmm2 * delrm[nm];
}
for (nm=0; nm<3; nm++) {
fj_rad[nm] = fkm[nm];
fk_rad[nm] = -fkm[nm];
}
}
/* ---------------------------------------------------------------------- */
double PairComb3::bbtor1(int torindx, Param *paramk, Param *paraml,
double rsq1, double rsq2, double rsq3, double *delrj,
double *delrk, double *delrl, double srmu)
{
double rmul, rij, rik, rjl;
rij = sqrt(rsq1);
rik = sqrt(rsq2);
rjl = sqrt(rsq3);
vec3_scale(-1.0,delrl,delrl);
rmul = vec3_dot(delrj,delrl)/(rij*rjl);
vec3_scale(-1.0,delrl,delrl);
rmul = sqrt(1.0-rmul*rmul);
if(rmul > 0.1 ) {
double fc1k, fc1l, TT1, TT2, rmut, btt, tork[3], torl[3];
fc1k = comb_fc(rik,paramk);
fc1l = comb_fc(rjl,paraml);
TT1 = rik*rjl*rij*rij*srmu*rmul;
tork[0] = delrk[1]*delrj[2] - delrk[2]*delrj[1];
torl[0] = delrj[1]*delrl[2] - delrj[2]*delrl[1];
tork[1] = delrk[2]*delrj[0] - delrk[0]*delrj[2];
torl[1] = delrj[2]*delrl[0] - delrj[0]*delrl[2];
tork[2] = delrk[0]*delrj[1] - delrk[1]*delrj[0];
torl[2] = delrj[0]*delrl[1] - delrj[1]*delrl[0];
TT2 = vec3_dot(tork,torl);
rmut = pow((TT2/TT1),2);
if(torindx>=1) {
btt = 1.0 - rmut;
return btt * fc1k * fc1l;
}
else {
btt=paramk->ptork1-TT2/TT1;
btt=paramk->ptork2*pow(btt,2);
return btt * fc1k * fc1l;
}
} else {
return 0.0;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::tor_calc(double r, Param *parami, Param *paramj,
double kconjug, double lconjug, int i, int j, double xcn, double ycn)
{
int ixmin, iymin, izmin, n;
double vtor, dtorx, dtory, dtorz;
double xtor, ytor, zcon;
int torindx;
vtor = dtorx = dtory = dtorz = 0.0;
torindx=parami->tor_flag;
if(torindx<0){
vtor=1.0;
dtorx=0.0;
dtory=0.0;
dtorz=0.0;
} else {
xtor = -comb_fc(r, parami) * parami->pcross + xcn;
ytor = -comb_fc(r, paramj) * paramj->pcross + ycn;
zcon = 1.0 + pow(kconjug,2) + pow(lconjug,2);
if (xtor < 0.0) xtor = 0.0;
if (ytor < 0.0) ytor = 0.0;
if (zcon < 1.0) zcon = 1.0;
if (xtor > maxxc) xtor = maxxc;
if (ytor > maxyc) ytor = maxyc;
if (zcon > maxconj) zcon = maxconj;
ixmin = int(xtor+1.0e-12);
iymin = int(ytor+1.0e-12);
izmin = int(zcon+1.0e-12);
torindx=torindx-1;
if (fabs(float(ixmin)-xtor)>1.0e-8 ||
fabs(float(iymin)-ytor)>1.0e-8 ||
fabs(float(izmin)-zcon)>1.0e-8) {
tor_int(torindx,xtor,ytor,zcon,ixmin,iymin,izmin,
vtor,dtorx,dtory,dtorz);
} else {
vtor = tor_grid[torindx][ixmin][iymin][izmin-1];
dtorx = tor_gridx[torindx][ixmin][iymin][izmin-1];
dtory = tor_gridy[torindx][ixmin][iymin][izmin-1];
dtorz = tor_gridz[torindx][ixmin][iymin][izmin-1];
}
}
btor[0] = vtor;
btor[1] = dtorx;
btor[2] = dtory;
btor[3] = dtorz;
}
/* ---------------------------------------------------------------------- */
void PairComb3::tor_int(int torindx,double xtor, double ytor, double zcon, int l,
int m, int n, double &vtor, double &dtorx, double &dtory, double &dtorz)
{
int j;
double x;
vtor = dtorx = dtory = dtorz = 0.0;
if(l >= maxxc-1) { l=maxxc-1; } //boundary condition changed
if(m >= maxyc-1) { m=maxyc-1; }
if(n >= maxconj-1) { n=maxconj-1; }
for (j=0; j<64; j++) {
x = tor_spl[torindx][l][m][n-1][j] * pow(xtor,iin3[j][0])
* pow(ytor,iin3[j][1]) * pow(zcon,iin3[j][2]);
vtor += x;
if(xtor > 1.0e-8 ) dtorx += x*iin3[j][0]/xtor;
if(ytor > 1.0e-8 ) dtory += x*iin3[j][1]/ytor;
if(zcon > 1.0e-8 ) dtorz += x*iin3[j][2]/zcon;
}
}
/* ---------------------------------------------------------------------- */
void PairComb3::tor_force(int torindx, Param *paramk, Param *paraml,
double srmu, double rsq1,double rsq2, double rsq3,
double *delrj, double *delrk, double *delrl)
{
int nm;
double rmu, rmul, srmul, rij, rik, rjl;
for (nm=0; nm<3; nm++) {
fi_tor[nm] = fj_tor[nm] = fk_tor[nm] = fl_tor[nm] = 0.0;
}
rij = sqrt(rsq1);
rik = sqrt(rsq2);
rjl = sqrt(rsq3);
rmu = vec3_dot(delrj,delrk)/(rij*rik);
vec3_scale(-1.0,delrl,delrl);
rmul = vec3_dot(delrj,delrl)/(rij*rjl);
vec3_scale(-1.0,delrl,delrl);
srmul = sqrt(1.0-rmul*rmul);
if(acos(rmul) > MY_PI) srmul = -srmul;
if(srmul > 0.1 ) {
double fc1k, fcp1k, fc1l, fcp1l, srmul2, dt1dik, dt1djl;
double TT1, TT2, rmut, btt, tork[3], torl[3];
double dt2dik[3], dt2djl[3], dt2dij[3], AA, AA2;
double tfij[4], tfik[2], tfjl[2], tjx[3], tjy[3], tjz[3];
double tkx[2], tky[2], tkz[2], tlx[2], tly[2], tlz[2];
fc1k = comb_fc(rik,paramk);
fcp1k = comb_fc_d(rik,paramk);
fc1l = comb_fc(rjl,paraml);
fcp1l = comb_fc_d(rjl,paraml);
srmul2 = pow(srmul,2);
TT1 = rik*rjl*rij*rij*srmu*srmul;
dt1dik = -rmu/pow(srmu,2);
dt1djl = -rmul/srmul2;
tork[0] = delrk[1]*delrj[2] - delrk[2]*delrj[1];
torl[0] = delrj[1]*delrl[2] - delrj[2]*delrl[1];
tork[1] = delrk[2]*delrj[0] - delrk[0]*delrj[2];
torl[1] = delrj[2]*delrl[0] - delrj[0]*delrl[2];
tork[2] = delrk[0]*delrj[1] - delrk[1]*delrj[0];
torl[2] = delrj[0]*delrl[1] - delrj[1]*delrl[0];
TT2 = vec3_dot(tork,torl);
dt2dik[0] = -delrj[1]*torl[2] + delrj[2]*torl[1];
dt2dik[1] = -delrj[2]*torl[0] + delrj[0]*torl[2];
dt2dik[2] = -delrj[0]*torl[1] + delrj[1]*torl[0];
dt2djl[0] = delrj[1]*tork[2] - delrj[2]*tork[1];
dt2djl[1] = delrj[2]*tork[0] - delrj[0]*tork[2];
dt2djl[2] = delrj[0]*tork[1] - delrj[1]*tork[0];
dt2dij[0] = -delrk[2]*torl[1] + delrl[2]*tork[1]
+ delrk[1]*torl[2] - delrl[1]*tork[2];
dt2dij[1] = -delrk[0]*torl[2] + delrl[0]*tork[2]
+ delrk[2]*torl[0] - delrl[2]*tork[0];
dt2dij[2] = -delrk[1]*torl[0] + delrl[1]*tork[0]
+ delrk[0]*torl[1] - delrl[0]*tork[1];
rmut = TT2/TT1;
if(torindx>=1) {
btt = 1.0 - pow(rmut,2);
AA = -2.0 * ptorr * rmut * fc1k * fc1l / TT1;
}
else {
btt=paramk->ptork1-rmut;
btt=paramk->ptork2*pow(btt,2);
AA = -2.0 * ptorr * paramk->ptork2 *
(paramk->ptork1-rmut) * fc1k * fc1l /TT1;
}
AA2 = AA * TT2;
tfij[0] = -(dt1dik*AA2)/rij/rik;
tfij[1] = AA2/rij/rij - dt1dik*AA2*rmu/rij/rij;
tfij[2] = -dt1djl*AA2/rij/rjl;
tfij[3] = AA2/rij/rij - dt1djl*AA2*rmul/rij/rij;
tfik[0] = tfij[0];
tfik[1] = (AA2/rik - btt*ptorr*fc1l*fcp1k)/rik -
dt1dik*AA2*rmu/rik/rik;
tfjl[0] = tfij[2];
tfjl[1] = (AA2/rjl - btt*ptorr*fc1k*fcp1l)/rjl -
dt1djl*AA2*rmul/rjl/rjl;
tjx[0] = tfij[0]*delrk[0] - tfij[1]*delrj[0];
tjy[0] = tfij[0]*delrk[1] - tfij[1]*delrj[1];
tjz[0] = tfij[0]*delrk[2] - tfij[1]*delrj[2];
tjx[1] = -tfij[2]*delrl[0] - tfij[3]*delrj[0];
tjy[1] = -tfij[2]*delrl[1] - tfij[3]*delrj[1];
tjz[1] = -tfij[2]*delrl[2] - tfij[3]*delrj[2];
tjx[2] = -dt2dij[0] * AA;
tjy[2] = -dt2dij[1] * AA;
tjz[2] = -dt2dij[2] * AA;
tkx[0] = tfik[0]*delrj[0] - tfik[1]*delrk[0];
tky[0] = tfik[0]*delrj[1] - tfik[1]*delrk[1];
tkz[0] = tfik[0]*delrj[2] - tfik[1]*delrk[2];
tkx[1] = -dt2dik[0] * AA;
tky[1] = -dt2dik[1] * AA;
tkz[1] = -dt2dik[2] * AA;
tlx[0] = -tfjl[0]*delrj[0] - tfjl[1]*delrl[0];
tly[0] = -tfjl[0]*delrj[1] - tfjl[1]*delrl[1];
tlz[0] = -tfjl[0]*delrj[2] - tfjl[1]*delrl[2];
tlx[1] = -dt2djl[0] * AA;
tly[1] = -dt2djl[1] * AA;
tlz[1] = -dt2djl[2] * AA;
fi_tor[0] = tjx[0]+tjx[1]+tjx[2]+tkx[0]+tkx[1];
fi_tor[1] = tjy[0]+tjy[1]+tjy[2]+tky[0]+tky[1];
fi_tor[2] = tjz[0]+tjz[1]+tjz[2]+tkz[0]+tkz[1];
fj_tor[0] = -tjx[0]-tjx[1]-tjx[2]+tlx[0]+tlx[1];
fj_tor[1] = -tjy[0]-tjy[1]-tjy[2]+tly[0]+tly[1];
fj_tor[2] = -tjz[0]-tjz[1]-tjz[2]+tlz[0]+tlz[1];
fk_tor[0] = -tkx[0]-tkx[1];
fk_tor[1] = -tky[0]-tky[1];
fk_tor[2] = -tkz[0]-tkz[1];
fl_tor[0] = -tlx[0]-tlx[1];
fl_tor[1] = -tly[0]-tly[1];
fl_tor[2] = -tlz[0]-tlz[1];
}
}
/* ---------------------------------------------------------------------- */
double PairComb3::combqeq(double *qf_fix, int &igroup)
{
- int i,j,ii, jj,itag,jtag,itype,jtype,jnum;
+ int i,j,ii,jj,itype,jtype,jnum;
int iparam_i,iparam_ji,iparam_ij;
int *ilist,*jlist,*numneigh,**firstneigh;
int mr1,mr2,mr3,inty,nj;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,rr,rsq,rsq1,rsq2,delrj[3],zeta_ij;
double iq,jq,fqi,fqj,fqij,fqji,yaself,yaself_d,sr1,sr2,sr3;
double rr_sw,ij_sw,ji_sw,fq_swi,fq_swj;
double potal,fac11,fac11e;
int sht_jnum,*sht_jlist;
double **x = atom->x;
double *q = atom->q;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int inum = list->inum;
int *mask = atom->mask;
int groupbit = group->bitmask[igroup];
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// Derivative debugging
int nlocal = atom->nlocal;
double fqself, fqdirect, fqfield, fqshort, fqdipole, fqtot;
fqself = fqdirect = fqfield = fqshort = fqdipole = fqtot = 0.0;
qf = qf_fix;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit)
qf[i] = 0.0;
dpl[i][0] = dpl[i][1] = dpl[i][2] = 0.0;
}
// communicating charge force to all nodes, first forward then reverse
pack_flag = 1;
comm->forward_comm_pair(this);
// self energy correction term: potal
potal_calc(potal,fac11,fac11e);
// loop over full neighbor list of my atoms
fqi = fqj = fqij = fqji = 0.0;
for (ii = 0; ii < inum; ii ++) {
i = ilist[ii];
itag = tag[i];
nj = 0;
if (mask[i] & groupbit) {
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
iq = q[i];
iparam_i = elem2param[itype][itype][itype];
// charge force from self energy
fqi =0.0;
fqi = qfo_self(&params[iparam_i],iq);
fq_swi = fqi;
jlist = firstneigh[i];
jnum = numneigh[i];
sht_jlist = sht_first[i];
sht_jnum = sht_num[i];
// two-body interactions
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
jtag = tag[j];
if (itag >= jtag) continue;
jtype = map[type[j]];
inty = intype[itype][jtype];
jq = q[j];
delrj[0] = xtmp - x[j][0];
delrj[1] = ytmp - x[j][1];
delrj[2] = ztmp - x[j][2];
rsq1 = vec3_dot(delrj,delrj);
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
// long range q-dependent
if (rsq1 > params[iparam_ij].lcutsq) continue;
// polynomial three-point interpolation
tri_point(rsq1,mr1,mr2,mr3,sr1,sr2,sr3);
// 1/r charge forces
qfo_direct(&params[iparam_ij],&params[iparam_ji],
mr1,mr2,mr3,rsq1,sr1,sr2,sr3,fac11e,fqij,fqji,
iq,jq,i,j);
fqi += fqij; qf[j] += fqji;
// field correction to self energy and charge force
qfo_field(&params[iparam_ij],&params[iparam_ji],rsq1,
iq,jq,fqij,fqji);
fqi += fqij; qf[j] += fqji;
// polarization field charge force
if (pol_flag) {
qfo_dipole(fac11,mr1,mr2,mr3,inty,rsq1,delrj,sr1,sr2,sr3,
fqij,fqji,i,j);
fqi += fqij; qf[j] += fqji;
}
}
for (jj = 0; jj < sht_jnum; jj++) {
j = sht_jlist[jj];
jtag = tag[j];
if (itag >= jtag) continue;
jtype = map[type[j]];
inty = intype[itype][jtype];
jq = q[j];
delrj[0] = xtmp - x[j][0];
delrj[1] = ytmp - x[j][1];
delrj[2] = ztmp - x[j][2];
rsq1 = vec3_dot(delrj,delrj);
iparam_ij = elem2param[itype][jtype][jtype];
iparam_ji = elem2param[jtype][itype][itype];
if (rsq1 >= params[iparam_ij].cutsq) continue;
nj ++;
// charge force in Aij and Bij
qfo_short(&params[iparam_ij],&params[iparam_ji],
rsq1,iq,jq,fqij,fqji,i,j,nj);
fqi += fqij; qf[j] += fqji;
}
qf[i] += fqi;
}
}
comm->reverse_comm_pair(this);
// sum charge force on each node and return it
double eneg = 0.0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit){
eneg += qf[i];
- itag=tag[i];
+ itag=tag[i];
}
}
double enegtot;
MPI_Allreduce(&eneg,&enegtot,1,MPI_DOUBLE,MPI_SUM,world);
MPI_Bcast(&enegtot,1,MPI_DOUBLE,0,world);
return enegtot;
}
/* ---------------------------------------------------------------------- */
double PairComb3::qfo_self(Param *param, double qi)
{
double self_d,cmin,cmax,qmin,qmax;
double s1 = param->chi;
double s2 = param->dj;
double s3 = param->dk;
double s4 = param->dl;
self_d = 0.0;
qmin = param->qmin;
qmax = param->qmax;
cmin = cmax = 100.0;
self_d = s1+qi*(2.0*s2+qi*(3.0*s3+qi*4.0*s4));
if (qi < qmin) self_d += 4.0 * cmin * pow((qi-qmin),3);
if (qi > qmax) self_d += 4.0 * cmax * pow((qi-qmax),3);
return self_d;
}
/* ---------------------------------------------------------------------- */
void PairComb3::qfo_direct(Param *parami, Param *paramj, int mr1,
int mr2, int mr3, double rsq, double sr1, double sr2,
double sr3, double fac11e, double &fqij, double &fqji,
double iq, double jq, int i, int j)
{
double r, erfcc, erfcd, fafbnl, vm, vmfafb, esucon;
double afbn, afbj, sme1n, sme1j;
double curli = parami->curl;
double curlj = paramj->curl;
int inti = parami->ielement;
int intj = paramj->ielement;
int inty = intype[inti][intj];
double curlcutij1 = parami->curlcut1;
double curlcutij2 = parami->curlcut2;
double curlcutji1 = paramj->curlcut1;
double curlcutji2 = paramj->curlcut2;
double curlij0 = parami->curl0;
double curlji0 = paramj->curl0;
double curlij1,curlji1;
int icurl, jcurl;
int ielegp = parami->ielementgp;
int jelegp = paramj->ielementgp;
r = sqrt(rsq);
esucon=force->qqr2e;
icurl = jcurl = 0;
if(ielegp==2 && curli>curlij0) {
icurl=1;
curlij1=curli;
}
if(jelegp==2 && curlj>curlji0) {
jcurl=1;
curlji1=curlj;
}
if(icurl==1 || jcurl ==1) {
double xcoij= xcotmp[i];
double xcoji= xcotmp[j];
if(icurl==1) {
curli=curlij1+(curlij0-curlij1)*comb_fc_curl(xcoij,parami);
}
if(jcurl==1) {
curlj=curlji1+(curlji0-curlji1)*comb_fc_curl(xcoji,paramj);
}
}
// 1/r force (wrt q)
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
fafbnl= sr1*fafb[mr1][inty] + sr2*fafb[mr2][inty] + sr3*fafb[mr3][inty];
afbn = sr1*afb[mr1][inti] + sr2*afb[mr2][inti] + sr3*afb[mr3][inti];
afbj = sr1*afb[mr1][intj] + sr2*afb[mr2][intj] + sr3*afb[mr3][intj];
vm = (erfcc/r * esucon - fac11e);
vmfafb = vm + esucon * fafbnl;
sme1n = curlj * (afbn - fafbnl) * esucon;
sme1j = curli * (afbj - fafbnl) * esucon;
fqij = 1.0 * (jq * vmfafb + sme1n);
fqji = 1.0 * (iq * vmfafb + sme1j);
}
/* ---------------------------------------------------------------------- */
void PairComb3::qfo_field(Param *parami, Param *paramj, double rsq,
double iq,double jq, double &fqij, double &fqji)
{
double r,r3,r4,r5,r6,rc,rc2,rc3,rc4,rc5,rc6;
double cmi1,cmi2,cmj1,cmj2,pcmi1,pcmi2,pcmj1,pcmj2;
double rf3i,rcf3i,rf5i,rcf5i;
double drf3i,drcf3i,drf5i,drcf5i,rf3,rf5;
r = sqrt(rsq);
r3 = r * rsq;
r4 = r * r3;
r5 = r3 * rsq;
r6 = r * r5;
rc = parami->lcut;
rc2= rc*rc;
rc3 = rc*rc*rc;
rc4 = rc3 * rc;
rc5 = rc4 * rc;
rc6 = rc5 * rc;
cmi1 = parami->cmn1;
cmi2 = parami->cmn2;
cmj1 = paramj->cmn1;
cmj2 = paramj->cmn2;
pcmi1 = parami->pcmn1;
pcmi2 = parami->pcmn2;
pcmj1 = paramj->pcmn1;
pcmj2 = paramj->pcmn2;
rf3i = r3/(pow(r3,2)+pow(pcmi1,3));
rcf3i = rc3/(pow(rc3,2)+pow(pcmi1,3));
rf5i = r5/(pow(r5,2)+pow(pcmi2,5));
rcf5i = rc5/(pow(rc5,2)+pow(pcmi2,5));
drf3i = 3/r*rf3i-6*rsq*rf3i*rf3i;
drcf3i = 3/rc*rcf3i-6*rc2*rcf3i*rcf3i;
drf5i = 5/r*rf5i-10*r4*rf5i*rf5i;
drcf5i = 5/rc*rcf5i-10*rc4*rcf5i*rcf5i;
rf3 = rf3i-rcf3i-(r-rc)*drcf3i;
rf5 = rf5i-rcf5i-(r-rc)*drcf5i;
// field correction charge force
fqij = 1.0 * cmj1*rf3+2.0*iq*cmj2*rf5;
fqji = 1.0 * cmi1*rf3+2.0*jq*cmi2*rf5;
}
/* ---------------------------------------------------------------------- */
void PairComb3::qfo_dipole(double fac11, int mr1, int mr2, int mr3,
int inty, double rsq, double *delrj, double sr1, double sr2,
double sr3, double &fqij, double &fqji, int i, int j)
{
double erfcc, erfcd, dvdrr, dfafbnl, smf2;
double r, r3, alfdpi, esucon;
r = sqrt(rsq);
r3 = r * rsq;
alfdpi = 0.4/MY_PIS;
esucon = force->qqr2e;
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
dfafbnl= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
smf2 = (dvdrr + dfafbnl*esucon)/r;
fqij = dpl[i][0]*delrj[0] + dpl[i][1]*delrj[1] +dpl[i][2]*delrj[2];
fqji = dpl[j][0]*delrj[0] + dpl[j][1]*delrj[1] +dpl[j][2]*delrj[2];
fqij *= smf2;
fqji *= smf2;
}
/* ---------------------------------------------------------------------- */
void PairComb3::qfo_short(Param *parami, Param *paramj, double rsq,
double iq, double jq, double &fqij, double &fqji,
int i, int j, int nj)
{
double r, tmp_fc, Asi, Asj, vrcs;
double Di, Dj, dDi, dDj, Bsi, Bsj, dBsi, dBsj;
double QUchi, QOchi, QUchj, QOchj;
double bij, caj, cbj, caqpn, caqpj, cbqpn, cbqpj;
double LamDiLamDj, AlfDiAlfDj;
double romi = parami->addrep;
double rrcs = parami->bigr + parami->bigd;
double rlm1 = parami->lambda;
double alfij1= parami->alpha1;
double alfij2= parami->alpha2;
double alfij3= parami->alpha3;
double pbij1= parami->bigB1;
double pbij2= parami->bigB2;
double pbij3= parami->bigB3;
caj = cbj = caqpn = caqpj = cbqpn = cbqpj = 0.0;
r = sqrt(rsq);
tmp_fc = comb_fc(r,parami);
bij = bbij[i][nj];
// additional repulsion
if (romi > 0.0) vrcs = romi * pow((1.0-r/rrcs),2.0);
QUchi = (parami->QU - iq) * parami->bD;
QUchj = (paramj->QU - jq) * paramj->bD;
QOchi = (iq - parami->Qo) * parami->bB;
QOchj = (jq - paramj->Qo) * paramj->bB;
if (iq < parami->QL-0.2) {
iq = parami->QL-0.2;
Di = parami->DL;
dDi = Bsi = dBsi = 0.0;
} else if (iq > parami->QU+0.2) {
iq = parami->QU+0.2;
Di = parami->DU;
dDi = Bsi = dBsi = 0.0;
} else {
Di = parami->DU + pow(QUchi,parami->nD); // YYDin
dDi = -parami->nD * parami->bD * pow(QUchi,(parami->nD-1.0)); // YYDiqp
Bsi = parami->aB - pow(QOchi,10); // YYBsin
dBsi = -parami->bB * 10.0 * pow(QOchi,9.0); // YYBsiqp
}
if (jq < paramj->QL-0.2) {
jq = paramj->QL-0.2;
Dj = paramj->DL;
dDj = Bsj = dBsj = 0.0;
} else if (jq > paramj->QU+0.2) {
jq = paramj->QU+0.2;
Dj = paramj->DU;
dDj = Bsj = dBsj = 0.0;
} else {
Dj = paramj->DU + pow(QUchj,paramj->nD); // YYDij
dDj = -paramj->nD * paramj->bD * pow(QUchj,(paramj->nD-1.0)); // YYDiqpj
Bsj = paramj->aB - pow(QOchj,10); // YYBsij
dBsj = -paramj->bB * 10.0 * pow(QOchj,9.0); // YYBsiqpj
}
LamDiLamDj = exp(0.5*(parami->lami*Di+paramj->lami*Dj)-rlm1*r);
caj = 0.5 * tmp_fc * parami->bigA * LamDiLamDj;
if (Bsi*Bsj > 0.0) {
AlfDiAlfDj = exp(0.5*(parami->alfi*Di+paramj->alfi*Dj));
cbj=-0.5*tmp_fc*bij*sqrt(Bsi*Bsj)*AlfDiAlfDj*
(pbij1*exp(-alfij1*r)+pbij2*exp(-alfij2*r)+pbij3*exp(-alfij3*r));
cbqpn = cbj * (parami->alfi * dDi + dBsi/Bsi);
cbqpj = cbj * (paramj->alfi * dDj + dBsj/Bsj);
} else {
cbj = cbqpn = cbqpj = 0.0;
}
caqpn = caj * parami->lami * dDi;
caqpj = caj * paramj->lami * dDj;
fqij = 1.0 * (caqpn + cbqpn);
fqji = 1.0 * (caqpj + cbqpj);
}
/* ---------------------------------------------------------------------- */
void PairComb3::dipole_init(Param *parami, Param *paramj, double fac11,
double *delrj, double rsq, int mr1, int mr2, int mr3, double sr1,
double sr2, double sr3, double iq, double jq, int i, int j)
{
double erfcc, erfcd, dvdrr, dfafbnl, smf2, phinn, phinj, efn, efj;
double r, r3, alfdpi, esucon;
double rcd, rct, tmurn, tmurj, poln[3], polj[3], Qext[3];
int nm;
int inti = parami->ielement;
int intj = paramj->ielement;
int inty = intype[inti][intj];
for(nm=0; nm<3; nm++) Qext[nm] = 0.0;
r = sqrt(rsq);
r3 = r * rsq;
rcd = 1.0/(r3);
rct = 3.0*rcd/rsq;
alfdpi = 0.4/MY_PIS;
esucon = force->qqr2e;
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
dfafbnl= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
smf2 = dvdrr/esucon + dfafbnl/r;
phinn = sr1*phin[mr1][inti] + sr2*phin[mr2][inti] + sr3*phin[mr3][inti];
phinj = sr1*phin[mr1][intj] + sr2*phin[mr2][intj] + sr3*phin[mr3][intj];
efn = jq * smf2;
efj = iq * smf2;
tmurn = dpl[i][0]*delrj[0] + dpl[i][1]*delrj[1] + dpl[i][2]*delrj[2];
tmurj = dpl[j][0]*delrj[0] + dpl[j][1]*delrj[1] + dpl[j][2]*delrj[2];
for (nm=0; nm<3; nm++) {
poln[nm] = (tmurj*delrj[nm]*rct - dpl[j][nm]*rcd)*phinj;
polj[nm] = (tmurn*delrj[nm]*rct - dpl[i][nm]*rcd)*phinn;
}
for (nm=0; nm<3; nm++) {
dpl[i][nm] += (Qext[nm]/esucon + delrj[nm]*efn + poln[nm])*parami->polz*0.50;
dpl[j][nm] += (Qext[nm]/esucon - delrj[nm]*efj + polj[nm])*paramj->polz*0.50;
}
}
/* ---------------------------------------------------------------------- */
double PairComb3::dipole_self(Param *parami, int i)
{
double esucon = force->qqr2e;
double apn = parami->polz;
double selfdpV = 0.0;
if (apn != 0.0) {
selfdpV= (dpl[i][0]*dpl[i][0]+dpl[i][1]*dpl[i][1]+dpl[i][2]*dpl[i][2])
*esucon/(2.0*apn); }
return selfdpV;
}
/* ---------------------------------------------------------------------- */
void PairComb3::dipole_calc(Param *parami, Param *paramj, double fac11,
double delx, double dely, double delz, double rsq,
int mr1, int mr2, int mr3, double sr1, double sr2, double sr3,
double iq, double jq, int i, int j, double &vionij,
double &fvionij, double *ddprx)
{
double erfcc, erfcd, dvdrr, dfafbnl, ef, phinn, phinj, efn, efj;
double r, r3, alf, alfdpi, esucon, dphinn, dphinj, ddfafbnl;
double def, defn, defj, tmun, tmuj, emuTmu, edqn, edqj, ddvdrr;
double rcd, rct, tmurn, tmurj, tmumu, poln[3], polj[3], delr1[3];
double demuTmu, ddpr, dcoef;
int nm;
int inti = parami->ielement;
int intj = paramj->ielement;
int inty = intype[inti][intj];
r = sqrt(rsq);
r3 = r * rsq;
esucon = force->qqr2e;
rcd = esucon/r3;
rct = 3.0*rcd/rsq;
alf = 0.2;
alfdpi = 2.0*alf/MY_PIS;
delr1[0] = delx;
delr1[1] = dely;
delr1[2] = delz;
// generate energy & force information from tables
erfcc = sr1*erpaw[mr1][0] + sr2*erpaw[mr2][0] + sr3*erpaw[mr3][0];
erfcd = sr1*erpaw[mr1][1] + sr2*erpaw[mr2][1] + sr3*erpaw[mr3][1];
dvdrr = (erfcc/r3+alfdpi*erfcd/rsq)*esucon-fac11;
ddvdrr = (2.0*erfcc/r3 + 2.0*alfdpi*erfcd*(1.0/rsq+alf*alf))*esucon;
dfafbnl= sr1*dfafb[mr1][inty] + sr2*dfafb[mr2][inty] + sr3*dfafb[mr3][inty];
phinn = sr1*phin[mr1][inti] + sr2*phin[mr2][inti] + sr3*phin[mr3][inti];
phinj = sr1*phin[mr1][intj] + sr2*phin[mr2][intj] + sr3*phin[mr3][intj];
dphinn = sr1*dphin[mr1][inti] + sr2*dphin[mr2][inti] + sr3*dphin[mr3][inti];
dphinj = sr1*dphin[mr1][intj] + sr2*dphin[mr2][intj] + sr3*dphin[mr3][intj];
ddfafbnl= sr1*ddfafb[mr1][inty] + sr2*ddfafb[mr2][inty] + sr3*ddfafb[mr3][inty];
ef = (dvdrr + dfafbnl * esucon)/r;
efn = jq * ef;
efj = -iq * ef;
def = (ddvdrr + ddfafbnl * esucon)/r;
defn = jq * def;
defj = -iq * def;
// dipole - dipole field tensor (Tij)
tmurn = dpl[i][0]*delr1[0] + dpl[i][1]*delr1[1] + dpl[i][2]*delr1[2];
tmurj = dpl[j][0]*delr1[0] + dpl[j][1]*delr1[1] + dpl[j][2]*delr1[2];
tmumu = dpl[i][0]*dpl[j][0] + dpl[i][1]*dpl[j][1] + dpl[i][2]*dpl[j][2];
for (nm=0; nm<3; nm++) {
poln[nm] = (tmurj*delr1[nm]*rct - dpl[j][nm]*rcd);
polj[nm] = (tmurn*delr1[nm]*rct - dpl[i][nm]*rcd);
}
tmun = dpl[j][0]*polj[0] + dpl[j][1]*polj[1] + dpl[j][2]*polj[2];
tmuj = dpl[i][0]*poln[0] + dpl[i][1]*poln[1] + dpl[i][2]*poln[2];
// dipole - dipole energy
emuTmu = -0.5*(tmun*phinn+tmuj*phinj);
// dipole - charge energy
edqn = -0.5 * (tmurn * efn);
edqj = -0.5 * (tmurj * efj);
// overall dipole energy
vionij = emuTmu + edqn + edqj;
// dipole - dipole force
demuTmu = (tmun*dphinn + tmuj*dphinj)/r;
ddpr = 5.0*tmurn*tmurj/rsq - tmumu;
dcoef = rct * (phinn+phinj);
for (nm = 0; nm < 3; nm ++) {
ddprx[nm] = dcoef * (ddpr*delr1[nm] - tmurn*dpl[j][nm] - tmurj*dpl[i][nm])
+ demuTmu * delr1[nm];
}
// dipole - charge force
fvionij = -tmurn*defn - tmurj*defj;
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fc_curl(double rocn, Param *param)
{
double r_inn = param->curlcut1;
double r_out = param->curlcut2;
if (rocn <= r_inn) return 1.0;
if (rocn >= r_out) return 0.0;
return 0.5*(1.0 + cos(MY_PI*(rocn-r_inn)/(r_out-r_inn)));
}
/* ---------------------------------------------------------------------- */
double PairComb3::comb_fc_curl_d(double rocn, Param *param)
{
double r_inn = param->curlcut1;
double r_out = param->curlcut2;
if (rocn <= r_inn) return 0.0;
if (rocn >= r_out) return 0.0;
return -MY_PI2/(r_out-r_inn)*sin(MY_PI*(rocn-r_inn)/(r_out-r_inn));
}
/* ---------------------------------------------------------------------- */
int PairComb3::heaviside(double rr)
{
if (rr <= 0.0) return 0;
else return 1;
}
/* ---------------------------------------------------------------------- */
double PairComb3::switching(double rr)
{
if (rr <= 0.0) return 1.0;
else if (rr >= 1.0) return 0.0;
else return heaviside(-rr)+heaviside(rr)*heaviside(1.0-rr)
* (1.0-(3.0-2.0*rr)*rr*rr);
}
/* ---------------------------------------------------------------------- */
double PairComb3::switching_d(double rr)
{
if (rr <= 0.0) return 0.0;
else if (rr >= 1.0) return 0.0;
else return heaviside(rr)*heaviside(1.0-rr)
* 6.0*rr*(rr-1.0);
}
/* ---------------------------------------------------------------------- */
int PairComb3::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
if (pack_flag == 1) {
for (i = 0; i < n; i ++) {
j = list[i];
buf[m++] = qf[j];
}
} else if (pack_flag == 2) {
for (i = 0; i < n; i ++) {
j = list[i];
buf[m++] = NCo[j];
}
}
return 1;
}
/* ---------------------------------------------------------------------- */
void PairComb3::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n ;
if (pack_flag == 1) {
for (i = first; i < last; i++)
qf[i] = buf[m++];
} else if (pack_flag == 2) {
for (i = first; i < last; i++)
NCo[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int PairComb3::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (pack_flag == 1) {
for (i = first; i < last; i++)
buf[m++] = qf[i];
} else if (pack_flag == 2) {
for (i = first; i < last; i++)
buf[m++] = NCo[i];
}
return 1;
}
/* ---------------------------------------------------------------------- */
void PairComb3::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
if (pack_flag == 1) {
for (i = 0; i < n; i++) {
j = list[i];
qf[j] += buf[m++];
}
} else if (pack_flag == 2) {
for (i = 0; i < n; i++) {
j = list[i];
NCo[j] += buf[m++];
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairComb3::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += nmax * sizeof(int);
bytes += nmax * 8.0 * sizeof(double);
bytes += 25000*2*sizeof(double);
for (int i = 0; i < comm->nthreads; i++)
bytes += ipage[i].size();
return bytes;
}
diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp
index cc511d59a..8ccb7ee8a 100644
--- a/src/MANYBODY/pair_lcbop.cpp
+++ b/src/MANYBODY/pair_lcbop.cpp
@@ -1,1292 +1,1292 @@
/* ----------------------------------------------------------------------
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: Dominik Wójt (Wroclaw University of Technology)
based on pair_airebo by Ase Henry (MIT)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "mpi.h"
#include "pair_lcbop.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_request.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 "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define MAXLINE 1024
#define TOL 1.0e-9
#define PGDELTA 1
/* ---------------------------------------------------------------------- */
PairLCBOP::PairLCBOP(LAMMPS *lmp) : Pair(lmp) {
single_enable = 0;
one_coeff = 1;
manybody_flag = 1;
ghostneigh = 1;
maxlocal = 0;
SR_numneigh = NULL;
SR_firstneigh = NULL;
ipage = NULL;
pgsize = oneatom = 0;
N = NULL;
M = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairLCBOP::~PairLCBOP()
{
memory->destroy(SR_numneigh);
memory->sfree(SR_firstneigh);
delete [] ipage;
memory->destroy(N);
memory->destroy(M);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairLCBOP::compute(int eflag, int vflag)
{
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = vflag_atom = 0;
SR_neigh();
FSR(eflag,vflag);
FLR(eflag,vflag);
if (vflag_fdotr) virial_fdotr_compute();
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairLCBOP::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairLCBOP::settings(int narg, char **arg) {
if( narg != 0 ) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairLCBOP::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 NULL
// map[i] = which element (0 for C) 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;
} else if (strcmp(arg[i],"C") == 0) {
map[i-2] = 0;
} 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 PairLCBOP::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style LCBOP requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style LCBOP requires newton pair on");
// need a full neighbor list, including neighbors of ghosts
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->ghost = 1;
// local SR 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 PairLCBOP::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
// cut3rebo = 3 SR distances
cut3rebo = 3.0 * r_2;
// cutmax = furthest distance from an owned atom
// at which another atom will feel force, i.e. the ghost cutoff
// for SR term in potential:
// interaction = M-K-I-J-L-N with I = owned and J = ghost
// I to N is max distance = 3 SR distances
// for V_LR term in potential:
// r_2_LR
// cutghost = SR cutoff used in SR_neigh() for neighbors of ghosts
double cutmax = MAX( cut3rebo,r_2_LR );
cutghost[i][j] = r_2;
cutLRsq = r_2_LR*r_2_LR;
cutghost[j][i] = cutghost[i][j];
r_2_sq = r_2*r_2;
return cutmax;
}
/* ----------------------------------------------------------------------
create SR neighbor list from main neighbor list
SR neighbor list stores neighbors of ghost atoms
------------------------------------------------------------------------- */
void PairLCBOP::SR_neigh()
{
int i,j,ii,jj,n,allnum,jnum;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
int *ilist,*jlist,*numneigh,**firstneigh;
int *neighptr;
double **x = atom->x;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if (atom->nmax > maxlocal) { // ensure ther is enough space
maxlocal = atom->nmax; // for atoms and ghosts allocated
memory->destroy(SR_numneigh);
memory->sfree(SR_firstneigh);
memory->destroy(N);
memory->destroy(M);
memory->create(SR_numneigh,maxlocal,"LCBOP:numneigh");
SR_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
"LCBOP:firstneigh");
memory->create(N,maxlocal,"LCBOP:N");
memory->create(M,maxlocal,"LCBOP:M");
}
allnum = list->inum + list->gnum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// store all SR 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];
N[i] = 0.0;
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 < r_2_sq) {
neighptr[n++] = j;
N[i] += f_c(sqrt(rsq),r_1,r_2,&dS);
}
}
SR_firstneigh[i] = neighptr;
SR_numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
// calculate M_i
for (ii = 0; ii < allnum; ii++) {
i = ilist[ii];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
M[i] = 0.0;
jlist = SR_firstneigh[i];
jnum = SR_numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < r_2_sq) {
double f_c_ij = f_c(sqrt(rsq),r_1,r_2,&dS);
double Nji = N[j]-f_c_ij;
// F(xij) = 1-f_c_LR(Nji, 2,3,&dummy)
M[i] += f_c_ij * ( 1-f_c_LR(Nji, 2,3,&dS) );
}
}
}
}
/* ----------------------------------------------------------------------
Short range forces and energy
------------------------------------------------------------------------- */
void PairLCBOP::FSR(int eflag, int vflag)
{
- int i,j,jj,ii,inum,itag,jtag;
+ int i,j,jj,ii,inum;
+ tagint itag,jtag;
double delx,dely,delz,fpair,xtmp,ytmp,ztmp;
double r_sq,rijmag,f_c_ij,df_c_ij;
double VR,dVRdi,VA,Bij,dVAdi,dVA;
double d_f_c_ij,del[3];
int *ilist,*SR_neighs;
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
inum = list->inum;
ilist = list->ilist;
// two-body interactions from SR neighbor list, skip half of them
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
SR_neighs = SR_firstneigh[i];
for (jj = 0; jj < SR_numneigh[i]; jj++) {
j = SR_neighs[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;
}
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
r_sq = delx*delx + dely*dely + delz*delz;
rijmag = sqrt(r_sq);
f_c_ij = f_c( rijmag,r_1,r_2,&df_c_ij );
if( f_c_ij <= TOL ) continue;
VR = A*exp(-alpha*rijmag);
dVRdi = -alpha*VR;
dVRdi = dVRdi*f_c_ij + df_c_ij*VR; // VR -> VR * f_c_ij
VR *= f_c_ij;
VA = dVA = 0.0;
{
double term = B_1 * exp(-beta_1*rijmag);
VA += term;
dVA += -beta_1 * term;
term = B_2 * exp(-beta_2*rijmag);
VA += term;
dVA += -beta_2 * term;
}
dVA = dVA*f_c_ij + df_c_ij*VA; // VA -> VA * f_c_ij
VA *= f_c_ij;
del[0] = delx;
del[1] = dely;
del[2] = delz;
Bij = bondorder(i,j,del,rijmag,VA,f,vflag_atom);
dVAdi = Bij*dVA;
// F = (dVRdi+dVAdi)*(-grad rijmag)
// grad_i rijmag = \vec{rij} /rijmag
// grad_j rijmag = -\vec{rij} /rijmag
fpair = -(dVRdi-dVAdi) / rijmag;
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;
double evdwl=0.0;
if (eflag) evdwl = VR - Bij*VA;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
/* ----------------------------------------------------------------------
compute long range forces and energy
------------------------------------------------------------------------- */
void PairLCBOP::FLR(int eflag, int vflag)
{
-
- int i,j,jj,m,ii,itag,jtag;
+ int i,j,jj,m,ii;
+ tagint itag,jtag;
double delx,dely,delz,fpair,xtmp,ytmp,ztmp;
double r_sq,rijmag,f_c_ij,df_c_ij;
double V,dVdi;
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int newton_pair = force->newton_pair;
-
int inum = list->inum;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
// two-body interactions from full neighbor list, skip half of them
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itag = tag[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
int *neighs = firstneigh[i];
for (jj = 0; jj < numneigh[i]; jj++) {
j = neighs[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;
}
delx = x[i][0] - x[j][0];
dely = x[i][1] - x[j][1];
delz = x[i][2] - x[j][2];
r_sq = delx*delx + dely*dely + delz*delz;
rijmag = sqrt(r_sq);
f_c_ij = 1-f_c( rijmag,r_1,r_2,&df_c_ij );
df_c_ij = -df_c_ij;
// derivative may be inherited from previous call, see f_c_LR definition
f_c_ij *= f_c_LR( rijmag, r_1_LR, r_2_LR, &df_c_ij );
if( f_c_ij <= TOL ) continue;
V = dVdi = 0;
if( rijmag<r_0 ) {
double exp_part = exp( -lambda_1*(rijmag-r_0) );
V = eps_1*( exp_part*exp_part - 2*exp_part) + v_1;
dVdi = 2*eps_1*lambda_1*exp_part*( 1-exp_part );
} else {
double exp_part = exp( -lambda_2*(rijmag-r_0) );
V = eps_2*( exp_part*exp_part - 2*exp_part) + v_2;
dVdi = 2*eps_2*lambda_2*exp_part*( 1-exp_part );
}
dVdi = dVdi*f_c_ij + df_c_ij*V; // V -> V * f_c_ij
V *= f_c_ij;
// F = (dVdi)*(-grad rijmag)
// grad_i rijmag = \vec{rij} /rijmag
// grad_j rijmag = -\vec{rij} /rijmag
fpair = -dVdi / rijmag;
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;
double evdwl=0.0;
if (eflag) evdwl = V;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
}
}
/* ----------------------------------------------------------------------
forces for Nij and Mij
------------------------------------------------------------------------- */
void PairLCBOP::FNij( int i, int j, double factor, double **f, int vflag_atom ) {
int atomi = i;
int atomj = j;
int *SR_neighs = SR_firstneigh[i];
double **x = atom->x;
for( int k=0; k<SR_numneigh[i]; k++ ) {
int atomk = SR_neighs[k];
if (atomk != atomj) {
double rik[3];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
double riksq = (rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]);
if( riksq > r_1*r_1 ) { // && riksq < r_2*r_2, if second condition not fulfilled neighbor would not be in the list
double rikmag = sqrt(riksq);
double df_c_ik;
double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
// F = factor*df_c_ik*(-grad rikmag)
// grad_i rikmag = \vec{rik} /rikmag
// grad_k rikmag = -\vec{rik} /rikmag
double fpair = -factor*df_c_ik / rikmag;
f[atomi][0] += rik[0]*fpair;
f[atomi][1] += rik[1]*fpair;
f[atomi][2] += rik[2]*fpair;
f[atomk][0] -= rik[0]*fpair;
f[atomk][1] -= rik[1]*fpair;
f[atomk][2] -= rik[2]*fpair;
if (vflag_atom) v_tally2(atomi,atomk,fpair,rik);
}
}
}
}
/* ---------------------------------------------------------------------- */
void PairLCBOP::FMij( int i, int j, double factor, double **f, int vflag_atom ) {
int atomi = i;
int atomj = j;
int *SR_neighs = SR_firstneigh[i];
double **x = atom->x;
for( int k=0; k<SR_numneigh[i]; k++ ) {
int atomk = SR_neighs[k];
if (atomk != atomj) {
double rik[3];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
double df_c_ik;
double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
double Nki = N[k]-(f_c_ik);
// double Mij = M[i] - f_c_ij*( 1-f_c(Nji, 2,3,&dummy) );
double dF=0;
double Fx = 1-f_c_LR(Nki, 2,3,&dF);
dF = -dF;
if( df_c_ik > TOL ) {
double factor2 = factor*df_c_ik*Fx;
// F = factor2*(-grad rikmag)
// grad_i rikmag = \vec{rik} /rikmag
// grad_k rikmag = -\vec{rik} /rikmag
double fpair = -factor2 / rikmag;
f[atomi][0] += rik[0]*fpair;
f[atomi][1] += rik[1]*fpair;
f[atomi][2] += rik[2]*fpair;
f[atomk][0] -= rik[0]*fpair;
f[atomk][1] -= rik[1]*fpair;
f[atomk][2] -= rik[2]*fpair;
if (vflag_atom) v_tally2(atomi,atomk,fpair,rik);
}
if( dF > TOL ) {
double factor2 = factor*f_c_ik*dF;
FNij( atomk, atomi, factor2, f, vflag_atom );
}
}
}
}
/* ----------------------------------------------------------------------
Bij function
------------------------------------------------------------------------- */
double PairLCBOP::bondorder(int i, int j, double rij[3],
double rijmag, double VA,
double **f, int vflag_atom)
{
double bij, bji;
/* bij & bji */{
double rji[3];
rji[0] = -rij[0]; rji[1] = -rij[1]; rji[2] = -rij[2];
bij = b(i,j,rij,rijmag,VA,f,vflag_atom);
bji = b(j,i,rji,rijmag,VA,f,vflag_atom);
}
double Fij_conj;
/* F_conj */{
double dummy;
double df_c_ij;
double f_c_ij = f_c( rijmag, r_1, r_2, &df_c_ij );
double Nij = MIN( 3, N[i]-(f_c_ij) );
double Nji = MIN( 3, N[j]-(f_c_ij) );
// F(xij) = 1-f_c(Nji, 2,3,&dummy)
double Mij = M[i] - f_c_ij*( 1-f_c(Nji, 2,3,&dummy) );
double Mji = M[j] - f_c_ij*( 1-f_c(Nij, 2,3,&dummy) );
Mij = MIN( Mij, 3 );
Mji = MIN( Mji, 3 );
double Nij_el, dNij_el_dNij, dNij_el_dMij;
double Nji_el, dNji_el_dNji, dNji_el_dMji;
{
double num_Nij_el = 4 - Mij;
double num_Nji_el = 4 - Mji;
double den_Nij_el = Nij + 1 - Mij;
double den_Nji_el = Nji + 1 - Mji;
Nij_el = num_Nij_el / den_Nij_el;
Nji_el = num_Nji_el / den_Nji_el;
dNij_el_dNij = -Nij_el/den_Nij_el;
dNji_el_dNji = -Nji_el/den_Nji_el;
dNij_el_dMij = ( -1 + Nij_el ) /den_Nij_el;
dNji_el_dMji = ( -1 + Nji_el ) /den_Nji_el;
}
double Nconj;
double dNconj_dNij;
double dNconj_dNji;
double dNconj_dNel;
{
double num_Nconj = ( Nij+1 )*( Nji+1 )*( Nij_el+Nji_el ) - 4*( Nij+Nji+2);
double den_Nconj = Nij*( 3-Nij )*( Nji+1 ) + Nji*( 3-Nji )*( Nij+1 ) + eps;
Nconj = num_Nconj / den_Nconj;
if( Nconj <= 0 ) {
Nconj = 0;
dNconj_dNij = 0;
dNconj_dNji = 0;
dNconj_dNel = 0;
} else if( Nconj >= 1 ) {
Nconj = 1;
dNconj_dNij = 0;
dNconj_dNji = 0;
dNconj_dNel = 0;
} else {
dNconj_dNij = (
( (Nji+1)*(Nij_el + Nji_el)-4)
- Nconj*( (Nji+1)*(3-2*Nij) + Nji*(3-Nji) )
) /den_Nconj;
dNconj_dNji = (
( (Nij+1)*(Nji_el + Nij_el)-4)
- Nconj*( (Nij+1)*(3-2*Nji) + Nij*(3-Nij) )
) /den_Nconj;
dNconj_dNel = (Nij+1)*(Nji+1) / den_Nconj;
}
}
double dF_dNij, dF_dNji, dF_dNconj;
Fij_conj = F_conj( Nij, Nji, Nconj, &dF_dNij, &dF_dNji, &dF_dNconj );
/*forces for Nij*/
if( 3-Nij > TOL ) {
double factor = -VA*0.5*( dF_dNij + dF_dNconj*( dNconj_dNij + dNconj_dNel*dNij_el_dNij ) );
FNij( i, j, factor, f, vflag_atom );
}
/*forces for Nji*/
if( 3-Nji > TOL ) {
double factor = -VA*0.5*( dF_dNji + dF_dNconj*( dNconj_dNji + dNconj_dNel*dNji_el_dNji ) );
FNij( j, i, factor, f, vflag_atom );
}
/*forces for Mij*/
if( 3-Mij > TOL ) {
double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNij_el_dMij );
FMij( i, j, factor, f, vflag_atom );
}
if( 3-Mji > TOL ) {
double factor = -VA*0.5*( dF_dNconj*dNconj_dNel*dNji_el_dMji );
FMij( j, i, factor, f, vflag_atom );
}
}
double Bij = 0.5*( bij + bji + Fij_conj );
return Bij;
}
/* ----------------------------------------------------------------------
bij function
------------------------------------------------------------------------- */
double PairLCBOP::b(int i, int j, double rij[3],
double rijmag, double VA,
double **f, int vflag_atom) {
int *SR_neighs = SR_firstneigh[i];
double **x = atom->x;
int atomi = i;
int atomj = j;
//calculate bij magnitude
double bij = 1.0;
for (int k = 0; k < SR_numneigh[i]; k++) {
int atomk = SR_neighs[k];
if (atomk != atomj) {
double rik[3];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
double delta_ijk = rijmag-rikmag;
double dummy;
double f_c_ik = f_c( rikmag, r_1, r_2, &dummy );
double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2]))
/ (rijmag*rikmag);
cos_ijk = MIN(cos_ijk,1.0);
cos_ijk = MAX(cos_ijk,-1.0);
double G = gSpline(cos_ijk, &dummy);
double H = hSpline(delta_ijk, &dummy);
bij += (f_c_ik*G*H);
}
}
bij = pow( bij, -delta );
// bij forces
for (int k = 0; k < SR_numneigh[i]; k++) {
int atomk = SR_neighs[k];
if (atomk != atomj) {
double rik[3];
rik[0] = x[atomi][0]-x[atomk][0];
rik[1] = x[atomi][1]-x[atomk][1];
rik[2] = x[atomi][2]-x[atomk][2];
double rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2]));
double delta_ijk = rijmag-rikmag;
double df_c_ik;
double f_c_ik = f_c( rikmag, r_1, r_2, &df_c_ik );
double cos_ijk = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2]))
/ (rijmag*rikmag);
cos_ijk = MIN(cos_ijk,1.0);
cos_ijk = MAX(cos_ijk,-1.0);
double dcos_ijk_dri[3],dcos_ijk_drj[3],dcos_ijk_drk[3];
dcos_ijk_drj[0] = -rik[0] / (rijmag*rikmag)
+ cos_ijk * rij[0] / (rijmag*rijmag);
dcos_ijk_drj[1] = -rik[1] / (rijmag*rikmag)
+ cos_ijk * rij[1] / (rijmag*rijmag);
dcos_ijk_drj[2] = -rik[2] / (rijmag*rikmag)
+ cos_ijk * rij[2] / (rijmag*rijmag);
dcos_ijk_drk[0] = -rij[0] / (rijmag*rikmag)
+ cos_ijk * rik[0] / (rikmag*rikmag);
dcos_ijk_drk[1] = -rij[1] / (rijmag*rikmag)
+ cos_ijk * rik[1] / (rikmag*rikmag);
dcos_ijk_drk[2] = -rij[2] / (rijmag*rikmag)
+ cos_ijk * rik[2] / (rikmag*rikmag);
dcos_ijk_dri[0] = -dcos_ijk_drk[0] - dcos_ijk_drj[0];
dcos_ijk_dri[1] = -dcos_ijk_drk[1] - dcos_ijk_drj[1];
dcos_ijk_dri[2] = -dcos_ijk_drk[2] - dcos_ijk_drj[2];
double dG, dH;
double G = gSpline( cos_ijk, &dG );
double H = hSpline( delta_ijk, &dH );
double tmp = -VA*0.5*(-0.5*bij*bij*bij);
double fi[3], fj[3], fk[3];
double tmp2 = -tmp*df_c_ik*G*H/rikmag;
// F = tmp*df_c_ik*G*H*(-grad rikmag)
// grad_i rikmag = \vec{rik} /rikmag
// grad_k rikmag = -\vec{rik} /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];
tmp2 = -tmp*f_c_ik*dG*H;
// F = tmp*f_c_ik*dG*H*(-grad cos_ijk)
// grad_i cos_ijk = dcos_ijk_dri
// grad_j cos_ijk = dcos_ijk_drj
// grad_k cos_ijk = dcos_ijk_drk
fi[0] += tmp2*dcos_ijk_dri[0];
fi[1] += tmp2*dcos_ijk_dri[1];
fi[2] += tmp2*dcos_ijk_dri[2];
fj[0] = tmp2*dcos_ijk_drj[0];
fj[1] = tmp2*dcos_ijk_drj[1];
fj[2] = tmp2*dcos_ijk_drj[2];
fk[0] += tmp2*dcos_ijk_drk[0];
fk[1] += tmp2*dcos_ijk_drk[1];
fk[2] += tmp2*dcos_ijk_drk[2];
tmp2 = -tmp*f_c_ik*G*dH;
// F = tmp*f_c_ik*G*dH*(-grad delta_ijk)
// grad_i delta_ijk = \vec{rij} /rijmag - \vec{rik} /rijmag
// grad_j delta_ijk = -\vec{rij} /rijmag
// grad_k delta_ijk = \vec{rik} /rikmag
fi[0] += tmp2*( rij[0]/rijmag - rik[0]/rikmag );
fi[1] += tmp2*( rij[1]/rijmag - rik[1]/rikmag );
fi[2] += tmp2*( rij[2]/rijmag - rik[2]/rikmag );
fj[0] += tmp2*( -rij[0]/rijmag );
fj[1] += tmp2*( -rij[1]/rijmag );
fj[2] += tmp2*( -rij[2]/rijmag );
fk[0] += tmp2*( rik[0]/rikmag );
fk[1] += tmp2*( rik[1]/rikmag );
fk[2] += tmp2*( rik[2]/rikmag );
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) {
double rji[3], rki[3];
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);
}
}
}
return bij;
}
/* ----------------------------------------------------------------------
spline interpolation for G
------------------------------------------------------------------------- */
void PairLCBOP::g_decompose_x( double x, size_t *field_idx, double *offset ) {
size_t i=0;
while( i<(6-1) && !( x<gX[i+1] ) )
i++;
*field_idx = i;
*offset = ( x - gX[i] );
}
/* ---------------------------------------------------------------------- */
double PairLCBOP::gSpline( double x, double *dgdc ) {
size_t i;
double x_n;
g_decompose_x( x, &i, &x_n );
double sum = 0;
*dgdc = 0;
double pow_x_n = 1.0;
for( size_t j=0; j<5; j++ ) {
sum += gC[j][i]*pow_x_n;
*dgdc += gC[j+1][i]*(j+1)*pow_x_n;
pow_x_n *= x_n;
}
sum += gC[5][i]*pow_x_n;
return sum;
}
/* ---------------------------------------------------------------------- */
double PairLCBOP::hSpline( double x, double *dhdx ) {
if( x < -d ) {
double z = kappa*( x+d );
double y = pow(z, 10.0);
double w = pow( 1+y, -0.1 );
*dhdx = kappa*L*w/(1+y);
return L*( 1 + z*w );
}
if( x > d ) {
*dhdx = R_1;
return R_0 + R_1*( x-d );
}
double result = 1 + C_1*x;
*dhdx = C_1*result;
double pow_x = x*x;
result += 0.5*C_1*C_1*pow_x;
pow_x *= x;// == x^3
*dhdx += 4*C_4*pow_x;
pow_x *= x;// == x^4
result += C_4*pow_x;
pow_x *= x;// == x^5
*dhdx += 6*C_6*pow_x;
pow_x *= x;// == x^5
result += C_6*pow_x;
return result;
}
/* ---------------------------------------------------------------------- */
double PairLCBOP::F_conj( double N_ij, double N_ji, double N_conj_ij, double *dFN_ij, double *dFN_ji, double *dFN_ij_conj ) {
size_t N_ij_int = MIN( static_cast<size_t>( floor( N_ij ) ), 2 ); // 2 is the highest number of field
size_t N_ji_int = MIN( static_cast<size_t>( floor( N_ji ) ), 2 ); // cast to suppress warning
double x = N_ij - N_ij_int;
double y = N_ji - N_ji_int;
const TF_conj_field &f0 = F_conj_field[N_ij_int][N_ji_int][0];
const TF_conj_field &f1 = F_conj_field[N_ij_int][N_ji_int][1];
double F_0 = 0;
double F_1 = 0;
double dF_0_dx = 0, dF_0_dy = 0;
double dF_1_dx = 0, dF_1_dy = 0;
double l, r;
if( N_conj_ij < 1 ) {
l = (1-y)* (1-x); r = ( f0.f_00 + x* x* f0.f_x_10 + y* y* f0.f_y_01 ); F_0 += l*r; dF_0_dx += -(1-y)*r +l*2*x* f0.f_x_10; dF_0_dy += -(1-x)*r +l*2*y* f0.f_y_01;
l = (1-y)* x; r = ( f0.f_10 + (1-x)*(1-x)*f0.f_x_00 + y* y* f0.f_y_11 ); F_0 += l*r; dF_0_dx += (1-y)*r -l*2*(1-x)*f0.f_x_00; dF_0_dy += -x* r +l*2*y* f0.f_y_11;
l = y* (1-x); r = ( f0.f_01 + x* x* f0.f_x_11 + (1-y)*(1-y)*f0.f_y_00 ); F_0 += l*r; dF_0_dx += -y* r +l*2*x* f0.f_x_11; dF_0_dy += (1-x)*r -l*2*(1-y)*f0.f_y_00;
l = y* x; r = ( f0.f_11 + (1-x)*(1-x)*f0.f_x_01 + (1-y)*(1-y)*f0.f_y_10 ); F_0 += l*r; dF_0_dx += y* r -l*2*(1-x)*f0.f_x_01; dF_0_dy += x* r -l*2*(1-y)*f0.f_y_10;
}
if( N_conj_ij > 0 ) {
l = (1-y)* (1-x); r = ( f0.f_00 + x* x* f1.f_x_10 + y* y* f1.f_y_01 ); F_1 += l*r; dF_1_dx += -(1-y)*r +l*2*x* f1.f_x_10; dF_1_dy += -(1-x)*r +l*2*y* f1.f_y_01;
l = (1-y)* x; r = ( f1.f_10 + (1-x)*(1-x)*f1.f_x_00 + y* y* f1.f_y_11 ); F_1 += l*r; dF_1_dx += (1-y)*r -l*2*(1-x)*f1.f_x_00; dF_1_dy += -x* r +l*2*y* f1.f_y_11;
l = y* (1-x); r = ( f1.f_01 + x* x* f1.f_x_11 + (1-y)*(1-y)*f1.f_y_00 ); F_1 += l*r; dF_1_dx += -y* r +l*2*x* f1.f_x_11; dF_1_dy += (1-x)*r -l*2*(1-y)*f1.f_y_00;
l = y* x; r = ( f1.f_11 + (1-x)*(1-x)*f1.f_x_01 + (1-y)*(1-y)*f1.f_y_10 ); F_1 += l*r; dF_1_dx += y* r -l*2*(1-x)*f1.f_x_01; dF_1_dy += x* r -l*2*(1-y)*f1.f_y_10;
}
double result = (1-N_conj_ij)*F_0 + N_conj_ij*F_1;
*dFN_ij = (1-N_conj_ij)*dF_0_dx + N_conj_ij*dF_1_dx;
*dFN_ji = (1-N_conj_ij)*dF_0_dy + N_conj_ij*dF_1_dy;
*dFN_ij_conj = -F_0 + F_1;
return result;
}
/* ----------------------------------------------------------------------
read LCBOP potential file
------------------------------------------------------------------------- */
void PairLCBOP::read_file(char *filename)
{
int i,j,k,l,limit;
char s[MAXLINE];
MPI_Comm_rank(world,&me);
// read file on proc 0
if (me == 0) {
FILE *fp = open_potential(filename);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open LCBOP 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",&r_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&gamma_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&A);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&B_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&B_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&alpha);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&beta_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&beta_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&d);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_4);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&C_6);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&L);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&kappa);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&R_0);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&R_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_0);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_1_LR);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&r_2_LR);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&v_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&v_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&lambda_1);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&lambda_2);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&eps);
fgets(s,MAXLINE,fp); sscanf(s,"%lg",&delta);
while (1) {
fgets(s,MAXLINE,fp);
if (s[0] != '#') break;
}
// F_conj spline
for (k = 0; k < 2; k++) { // 2 values of N_ij_conj
for (l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy
for (i = 0; i < 4; i++) { // 4x4 matrix
fgets(s,MAXLINE,fp);
sscanf(s,"%lg %lg %lg %lg",
&F_conj_data[i][0][k][l],
&F_conj_data[i][1][k][l],
&F_conj_data[i][2][k][l],
&F_conj_data[i][3][k][l]);
}
while (1) { fgets(s,MAXLINE,fp); if (s[0] != '#') break; }
}
}
// G spline
// x coordinates of mesh points
fgets(s,MAXLINE,fp);
sscanf( s,"%lg %lg %lg %lg %lg %lg",
&gX[0], &gX[1], &gX[2],
&gX[3], &gX[4], &gX[5] );
for (i = 0; i < 6; i++) { // for each power in polynomial
fgets(s,MAXLINE,fp);
sscanf( s,"%lg %lg %lg %lg %lg",
&gC[i][0], &gC[i][1], &gC[i][2],
&gC[i][3], &gC[i][4] );
}
fclose(fp);
}
// broadcast read-in and setup values
MPI_Bcast(&r_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&r_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&gamma_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&A ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&B_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&B_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&alpha ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&beta_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&beta_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&d ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&C_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&C_4 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&C_6 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&L ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&kappa ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&R_0 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&R_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&r_0 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&r_1_LR ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&r_2_LR ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&v_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&v_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&eps_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&eps_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda_1 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&lambda_2 ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&eps ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&delta ,1,MPI_DOUBLE,0,world);
MPI_Bcast(&gX[0] ,6,MPI_DOUBLE,0,world);
MPI_Bcast(&gC[0][0] ,(6-1)*(5+1),MPI_DOUBLE,0,world);
MPI_Bcast(&F_conj_data[0],6*4*4,MPI_DOUBLE,0,world);
}
/* ----------------------------------------------------------------------
init coefficients for TF_conj
------------------------------------------------------------------------- */
#include <iostream>
#include <fstream>
#include <functional>
template< class function > void print_function( double x_0, double x_1, size_t n, function f, std::ostream &stream ) {
double dx = (x_1-x_0)/n;
for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
double f_val, df;
f_val = f(x, &df);
stream << x << " " << f_val << " " << df << std::endl;
}
stream << std::endl;
}
void PairLCBOP::spline_init() {
for( size_t N_conj_ij=0; N_conj_ij<2; N_conj_ij++ ) // N_conj_ij
for( size_t N_ij=0; N_ij<4-1; N_ij++ )
for( size_t N_ji=0; N_ji<4-1; N_ji++ ) {
TF_conj_field &field = F_conj_field[N_ij][N_ji][N_conj_ij];
field.f_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][0];
field.f_01 = F_conj_data[N_ij ][N_ji+1][N_conj_ij][0];
field.f_10 = F_conj_data[N_ij+1][N_ji ][N_conj_ij][0];
field.f_11 = F_conj_data[N_ij+1][N_ji+1][N_conj_ij][0];
field.f_x_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][1] - field.f_10 + field.f_00;
field.f_x_01 = F_conj_data[N_ij ][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01;
field.f_x_10 = -(F_conj_data[N_ij+1][N_ji ][N_conj_ij][1] - field.f_10 + field.f_00);
field.f_x_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][1] - field.f_11 + field.f_01);
field.f_y_00 = F_conj_data[N_ij ][N_ji ][N_conj_ij][2] - field.f_01 + field.f_00;
field.f_y_01 = -(F_conj_data[N_ij ][N_ji+1][N_conj_ij][2] - field.f_01 + field.f_00);
field.f_y_10 = F_conj_data[N_ij+1][N_ji ][N_conj_ij][2] - field.f_11 + field.f_10;
field.f_y_11 = -(F_conj_data[N_ij+1][N_ji+1][N_conj_ij][2] - field.f_11 + field.f_10);
}
//some testing:
// std::ofstream file( "test.txt" );
// file << "gX:\n";
// file << gX[0] << " "
// << gX[1] << " "
// << gX[2] << " "
// << gX[3] << " "
// << gX[4] << " "
// << gX[5] << std::endl;
// file << "gC:\n";
// for( int i=0; i<6; i++ )
// file << gC[i][0] << " "
// << gC[i][1] << " "
// << gC[i][2] << " "
// << gC[i][3] << " "
// << gC[i][4] << std::endl;
// file << std::endl;
//
// file << "gamma_1 = " << gamma_1 << std::endl;
// file << "r_1 = " << r_1 << std::endl;
// file << "r_2 = " << r_2 << std::endl;
// file << "A = " << A << std::endl;
// file << "B_1 = " << B_1 << std::endl;
// file << "B_2 = " << B_2 << std::endl;
// file << "alpha = " << alpha << std::endl;
// file << "beta_1 = " << beta_1 << std::endl;
// file << "beta_2 = " << beta_2 << std::endl;
// file << "d = " << d << std::endl;
// file << "C_1 = " << C_1 << std::endl;
// file << "C_4 = " << C_4 << std::endl;
// file << "C_6 = " << C_6 << std::endl;
// file << "L = " << L << std::endl;
// file << "kappa = " << kappa << std::endl;
// file << "R_0 = " << R_0 << std::endl;
// file << "R_1 = " << R_1 << std::endl;
// file << "r_0 = " << r_0 << std::endl;
// file << "r_1_LR = " << r_1_LR << std::endl;
// file << "r_2_LR = " << r_2_LR << std::endl;
// file << "v_1 = " << v_1 << std::endl;
// file << "v_2 = " << v_2 << std::endl;
// file << "eps_1 = " << eps_1 << std::endl;
// file << "eps_2 = " << eps_2 << std::endl;
// file << "lambda_1 = " << lambda_1 << std::endl;
// file << "lambda_2 = " << lambda_2 << std::endl;
// file << "eps = " << eps << std::endl;
// file << "delta = " << delta << std::endl;
// file << "r_2_sq = " << r_2_sq << std::endl;
// file << std::endl;
//
//
// file << "gSpline:" << std::endl;
// double x_1 = 1, x_0 = -1;
// int n=1000;
// double dx = (x_1-x_0)/n;
// for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
// double g, dg;
// g = gSpline(x, &dg);
// file << x << " " << g << " " << dg << std::endl;
// }
// file << std::endl;
//
// file << "hSpline:" << std::endl;
// double x_1 = 1, x_0 = -1;
// int n=1000;
// double dx = (x_1-x_0)/n;
// for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
// double h, dh;
// h = hSpline(x, &dh);
// file << x << " " << h << " " << dh << std::endl;
// }
// file << std::endl;
//
//
// file << "f_c:" << std::endl;
// double x_1 = 4, x_0 = 0;
// int n=1000;
// double dx = (x_1-x_0)/n;
// for( double x=x_0; x<=x_1+0.0001; x+=dx ) {
// double f, df;
// f = f_c(x, r_1, r_2, &df);
// file << x << " " << f << " " << df << std::endl;
// }
// file << std::endl;
// file << "F_conj_data\n";
// for (int k = 0; k < 2; k++) { // 2 values of N_ij_conj
// for (int l = 0; l < 3; l++) { // 3 types of data: f, dfdx, dfdy
// for (int i = 0; i < 4; i++) { // 4x4 matrix
// file
// << F_conj_data[i][0][k][l] << " "
// << F_conj_data[i][1][k][l] << " "
// << F_conj_data[i][2][k][l] << " "
// << F_conj_data[i][3][k][l] << std::endl;
// }
// file << std::endl;
// }
// }
//
//
// file << "F_conj_0 ";
// double dummy;
// for( double y=0; y<=3.0+0.0001; y+=0.1 )
// file << y << " ";
// file << std::endl;
// for( double x=0; x<=3.0+0.0001; x+=0.1 ){
// file << x << " ";
// for( double y=0; y<=3.0+0.0001; y+=0.1 )
// file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " ";
// file << std::endl;
// }
//
// file << "dF0_dx ";
// for( double y=0; y<=3.0+0.0001; y+=0.1 )
// file << y << " ";
// file << std::endl;
// for( double x=0; x<=3.0+0.0001; x+=0.1 ){
// file << x << " ";
// for( double y=0; y<=3.0+0.0001; y+=0.1 ) {
// double dF_dx;
// F_conj( x, y, 0, &dF_dx, &dummy, &dummy );
// file << dF_dx << " ";
// }
// file << std::endl;
// }
//
//
//
// file << "F_conj_1 ";
// for( double y=0; y<=3.0+0.0001; y+=0.1 )
// file << y << " ";
// file << std::endl;
// for( double x=0; x<=3.0+0.0001; x+=0.1 ){
// file << x << " ";
// for( double y=0; y<=3.0+0.0001; y+=0.1 )
// file << F_conj( x, y, 0, &dummy, &dummy, &dummy ) << " ";
// file << std::endl;
// }
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairLCBOP::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 += 3*maxlocal * sizeof(double);
return bytes;
}
diff --git a/src/MANYBODY/pair_nb3b_harmonic.cpp b/src/MANYBODY/pair_nb3b_harmonic.cpp
index db1e816c6..0f7b78792 100644
--- a/src/MANYBODY/pair_nb3b_harmonic.cpp
+++ b/src/MANYBODY/pair_nb3b_harmonic.cpp
@@ -1,530 +1,531 @@
/* ----------------------------------------------------------------------
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: Todd R. Zeitler (SNL)
(based on Stillinger-Weber pair style)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_nb3b_harmonic.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
#define DELTA 4
#define SMALL 0.001
#define PI 3.141592653589793238462643383279
/* ---------------------------------------------------------------------- */
PairNb3bHarmonic::PairNb3bHarmonic(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
manybody_flag = 1;
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairNb3bHarmonic::~PairNb3bHarmonic()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairNb3bHarmonic::compute(int eflag, int vflag)
{
- int i,j,k,ii,jj,kk,inum,jnum,jnumm1,itag,jtag;
+ int i,j,k,ii,jj,kk,inum,jnum,jnumm1;
int itype,jtype,ktype,ijparam,ikparam,ijkparam;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl;
double rsq,rsq1,rsq2;
double delr1[3],delr2[3],fj[3],fk[3];
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 *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over full neighbor list of my atoms
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];
// two-body interactions, skip half of them
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]];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
ijparam = elem2param[itype][jtype][jtype];
if (rsq > params[ijparam].cutsq) continue;
}
jnumm1 = jnum - 1;
for (jj = 0; jj < jnumm1; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
if (rsq1 > params[ijparam].cutsq) continue;
for (kk = jj+1; kk < jnum; kk++) {
k = jlist[kk];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
if (rsq2 > params[ikparam].cutsq) continue;
threebody(&params[ijparam],&params[ikparam],&params[ijkparam],
rsq1,rsq2,delr1,delr2,fj,fk,eflag,evdwl);
f[i][0] -= fj[0] + fk[0];
f[i][1] -= fj[1] + fk[1];
f[i][2] -= fj[2] + fk[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];
if (evflag) ev_tally3(i,j,k,evdwl,0.0,fj,fk,delr1,delr2);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairNb3bHarmonic::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairNb3bHarmonic::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairNb3bHarmonic::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
// clear setflag since coeff() called once with I,J = * *
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 PairNb3bHarmonic::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style nb3b/harmonic requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style nb3b/harmonic requires newton pair on");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairNb3bHarmonic::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairNb3bHarmonic::read_file(char *file)
{
int params_per_line = 6;
char **words = new char*[params_per_line+1];
memory->sfree(params);
params = NULL;
nparams = maxparam = 0;
// open file on proc 0
FILE *fp = NULL;
if (comm->me == 0) {
fp = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open nb3b/harmonic potential file %s",file);
error->one(FLERR,str);
}
}
// read each set of params from potential file
// one set of params can span multiple lines
// store params if all 3 element tags are in element list
int n,nwords,ielement,jelement,kelement;
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,"Incorrect format in nb3b/harmonic 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next entry in file
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].k_theta = atof(words[3]);
params[nparams].theta0 = atof(words[4]);
params[nparams].cutoff = atof(words[5]);
if (params[nparams].k_theta < 0.0 || params[nparams].theta0 < 0.0 ||
params[nparams].cutoff < 0.0)
error->all(FLERR,"Illegal nb3b/harmonic parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairNb3bHarmonic::setup()
{
int i,j,k,m,n;
double rtmp;
// set elem2param for all triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// compute parameter values derived from inputs
// set cutsq using shortcut to reduce neighbor list for accelerated
// calculations. cut must remain unchanged as it is a potential parameter
// (cut = a*sigma)
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].cutoff;
params[m].cutsq = params[m].cut * params[m].cut;
params[m].theta0 = params[m].theta0 / 180.0 * PI;
}
// set cutmax to max of all params
cutmax = 0.0;
for (m = 0; m < nparams; m++) {
rtmp = sqrt(params[m].cutsq);
if (rtmp > cutmax) cutmax = rtmp;
}
}
/* ---------------------------------------------------------------------- */
void PairNb3bHarmonic::threebody(Param *paramij, Param *paramik,
Param *paramijk,
double rsq1, double rsq2,
double *delr1, double *delr2,
double *fj, double *fk, int eflag, double &eng)
{
double dtheta,tk;
double r1,r2,c,s,a,a11,a12,a22;
// angle (cos and sin)
r1 = sqrt(rsq1);
r2 = sqrt(rsq2);
c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2];
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
s = 1.0/s;
// force & energy
dtheta = acos(c) - paramijk->theta0;
tk = paramijk->k_theta * dtheta;
if (eflag) eng = tk*dtheta;
a = -2.0 * tk * s;
a11 = a*c / rsq1;
a12 = -a / (r1*r2);
a22 = a*c / rsq2;
fj[0] = a11*delr1[0] + a12*delr2[0];
fj[1] = a11*delr1[1] + a12*delr2[1];
fj[2] = a11*delr1[2] + a12*delr2[2];
fk[0] = a22*delr2[0] + a12*delr1[0];
fk[1] = a22*delr2[1] + a12*delr1[1];
fk[2] = a22*delr2[2] + a12*delr1[2];
}
diff --git a/src/MANYBODY/pair_sw.cpp b/src/MANYBODY/pair_sw.cpp
index d3cc16838..3928ff0d0 100644
--- a/src/MANYBODY/pair_sw.cpp
+++ b/src/MANYBODY/pair_sw.cpp
@@ -1,603 +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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Aidan Thompson (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_sw.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
#define DELTA 4
/* ---------------------------------------------------------------------- */
PairSW::PairSW(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairSW::~PairSW()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairSW::compute(int eflag, int vflag)
{
- int i,j,k,ii,jj,kk,inum,jnum,jnumm1,itag,jtag;
+ int i,j,k,ii,jj,kk,inum,jnum,jnumm1;
int itype,jtype,ktype,ijparam,ikparam,ijkparam;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,rsq1,rsq2;
double delr1[3],delr2[3],fj[3],fk[3];
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 *tag = atom->tag;
+ 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 full neighbor list of my atoms
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];
// two-body interactions, skip half of them
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]];
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
ijparam = elem2param[itype][jtype][jtype];
if (rsq > params[ijparam].cutsq) continue;
twobody(&params[ijparam],rsq,fpair,eflag,evdwl);
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 (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
jnumm1 = jnum - 1;
for (jj = 0; jj < jnumm1; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
if (rsq1 > params[ijparam].cutsq) continue;
for (kk = jj+1; kk < jnum; kk++) {
k = jlist[kk];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
if (rsq2 > params[ikparam].cutsq) continue;
threebody(&params[ijparam],&params[ikparam],&params[ijkparam],
rsq1,rsq2,delr1,delr2,fj,fk,eflag,evdwl);
f[i][0] -= fj[0] + fk[0];
f[i][1] -= fj[1] + fk[1];
f[i][2] -= fj[2] + fk[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];
if (evflag) ev_tally3(i,j,k,evdwl,0.0,fj,fk,delr1,delr2);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairSW::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairSW::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairSW::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
// clear setflag since coeff() called once with I,J = * *
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 PairSW::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style Stillinger-Weber requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style Stillinger-Weber requires newton pair on");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairSW::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairSW::read_file(char *file)
{
int params_per_line = 14;
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 = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open Stillinger-Weber potential file %s",file);
error->one(FLERR,str);
}
}
// read each set of params from potential file
// one set of params can span multiple lines
// store params if all 3 element tags are in element list
int n,nwords,ielement,jelement,kelement;
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,"Incorrect format in Stillinger-Weber 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next entry in file
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].epsilon = atof(words[3]);
params[nparams].sigma = atof(words[4]);
params[nparams].littlea = atof(words[5]);
params[nparams].lambda = atof(words[6]);
params[nparams].gamma = atof(words[7]);
params[nparams].costheta = atof(words[8]);
params[nparams].biga = atof(words[9]);
params[nparams].bigb = atof(words[10]);
params[nparams].powerp = atof(words[11]);
params[nparams].powerq = atof(words[12]);
params[nparams].tol = atof(words[13]);
if (params[nparams].epsilon < 0.0 || params[nparams].sigma < 0.0 ||
params[nparams].littlea < 0.0 || params[nparams].lambda < 0.0 ||
params[nparams].gamma < 0.0 || params[nparams].biga < 0.0 ||
params[nparams].bigb < 0.0 || params[nparams].powerp < 0.0 ||
params[nparams].powerq < 0.0 || params[nparams].tol < 0.0)
error->all(FLERR,"Illegal Stillinger-Weber parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairSW::setup()
{
int i,j,k,m,n;
double rtmp;
// set elem2param for all triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// compute parameter values derived from inputs
// set cutsq using shortcut to reduce neighbor list for accelerated
// calculations. cut must remain unchanged as it is a potential parameter
// (cut = a*sigma)
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].sigma*params[m].littlea;
rtmp = params[m].cut;
if (params[m].tol > 0.0) {
if (params[m].tol > 0.01) params[m].tol = 0.01;
if (params[m].gamma < 1.0)
rtmp = rtmp +
params[m].gamma * params[m].sigma / log(params[m].tol);
else rtmp = rtmp +
params[m].sigma / log(params[m].tol);
}
params[m].cutsq = rtmp * rtmp;
params[m].sigma_gamma = params[m].sigma*params[m].gamma;
params[m].lambda_epsilon = params[m].lambda*params[m].epsilon;
params[m].lambda_epsilon2 = 2.0*params[m].lambda*params[m].epsilon;
params[m].c1 = params[m].biga*params[m].epsilon *
params[m].powerp*params[m].bigb *
pow(params[m].sigma,params[m].powerp);
params[m].c2 = params[m].biga*params[m].epsilon*params[m].powerq *
pow(params[m].sigma,params[m].powerq);
params[m].c3 = params[m].biga*params[m].epsilon*params[m].bigb *
pow(params[m].sigma,params[m].powerp+1.0);
params[m].c4 = params[m].biga*params[m].epsilon *
pow(params[m].sigma,params[m].powerq+1.0);
params[m].c5 = params[m].biga*params[m].epsilon*params[m].bigb *
pow(params[m].sigma,params[m].powerp);
params[m].c6 = params[m].biga*params[m].epsilon *
pow(params[m].sigma,params[m].powerq);
}
// set cutmax to max of all params
cutmax = 0.0;
for (m = 0; m < nparams; m++) {
rtmp = sqrt(params[m].cutsq);
if (rtmp > cutmax) cutmax = rtmp;
}
}
/* ---------------------------------------------------------------------- */
void PairSW::twobody(Param *param, double rsq, double &fforce,
int eflag, double &eng)
{
double r,rinvsq,rp,rq,rainv,rainvsq,expsrainv;
r = sqrt(rsq);
rinvsq = 1.0/rsq;
rp = pow(r,-param->powerp);
rq = pow(r,-param->powerq);
rainv = 1.0 / (r - param->cut);
rainvsq = rainv*rainv*r;
expsrainv = exp(param->sigma * rainv);
fforce = (param->c1*rp - param->c2*rq +
(param->c3*rp -param->c4*rq) * rainvsq) * expsrainv * rinvsq;
if (eflag) eng = (param->c5*rp - param->c6*rq) * expsrainv;
}
/* ---------------------------------------------------------------------- */
void PairSW::threebody(Param *paramij, Param *paramik, Param *paramijk,
double rsq1, double rsq2,
double *delr1, double *delr2,
double *fj, double *fk, int eflag, double &eng)
{
double r1,rinvsq1,rainv1,gsrainv1,gsrainvsq1,expgsrainv1;
double r2,rinvsq2,rainv2,gsrainv2,gsrainvsq2,expgsrainv2;
double rinv12,cs,delcs,delcssq,facexp,facrad,frad1,frad2;
double facang,facang12,csfacang,csfac1,csfac2;
r1 = sqrt(rsq1);
rinvsq1 = 1.0/rsq1;
rainv1 = 1.0/(r1 - paramij->cut);
gsrainv1 = paramij->sigma_gamma * rainv1;
gsrainvsq1 = gsrainv1*rainv1/r1;
expgsrainv1 = exp(gsrainv1);
r2 = sqrt(rsq2);
rinvsq2 = 1.0/rsq2;
rainv2 = 1.0/(r2 - paramik->cut);
gsrainv2 = paramik->sigma_gamma * rainv2;
gsrainvsq2 = gsrainv2*rainv2/r2;
expgsrainv2 = exp(gsrainv2);
rinv12 = 1.0/(r1*r2);
cs = (delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]) * rinv12;
delcs = cs - paramijk->costheta;
delcssq = delcs*delcs;
facexp = expgsrainv1*expgsrainv2;
// facrad = sqrt(paramij->lambda_epsilon*paramik->lambda_epsilon) *
// facexp*delcssq;
facrad = paramijk->lambda_epsilon * facexp*delcssq;
frad1 = facrad*gsrainvsq1;
frad2 = facrad*gsrainvsq2;
facang = paramijk->lambda_epsilon2 * facexp*delcs;
facang12 = rinv12*facang;
csfacang = cs*facang;
csfac1 = rinvsq1*csfacang;
fj[0] = delr1[0]*(frad1+csfac1)-delr2[0]*facang12;
fj[1] = delr1[1]*(frad1+csfac1)-delr2[1]*facang12;
fj[2] = delr1[2]*(frad1+csfac1)-delr2[2]*facang12;
csfac2 = rinvsq2*csfacang;
fk[0] = delr2[0]*(frad2+csfac2)-delr1[0]*facang12;
fk[1] = delr2[1]*(frad2+csfac2)-delr1[1]*facang12;
fk[2] = delr2[2]*(frad2+csfac2)-delr1[2]*facang12;
if (eflag) eng = facrad;
}
diff --git a/src/MANYBODY/pair_tersoff.cpp b/src/MANYBODY/pair_tersoff.cpp
index fbbe857f0..fe02371fe 100644
--- a/src/MANYBODY/pair_tersoff.cpp
+++ b/src/MANYBODY/pair_tersoff.cpp
@@ -1,777 +1,778 @@
/* ----------------------------------------------------------------------
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: Aidan Thompson (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_tersoff.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
#include "math_const.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define MAXLINE 1024
#define DELTA 4
/* ---------------------------------------------------------------------- */
PairTersoff::PairTersoff(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairTersoff::~PairTersoff()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
}
}
/* ---------------------------------------------------------------------- */
void PairTersoff::compute(int eflag, int vflag)
{
int i,j,k,ii,jj,kk,inum,jnum;
- int itag,jtag,itype,jtype,ktype,iparam_ij,iparam_ijk;
+ int itype,jtype,ktype,iparam_ij,iparam_ijk;
+ tagint itag,jtag;
double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair;
double rsq,rsq1,rsq2;
double delr1[3],delr2[3],fi[3],fj[3],fk[3];
double zeta_ij,prefactor;
int *ilist,*jlist,*numneigh,**firstneigh;
evdwl = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = vflag_atom = 0;
double **x = atom->x;
double **f = atom->f;
- int *tag = atom->tag;
+ 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 full neighbor list of my atoms
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];
// two-body interactions, skip half of them
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] < x[i][2]) 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 = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
iparam_ij = elem2param[itype][jtype][jtype];
if (rsq > params[iparam_ij].cutsq) continue;
repulsive(&params[iparam_ij],rsq,fpair,eflag,evdwl);
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 (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,fpair,delx,dely,delz);
}
// three-body interactions
// skip immediately if I-J is not within cutoff
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
jtype = map[type[j]];
iparam_ij = elem2param[itype][jtype][jtype];
delr1[0] = x[j][0] - xtmp;
delr1[1] = x[j][1] - ytmp;
delr1[2] = x[j][2] - ztmp;
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
if (rsq1 > params[iparam_ij].cutsq) continue;
// accumulate bondorder zeta for each i-j interaction via loop over k
zeta_ij = 0.0;
for (kk = 0; kk < jnum; kk++) {
if (jj == kk) continue;
k = jlist[kk];
k &= NEIGHMASK;
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
if (rsq2 > params[iparam_ijk].cutsq) continue;
zeta_ij += zeta(&params[iparam_ijk],rsq1,rsq2,delr1,delr2);
}
// pairwise force due to zeta
force_zeta(&params[iparam_ij],rsq1,zeta_ij,fpair,prefactor,eflag,evdwl);
f[i][0] += delr1[0]*fpair;
f[i][1] += delr1[1]*fpair;
f[i][2] += delr1[2]*fpair;
f[j][0] -= delr1[0]*fpair;
f[j][1] -= delr1[1]*fpair;
f[j][2] -= delr1[2]*fpair;
if (evflag) ev_tally(i,j,nlocal,newton_pair,
evdwl,0.0,-fpair,-delr1[0],-delr1[1],-delr1[2]);
// attractive term via loop over k
for (kk = 0; kk < jnum; kk++) {
if (jj == kk) continue;
k = jlist[kk];
k &= NEIGHMASK;
ktype = map[type[k]];
iparam_ijk = elem2param[itype][jtype][ktype];
delr2[0] = x[k][0] - xtmp;
delr2[1] = x[k][1] - ytmp;
delr2[2] = x[k][2] - ztmp;
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
if (rsq2 > params[iparam_ijk].cutsq) continue;
attractive(&params[iparam_ijk],prefactor,
rsq1,rsq2,delr1,delr2,fi,fj,fk);
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];
if (vflag_atom) v_tally3(i,j,k,fj,fk,delr1,delr2);
}
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairTersoff::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairTersoff::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairTersoff::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
// clear setflag since coeff() called once with I,J = * *
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 PairTersoff::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style Tersoff requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style Tersoff requires newton pair on");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairTersoff::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairTersoff::read_file(char *file)
{
int params_per_line = 17;
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 = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open Tersoff potential file %s",file);
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 n,nwords,ielement,jelement,kelement;
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,"Incorrect format in Tersoff 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next line
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].powerm = atof(words[3]);
params[nparams].gamma = atof(words[4]);
params[nparams].lam3 = atof(words[5]);
params[nparams].c = atof(words[6]);
params[nparams].d = atof(words[7]);
params[nparams].h = atof(words[8]);
params[nparams].powern = atof(words[9]);
params[nparams].beta = atof(words[10]);
params[nparams].lam2 = atof(words[11]);
params[nparams].bigb = atof(words[12]);
params[nparams].bigr = atof(words[13]);
params[nparams].bigd = atof(words[14]);
params[nparams].lam1 = atof(words[15]);
params[nparams].biga = atof(words[16]);
// currently only allow m exponent of 1 or 3
params[nparams].powermint = int(params[nparams].powerm);
if (params[nparams].c < 0.0 || params[nparams].d < 0.0 ||
params[nparams].powern < 0.0 || params[nparams].beta < 0.0 ||
params[nparams].lam2 < 0.0 || params[nparams].bigb < 0.0 ||
params[nparams].bigr < 0.0 ||params[nparams].bigd < 0.0 ||
params[nparams].bigd > params[nparams].bigr ||
params[nparams].lam1 < 0.0 || params[nparams].biga < 0.0 ||
params[nparams].powerm - params[nparams].powermint != 0.0 ||
(params[nparams].powermint != 3 && params[nparams].powermint != 1) ||
params[nparams].gamma < 0.0)
error->all(FLERR,"Illegal Tersoff parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairTersoff::setup()
{
int i,j,k,m,n;
// set elem2param for all element triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// compute parameter values derived from inputs
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].bigr + params[m].bigd;
params[m].cutsq = params[m].cut*params[m].cut;
params[m].c1 = pow(2.0*params[m].powern*1.0e-16,-1.0/params[m].powern);
params[m].c2 = pow(2.0*params[m].powern*1.0e-8,-1.0/params[m].powern);
params[m].c3 = 1.0/params[m].c2;
params[m].c4 = 1.0/params[m].c1;
}
// set cutmax to max of all params
cutmax = 0.0;
for (m = 0; m < nparams; m++)
if (params[m].cut > cutmax) cutmax = params[m].cut;
}
/* ---------------------------------------------------------------------- */
void PairTersoff::repulsive(Param *param, double rsq, double &fforce,
int eflag, double &eng)
{
double r,tmp_fc,tmp_fc_d,tmp_exp;
r = sqrt(rsq);
tmp_fc = ters_fc(r,param);
tmp_fc_d = ters_fc_d(r,param);
tmp_exp = exp(-param->lam1 * r);
fforce = -param->biga * tmp_exp * (tmp_fc_d - tmp_fc*param->lam1) / r;
if (eflag) eng = tmp_fc * param->biga * tmp_exp;
}
/* ---------------------------------------------------------------------- */
double PairTersoff::zeta(Param *param, double rsqij, double rsqik,
double *delrij, double *delrik)
{
double rij,rik,costheta,arg,ex_delr;
rij = sqrt(rsqij);
rik = sqrt(rsqik);
costheta = (delrij[0]*delrik[0] + delrij[1]*delrik[1] +
delrij[2]*delrik[2]) / (rij*rik);
if (param->powermint == 3) arg = pow(param->lam3 * (rij-rik),3.0);
else arg = param->lam3 * (rij-rik);
if (arg > 69.0776) ex_delr = 1.e30;
else if (arg < -69.0776) ex_delr = 0.0;
else ex_delr = exp(arg);
return ters_fc(rik,param) * ters_gijk(costheta,param) * ex_delr;
}
/* ---------------------------------------------------------------------- */
void PairTersoff::force_zeta(Param *param, double rsq, double zeta_ij,
double &fforce, double &prefactor,
int eflag, double &eng)
{
double r,fa,fa_d,bij;
r = sqrt(rsq);
fa = ters_fa(r,param);
fa_d = ters_fa_d(r,param);
bij = ters_bij(zeta_ij,param);
fforce = 0.5*bij*fa_d / r;
prefactor = -0.5*fa * ters_bij_d(zeta_ij,param);
if (eflag) eng = 0.5*bij*fa;
}
/* ----------------------------------------------------------------------
attractive term
use param_ij cutoff for rij test
use param_ijk cutoff for rik test
------------------------------------------------------------------------- */
void PairTersoff::attractive(Param *param, double prefactor,
double rsqij, double rsqik,
double *delrij, double *delrik,
double *fi, double *fj, double *fk)
{
double rij_hat[3],rik_hat[3];
double rij,rijinv,rik,rikinv;
rij = sqrt(rsqij);
rijinv = 1.0/rij;
vec3_scale(rijinv,delrij,rij_hat);
rik = sqrt(rsqik);
rikinv = 1.0/rik;
vec3_scale(rikinv,delrik,rik_hat);
ters_zetaterm_d(prefactor,rij_hat,rij,rik_hat,rik,fi,fj,fk,param);
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_fc(double r, Param *param)
{
double ters_R = param->bigr;
double ters_D = param->bigd;
if (r < ters_R-ters_D) return 1.0;
if (r > ters_R+ters_D) return 0.0;
return 0.5*(1.0 - sin(MY_PI2*(r - ters_R)/ters_D));
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_fc_d(double r, Param *param)
{
double ters_R = param->bigr;
double ters_D = param->bigd;
if (r < ters_R-ters_D) return 0.0;
if (r > ters_R+ters_D) return 0.0;
return -(MY_PI4/ters_D) * cos(MY_PI2*(r - ters_R)/ters_D);
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_fa(double r, Param *param)
{
if (r > param->bigr + param->bigd) return 0.0;
return -param->bigb * exp(-param->lam2 * r) * ters_fc(r,param);
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_fa_d(double r, Param *param)
{
if (r > param->bigr + param->bigd) return 0.0;
return param->bigb * exp(-param->lam2 * r) *
(param->lam2 * ters_fc(r,param) - ters_fc_d(r,param));
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_bij(double zeta, Param *param)
{
double tmp = param->beta * zeta;
if (tmp > param->c1) return 1.0/sqrt(tmp);
if (tmp > param->c2)
return (1.0 - pow(tmp,-param->powern) / (2.0*param->powern))/sqrt(tmp);
if (tmp < param->c4) return 1.0;
if (tmp < param->c3)
return 1.0 - pow(tmp,param->powern)/(2.0*param->powern);
return pow(1.0 + pow(tmp,param->powern), -1.0/(2.0*param->powern));
}
/* ---------------------------------------------------------------------- */
double PairTersoff::ters_bij_d(double zeta, Param *param)
{
double tmp = param->beta * zeta;
if (tmp > param->c1) return param->beta * -0.5*pow(tmp,-1.5);
if (tmp > param->c2)
return param->beta * (-0.5*pow(tmp,-1.5) *
(1.0 - 0.5*(1.0 + 1.0/(2.0*param->powern)) *
pow(tmp,-param->powern)));
if (tmp < param->c4) return 0.0;
if (tmp < param->c3)
return -0.5*param->beta * pow(tmp,param->powern-1.0);
double tmp_n = pow(tmp,param->powern);
return -0.5 * pow(1.0+tmp_n, -1.0-(1.0/(2.0*param->powern)))*tmp_n / zeta;
}
/* ---------------------------------------------------------------------- */
void PairTersoff::ters_zetaterm_d(double prefactor,
double *rij_hat, double rij,
double *rik_hat, double rik,
double *dri, double *drj, double *drk,
Param *param)
{
double gijk,gijk_d,ex_delr,ex_delr_d,fc,dfc,cos_theta,tmp;
double dcosdri[3],dcosdrj[3],dcosdrk[3];
fc = ters_fc(rik,param);
dfc = ters_fc_d(rik,param);
if (param->powermint == 3) tmp = pow(param->lam3 * (rij-rik),3.0);
else tmp = param->lam3 * (rij-rik);
if (tmp > 69.0776) ex_delr = 1.e30;
else if (tmp < -69.0776) ex_delr = 0.0;
else ex_delr = exp(tmp);
if (param->powermint == 3)
ex_delr_d = 3.0*pow(param->lam3,3.0) * pow(rij-rik,2.0)*ex_delr;
else ex_delr_d = param->lam3 * ex_delr;
cos_theta = vec3_dot(rij_hat,rik_hat);
gijk = ters_gijk(cos_theta,param);
gijk_d = ters_gijk_d(cos_theta,param);
costheta_d(rij_hat,rij,rik_hat,rik,dcosdri,dcosdrj,dcosdrk);
// compute the derivative wrt Ri
// dri = -dfc*gijk*ex_delr*rik_hat;
// dri += fc*gijk_d*ex_delr*dcosdri;
// dri += fc*gijk*ex_delr_d*(rik_hat - rij_hat);
vec3_scale(-dfc*gijk*ex_delr,rik_hat,dri);
vec3_scaleadd(fc*gijk_d*ex_delr,dcosdri,dri,dri);
vec3_scaleadd(fc*gijk*ex_delr_d,rik_hat,dri,dri);
vec3_scaleadd(-fc*gijk*ex_delr_d,rij_hat,dri,dri);
vec3_scale(prefactor,dri,dri);
// compute the derivative wrt Rj
// drj = fc*gijk_d*ex_delr*dcosdrj;
// drj += fc*gijk*ex_delr_d*rij_hat;
vec3_scale(fc*gijk_d*ex_delr,dcosdrj,drj);
vec3_scaleadd(fc*gijk*ex_delr_d,rij_hat,drj,drj);
vec3_scale(prefactor,drj,drj);
// compute the derivative wrt Rk
// drk = dfc*gijk*ex_delr*rik_hat;
// drk += fc*gijk_d*ex_delr*dcosdrk;
// drk += -fc*gijk*ex_delr_d*rik_hat;
vec3_scale(dfc*gijk*ex_delr,rik_hat,drk);
vec3_scaleadd(fc*gijk_d*ex_delr,dcosdrk,drk,drk);
vec3_scaleadd(-fc*gijk*ex_delr_d,rik_hat,drk,drk);
vec3_scale(prefactor,drk,drk);
}
/* ---------------------------------------------------------------------- */
void PairTersoff::costheta_d(double *rij_hat, double rij,
double *rik_hat, double rik,
double *dri, double *drj, double *drk)
{
// first element is devative wrt Ri, second wrt Rj, third wrt Rk
double cos_theta = vec3_dot(rij_hat,rik_hat);
vec3_scaleadd(-cos_theta,rij_hat,rik_hat,drj);
vec3_scale(1.0/rij,drj,drj);
vec3_scaleadd(-cos_theta,rik_hat,rij_hat,drk);
vec3_scale(1.0/rik,drk,drk);
vec3_add(drj,drk,dri);
vec3_scale(-1.0,dri,dri);
}
diff --git a/src/MC/fix_bond_break.cpp b/src/MC/fix_bond_break.cpp
index 0ae5ae94b..50f718492 100644
--- a/src/MC/fix_bond_break.cpp
+++ b/src/MC/fix_bond_break.cpp
@@ -1,390 +1,390 @@
/* ----------------------------------------------------------------------
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 "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "fix_bond_break.h"
#include "update.h"
#include "respa.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixBondBreak::FixBondBreak(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 6) error->all(FLERR,"Illegal fix bond/break command");
MPI_Comm_rank(world,&me);
nevery = force->inumeric(FLERR,arg[3]);
if (nevery <= 0) error->all(FLERR,"Illegal fix bond/break command");
force_reneighbor = 1;
next_reneighbor = -1;
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
btype = force->inumeric(FLERR,arg[4]);
double cutoff = force->numeric(FLERR,arg[5]);
if (btype < 1 || btype > atom->nbondtypes)
error->all(FLERR,"Invalid bond type in fix bond/break command");
if (cutoff < 0.0) error->all(FLERR,"Illegal fix bond/break command");
cutsq = cutoff*cutoff;
// optional keywords
fraction = 1.0;
int seed = 12345;
int iarg = 6;
while (iarg < narg) {
if (strcmp(arg[iarg],"prob") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix bond/break command");
fraction = force->numeric(FLERR,arg[iarg+1]);
seed = force->inumeric(FLERR,arg[iarg+2]);
if (fraction < 0.0 || fraction > 1.0)
error->all(FLERR,"Illegal fix bond/break command");
if (seed <= 0) error->all(FLERR,"Illegal fix bond/break command");
iarg += 3;
} else error->all(FLERR,"Illegal fix bond/break command");
}
// error check
if (atom->molecular == 0)
error->all(FLERR,"Cannot use fix bond/break with non-molecular systems");
// initialize Marsaglia RNG with processor-unique seed
random = new RanMars(lmp,seed + me);
// set comm sizes needed by this fix
comm_forward = 2;
comm_reverse = 2;
// allocate arrays local to this fix
nmax = 0;
partner = NULL;
distsq = NULL;
// zero out stats
breakcount = 0;
breakcounttotal = 0;
}
/* ---------------------------------------------------------------------- */
FixBondBreak::~FixBondBreak()
{
delete random;
// delete locally stored arrays
memory->destroy(partner);
memory->destroy(distsq);
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
mask |= POST_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::init()
{
// require special bonds = 0,1,1
int flag = 0;
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0) flag = 1;
if (force->special_coul[1] != 0.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0) flag = 1;
if (flag) error->all(FLERR,"Fix bond/break requires special_bonds = 0,1,1");
// warn if angles, dihedrals, impropers are being used
if (force->angle || force->dihedral || force->improper) {
if (me == 0)
error->warning(FLERR,"Broken bonds will not alter angles, "
"dihedrals, or impropers");
}
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::post_integrate()
{
int i,j,k,m,n,i1,i2,n1,n3,type;
double delx,dely,delz,rsq;
- int *slist;
+ tagint *slist;
if (update->ntimestep % nevery) return;
// need updated ghost atom positions
comm->forward_comm();
// resize bond partner list and initialize it
// probability array overlays distsq array
// needs to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(partner);
memory->destroy(distsq);
nmax = atom->nmax;
memory->create(partner,nmax,"bond/break:partner");
memory->create(distsq,nmax,"bond/break:distsq");
probability = distsq;
}
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
for (i = 0; i < nall; i++) {
partner[i] = 0;
distsq[i] = 0.0;
}
// loop over bond list
// setup possible partner list of bonds to break
double **x = atom->x;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
for (n = 0; n < nbondlist; n++) {
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
if (!(mask[i1] & groupbit)) continue;
if (!(mask[i2] & groupbit)) continue;
if (type != btype) continue;
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutsq) continue;
if (rsq > distsq[i1]) {
partner[i1] = tag[i2];
distsq[i1] = rsq;
}
if (rsq > distsq[i2]) {
partner[i2] = tag[i1];
distsq[i2] = rsq;
}
}
// reverse comm of partner info
if (force->newton_bond) comm->reverse_comm_fix(this);
// each atom now knows its winning partner
// for prob check, generate random value for each atom with a bond partner
// forward comm of partner and random value, so ghosts have it
if (fraction < 1.0) {
for (i = 0; i < nlocal; i++)
if (partner[i]) probability[i] = random->uniform();
}
comm->forward_comm_fix(this);
// break bonds
// if both atoms list each other as winning bond partner
// and probability constraint is satisfied
int **bond_type = atom->bond_type;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int *num_bond = atom->num_bond;
int **nspecial = atom->nspecial;
- int **special = atom->special;
+ tagint **special = atom->special;
int nbreak = 0;
for (i = 0; i < nlocal; i++) {
if (partner[i] == 0) continue;
j = atom->map(partner[i]);
if (partner[j] != tag[i]) continue;
// apply probability constraint using RN for atom with smallest ID
if (fraction < 1.0) {
if (tag[i] < tag[j]) {
if (probability[i] >= fraction) continue;
} else {
if (probability[j] >= fraction) continue;
}
}
// delete bond from atom I if I stores it
// atom J will also do this
for (m = 0; m < num_bond[i]; m++) {
if (bond_atom[i][m] == partner[i]) {
for (k = m; k < num_bond[i]-1; k++) {
bond_atom[i][k] = bond_atom[i][k+1];
bond_type[i][k] = bond_type[i][k+1];
}
num_bond[i]--;
break;
}
}
// remove J from special bond list for atom I
// atom J will also do this
slist = special[i];
n1 = nspecial[i][0];
n3 = nspecial[i][2];
for (m = 0; m < n1; m++)
if (slist[m] == partner[i]) break;
for (; m < n3-1; m++) slist[m] = slist[m+1];
nspecial[i][0]--;
nspecial[i][1]--;
nspecial[i][2]--;
// count the broken bond once
if (tag[i] < tag[j]) nbreak++;
}
// tally stats
MPI_Allreduce(&nbreak,&breakcount,1,MPI_INT,MPI_SUM,world);
breakcounttotal += breakcount;
atom->nbonds -= breakcount;
// trigger reneighboring if any bonds were formed
if (breakcount) next_reneighbor = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::post_integrate_respa(int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_integrate();
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::pack_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++] = partner[j];
buf[m++] = probability[j];
}
return 2;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
- partner[i] = static_cast<int> (buf[m++]);
+ partner[i] = static_cast<tagint> (buf[m++]);
probability[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::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++] = partner[i];
buf[m++] = distsq[i];
}
return 2;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (buf[m+1] > distsq[j]) {
- partner[j] = static_cast<int> (buf[m++]);
+ partner[j] = static_cast<tagint> (buf[m++]);
distsq[j] = buf[m++];
} else m += 2;
}
}
/* ---------------------------------------------------------------------- */
double FixBondBreak::compute_vector(int n)
{
if (n == 1) return (double) breakcount;
return (double) breakcounttotal;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixBondBreak::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax * sizeof(int);
bytes += nmax * sizeof(double);
return bytes;
}
diff --git a/src/MC/fix_bond_break.h b/src/MC/fix_bond_break.h
index 190ed8529..03aef0166 100644
--- a/src/MC/fix_bond_break.h
+++ b/src/MC/fix_bond_break.h
@@ -1,87 +1,87 @@
/* -*- 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 FIX_CLASS
FixStyle(bond/break,FixBondBreak)
#else
#ifndef LMP_FIX_BOND_BREAK_H
#define LMP_FIX_BOND_BREAK_H
#include "fix.h"
namespace LAMMPS_NS {
class FixBondBreak : public Fix {
public:
FixBondBreak(class LAMMPS *, int, char **);
~FixBondBreak();
int setmask();
void init();
void post_integrate();
void post_integrate_respa(int,int);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int pack_reverse_comm(int, int, double *);
void unpack_reverse_comm(int, int *, double *);
double compute_vector(int);
double memory_usage();
private:
int me;
int btype,seed;
double cutsq,fraction;
int breakcount,breakcounttotal;
int nmax;
- int *partner;
+ tagint *partner;
double *distsq,*probability;
class RanMars *random;
int nlevels_respa;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Invalid bond type in fix bond/break command
Self-explanatory.
E: Cannot use fix bond/break with non-molecular systems
Self-explanatory.
E: Fix bond/break requires special_bonds = 0,1,1
This is a restriction of the current fix bond/break implementation.
W: Broken bonds will not alter angles, dihedrals, or impropers
See the doc page for fix bond/break for more info on this
restriction.
*/
diff --git a/src/MC/fix_bond_create.cpp b/src/MC/fix_bond_create.cpp
index 7d0850c57..015a52701 100644
--- a/src/MC/fix_bond_create.cpp
+++ b/src/MC/fix_bond_create.cpp
@@ -1,619 +1,620 @@
/* ----------------------------------------------------------------------
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 "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "fix_bond_create.h"
#include "update.h"
#include "respa.h"
#include "atom.h"
#include "force.h"
#include "pair.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define BIG 1.0e20
/* ---------------------------------------------------------------------- */
FixBondCreate::FixBondCreate(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 8) error->all(FLERR,"Illegal fix bond/create command");
MPI_Comm_rank(world,&me);
nevery = force->inumeric(FLERR,arg[3]);
if (nevery <= 0) error->all(FLERR,"Illegal fix bond/create command");
force_reneighbor = 1;
next_reneighbor = -1;
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
iatomtype = force->inumeric(FLERR,arg[4]);
jatomtype = force->inumeric(FLERR,arg[5]);
double cutoff = force->numeric(FLERR,arg[6]);
btype = force->inumeric(FLERR,arg[7]);
if (iatomtype < 1 || iatomtype > atom->ntypes ||
jatomtype < 1 || jatomtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix bond/create command");
if (cutoff < 0.0) error->all(FLERR,"Illegal fix bond/create command");
if (btype < 1 || btype > atom->nbondtypes)
error->all(FLERR,"Invalid bond type in fix bond/create command");
cutsq = cutoff*cutoff;
// optional keywords
imaxbond = 0;
inewtype = iatomtype;
jmaxbond = 0;
jnewtype = jatomtype;
fraction = 1.0;
int seed = 12345;
int iarg = 8;
while (iarg < narg) {
if (strcmp(arg[iarg],"iparam") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix bond/create command");
imaxbond = force->inumeric(FLERR,arg[iarg+1]);
inewtype = force->inumeric(FLERR,arg[iarg+2]);
if (imaxbond < 0) error->all(FLERR,"Illegal fix bond/create command");
if (inewtype < 1 || inewtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix bond/create command");
iarg += 3;
} else if (strcmp(arg[iarg],"jparam") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix bond/create command");
jmaxbond = force->inumeric(FLERR,arg[iarg+1]);
jnewtype = force->inumeric(FLERR,arg[iarg+2]);
if (jmaxbond < 0) error->all(FLERR,"Illegal fix bond/create command");
if (jnewtype < 1 || jnewtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix bond/create command");
iarg += 3;
} else if (strcmp(arg[iarg],"prob") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix bond/create command");
fraction = force->numeric(FLERR,arg[iarg+1]);
seed = force->inumeric(FLERR,arg[iarg+2]);
if (fraction < 0.0 || fraction > 1.0)
error->all(FLERR,"Illegal fix bond/create command");
if (seed <= 0) error->all(FLERR,"Illegal fix bond/create command");
iarg += 3;
} else error->all(FLERR,"Illegal fix bond/create command");
}
// error check
if (atom->molecular == 0)
error->all(FLERR,"Cannot use fix bond/create with non-molecular systems");
if (iatomtype == jatomtype &&
((imaxbond != jmaxbond) || (inewtype != jnewtype)))
error->all(FLERR,
"Inconsistent iparam/jparam values in fix bond/create command");
// initialize Marsaglia RNG with processor-unique seed
random = new RanMars(lmp,seed + me);
// perform initial allocation of atom-based arrays
// register with Atom class
// bondcount values will be initialized in setup()
bondcount = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
countflag = 0;
// set comm sizes needed by this fix
comm_forward = 2;
comm_reverse = 2;
// allocate arrays local to this fix
nmax = 0;
partner = NULL;
distsq = NULL;
// zero out stats
createcount = 0;
createcounttotal = 0;
}
/* ---------------------------------------------------------------------- */
FixBondCreate::~FixBondCreate()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
delete random;
// delete locally stored arrays
memory->destroy(bondcount);
memory->destroy(partner);
memory->destroy(distsq);
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
mask |= POST_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::init()
{
// check cutoff for iatomtype,jatomtype
if (force->pair == NULL || cutsq > force->pair->cutsq[iatomtype][jatomtype])
error->all(FLERR,"Fix bond/create cutoff is longer than pairwise cutoff");
// require special bonds = 0,1,1
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0)
error->all(FLERR,"Fix bond/create requires special_bonds lj = 0,1,1");
if (atom->q_flag)
if (force->special_coul[1] != 0.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0)
error->all(FLERR,"Fix bond/create requires special_bonds coul = 0,1,1");
// warn if angles, dihedrals, impropers are being used
if (force->angle || force->dihedral || force->improper) {
if (me == 0)
error->warning(FLERR,"Created bonds will not create angles, "
"dihedrals, or impropers");
}
// need a half neighbor list, built when ever re-neighboring occurs
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::setup(int vflag)
{
int i,j,m;
// compute initial bondcount if this is first run
// can't do this earlier, like in constructor or init, b/c need ghost info
if (countflag) return;
countflag = 1;
// count bonds stored with each bond I own
// if newton bond is not set, just increment count on atom I
// if newton bond is set, also increment count on atom J even if ghost
// bondcount is long enough to tally ghost atom counts
int *num_bond = atom->num_bond;
int **bond_type = atom->bond_type;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int nall = nlocal + nghost;
int newton_bond = force->newton_bond;
for (i = 0; i < nall; i++) bondcount[i] = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
if (bond_type[i][j] == btype) {
bondcount[i]++;
if (newton_bond) {
m = atom->map(bond_atom[i][j]);
if (m < 0)
error->one(FLERR,
"Could not count initial bonds in fix bond/create");
bondcount[m]++;
}
}
}
// if newton_bond is set, need to sum bondcount
commflag = 0;
if (newton_bond) comm->reverse_comm_fix(this);
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::post_integrate()
{
int i,j,m,ii,jj,inum,jnum,itype,jtype,n1,n3,possible;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
- int *ilist,*jlist,*numneigh,**firstneigh,*slist;
+ int *ilist,*jlist,*numneigh,**firstneigh;
+ tagint *slist;
if (update->ntimestep % nevery) return;
// need updated ghost atom positions
comm->forward_comm();
// forward comm of bondcount, so ghosts have it
commflag = 0;
comm->forward_comm_fix(this);
// resize bond partner list and initialize it
// probability array overlays distsq array
// needs to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(partner);
memory->destroy(distsq);
nmax = atom->nmax;
memory->create(partner,nmax,"bond/create:partner");
memory->create(distsq,nmax,"bond/create:distsq");
probability = distsq;
}
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
for (i = 0; i < nall; i++) {
partner[i] = 0;
distsq[i] = BIG;
}
// loop over neighbors of my atoms
// each atom sets one closest eligible partner atom ID to bond with
double **x = atom->x;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int *type = atom->type;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (!(mask[i] & groupbit)) continue;
itype = type[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;
if (!(mask[j] & groupbit)) continue;
jtype = type[j];
possible = 0;
if (itype == iatomtype && jtype == jatomtype) {
if ((imaxbond == 0 || bondcount[i] < imaxbond) &&
(jmaxbond == 0 || bondcount[j] < jmaxbond))
possible = 1;
} else if (itype == jatomtype && jtype == iatomtype) {
if ((jmaxbond == 0 || bondcount[i] < jmaxbond) &&
(imaxbond == 0 || bondcount[j] < imaxbond))
possible = 1;
}
if (!possible) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq >= cutsq) continue;
if (rsq < distsq[i]) {
partner[i] = tag[j];
distsq[i] = rsq;
}
if (rsq < distsq[j]) {
partner[j] = tag[i];
distsq[j] = rsq;
}
}
}
// reverse comm of distsq and partner
// not needed if newton_pair off since I,J pair was seen by both procs
commflag = 1;
if (force->newton_pair) comm->reverse_comm_fix(this);
// each atom now knows its winning partner
// for prob check, generate random value for each atom with a bond partner
// forward comm of partner and random value, so ghosts have it
if (fraction < 1.0) {
for (i = 0; i < nlocal; i++)
if (partner[i]) probability[i] = random->uniform();
}
commflag = 1;
comm->forward_comm_fix(this);
// create bonds for atoms I own
// if other atom is owned by another proc, it should create same bond
// if both atoms list each other as winning bond partner
// and probability constraint is satisfied
int **bond_type = atom->bond_type;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int *num_bond = atom->num_bond;
int **nspecial = atom->nspecial;
- int **special = atom->special;
+ tagint **special = atom->special;
int newton_bond = force->newton_bond;
int ncreate = 0;
for (i = 0; i < nlocal; i++) {
if (partner[i] == 0) continue;
j = atom->map(partner[i]);
if (partner[j] != tag[i]) continue;
// apply probability constraint using RN for atom with smallest ID
if (fraction < 1.0) {
if (tag[i] < tag[j]) {
if (probability[i] >= fraction) continue;
} else {
if (probability[j] >= fraction) continue;
}
}
// if newton_bond is set, only store with I or J
// if not newton_bond, store bond with both I and J
if (!newton_bond || tag[i] < tag[j]) {
if (num_bond[i] == atom->bond_per_atom)
error->one(FLERR,"New bond exceeded bonds per atom in fix bond/create");
bond_type[i][num_bond[i]] = btype;
bond_atom[i][num_bond[i]] = tag[j];
num_bond[i]++;
}
// add a 1-2 neighbor to special bond list for atom I
// atom J will also do this
slist = special[i];
n1 = nspecial[i][0];
n3 = nspecial[i][2];
if (n3 == atom->maxspecial)
error->one(FLERR,
"New bond exceeded special list size in fix bond/create");
for (m = n3; m > n1; m--) slist[m+1] = slist[m];
slist[n1] = tag[j];
nspecial[i][0]++;
nspecial[i][1]++;
nspecial[i][2]++;
// increment bondcount, convert atom to new type if limit reached
bondcount[i]++;
if (type[i] == iatomtype) {
if (bondcount[i] == imaxbond) type[i] = inewtype;
} else {
if (bondcount[i] == jmaxbond) type[i] = jnewtype;
}
// count the created bond once
if (tag[i] < tag[j]) ncreate++;
}
// tally stats
MPI_Allreduce(&ncreate,&createcount,1,MPI_INT,MPI_SUM,world);
createcounttotal += createcount;
atom->nbonds += createcount;
// trigger reneighboring if any bonds were formed
if (createcount) next_reneighbor = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::post_integrate_respa(int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_integrate();
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
if (commflag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = bondcount[j];
}
return 1;
} else {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = partner[j];
buf[m++] = probability[j];
}
return 2;
}
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (commflag == 0) {
for (i = first; i < last; i++)
bondcount[i] = static_cast<int> (buf[m++]);
} else {
for (i = first; i < last; i++) {
- partner[i] = static_cast<int> (buf[m++]);
+ partner[i] = static_cast<tagint> (buf[m++]);
probability[i] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (commflag == 0) {
for (i = first; i < last; i++)
buf[m++] = bondcount[i];
return 1;
} else {
for (i = first; i < last; i++) {
buf[m++] = distsq[i];
buf[m++] = partner[i];
}
return 2;
}
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
if (commflag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
bondcount[j] += static_cast<int> (buf[m++]);
}
} else {
for (i = 0; i < n; i++) {
j = list[i];
if (buf[m] < distsq[j]) {
distsq[j] = buf[m++];
- partner[j] = static_cast<int> (buf[m++]);
+ partner[j] = static_cast<tagint> (buf[m++]);
} else m += 2;
}
}
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixBondCreate::grow_arrays(int nmax)
{
memory->grow(bondcount,nmax,"bond/create:bondcount");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixBondCreate::copy_arrays(int i, int j, int delflag)
{
bondcount[j] = bondcount[i];
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixBondCreate::pack_exchange(int i, double *buf)
{
buf[0] = bondcount[i];
return 1;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixBondCreate::unpack_exchange(int nlocal, double *buf)
{
bondcount[nlocal] = static_cast<int> (buf[0]);
return 1;
}
/* ---------------------------------------------------------------------- */
double FixBondCreate::compute_vector(int n)
{
if (n == 1) return (double) createcount;
return (double) createcounttotal;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixBondCreate::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax*2 * sizeof(int);
bytes += nmax * sizeof(double);
return bytes;
}
diff --git a/src/MC/fix_bond_create.h b/src/MC/fix_bond_create.h
index 3aebdc3f3..22a6e79c3 100644
--- a/src/MC/fix_bond_create.h
+++ b/src/MC/fix_bond_create.h
@@ -1,133 +1,133 @@
/* -*- 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 FIX_CLASS
FixStyle(bond/create,FixBondCreate)
#else
#ifndef LMP_FIX_BOND_CREATE_H
#define LMP_FIX_BOND_CREATE_H
#include "fix.h"
namespace LAMMPS_NS {
class FixBondCreate : public Fix {
public:
FixBondCreate(class LAMMPS *, int, char **);
~FixBondCreate();
int setmask();
void init();
void init_list(int, class NeighList *);
void setup(int);
void post_integrate();
void post_integrate_respa(int, int);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int pack_reverse_comm(int, int, double *);
void unpack_reverse_comm(int, int *, double *);
void grow_arrays(int);
void copy_arrays(int, int, int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
double compute_vector(int);
double memory_usage();
private:
int me;
int iatomtype,jatomtype;
int btype,seed;
int imaxbond,jmaxbond;
int inewtype,jnewtype;
double cutsq,fraction;
int createcount,createcounttotal; // bond formation stats
int nmax;
int *bondcount; // count of created bonds this atom is part of
- int *partner; // ID of preferred atom for this atom to bond to
+ tagint *partner; // ID of preferred atom for this atom to bond to
double *distsq; // distance to preferred bond partner
double *probability; // random # to use in decision to form bond
class RanMars *random;
class NeighList *list;
int countflag,commflag;
int nlevels_respa;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Invalid atom type in fix bond/create command
Self-explanatory.
E: Invalid bond type in fix bond/create command
Self-explanatory.
E: Cannot use fix bond/create with non-molecular systems
Self-explanatory.
E: Inconsistent iparam/jparam values in fix bond/create command
If itype and jtype are the same, then their maxbond and newtype
settings must also be the same.
E: Fix bond/create cutoff is longer than pairwise cutoff
This is not allowed because bond creation is done using the
pairwise neighbor list.
E: Fix bond/create requires special_bonds lj = 0,1,1
Self-explanatory.
E: Fix bond/create requires special_bonds coul = 0,1,1
Self-explanatory.
W: Created bonds will not create angles, dihedrals, or impropers
See the doc page for fix bond/create for more info on this
restriction.
E: Could not count initial bonds in fix bond/create
Could not find one of the atoms in a bond on this processor.
E: New bond exceeded bonds per atom in fix bond/create
See the read_data command for info on setting the "extra bond per
atom" header value to allow for additional bonds to be formed.
E: New bond exceeded special list size in fix bond/create
See the special_bonds extra command for info on how to leave space in
the special bonds list to allow for additional bonds to be formed.
*/
diff --git a/src/MC/fix_bond_swap.cpp b/src/MC/fix_bond_swap.cpp
index 24474052f..31bdb7568 100644
--- a/src/MC/fix_bond_swap.cpp
+++ b/src/MC/fix_bond_swap.cpp
@@ -1,705 +1,706 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "fix_bond_swap.h"
#include "atom.h"
#include "force.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "group.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "compute.h"
#include "random_mars.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
#include "update.h"
using namespace LAMMPS_NS;
using namespace FixConst;
static const char cite_fix_bond_swap[] =
"neighbor multi command:\n\n"
"@Article{Auhl03,\n"
" author = {R. Auhl, R. Everaers, G. S. Grest, K. Kremer, S. J. Plimpton},\n"
" title = {Equilibration of long chain polymer melts in computer simulations},\n"
" journal = {J.~Chem.~Phys.},\n"
" year = 2003,\n"
" volume = 119,\n"
" pages = {12718--12728}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
FixBondSwap::FixBondSwap(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_bond_swap);
if (narg != 6) error->all(FLERR,"Illegal fix bond/swap command");
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
fraction = force->numeric(FLERR,arg[3]);
double cutoff = force->numeric(FLERR,arg[4]);
cutsq = cutoff*cutoff;
// initialize Marsaglia RNG with processor-unique seed
int seed = force->inumeric(FLERR,arg[5]);
random = new RanMars(lmp,seed + comm->me);
// create a new compute temp style
// id = fix-ID + temp, compute group = fix group
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = (char *) "all";
newarg[2] = (char *) "temp";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
// initialize atom list
nmax = 0;
alist = NULL;
naccept = foursome = 0;
}
/* ---------------------------------------------------------------------- */
FixBondSwap::~FixBondSwap()
{
delete random;
// delete temperature if fix created it
if (tflag) modify->delete_compute(id_temp);
delete [] id_temp;
memory->destroy(alist);
}
/* ---------------------------------------------------------------------- */
int FixBondSwap::setmask()
{
int mask = 0;
mask |= PRE_NEIGHBOR;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::init()
{
// require an atom style with molecule IDs
if (atom->molecule == NULL)
error->all(FLERR,"Must use atom style with molecule IDs with fix bond/swap");
int icompute = modify->find_compute(id_temp);
if (icompute < 0)
error->all(FLERR,"Temperature ID for fix bond/swap does not exist");
temperature = modify->compute[icompute];
// pair and bonds must be defined
// no dihedral or improper potentials allowed
// special bonds must be 0 1 1
if (force->pair == NULL || force->bond == NULL)
error->all(FLERR,"Fix bond/swap requires pair and bond styles");
if (force->pair->single_enable == 0)
error->all(FLERR,"Pair style does not support fix bond/swap");
if (force->angle == NULL && atom->nangles > 0 && comm->me == 0)
error->warning(FLERR,"Fix bond/swap will ignore defined angles");
if (force->dihedral || force->improper)
error->all(FLERR,"Fix bond/swap cannot use dihedral or improper styles");
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0)
error->all(FLERR,"Fix bond/swap requires special_bonds = 0,1,1");
// need a half neighbor list, built when ever re-neighboring occurs
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
// zero out stats
naccept = foursome = 0;
angleflag = 0;
if (force->angle) angleflag = 1;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::pre_neighbor()
{
int i,j,ii,jj,m,inum,jnum;
int inext,iprev,ilast,jnext,jprev,jlast,ibond,iangle,jbond,jangle;
- int itag,inexttag,iprevtag,ilasttag,jtag,jnexttag,jprevtag,jlasttag;
int ibondtype,jbondtype,iangletype,inextangletype,jangletype,jnextangletype;
- int i1,i2,i3,j1,j2,j3,tmp;
+ tagint itag,inexttag,iprevtag,ilasttag,jtag,jnexttag,jprevtag,jlasttag;
+ tagint i1,i2,i3,j1,j2,j3;
int *ilist,*jlist,*numneigh,**firstneigh;
double delta,factor;
// compute current temp for Boltzmann factor test
double t_current = temperature->compute_scalar();
// local ptrs to atom arrays
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int *molecule = atom->molecule;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
int *num_angle = atom->num_angle;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
int **nspecial = atom->nspecial;
- int **special = atom->special;
+ tagint **special = atom->special;
int newton_bond = force->newton_bond;
int nlocal = atom->nlocal;
type = atom->type;
x = atom->x;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// randomize list of my owned atoms that are in fix group
// grow atom list if necessary
if (nlocal > nmax) {
memory->destroy(alist);
nmax = atom->nmax;
memory->create(alist,nmax,"bondswap:alist");
}
int neligible = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit)
alist[neligible++] = i;
}
+ int tmp;
for (i = 0; i < neligible; i++) {
j = static_cast<int> (random->uniform() * neligible);
tmp = alist[i];
alist[i] = alist[j];
alist[j] = tmp;
}
// examine ntest of my eligible atoms for potential swaps
// atom i is randomly selected via atom list
// look at all j neighbors of atom i
// atom j must be on-processor (j < nlocal)
// atom j must be in fix group
// i and j must be same distance from chain end (mol[i] = mol[j])
// NOTE: must use extra parens in if test on mask[j] & groupbit
int ntest = static_cast<int> (fraction * neligible);
int accept = 0;
for (int itest = 0; itest < ntest; itest++) {
i = alist[itest];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
if (j >= nlocal) continue;
if ((mask[j] & groupbit) == 0) continue;
if (molecule[i] != molecule[j]) continue;
// look at all bond partners of atoms i and j
// use num_bond for this, not special list, so also find bondtypes
// inext,jnext = bonded atoms
// inext,jnext must be on-processor (inext,jnext < nlocal)
// inext,jnext must be same dist from chain end (mol[inext] = mol[jnext])
// since swaps may occur between two ends of a single chain, insure
// the 4 atoms are unique (no duplicates): inext != jnext, inext != j
// all 4 old and new bonds must have length < cutoff
for (ibond = 0; ibond < num_bond[i]; ibond++) {
inext = atom->map(bond_atom[i][ibond]);
if (inext >= nlocal || inext < 0) continue;
ibondtype = bond_type[i][ibond];
for (jbond = 0; jbond < num_bond[j]; jbond++) {
jnext = atom->map(bond_atom[j][jbond]);
if (jnext >= nlocal || jnext < 0) continue;
jbondtype = bond_type[j][jbond];
if (molecule[inext] != molecule[jnext]) continue;
if (inext == jnext || inext == j) continue;
if (dist_rsq(i,inext) >= cutsq) continue;
if (dist_rsq(j,jnext) >= cutsq) continue;
if (dist_rsq(i,jnext) >= cutsq) continue;
if (dist_rsq(j,inext) >= cutsq) continue;
// if angles are enabled:
// find other atoms i,inext,j,jnext are in angles with
// and angletypes: i/j angletype, i/j nextangletype
// use num_angle for this, not special list, so also find angletypes
// 4 atoms consecutively along 1st chain: iprev,i,inext,ilast
// 4 atoms consecutively along 2nd chain: jprev,j,jnext,jlast
// prev or last atom can be non-existent at end of chain
// set prev/last = -1 in this case
// if newton bond = 0, then angles are stored by all 4 atoms
// so require that iprev,ilast,jprev,jlast be owned by this proc
// so all copies of angles can be updated if a swap takes place
if (angleflag) {
itag = tag[i];
inexttag = tag[inext];
jtag = tag[j];
jnexttag = tag[jnext];
iprev = -1;
for (iangle = 0; iangle < num_angle[i]; iangle++) {
i1 = angle_atom1[i][iangle];
i2 = angle_atom2[i][iangle];
i3 = angle_atom3[i][iangle];
if (i2 == itag && i3 == inexttag) iprev = atom->map(i1);
else if (i1 == inexttag && i2 == itag) iprev = atom->map(i3);
if (iprev >= 0) {
iangletype = angle_type[i][iangle];
break;
}
}
if (!newton_bond && iprev >= nlocal) continue;
ilast = -1;
for (iangle = 0; iangle < num_angle[inext]; iangle++) {
i1 = angle_atom1[inext][iangle];
i2 = angle_atom2[inext][iangle];
i3 = angle_atom3[inext][iangle];
if (i1 == itag && i2 == inexttag) ilast = atom->map(i3);
else if (i2 == inexttag && i3 == itag) ilast = atom->map(i1);
if (ilast >= 0) {
inextangletype = angle_type[inext][iangle];
break;
}
}
if (!newton_bond && ilast >= nlocal) continue;
jprev = -1;
for (jangle = 0; jangle < num_angle[j]; jangle++) {
j1 = angle_atom1[j][jangle];
j2 = angle_atom2[j][jangle];
j3 = angle_atom3[j][jangle];
if (j2 == jtag && j3 == jnexttag) jprev = atom->map(j1);
else if (j1 == jnexttag && j2 == jtag) jprev = atom->map(j3);
if (jprev >= 0) {
jangletype = angle_type[j][jangle];
break;
}
}
if (!newton_bond && jprev >= nlocal) continue;
jlast = -1;
for (jangle = 0; jangle < num_angle[jnext]; jangle++) {
j1 = angle_atom1[jnext][jangle];
j2 = angle_atom2[jnext][jangle];
j3 = angle_atom3[jnext][jangle];
if (j1 == jtag && j2 == jnexttag) jlast = atom->map(j3);
else if (j2 == jnexttag && j3 == jtag) jlast = atom->map(j1);
if (jlast >= 0) {
jnextangletype = angle_type[jnext][jangle];
break;
}
}
if (!newton_bond && jlast >= nlocal) continue;
}
// valid foursome found between 2 chains:
// chains = iprev-i-inext-ilast and jprev-j-jnext-jlast
// prev or last values are -1 if do not exist due to end of chain
// OK to call angle_eng with -1 atom, since just return 0.0
// current energy of foursome =
// E_nb(i,j) + E_nb(i,jnext) + E_nb(inext,j) + E_nb(inext,jnext) +
// E_bond(i,inext) + E_bond(j,jnext) +
// E_angle(iprev,i,inext) + E_angle(i,inext,ilast) +
// E_angle(jprev,j,jnext) + E_angle(j,jnext,jlast)
// new energy of foursome with swapped bonds =
// E_nb(i,j) + E_nb(i,inext) + E_nb(j,jnext) + E_nb(inext,jnext) +
// E_bond(i,jnext) + E_bond(j,inext) +
// E_angle(iprev,i,jnext) + E_angle(i,jnext,jlast) +
// E_angle(jprev,j,inext) + E_angle(j,inext,ilast)
// energy delta = add/subtract differing terms between 2 formulas
foursome++;
delta = pair_eng(i,inext) + pair_eng(j,jnext) -
pair_eng(i,jnext) - pair_eng(inext,j);
delta += bond_eng(ibondtype,i,jnext) + bond_eng(jbondtype,j,inext) -
bond_eng(ibondtype,i,inext) - bond_eng(jbondtype,j,jnext);
if (angleflag)
delta += angle_eng(iangletype,iprev,i,jnext) +
angle_eng(jnextangletype,i,jnext,jlast) +
angle_eng(jangletype,jprev,j,inext) +
angle_eng(inextangletype,j,inext,ilast) -
angle_eng(iangletype,iprev,i,inext) -
angle_eng(inextangletype,i,inext,ilast) -
angle_eng(jangletype,jprev,j,jnext) -
angle_eng(jnextangletype,j,jnext,jlast);
// if delta <= 0, accept swap
// if delta > 0, compute Boltzmann factor with current temperature
// only accept if greater than random value
// whether accept or not, exit test loop
if (delta < 0.0) accept = 1;
else {
factor = exp(-delta/force->boltz/t_current);
if (random->uniform() < factor) accept = 1;
}
goto done;
}
}
}
}
done:
if (!accept) return;
naccept++;
// change bond partners of affected atoms
// on atom i: bond i-inext changes to i-jnext
// on atom j: bond j-jnext changes to j-inext
// on atom inext: bond inext-i changes to inext-j
// on atom jnext: bond jnext-j changes to jnext-i
for (ibond = 0; ibond < num_bond[i]; ibond++)
if (bond_atom[i][ibond] == tag[inext]) bond_atom[i][ibond] = tag[jnext];
for (jbond = 0; jbond < num_bond[j]; jbond++)
if (bond_atom[j][jbond] == tag[jnext]) bond_atom[j][jbond] = tag[inext];
for (ibond = 0; ibond < num_bond[inext]; ibond++)
if (bond_atom[inext][ibond] == tag[i]) bond_atom[inext][ibond] = tag[j];
for (jbond = 0; jbond < num_bond[jnext]; jbond++)
if (bond_atom[jnext][jbond] == tag[j]) bond_atom[jnext][jbond] = tag[i];
// set global tags of 4 atoms in bonds
itag = tag[i];
inexttag = tag[inext];
jtag = tag[j];
jnexttag = tag[jnext];
// change 1st special neighbors of affected atoms: i,j,inext,jnext
// don't need to change 2nd/3rd special neighbors for any atom
// since special bonds = 0 1 1 means they are never used
for (m = 0; m < nspecial[i][0]; m++)
if (special[i][m] == inexttag) special[i][m] = jnexttag;
for (m = 0; m < nspecial[j][0]; m++)
if (special[j][m] == jnexttag) special[j][m] = inexttag;
for (m = 0; m < nspecial[inext][0]; m++)
if (special[inext][m] == itag) special[inext][m] = jtag;
for (m = 0; m < nspecial[jnext][0]; m++)
if (special[jnext][m] == jtag) special[jnext][m] = itag;
// done if no angles
if (!angleflag) return;
// set global tags of 4 additional atoms in angles, 0 if no angle
if (iprev >= 0) iprevtag = tag[iprev];
else iprevtag = 0;
if (ilast >= 0) ilasttag = tag[ilast];
else ilasttag = 0;
if (jprev >= 0) jprevtag = tag[jprev];
else jprevtag = 0;
if (jlast >= 0) jlasttag = tag[jlast];
else jlasttag = 0;
// change angle partners of affected atoms
// must check if each angle is stored as a-b-c or c-b-a
// on atom i:
// angle iprev-i-inext changes to iprev-i-jnext
// angle i-inext-ilast changes to i-jnext-jlast
// on atom j:
// angle jprev-j-jnext changes to jprev-j-inext
// angle j-jnext-jlast changes to j-inext-ilast
// on atom inext:
// angle iprev-i-inext changes to jprev-j-inext
// angle i-inext-ilast changes to j-inext-ilast
// on atom jnext:
// angle jprev-j-jnext changes to iprev-i-jnext
// angle j-jnext-jlast changes to i-jnext-jlast
for (iangle = 0; iangle < num_angle[i]; iangle++) {
i1 = angle_atom1[i][iangle];
i2 = angle_atom2[i][iangle];
i3 = angle_atom3[i][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag)
angle_atom3[i][iangle] = jnexttag;
else if (i1 == inexttag && i2 == itag && i3 == iprevtag)
angle_atom1[i][iangle] = jnexttag;
else if (i1 == itag && i2 == inexttag && i3 == ilasttag) {
angle_atom2[i][iangle] = jnexttag;
angle_atom3[i][iangle] = jlasttag;
} else if (i1 == ilasttag && i2 == inexttag && i3 == itag) {
angle_atom1[i][iangle] = jlasttag;
angle_atom2[i][iangle] = jnexttag;
}
}
for (jangle = 0; jangle < num_angle[j]; jangle++) {
j1 = angle_atom1[j][jangle];
j2 = angle_atom2[j][jangle];
j3 = angle_atom3[j][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag)
angle_atom3[j][jangle] = inexttag;
else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag)
angle_atom1[j][jangle] = inexttag;
else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) {
angle_atom2[j][jangle] = inexttag;
angle_atom3[j][jangle] = ilasttag;
} else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) {
angle_atom1[j][jangle] = ilasttag;
angle_atom2[j][jangle] = inexttag;
}
}
for (iangle = 0; iangle < num_angle[inext]; iangle++) {
i1 = angle_atom1[inext][iangle];
i2 = angle_atom2[inext][iangle];
i3 = angle_atom3[inext][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag) {
angle_atom1[inext][iangle] = jprevtag;
angle_atom2[inext][iangle] = jtag;
} else if (i1 == inexttag && i2 == itag && i3 == iprevtag) {
angle_atom2[inext][iangle] = jtag;
angle_atom3[inext][iangle] = jprevtag;
} else if (i1 == itag && i2 == inexttag && i3 == ilasttag)
angle_atom1[inext][iangle] = jtag;
else if (i1 == ilasttag && i2 == inexttag && i3 == itag)
angle_atom3[inext][iangle] = jtag;
}
for (jangle = 0; jangle < num_angle[jnext]; jangle++) {
j1 = angle_atom1[jnext][jangle];
j2 = angle_atom2[jnext][jangle];
j3 = angle_atom3[jnext][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) {
angle_atom1[jnext][jangle] = iprevtag;
angle_atom2[jnext][jangle] = itag;
} else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) {
angle_atom2[jnext][jangle] = itag;
angle_atom3[jnext][jangle] = iprevtag;
} else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag)
angle_atom1[jnext][jangle] = itag;
else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag)
angle_atom3[jnext][jangle] = itag;
}
// done if newton bond set
if (newton_bond) return;
// change angles stored by iprev,ilast,jprev,jlast
// on atom iprev: angle iprev-i-inext changes to iprev-i-jnext
// on atom jprev: angle jprev-j-jnext changes to jprev-j-inext
// on atom ilast: angle i-inext-ilast changes to j-inext-ilast
// on atom jlast: angle j-jnext-jlast changes to i-jnext-jlast
for (iangle = 0; iangle < num_angle[iprev]; iangle++) {
i1 = angle_atom1[iprev][iangle];
i2 = angle_atom2[iprev][iangle];
i3 = angle_atom3[iprev][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag)
angle_atom3[iprev][iangle] = jnexttag;
else if (i1 == inexttag && i2 == itag && i3 == iprevtag)
angle_atom1[iprev][iangle] = jnexttag;
}
for (jangle = 0; jangle < num_angle[jprev]; jangle++) {
j1 = angle_atom1[jprev][jangle];
j2 = angle_atom2[jprev][jangle];
j3 = angle_atom3[jprev][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag)
angle_atom3[jprev][jangle] = inexttag;
else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag)
angle_atom1[jprev][jangle] = inexttag;
}
for (iangle = 0; iangle < num_angle[ilast]; iangle++) {
i1 = angle_atom1[ilast][iangle];
i2 = angle_atom2[ilast][iangle];
i3 = angle_atom3[ilast][iangle];
if (i1 == itag && i2 == inexttag && i3 == ilasttag)
angle_atom1[ilast][iangle] = jtag;
else if (i1 == ilasttag && i2 == inexttag && i3 == itag)
angle_atom3[ilast][iangle] = jtag;
}
for (jangle = 0; jangle < num_angle[jlast]; jangle++) {
j1 = angle_atom1[jlast][jangle];
j2 = angle_atom2[jlast][jangle];
j3 = angle_atom3[jlast][jangle];
if (j1 == jtag && j2 == jnexttag && j3 == jlasttag)
angle_atom1[jlast][jangle] = itag;
else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag)
angle_atom3[jlast][jangle] = itag;
}
}
/* ---------------------------------------------------------------------- */
int FixBondSwap::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all(FLERR,"Illegal fix_modify command");
if (tflag) {
modify->delete_compute(id_temp);
tflag = 0;
}
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all(FLERR,"Could not find fix_modify temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all(FLERR,"Fix_modify temperature ID does not compute temperature");
if (temperature->igroup != igroup && comm->me == 0)
error->warning(FLERR,"Group for fix_modify temp != fix group");
return 2;
}
return 0;
}
/* ----------------------------------------------------------------------
compute squared distance between atoms I,J
must use minimum_image since J was found thru atom->map()
------------------------------------------------------------------------- */
double FixBondSwap::dist_rsq(int i, int j)
{
double delx = x[i][0] - x[j][0];
double dely = x[i][1] - x[j][1];
double delz = x[i][2] - x[j][2];
domain->minimum_image(delx,dely,delz);
return (delx*delx + dely*dely + delz*delz);
}
/* ----------------------------------------------------------------------
return pairwise interaction energy between atoms I,J
will always be full non-bond interaction, so factors = 1 in single() call
------------------------------------------------------------------------- */
double FixBondSwap::pair_eng(int i, int j)
{
double tmp;
double rsq = dist_rsq(i,j);
return force->pair->single(i,j,type[i],type[j],rsq,1.0,1.0,tmp);
}
/* ---------------------------------------------------------------------- */
double FixBondSwap::bond_eng(int btype, int i, int j)
{
double tmp;
double rsq = dist_rsq(i,j);
return force->bond->single(btype,rsq,i,j,tmp);
}
/* ---------------------------------------------------------------------- */
double FixBondSwap::angle_eng(int atype, int i, int j, int k)
{
// test for non-existent angle at end of chain
if (i == -1 || k == -1) return 0.0;
return force->angle->single(atype,i,j,k);
}
/* ----------------------------------------------------------------------
return bond swapping stats
n = 1 is # of swaps
n = 2 is # of attempted swaps
------------------------------------------------------------------------- */
double FixBondSwap::compute_vector(int n)
{
double one,all;
if (n == 0) one = naccept;
else one = foursome;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
return all;
}
/* ----------------------------------------------------------------------
memory usage of alist
------------------------------------------------------------------------- */
double FixBondSwap::memory_usage()
{
double bytes = nmax * sizeof(int);
return bytes;
}
diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp
index eb8fba2da..ab85e6e21 100644
--- a/src/MC/fix_gcmc.cpp
+++ b/src/MC/fix_gcmc.cpp
@@ -1,1315 +1,1316 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "fix_gcmc.h"
#include "atom.h"
#include "atom_vec.h"
#include "atom_vec_hybrid.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "comm.h"
#include "group.h"
#include "domain.h"
#include "region.h"
#include "random_park.h"
#include "force.h"
#include "pair.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include <iostream>
using namespace std;
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 11) error->all(FLERR,"Illegal fix gcmc command");
vector_flag = 1;
size_vector = 8;
global_freq = 1;
extvector = 0;
restart_global = 1;
time_depend = 1;
// required args
nevery = force->inumeric(FLERR,arg[3]);
nexchanges = force->inumeric(FLERR,arg[4]);
nmcmoves = force->inumeric(FLERR,arg[5]);
ngcmc_type = force->inumeric(FLERR,arg[6]);
seed = force->inumeric(FLERR,arg[7]);
reservoir_temperature = force->numeric(FLERR,arg[8]);
chemical_potential = force->numeric(FLERR,arg[9]);
displace = force->numeric(FLERR,arg[10]);
if (nexchanges < 0) error->all(FLERR,"Illegal fix gcmc command");
if (nmcmoves < 0) error->all(FLERR,"Illegal fix gcmc command");
if (seed <= 0) error->all(FLERR,"Illegal fix gcmc command");
if (reservoir_temperature < 0.0)
error->all(FLERR,"Illegal fix gcmc command");
if (displace < 0.0) error->all(FLERR,"Illegal fix gcmc command");
// set defaults
molflag = 0;
max_rotation_angle = 10*MY_PI/180;
regionflag = 0;
iregion = -1;
region_volume = 0;
max_region_attempts = 1000;
rotation_group = 0;
rotation_groupbit = 0;
rotation_inversegroupbit = 0;
pressure_flag = false;
pressure = 0.0;
fugacity_coeff = 1.0;
// read options from end of input line
options(narg-11,&arg[11]);
// random number generator, same for all procs
random_equal = new RanPark(lmp,seed);
// random number generator, not the same for all procs
random_unequal = new RanPark(lmp,seed);
// error checks on region and its extent being inside simulation box
region_xlo = region_xhi = region_ylo = region_yhi =
region_zlo = region_zhi = 0.0;
if (regionflag) {
if (domain->regions[iregion]->bboxflag == 0)
error->all(FLERR,"Fix gcmc region does not support a bounding box");
if (domain->regions[iregion]->dynamic_check())
error->all(FLERR,"Fix gcmc region cannot be dynamic");
region_xlo = domain->regions[iregion]->extent_xlo;
region_xhi = domain->regions[iregion]->extent_xhi;
region_ylo = domain->regions[iregion]->extent_ylo;
region_yhi = domain->regions[iregion]->extent_yhi;
region_zlo = domain->regions[iregion]->extent_zlo;
region_zhi = domain->regions[iregion]->extent_zhi;
if (region_xlo < domain->boxlo[0] || region_xhi > domain->boxhi[0] ||
region_ylo < domain->boxlo[1] || region_yhi > domain->boxhi[1] ||
region_zlo < domain->boxlo[2] || region_zhi > domain->boxhi[2])
error->all(FLERR,"Fix gcmc region extends outside simulation box");
// estimate region volume using MC trials
double coord[3];
int inside = 0;
int attempts = 10000000;
for (int i = 0; i < attempts; i++) {
coord[0] = region_xlo + random_equal->uniform() * (region_xhi-region_xlo);
coord[1] = region_ylo + random_equal->uniform() * (region_yhi-region_ylo);
coord[2] = region_zlo + random_equal->uniform() * (region_zhi-region_zlo);
if (domain->regions[iregion]->match(coord[0],coord[1],coord[2]) != 0)
inside++;
}
double max_region_volume = (region_xhi - region_xlo)*
(region_yhi - region_ylo)*(region_zhi - region_zlo);
region_volume = max_region_volume*static_cast<double> (inside)/
static_cast<double> (attempts);
}
// compute the number of MC cycles that occur nevery timesteps
ncycles = nexchanges + nmcmoves;
// set up reneighboring
force_reneighbor = 1;
next_reneighbor = update->ntimestep + 1;
// zero out counters
ntranslation_attempts = 0.0;
ntranslation_successes = 0.0;
nrotation_attempts = 0.0;
nrotation_successes = 0.0;
ndeletion_attempts = 0.0;
ndeletion_successes = 0.0;
ninsertion_attempts = 0.0;
ninsertion_successes = 0.0;
gcmc_nmax = 0;
local_gas_list = NULL;
atom_coord = NULL;
model_atom = NULL;
model_atom_buf = NULL;
}
/* ----------------------------------------------------------------------
parse optional parameters at end of input line
------------------------------------------------------------------------- */
void FixGCMC::options(int narg, char **arg)
{
if (narg < 0) error->all(FLERR,"Illegal fix gcmc command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"molecule") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command");
if (strcmp(arg[iarg+1],"no") == 0) molflag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) molflag = 1;
else error->all(FLERR,"Illegal fix gcmc command");
iarg += 2;
} else if (strcmp(arg[iarg],"region") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command");
iregion = domain->find_region(arg[iarg+1]);
if (iregion == -1)
error->all(FLERR,"Region ID for fix gcmc does not exist");
int n = strlen(arg[iarg+1]) + 1;
idregion = new char[n];
strcpy(idregion,arg[iarg+1]);
regionflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"maxangle") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command");
max_rotation_angle = force->numeric(FLERR,arg[iarg+1]);
max_rotation_angle *= MY_PI/180;
iarg += 2;
} else if (strcmp(arg[iarg],"pressure") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command");
pressure = force->numeric(FLERR,arg[iarg+1]);
pressure_flag = true;
iarg += 2;
} else if (strcmp(arg[iarg],"fugacity_coeff") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix gcmc command");
fugacity_coeff = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else error->all(FLERR,"Illegal fix gcmc command");
}
}
/* ---------------------------------------------------------------------- */
FixGCMC::~FixGCMC()
{
if (regionflag) delete [] idregion;
delete random_equal;
delete random_unequal;
memory->destroy(local_gas_list);
memory->destroy(atom_coord);
memory->destroy(model_atom_buf);
delete model_atom;
}
/* ---------------------------------------------------------------------- */
int FixGCMC::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixGCMC::init()
{
int *type = atom->type;
if (molflag == 0) {
if (ngcmc_type <= 0 || ngcmc_type > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix gcmc command");
}
// if molflag not set, warn if any deletable atom has a mol ID
if (molflag == 0 && atom->molecule_flag) {
int *molecule = atom->molecule;
int *mask = atom->mask;
int flag = 0;
for (int i = 0; i < atom->nlocal; i++)
if (type[i] == ngcmc_type)
if (molecule[i]) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->all(FLERR,
"Fix gcmc cannot exchange individual atoms belonging to a molecule");
}
// if molflag set, check for unset mol IDs
if (molflag == 1) {
int *molecule = atom->molecule;
int *mask = atom->mask;
int flag = 0;
for (int i = 0; i < atom->nlocal; i++)
if (mask[i] == groupbit)
if (molecule[i] == 0) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->all(FLERR,
"All mol IDs should be set for fix gcmc group atoms");
}
if ((molflag && (atom->molecule_flag == 0)) ||
- (molflag && ((!atom->tag_enable) || (!atom->map_style))))
+ (molflag && (!atom->tag_enable || !atom->map_style)))
error->all(FLERR,
- "Fix gcmc molecule command requires that atoms have molecule attributes");
+ "Fix gcmc molecule command requires that "
+ "atoms have molecule attributes");
if (force->pair->single_enable == 0)
error->all(FLERR,"Fix gcmc incompatible with given pair_style");
if (domain->dimension == 2)
error->all(FLERR,"Cannot use fix gcmc in a 2d simulation");
if (domain->triclinic == 1)
error->all(FLERR,"Cannot use fix gcmc with a triclinic box");
// create a new group for rotation molecules
if (molflag) {
char **group_arg = new char*[3];
group_arg[0] = (char *) "rotation_gas_atoms";
group_arg[1] = (char *) "molecule";
char digits[12];
sprintf(digits,"%d",ngcmc_type);
group_arg[2] = digits;
group->assign(3,group_arg);
rotation_group = group->find(group_arg[0]);
if (rotation_group == -1)
error->all(FLERR,"Could not find fix gcmc rotation group ID");
rotation_groupbit = group->bitmask[rotation_group];
rotation_inversegroupbit = rotation_groupbit ^ ~0;
delete [] group_arg;
}
// get all of the needed molecule data if molflag,
// otherwise just get the gas mass
if (molflag) get_model_molecule();
else gas_mass = atom->mass[ngcmc_type];
if (gas_mass <= 0.0)
error->all(FLERR,"Illegal fix gcmc gas mass <= 0");
// check that no deletable atoms are in atom->firstgroup
// deleting such an atom would not leave firstgroup atoms first
if (atom->firstgroup >= 0) {
int *mask = atom->mask;
int firstgroupbit = group->bitmask[atom->firstgroup];
int flag = 0;
for (int i = 0; i < atom->nlocal; i++)
if ((mask[i] == groupbit) && (mask[i] && firstgroupbit)) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall)
error->all(FLERR,"Cannot do GCMC on atoms in atom_modify first group");
}
// compute beta, lambda, sigma, and the zz factor
beta = 1.0/(force->boltz*reservoir_temperature);
double lambda = sqrt(force->hplanck*force->hplanck/
(2.0*MY_PI*gas_mass*force->mvv2e*
force->boltz*reservoir_temperature));
sigma = sqrt(force->boltz*reservoir_temperature/gas_mass/force->mvv2e);
zz = exp(beta*chemical_potential)/(pow(lambda,3.0));
if (pressure_flag) zz = pressure*fugacity_coeff*beta/force->nktv2p;
imagetmp = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
}
/* ----------------------------------------------------------------------
attempt Monte Carlo translations, rotations, insertions, and deletions
done before exchange, borders, reneighbor
so that ghost atoms and neighbor lists will be correct
------------------------------------------------------------------------- */
void FixGCMC::pre_exchange()
{
// just return if should not be called on this timestep
if (next_reneighbor != update->ntimestep) return;
xlo = domain->boxlo[0];
xhi = domain->boxhi[0];
ylo = domain->boxlo[1];
yhi = domain->boxhi[1];
zlo = domain->boxlo[2];
zhi = domain->boxhi[2];
sublo = domain->sublo;
subhi = domain->subhi;
if (regionflag) volume = region_volume;
else volume = domain->xprd * domain->yprd * domain->zprd;
domain->pbc();
comm->exchange();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
if (molflag) {
for (int i = 0; i < ncycles; i++) {
int random_int_fraction =
static_cast<int>(random_equal->uniform()*ncycles) + 1;
if (random_int_fraction <= nmcmoves) {
if (random_equal->uniform() < 0.5) attempt_molecule_translation();
else attempt_molecule_rotation();
} else {
if (random_equal->uniform() < 0.5) attempt_molecule_deletion();
else attempt_molecule_insertion();
}
}
} else {
for (int i = 0; i < ncycles; i++) {
int random_int_fraction =
static_cast<int>(random_equal->uniform()*ncycles) + 1;
if (random_int_fraction <= nmcmoves) {
attempt_atomic_translation();
} else {
if (random_equal->uniform() < 0.5) attempt_atomic_deletion();
else attempt_atomic_insertion();
}
}
}
next_reneighbor = update->ntimestep + nevery;
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_atomic_translation()
{
ntranslation_attempts += 1.0;
if (ngas == 0) return;
int i = pick_random_gas_atom();
int success = 0;
if (i >= 0) {
double **x = atom->x;
double energy_before = energy(i,ngcmc_type,-1,x[i]);
double rsq = 1.1;
double rx,ry,rz;
rx = ry = rz = 0.0;
while (rsq > 1.0) {
rx = 2*random_unequal->uniform() - 1.0;
ry = 2*random_unequal->uniform() - 1.0;
rz = 2*random_unequal->uniform() - 1.0;
rsq = rx*rx + ry*ry + rz*rz;
}
double coord[3];
coord[0] = x[i][0] + displace*rx;
coord[1] = x[i][1] + displace*ry;
coord[2] = x[i][2] + displace*rz;
double energy_after = energy(i,ngcmc_type,-1,coord);
if (random_unequal->uniform() <
exp(-beta*(energy_after - energy_before))) {
x[i][0] = coord[0];
x[i][1] = coord[1];
x[i][2] = coord[2];
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
domain->pbc();
comm->exchange();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ntranslation_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_atomic_deletion()
{
ndeletion_attempts += 1.0;
if (ngas == 0) return;
int i = pick_random_gas_atom();
int success = 0;
if (i >= 0) {
double deletion_energy = energy(i,ngcmc_type,-1,atom->x[i]);
if (random_unequal->uniform() <
ngas*exp(beta*deletion_energy)/(zz*volume)) {
atom->avec->copy(atom->nlocal-1,i,1);
atom->nlocal--;
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
if (atom->tag_enable) {
atom->natoms--;
if (atom->map_style) atom->map_init();
}
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ndeletion_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_atomic_insertion()
{
ninsertion_attempts += 1.0;
double coord[3];
if (regionflag) {
int region_attempt = 0;
coord[0] = region_xlo + random_equal->uniform() * (region_xhi-region_xlo);
coord[1] = region_ylo + random_equal->uniform() * (region_yhi-region_ylo);
coord[2] = region_zlo + random_equal->uniform() * (region_zhi-region_zlo);
while (domain->regions[iregion]->match(coord[0],coord[1],coord[2]) == 0) {
coord[0] = region_xlo + random_equal->uniform() * (region_xhi-region_xlo);
coord[1] = region_ylo + random_equal->uniform() * (region_yhi-region_ylo);
coord[2] = region_zlo + random_equal->uniform() * (region_zhi-region_zlo);
region_attempt++;
if (region_attempt >= max_region_attempts) return;
}
} else {
coord[0] = xlo + random_equal->uniform() * (xhi-xlo);
coord[1] = ylo + random_equal->uniform() * (yhi-ylo);
coord[2] = zlo + random_equal->uniform() * (zhi-zlo);
}
int proc_flag = 0;
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2]) proc_flag = 1;
int success = 0;
if (proc_flag) {
double insertion_energy = energy(-1,ngcmc_type,-1,coord);
if (random_unequal->uniform() <
zz*volume*exp(-beta*insertion_energy)/(ngas+1)) {
atom->avec->create_atom(ngcmc_type,coord);
int m = atom->nlocal - 1;
atom->mask[m] = 1 | groupbit;
atom->v[m][0] = random_unequal->gaussian()*sigma;
atom->v[m][1] = random_unequal->gaussian()*sigma;
atom->v[m][2] = random_unequal->gaussian()*sigma;
int nfix = modify->nfix;
Fix **fix = modify->fix;
for (int j = 0; j < nfix; j++)
if (fix[j]->create_attribute) fix[j]->set_arrays(m);
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
if (atom->tag_enable) {
atom->natoms++;
atom->tag_extend();
if (atom->map_style) atom->map_init();
}
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ninsertion_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_molecule_translation()
{
ntranslation_attempts += 1.0;
if (ngas == 0) return;
int translation_molecule = pick_random_gas_molecule();
if (translation_molecule == -1) return;
double energy_before_sum = molecule_energy(translation_molecule);
double **x = atom->x;
double rx,ry,rz;
double com_displace[3],coord[3];
double rsq = 1.1;
while (rsq > 1.0) {
rx = 2*random_equal->uniform() - 1.0;
ry = 2*random_equal->uniform() - 1.0;
rz = 2*random_equal->uniform() - 1.0;
rsq = rx*rx + ry*ry + rz*rz;
}
com_displace[0] = displace*rx;
com_displace[1] = displace*ry;
com_displace[2] = displace*rz;
double energy_after = 0.0;
for (int i = 0; i < atom->nlocal; i++) {
if (atom->molecule[i] == translation_molecule) {
coord[0] = x[i][0] + com_displace[0];
coord[1] = x[i][1] + com_displace[1];
coord[2] = x[i][2] + com_displace[2];
energy_after += energy(i,atom->type[i],translation_molecule,coord);
}
}
double energy_after_sum = 0.0;
MPI_Allreduce(&energy_after,&energy_after_sum,1,MPI_DOUBLE,MPI_SUM,world);
if (random_equal->uniform() <
exp(-beta*(energy_after_sum - energy_before_sum))) {
for (int i = 0; i < atom->nlocal; i++) {
if (atom->molecule[i] == translation_molecule) {
x[i][0] += com_displace[0];
x[i][1] += com_displace[1];
x[i][2] += com_displace[2];
}
}
domain->pbc();
comm->exchange();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ntranslation_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_molecule_rotation()
{
nrotation_attempts += 1.0;
if (ngas == 0) return;
int rotation_molecule = pick_random_gas_molecule();
if (rotation_molecule == -1) return;
double energy_before_sum = molecule_energy(rotation_molecule);
int nlocal = atom->nlocal;
int *mask = atom->mask;
for (int i = 0; i < nlocal; i++) {
if (atom->molecule[i] == rotation_molecule) {
mask[i] |= rotation_groupbit;
} else {
mask[i] &= rotation_inversegroupbit;
}
}
double com[3];
com[0] = com[1] = com[2] = 0.0;
group->xcm(rotation_group,gas_mass,com);
double rot[9];
get_rotation_matrix(max_rotation_angle,&rot[0]);
double **x = atom->x;
imageint *image = atom->image;
double energy_after = 0.0;
int n = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & rotation_groupbit) {
double xtmp[3];
domain->unmap(x[i],image[i],xtmp);
xtmp[0] -= com[0];
xtmp[1] -= com[1];
xtmp[2] -= com[2];
atom_coord[n][0] =
rot[0]*xtmp[0] + rot[1]*xtmp[1] + rot[2]*xtmp[2] + com[0];
atom_coord[n][1] =
rot[3]*xtmp[0] + rot[4]*xtmp[1] + rot[5]*xtmp[2] + com[1];
atom_coord[n][2] =
rot[6]*xtmp[0] + rot[7]*xtmp[1] + rot[8]*xtmp[2] + com[2];
xtmp[0] = atom_coord[n][0];
xtmp[1] = atom_coord[n][1];
xtmp[2] = atom_coord[n][2];
domain->remap(xtmp);
energy_after += energy(i,atom->type[i],rotation_molecule,xtmp);
n++;
}
}
double energy_after_sum = 0.0;
MPI_Allreduce(&energy_after,&energy_after_sum,1,MPI_DOUBLE,MPI_SUM,world);
if (random_equal->uniform() <
exp(-beta*(energy_after_sum - energy_before_sum))) {
int n = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & rotation_groupbit) {
image[i] = imagetmp;
x[i][0] = atom_coord[n][0];
x[i][1] = atom_coord[n][1];
x[i][2] = atom_coord[n][2];
domain->remap(x[i],image[i]);
n++;
}
}
domain->pbc();
comm->exchange();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
nrotation_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_molecule_deletion()
{
ndeletion_attempts += 1.0;
if (ngas == 0) return;
int deletion_molecule = pick_random_gas_molecule();
if (deletion_molecule == -1) return;
double deletion_energy_sum = molecule_energy(deletion_molecule);
if (random_equal->uniform() <
ngas*exp(beta*deletion_energy_sum)/(zz*volume*natoms_per_molecule)) {
int i = 0;
while (i < atom->nlocal) {
if (atom->molecule[i] == deletion_molecule) {
atom->avec->copy(atom->nlocal-1,i,1);
atom->nlocal--;
} else i++;
}
atom->natoms -= natoms_per_molecule;
atom->map_init();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ndeletion_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void FixGCMC::attempt_molecule_insertion()
{
ninsertion_attempts += 1.0;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double com_coord[3];
if (regionflag) {
int region_attempt = 0;
com_coord[0] = region_xlo + random_equal->uniform() * (region_xhi-region_xlo);
com_coord[1] = region_ylo + random_equal->uniform() * (region_yhi-region_ylo);
com_coord[2] = region_zlo + random_equal->uniform() * (region_zhi-region_zlo);
while (domain->regions[iregion]->match(com_coord[0],com_coord[1],com_coord[2]) == 0) {
com_coord[0] = region_xlo + random_equal->uniform() * (region_xhi-region_xlo);
com_coord[1] = region_ylo + random_equal->uniform() * (region_yhi-region_ylo);
com_coord[2] = region_zlo + random_equal->uniform() * (region_zhi-region_zlo);
region_attempt++;
if (region_attempt >= max_region_attempts) return;
}
} else {
com_coord[0] = xlo + random_equal->uniform() * (xhi-xlo);
com_coord[1] = ylo + random_equal->uniform() * (yhi-ylo);
com_coord[2] = zlo + random_equal->uniform() * (zhi-zlo);
}
double rot[9];
get_rotation_matrix(MY_2PI,&rot[0]);
double **model_x = model_atom->x;
double insertion_energy = 0.0;
bool procflag[natoms_per_molecule];
for (int i = 0; i < natoms_per_molecule; i++) {
atom_coord[i][0] = rot[0]*model_x[i][0] + rot[1]*model_x[i][1] + rot[2]*model_x[i][2] + com_coord[0];
atom_coord[i][1] = rot[3]*model_x[i][0] + rot[4]*model_x[i][1] + rot[5]*model_x[i][2] + com_coord[1];
atom_coord[i][2] = rot[6]*model_x[i][0] + rot[7]*model_x[i][1] + rot[8]*model_x[i][2] + com_coord[2];
double xtmp[3];
xtmp[0] = atom_coord[i][0];
xtmp[1] = atom_coord[i][1];
xtmp[2] = atom_coord[i][2];
domain->remap(xtmp);
procflag[i] = false;
if (xtmp[0] >= sublo[0] && xtmp[0] < subhi[0] &&
xtmp[1] >= sublo[1] && xtmp[1] < subhi[1] &&
xtmp[2] >= sublo[2] && xtmp[2] < subhi[2]) {
procflag[i] = true;
insertion_energy += energy(-1,model_atom->type[i],-1,xtmp);
}
}
double insertion_energy_sum = 0.0;
MPI_Allreduce(&insertion_energy,&insertion_energy_sum,1,MPI_DOUBLE,MPI_SUM,world);
if (random_equal->uniform() < zz*volume*natoms_per_molecule*exp(-beta*insertion_energy_sum)/(ngas+1)) {
maxmol++;
if (maxmol >= MAXSMALLINT)
error->all(FLERR,"Fix gcmc ran out of available molecule IDs");
- int maxtag = 0;
+ tagint maxtag = 0;
for (int i = 0; i < atom->nlocal; i++) maxtag = MAX(maxtag,atom->tag[i]);
- int maxtag_all;
- MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_INT,MPI_MAX,world);
- int atom_offset = maxtag_all;
+ tagint maxtag_all;
+ MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world);
+ tagint atom_offset = maxtag_all;
int k = 0;
double **x = atom->x;
double **v = atom->v;
imageint *image = atom->image;
int *molecule = atom->molecule;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int i = 0; i < natoms_per_molecule; i++) {
k += atom->avec->unpack_exchange(&model_atom_buf[k]);
if (procflag[i]) {
int m = atom->nlocal - 1;
image[m] = imagetmp;
x[m][0] = atom_coord[i][0];
x[m][1] = atom_coord[i][1];
x[m][2] = atom_coord[i][2];
domain->remap(x[m],image[m]);
atom->molecule[m] = maxmol;
tag[m] += atom_offset;
v[m][0] = random_unequal->gaussian()*sigma;
v[m][1] = random_unequal->gaussian()*sigma;
v[m][2] = random_unequal->gaussian()*sigma;
if (atom->avec->bonds_allow)
for (int j = 0; j < atom->num_bond[m]; j++)
atom->bond_atom[m][j] += atom_offset;
if (atom->avec->angles_allow)
for (int j = 0; j < atom->num_angle[m]; j++) {
atom->angle_atom1[m][j] += atom_offset;
atom->angle_atom2[m][j] += atom_offset;
atom->angle_atom3[m][j] += atom_offset;
}
if (atom->avec->dihedrals_allow)
for (int j = 0; j < atom->num_dihedral[m]; j++) {
atom->dihedral_atom1[m][j] += atom_offset;
atom->dihedral_atom2[m][j] += atom_offset;
atom->dihedral_atom3[m][j] += atom_offset;
atom->dihedral_atom4[m][j] += atom_offset;
}
if (atom->avec->impropers_allow)
for (int j = 0; j < atom->num_improper[m]; j++) {
atom->improper_atom1[m][j] += atom_offset;
atom->improper_atom2[m][j] += atom_offset;
atom->improper_atom3[m][j] += atom_offset;
atom->improper_atom4[m][j] += atom_offset;
}
for (int j = 0; j < atom->nspecial[m][2]; j++)
atom->special[m][j] += atom_offset;
int nfix = modify->nfix;
Fix **fix = modify->fix;
for (int j = 0; j < nfix; j++) {
if (strcmp(modify->fix[j]->style,"shake") == 0) {
fix[j]->update_arrays(m,atom_offset);
} else if (fix[j]->create_attribute) fix[j]->set_arrays(m);
}
} else atom->nlocal--;
}
atom->natoms += natoms_per_molecule;
atom->map_init();
atom->nghost = 0;
comm->borders();
update_gas_atoms_list();
ninsertion_successes += 1.0;
}
}
/* ----------------------------------------------------------------------
compute particle's interaction energy with the rest of the system
------------------------------------------------------------------------- */
double FixGCMC::energy(int i, int itype, int imolecule, double *coord)
{
double delx,dely,delz,rsq;
double **x = atom->x;
int *type = atom->type;
int *molecule = atom->molecule;
int nall = atom->nlocal + atom->nghost;
pair = force->pair;
cutsq = force->pair->cutsq;
double fpair = 0.0;
double factor_coul = 1.0;
double factor_lj = 1.0;
double total_energy = 0.0;
for (int j = 0; j < nall; j++) {
if (i == j) continue;
if (molflag)
if (imolecule == molecule[j]) continue;
delx = coord[0] - x[j][0];
dely = coord[1] - x[j][1];
delz = coord[2] - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
int jtype = type[j];
if (rsq < cutsq[itype][jtype])
total_energy +=
pair->single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fpair);
}
return total_energy;
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
int FixGCMC::pick_random_gas_atom()
{
int i = -1;
int iwhichglobal = static_cast<int> (ngas*random_equal->uniform());
if ((iwhichglobal >= ngas_before) &&
(iwhichglobal < ngas_before + ngas_local)) {
int iwhichlocal = iwhichglobal - ngas_before;
i = local_gas_list[iwhichlocal];
}
return i;
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
int FixGCMC::pick_random_gas_molecule()
{
int iwhichglobal = static_cast<int> (ngas*random_equal->uniform());
int gas_molecule_id = 0;
if ((iwhichglobal >= ngas_before) &&
(iwhichglobal < ngas_before + ngas_local)) {
int iwhichlocal = iwhichglobal - ngas_before;
int i = local_gas_list[iwhichlocal];
gas_molecule_id = atom->molecule[i];
}
int gas_molecule_id_all = 0;
MPI_Allreduce(&gas_molecule_id,&gas_molecule_id_all,1,MPI_INT,MPI_MAX,world);
return gas_molecule_id_all;
}
/* ----------------------------------------------------------------------
compute the energy of the given gas molecule in its current position
sum across all procs that own atoms of the given molecule
------------------------------------------------------------------------- */
double FixGCMC::molecule_energy(int gas_molecule_id)
{
double mol_energy = 0.0;
for (int i = 0; i < atom->nlocal; i++)
if (atom->molecule[i] == gas_molecule_id) {
mol_energy += energy(i,atom->type[i],gas_molecule_id,atom->x[i]);
}
double mol_energy_sum = 0.0;
MPI_Allreduce(&mol_energy,&mol_energy_sum,1,MPI_DOUBLE,MPI_SUM,world);
return mol_energy_sum;
}
/* ----------------------------------------------------------------------
compute a 3x3 rotation matrix using 3 random Euler angles,
each with a random maximum value supplied by the caller
------------------------------------------------------------------------- */
void FixGCMC::get_rotation_matrix(double max_angle, double *rot)
{
double angle_x = max_angle*random_equal->uniform();
double angle_y = max_angle*random_equal->uniform();
double angle_z = max_angle*random_equal->uniform();
double a = cos(angle_x);
double b = sin(angle_x);
double c = cos(angle_y);
double d = sin(angle_y);
double e = cos(angle_z);
double f = sin(angle_z);
double ad = a*d;
double bd = b*d;
rot[0] = c*e;
rot[1] = -c*f;
rot[2] = -d;
rot[3] = -bd*e + a*f;
rot[4] = bd*f + a*e;
rot[5] = -b*c;
rot[6] = ad*e + b*f;
rot[7] = -ad*f + b*e;
rot[8] = a*c;
}
/* ----------------------------------------------------------------------
when using the molecule capability, populate model atom arrays from
the model molecule provided by the user that will then be used to build
inserted molecules
------------------------------------------------------------------------- */
void FixGCMC::get_model_molecule()
{
// find out how many atoms are in the model molecule
// just loop through all of the atoms I own, then sum up across procs
int model_molecule_number = ngcmc_type;
int natoms_per_molecule_local = 0;
for (int i = 0; i < atom->nlocal; i++) {
if (atom->molecule[i] == model_molecule_number) {
natoms_per_molecule_local++;
}
}
natoms_per_molecule = 0;
MPI_Allreduce(&natoms_per_molecule_local,&natoms_per_molecule,1,
MPI_INT,MPI_SUM,world);
if (natoms_per_molecule == 0)
error->all(FLERR,"Fix gcmc could not find any atoms "
"in the user-supplied template molecule");
memory->create(atom_coord,natoms_per_molecule,3,"fixGCMC:atom_coord");
// maxmol = largest molecule tag across all existing atoms
maxmol = 0;
if (atom->molecular) {
for (int i = 0; i < atom->nlocal; i++)
maxmol = MAX(atom->molecule[i],maxmol);
int maxmol_all;
MPI_Allreduce(&maxmol,&maxmol_all,1,MPI_INT,MPI_MAX,world);
maxmol = maxmol_all;
}
// communication buffer for model atom's info
// max_size = largest buffer needed by any proc
// must do before new Atom class created,
// since size_restart() uses atom->nlocal
int max_size;
int buf_send_size = atom->avec->size_restart();
MPI_Allreduce(&buf_send_size,&max_size,1,MPI_INT,MPI_MAX,world);
max_size *= 2;
double *buf;
memory->create(buf,max_size,"fixGCMC:buf");
// create storage space for the model molecule's atoms
// create a new atom object called atom to store the data
// old_atom = original atom class
// atom = new model atom class
// if old_atom style was hybrid, pass sub-style names to create_avec
Atom *old_atom = atom;
atom = new Atom(lmp);
atom->settings(old_atom);
int nstyles = 0;
char **keywords = NULL;
if (strcmp(old_atom->atom_style,"hybrid") == 0) {
AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) old_atom->avec;
nstyles = avec_hybrid->nstyles;
keywords = avec_hybrid->keywords;
}
atom->create_avec(old_atom->atom_style,nstyles,keywords);
// assign atom and topology counts in model atom class from old_atom
atom->ntypes = old_atom->ntypes;
atom->nbondtypes = old_atom->nbondtypes;
atom->nangletypes = old_atom->nangletypes;
atom->ndihedraltypes = old_atom->ndihedraltypes;
atom->nimpropertypes = old_atom->nimpropertypes;
atom->bond_per_atom = old_atom->bond_per_atom;
atom->angle_per_atom = old_atom->angle_per_atom;
atom->dihedral_per_atom = old_atom->dihedral_per_atom;
atom->improper_per_atom = old_atom->improper_per_atom;
atom->maxspecial = old_atom->maxspecial;
atom->nextra_grow = old_atom->nextra_grow;
if (atom->nextra_grow) {
memory->grow(atom->extra_grow,old_atom->nextra_grow_max,
"fixGCMC:extra_grow");
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
atom->extra_grow[iextra] = old_atom->extra_grow[iextra];
}
atom->extra_bond_per_atom = old_atom->extra_bond_per_atom;
atom->allocate_type_arrays();
atom->avec->grow(natoms_per_molecule + old_atom->nlocal);
// copy type arrays to model atom class
if (atom->mass) {
for (int itype = 1; itype <= atom->ntypes; itype++) {
atom->mass_setflag[itype] = old_atom->mass_setflag[itype];
if (atom->mass_setflag[itype]) atom->mass[itype] = old_atom->mass[itype];
}
}
// loop over all procs
// if this iteration of loop is me:
// pack my atom data into buf
// bcast it to all other procs
AtomVec *old_avec = old_atom->avec;
AtomVec *model_avec = atom->avec;
int model_buf_size = 0;
for (int iproc = 0; iproc < comm->nprocs; iproc++) {
int nbuf_iproc = 0;
if (comm->me == iproc) {
for (int i = 0; i < old_atom->nlocal; i++) {
if (old_atom->molecule[i] == model_molecule_number) {
nbuf_iproc += old_avec->pack_exchange(i,&buf[nbuf_iproc]);
}
}
}
MPI_Bcast(&nbuf_iproc,1,MPI_INT,iproc,world);
MPI_Bcast(buf,nbuf_iproc,MPI_DOUBLE,iproc,world);
model_buf_size += nbuf_iproc;
int m = 0;
while (m < nbuf_iproc)
m += model_avec->unpack_exchange(&buf[m]);
}
// free communication buffer
memory->destroy(buf);
// make sure that the number of model atoms is
// equal to the number of atoms per gas molecule
int nlocal = atom->nlocal;
if (nlocal != natoms_per_molecule)
error->all(FLERR,"Fix gcmc incorrect number of atoms per molecule");
// compute the model molecule's mass and center-of-mass
// then recenter model molecule on the origin
double com[3];
gas_mass = group->mass(0);
group->xcm(0,gas_mass,com);
double **x = atom->x;
for (int i = 0; i < nlocal; i++) {
domain->unmap(x[i],atom->image[i]);
x[i][0] -= com[0];
x[i][1] -= com[1];
x[i][2] -= com[2];
}
- int mintag = atom->tag[0];
+ tagint mintag = atom->tag[0];
for (int i = 0; i < atom->nlocal; i++) mintag = MIN(mintag,atom->tag[i]);
- int atom_offset = mintag - 1;
+ tagint atom_offset = mintag - 1;
for (int i = 0; i < nlocal; i++) {
atom->mask[i] = 1 | groupbit;
atom->tag[i] -= atom_offset;
if (atom->avec->bonds_allow)
for (int j = 0; j < atom->num_bond[i]; j++)
atom->bond_atom[i][j] -= atom_offset;
if (atom->avec->angles_allow)
for (int j = 0; j < atom->num_angle[i]; j++) {
atom->angle_atom1[i][j] -= atom_offset;
atom->angle_atom2[i][j] -= atom_offset;
atom->angle_atom3[i][j] -= atom_offset;
}
if (atom->avec->dihedrals_allow)
for (int j = 0; j < atom->num_dihedral[i]; j++) {
atom->dihedral_atom1[i][j] -= atom_offset;
atom->dihedral_atom2[i][j] -= atom_offset;
atom->dihedral_atom3[i][j] -= atom_offset;
atom->dihedral_atom4[i][j] -= atom_offset;
}
if (atom->avec->impropers_allow)
for (int j = 0; j < atom->num_improper[i]; j++) {
atom->improper_atom1[i][j] -= atom_offset;
atom->improper_atom2[i][j] -= atom_offset;
atom->improper_atom3[i][j] -= atom_offset;
atom->improper_atom4[i][j] -= atom_offset;
}
for (int j = 0; j < atom->nspecial[i][2]; j++)
atom->special[i][j] -= atom_offset;
}
// pack model atoms into a buffer for use during molecule insertions
memory->create(model_atom_buf,model_buf_size,"fixGCMC:model_atom_buf");
int n = 0;
for (int i = 0; i < nlocal; i++)
n += model_avec->pack_exchange(i,&model_atom_buf[n]);
// move atom to model_atom and restore old_atom class pointer back to atom
model_atom = atom;
atom = old_atom;
}
/* ----------------------------------------------------------------------
update the list of gas atoms
------------------------------------------------------------------------- */
void FixGCMC::update_gas_atoms_list()
{
if (atom->nlocal > gcmc_nmax) {
memory->sfree(local_gas_list);
gcmc_nmax = atom->nmax;
local_gas_list = (int *) memory->smalloc(gcmc_nmax*sizeof(int),
"GCMC:local_gas_list");
}
ngas_local = 0;
if (regionflag) {
for (int i = 0; i < atom->nlocal; i++) {
if (atom->mask[i] & groupbit) {
double **x = atom->x;
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]) == 1) {
local_gas_list[ngas_local] = i;
ngas_local++;
}
}
}
} else {
for (int i = 0; i < atom->nlocal; i++) {
if (atom->mask[i] & groupbit) {
local_gas_list[ngas_local] = i;
ngas_local++;
}
}
}
MPI_Allreduce(&ngas_local,&ngas,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ngas_local,&ngas_before,1,MPI_INT,MPI_SUM,world);
ngas_before -= ngas_local;
}
/* ----------------------------------------------------------------------
return acceptance ratios
------------------------------------------------------------------------- */
double FixGCMC::compute_vector(int n)
{
if (n == 0) return ntranslation_attempts;
if (n == 1) return ntranslation_successes;
if (n == 2) return ninsertion_attempts;
if (n == 3) return ninsertion_successes;
if (n == 4) return ndeletion_attempts;
if (n == 5) return ndeletion_successes;
if (n == 6) return nrotation_attempts;
if (n == 7) return nrotation_successes;
return 0.0;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixGCMC::memory_usage()
{
double bytes = gcmc_nmax * sizeof(int);
return bytes;
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixGCMC::write_restart(FILE *fp)
{
int n = 0;
double list[4];
list[n++] = random_equal->state();
list[n++] = random_unequal->state();
list[n++] = next_reneighbor;
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 FixGCMC::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
seed = static_cast<int> (list[n++]);
random_equal->reset(seed);
seed = static_cast<int> (list[n++]);
random_unequal->reset(seed);
next_reneighbor = static_cast<int> (list[n++]);
}
diff --git a/src/MISC/fix_deposit.cpp b/src/MISC/fix_deposit.cpp
index fa8dbf6c6..ea8fb37be 100644
--- a/src/MISC/fix_deposit.cpp
+++ b/src/MISC/fix_deposit.cpp
@@ -1,703 +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.
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "fix_deposit.h"
#include "atom.h"
#include "atom_vec.h"
#include "molecule.h"
#include "force.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "comm.h"
#include "domain.h"
#include "lattice.h"
#include "region.h"
#include "random_park.h"
#include "math_extra.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
enum{ATOM,MOLECULE};
/* ---------------------------------------------------------------------- */
FixDeposit::FixDeposit(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 7) error->all(FLERR,"Illegal fix deposit command");
restart_global = 1;
time_depend = 1;
// required args
ninsert = force->inumeric(FLERR,arg[3]);
ntype = force->inumeric(FLERR,arg[4]);
nfreq = force->inumeric(FLERR,arg[5]);
seed = force->inumeric(FLERR,arg[6]);
if (seed <= 0) error->all(FLERR,"Illegal fix deposit command");
// read options from end of input line
options(narg-7,&arg[7]);
// error check on type
if (mode == ATOM && (ntype <= 0 || ntype > atom->ntypes))
error->all(FLERR,"Invalid atom type in fix deposit command");
// error checks on region and its extent being inside simulation box
if (iregion == -1) error->all(FLERR,"Must specify a region in fix deposit");
if (domain->regions[iregion]->bboxflag == 0)
error->all(FLERR,"Fix deposit region does not support a bounding box");
if (domain->regions[iregion]->dynamic_check())
error->all(FLERR,"Fix deposit region cannot be dynamic");
xlo = domain->regions[iregion]->extent_xlo;
xhi = domain->regions[iregion]->extent_xhi;
ylo = domain->regions[iregion]->extent_ylo;
yhi = domain->regions[iregion]->extent_yhi;
zlo = domain->regions[iregion]->extent_zlo;
zhi = domain->regions[iregion]->extent_zhi;
if (domain->triclinic == 0) {
if (xlo < domain->boxlo[0] || xhi > domain->boxhi[0] ||
ylo < domain->boxlo[1] || yhi > domain->boxhi[1] ||
zlo < domain->boxlo[2] || zhi > domain->boxhi[2])
error->all(FLERR,"Deposition region extends outside simulation box");
} else {
if (xlo < domain->boxlo_bound[0] || xhi > domain->boxhi_bound[0] ||
ylo < domain->boxlo_bound[1] || yhi > domain->boxhi_bound[1] ||
zlo < domain->boxlo_bound[2] || zhi > domain->boxhi_bound[2])
error->all(FLERR,"Deposition region extends outside simulation box");
}
// error check and further setup for mode = MOLECULE
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use fix_deposit unless atoms have IDs");
if (mode == MOLECULE) {
if (onemol->xflag == 0)
error->all(FLERR,"Fix deposit molecule must have coordinates");
if (onemol->typeflag == 0)
error->all(FLERR,"Fix deposit molecule must have atom types");
if (ntype+onemol->maxtype <= 0 || ntype+onemol->maxtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in fix deposit mol command");
// fix deposit uses geoemetric center of molecule for insertion
onemol->compute_center();
}
if (rigidflag && mode == ATOM)
error->all(FLERR,"Cannot use fix deposit rigid and not molecule");
if (shakeflag && mode == ATOM)
error->all(FLERR,"Cannot use fix deposit shake and not molecule");
if (rigidflag && shakeflag)
error->all(FLERR,"Cannot use fix deposit rigid and shake");
// setup of coords and imageflags array
if (mode == ATOM) natom = 1;
else natom = onemol->natoms;
memory->create(coords,natom,3,"deposit:coords");
memory->create(imageflags,natom,"deposit:imageflags");
// setup scaling
double xscale,yscale,zscale;
if (scaleflag) {
xscale = domain->lattice->xlattice;
yscale = domain->lattice->ylattice;
zscale = domain->lattice->zlattice;
}
else xscale = yscale = zscale = 1.0;
// apply scaling to all input parameters with dist/vel units
if (domain->dimension == 2) {
lo *= yscale;
hi *= yscale;
rate *= yscale;
} else {
lo *= zscale;
hi *= zscale;
rate *= zscale;
}
deltasq *= xscale*xscale;
nearsq *= xscale*xscale;
vxlo *= xscale;
vxhi *= xscale;
vylo *= yscale;
vyhi *= yscale;
vzlo *= zscale;
vzhi *= zscale;
tx *= xscale;
ty *= yscale;
tz *= zscale;
// find current max atom and molecule IDs if necessary
if (idnext) find_maxid();
// random number generator, same for all procs
random = new RanPark(lmp,seed);
// set up reneighboring
force_reneighbor = 1;
next_reneighbor = update->ntimestep + 1;
nfirst = next_reneighbor;
ninserted = 0;
}
/* ---------------------------------------------------------------------- */
FixDeposit::~FixDeposit()
{
delete random;
delete [] idrigid;
delete [] idshake;
delete [] idregion;
memory->destroy(coords);
memory->destroy(imageflags);
}
/* ---------------------------------------------------------------------- */
int FixDeposit::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixDeposit::init()
{
// set index and check validity of region
iregion = domain->find_region(idregion);
if (iregion == -1)
error->all(FLERR,"Region ID for fix deposit does not exist");
// if rigidflag defined, check for rigid/small fix
// its molecule template must be same as this one
fixrigid = NULL;
if (rigidflag) {
int ifix = modify->find_fix(idrigid);
if (ifix < 0) error->all(FLERR,"Fix pour rigid fix does not exist");
fixrigid = modify->fix[ifix];
int tmp;
if (onemol != (Molecule *) fixrigid->extract("onemol",tmp))
error->all(FLERR,
"Fix deposit and fix rigid/small not using same molecule ID");
}
// if shakeflag defined, check for SHAKE fix
// its molecule template must be same as this one
fixshake = NULL;
if (shakeflag) {
int ifix = modify->find_fix(idshake);
if (ifix < 0) error->all(FLERR,"Fix deposit shake fix does not exist");
fixshake = modify->fix[ifix];
int tmp;
if (onemol != (Molecule *) fixshake->extract("onemol",tmp))
error->all(FLERR,"Fix deposit and fix shake not using same molecule ID");
}
}
/* ----------------------------------------------------------------------
perform particle insertion
------------------------------------------------------------------------- */
void FixDeposit::pre_exchange()
{
int i,j,m,n,nlocalprev,flag,flagall;
double coord[3],lamda[3],delx,dely,delz,rsq;
double alpha,beta,gamma;
double r[3],vnew[3],rotmat[3][3],quat[4];
double *newcoord;
// just return if should not be called on this timestep
if (next_reneighbor != update->ntimestep) return;
// compute current offset = bottom of insertion volume
double offset = 0.0;
if (rateflag) offset = (update->ntimestep - nfirst) * update->dt * rate;
double *sublo,*subhi;
if (domain->triclinic == 0) {
sublo = domain->sublo;
subhi = domain->subhi;
} else {
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
// find current max atom and molecule IDs if necessary
if (!idnext) find_maxid();
// attempt an insertion until successful
int dimension = domain->dimension;
int nfix = modify->nfix;
Fix **fix = modify->fix;
int success = 0;
int attempt = 0;
while (attempt < maxattempt) {
attempt++;
// choose random position for new particle within region
coord[0] = xlo + random->uniform() * (xhi-xlo);
coord[1] = ylo + random->uniform() * (yhi-ylo);
coord[2] = zlo + random->uniform() * (zhi-zlo);
while (domain->regions[iregion]->match(coord[0],coord[1],coord[2]) == 0) {
coord[0] = xlo + random->uniform() * (xhi-xlo);
coord[1] = ylo + random->uniform() * (yhi-ylo);
coord[2] = zlo + random->uniform() * (zhi-zlo);
}
// adjust vertical coord by offset
if (dimension == 2) coord[1] += offset;
else coord[2] += offset;
// if global, reset vertical coord to be lo-hi above highest atom
// if local, reset vertical coord to be lo-hi above highest "nearby" atom
// local computation computes lateral distance between 2 particles w/ PBC
// when done, have final coord of atom or center pt of molecule
if (globalflag || localflag) {
int dim;
double max,maxall,delx,dely,delz,rsq;
if (dimension == 2) {
dim = 1;
max = domain->boxlo[1];
} else {
dim = 2;
max = domain->boxlo[2];
}
double **x = atom->x;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) {
if (localflag) {
delx = coord[0] - x[i][0];
dely = coord[1] - x[i][1];
delz = 0.0;
domain->minimum_image(delx,dely,delz);
if (dimension == 2) rsq = delx*delx;
else rsq = delx*delx + dely*dely;
if (rsq > deltasq) continue;
}
if (x[i][dim] > max) max = x[i][dim];
}
MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world);
if (dimension == 2)
coord[1] = maxall + lo + random->uniform()*(hi-lo);
else
coord[2] = maxall + lo + random->uniform()*(hi-lo);
}
// coords = coords of all atoms
// for molecule, perform random rotation around center pt
// apply PBC so final coords are inside box
// also store image flag modified due to PBC
if (mode == ATOM) {
coords[0][0] = coord[0];
coords[0][1] = coord[1];
coords[0][2] = coord[2];
} else {
if (dimension == 3) {
r[0] = random->uniform() - 0.5;
r[1] = random->uniform() - 0.5;
r[2] = random->uniform() - 0.5;
} else {
r[0] = r[1] = 0.0;
r[2] = 1.0;
}
double theta = random->uniform() * MY_2PI;
MathExtra::norm3(r);
MathExtra::axisangle_to_quat(r,theta,quat);
MathExtra::quat_to_mat(quat,rotmat);
for (i = 0; i < natom; i++) {
MathExtra::matvec(rotmat,onemol->dx[i],coords[i]);
coords[i][0] += coord[0];
coords[i][1] += coord[1];
coords[i][2] += coord[2];
imageflags[i] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
domain->remap(coords[i],imageflags[i]);
}
}
// if distance to any inserted atom is less than near, try again
// use minimum_image() to account for PBC
double **x = atom->x;
int nlocal = atom->nlocal;
flag = 0;
for (m = 0; m < natom; m++) {
for (i = 0; i < nlocal; i++) {
delx = coords[m][0] - x[i][0];
dely = coords[m][1] - x[i][1];
delz = coords[m][2] - x[i][2];
domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < nearsq) flag = 1;
}
}
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall) continue;
// proceed with insertion
nlocalprev = atom->nlocal;
// choose random velocity for new particle
// used for every atom in molecule
vnew[0] = vxlo + random->uniform() * (vxhi-vxlo);
vnew[1] = vylo + random->uniform() * (vyhi-vylo);
vnew[2] = vzlo + random->uniform() * (vzhi-vzlo);
// if target specified, change velocity vector accordingly
if (targetflag) {
double vel = sqrt(vnew[0]*vnew[0] + vnew[1]*vnew[1] + vnew[2]*vnew[2]);
delx = tx - coord[0];
dely = ty - coord[1];
delz = tz - coord[2];
double rsq = delx*delx + dely*dely + delz*delz;
if (rsq > 0.0) {
double rinv = sqrt(1.0/rsq);
vnew[0] = delx*rinv*vel;
vnew[1] = dely*rinv*vel;
vnew[2] = delz*rinv*vel;
}
}
// check if new atoms are in my sub-box or above it if I am highest proc
// if so, add atom to my list via create_atom()
// initialize additional info about the atoms
// set group mask to "all" plus fix group
for (m = 0; m < natom; m++) {
if (domain->triclinic) {
domain->x2lamda(coords[m],lamda);
newcoord = lamda;
} else newcoord = coords[m];
flag = 0;
if (newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1] &&
newcoord[2] >= sublo[2] && newcoord[2] < subhi[2]) flag = 1;
else if (dimension == 3 && newcoord[2] >= domain->boxhi[2] &&
comm->myloc[2] == comm->procgrid[2]-1 &&
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1]) flag = 1;
else if (dimension == 2 && newcoord[1] >= domain->boxhi[1] &&
comm->myloc[1] == comm->procgrid[1]-1 &&
newcoord[0] >= sublo[0] && newcoord[0] < subhi[0]) flag = 1;
if (flag) {
if (mode == ATOM) atom->avec->create_atom(ntype,coords[m]);
else atom->avec->create_atom(ntype+onemol->type[m],coords[m]);
n = atom->nlocal - 1;
atom->tag[n] = maxtag_all + m+1;
if (mode == MOLECULE && atom->molecule_flag)
atom->molecule[n] = maxmol_all+1;
atom->mask[n] = 1 | groupbit;
atom->image[n] = imageflags[m];
atom->v[n][0] = vnew[0];
atom->v[n][1] = vnew[1];
atom->v[n][2] = vnew[2];
if (mode == MOLECULE) atom->add_molecule_atom(onemol,m,n,maxtag_all);
for (j = 0; j < nfix; j++)
if (fix[j]->create_attribute) fix[j]->set_arrays(n);
}
// FixRigidSmall::set_molecule stores rigid body attributes
// coord is new position of geometric center of mol, not COM
// FixShake::set_molecule stores shake info for molecule
if (rigidflag)
fixrigid->set_molecule(nlocalprev,maxtag_all,coord,vnew,quat);
else if (shakeflag)
fixshake->set_molecule(nlocalprev,maxtag_all,coord,vnew,quat);
}
// old code: unsuccessful if no proc performed insertion of an atom
// don't think that check is necessary
// if get this far, should always be succesful
// would be hard to undo partial insertion for a molecule
// better to check how many atoms could be inserted (w/out inserting)
// then sum to insure all are inserted, before doing actual insertion
// MPI_Allreduce(&flag,&success,1,MPI_INT,MPI_MAX,world);
success = 1;
break;
}
// warn if not successful b/c too many attempts
if (!success && comm->me == 0)
error->warning(FLERR,"Particle deposition was unsuccessful",0);
// reset global natoms,nbonds,etc
// increment maxtag_all and maxmol_all if necessary
// if global map exists, reset it now instead of waiting for comm
// since adding atoms messes up ghosts
if (success) {
atom->natoms += natom;
+ if (atom->natoms < 0 || atom->natoms > MAXBIGINT)
+ error->all(FLERR,"Too many total atoms");
if (mode == MOLECULE) {
atom->nbonds += onemol->nbonds;
atom->nangles += onemol->nangles;
atom->ndihedrals += onemol->ndihedrals;
atom->nimpropers += onemol->nimpropers;
}
- if (idnext) {
- maxtag_all += natom;
- if (mode == MOLECULE && atom->molecule_flag) maxmol_all++;
- }
+ maxtag_all += natom;
+ if (maxtag_all >= MAXTAGINT)
+ error->all(FLERR,"New atom IDs exceed maximum allowed ID");
+ if (mode == MOLECULE && atom->molecule_flag) maxmol_all++;
if (atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
}
// next timestep to insert
// next_reneighbor = 0 if done
if (success) ninserted++;
if (ninserted < ninsert) next_reneighbor += nfreq;
else next_reneighbor = 0;
}
/* ----------------------------------------------------------------------
maxtag_all = current max atom ID for all atoms
maxmol_all = current max molecule ID for all atoms
------------------------------------------------------------------------- */
void FixDeposit::find_maxid()
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
- int max = 0;
+ tagint max = 0;
for (int i = 0; i < nlocal; i++) max = MAX(max,tag[i]);
- MPI_Allreduce(&max,&maxtag_all,1,MPI_INT,MPI_MAX,world);
+ MPI_Allreduce(&max,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world);
if (mode == MOLECULE && molecule) {
max = 0;
for (int i = 0; i < nlocal; i++) max = MAX(max,molecule[i]);
MPI_Allreduce(&max,&maxmol_all,1,MPI_INT,MPI_MAX,world);
}
}
/* ----------------------------------------------------------------------
parse optional parameters at end of input line
------------------------------------------------------------------------- */
void FixDeposit::options(int narg, char **arg)
{
// defaults
iregion = -1;
idregion = NULL;
mode = ATOM;
rigidflag = 0;
idrigid = NULL;
shakeflag = 0;
idshake = NULL;
idnext = 0;
globalflag = localflag = 0;
lo = hi = deltasq = 0.0;
nearsq = 0.0;
maxattempt = 10;
rateflag = 0;
vxlo = vxhi = vylo = vyhi = vzlo = vzhi = 0.0;
scaleflag = 1;
targetflag = 0;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"region") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
iregion = domain->find_region(arg[iarg+1]);
if (iregion == -1)
error->all(FLERR,"Region ID for fix deposit does not exist");
int n = strlen(arg[iarg+1]) + 1;
idregion = new char[n];
strcpy(idregion,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
int imol = atom->find_molecule(arg[iarg+1]);
if (imol == -1)
error->all(FLERR,"Molecule ID for fix deposit does not exist");
mode = MOLECULE;
onemol = atom->molecules[imol];
iarg += 2;
} else if (strcmp(arg[iarg],"rigid") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
int n = strlen(arg[iarg+1]) + 1;
delete [] idrigid;
idrigid = new char[n];
strcpy(idrigid,arg[iarg+1]);
rigidflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"shake") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
int n = strlen(arg[iarg+1]) + 1;
delete [] idshake;
idshake = new char[n];
strcpy(idshake,arg[iarg+1]);
shakeflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"id") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
if (strcmp(arg[iarg+1],"max") == 0) idnext = 0;
else if (strcmp(arg[iarg+1],"next") == 0) idnext = 1;
else error->all(FLERR,"Illegal fix deposit command");
iarg += 2;
} else if (strcmp(arg[iarg],"global") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
globalflag = 1;
localflag = 0;
lo = force->numeric(FLERR,arg[iarg+1]);
hi = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"local") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal fix deposit command");
localflag = 1;
globalflag = 0;
lo = force->numeric(FLERR,arg[iarg+1]);
hi = force->numeric(FLERR,arg[iarg+2]);
deltasq = force->numeric(FLERR,arg[iarg+3]) *
force->numeric(FLERR,arg[iarg+3]);
iarg += 4;
} else if (strcmp(arg[iarg],"near") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
nearsq = force->numeric(FLERR,arg[iarg+1]) *
force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"attempt") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
maxattempt = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"rate") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
rateflag = 1;
rate = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"vx") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
vxlo = force->numeric(FLERR,arg[iarg+1]);
vxhi = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"vy") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
vylo = force->numeric(FLERR,arg[iarg+1]);
vyhi = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"vz") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix deposit command");
vzlo = force->numeric(FLERR,arg[iarg+1]);
vzhi = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix deposit command");
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
else error->all(FLERR,"Illegal fix deposit command");
iarg += 2;
} else if (strcmp(arg[iarg],"target") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal fix deposit command");
tx = force->numeric(FLERR,arg[iarg+1]);
ty = force->numeric(FLERR,arg[iarg+2]);
tz = force->numeric(FLERR,arg[iarg+3]);
targetflag = 1;
iarg += 4;
} else error->all(FLERR,"Illegal fix deposit command");
}
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixDeposit::write_restart(FILE *fp)
{
int n = 0;
double list[4];
list[n++] = random->state();
list[n++] = ninserted;
list[n++] = nfirst;
list[n++] = next_reneighbor;
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 FixDeposit::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
seed = static_cast<int> (list[n++]);
ninserted = static_cast<int> (list[n++]);
nfirst = static_cast<int> (list[n++]);
next_reneighbor = static_cast<int> (list[n++]);
random->reset(seed);
}
diff --git a/src/MISC/fix_deposit.h b/src/MISC/fix_deposit.h
index 7e9bea0f3..56bf34c6d 100644
--- a/src/MISC/fix_deposit.h
+++ b/src/MISC/fix_deposit.h
@@ -1,110 +1,111 @@
/* -*- 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 FIX_CLASS
FixStyle(deposit,FixDeposit)
#else
#ifndef LMP_FIX_DEPOSIT_H
#define LMP_FIX_DEPOSIT_H
#include "stdio.h"
#include "fix.h"
namespace LAMMPS_NS {
class FixDeposit : public Fix {
public:
int ntype; // type of deposited atom, visible to PairGran
FixDeposit(class LAMMPS *, int, char **);
~FixDeposit();
int setmask();
void init();
void pre_exchange();
void write_restart(FILE *);
void restart(char *);
private:
int ninsert,nfreq,seed;
int iregion,globalflag,localflag,maxattempt,rateflag,scaleflag,targetflag;
int mode,rigidflag,shakeflag,idnext;
double lo,hi,deltasq,nearsq,rate;
double vxlo,vxhi,vylo,vyhi,vzlo,vzhi;
double xlo,xhi,ylo,yhi,zlo,zhi;
double tx,ty,tz;
char *idregion;
char *idrigid,*idshake;
class Molecule *onemol;
int natom;
double **coords;
imageint *imageflags;
class Fix *fixrigid,*fixshake;
int nfirst,ninserted;
- int maxtag_all,maxmol_all;
+ tagint maxtag_all;
+ int maxmol_all;
class RanPark *random;
void find_maxid();
void options(int, char **);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Must specify a region in fix deposit
The region keyword must be specified with this fix.
E: Fix deposit region does not support a bounding box
Not all regions represent bounded volumes. You cannot use
such a region with the fix deposit command.
E: Fix deposit region cannot be dynamic
Only static regions can be used with fix deposit.
E: Deposition region extends outside simulation box
Self-explanatory.
E: Region ID for fix deposit does not exist
Self-explanatory.
W: Particle deposition was unsuccessful
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.
U: Use of fix deposit with undefined lattice
Must use lattice command with compute fix deposit command if units
option is set to lattice.
*/
diff --git a/src/MISC/fix_evaporate.cpp b/src/MISC/fix_evaporate.cpp
index 5fe5c1412..ab153f805 100644
--- a/src/MISC/fix_evaporate.cpp
+++ b/src/MISC/fix_evaporate.cpp
@@ -1,386 +1,386 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "fix_evaporate.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "domain.h"
#include "region.h"
#include "comm.h"
#include "force.h"
#include "group.h"
#include "random_park.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixEvaporate::FixEvaporate(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 7) error->all(FLERR,"Illegal fix evaporate command");
scalar_flag = 1;
global_freq = 1;
extscalar = 0;
nevery = force->inumeric(FLERR,arg[3]);
nflux = force->inumeric(FLERR,arg[4]);
iregion = domain->find_region(arg[5]);
int n = strlen(arg[5]) + 1;
idregion = new char[n];
strcpy(idregion,arg[5]);
int seed = force->inumeric(FLERR,arg[6]);
if (nevery <= 0 || nflux <= 0)
error->all(FLERR,"Illegal fix evaporate command");
if (iregion == -1)
error->all(FLERR,"Region ID for fix evaporate does not exist");
if (seed <= 0) error->all(FLERR,"Illegal fix evaporate command");
// random number generator, same for all procs
random = new RanPark(lmp,seed);
// optional args
molflag = 0;
int iarg = 7;
while (iarg < narg) {
if (strcmp(arg[iarg],"molecule") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix evaporate command");
if (strcmp(arg[iarg+1],"no") == 0) molflag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) molflag = 1;
else error->all(FLERR,"Illegal fix evaporate command");
iarg += 2;
} else error->all(FLERR,"Illegal fix evaporate command");
}
// set up reneighboring
force_reneighbor = 1;
next_reneighbor = (update->ntimestep/nevery)*nevery + nevery;
ndeleted = 0;
nmax = 0;
list = NULL;
mark = NULL;
}
/* ---------------------------------------------------------------------- */
FixEvaporate::~FixEvaporate()
{
delete [] idregion;
delete random;
memory->destroy(list);
memory->destroy(mark);
}
/* ---------------------------------------------------------------------- */
int FixEvaporate::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixEvaporate::init()
{
// set index and check validity of region
iregion = domain->find_region(idregion);
if (iregion == -1)
error->all(FLERR,"Region ID for fix evaporate does not exist");
// check that no deletable atoms are in atom->firstgroup
// deleting such an atom would not leave firstgroup atoms first
if (atom->firstgroup >= 0) {
int *mask = atom->mask;
int nlocal = atom->nlocal;
int firstgroupbit = group->bitmask[atom->firstgroup];
int flag = 0;
for (int i = 0; i < nlocal; i++)
if ((mask[i] & groupbit) && (mask[i] && firstgroupbit)) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall)
error->all(FLERR,"Cannot evaporate atoms in atom_modify first group");
}
// if molflag not set, warn if any deletable atom has a mol ID
if (molflag == 0 && atom->molecule_flag) {
int *molecule = atom->molecule;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int flag = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (molecule[i]) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->warning(FLERR,
"Fix evaporate may delete atom with non-zero molecule ID");
}
if (molflag && atom->molecule_flag == 0)
error->all(FLERR,
"Fix evaporate molecule requires atom attribute molecule");
}
/* ----------------------------------------------------------------------
perform particle deletion
done before exchange, borders, reneighbor
so that ghost atoms and neighbor lists will be correct
------------------------------------------------------------------------- */
void FixEvaporate::pre_exchange()
{
int i,j,m,iwhichglobal,iwhichlocal;
int ndel,ndeltopo[4];
if (update->ntimestep != next_reneighbor) return;
// grow list and mark arrays if necessary
if (atom->nlocal > nmax) {
memory->destroy(list);
memory->destroy(mark);
nmax = atom->nmax;
memory->create(list,nmax,"evaporate:list");
memory->create(mark,nmax,"evaporate:mark");
}
// ncount = # of deletable atoms in region that I own
// nall = # on all procs
// nbefore = # on procs before me
// list[ncount] = list of local indices of atoms I can delete
double **x = atom->x;
int *mask = atom->mask;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int ncount = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
list[ncount++] = i;
int nall,nbefore;
MPI_Allreduce(&ncount,&nall,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ncount,&nbefore,1,MPI_INT,MPI_SUM,world);
nbefore -= ncount;
// ndel = total # of atom deletions, in or out of region
// ndeltopo[1,2,3,4] = ditto for bonds, angles, dihedrals, impropers
// mark[] = 1 if deleted
ndel = 0;
for (i = 0; i < nlocal; i++) mark[i] = 0;
// atomic deletions
// choose atoms randomly across all procs and mark them for deletion
// shrink eligible list as my atoms get marked
// keep ndel,ncount,nall,nbefore current after each atom deletion
if (molflag == 0) {
while (nall && ndel < nflux) {
iwhichglobal = static_cast<int> (nall*random->uniform());
if (iwhichglobal < nbefore) nbefore--;
else if (iwhichglobal < nbefore + ncount) {
iwhichlocal = iwhichglobal - nbefore;
mark[list[iwhichlocal]] = 1;
list[iwhichlocal] = list[ncount-1];
ncount--;
}
ndel++;
nall--;
}
// molecule deletions
// choose one atom in one molecule randomly across all procs
// bcast mol ID and delete all atoms in that molecule on any proc
// update deletion count by total # of atoms in molecule
// shrink list of eligible candidates as any of my atoms get marked
// keep ndel,ndeltopo,ncount,nall,nbefore current after each mol deletion
} else {
int me,proc,iatom,imolecule,ndelone,ndelall;
int *molecule = atom->molecule;
ndeltopo[0] = ndeltopo[1] = ndeltopo[2] = ndeltopo[3] = 0;
while (nall && ndel < nflux) {
// pick an iatom,imolecule on proc me to delete
iwhichglobal = static_cast<int> (nall*random->uniform());
if (iwhichglobal >= nbefore && iwhichglobal < nbefore + ncount) {
iwhichlocal = iwhichglobal - nbefore;
iatom = list[iwhichlocal];
imolecule = molecule[iatom];
me = comm->me;
} else me = -1;
// bcast mol ID to delete all atoms from
// if mol ID > 0, delete any atom in molecule and decrement counters
// if mol ID == 0, delete single iatom
// be careful to delete correct # of bond,angle,etc for newton on or off
MPI_Allreduce(&me,&proc,1,MPI_INT,MPI_MAX,world);
MPI_Bcast(&imolecule,1,MPI_INT,proc,world);
ndelone = 0;
for (i = 0; i < nlocal; i++) {
if (imolecule && molecule[i] == imolecule) {
mark[i] = 1;
ndelone++;
if (atom->avec->bonds_allow) {
if (force->newton_bond) ndeltopo[0] += atom->num_bond[i];
else {
for (j = 0; j < atom->num_bond[i]; j++) {
if (tag[i] < atom->bond_atom[i][j]) ndeltopo[0]++;
}
}
}
if (atom->avec->angles_allow) {
if (force->newton_bond) ndeltopo[1] += atom->num_angle[i];
else {
for (j = 0; j < atom->num_angle[i]; j++) {
m = atom->map(atom->angle_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[1]++;
}
}
}
if (atom->avec->dihedrals_allow) {
if (force->newton_bond) ndeltopo[2] += atom->num_dihedral[i];
else {
for (j = 0; j < atom->num_dihedral[i]; j++) {
m = atom->map(atom->dihedral_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[2]++;
}
}
}
if (atom->avec->impropers_allow) {
if (force->newton_bond) ndeltopo[3] += atom->num_improper[i];
else {
for (j = 0; j < atom->num_improper[i]; j++) {
m = atom->map(atom->improper_atom2[i][j]);
if (m >= 0 && m < nlocal) ndeltopo[3]++;
}
}
}
} else if (me == proc && i == iatom) {
mark[i] = 1;
ndelone++;
}
}
// remove any atoms marked for deletion from my eligible list
i = 0;
while (i < ncount) {
if (mark[list[i]]) {
list[i] = list[ncount-1];
ncount--;
} else i++;
}
// update ndel,ncount,nall,nbefore
// ndelall is total atoms deleted on this iteration
// ncount is already correct, so resum to get nall and nbefore
MPI_Allreduce(&ndelone,&ndelall,1,MPI_INT,MPI_SUM,world);
ndel += ndelall;
MPI_Allreduce(&ncount,&nall,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ncount,&nbefore,1,MPI_INT,MPI_SUM,world);
nbefore -= ncount;
}
}
// delete my marked atoms
// loop in reverse order to avoid copying marked atoms
AtomVec *avec = atom->avec;
for (i = nlocal-1; i >= 0; i--) {
if (mark[i]) {
avec->copy(atom->nlocal-1,i,1);
atom->nlocal--;
}
}
// reset global natoms and bonds, angles, etc
// if global map exists, reset it now instead of waiting for comm
// since deleting atoms messes up ghosts
atom->natoms -= ndel;
if (molflag) {
int all[4];
MPI_Allreduce(ndeltopo,all,4,MPI_INT,MPI_SUM,world);
atom->nbonds -= all[0];
atom->nangles -= all[1];
atom->ndihedrals -= all[2];
atom->nimpropers -= all[3];
}
if (ndel && atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
// statistics
ndeleted += ndel;
next_reneighbor = update->ntimestep + nevery;
}
/* ----------------------------------------------------------------------
return number of deleted particles
------------------------------------------------------------------------- */
double FixEvaporate::compute_scalar()
{
return 1.0*ndeleted;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixEvaporate::memory_usage()
{
double bytes = 2*nmax * sizeof(int);
return bytes;
}
diff --git a/src/MISC/fix_orient_fcc.cpp b/src/MISC/fix_orient_fcc.cpp
index a7fc2ecea..722dc0485 100644
--- a/src/MISC/fix_orient_fcc.cpp
+++ b/src/MISC/fix_orient_fcc.cpp
@@ -1,607 +1,610 @@
/* ----------------------------------------------------------------------
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: Koenraad Janssens and David Olmsted (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "mpi.h"
#include "fix_orient_fcc.h"
#include "atom.h"
#include "update.h"
#include "respa.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "comm.h"
#include "output.h"
#include "force.h"
#include "math_const.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
#define BIG 1000000000
static const char cite_fix_orient_fcc[] =
"fix orient/fcc command:\n\n"
"@Article{Janssens06,\n"
" author = {K. G. F. Janssens, D. Olmsted, E.A. Holm, S. M. Foiles, S. J. Plimpton, and P. M. Derlet},\n"
" title = {Computing the Mobility of Grain Boundaries},\n"
" journal = {Nature Materials},\n"
" year = 2006,\n"
" volume = 5,\n"
" pages = {124--127}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
FixOrientFCC::FixOrientFCC(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_orient_fcc);
MPI_Comm_rank(world,&me);
if (narg != 11) error->all(FLERR,"Illegal fix orient/fcc command");
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
peratom_flag = 1;
size_peratom_cols = 2;
peratom_freq = 1;
nstats = force->inumeric(FLERR,arg[3]);
direction_of_motion = force->inumeric(FLERR,arg[4]);
a = force->numeric(FLERR,arg[5]);
Vxi = force->numeric(FLERR,arg[6]);
uxif_low = force->numeric(FLERR,arg[7]);
uxif_high = force->numeric(FLERR,arg[8]);
if (direction_of_motion == 0) {
int n = strlen(arg[9]) + 1;
chifilename = new char[n];
strcpy(chifilename,arg[9]);
n = strlen(arg[10]) + 1;
xifilename = new char[n];
strcpy(xifilename,arg[10]);
} else if (direction_of_motion == 1) {
int n = strlen(arg[9]) + 1;
xifilename = new char[n];
strcpy(xifilename,arg[9]);
n = strlen(arg[10]) + 1;
chifilename = new char[n];
strcpy(chifilename,arg[10]);
} else error->all(FLERR,"Illegal fix orient/fcc command");
// initializations
half_fcc_nn = 6;
use_xismooth = false;
double xicutoff = 1.57;
xicutoffsq = xicutoff * xicutoff;
cutsq = 0.5 * a*a*xicutoffsq;
nmax = 0;
// read xi and chi reference orientations from files
if (me == 0) {
char line[IMGMAX];
char *result;
int count;
FILE *infile = fopen(xifilename,"r");
if (infile == NULL) error->one(FLERR,"Fix orient/fcc file open failed");
for (int i = 0; i < 6; i++) {
result = fgets(line,IMGMAX,infile);
if (!result) error->one(FLERR,"Fix orient/fcc file read failed");
count = sscanf(line,"%lg %lg %lg",&Rxi[i][0],&Rxi[i][1],&Rxi[i][2]);
if (count != 3) error->one(FLERR,"Fix orient/fcc file read failed");
}
fclose(infile);
infile = fopen(chifilename,"r");
if (infile == NULL) error->one(FLERR,"Fix orient/fcc file open failed");
for (int i = 0; i < 6; i++) {
result = fgets(line,IMGMAX,infile);
if (!result) error->one(FLERR,"Fix orient/fcc file read failed");
count = sscanf(line,"%lg %lg %lg",&Rchi[i][0],&Rchi[i][1],&Rchi[i][2]);
if (count != 3) error->one(FLERR,"Fix orient/fcc file read failed");
}
fclose(infile);
}
MPI_Bcast(&Rxi[0][0],18,MPI_DOUBLE,0,world);
MPI_Bcast(&Rchi[0][0],18,MPI_DOUBLE,0,world);
// make copy of the reference vectors
for (int i = 0; i < 6; i++)
for (int j = 0; j < 3; j++) {
half_xi_chi_vec[0][i][j] = Rxi[i][j];
half_xi_chi_vec[1][i][j] = Rchi[i][j];
}
// compute xiid,xi0,xi1 for all 12 neighbors
// xi is the favored crystal
// want order parameter when actual is Rchi
double xi_sq,dxi[3],rchi[3];
xiid = 0.0;
for (int i = 0; i < 6; i++) {
rchi[0] = Rchi[i][0];
rchi[1] = Rchi[i][1];
rchi[2] = Rchi[i][2];
find_best_ref(rchi,0,xi_sq,dxi);
xiid += sqrt(xi_sq);
for (int j = 0; j < 3; j++) rchi[j] = -rchi[j];
find_best_ref(rchi,0,xi_sq,dxi);
xiid += sqrt(xi_sq);
}
xiid /= 12.0;
xi0 = uxif_low * xiid;
xi1 = uxif_high * xiid;
// set comm size needed by this Fix
// NOTE: doesn't seem that use_xismooth is ever true
if (use_xismooth) comm_forward = 62;
else comm_forward = 50;
added_energy = 0.0;
nmax = atom->nmax;
nbr = (Nbr *) memory->smalloc(nmax*sizeof(Nbr),"orient/fcc:nbr");
memory->create(order,nmax,2,"orient/fcc:order");
array_atom = order;
// zero the array since a variable may access it before first run
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) order[i][0] = order[i][1] = 0.0;
}
/* ---------------------------------------------------------------------- */
FixOrientFCC::~FixOrientFCC()
{
delete [] xifilename;
delete [] chifilename;
memory->sfree(nbr);
memory->destroy(order);
}
/* ---------------------------------------------------------------------- */
int FixOrientFCC::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= THERMO_ENERGY;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::init()
{
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
// need a full neighbor list, built whenever re-neighboring occurs
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::setup(int vflag)
{
if (strstr(update->integrate_style,"verlet"))
post_force(vflag);
else {
((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
post_force_respa(vflag,nlevels_respa-1,0);
((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
}
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::post_force(int vflag)
{
- int i,j,k,ii,jj,inum,jnum,m,n,nn,nsort,id_self;
+ int i,j,k,ii,jj,inum,jnum,m,n,nn,nsort;
+ tagint id_self;
int *ilist,*jlist,*numneigh,**firstneigh;
double edelta,omega;
double dx,dy,dz,rsq,xismooth,xi_sq,duxi,duxi_other;
double dxi[3];
double *dxiptr;
bool found_myself;
// set local ptrs
double **x = atom->x;
double **f = atom->f;
int *mask = atom->mask;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// insure nbr and order data structures are adequate size
if (nall > nmax) {
nmax = nall;
memory->destroy(nbr);
memory->destroy(order);
nbr = (Nbr *) memory->smalloc(nmax*sizeof(Nbr),"orient/fcc:nbr");
memory->create(order,nmax,2,"orient/fcc:order");
array_atom = order;
}
// loop over owned atoms and build Nbr data structure of neighbors
// use full neighbor list
added_energy = 0.0;
int count = 0;
int mincount = BIG;
int maxcount = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
jlist = firstneigh[i];
jnum = numneigh[i];
if (jnum < mincount) mincount = jnum;
if (jnum > maxcount) {
if (maxcount) delete [] sort;
sort = new Sort[jnum];
maxcount = jnum;
}
// loop over all neighbors of atom i
// for those within cutsq, build sort data structure
// store local id, rsq, delta vector, xismooth (if included)
nsort = 0;
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
count++;
dx = x[i][0] - x[j][0];
dy = x[i][1] - x[j][1];
dz = x[i][2] - x[j][2];
rsq = dx*dx + dy*dy + dz*dz;
if (rsq < cutsq) {
sort[nsort].id = j;
sort[nsort].rsq = rsq;
sort[nsort].delta[0] = dx;
sort[nsort].delta[1] = dy;
sort[nsort].delta[2] = dz;
if (use_xismooth) {
xismooth = (xicutoffsq - 2.0*rsq/(a*a)) / (xicutoffsq - 1.0);
sort[nsort].xismooth = 1.0 - fabs(1.0-xismooth);
}
nsort++;
}
}
// sort neighbors by rsq distance
// no need to sort if nsort <= 12
if (nsort > 12) qsort(sort,nsort,sizeof(Sort),compare);
// copy up to 12 nearest neighbors into nbr data structure
// operate on delta vector via find_best_ref() to compute dxi
n = MIN(12,nsort);
nbr[i].n = n;
if (n == 0) continue;
double xi_total = 0.0;
for (j = 0; j < n; j++) {
find_best_ref(sort[j].delta,0,xi_sq,dxi);
xi_total += sqrt(xi_sq);
nbr[i].id[j] = sort[j].id;
nbr[i].dxi[j][0] = dxi[0]/n;
nbr[i].dxi[j][1] = dxi[1]/n;
nbr[i].dxi[j][2] = dxi[2]/n;
if (use_xismooth) nbr[i].xismooth[j] = sort[j].xismooth;
}
xi_total /= n;
order[i][0] = xi_total;
// compute potential derivative to xi
if (xi_total < xi0) {
nbr[i].duxi = 0.0;
edelta = 0.0;
order[i][1] = 0.0;
} else if (xi_total > xi1) {
nbr[i].duxi = 0.0;
edelta = Vxi;
order[i][1] = 1.0;
} else {
omega = MY_PI2*(xi_total-xi0) / (xi1-xi0);
nbr[i].duxi = MY_PI*Vxi*sin(2.0*omega) / (2.0*(xi1-xi0));
edelta = Vxi*(1 - cos(2.0*omega)) / 2.0;
order[i][1] = omega / MY_PI2;
}
added_energy += edelta;
}
if (maxcount) delete [] sort;
// communicate to acquire nbr data for ghost atoms
comm->forward_comm_fix(this);
// compute grain boundary force on each owned atom
// skip atoms not in group
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (!(mask[i] & groupbit)) continue;
n = nbr[i].n;
duxi = nbr[i].duxi;
for (j = 0; j < n; j++) {
dxiptr = &nbr[i].dxi[j][0];
if (use_xismooth) {
xismooth = nbr[i].xismooth[j];
f[i][0] += duxi * dxiptr[0] * xismooth;
f[i][1] += duxi * dxiptr[1] * xismooth;
f[i][2] += duxi * dxiptr[2] * xismooth;
} else {
f[i][0] += duxi * dxiptr[0];
f[i][1] += duxi * dxiptr[1];
f[i][2] += duxi * dxiptr[2];
}
// m = local index of neighbor
// id_self = ID for atom I in atom M's neighbor list
// if M is local atom, id_self will be local ID of atom I
// if M is ghost atom, id_self will be global ID of atom I
m = nbr[i].id[j];
if (m < nlocal) id_self = i;
else id_self = tag[i];
found_myself = false;
nn = nbr[m].n;
for (k = 0; k < nn; k++) {
if (id_self == nbr[m].id[k]) {
if (found_myself) error->one(FLERR,"Fix orient/fcc found self twice");
found_myself = true;
duxi_other = nbr[m].duxi;
dxiptr = &nbr[m].dxi[k][0];
if (use_xismooth) {
xismooth = nbr[m].xismooth[k];
f[i][0] -= duxi_other * dxiptr[0] * xismooth;
f[i][1] -= duxi_other * dxiptr[1] * xismooth;
f[i][2] -= duxi_other * dxiptr[2] * xismooth;
} else {
f[i][0] -= duxi_other * dxiptr[0];
f[i][1] -= duxi_other * dxiptr[1];
f[i][2] -= duxi_other * dxiptr[2];
}
}
}
}
}
// print statistics every nstats timesteps
if (nstats && update->ntimestep % nstats == 0) {
int total;
MPI_Allreduce(&count,&total,1,MPI_INT,MPI_SUM,world);
double ave = total/atom->natoms;
int min,max;
MPI_Allreduce(&mincount,&min,1,MPI_INT,MPI_MIN,world);
MPI_Allreduce(&maxcount,&max,1,MPI_INT,MPI_MAX,world);
if (me == 0) {
if (screen) fprintf(screen,
"orient step " BIGINT_FORMAT ": " BIGINT_FORMAT
" atoms have %d neighbors\n",
update->ntimestep,atom->natoms,total);
if (logfile) fprintf(logfile,
"orient step " BIGINT_FORMAT ": " BIGINT_FORMAT
" atoms have %d neighbors\n",
update->ntimestep,atom->natoms,total);
if (screen)
fprintf(screen," neighs: min = %d, max = %d, ave = %g\n",
min,max,ave);
if (logfile)
fprintf(logfile," neighs: min = %d, max = %d, ave = %g\n",
min,max,ave);
}
}
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::post_force_respa(int vflag, int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
double FixOrientFCC::compute_scalar()
{
double added_energy_total;
MPI_Allreduce(&added_energy,&added_energy_total,1,MPI_DOUBLE,MPI_SUM,world);
return added_energy_total;
}
/* ---------------------------------------------------------------------- */
int FixOrientFCC::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
- int i,j,k,id,num;
- int *tag = atom->tag;
+ int i,j,k,num;
+ tagint id;
+
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int m = 0;
for (i = 0; i < n; i++) {
k = list[i];
num = nbr[k].n;
buf[m++] = num;
buf[m++] = nbr[k].duxi;
for (j = 0; j < num; j++) {
if (use_xismooth) buf[m++] = nbr[m].xismooth[j];
buf[m++] = nbr[k].dxi[j][0];
buf[m++] = nbr[k].dxi[j][1];
buf[m++] = nbr[k].dxi[j][2];
// id stored in buf needs to be global ID
// if k is a local atom, it stores local IDs, so convert to global
// if k is a ghost atom (already comm'd), its IDs are already global
id = nbr[k].id[j];
if (k < nlocal) id = tag[id];
buf[m++] = id;
}
m += (12-num) * 3;
if (use_xismooth) m += 12-num;
}
if (use_xismooth) return 62;
return 50;
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::unpack_comm(int n, int first, double *buf)
{
int i,j,num;
int last = first + n;
int m = 0;
for (i = first; i < last; i++) {
nbr[i].n = num = static_cast<int> (buf[m++]);
nbr[i].duxi = buf[m++];
for (j = 0; j < num; j++) {
if (use_xismooth) nbr[i].xismooth[j] = buf[m++];
nbr[i].dxi[j][0] = buf[m++];
nbr[i].dxi[j][1] = buf[m++];
nbr[i].dxi[j][2] = buf[m++];
- nbr[i].id[j] = static_cast<int> (buf[m++]);
+ nbr[i].id[j] = static_cast<tagint> (buf[m++]);
}
m += (12-num) * 3;
if (use_xismooth) m += 12-num;
}
}
/* ---------------------------------------------------------------------- */
void FixOrientFCC::find_best_ref(double *displs, int which_crystal,
double &xi_sq, double *dxi)
{
int i;
double dot,tmp;
double best_dot = -1.0; // best is biggest (smallest angle)
int best_i = -1;
int best_sign = 0;
for (i = 0; i < half_fcc_nn; i++) {
dot = displs[0] * half_xi_chi_vec[which_crystal][i][0] +
displs[1] * half_xi_chi_vec[which_crystal][i][1] +
displs[2] * half_xi_chi_vec[which_crystal][i][2];
if (fabs(dot) > best_dot) {
best_dot = fabs(dot);
best_i = i;
if (dot < 0.0) best_sign = -1;
else best_sign = 1;
}
}
xi_sq = 0.0;
for (i = 0; i < 3; i++) {
tmp = displs[i] - best_sign * half_xi_chi_vec[which_crystal][best_i][i];
xi_sq += tmp*tmp;
}
if (xi_sq > 0.0) {
double xi = sqrt(xi_sq);
for (i = 0; i < 3; i++)
dxi[i] = (best_sign * half_xi_chi_vec[which_crystal][best_i][i] -
displs[i]) / xi;
} else dxi[0] = dxi[1] = dxi[2] = 0.0;
}
/* ----------------------------------------------------------------------
compare two neighbors I and J in sort data structure
called via qsort in post_force() method
is a static method so can't access sort data structure directly
return -1 if I < J, 0 if I = J, 1 if I > J
do comparison based on rsq distance
------------------------------------------------------------------------- */
int FixOrientFCC::compare(const void *pi, const void *pj)
{
FixOrientFCC::Sort *ineigh = (FixOrientFCC::Sort *) pi;
FixOrientFCC::Sort *jneigh = (FixOrientFCC::Sort *) pj;
if (ineigh->rsq < jneigh->rsq) return -1;
else if (ineigh->rsq > jneigh->rsq) return 1;
return 0;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixOrientFCC::memory_usage()
{
double bytes = nmax * sizeof(Nbr);
bytes += 2*nmax * sizeof(double);
return bytes;
}
diff --git a/src/MISC/fix_orient_fcc.h b/src/MISC/fix_orient_fcc.h
index c15c79d55..adbb93f1a 100644
--- a/src/MISC/fix_orient_fcc.h
+++ b/src/MISC/fix_orient_fcc.h
@@ -1,115 +1,115 @@
/* -*- 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 FIX_CLASS
FixStyle(orient/fcc,FixOrientFCC)
#else
#ifndef LMP_FIX_ORIENT_FCC_H
#define LMP_FIX_ORIENT_FCC_H
#include "fix.h"
namespace LAMMPS_NS {
class FixOrientFCC : public Fix {
public:
struct Nbr { // neighbor info for each owned and ghost atom
int n; // # of closest neighbors (up to 12)
- int id[12]; // IDs of each neighbor
+ tagint id[12]; // IDs of each neighbor
// if center atom is owned, these are local IDs
// if center atom is ghost, these are global IDs
double xismooth[12]; // distance weighting factor for each neighbors
double dxi[12][3]; // d order-parameter / dx for each neighbor
double duxi; // d Energy / d order-parameter for atom
};
struct Sort { // data structure for sorting to find 12 closest
- int id; // ID of neighbor atom
+ int id; // local ID of neighbor atom
double rsq; // distance between center and neighbor atom
double delta[3]; // displacement between center and neighbor atom
double xismooth; // distance weighting factor
};
FixOrientFCC(class LAMMPS *, int, char **);
~FixOrientFCC();
int setmask();
void init();
void init_list(int, class NeighList *);
void setup(int);
void post_force(int);
void post_force_respa(int, int, int);
double compute_scalar();
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
double memory_usage();
private:
int me;
int nlevels_respa;
int direction_of_motion; // 1 = center shrinks, 0 = center grows
int nstats; // stats output every this many steps
double a; // lattice parameter
double Vxi; // potential value
double uxif_low; // cut-off fraction, low order parameter
double uxif_high; // cut-off fraction, high order parameter
char *xifilename, *chifilename; // file names for 2 crystal orientations
bool use_xismooth;
double Rxi[12][3],Rchi[12][3],half_xi_chi_vec[2][6][3];
double xiid,xi0,xi1,xicutoffsq,cutsq,added_energy;
int half_fcc_nn;
int nmax; // expose 2 per-atom quantities
double **order; // order param and normalized order param
Nbr *nbr;
Sort *sort;
class NeighList *list;
void find_best_ref(double *, int, double &, double *);
static int compare(const void *, const void *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Fix orient/fcc file open failed
The fix orient/fcc command could not open a specified file.
E: Fix orient/fcc file read failed
The fix orient/fcc command could not read the needed parameters from a
specified file.
E: Fix orient/fcc found self twice
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.
*/
diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp
index 224c25605..9b303451c 100644
--- a/src/MOLECULE/atom_vec_angle.cpp
+++ b/src/MOLECULE/atom_vec_angle.cpp
@@ -1,930 +1,926 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_angle.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecAngle::AtomVecAngle(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 1;
bonds_allow = angles_allow = 1;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 7;
size_velocity = 3;
size_data_atom = 6;
size_data_vel = 4;
xcol_data = 4;
atom->molecule_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecAngle::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial");
special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special");
num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond");
bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom,
"atom:bond_type");
bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom,
"atom:bond_atom");
num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle");
angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom,
"atom:angle_type");
angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom,
"atom:angle_atom1");
angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom,
"atom:angle_atom2");
angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom,
"atom:angle_atom3");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecAngle::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
molecule = atom->molecule;
nspecial = atom->nspecial; special = atom->special;
num_bond = atom->num_bond; bond_type = atom->bond_type;
bond_atom = atom->bond_atom;
num_angle = atom->num_angle; angle_type = atom->angle_type;
angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2;
angle_atom3 = atom->angle_atom3;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecAngle::copy(int i, int j, int delflag)
{
int k;
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
molecule[j] = molecule[i];
num_bond[j] = num_bond[i];
for (k = 0; k < num_bond[j]; k++) {
bond_type[j][k] = bond_type[i][k];
bond_atom[j][k] = bond_atom[i][k];
}
num_angle[j] = num_angle[i];
for (k = 0; k < num_angle[j]; k++) {
angle_type[j][k] = angle_type[i][k];
angle_atom1[j][k] = angle_atom1[i][k];
angle_atom2[j][k] = angle_atom2[i][k];
angle_atom3[j][k] = angle_atom3[i][k];
}
nspecial[j][0] = nspecial[i][0];
nspecial[j][1] = nspecial[i][1];
nspecial[j][2] = nspecial[i][2];
for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAngle::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecAngle::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAngle::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = ubuf(molecule[j]).d;
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAngle::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecAngle::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
molecule[i] = (int) ubuf(buf[m++]).i;
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecAngle::pack_exchange(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(bond_type[i][k]).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
buf[m++] = ubuf(angle_type[i][k]).d;
buf[m++] = ubuf(angle_atom1[i][k]).d;
buf[m++] = ubuf(angle_atom2[i][k]).d;
buf[m++] = ubuf(angle_atom3[i][k]).d;
}
buf[m++] = ubuf(nspecial[i][0]).d;
buf[m++] = ubuf(nspecial[i][1]).d;
buf[m++] = ubuf(nspecial[i][2]).d;
for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAngle::unpack_exchange(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
+ angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][1] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][2] = (int) ubuf(buf[m++]).i;
for (k = 0; k < nspecial[nlocal][2]; k++)
- special[nlocal][k] = (int) ubuf(buf[m++]).i;
+ special[nlocal][k] = (tagint) ubuf(buf[m++]).i;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecAngle::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 0;
for (i = 0; i < nlocal; i++)
n += 14 + 2*num_bond[i] + 4*num_angle[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecAngle::pack_restart(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
- buf[m++] = tag[i];
- buf[m++] = type[i];
- buf[m++] = mask[i];
- *((imageint *) &buf[m++]) = image[i];
+ buf[m++] = ubuf(tag[i]).d;
+ buf[m++] = ubuf(type[i]).d;
+ buf[m++] = ubuf(mask[i]).d;
+ buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
- buf[m++] = molecule[i];
+ buf[m++] = ubuf(molecule[i]).d;
- buf[m++] = num_bond[i];
+ buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
- buf[m++] = MAX(bond_type[i][k],-bond_type[i][k]);
- buf[m++] = bond_atom[i][k];
+ buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d;
+ buf[m++] = ubuf(bond_atom[i][k]).d;
}
- buf[m++] = num_angle[i];
+ buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
- buf[m++] = MAX(angle_type[i][k],-angle_type[i][k]);
- buf[m++] = angle_atom1[i][k];
- buf[m++] = angle_atom2[i][k];
- buf[m++] = angle_atom3[i][k];
+ buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d;
+ buf[m++] = ubuf(angle_atom1[i][k]).d;
+ buf[m++] = ubuf(angle_atom2[i][k]).d;
+ buf[m++] = ubuf(angle_atom3[i][k]).d;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecAngle::unpack_restart(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
+ angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecAngle::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
molecule[nlocal] = 0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecAngle::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecAngle::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecAngle::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
buf[i][3] = x[i][0];
buf[i][4] = x[i][1];
buf[i][5] = x[i][2];
buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecAngle::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
return 1;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecAngle::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],
(int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i,
(int) ubuf(buf[i][8]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecAngle::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d",(int) ubuf(buf[0]).i);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecAngle::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3);
if (atom->memcheck("special"))
bytes += memory->usage(special,nmax,atom->maxspecial);
if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax);
if (atom->memcheck("bond_type"))
bytes += memory->usage(bond_type,nmax,atom->bond_per_atom);
if (atom->memcheck("bond_atom"))
bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom);
if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax);
if (atom->memcheck("angle_type"))
bytes += memory->usage(angle_type,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom1"))
bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom2"))
bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom3"))
bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom);
return bytes;
}
diff --git a/src/MOLECULE/atom_vec_angle.h b/src/MOLECULE/atom_vec_angle.h
index 56c00ace2..beccef79d 100644
--- a/src/MOLECULE/atom_vec_angle.h
+++ b/src/MOLECULE/atom_vec_angle.h
@@ -1,93 +1,96 @@
/* -*- 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 ATOM_CLASS
AtomStyle(angle,AtomVecAngle)
#else
#ifndef LMP_ATOM_VEC_ANGLE_H
#define LMP_ATOM_VEC_ANGLE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecAngle : public AtomVec {
public:
AtomVecAngle(class LAMMPS *);
virtual ~AtomVecAngle() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
virtual int pack_comm(int, int *, double *, int, int *);
virtual int pack_comm_vel(int, int *, double *, int, int *);
virtual void unpack_comm(int, int, double *);
virtual void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
virtual int pack_border(int, int *, double *, int, int *);
virtual int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
virtual void unpack_border(int, int, double *);
virtual void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
virtual int pack_exchange(int, double *);
virtual int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
protected:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule;
- int **nspecial,**special;
+ int **nspecial;
+ tagint **special;
int *num_bond;
- int **bond_type,**bond_atom;
+ int **bond_type;
+ tagint **bond_atom;
int *num_angle;
int **angle_type;
- int **angle_atom1,**angle_atom2,**angle_atom3;
+ tagint **angle_atom1,**angle_atom2,**angle_atom3;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp
index c06d3eed2..7e5e63991 100644
--- a/src/MOLECULE/atom_vec_bond.cpp
+++ b/src/MOLECULE/atom_vec_bond.cpp
@@ -1,864 +1,860 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_bond.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecBond::AtomVecBond(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 1;
bonds_allow = 1;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 7;
size_velocity = 3;
size_data_atom = 6;
size_data_vel = 4;
xcol_data = 4;
atom->molecule_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecBond::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial");
special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special");
num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond");
bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom,
"atom:bond_type");
bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom,
"atom:bond_atom");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecBond::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
molecule = atom->molecule;
nspecial = atom->nspecial; special = atom->special;
num_bond = atom->num_bond; bond_type = atom->bond_type;
bond_atom = atom->bond_atom;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecBond::copy(int i, int j, int delflag)
{
int k;
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
molecule[j] = molecule[i];
num_bond[j] = num_bond[i];
for (k = 0; k < num_bond[j]; k++) {
bond_type[j][k] = bond_type[i][k];
bond_atom[j][k] = bond_atom[i][k];
}
nspecial[j][0] = nspecial[i][0];
nspecial[j][1] = nspecial[i][1];
nspecial[j][2] = nspecial[i][2];
for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBond::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecBond::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBond::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = molecule[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBond::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecBond::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
molecule[i] = (int) ubuf(buf[m++]).i;
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecBond::pack_exchange(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(bond_type[i][k]).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(nspecial[i][0]).d;
buf[m++] = ubuf(nspecial[i][1]).d;
buf[m++] = ubuf(nspecial[i][2]).d;
for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBond::unpack_exchange(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][1] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][2] = (int) ubuf(buf[m++]).i;
for (k = 0; k < nspecial[nlocal][2]; k++)
- special[nlocal][k] = (int) ubuf(buf[m++]).i;
+ special[nlocal][k] = (tagint) ubuf(buf[m++]).i;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecBond::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 0;
for (i = 0; i < nlocal; i++)
n += 13 + 2*num_bond[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecBond::pack_restart(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecBond::unpack_restart(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecBond::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
molecule[nlocal] = 0;
num_bond[nlocal] = 0;
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecBond::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
num_bond[nlocal] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecBond::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
num_bond[nlocal] = 0;
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecBond::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
buf[i][3] = x[i][0];
buf[i][4] = x[i][1];
buf[i][5] = x[i][2];
buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecBond::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
return 1;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecBond::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],
(int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i,
(int) ubuf(buf[i][8]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecBond::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d",(int) ubuf(buf[0]).i);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecBond::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3);
if (atom->memcheck("special"))
bytes += memory->usage(special,nmax,atom->maxspecial);
if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax);
if (atom->memcheck("bond_type"))
bytes += memory->usage(bond_type,nmax,atom->bond_per_atom);
if (atom->memcheck("bond_atom"))
bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom);
return bytes;
}
diff --git a/src/MOLECULE/atom_vec_bond.h b/src/MOLECULE/atom_vec_bond.h
index 388195206..94c43f4c2 100644
--- a/src/MOLECULE/atom_vec_bond.h
+++ b/src/MOLECULE/atom_vec_bond.h
@@ -1,89 +1,92 @@
/* -*- 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 ATOM_CLASS
AtomStyle(bond,AtomVecBond)
#else
#ifndef LMP_ATOM_VEC_BOND_H
#define LMP_ATOM_VEC_BOND_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecBond : public AtomVec {
public:
AtomVecBond(class LAMMPS *);
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule;
- int **nspecial,**special;
+ int **nspecial;
+ tagint **special;
int *num_bond;
- int **bond_type,**bond_atom;
+ int **bond_type;
+ tagint **bond_atom;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp
index 6d44289d4..09175dd03 100644
--- a/src/MOLECULE/atom_vec_full.cpp
+++ b/src/MOLECULE/atom_vec_full.cpp
@@ -1,1113 +1,1110 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_full.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecFull::AtomVecFull(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 1;
bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 8;
size_velocity = 3;
size_data_atom = 7;
size_data_vel = 4;
xcol_data = 5;
atom->molecule_flag = atom->q_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecFull::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
q = memory->grow(atom->q,nmax,"atom:q");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial");
special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special");
num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond");
bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom,
"atom:bond_type");
bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom,
"atom:bond_atom");
num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle");
angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom,
"atom:angle_type");
angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom,
"atom:angle_atom1");
angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom,
"atom:angle_atom2");
angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom,
"atom:angle_atom3");
num_dihedral = memory->grow(atom->num_dihedral,nmax,"atom:num_dihedral");
dihedral_type = memory->grow(atom->dihedral_type,nmax,
atom->dihedral_per_atom,"atom:dihedral_type");
dihedral_atom1 =
memory->grow(atom->dihedral_atom1,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom1");
dihedral_atom2 =
memory->grow(atom->dihedral_atom2,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom2");
dihedral_atom3 =
memory->grow(atom->dihedral_atom3,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom3");
dihedral_atom4 =
memory->grow(atom->dihedral_atom4,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom4");
num_improper = memory->grow(atom->num_improper,nmax,"atom:num_improper");
improper_type =
memory->grow(atom->improper_type,nmax,atom->improper_per_atom,
"atom:improper_type");
improper_atom1 =
memory->grow(atom->improper_atom1,nmax,atom->improper_per_atom,
"atom:improper_atom1");
improper_atom2 =
memory->grow(atom->improper_atom2,nmax,atom->improper_per_atom,
"atom:improper_atom2");
improper_atom3 =
memory->grow(atom->improper_atom3,nmax,atom->improper_per_atom,
"atom:improper_atom3");
improper_atom4 =
memory->grow(atom->improper_atom4,nmax,atom->improper_per_atom,
"atom:improper_atom4");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecFull::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
q = atom->q; molecule = atom->molecule;
nspecial = atom->nspecial; special = atom->special;
num_bond = atom->num_bond; bond_type = atom->bond_type;
bond_atom = atom->bond_atom;
num_angle = atom->num_angle; angle_type = atom->angle_type;
angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2;
angle_atom3 = atom->angle_atom3;
num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type;
dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2;
dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4;
num_improper = atom->num_improper; improper_type = atom->improper_type;
improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2;
improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecFull::copy(int i, int j, int delflag)
{
int k;
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
q[j] = q[i];
molecule[j] = molecule[i];
num_bond[j] = num_bond[i];
for (k = 0; k < num_bond[j]; k++) {
bond_type[j][k] = bond_type[i][k];
bond_atom[j][k] = bond_atom[i][k];
}
num_angle[j] = num_angle[i];
for (k = 0; k < num_angle[j]; k++) {
angle_type[j][k] = angle_type[i][k];
angle_atom1[j][k] = angle_atom1[i][k];
angle_atom2[j][k] = angle_atom2[i][k];
angle_atom3[j][k] = angle_atom3[i][k];
}
num_dihedral[j] = num_dihedral[i];
for (k = 0; k < num_dihedral[j]; k++) {
dihedral_type[j][k] = dihedral_type[i][k];
dihedral_atom1[j][k] = dihedral_atom1[i][k];
dihedral_atom2[j][k] = dihedral_atom2[i][k];
dihedral_atom3[j][k] = dihedral_atom3[i][k];
dihedral_atom4[j][k] = dihedral_atom4[i][k];
}
num_improper[j] = num_improper[i];
for (k = 0; k < num_improper[j]; k++) {
improper_type[j][k] = improper_type[i][k];
improper_atom1[j][k] = improper_atom1[i][k];
improper_atom2[j][k] = improper_atom2[i][k];
improper_atom3[j][k] = improper_atom3[i][k];
improper_atom4[j][k] = improper_atom4[i][k];
}
nspecial[j][0] = nspecial[i][0];
nspecial[j][1] = nspecial[i][1];
nspecial[j][2] = nspecial[i][2];
for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecFull::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecFull::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecFull::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(molecule[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(molecule[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
- buf[m++] = tag[j];
- buf[m++] = type[j];
- buf[m++] = mask[j];
+ buf[m++] = ubuf(tag[j]).d;
+ buf[m++] = ubuf(type[j]).d;
+ buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = molecule[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(molecule[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
buf[m++] = ubuf(molecule[j]).d;
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecFull::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
molecule[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecFull::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
molecule[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
q[i] = buf[m++];
molecule[i] = (int) ubuf(buf[m++]).i;
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecFull::pack_exchange(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = q[i];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(bond_type[i][k]).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
buf[m++] = ubuf(angle_type[i][k]).d;
buf[m++] = ubuf(angle_atom1[i][k]).d;
buf[m++] = ubuf(angle_atom2[i][k]).d;
buf[m++] = ubuf(angle_atom3[i][k]).d;
}
buf[m++] = ubuf(num_dihedral[i]).d;
for (k = 0; k < num_dihedral[i]; k++) {
buf[m++] = ubuf(dihedral_type[i][k]).d;
buf[m++] = ubuf(dihedral_atom1[i][k]).d;
buf[m++] = ubuf(dihedral_atom2[i][k]).d;
buf[m++] = ubuf(dihedral_atom3[i][k]).d;
buf[m++] = ubuf(dihedral_atom4[i][k]).d;
}
buf[m++] = ubuf(num_improper[i]).d;
for (k = 0; k < num_improper[i]; k++) {
buf[m++] = ubuf(improper_type[i][k]).d;
buf[m++] = ubuf(improper_atom1[i][k]).d;
buf[m++] = ubuf(improper_atom2[i][k]).d;
buf[m++] = ubuf(improper_atom3[i][k]).d;
buf[m++] = ubuf(improper_atom4[i][k]).d;
}
buf[m++] = ubuf(nspecial[i][0]).d;
buf[m++] = ubuf(nspecial[i][1]).d;
buf[m++] = ubuf(nspecial[i][2]).d;
for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecFull::unpack_exchange(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
q[nlocal] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
+ angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_dihedral[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_dihedral[nlocal]; k++) {
dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
+ dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_improper[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_improper[nlocal]; k++) {
improper_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
+ improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][1] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][2] = (int) ubuf(buf[m++]).i;
for (k = 0; k < nspecial[nlocal][2]; k++)
- special[nlocal][k] = (int) ubuf(buf[m++]).i;
+ special[nlocal][k] = (tagint) ubuf(buf[m++]).i;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecFull::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 0;
for (i = 0; i < nlocal; i++)
n += 17 + 2*num_bond[i] + 4*num_angle[i] +
5*num_dihedral[i] + 5*num_improper[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecFull::pack_restart(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = q[i];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d;
buf[m++] = ubuf(angle_atom1[i][k]).d;
buf[m++] = ubuf(angle_atom2[i][k]).d;
buf[m++] = ubuf(angle_atom3[i][k]).d;
}
buf[m++] = ubuf(num_dihedral[i]).d;
for (k = 0; k < num_dihedral[i]; k++) {
buf[m++] = ubuf(MAX(dihedral_type[i][k],-dihedral_type[i][k])).d;
buf[m++] = ubuf(dihedral_atom1[i][k]).d;
buf[m++] = ubuf(dihedral_atom2[i][k]).d;
buf[m++] = ubuf(dihedral_atom3[i][k]).d;
buf[m++] = ubuf(dihedral_atom4[i][k]).d;
}
buf[m++] = ubuf(num_improper[i]).d;
for (k = 0; k < num_improper[i]; k++) {
buf[m++] = ubuf(MAX(improper_type[i][k],-improper_type[i][k])).d;
buf[m++] = ubuf(improper_atom1[i][k]).d;
buf[m++] = ubuf(improper_atom2[i][k]).d;
buf[m++] = ubuf(improper_atom3[i][k]).d;
buf[m++] = ubuf(improper_atom4[i][k]).d;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecFull::unpack_restart(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
q[nlocal] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
+ bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
+ angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_dihedral[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_dihedral[nlocal]; k++) {
dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
- dihedral_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
+ dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
num_improper[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_improper[nlocal]; k++) {
improper_type[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
- improper_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
+ improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i;
+ improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecFull::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
q[nlocal] = 0.0;
molecule[nlocal] = 0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecFull::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
q[nlocal] = atof(values[3]);
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecFull::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
q[nlocal] = atof(values[1]);
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
return 2;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecFull::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
buf[i][3] = q[i];
buf[i][4] = x[i][0];
buf[i][5] = x[i][1];
buf[i][6] = x[i][2];
buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecFull::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
buf[1] = q[i];
return 2;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecFull::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],buf[i][6],
(int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,
(int) ubuf(buf[i][9]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecFull::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d %-1.16e",(int) ubuf(buf[0]).i,buf[1]);
return 2;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecFull::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("q")) bytes += memory->usage(q,nmax);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3);
if (atom->memcheck("special"))
bytes += memory->usage(special,nmax,atom->maxspecial);
if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax);
if (atom->memcheck("bond_type"))
bytes += memory->usage(bond_type,nmax,atom->bond_per_atom);
if (atom->memcheck("bond_atom"))
bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom);
if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax);
if (atom->memcheck("angle_type"))
bytes += memory->usage(angle_type,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom1"))
bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom2"))
bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom3"))
bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom);
if (atom->memcheck("num_dihedral")) bytes += memory->usage(num_dihedral,nmax);
if (atom->memcheck("dihedral_type"))
bytes += memory->usage(dihedral_type,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom1"))
bytes += memory->usage(dihedral_atom1,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom2"))
bytes += memory->usage(dihedral_atom2,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom3"))
bytes += memory->usage(dihedral_atom3,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom4"))
bytes += memory->usage(dihedral_atom4,nmax,atom->dihedral_per_atom);
if (atom->memcheck("num_improper")) bytes += memory->usage(num_improper,nmax);
if (atom->memcheck("improper_type"))
bytes += memory->usage(improper_type,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom1"))
bytes += memory->usage(improper_atom1,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom2"))
bytes += memory->usage(improper_atom2,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom3"))
bytes += memory->usage(improper_atom3,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom4"))
bytes += memory->usage(improper_atom4,nmax,atom->improper_per_atom);
return bytes;
}
diff --git a/src/MOLECULE/atom_vec_full.h b/src/MOLECULE/atom_vec_full.h
index 45202af09..11b44a8b0 100644
--- a/src/MOLECULE/atom_vec_full.h
+++ b/src/MOLECULE/atom_vec_full.h
@@ -1,100 +1,103 @@
/* -*- 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 ATOM_CLASS
AtomStyle(full,AtomVecFull)
#else
#ifndef LMP_ATOM_VEC_FULL_H
#define LMP_ATOM_VEC_FULL_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecFull : public AtomVec {
public:
AtomVecFull(class LAMMPS *);
virtual ~AtomVecFull() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
virtual int pack_comm(int, int *, double *, int, int *);
virtual int pack_comm_vel(int, int *, double *, int, int *);
virtual void unpack_comm(int, int, double *);
virtual void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
virtual int pack_border(int, int *, double *, int, int *);
virtual int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
virtual void unpack_border(int, int, double *);
virtual void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
virtual int pack_exchange(int, double *);
virtual int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
protected:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *q;
int *molecule;
- int **nspecial,**special;
+ int **nspecial;
+ tagint **special;
int *num_bond;
- int **bond_type,**bond_atom;
+ int **bond_type;
+ tagint **bond_atom;
int *num_angle;
int **angle_type;
- int **angle_atom1,**angle_atom2,**angle_atom3;
+ tagint **angle_atom1,**angle_atom2,**angle_atom3;
int *num_dihedral;
int **dihedral_type;
- int **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
+ tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
int *num_improper;
int **improper_type;
- int **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
+ tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp
index 9feb31e1c..2f2265b5d 100644
--- a/src/MOLECULE/atom_vec_molecular.cpp
+++ b/src/MOLECULE/atom_vec_molecular.cpp
@@ -1,1090 +1,1087 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_molecular.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 1;
bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 7;
size_velocity = 3;
size_data_atom = 6;
size_data_vel = 4;
xcol_data = 4;
atom->molecule_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecMolecular::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial");
special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special");
num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond");
bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom,
"atom:bond_type");
bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom,
"atom:bond_atom");
num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle");
angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom,
"atom:angle_type");
angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom,
"atom:angle_atom1");
angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom,
"atom:angle_atom2");
angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom,
"atom:angle_atom3");
num_dihedral = memory->grow(atom->num_dihedral,nmax,"atom:num_dihedral");
dihedral_type = memory->grow(atom->dihedral_type,nmax,
atom->dihedral_per_atom,"atom:dihedral_type");
dihedral_atom1 =
memory->grow(atom->dihedral_atom1,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom1");
dihedral_atom2 =
memory->grow(atom->dihedral_atom2,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom2");
dihedral_atom3 =
memory->grow(atom->dihedral_atom3,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom3");
dihedral_atom4 =
memory->grow(atom->dihedral_atom4,nmax,atom->dihedral_per_atom,
"atom:dihedral_atom4");
num_improper = memory->grow(atom->num_improper,nmax,"atom:num_improper");
improper_type =
memory->grow(atom->improper_type,nmax,atom->improper_per_atom,
"atom:improper_type");
improper_atom1 =
memory->grow(atom->improper_atom1,nmax,atom->improper_per_atom,
"atom:improper_atom1");
improper_atom2 =
memory->grow(atom->improper_atom2,nmax,atom->improper_per_atom,
"atom:improper_atom2");
improper_atom3 =
memory->grow(atom->improper_atom3,nmax,atom->improper_per_atom,
"atom:improper_atom3");
improper_atom4 =
memory->grow(atom->improper_atom4,nmax,atom->improper_per_atom,
"atom:improper_atom4");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecMolecular::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
molecule = atom->molecule;
nspecial = atom->nspecial; special = atom->special;
num_bond = atom->num_bond; bond_type = atom->bond_type;
bond_atom = atom->bond_atom;
num_angle = atom->num_angle; angle_type = atom->angle_type;
angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2;
angle_atom3 = atom->angle_atom3;
num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type;
dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2;
dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4;
num_improper = atom->num_improper; improper_type = atom->improper_type;
improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2;
improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecMolecular::copy(int i, int j, int delflag)
{
int k;
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
molecule[j] = molecule[i];
num_bond[j] = num_bond[i];
for (k = 0; k < num_bond[j]; k++) {
bond_type[j][k] = bond_type[i][k];
bond_atom[j][k] = bond_atom[i][k];
}
num_angle[j] = num_angle[i];
for (k = 0; k < num_angle[j]; k++) {
angle_type[j][k] = angle_type[i][k];
angle_atom1[j][k] = angle_atom1[i][k];
angle_atom2[j][k] = angle_atom2[i][k];
angle_atom3[j][k] = angle_atom3[i][k];
}
num_dihedral[j] = num_dihedral[i];
for (k = 0; k < num_dihedral[j]; k++) {
dihedral_type[j][k] = dihedral_type[i][k];
dihedral_atom1[j][k] = dihedral_atom1[i][k];
dihedral_atom2[j][k] = dihedral_atom2[i][k];
dihedral_atom3[j][k] = dihedral_atom3[i][k];
dihedral_atom4[j][k] = dihedral_atom4[i][k];
}
num_improper[j] = num_improper[i];
for (k = 0; k < num_improper[j]; k++) {
improper_type[j][k] = improper_type[i][k];
improper_atom1[j][k] = improper_atom1[i][k];
improper_atom2[j][k] = improper_atom2[i][k];
improper_atom3[j][k] = improper_atom3[i][k];
improper_atom4[j][k] = improper_atom4[i][k];
}
nspecial[j][0] = nspecial[i][0];
nspecial[j][1] = nspecial[i][1];
nspecial[j][2] = nspecial[i][2];
for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMolecular::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecMolecular::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMolecular::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = ubuf(molecule[j]).d;
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMolecular::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecMolecular::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
molecule[i] = (int) ubuf(buf[m++]).i;
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecMolecular::pack_exchange(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(bond_type[i][k]).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
buf[m++] = ubuf(angle_type[i][k]).d;
buf[m++] = ubuf(angle_atom1[i][k]).d;
buf[m++] = ubuf(angle_atom2[i][k]).d;
buf[m++] = ubuf(angle_atom3[i][k]).d;
}
buf[m++] = ubuf(num_dihedral[i]).d;
for (k = 0; k < num_dihedral[i]; k++) {
buf[m++] = ubuf(dihedral_type[i][k]).d;
buf[m++] = ubuf(dihedral_atom1[i][k]).d;
buf[m++] = ubuf(dihedral_atom2[i][k]).d;
buf[m++] = ubuf(dihedral_atom3[i][k]).d;
buf[m++] = ubuf(dihedral_atom4[i][k]).d;
}
buf[m++] = ubuf(num_improper[i]).d;
for (k = 0; k < num_improper[i]; k++) {
buf[m++] = ubuf(improper_type[i][k]).d;
buf[m++] = ubuf(improper_atom1[i][k]).d;
buf[m++] = ubuf(improper_atom2[i][k]).d;
buf[m++] = ubuf(improper_atom3[i][k]).d;
buf[m++] = ubuf(improper_atom4[i][k]).d;
}
buf[m++] = ubuf(nspecial[i][0]).d;
buf[m++] = ubuf(nspecial[i][1]).d;
buf[m++] = ubuf(nspecial[i][2]).d;
for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMolecular::unpack_exchange(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_dihedral[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_dihedral[nlocal]; k++) {
dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_improper[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_improper[nlocal]; k++) {
improper_type[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][1] = (int) ubuf(buf[m++]).i;
nspecial[nlocal][2] = (int) ubuf(buf[m++]).i;
for (k = 0; k < nspecial[nlocal][2]; k++)
special[nlocal][k] = (int) ubuf(buf[m++]).i;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecMolecular::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 0;
for (i = 0; i < nlocal; i++)
n += 16 + 2*num_bond[i] + 4*num_angle[i] +
5*num_dihedral[i] + 5*num_improper[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecMolecular::pack_restart(int i, double *buf)
{
int k;
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = ubuf(num_bond[i]).d;
for (k = 0; k < num_bond[i]; k++) {
buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d;
buf[m++] = ubuf(bond_atom[i][k]).d;
}
buf[m++] = ubuf(num_angle[i]).d;
for (k = 0; k < num_angle[i]; k++) {
buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d;
buf[m++] = ubuf(angle_atom1[i][k]).d;
buf[m++] = ubuf(angle_atom2[i][k]).d;
buf[m++] = ubuf(angle_atom3[i][k]).d;
}
buf[m++] = ubuf(num_dihedral[i]).d;
for (k = 0; k < num_dihedral[i]; k++) {
buf[m++] = ubuf(MAX(dihedral_type[i][k],-dihedral_type[i][k])).d;
buf[m++] = ubuf(dihedral_atom1[i][k]).d;
buf[m++] = ubuf(dihedral_atom2[i][k]).d;
buf[m++] = ubuf(dihedral_atom3[i][k]).d;
buf[m++] = ubuf(dihedral_atom4[i][k]).d;
}
buf[m++] = ubuf(num_improper[i]).d;
for (k = 0; k < num_improper[i]; k++) {
buf[m++] = ubuf(MAX(improper_type[i][k],-improper_type[i][k])).d;
buf[m++] = ubuf(improper_atom1[i][k]).d;
buf[m++] = ubuf(improper_atom2[i][k]).d;
buf[m++] = ubuf(improper_atom3[i][k]).d;
buf[m++] = ubuf(improper_atom4[i][k]).d;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecMolecular::unpack_restart(double *buf)
{
int k;
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
num_bond[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_bond[nlocal]; k++) {
bond_type[nlocal][k] = (int) ubuf(buf[m++]).i;
bond_atom[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_angle[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_angle[nlocal]; k++) {
angle_type[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
angle_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_dihedral[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_dihedral[nlocal]; k++) {
dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
dihedral_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
}
num_improper[nlocal] = (int) ubuf(buf[m++]).i;
for (k = 0; k < num_improper[nlocal]; k++) {
improper_type[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom1[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom2[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom3[nlocal][k] = (int) ubuf(buf[m++]).i;
improper_atom4[nlocal][k] = (int) ubuf(buf[m++]).i;
}
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecMolecular::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
molecule[nlocal] = 0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
-void AtomVecMolecular::data_atom(double *coord, imageint imagetmp, char **values)
+void AtomVecMolecular::data_atom(double *coord, imageint imagetmp,
+ char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecMolecular::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
num_bond[nlocal] = 0;
num_angle[nlocal] = 0;
num_dihedral[nlocal] = 0;
num_improper[nlocal] = 0;
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecMolecular::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
buf[i][3] = x[i][0];
buf[i][4] = x[i][1];
buf[i][5] = x[i][2];
buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecMolecular::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
return 1;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecMolecular::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],
(int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i,
(int) ubuf(buf[i][8]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecMolecular::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d",(int) ubuf(buf[0]).i);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecMolecular::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3);
if (atom->memcheck("special"))
bytes += memory->usage(special,nmax,atom->maxspecial);
if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax);
if (atom->memcheck("bond_type"))
bytes += memory->usage(bond_type,nmax,atom->bond_per_atom);
if (atom->memcheck("bond_atom"))
bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom);
if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax);
if (atom->memcheck("angle_type"))
bytes += memory->usage(angle_type,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom1"))
bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom2"))
bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom);
if (atom->memcheck("angle_atom3"))
bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom);
if (atom->memcheck("num_dihedral")) bytes += memory->usage(num_dihedral,nmax);
if (atom->memcheck("dihedral_type"))
bytes += memory->usage(dihedral_type,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom1"))
bytes += memory->usage(dihedral_atom1,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom2"))
bytes += memory->usage(dihedral_atom2,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom3"))
bytes += memory->usage(dihedral_atom3,nmax,atom->dihedral_per_atom);
if (atom->memcheck("dihedral_atom4"))
bytes += memory->usage(dihedral_atom4,nmax,atom->dihedral_per_atom);
if (atom->memcheck("num_improper")) bytes += memory->usage(num_improper,nmax);
if (atom->memcheck("improper_type"))
bytes += memory->usage(improper_type,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom1"))
bytes += memory->usage(improper_atom1,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom2"))
bytes += memory->usage(improper_atom2,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom3"))
bytes += memory->usage(improper_atom3,nmax,atom->improper_per_atom);
if (atom->memcheck("improper_atom4"))
bytes += memory->usage(improper_atom4,nmax,atom->improper_per_atom);
return bytes;
}
diff --git a/src/MOLECULE/atom_vec_molecular.h b/src/MOLECULE/atom_vec_molecular.h
index 6b8791cd4..51b5dd3e4 100644
--- a/src/MOLECULE/atom_vec_molecular.h
+++ b/src/MOLECULE/atom_vec_molecular.h
@@ -1,98 +1,101 @@
/* -*- 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 ATOM_CLASS
AtomStyle(molecular,AtomVecMolecular)
#else
#ifndef LMP_ATOM_VEC_MOLECULAR_H
#define LMP_ATOM_VEC_MOLECULAR_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecMolecular : public AtomVec {
public:
AtomVecMolecular(class LAMMPS *);
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule;
- int **nspecial,**special;
+ int **nspecial;
+ tagint **special;
int *num_bond;
- int **bond_type,**bond_atom;
+ int **bond_type;
+ tagint **bond_atom;
int *num_angle;
int **angle_type;
- int **angle_atom1,**angle_atom2,**angle_atom3;
+ tagint **angle_atom1,**angle_atom2,**angle_atom3;
int *num_dihedral;
int **dihedral_type;
- int **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
+ tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
int *num_improper;
int **improper_type;
- int **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
+ tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/MOLECULE/bond_fene.cpp b/src/MOLECULE/bond_fene.cpp
index 8eca809d1..fb69de6e5 100644
--- a/src/MOLECULE/bond_fene.cpp
+++ b/src/MOLECULE/bond_fene.cpp
@@ -1,274 +1,275 @@
/* ----------------------------------------------------------------------
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 "bond_fene.h"
#include "atom.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "update.h"
#include "force.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondFENE::BondFENE(LAMMPS *lmp) : Bond(lmp)
{
TWO_1_3 = pow(2.0,(1.0/3.0));
}
/* ---------------------------------------------------------------------- */
BondFENE::~BondFENE()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(r0);
memory->destroy(epsilon);
memory->destroy(sigma);
}
}
/* ---------------------------------------------------------------------- */
void BondFENE::compute(int eflag, int vflag)
{
int i1,i2,n,type;
double delx,dely,delz,ebond,fbond;
double rsq,r0sq,rlogarg,sr2,sr6;
ebond = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nbondlist; n++) {
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
// force from log term
rsq = delx*delx + dely*dely + delz*delz;
r0sq = r0[type] * r0[type];
rlogarg = 1.0 - rsq/r0sq;
// if r -> r0, then rlogarg < 0.0 which is an error
// issue a warning and reset rlogarg = epsilon
// if r > 2*r0 something serious is wrong, abort
if (rlogarg < 0.1) {
char str[128];
- sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %d %d %g",
+ sprintf(str,"FENE bond too long: " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " %g",
update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq));
error->warning(FLERR,str,0);
if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond");
rlogarg = 0.1;
}
fbond = -k[type]/rlogarg;
// force from LJ term
if (rsq < TWO_1_3*sigma[type]*sigma[type]) {
sr2 = sigma[type]*sigma[type]/rsq;
sr6 = sr2*sr2*sr2;
fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rsq;
}
// energy
if (eflag) {
ebond = -0.5 * k[type]*r0sq*log(rlogarg);
if (rsq < TWO_1_3*sigma[type]*sigma[type])
ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type];
}
// apply force to each of 2 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx*fbond;
f[i1][1] += dely*fbond;
f[i1][2] += delz*fbond;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= delx*fbond;
f[i2][1] -= dely*fbond;
f[i2][2] -= delz*fbond;
}
if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz);
}
}
/* ---------------------------------------------------------------------- */
void BondFENE::allocate()
{
allocated = 1;
int n = atom->nbondtypes;
memory->create(k,n+1,"bond:k");
memory->create(r0,n+1,"bond:r0");
memory->create(epsilon,n+1,"bond:epsilon");
memory->create(sigma,n+1,"bond:sigma");
memory->create(setflag,n+1,"bond:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void BondFENE::coeff(int narg, char **arg)
{
if (narg != 5) error->all(FLERR,"Incorrect args for bond coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nbondtypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double r0_one = force->numeric(FLERR,arg[2]);
double epsilon_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
r0[i] = r0_one;
epsilon[i] = epsilon_one;
sigma[i] = sigma_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients");
}
/* ----------------------------------------------------------------------
check if special_bond settings are valid
------------------------------------------------------------------------- */
void BondFENE::init_style()
{
// special bonds should be 0 1 1
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0) {
if (comm->me == 0)
error->warning(FLERR,"Use special bonds = 0,1,1 with bond style fene");
}
}
/* ---------------------------------------------------------------------- */
double BondFENE::equilibrium_distance(int i)
{
return 0.97*sigma[i];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void BondFENE::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void BondFENE::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nbondtypes,fp);
fread(&r0[1],sizeof(double),atom->nbondtypes,fp);
fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp);
fread(&sigma[1],sizeof(double),atom->nbondtypes,fp);
}
MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void BondFENE::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nbondtypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,k[i],r0[i],epsilon[i],sigma[i]);
}
/* ---------------------------------------------------------------------- */
double BondFENE::single(int type, double rsq, int i, int j,
double &fforce)
{
double r0sq = r0[type] * r0[type];
double rlogarg = 1.0 - rsq/r0sq;
// if r -> r0, then rlogarg < 0.0 which is an error
// issue a warning and reset rlogarg = epsilon
// if r > 2*r0 something serious is wrong, abort
if (rlogarg < 0.1) {
char str[128];
sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %g",
update->ntimestep,sqrt(rsq));
error->warning(FLERR,str,0);
if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond");
rlogarg = 0.1;
}
double eng = -0.5 * k[type]*r0sq*log(rlogarg);
fforce = -k[type]/rlogarg;
if (rsq < TWO_1_3*sigma[type]*sigma[type]) {
double sr2,sr6;
sr2 = sigma[type]*sigma[type]/rsq;
sr6 = sr2*sr2*sr2;
eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type];
fforce += 48.0*epsilon[type]*sr6*(sr6-0.5)/rsq;
}
return eng;
}
diff --git a/src/MOLECULE/bond_fene_expand.cpp b/src/MOLECULE/bond_fene_expand.cpp
index 214e63279..439b09a5a 100644
--- a/src/MOLECULE/bond_fene_expand.cpp
+++ b/src/MOLECULE/bond_fene_expand.cpp
@@ -1,288 +1,289 @@
/* ----------------------------------------------------------------------
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 "bond_fene_expand.h"
#include "atom.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "update.h"
#include "force.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
BondFENEExpand::BondFENEExpand(LAMMPS *lmp) : Bond(lmp)
{
TWO_1_3 = pow(2.0,(1.0/3.0));
}
/* ---------------------------------------------------------------------- */
BondFENEExpand::~BondFENEExpand()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(r0);
memory->destroy(epsilon);
memory->destroy(sigma);
memory->destroy(shift);
}
}
/* ---------------------------------------------------------------------- */
void BondFENEExpand::compute(int eflag, int vflag)
{
int i1,i2,n,type;
double delx,dely,delz,ebond,fbond;
double rsq,r0sq,rlogarg,sr2,sr6;
double r,rshift,rshiftsq;
ebond = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nbondlist; n++) {
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
// force from log term
rsq = delx*delx + dely*dely + delz*delz;
r = sqrt(rsq);
rshift = r - shift[type];
rshiftsq = rshift*rshift;
r0sq = r0[type] * r0[type];
rlogarg = 1.0 - rshiftsq/r0sq;
// if r -> r0, then rlogarg < 0.0 which is an error
// issue a warning and reset rlogarg = epsilon
// if r > 2*r0 something serious is wrong, abort
if (rlogarg < 0.1) {
char str[128];
- sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %d %d %g",
+ sprintf(str,"FENE bond too long: " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " %g",
update->ntimestep,atom->tag[i1],atom->tag[i2],sqrt(rsq));
error->warning(FLERR,str,0);
if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond");
rlogarg = 0.1;
}
fbond = -k[type]*rshift/rlogarg/r;
// force from LJ term
if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) {
sr2 = sigma[type]*sigma[type]/rshiftsq;
sr6 = sr2*sr2*sr2;
fbond += 48.0*epsilon[type]*sr6*(sr6-0.5)/rshift/r;
}
// energy
if (eflag) {
ebond = -0.5 * k[type]*r0sq*log(rlogarg);
if (rshiftsq < TWO_1_3*sigma[type]*sigma[type])
ebond += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type];
}
// apply force to each of 2 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx*fbond;
f[i1][1] += dely*fbond;
f[i1][2] += delz*fbond;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= delx*fbond;
f[i2][1] -= dely*fbond;
f[i2][2] -= delz*fbond;
}
if (evflag) ev_tally(i1,i2,nlocal,newton_bond,ebond,fbond,delx,dely,delz);
}
}
/* ---------------------------------------------------------------------- */
void BondFENEExpand::allocate()
{
allocated = 1;
int n = atom->nbondtypes;
memory->create(k,n+1,"bond:k");
memory->create(r0,n+1,"bond:r0");
memory->create(epsilon,n+1,"bond:epsilon");
memory->create(sigma,n+1,"bond:sigma");
memory->create(shift,n+1,"bond:shift");
memory->create(setflag,n+1,"bond:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void BondFENEExpand::coeff(int narg, char **arg)
{
if (narg != 6) error->all(FLERR,"Incorrect args for bond coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nbondtypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double r0_one = force->numeric(FLERR,arg[2]);
double epsilon_one = force->numeric(FLERR,arg[3]);
double sigma_one = force->numeric(FLERR,arg[4]);
double shift_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
r0[i] = r0_one;
epsilon[i] = epsilon_one;
sigma[i] = sigma_one;
shift[i] = shift_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for bond coefficients");
}
/* ----------------------------------------------------------------------
check if special_bond settings are valid
------------------------------------------------------------------------- */
void BondFENEExpand::init_style()
{
// special bonds should be 0 1 1
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0) {
if (comm->me == 0)
error->warning(FLERR,"Use special bonds = 0,1,1 with bond style fene/expand");
}
}
/* ---------------------------------------------------------------------- */
double BondFENEExpand::equilibrium_distance(int i)
{
return 0.97*sigma[i] + shift[i];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void BondFENEExpand::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&r0[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&epsilon[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&sigma[1],sizeof(double),atom->nbondtypes,fp);
fwrite(&shift[1],sizeof(double),atom->nbondtypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void BondFENEExpand::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nbondtypes,fp);
fread(&r0[1],sizeof(double),atom->nbondtypes,fp);
fread(&epsilon[1],sizeof(double),atom->nbondtypes,fp);
fread(&sigma[1],sizeof(double),atom->nbondtypes,fp);
fread(&shift[1],sizeof(double),atom->nbondtypes,fp);
}
MPI_Bcast(&k[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&r0[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&epsilon[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&sigma[1],atom->nbondtypes,MPI_DOUBLE,0,world);
MPI_Bcast(&shift[1],atom->nbondtypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nbondtypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void BondFENEExpand::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nbondtypes; i++)
fprintf(fp,"%d %g %g %g %g %g\n",i,k[i],r0[i],epsilon[i],sigma[i],shift[i]);
}
/* ---------------------------------------------------------------------- */
double BondFENEExpand::single(int type, double rsq, int i, int j,
double &fforce)
{
double r = sqrt(rsq);
double rshift = r - shift[type];
double rshiftsq = rshift*rshift;
double r0sq = r0[type] * r0[type];
double rlogarg = 1.0 - rshiftsq/r0sq;
// if r -> r0, then rlogarg < 0.0 which is an error
// issue a warning and reset rlogarg = epsilon
// if r > 2*r0 something serious is wrong, abort
if (rlogarg < 0.1) {
char str[128];
sprintf(str,"FENE bond too long: " BIGINT_FORMAT " %g",
update->ntimestep,sqrt(rsq));
error->warning(FLERR,str,0);
if (rlogarg <= -3.0) error->one(FLERR,"Bad FENE bond");
rlogarg = 0.1;
}
double eng = -0.5 * k[type]*r0sq*log(rlogarg);
fforce = -k[type]*rshift/rlogarg/r;
if (rshiftsq < TWO_1_3*sigma[type]*sigma[type]) {
double sr2,sr6;
sr2 = sigma[type]*sigma[type]/rshiftsq;
sr6 = sr2*sr2*sr2;
eng += 4.0*epsilon[type]*sr6*(sr6-1.0) + epsilon[type];
fforce += 48.0*epsilon[type]*sr6*(sr6-0.5)/rshift/r;
}
return eng;
}
diff --git a/src/MOLECULE/dihedral_charmm.cpp b/src/MOLECULE/dihedral_charmm.cpp
index 8029e7b4f..671514fc5 100644
--- a/src/MOLECULE/dihedral_charmm.cpp
+++ b/src/MOLECULE/dihedral_charmm.cpp
@@ -1,438 +1,440 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_charmm.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "pair.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
/* ---------------------------------------------------------------------- */
DihedralCharmm::DihedralCharmm(LAMMPS *lmp) : Dihedral(lmp)
{
weightflag = 0;
writedata = 1;
}
/* ---------------------------------------------------------------------- */
DihedralCharmm::~DihedralCharmm()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(multiplicity);
memory->destroy(shift);
memory->destroy(cos_shift);
memory->destroy(sin_shift);
memory->destroy(weight);
}
}
/* ---------------------------------------------------------------------- */
void DihedralCharmm::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,m,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb;
double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz;
double c,s,p,sx2,sy2,sz2;
int itype,jtype;
double delx,dely,delz,rsq,r2inv,r6inv;
double forcecoul,forcelj,fpair,ecoul,evdwl;
edihedral = evdwl = ecoul = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
// insure pair->ev_tally() will use 1-4 virial contribution
if (weightflag && vflag_global == 2)
force->pair->vflag_either = force->pair->vflag_global = 1;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *atomtype = atom->type;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double qqrd2e = force->qqrd2e;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
m = multiplicity[type];
p = 1.0;
ddf1 = df1 = 0.0;
for (i = 0; i < m; i++) {
ddf1 = p*c - df1*s;
df1 = p*s + df1*c;
p = ddf1;
}
p = p*cos_shift[type] + df1*sin_shift[type];
df1 = df1*cos_shift[type] - ddf1*sin_shift[type];
df1 *= -m;
p += 1.0;
if (m == 0) {
p = 1.0 + cos_shift[type];
df1 = 0.0;
}
if (eflag) edihedral = k[type] * p;
fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm;
hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm;
fga = fg*ra2inv*rginv;
hgb = hg*rb2inv*rginv;
gaa = -ra2inv*rg;
gbb = rb2inv*rg;
dtfx = gaa*ax;
dtfy = gaa*ay;
dtfz = gaa*az;
dtgx = fga*ax - hgb*bx;
dtgy = fga*ay - hgb*by;
dtgz = fga*az - hgb*bz;
dthx = gbb*bx;
dthy = gbb*by;
dthz = gbb*bz;
df = -k[type] * df1;
sx2 = df*dtgx;
sy2 = df*dtgy;
sz2 = df*dtgz;
f1[0] = df*dtfx;
f1[1] = df*dtfy;
f1[2] = df*dtfz;
f2[0] = sx2 - f1[0];
f2[1] = sy2 - f1[1];
f2[2] = sz2 - f1[2];
f4[0] = df*dthx;
f4[1] = df*dthy;
f4[2] = df*dthz;
f3[0] = -sx2 - f4[0];
f3[1] = -sy2 - f4[1];
f3[2] = -sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
// 1-4 LJ and Coulomb interactions
// tally energy/virial in pair, using newton_bond as newton flag
if (weight[type] > 0.0) {
itype = atomtype[i1];
jtype = atomtype[i4];
delx = x[i1][0] - x[i4][0];
dely = x[i1][1] - x[i4][1];
delz = x[i1][2] - x[i4][2];
rsq = delx*delx + dely*dely + delz*delz;
r2inv = 1.0/rsq;
r6inv = r2inv*r2inv*r2inv;
if (implicit) forcecoul = qqrd2e * q[i1]*q[i4]*r2inv;
else forcecoul = qqrd2e * q[i1]*q[i4]*sqrt(r2inv);
forcelj = r6inv * (lj14_1[itype][jtype]*r6inv - lj14_2[itype][jtype]);
fpair = weight[type] * (forcelj+forcecoul)*r2inv;
if (eflag) {
ecoul = weight[type] * forcecoul;
evdwl = r6inv * (lj14_3[itype][jtype]*r6inv - lj14_4[itype][jtype]);
evdwl *= weight[type];
}
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx*fpair;
f[i1][1] += dely*fpair;
f[i1][2] += delz*fpair;
}
if (newton_bond || i4 < nlocal) {
f[i4][0] -= delx*fpair;
f[i4][1] -= dely*fpair;
f[i4][2] -= delz*fpair;
}
if (evflag) force->pair->ev_tally(i1,i4,nlocal,newton_bond,
evdwl,ecoul,fpair,delx,dely,delz);
}
}
}
/* ---------------------------------------------------------------------- */
void DihedralCharmm::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(k,n+1,"dihedral:k");
memory->create(multiplicity,n+1,"dihedral:k");
memory->create(shift,n+1,"dihedral:shift");
memory->create(cos_shift,n+1,"dihedral:cos_shift");
memory->create(sin_shift,n+1,"dihedral:sin_shift");
memory->create(weight,n+1,"dihedral:weight");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralCharmm::coeff(int narg, char **arg)
{
if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
// require integer values of shift for backwards compatibility
// arbitrary phase angle shift could be allowed, but would break
// backwards compatibility and is probably not needed
double k_one = force->numeric(FLERR,arg[1]);
int multiplicity_one = force->inumeric(FLERR,arg[2]);
int shift_one = force->inumeric(FLERR,arg[3]);
double weight_one = force->numeric(FLERR,arg[4]);
if (multiplicity_one < 0)
error->all(FLERR,"Incorrect multiplicity arg for dihedral coefficients");
if (weight_one < 0.0 || weight_one > 1.0)
error->all(FLERR,"Incorrect weight arg for dihedral coefficients");
if (weight_one > 0.0) weightflag=1;
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
shift[i] = shift_one;
cos_shift[i] = cos(MY_PI*shift_one/180.0);
sin_shift[i] = sin(MY_PI*shift_one/180.0);
multiplicity[i] = multiplicity_one;
weight[i] = weight_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
error check and initialize all values needed for force computation
------------------------------------------------------------------------- */
void DihedralCharmm::init_style()
{
// insure use of CHARMM pair_style if any weight factors are non-zero
// set local ptrs to LJ 14 arrays setup by Pair
if (weightflag) {
int itmp;
if (force->pair == NULL)
error->all(FLERR,"Dihedral charmm is incompatible with Pair style");
lj14_1 = (double **) force->pair->extract("lj14_1",itmp);
lj14_2 = (double **) force->pair->extract("lj14_2",itmp);
lj14_3 = (double **) force->pair->extract("lj14_3",itmp);
lj14_4 = (double **) force->pair->extract("lj14_4",itmp);
int *ptr = (int *) force->pair->extract("implicit",itmp);
if (!lj14_1 || !lj14_2 || !lj14_3 || !lj14_4 || !ptr)
error->all(FLERR,"Dihedral charmm is incompatible with Pair style");
implicit = *ptr;
}
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralCharmm::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp);
fwrite(&shift[1],sizeof(int),atom->ndihedraltypes,fp);
fwrite(&weight[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&weightflag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralCharmm::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp);
fread(&shift[1],sizeof(int),atom->ndihedraltypes,fp);
fread(&weight[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&weightflag,sizeof(int),1,fp);
}
MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world);
MPI_Bcast(&shift[1],atom->ndihedraltypes,MPI_INT,0,world);
MPI_Bcast(&weight[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&weightflag,1,MPI_INT,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) {
setflag[i] = 1;
cos_shift[i] = cos(MY_PI*shift[i]/180.0);
sin_shift[i] = sin(MY_PI*shift[i]/180.0);
}
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void DihedralCharmm::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %d %d %g\n",i,k[i],multiplicity[i],shift[i],weight[i]);
}
diff --git a/src/MOLECULE/dihedral_harmonic.cpp b/src/MOLECULE/dihedral_harmonic.cpp
index a7f353269..0c0ff327b 100644
--- a/src/MOLECULE/dihedral_harmonic.cpp
+++ b/src/MOLECULE/dihedral_harmonic.cpp
@@ -1,361 +1,363 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_harmonic.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
DihedralHarmonic::DihedralHarmonic(LAMMPS *lmp) : Dihedral(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
DihedralHarmonic::~DihedralHarmonic()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(sign);
memory->destroy(multiplicity);
memory->destroy(cos_shift);
memory->destroy(sin_shift);
}
}
/* ---------------------------------------------------------------------- */
void DihedralHarmonic::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,m,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb;
double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz;
double c,s,p,sx2,sy2,sz2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c,s calculation
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
m = multiplicity[type];
p = 1.0;
ddf1 = df1 = 0.0;
for (i = 0; i < m; i++) {
ddf1 = p*c - df1*s;
df1 = p*s + df1*c;
p = ddf1;
}
p = p*cos_shift[type] + df1*sin_shift[type];
df1 = df1*cos_shift[type] - ddf1*sin_shift[type];
df1 *= -m;
p += 1.0;
if (m == 0) {
p = 1.0 + cos_shift[type];
df1 = 0.0;
}
if (eflag) edihedral = k[type] * p;
fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm;
hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm;
fga = fg*ra2inv*rginv;
hgb = hg*rb2inv*rginv;
gaa = -ra2inv*rg;
gbb = rb2inv*rg;
dtfx = gaa*ax;
dtfy = gaa*ay;
dtfz = gaa*az;
dtgx = fga*ax - hgb*bx;
dtgy = fga*ay - hgb*by;
dtgz = fga*az - hgb*bz;
dthx = gbb*bx;
dthy = gbb*by;
dthz = gbb*bz;
df = -k[type] * df1;
sx2 = df*dtgx;
sy2 = df*dtgy;
sz2 = df*dtgz;
f1[0] = df*dtfx;
f1[1] = df*dtfy;
f1[2] = df*dtfz;
f2[0] = sx2 - f1[0];
f2[1] = sy2 - f1[1];
f2[2] = sz2 - f1[2];
f4[0] = df*dthx;
f4[1] = df*dthy;
f4[2] = df*dthz;
f3[0] = -sx2 - f4[0];
f3[1] = -sy2 - f4[1];
f3[2] = -sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralHarmonic::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(k,n+1,"dihedral:k");
memory->create(sign,n+1,"dihedral:sign");
memory->create(multiplicity,n+1,"dihedral:multiplicity");
memory->create(cos_shift,n+1,"dihedral:cos_shift");
memory->create(sin_shift,n+1,"dihedral:sin_shift");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralHarmonic::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
int sign_one = force->inumeric(FLERR,arg[2]);
int multiplicity_one = force->inumeric(FLERR,arg[3]);
// require sign = +/- 1 for backwards compatibility
// arbitrary phase angle shift could be allowed, but would break
// backwards compatibility and is probably not needed
if (sign_one != -1 && sign_one != 1)
error->all(FLERR,"Incorrect sign arg for dihedral coefficients");
if (multiplicity_one < 0)
error->all(FLERR,"Incorrect multiplicity arg for dihedral coefficients");
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
sign[i] = sign_one;
if (sign[i] == 1) {
cos_shift[i] = 1;
sin_shift[i] = 0;
} else {
cos_shift[i] = -1;
sin_shift[i] = 0;
}
multiplicity[i] = multiplicity_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralHarmonic::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&sign[1],sizeof(int),atom->ndihedraltypes,fp);
fwrite(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralHarmonic::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&sign[1],sizeof(int),atom->ndihedraltypes,fp);
fread(&multiplicity[1],sizeof(int),atom->ndihedraltypes,fp);
}
MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&sign[1],atom->ndihedraltypes,MPI_INT,0,world);
MPI_Bcast(&multiplicity[1],atom->ndihedraltypes,MPI_INT,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) {
setflag[i] = 1;
if (sign[i] == 1) {
cos_shift[i] = 1;
sin_shift[i] = 0;
} else {
cos_shift[i] = -1;
sin_shift[i] = 0;
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void DihedralHarmonic::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %d %d\n",i,k[i],sign[i],multiplicity[i]);
}
diff --git a/src/MOLECULE/dihedral_helix.cpp b/src/MOLECULE/dihedral_helix.cpp
index fd5d72e84..744f3b491 100644
--- a/src/MOLECULE/dihedral_helix.cpp
+++ b/src/MOLECULE/dihedral_helix.cpp
@@ -1,333 +1,335 @@
/* ----------------------------------------------------------------------
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: Naveen Michaud-Agrawal (Johns Hopkins U) and
Mark Stevens (Sandia)
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_helix.h"
#include "atom.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.001
#define SMALLER 0.00001
/* ---------------------------------------------------------------------- */
DihedralHelix::DihedralHelix(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralHelix::~DihedralHelix()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(aphi);
memory->destroy(bphi);
memory->destroy(cphi);
}
}
/* ---------------------------------------------------------------------- */
void DihedralHelix::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - c1mag*c1mag,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - c2mag*c2mag,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
cx = vb1y*vb2z - vb1z*vb2y;
cy = vb1z*vb2x - vb1x*vb2z;
cz = vb1x*vb2y - vb1y*vb2x;
cmag = sqrt(cx*cx + cy*cy + cz*cz);
dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
phi = acos(c);
if (dx > 0.0) phi *= -1.0;
si = sin(phi);
if (fabs(si) < SMALLER) si = SMALLER;
siinv = 1.0/si;
p = aphi[type]*(1.0 - c) + bphi[type]*(1.0 + cos(3.0*phi)) +
cphi[type]*(1.0 + cos(phi + MY_PI4));
pd = -aphi[type] + 3.0*bphi[type]*sin(3.0*phi)*siinv +
cphi[type]*sin(phi + MY_PI4)*siinv;
if (eflag) edihedral = p;
a = pd;
c = c * a;
s12 = s12 * a;
a11 = c*sb1*s1;
a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2 * (c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralHelix::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(aphi,n+1,"dihedral:aphi");
memory->create(bphi,n+1,"dihedral:bphi");
memory->create(cphi,n+1,"dihedral:cphi");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs from one line in input script
------------------------------------------------------------------------- */
void DihedralHelix::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double aphi_one = force->numeric(FLERR,arg[1]);
double bphi_one = force->numeric(FLERR,arg[2]);
double cphi_one = force->numeric(FLERR,arg[3]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
aphi[i] = aphi_one;
bphi[i] = bphi_one;
cphi[i] = cphi_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralHelix::write_restart(FILE *fp)
{
fwrite(&aphi[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&bphi[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&cphi[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralHelix::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&aphi[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&bphi[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&cphi[1],sizeof(double),atom->ndihedraltypes,fp);
}
MPI_Bcast(&aphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&bphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&cphi[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
diff --git a/src/MOLECULE/dihedral_multi_harmonic.cpp b/src/MOLECULE/dihedral_multi_harmonic.cpp
index 2e3b4e79d..48f4f2b45 100644
--- a/src/MOLECULE/dihedral_multi_harmonic.cpp
+++ b/src/MOLECULE/dihedral_multi_harmonic.cpp
@@ -1,331 +1,333 @@
/* ----------------------------------------------------------------------
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: Mathias Puetz (SNL) and friends
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "dihedral_multi_harmonic.h"
#include "atom.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
DihedralMultiHarmonic::DihedralMultiHarmonic(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralMultiHarmonic::~DihedralMultiHarmonic()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(a1);
memory->destroy(a2);
memory->destroy(a3);
memory->destroy(a4);
memory->destroy(a5);
}
}
/* ---------------------------------------------------------------------- */
void DihedralMultiHarmonic::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
double s2,sin2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - c1mag*c1mag,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - c2mag*c2mag,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
// p = sum (i=1,5) a_i * c**(i-1)
// pd = dp/dc
p = a1[type] + c*(a2[type] + c*(a3[type] + c*(a4[type] + c*a5[type])));
pd = a2[type] + c*(2.0*a3[type] + c*(3.0*a4[type] + c*4.0*a5[type]));
if (eflag) edihedral = p;
a = pd;
c = c * a;
s12 = s12 * a;
a11 = c*sb1*s1;
a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1*(c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2*(c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralMultiHarmonic::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(a1,n+1,"dihedral:a1");
memory->create(a2,n+1,"dihedral:a2");
memory->create(a3,n+1,"dihedral:a3");
memory->create(a4,n+1,"dihedral:a4");
memory->create(a5,n+1,"dihedral:a5");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralMultiHarmonic::coeff(int narg, char **arg)
{
if (narg != 6) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double a1_one = force->numeric(FLERR,arg[1]);
double a2_one = force->numeric(FLERR,arg[2]);
double a3_one = force->numeric(FLERR,arg[3]);
double a4_one = force->numeric(FLERR,arg[4]);
double a5_one = force->numeric(FLERR,arg[5]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
a1[i] = a1_one;
a2[i] = a2_one;
a3[i] = a3_one;
a4[i] = a4_one;
a5[i] = a5_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralMultiHarmonic::write_restart(FILE *fp)
{
fwrite(&a1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&a2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&a3[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&a4[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&a5[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralMultiHarmonic::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&a1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&a2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&a3[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&a4[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&a5[1],sizeof(double),atom->ndihedraltypes,fp);
}
MPI_Bcast(&a1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&a2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&a3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&a4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&a5[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
diff --git a/src/MOLECULE/dihedral_opls.cpp b/src/MOLECULE/dihedral_opls.cpp
index 074c8bf15..f73b85f9b 100644
--- a/src/MOLECULE/dihedral_opls.cpp
+++ b/src/MOLECULE/dihedral_opls.cpp
@@ -1,355 +1,357 @@
/* ----------------------------------------------------------------------
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: Mark Stevens (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "dihedral_opls.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
#define SMALLER 0.00001
/* ---------------------------------------------------------------------- */
DihedralOPLS::DihedralOPLS(LAMMPS *lmp) : Dihedral(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
DihedralOPLS::~DihedralOPLS()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k1);
memory->destroy(k2);
memory->destroy(k3);
memory->destroy(k4);
}
}
/* ---------------------------------------------------------------------- */
void DihedralOPLS::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
double s2,cx,cy,cz,cmag,dx,phi,si,siinv,sin2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - c1mag*c1mag,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - c2mag*c2mag,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
cx = vb1y*vb2z - vb1z*vb2y;
cy = vb1z*vb2x - vb1x*vb2z;
cz = vb1x*vb2y - vb1y*vb2x;
cmag = sqrt(cx*cx + cy*cy + cz*cz);
dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
// p = sum (i=1,4) k_i * (1 + (-1)**(i+1)*cos(i*phi) )
// pd = dp/dc
phi = acos(c);
if (dx < 0.0) phi *= -1.0;
si = sin(phi);
if (fabs(si) < SMALLER) si = SMALLER;
siinv = 1.0/si;
p = k1[type]*(1.0 + c) + k2[type]*(1.0 - cos(2.0*phi)) +
k3[type]*(1.0 + cos(3.0*phi)) + k4[type]*(1.0 - cos(4.0*phi)) ;
pd = k1[type] - 2.0*k2[type]*sin(2.0*phi)*siinv +
3.0*k3[type]*sin(3.0*phi)*siinv - 4.0*k4[type]*sin(4.0*phi)*siinv;
if (eflag) edihedral = p;
a = pd;
c = c * a;
s12 = s12 * a;
a11 = c*sb1*s1;
a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2 * (c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralOPLS::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(k1,n+1,"dihedral:k1");
memory->create(k2,n+1,"dihedral:k2");
memory->create(k3,n+1,"dihedral:k3");
memory->create(k4,n+1,"dihedral:k4");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralOPLS::coeff(int narg, char **arg)
{
if (narg != 5) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double k1_one = force->numeric(FLERR,arg[1]);
double k2_one = force->numeric(FLERR,arg[2]);
double k3_one = force->numeric(FLERR,arg[3]);
double k4_one = force->numeric(FLERR,arg[4]);
// store 1/2 factor with prefactor
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k1[i] = 0.5*k1_one;
k2[i] = 0.5*k2_one;
k3[i] = 0.5*k3_one;
k4[i] = 0.5*k4_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralOPLS::write_restart(FILE *fp)
{
fwrite(&k1[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&k2[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&k3[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&k4[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralOPLS::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k1[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&k2[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&k3[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&k4[1],sizeof(double),atom->ndihedraltypes,fp);
}
MPI_Bcast(&k1[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k2[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k3[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&k4[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void DihedralOPLS::write_data(FILE *fp)
{
for (int i = 1; i <= atom->ndihedraltypes; i++)
fprintf(fp,"%d %g %g %g %g\n",i,2.0*k1[i],2.0*k2[i],2.0*k3[i],2.0*k4[i]);
}
diff --git a/src/MOLECULE/improper_cvff.cpp b/src/MOLECULE/improper_cvff.cpp
index 06485e918..3d33b3b9f 100644
--- a/src/MOLECULE/improper_cvff.cpp
+++ b/src/MOLECULE/improper_cvff.cpp
@@ -1,358 +1,359 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "improper_cvff.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperCvff::ImproperCvff(LAMMPS *lmp) : Improper(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
ImproperCvff::~ImproperCvff()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(sign);
memory->destroy(multiplicity);
}
}
/* ---------------------------------------------------------------------- */
void ImproperCvff::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,m,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double eimproper,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s2,s12,c,p,pd,rc2,a,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
eimproper = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sc1 = sqrt(1.0 - c1mag*c1mag);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sc2 = sqrt(1.0 - c2mag*c2mag);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,
- "Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
// p = 1 + cos(n*phi) for d = 1
// p = 1 - cos(n*phi) for d = -1
// pd = dp/dc / 2
m = multiplicity[type];
if (m == 2) {
p = 2.0*c*c;
pd = 2.0*c;
} else if (m == 3) {
rc2 = c*c;
p = (4.0*rc2-3.0)*c + 1.0;
pd = 6.0*rc2 - 1.5;
} else if (m == 4) {
rc2 = c*c;
p = 8.0*(rc2-1)*rc2 + 2.0;
pd = (16.0*rc2-8.0)*c;
} else if (m == 6) {
rc2 = c*c;
p = ((32.0*rc2-48.0)*rc2 + 18.0)*rc2;
pd = (96.0*(rc2-1.0)*rc2 + 18.0)*c;
} else if (m == 1) {
p = c + 1.0;
pd = 0.5;
} else if (m == 5) {
rc2 = c*c;
p = ((16.0*rc2-20.0)*rc2 + 5.0)*c + 1.0;
pd = (40.0*rc2-30.0)*rc2 + 2.5;
} else if (m == 0) {
p = 2.0;
pd = 0.0;
}
if (sign[type] == -1) {
p = 2.0 - p;
pd = -pd;
}
if (eflag) eimproper = k[type]*p;
a = 2.0 * k[type] * pd;
c = c * a;
s12 = s12 * a;
a11 = c*sb1*s1;
a22 = -sb2*(2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1*(c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2*(c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void ImproperCvff::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k,n+1,"improper:k");
memory->create(sign,n+1,"improper:sign");
memory->create(multiplicity,n+1,"improper:multiplicity");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperCvff::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
int sign_one = force->inumeric(FLERR,arg[2]);
int multiplicity_one = force->inumeric(FLERR,arg[3]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
sign[i] = sign_one;
multiplicity[i] = multiplicity_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperCvff::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&sign[1],sizeof(int),atom->nimpropertypes,fp);
fwrite(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperCvff::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nimpropertypes,fp);
fread(&sign[1],sizeof(int),atom->nimpropertypes,fp);
fread(&multiplicity[1],sizeof(int),atom->nimpropertypes,fp);
}
MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&sign[1],atom->nimpropertypes,MPI_INT,0,world);
MPI_Bcast(&multiplicity[1],atom->nimpropertypes,MPI_INT,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void ImproperCvff::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nimpropertypes; i++)
fprintf(fp,"%d %g %d %d\n",i,k[i],sign[i],multiplicity[i]);
}
diff --git a/src/MOLECULE/improper_harmonic.cpp b/src/MOLECULE/improper_harmonic.cpp
index 4db32456b..19f845452 100644
--- a/src/MOLECULE/improper_harmonic.cpp
+++ b/src/MOLECULE/improper_harmonic.cpp
@@ -1,297 +1,298 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "improper_harmonic.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperHarmonic::ImproperHarmonic(LAMMPS *lmp) : Improper(lmp)
{
writedata = 1;
}
/* ---------------------------------------------------------------------- */
ImproperHarmonic::~ImproperHarmonic()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(chi);
}
}
/* ---------------------------------------------------------------------- */
void ImproperHarmonic::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z;
double eimproper,f1[3],f2[3],f3[3],f4[3];
double ss1,ss2,ss3,r1,r2,r3,c0,c1,c2,s1,s2;
double s12,c,s,domega,a,a11,a22,a33,a12,a13,a23;
double sx2,sy2,sz2;
eimproper = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
// geometry of 4-body
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
ss1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
ss2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
ss3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
r1 = sqrt(ss1);
r2 = sqrt(ss2);
r3 = sqrt(ss3);
// sin and cos of angle
c0 = (vb1x * vb3x + vb1y * vb3y + vb1z * vb3z) * r1 * r3;
c1 = (vb1x * vb2x + vb1y * vb2y + vb1z * vb2z) * r1 * r2;
c2 = -(vb3x * vb2x + vb3y * vb2y + vb3z * vb2z) * r3 * r2;
s1 = 1.0 - c1*c1;
if (s1 < SMALL) s1 = SMALL;
s1 = 1.0 / s1;
s2 = 1.0 - c2*c2;
if (s2 < SMALL) s2 = SMALL;
s2 = 1.0 / s2;
s12 = sqrt(s1*s2);
c = (c1*c2 + c0) * s12;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,
- "Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
// force & energy
domega = acos(c) - chi[type];
a = k[type] * domega;
if (eflag) eimproper = a*domega;
a = -a * 2.0/s;
c = c * a;
s12 = s12 * a;
a11 = c*ss1*s1;
a22 = -ss2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*ss3*s2;
a12 = -r1*r2*(c1*c*s1 + c2*s12);
a13 = -r1*r3*s12;
a23 = r2*r3*(c2*c*s2 + c1*s12);
sx2 = a22*vb2x + a23*vb3x + a12*vb1x;
sy2 = a22*vb2y + a23*vb3y + a12*vb1y;
sz2 = a22*vb2z + a23*vb3z + a12*vb1z;
f1[0] = a12*vb2x + a13*vb3x + a11*vb1x;
f1[1] = a12*vb2y + a13*vb3y + a11*vb1y;
f1[2] = a12*vb2z + a13*vb3z + a11*vb1z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a23*vb2x + a33*vb3x + a13*vb1x;
f4[1] = a23*vb2y + a33*vb3y + a13*vb1y;
f4[2] = a23*vb2z + a33*vb3z + a13*vb1z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void ImproperHarmonic::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k,n+1,"improper:k");
memory->create(chi,n+1,"improper:chi");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperHarmonic::coeff(int narg, char **arg)
{
if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double chi_one = force->numeric(FLERR,arg[2]);
// convert chi from degrees to radians
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
chi[i] = chi_one/180.0 * MY_PI;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperHarmonic::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperHarmonic::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nimpropertypes,fp);
fread(&chi[1],sizeof(double),atom->nimpropertypes,fp);
}
MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void ImproperHarmonic::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nimpropertypes; i++)
fprintf(fp,"%d %g %g\n",i,k[i],chi[i]/MY_PI*180.0);
}
diff --git a/src/MOLECULE/improper_umbrella.cpp b/src/MOLECULE/improper_umbrella.cpp
index ef8c1a135..a3b7295b3 100644
--- a/src/MOLECULE/improper_umbrella.cpp
+++ b/src/MOLECULE/improper_umbrella.cpp
@@ -1,310 +1,311 @@
/* ----------------------------------------------------------------------
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: Tod A Pascal (Caltech)
------------------------------------------------------------------------- */
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "improper_umbrella.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperUmbrella::ImproperUmbrella(LAMMPS *lmp) : Improper(lmp) {}
/* ---------------------------------------------------------------------- */
ImproperUmbrella::~ImproperUmbrella()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(kw);
memory->destroy(w0);
memory->destroy(C);
}
}
/* ---------------------------------------------------------------------- */
void ImproperUmbrella::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double eimproper,f1[3],f2[3],f3[3],f4[3];
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z;
double domega,c,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi;
double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz;
eimproper = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
// 1st bond
vb1x = x[i2][0] - x[i1][0];
vb1y = x[i2][1] - x[i1][1];
vb1z = x[i2][2] - x[i1][2];
// 2nd bond
vb2x = x[i3][0] - x[i1][0];
vb2y = x[i3][1] - x[i1][1];
vb2z = x[i3][2] - x[i1][2];
// 3rd bond
vb3x = x[i4][0] - x[i1][0];
vb3y = x[i4][1] - x[i1][1];
vb3z = x[i4][2] - x[i1][2];
// c0 calculation
// A = vb1 X vb2 is perpendicular to IJK plane
ax = vb1y*vb2z-vb1z*vb2y;
ay = vb1z*vb2x-vb1x*vb2z;
az = vb1x*vb2y-vb1y*vb2x;
ra2 = ax*ax+ay*ay+az*az;
rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z;
ra = sqrt(ra2);
rh = sqrt(rh2);
if (ra < SMALL) ra = SMALL;
if (rh < SMALL) rh = SMALL;
rar = 1/ra;
rhr = 1/rh;
arx = ax*rar;
ary = ay*rar;
arz = az*rar;
hrx = vb3x*rhr;
hry = vb3y*rhr;
hrz = vb3z*rhr;
c = arx*hrx+ary*hry+arz*hrz;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,
- "Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) s = 1.0;
if (c < -1.0) s = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
cotphi = c/s;
projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) /
sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z);
projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) /
sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z);
if (projhfg > 0.0) {
s *= -1.0;
cotphi *= -1.0;
}
// force and energy
// if w0 = 0: E = k * (1 - cos w)
// if w0 != 0: E = 0.5 * C (cos w - cos w0)^2, C = k/(sin(w0)^2
if (w0[type] == 0.0) {
if (eflag) eimproper = kw[type] * (1.0-s);
a = -kw[type];
} else {
domega = s - cos(w0[type]);
a = 0.5 * C[type] * domega;
if (eflag) eimproper = a * domega;
a *= 2.0;
}
// dhax = diffrence between H and A in X direction, etc
a = a*cotphi;
dhax = hrx-c*arx;
dhay = hry-c*ary;
dhaz = hrz-c*arz;
dahx = arx-c*hrx;
dahy = ary-c*hry;
dahz = arz-c*hrz;
f2[0] = (dhay*vb1z - dhaz*vb1y)*rar;
f2[1] = (dhaz*vb1x - dhax*vb1z)*rar;
f2[2] = (dhax*vb1y - dhay*vb1x)*rar;
f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar;
f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar;
f3[2] = (-dhax*vb2y + dhay*vb2x)*rar;
f4[0] = dahx*rhr;
f4[1] = dahy*rhr;
f4[2] = dahz*rhr;
f1[0] = -(f2[0] + f3[0] + f4[0]);
f1[1] = -(f2[1] + f3[1] + f4[1]);
f1[2] = -(f2[2] + f3[2] + f4[2]);
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0]*a;
f[i1][1] += f1[1]*a;
f[i1][2] += f1[2]*a;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f3[0]*a;
f[i2][1] += f3[1]*a;
f[i2][2] += f3[2]*a;
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f2[0]*a;
f[i3][1] += f2[1]*a;
f[i3][2] += f2[2]*a;
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0]*a;
f[i4][1] += f4[1]*a;
f[i4][2] += f4[2]*a;
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void ImproperUmbrella::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(kw,n+1,"improper:kw");
memory->create(w0,n+1,"improper:w0");
memory->create(C,n+1,"improper:C");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperUmbrella::coeff(int narg, char **arg)
{
if (narg != 3) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double w_one = force->numeric(FLERR,arg[2]);
// convert w0 from degrees to radians
int count = 0;
for (int i = ilo; i <= ihi; i++) {
kw[i] = k_one;
w0[i] = w_one/180.0 * MY_PI;
if (w_one == 0) C[i] = 1.0;
else C[i] = kw[i]/(pow(sin(w0[i]),2.0));
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperUmbrella::write_restart(FILE *fp)
{
fwrite(&kw[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&w0[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&C[1],sizeof(double),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperUmbrella::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&kw[1],sizeof(double),atom->nimpropertypes,fp);
fread(&w0[1],sizeof(double),atom->nimpropertypes,fp);
fread(&C[1],sizeof(double),atom->nimpropertypes,fp);
}
MPI_Bcast(&kw[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&w0[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&C[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
diff --git a/src/MOLECULE/pair_hbond_dreiding_lj.cpp b/src/MOLECULE/pair_hbond_dreiding_lj.cpp
index 381629e16..a25e116e9 100644
--- a/src/MOLECULE/pair_hbond_dreiding_lj.cpp
+++ b/src/MOLECULE/pair_hbond_dreiding_lj.cpp
@@ -1,540 +1,541 @@
/* ----------------------------------------------------------------------
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: Tod A Pascal (Caltech)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_hbond_dreiding_lj.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "neigh_list.h"
#include "domain.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 SMALL 0.001
#define CHUNK 8
/* ---------------------------------------------------------------------- */
PairHbondDreidingLJ::PairHbondDreidingLJ(LAMMPS *lmp) : Pair(lmp)
{
// hbond cannot compute virial as F dot r
// due to using map() to find bonded H atoms which are not near donor atom
no_virial_fdotr_compute = 1;
restartinfo = 0;
nparams = maxparam = 0;
params = NULL;
nextra = 2;
pvector = new double[2];
}
/* ---------------------------------------------------------------------- */
PairHbondDreidingLJ::~PairHbondDreidingLJ()
{
memory->sfree(params);
delete [] pvector;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] donor;
delete [] acceptor;
memory->destroy(type2param);
}
}
/* ---------------------------------------------------------------------- */
void PairHbondDreidingLJ::compute(int eflag, int vflag)
{
int i,j,k,m,ii,jj,kk,inum,jnum,knum,itype,jtype,ktype;
double delx,dely,delz,rsq,rsq1,rsq2,r1,r2;
double factor_hb,force_angle,force_kernel,evdwl,eng_lj,ehbond,force_switch;
double c,s,a,b,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2,d;
double fi[3],fj[3],delr1[3],delr2[3];
double r2inv,r10inv;
double switch1,switch2;
- int *ilist,*jlist,*klist,*numneigh,**firstneigh;
+ int *ilist,*jlist,*numneigh,**firstneigh;
+ tagint *klist;
evdwl = ehbond = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
- int **special = atom->special;
+ tagint **special = atom->special;
int *type = atom->type;
int **nspecial = atom->nspecial;
double *special_lj = force->special_lj;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// ii = loop over donors
// jj = loop over acceptors
// kk = loop over hydrogens bonded to donor
int hbcount = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = type[i];
if (!donor[itype]) continue;
klist = special[i];
knum = nspecial[i][0];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_hb = special_lj[sbmask(j)];
j &= NEIGHMASK;
jtype = type[j];
if (!acceptor[jtype]) continue;
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;
for (kk = 0; kk < knum; kk++) {
k = atom->map(klist[kk]);
if (k < 0) continue;
ktype = type[k];
m = type2param[itype][jtype][ktype];
if (m < 0) continue;
const Param &pm = params[m];
if (rsq < pm.cut_outersq) {
delr1[0] = x[i][0] - x[k][0];
delr1[1] = x[i][1] - x[k][1];
delr1[2] = x[i][2] - x[k][2];
domain->minimum_image(delr1);
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
r1 = sqrt(rsq1);
delr2[0] = x[j][0] - x[k][0];
delr2[1] = x[j][1] - x[k][1];
delr2[2] = x[j][2] - x[k][2];
domain->minimum_image(delr2);
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2];
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
ac = acos(c);
if (ac > pm.cut_angle && ac < (2.0*MY_PI - pm.cut_angle)) {
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
// LJ-specific kernel
r2inv = 1.0/rsq;
r10inv = r2inv*r2inv*r2inv*r2inv*r2inv;
force_kernel = r10inv*(pm.lj1*r2inv - pm.lj2)*r2inv *
powint(c,pm.ap);
force_angle = pm.ap * r10inv*(pm.lj3*r2inv - pm.lj4) *
powint(c,pm.ap-1)*s;
eng_lj = r10inv*(pm.lj3*r2inv - pm.lj4);
force_switch=0.0;
if (rsq > pm.cut_innersq) {
switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) *
(pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) /
pm.denom_vdw;
switch2 = 12.0*rsq * (pm.cut_outersq-rsq) *
(rsq-pm.cut_innersq) / pm.denom_vdw;
force_kernel *= switch1;
force_angle *= switch1;
force_switch = eng_lj*switch2/rsq;
eng_lj *= switch1;
}
if (eflag) {
evdwl = eng_lj * powint(c,pm.ap);
evdwl *= factor_hb;
ehbond += evdwl;
}
a = factor_hb*force_angle/s;
b = factor_hb*force_kernel;
d = factor_hb*force_switch;
a11 = a*c / rsq1;
a12 = -a / (r1*r2);
a22 = a*c / rsq2;
vx1 = a11*delr1[0] + a12*delr2[0];
vx2 = a22*delr2[0] + a12*delr1[0];
vy1 = a11*delr1[1] + a12*delr2[1];
vy2 = a22*delr2[1] + a12*delr1[1];
vz1 = a11*delr1[2] + a12*delr2[2];
vz2 = a22*delr2[2] + a12*delr1[2];
fi[0] = vx1 + b*delx + d*delx;
fi[1] = vy1 + b*dely + d*dely;
fi[2] = vz1 + b*delz + d*delz;
fj[0] = vx2 - b*delx - d*delx;
fj[1] = vy2 - b*dely - d*dely;
fj[2] = vz2 - b*delz - d*delz;
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] -= vx1 + vx2;
f[k][1] -= vy1 + vy2;
f[k][2] -= vz1 + vz2;
// KIJ instead of IJK b/c delr1/delr2 are both with respect to k
if (evflag) ev_tally3(k,i,j,evdwl,0.0,fi,fj,delr1,delr2);
hbcount++;
}
}
}
}
}
if (eflag_global) {
pvector[0] = hbcount;
pvector[1] = ehbond;
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairHbondDreidingLJ::allocate()
{
allocated = 1;
int n = atom->ntypes;
// mark all setflag as set, since don't require pair_coeff of all I,J
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] = 1;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
donor = new int[n+1];
acceptor = new int[n+1];
memory->create(type2param,n+1,n+1,n+1,"pair:type2param");
int i,j,k;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
for (k = 1; k <= n; k++)
type2param[i][j][k] = -1;
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairHbondDreidingLJ::settings(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Illegal pair_style command");
ap_global = force->inumeric(FLERR,arg[0]);
cut_inner_global = force->numeric(FLERR,arg[1]);
cut_outer_global = force->numeric(FLERR,arg[2]);
cut_angle_global = force->numeric(FLERR,arg[3]) * MY_PI/180.0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairHbondDreidingLJ::coeff(int narg, char **arg)
{
if (narg < 6 || narg > 10)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi,klo,khi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
force->bounds(arg[2],atom->ntypes,klo,khi);
int donor_flag;
if (strcmp(arg[3],"i") == 0) donor_flag = 0;
else if (strcmp(arg[3],"j") == 0) donor_flag = 1;
else error->all(FLERR,"Incorrect args for pair coefficients");
double epsilon_one = force->numeric(FLERR,arg[4]);
double sigma_one = force->numeric(FLERR,arg[5]);
int ap_one = ap_global;
if (narg > 6) ap_one = force->inumeric(FLERR,arg[6]);
double cut_inner_one = cut_inner_global;
double cut_outer_one = cut_outer_global;
if (narg > 8) {
cut_inner_one = force->numeric(FLERR,arg[7]);
cut_outer_one = force->numeric(FLERR,arg[8]);
}
if (cut_inner_one>cut_outer_one)
error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff");
double cut_angle_one = cut_angle_global;
if (narg == 10) cut_angle_one = force->numeric(FLERR,arg[9]) * MY_PI/180.0;
// grow params array if necessary
if (nparams == maxparam) {
maxparam += CHUNK;
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
"pair:params");
}
params[nparams].epsilon = epsilon_one;
params[nparams].sigma = sigma_one;
params[nparams].ap = ap_one;
params[nparams].cut_inner = cut_inner_one;
params[nparams].cut_outer = cut_outer_one;
params[nparams].cut_innersq = cut_inner_one*cut_inner_one;
params[nparams].cut_outersq = cut_outer_one*cut_outer_one;
params[nparams].cut_angle = cut_angle_one;
params[nparams].denom_vdw =
(params[nparams].cut_outersq-params[nparams].cut_innersq) *
(params[nparams].cut_outersq-params[nparams].cut_innersq) *
(params[nparams].cut_outersq-params[nparams].cut_innersq);
// flag type2param with either i,j = D,A or j,i = D,A
int count = 0;
for (int i = ilo; i <= ihi; i++)
for (int j = MAX(jlo,i); j <= jhi; j++)
for (int k = klo; k <= khi; k++) {
if (donor_flag == 0) type2param[i][j][k] = nparams;
else type2param[j][i][k] = nparams;
count++;
}
nparams++;
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairHbondDreidingLJ::init_style()
{
// molecular system required to use special list to find H atoms
// tags required to use special list
// pair newton on required since are looping over D atoms
// and computing forces on A,H which may be on different procs
if (atom->molecular == 0)
error->all(FLERR,"Pair style hbond/dreiding requires molecular system");
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style hbond/dreiding requires atom IDs");
if (atom->map_style == 0)
error->all(FLERR,"Pair style hbond/dreiding requires an atom map, "
"see atom_modify");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style hbond/dreiding requires newton pair on");
// set donor[M]/acceptor[M] if any atom of type M is a donor/acceptor
int anyflag = 0;
int n = atom->ntypes;
for (int m = 1; m <= n; m++) donor[m] = acceptor[m] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
if (type2param[i][j][k] >= 0) {
anyflag = 1;
donor[i] = 1;
acceptor[j] = 1;
}
if (!anyflag) error->all(FLERR,"No pair hbond/dreiding coefficients set");
// set additional param values
// offset is for LJ only, angle term is not included
for (int m = 0; m < nparams; m++) {
params[m].lj1 = 60.0*params[m].epsilon*pow(params[m].sigma,12.0);
params[m].lj2 = 60.0*params[m].epsilon*pow(params[m].sigma,10.0);
params[m].lj3 = 5.0*params[m].epsilon*pow(params[m].sigma,12.0);
params[m].lj4 = 6.0*params[m].epsilon*pow(params[m].sigma,10.0);
/*
if (offset_flag) {
double ratio = params[m].sigma / params[m].cut_outer;
params[m].offset = params[m].epsilon *
((2.0*pow(ratio,9.0)) - (3.0*pow(ratio,6.0)));
} else params[m].offset = 0.0;
*/
}
// full neighbor list request
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairHbondDreidingLJ::init_one(int i, int j)
{
int m;
// return maximum cutoff for any K with I,J = D,A or J,I = D,A
// donor/acceptor is not symmetric, IJ interaction != JI interaction
double cut = 0.0;
for (int k = 1; k <= atom->ntypes; k++) {
m = type2param[i][j][k];
if (m >= 0) cut = MAX(cut,params[m].cut_outer);
m = type2param[j][i][k];
if (m >= 0) cut = MAX(cut,params[m].cut_outer);
}
return cut;
}
/* ---------------------------------------------------------------------- */
double PairHbondDreidingLJ::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
int k,kk,ktype,knum,m;
double eng,eng_lj,force_kernel,force_angle;
double rsq1,rsq2,r1,r2,c,s,ac,r2inv,r10inv,factor_hb;
double switch1,switch2;
double delr1[3],delr2[3];
- int *klist;
+ tagint *klist;
double **x = atom->x;
- int **special = atom->special;
+ tagint **special = atom->special;
int *type = atom->type;
int **nspecial = atom->nspecial;
double *special_lj = force->special_lj;
eng = 0.0;
fforce = 0;
// sanity check
if (!donor[itype]) return 0.0;
if (!acceptor[jtype]) return 0.0;
klist = special[i];
knum = nspecial[i][0];
factor_hb = special_lj[sbmask(j)];
for (kk = 0; kk < knum; kk++) {
k = atom->map(klist[kk]);
if (k < 0) continue;
ktype = type[k];
m = type2param[itype][jtype][ktype];
if (m < 0) continue;
const Param &pm = params[m];
delr1[0] = x[i][0] - x[k][0];
delr1[1] = x[i][1] - x[k][1];
delr1[2] = x[i][2] - x[k][2];
domain->minimum_image(delr1);
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
r1 = sqrt(rsq1);
delr2[0] = x[j][0] - x[k][0];
delr2[1] = x[j][1] - x[k][1];
delr2[2] = x[j][2] - x[k][2];
domain->minimum_image(delr2);
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2];
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
ac = acos(c);
if (ac < pm.cut_angle || ac > (2.0*MY_PI - pm.cut_angle)) return 0.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
// LJ-specific kernel
r2inv = 1.0/rsq;
r10inv = r2inv*r2inv*r2inv*r2inv*r2inv;
force_kernel = r10inv*(pm.lj1*r2inv - pm.lj2)*r2inv * powint(c,pm.ap);
force_angle = pm.ap * r10inv*(pm.lj3*r2inv - pm.lj4) *
powint(c,pm.ap-1)*s;
// only lj part for now
eng_lj = r10inv*(pm.lj3*r2inv - pm.lj4);
if (rsq > pm.cut_innersq) {
switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) *
(pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) / pm.denom_vdw;
switch2 = 12.0*rsq * (pm.cut_outersq-rsq) *
(rsq-pm.cut_innersq) / pm.denom_vdw;
force_kernel = force_kernel*switch1 + eng_lj*switch2;
eng_lj *= switch1;
}
fforce += force_kernel*powint(c,pm.ap) + eng_lj*force_angle;
eng += eng_lj * powint(c,pm.ap) * factor_hb;
}
return eng;
}
diff --git a/src/MOLECULE/pair_hbond_dreiding_morse.cpp b/src/MOLECULE/pair_hbond_dreiding_morse.cpp
index e3c26a5dc..975bc9433 100644
--- a/src/MOLECULE/pair_hbond_dreiding_morse.cpp
+++ b/src/MOLECULE/pair_hbond_dreiding_morse.cpp
@@ -1,442 +1,443 @@
/* ----------------------------------------------------------------------
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: Tod A Pascal (Caltech)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_hbond_dreiding_morse.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "neigh_list.h"
#include "domain.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 SMALL 0.001
#define CHUNK 8
/* ---------------------------------------------------------------------- */
PairHbondDreidingMorse::PairHbondDreidingMorse(LAMMPS *lmp) :
PairHbondDreidingLJ(lmp) {}
/* ---------------------------------------------------------------------- */
void PairHbondDreidingMorse::compute(int eflag, int vflag)
{
int i,j,k,m,ii,jj,kk,inum,jnum,knum,itype,jtype,ktype;
double delx,dely,delz,rsq,rsq1,rsq2,r1,r2;
double factor_hb,force_angle,force_kernel,force_switch,evdwl,ehbond;
double c,s,a,b,d,ac,a11,a12,a22,vx1,vx2,vy1,vy2,vz1,vz2;
double fi[3],fj[3],delr1[3],delr2[3];
double r,dr,dexp,eng_morse,switch1,switch2;
- int *ilist,*jlist,*klist,*numneigh,**firstneigh;
+ int *ilist,*jlist,*numneigh,**firstneigh;
+ tagint *klist;
evdwl = ehbond = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
double **x = atom->x;
double **f = atom->f;
- int **special = atom->special;
+ tagint **special = atom->special;
int *type = atom->type;
int **nspecial = atom->nspecial;
double *special_lj = force->special_lj;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// ii = loop over donors
// jj = loop over acceptors
// kk = loop over hydrogens bonded to donor
int hbcount = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = type[i];
if (!donor[itype]) continue;
klist = special[i];
knum = nspecial[i][0];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
factor_hb = special_lj[sbmask(j)];
j &= NEIGHMASK;
jtype = type[j];
if (!acceptor[jtype]) continue;
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;
for (kk = 0; kk < knum; kk++) {
k = atom->map(klist[kk]);
if (k < 0) continue;
ktype = type[k];
m = type2param[itype][jtype][ktype];
if (m < 0) continue;
const Param &pm = params[m];
if (rsq < pm.cut_outersq) {
delr1[0] = x[i][0] - x[k][0];
delr1[1] = x[i][1] - x[k][1];
delr1[2] = x[i][2] - x[k][2];
domain->minimum_image(delr1);
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
r1 = sqrt(rsq1);
delr2[0] = x[j][0] - x[k][0];
delr2[1] = x[j][1] - x[k][1];
delr2[2] = x[j][2] - x[k][2];
domain->minimum_image(delr2);
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2];
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
ac = acos(c);
if (ac > pm.cut_angle && ac < (2.0*MY_PI - pm.cut_angle)) {
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
// Morse-specific kernel
r = sqrt(rsq);
dr = r - pm.r0;
dexp = exp(-pm.alpha * dr);
eng_morse = pm.d0 * (dexp*dexp - 2.0*dexp);
force_kernel = pm.morse1*(dexp*dexp - dexp)/r * powint(c,pm.ap);
force_angle = pm.ap * eng_morse * powint(c,pm.ap-1)*s;
force_switch = 0.0;
if (rsq > pm.cut_innersq) {
switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) *
(pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) /
pm.denom_vdw;
switch2 = 12.0*rsq * (pm.cut_outersq-rsq) *
(rsq-pm.cut_innersq) / pm.denom_vdw;
force_kernel *= switch1;
force_angle *= switch1;
force_switch = eng_morse*switch2/rsq;
eng_morse *= switch1;
}
if (eflag) {
evdwl = eng_morse * powint(c,pm.ap);
evdwl *= factor_hb;
ehbond += evdwl;
}
a = factor_hb*force_angle/s;
b = factor_hb*force_kernel;
d = factor_hb*force_switch;
a11 = a*c / rsq1;
a12 = -a / (r1*r2);
a22 = a*c / rsq2;
vx1 = a11*delr1[0] + a12*delr2[0];
vx2 = a22*delr2[0] + a12*delr1[0];
vy1 = a11*delr1[1] + a12*delr2[1];
vy2 = a22*delr2[1] + a12*delr1[1];
vz1 = a11*delr1[2] + a12*delr2[2];
vz2 = a22*delr2[2] + a12*delr1[2];
fi[0] = vx1 + (b+d)*delx;
fi[1] = vy1 + (b+d)*dely;
fi[2] = vz1 + (b+d)*delz;
fj[0] = vx2 - (b+d)*delx;
fj[1] = vy2 - (b+d)*dely;
fj[2] = vz2 - (b+d)*delz;
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] -= vx1 + vx2;
f[k][1] -= vy1 + vy2;
f[k][2] -= vz1 + vz2;
// KIJ instead of IJK b/c delr1/delr2 are both with respect to k
if (evflag) ev_tally3(k,i,j,evdwl,0.0,fi,fj,delr1,delr2);
hbcount++;
}
}
}
}
}
if (eflag_global) {
pvector[0] = hbcount;
pvector[1] = ehbond;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairHbondDreidingMorse::coeff(int narg, char **arg)
{
if (narg < 7 || narg > 11)
error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi,klo,khi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
force->bounds(arg[2],atom->ntypes,klo,khi);
int donor_flag;
if (strcmp(arg[3],"i") == 0) donor_flag = 0;
else if (strcmp(arg[3],"j") == 0) donor_flag = 1;
else error->all(FLERR,"Incorrect args for pair coefficients");
double d0_one = force->numeric(FLERR,arg[4]);
double alpha_one = force->numeric(FLERR,arg[5]);
double r0_one = force->numeric(FLERR,arg[6]);
int ap_one = ap_global;
if (narg > 7) ap_one = force->inumeric(FLERR,arg[7]);
double cut_inner_one = cut_inner_global;
double cut_outer_one = cut_outer_global;
if (narg > 9) {
cut_inner_one = force->numeric(FLERR,arg[8]);
cut_outer_one = force->numeric(FLERR,arg[9]);
}
if (cut_inner_one>cut_outer_one)
error->all(FLERR,"Pair inner cutoff >= Pair outer cutoff");
double cut_angle_one = cut_angle_global;
if (narg > 10) cut_angle_one = force->numeric(FLERR,arg[10]) * MY_PI/180.0;
// grow params array if necessary
if (nparams == maxparam) {
maxparam += CHUNK;
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
"pair:params");
}
params[nparams].d0 = d0_one;
params[nparams].alpha = alpha_one;
params[nparams].r0 = r0_one;
params[nparams].ap = ap_one;
params[nparams].cut_inner = cut_inner_one;
params[nparams].cut_outer = cut_outer_one;
params[nparams].cut_innersq = cut_inner_one*cut_inner_one;
params[nparams].cut_outersq = cut_outer_one*cut_outer_one;
params[nparams].cut_angle = cut_angle_one;
params[nparams].denom_vdw =
(params[nparams].cut_outersq-params[nparams].cut_innersq) *
(params[nparams].cut_outersq-params[nparams].cut_innersq) *
(params[nparams].cut_outersq-params[nparams].cut_innersq);
// flag type2param with either i,j = D,A or j,i = D,A
int count = 0;
for (int i = ilo; i <= ihi; i++)
for (int j = MAX(jlo,i); j <= jhi; j++)
for (int k = klo; k <= khi; k++) {
if (donor_flag == 0) type2param[i][j][k] = nparams;
else type2param[j][i][k] = nparams;
count++;
}
nparams++;
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairHbondDreidingMorse::init_style()
{
// molecular system required to use special list to find H atoms
// tags required to use special list
// pair newton on required since are looping over D atoms
// and computing forces on A,H which may be on different procs
if (atom->molecular == 0)
error->all(FLERR,"Pair style hbond/dreiding requires molecular system");
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style hbond/dreiding requires atom IDs");
if (atom->map_style == 0)
error->all(FLERR,"Pair style hbond/dreiding requires an atom map, "
"see atom_modify");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style hbond/dreiding requires newton pair on");
// set donor[M]/acceptor[M] if any atom of type M is a donor/acceptor
int anyflag = 0;
int n = atom->ntypes;
for (int m = 1; m <= n; m++) donor[m] = acceptor[m] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
if (type2param[i][j][k] >= 0) {
anyflag = 1;
donor[i] = 1;
acceptor[j] = 1;
}
if (!anyflag) error->all(FLERR,"No pair hbond/dreiding coefficients set");
// set additional param values
// offset is for Morse only, angle term is not included
for (int m = 0; m < nparams; m++) {
params[m].morse1 = 2.0*params[m].d0*params[m].alpha;
/*
if (offset_flag) {
double alpha_dr = -params[m].alpha * (params[m].cut - params[m].r0);
params[m].offset = params[m].d0 *
((exp(2.0*alpha_dr)) - (2.0*exp(alpha_dr)));
} else params[m].offset = 0.0;
*/
}
// full neighbor list request
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ---------------------------------------------------------------------- */
double PairHbondDreidingMorse::single(int i, int j, int itype, int jtype,
double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
int k,kk,ktype,knum,m;
double eng,eng_morse,force_kernel,force_angle;
double rsq1,rsq2,r1,r2,c,s,ac,r,dr,dexp,factor_hb;
double switch1,switch2;
double delr1[3],delr2[3];
- int *klist;
+ tagint *klist;
double **x = atom->x;
- int **special = atom->special;
+ tagint **special = atom->special;
int *type = atom->type;
int **nspecial = atom->nspecial;
double *special_lj = force->special_lj;
eng = 0.0;
fforce = 0;
//sanity check
if (!donor[itype]) return 0.0;
if (!acceptor[jtype]) return 0.0;
klist = special[i];
knum = nspecial[i][0];
factor_hb = special_lj[sbmask(j)];
for (kk = 0; kk < knum; kk++) {
k = atom->map(klist[kk]);
if (k < 0) continue;
ktype = type[k];
m = type2param[itype][jtype][ktype];
if (m < 0) continue;
const Param &pm = params[m];
delr1[0] = x[i][0] - x[k][0];
delr1[1] = x[i][1] - x[k][1];
delr1[2] = x[i][2] - x[k][2];
domain->minimum_image(delr1);
rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2];
r1 = sqrt(rsq1);
delr2[0] = x[j][0] - x[k][0];
delr2[1] = x[j][1] - x[k][1];
delr2[2] = x[j][2] - x[k][2];
domain->minimum_image(delr2);
rsq2 = delr2[0]*delr2[0] + delr2[1]*delr2[1] + delr2[2]*delr2[2];
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2];
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
ac = acos(c);
if (ac < pm.cut_angle || ac > (2.0*MY_PI - pm.cut_angle)) return 0.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
// Morse-specific kernel
r = sqrt(rsq);
dr = r - pm.r0;
dexp = exp(-pm.alpha * dr);
eng_morse = pm.d0 * (dexp*dexp - 2.0*dexp); //<-- BUGFIX 2012-11-14
force_kernel = pm.morse1*(dexp*dexp - dexp)/r * powint(c,pm.ap);
force_angle = pm.ap * eng_morse * powint(c,pm.ap-1)*s;
if (rsq > pm.cut_innersq) {
switch1 = (pm.cut_outersq-rsq) * (pm.cut_outersq-rsq) *
(pm.cut_outersq + 2.0*rsq - 3.0*pm.cut_innersq) /
pm.denom_vdw;
switch2 = 12.0*rsq * (pm.cut_outersq-rsq) *
(rsq-pm.cut_innersq) / pm.denom_vdw;
force_kernel = force_kernel*switch1 + eng_morse*switch2;
eng_morse *= switch1;
}
eng += eng_morse * powint(c,pm.ap)* factor_hb;
fforce += force_kernel*powint(c,pm.ap) + eng_morse*force_angle;
}
return eng;
}
diff --git a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
index 04b37635b..39f8a3c1f 100644
--- a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
+++ b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp
@@ -1,734 +1,735 @@
/* ----------------------------------------------------------------------
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 "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],xH1[3],xH2[3];
double *x1,*x2;
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) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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+1; 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(arg[0],atom->ntypes,ilo,ihi);
force->bounds(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);
// 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) {
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];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
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);
}
/* ----------------------------------------------------------------------
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/MOLECULE/pair_tip4p_cut.cpp b/src/MOLECULE/pair_tip4p_cut.cpp
index d1ce9b256..57bb72da8 100644
--- a/src/MOLECULE/pair_tip4p_cut.cpp
+++ b/src/MOLECULE/pair_tip4p_cut.cpp
@@ -1,551 +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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Pavel Elkind (Gothenburg University)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "pair_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;
/* ---------------------------------------------------------------------- */
PairTIP4PCut::PairTIP4PCut(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
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;
}
/* ---------------------------------------------------------------------- */
PairTIP4PCut::~PairTIP4PCut()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
}
memory->destroy(hneigh);
memory->destroy(newsite);
}
/* ---------------------------------------------------------------------- */
void PairTIP4PCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul;
double rsq,r2inv,forcecoul,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],xH1[3],xH2[3];
double *x1,*x2;
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_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) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite(x[i],x[iH1],x[iH2],newsite[i]);
} 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_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];
// 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) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite(x[j],x[jH1],x[jH2],newsite[j]);
} 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) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
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) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
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 PairTIP4PCut::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");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairTIP4PCut::settings(int narg, char **arg)
{
if (narg != 6) 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_coul = force->numeric(FLERR,arg[5]);
cut_coulsq = cut_coul * cut_coul;
cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist);
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairTIP4PCut::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(arg[0],atom->ntypes,ilo,ihi);
force->bounds(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
------------------------------------------------------------------------- */
void PairTIP4PCut::init_style()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Pair style tip4p/cut requires atom IDs");
if (!force->newton_pair)
error->all(FLERR,
"Pair style tip4p/cut requires newton pair on");
if (!atom->q_flag)
error->all(FLERR,
"Pair style 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);
// 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 PairTIP4PCut::init_one(int i, int j)
{
// include TIP4P qdist in full cutoff, qdist = 0.0 if not TIP4P
return cut_coul+2.0*qdist;
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairTIP4PCut::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);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairTIP4PCut::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);
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairTIP4PCut::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_coul,sizeof(double),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairTIP4PCut::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_coul,sizeof(double),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_coul,1,MPI_DOUBLE,0,world);
cut_coulsq = cut_coul * cut_coul;
cut_coulsqplus = (cut_coul + 2.0*qdist) * (cut_coul + 2.0*qdist);
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairTIP4PCut::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];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
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);
}
/* ----------------------------------------------------------------------
memory usage of hneigh
------------------------------------------------------------------------- */
double PairTIP4PCut::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index a4770269d..9c9d1b903 100644
--- a/src/Makefile.shlib
+++ b/src/Makefile.shlib
@@ -1,43 +1,43 @@
# LAMMPS shared library multiple-machine Makefile
SHELL = /bin/sh
# Definitions
ROOT = lammps
EXE = lib$(ROOT)_$@.so
-SRC = angle.cpp angle_charmm.cpp angle_class2.cpp angle_cosine.cpp angle_cosine_delta.cpp angle_cosine_periodic.cpp angle_cosine_squared.cpp angle_harmonic.cpp angle_hybrid.cpp angle_table.cpp atom.cpp atom_map.cpp atom_vec.cpp atom_vec_angle.cpp atom_vec_atomic.cpp atom_vec_body.cpp atom_vec_bond.cpp atom_vec_charge.cpp atom_vec_dipole.cpp atom_vec_ellipsoid.cpp atom_vec_full.cpp atom_vec_hybrid.cpp atom_vec_line.cpp atom_vec_molecular.cpp atom_vec_peri.cpp atom_vec_sphere.cpp atom_vec_tri.cpp balance.cpp body.cpp body_nparticle.cpp bond.cpp bond_class2.cpp bond_fene.cpp bond_fene_expand.cpp bond_harmonic.cpp bond_hybrid.cpp bond_morse.cpp bond_nonlinear.cpp bond_quartic.cpp bond_table.cpp change_box.cpp comm.cpp compute.cpp compute_angle_local.cpp compute_atom_molecule.cpp compute_body_local.cpp compute_bond_local.cpp compute_centro_atom.cpp compute_cluster_atom.cpp compute_cna_atom.cpp compute_com.cpp compute_com_molecule.cpp compute_contact_atom.cpp compute_coord_atom.cpp compute_damage_atom.cpp compute_dihedral_local.cpp compute_displace_atom.cpp compute_erotate_asphere.cpp compute_erotate_sphere.cpp compute_erotate_sphere_atom.cpp compute_event_displace.cpp compute_group_group.cpp compute_gyration.cpp compute_gyration_molecule.cpp compute_heat_flux.cpp compute_improper_local.cpp compute_inertia_molecule.cpp compute_ke.cpp compute_ke_atom.cpp compute_msd.cpp compute_msd_molecule.cpp compute_pair.cpp compute_pair_local.cpp compute_pe.cpp compute_pe_atom.cpp compute_pressure.cpp compute_property_atom.cpp compute_property_local.cpp compute_property_molecule.cpp compute_rdf.cpp compute_reduce.cpp compute_reduce_region.cpp compute_slice.cpp compute_stress_atom.cpp compute_temp.cpp compute_temp_asphere.cpp compute_temp_com.cpp compute_temp_deform.cpp compute_temp_partial.cpp compute_temp_profile.cpp compute_temp_ramp.cpp compute_temp_region.cpp compute_temp_sphere.cpp compute_ti.cpp create_atoms.cpp create_box.cpp delete_atoms.cpp delete_bonds.cpp dihedral.cpp dihedral_charmm.cpp dihedral_class2.cpp dihedral_harmonic.cpp dihedral_helix.cpp dihedral_hybrid.cpp dihedral_multi_harmonic.cpp dihedral_opls.cpp displace_atoms.cpp domain.cpp dump.cpp dump_atom.cpp dump_cfg.cpp dump_custom.cpp dump_dcd.cpp dump_image.cpp dump_local.cpp dump_xtc.cpp dump_xyz.cpp error.cpp finish.cpp fix.cpp fix_adapt.cpp fix_addforce.cpp fix_append_atoms.cpp fix_ave_atom.cpp fix_ave_correlate.cpp fix_ave_histo.cpp fix_ave_spatial.cpp fix_ave_time.cpp fix_aveforce.cpp fix_balance.cpp fix_bond_break.cpp fix_bond_create.cpp fix_bond_swap.cpp fix_box_relax.cpp fix_deform.cpp fix_deposit.cpp fix_drag.cpp fix_dt_reset.cpp fix_efield.cpp fix_enforce2d.cpp fix_evaporate.cpp fix_event.cpp fix_event_prd.cpp fix_event_tad.cpp fix_external.cpp fix_freeze.cpp fix_gcmc.cpp fix_gravity.cpp fix_heat.cpp fix_indent.cpp fix_langevin.cpp fix_lineforce.cpp fix_minimize.cpp fix_momentum.cpp fix_move.cpp fix_msst.cpp fix_neb.cpp fix_nh.cpp fix_nh_asphere.cpp fix_nh_sphere.cpp fix_nph.cpp fix_nph_asphere.cpp fix_nph_sphere.cpp fix_nphug.cpp fix_npt.cpp fix_npt_asphere.cpp fix_npt_sphere.cpp fix_nve.cpp fix_nve_asphere.cpp fix_nve_asphere_noforce.cpp fix_nve_body.cpp fix_nve_limit.cpp fix_nve_line.cpp fix_nve_noforce.cpp fix_nve_sphere.cpp fix_nve_tri.cpp fix_nvt.cpp fix_nvt_asphere.cpp fix_nvt_sllod.cpp fix_nvt_sphere.cpp fix_orient_fcc.cpp fix_peri_neigh.cpp fix_planeforce.cpp fix_pour.cpp fix_press_berendsen.cpp fix_print.cpp fix_qeq_comb.cpp fix_read_restart.cpp fix_recenter.cpp fix_respa.cpp fix_restrain.cpp fix_rigid.cpp fix_rigid_nh.cpp fix_rigid_nph.cpp fix_rigid_npt.cpp fix_rigid_nve.cpp fix_rigid_nvt.cpp fix_rigid_small.cpp fix_setforce.cpp fix_shake.cpp fix_shear_history.cpp fix_spring.cpp fix_spring_rg.cpp fix_spring_self.cpp fix_srd.cpp fix_store_force.cpp fix_store_state.cpp fix_temp_berendsen.cpp fix_temp_rescale.cpp fix_thermal_conductivity.cpp fix_tmd.cpp fix_ttm.cpp fix_viscosity.cpp fix_viscous.cpp fix_wall.cpp fix_wall_colloid.cpp fix_wall_gran.cpp fix_wall_harmonic.cpp fix_wall_lj126.cpp fix_wall_lj93.cpp fix_wall_piston.cpp fix_wall_reflect.cpp fix_wall_region.cpp fix_wall_srd.cpp force.cpp group.cpp image.cpp improper.cpp improper_class2.cpp improper_cvff.cpp improper_harmonic.cpp improper_hybrid.cpp improper_umbrella.cpp input.cpp integrate.cpp irregular.cpp kspace.cpp lammps.cpp lattice.cpp library.cpp math_extra.cpp memory.cpp min.cpp min_cg.cpp min_fire.cpp min_hftn.cpp min_linesearch.cpp min_quickmin.cpp min_sd.cpp minimize.cpp modify.cpp neb.cpp neigh_bond.cpp neigh_derive.cpp neigh_full.cpp neigh_gran.cpp neigh_half_bin.cpp neigh_half_multi.cpp neigh_half_nsq.cpp neigh_list.cpp neigh_request.cpp neigh_respa.cpp neigh_stencil.cpp neighbor.cpp output.cpp pair.cpp pair_adp.cpp pair_airebo.cpp pair_beck.cpp pair_body.cpp pair_bop.cpp pair_born.cpp pair_born_coul_wolf.cpp pair_brownian.cpp pair_brownian_poly.cpp pair_buck.cpp pair_buck_coul_cut.cpp pair_colloid.cpp pair_comb.cpp pair_coul_cut.cpp pair_coul_debye.cpp pair_coul_dsf.cpp pair_coul_wolf.cpp pair_dipole_cut.cpp pair_dpd.cpp pair_dpd_tstat.cpp pair_dsmc.cpp pair_eam.cpp pair_eam_alloy.cpp pair_eam_alloy_opt.cpp pair_eam_fs.cpp pair_eam_fs_opt.cpp pair_eam_opt.cpp pair_eim.cpp pair_gauss.cpp pair_gayberne.cpp pair_gran_hertz_history.cpp pair_gran_hooke.cpp pair_gran_hooke_history.cpp pair_hbond_dreiding_lj.cpp pair_hbond_dreiding_morse.cpp pair_hybrid.cpp pair_hybrid_overlay.cpp pair_lcbop.cpp pair_line_lj.cpp pair_lj96_cut.cpp pair_lj_charmm_coul_charmm.cpp pair_lj_charmm_coul_charmm_implicit.cpp pair_lj_class2.cpp pair_lj_class2_coul_cut.cpp pair_lj_class2_coul_long.cpp pair_lj_cubic.cpp pair_lj_cut.cpp pair_lj_cut_coul_cut.cpp pair_lj_cut_coul_debye.cpp pair_lj_cut_coul_dsf.cpp pair_lj_cut_opt.cpp pair_lj_cut_tip4p_cut.cpp pair_lj_expand.cpp pair_lj_gromacs.cpp pair_lj_gromacs_coul_gromacs.cpp pair_lj_smooth.cpp pair_lj_smooth_linear.cpp pair_lubricate.cpp pair_lubricateU.cpp pair_lubricateU_poly.cpp pair_lubricate_poly.cpp pair_mie_cut.cpp pair_morse.cpp pair_morse_opt.cpp pair_peri_lps.cpp pair_peri_pmb.cpp pair_rebo.cpp pair_resquared.cpp pair_soft.cpp pair_sw.cpp pair_table.cpp pair_tersoff.cpp pair_tersoff_zbl.cpp pair_tri_lj.cpp pair_yukawa.cpp pair_yukawa_colloid.cpp prd.cpp procmap.cpp random_mars.cpp random_park.cpp read_data.cpp read_dump.cpp read_restart.cpp reader.cpp reader_native.cpp reader_xyz.cpp region.cpp region_block.cpp region_cone.cpp region_cylinder.cpp region_intersect.cpp region_plane.cpp region_prism.cpp region_sphere.cpp region_union.cpp replicate.cpp rerun.cpp respa.cpp run.cpp set.cpp special.cpp tad.cpp temper.cpp thermo.cpp timer.cpp universe.cpp update.cpp variable.cpp velocity.cpp verlet.cpp verlet_split.cpp write_restart.cpp xdr_compat.cpp
+SRC = angle.cpp angle_charmm.cpp angle_class2.cpp angle_cosine.cpp angle_cosine_delta.cpp angle_cosine_periodic.cpp angle_cosine_squared.cpp angle_harmonic.cpp angle_hybrid.cpp angle_table.cpp atom.cpp atom_map.cpp atom_vec.cpp atom_vec_angle.cpp atom_vec_atomic.cpp atom_vec_body.cpp atom_vec_bond.cpp atom_vec_charge.cpp atom_vec_dipole.cpp atom_vec_ellipsoid.cpp atom_vec_full.cpp atom_vec_hybrid.cpp atom_vec_line.cpp atom_vec_molecular.cpp atom_vec_peri.cpp atom_vec_sphere.cpp atom_vec_tri.cpp balance.cpp body.cpp body_nparticle.cpp bond.cpp bond_class2.cpp bond_fene.cpp bond_fene_expand.cpp bond_harmonic.cpp bond_hybrid.cpp bond_morse.cpp bond_nonlinear.cpp bond_quartic.cpp bond_table.cpp change_box.cpp citeme.cpp comm.cpp compute.cpp compute_angle_local.cpp compute_atom_molecule.cpp compute_body_local.cpp compute_bond_local.cpp compute_centro_atom.cpp compute_cluster_atom.cpp compute_cna_atom.cpp compute_com.cpp compute_com_molecule.cpp compute_contact_atom.cpp compute_coord_atom.cpp compute_damage_atom.cpp compute_dihedral_local.cpp compute_displace_atom.cpp compute_erotate_asphere.cpp compute_erotate_rigid.cpp compute_erotate_sphere.cpp compute_erotate_sphere_atom.cpp compute_event_displace.cpp compute_group_group.cpp compute_gyration.cpp compute_gyration_molecule.cpp compute_heat_flux.cpp compute_improper_local.cpp compute_inertia_molecule.cpp compute_ke.cpp compute_ke_atom.cpp compute_ke_rigid.cpp compute_msd.cpp compute_msd_molecule.cpp compute_msd_nongauss.cpp compute_pair.cpp compute_pair_local.cpp compute_pe.cpp compute_pe_atom.cpp compute_pressure.cpp compute_property_atom.cpp compute_property_local.cpp compute_property_molecule.cpp compute_rdf.cpp compute_reduce.cpp compute_reduce_region.cpp compute_slice.cpp compute_stress_atom.cpp compute_temp.cpp compute_temp_asphere.cpp compute_temp_com.cpp compute_temp_deform.cpp compute_temp_partial.cpp compute_temp_profile.cpp compute_temp_ramp.cpp compute_temp_region.cpp compute_temp_sphere.cpp compute_ti.cpp compute_vacf.cpp create_atoms.cpp create_box.cpp delete_atoms.cpp delete_bonds.cpp dihedral.cpp dihedral_charmm.cpp dihedral_class2.cpp dihedral_harmonic.cpp dihedral_helix.cpp dihedral_hybrid.cpp dihedral_multi_harmonic.cpp dihedral_opls.cpp displace_atoms.cpp domain.cpp dump.cpp dump_atom.cpp dump_cfg.cpp dump_custom.cpp dump_dcd.cpp dump_image.cpp dump_local.cpp dump_movie.cpp dump_xtc.cpp dump_xyz.cpp error.cpp finish.cpp fix.cpp fix_adapt.cpp fix_addforce.cpp fix_append_atoms.cpp fix_ave_atom.cpp fix_ave_correlate.cpp fix_ave_histo.cpp fix_ave_spatial.cpp fix_ave_time.cpp fix_aveforce.cpp fix_balance.cpp fix_bond_break.cpp fix_bond_create.cpp fix_bond_swap.cpp fix_box_relax.cpp fix_deform.cpp fix_deposit.cpp fix_drag.cpp fix_dt_reset.cpp fix_efield.cpp fix_enforce2d.cpp fix_evaporate.cpp fix_event.cpp fix_event_prd.cpp fix_event_tad.cpp fix_external.cpp fix_freeze.cpp fix_gcmc.cpp fix_gld.cpp fix_gravity.cpp fix_heat.cpp fix_indent.cpp fix_langevin.cpp fix_lineforce.cpp fix_minimize.cpp fix_momentum.cpp fix_move.cpp fix_msst.cpp fix_neb.cpp fix_nh.cpp fix_nh_asphere.cpp fix_nh_sphere.cpp fix_nph.cpp fix_nph_asphere.cpp fix_nph_sphere.cpp fix_nphug.cpp fix_npt.cpp fix_npt_asphere.cpp fix_npt_sphere.cpp fix_nve.cpp fix_nve_asphere.cpp fix_nve_asphere_noforce.cpp fix_nve_body.cpp fix_nve_limit.cpp fix_nve_line.cpp fix_nve_noforce.cpp fix_nve_sphere.cpp fix_nve_tri.cpp fix_nvt.cpp fix_nvt_asphere.cpp fix_nvt_sllod.cpp fix_nvt_sphere.cpp fix_orient_fcc.cpp fix_peri_neigh.cpp fix_planeforce.cpp fix_pour.cpp fix_press_berendsen.cpp fix_print.cpp fix_property_atom.cpp fix_qeq_comb.cpp fix_read_restart.cpp fix_recenter.cpp fix_respa.cpp fix_restrain.cpp fix_rigid.cpp fix_rigid_nh.cpp fix_rigid_nph.cpp fix_rigid_npt.cpp fix_rigid_nve.cpp fix_rigid_nvt.cpp fix_rigid_small.cpp fix_setforce.cpp fix_shake.cpp fix_shear_history.cpp fix_spring.cpp fix_spring_rg.cpp fix_spring_self.cpp fix_srd.cpp fix_store.cpp fix_store_force.cpp fix_store_state.cpp fix_temp_berendsen.cpp fix_temp_rescale.cpp fix_thermal_conductivity.cpp fix_tmd.cpp fix_ttm.cpp fix_viscosity.cpp fix_viscous.cpp fix_wall.cpp fix_wall_colloid.cpp fix_wall_gran.cpp fix_wall_harmonic.cpp fix_wall_lj1043.cpp fix_wall_lj126.cpp fix_wall_lj93.cpp fix_wall_piston.cpp fix_wall_reflect.cpp fix_wall_region.cpp fix_wall_srd.cpp force.cpp group.cpp image.cpp improper.cpp improper_class2.cpp improper_cvff.cpp improper_harmonic.cpp improper_hybrid.cpp improper_umbrella.cpp input.cpp integrate.cpp irregular.cpp kspace.cpp lammps.cpp lattice.cpp library.cpp math_extra.cpp memory.cpp min.cpp min_cg.cpp min_fire.cpp min_hftn.cpp min_linesearch.cpp min_quickmin.cpp min_sd.cpp minimize.cpp modify.cpp molecule.cpp neb.cpp neigh_bond.cpp neigh_derive.cpp neigh_full.cpp neigh_gran.cpp neigh_half_bin.cpp neigh_half_multi.cpp neigh_half_nsq.cpp neigh_list.cpp neigh_request.cpp neigh_respa.cpp neigh_stencil.cpp neighbor.cpp output.cpp pair.cpp pair_adp.cpp pair_airebo.cpp pair_beck.cpp pair_body.cpp pair_bop.cpp pair_born.cpp pair_born_coul_wolf.cpp pair_brownian.cpp pair_brownian_poly.cpp pair_buck.cpp pair_buck_coul_cut.cpp pair_colloid.cpp pair_colloid_poly.cpp pair_comb.cpp pair_comb3.cpp pair_coul_cut.cpp pair_coul_debye.cpp pair_coul_dsf.cpp pair_coul_wolf.cpp pair_dipole_cut.cpp pair_dpd.cpp pair_dpd_tstat.cpp pair_dsmc.cpp pair_eam.cpp pair_eam_alloy.cpp pair_eam_alloy_opt.cpp pair_eam_fs.cpp pair_eam_fs_opt.cpp pair_eam_opt.cpp pair_eim.cpp pair_gauss.cpp pair_gayberne.cpp pair_gran_hertz_history.cpp pair_gran_hooke.cpp pair_gran_hooke_history.cpp pair_hbond_dreiding_lj.cpp pair_hbond_dreiding_morse.cpp pair_hybrid.cpp pair_hybrid_overlay.cpp pair_lcbop.cpp pair_line_lj.cpp pair_lj96_cut.cpp pair_lj_charmm_coul_charmm.cpp pair_lj_charmm_coul_charmm_implicit.cpp pair_lj_class2.cpp pair_lj_class2_coul_cut.cpp pair_lj_class2_coul_long.cpp pair_lj_cubic.cpp pair_lj_cut.cpp pair_lj_cut_coul_cut.cpp pair_lj_cut_coul_debye.cpp pair_lj_cut_coul_dsf.cpp pair_lj_cut_dipole_cut.cpp pair_lj_cut_dipole_long.cpp pair_lj_cut_opt.cpp pair_lj_cut_tip4p_cut.cpp pair_lj_expand.cpp pair_lj_gromacs.cpp pair_lj_gromacs_coul_gromacs.cpp pair_lj_long_dipole_long.cpp pair_lj_smooth.cpp pair_lj_smooth_linear.cpp pair_lubricate.cpp pair_lubricateU.cpp pair_lubricateU_poly.cpp pair_lubricate_poly.cpp pair_mie_cut.cpp pair_morse.cpp pair_morse_opt.cpp pair_nb3b_harmonic.cpp pair_nm_cut.cpp pair_nm_cut_coul_cut.cpp pair_nm_cut_coul_long.cpp pair_peri_lps.cpp pair_peri_pmb.cpp pair_peri_ves.cpp pair_rebo.cpp pair_resquared.cpp pair_soft.cpp pair_sw.cpp pair_table.cpp pair_tersoff.cpp pair_tersoff_mod.cpp pair_tersoff_zbl.cpp pair_tip4p_cut.cpp pair_tri_lj.cpp pair_yukawa.cpp pair_yukawa_colloid.cpp pair_zbl.cpp prd.cpp procmap.cpp random_mars.cpp random_park.cpp read_data.cpp read_dump.cpp read_restart.cpp reader.cpp reader_native.cpp reader_xyz.cpp region.cpp region_block.cpp region_cone.cpp region_cylinder.cpp region_intersect.cpp region_plane.cpp region_prism.cpp region_sphere.cpp region_union.cpp replicate.cpp rerun.cpp respa.cpp run.cpp set.cpp special.cpp tad.cpp temper.cpp thermo.cpp timer.cpp universe.cpp update.cpp variable.cpp velocity.cpp verlet.cpp verlet_split.cpp write_data.cpp write_dump.cpp write_restart.cpp xdr_compat.cpp
-INC = accelerator_cuda.h accelerator_omp.h angle.h angle_charmm.h angle_class2.h angle_cosine.h angle_cosine_delta.h angle_cosine_periodic.h angle_cosine_squared.h angle_harmonic.h angle_hybrid.h angle_table.h atom.h atom_map.h atom_masks.h atom_vec.h atom_vec_angle.h atom_vec_atomic.h atom_vec_body.h atom_vec_bond.h atom_vec_charge.h atom_vec_dipole.h atom_vec_ellipsoid.h atom_vec_full.h atom_vec_hybrid.h atom_vec_line.h atom_vec_molecular.h atom_vec_peri.h atom_vec_sphere.h atom_vec_tri.h balance.h body.h body_nparticle.h bond.h bond_class2.h bond_fene.h bond_fene_expand.h bond_harmonic.h bond_hybrid.h bond_morse.h bond_nonlinear.h bond_quartic.h bond_table.h change_box.h comm.h compute.h compute_angle_local.h compute_atom_molecule.h compute_body_local.h compute_bond_local.h compute_centro_atom.h compute_cluster_atom.h compute_cna_atom.h compute_com.h compute_com_molecule.h compute_contact_atom.h compute_coord_atom.h compute_damage_atom.h compute_dihedral_local.h compute_displace_atom.h compute_erotate_asphere.h compute_erotate_sphere.h compute_erotate_sphere_atom.h compute_event_displace.h compute_group_group.h compute_gyration.h compute_gyration_molecule.h compute_heat_flux.h compute_improper_local.h compute_inertia_molecule.h compute_ke.h compute_ke_atom.h compute_msd.h compute_msd_molecule.h compute_pair.h compute_pair_local.h compute_pe.h compute_pe_atom.h compute_pressure.h compute_property_atom.h compute_property_local.h compute_property_molecule.h compute_rdf.h compute_reduce.h compute_reduce_region.h compute_slice.h compute_stress_atom.h compute_temp.h compute_temp_asphere.h compute_temp_com.h compute_temp_deform.h compute_temp_partial.h compute_temp_profile.h compute_temp_ramp.h compute_temp_region.h compute_temp_sphere.h compute_ti.h create_atoms.h create_box.h delete_atoms.h delete_bonds.h dihedral.h dihedral_charmm.h dihedral_class2.h dihedral_harmonic.h dihedral_helix.h dihedral_hybrid.h dihedral_multi_harmonic.h dihedral_opls.h displace_atoms.h domain.h dump.h dump_atom.h dump_cfg.h dump_custom.h dump_dcd.h dump_image.h dump_local.h dump_xtc.h dump_xyz.h error.h finish.h fix.h fix_adapt.h fix_addforce.h fix_append_atoms.h fix_ave_atom.h fix_ave_correlate.h fix_ave_histo.h fix_ave_spatial.h fix_ave_time.h fix_aveforce.h fix_balance.h fix_bond_break.h fix_bond_create.h fix_bond_swap.h fix_box_relax.h fix_deform.h fix_deposit.h fix_drag.h fix_dt_reset.h fix_efield.h fix_enforce2d.h fix_evaporate.h fix_event.h fix_event_prd.h fix_event_tad.h fix_external.h fix_freeze.h fix_gcmc.h fix_gravity.h fix_heat.h fix_indent.h fix_langevin.h fix_lineforce.h fix_minimize.h fix_momentum.h fix_move.h fix_msst.h fix_neb.h fix_nh.h fix_nh_asphere.h fix_nh_sphere.h fix_nph.h fix_nph_asphere.h fix_nph_sphere.h fix_nphug.h fix_npt.h fix_npt_asphere.h fix_npt_sphere.h fix_nve.h fix_nve_asphere.h fix_nve_asphere_noforce.h fix_nve_body.h fix_nve_limit.h fix_nve_line.h fix_nve_noforce.h fix_nve_sphere.h fix_nve_tri.h fix_nvt.h fix_nvt_asphere.h fix_nvt_sllod.h fix_nvt_sphere.h fix_orient_fcc.h fix_peri_neigh.h fix_planeforce.h fix_pour.h fix_press_berendsen.h fix_print.h fix_qeq_comb.h fix_read_restart.h fix_recenter.h fix_respa.h fix_restrain.h fix_rigid.h fix_rigid_nh.h fix_rigid_nph.h fix_rigid_npt.h fix_rigid_nve.h fix_rigid_nvt.h fix_rigid_small.h fix_setforce.h fix_shake.h fix_shear_history.h fix_spring.h fix_spring_rg.h fix_spring_self.h fix_srd.h fix_store_force.h fix_store_state.h fix_temp_berendsen.h fix_temp_rescale.h fix_thermal_conductivity.h fix_tmd.h fix_ttm.h fix_viscosity.h fix_viscous.h fix_wall.h fix_wall_colloid.h fix_wall_gran.h fix_wall_harmonic.h fix_wall_lj126.h fix_wall_lj93.h fix_wall_piston.h fix_wall_reflect.h fix_wall_region.h fix_wall_srd.h force.h group.h image.h improper.h improper_class2.h improper_cvff.h improper_harmonic.h improper_hybrid.h improper_umbrella.h input.h integrate.h irregular.h kspace.h lammps.h lattice.h library.h lmptype.h lmpwindows.h math_const.h math_extra.h math_special.h memory.h min.h min_cg.h min_fire.h min_hftn.h min_linesearch.h min_quickmin.h min_sd.h minimize.h modify.h my_pool.h neb.h neigh_bond.h neigh_derive.h neigh_full.h neigh_gran.h neigh_half_bin.h neigh_half_multi.h neigh_half_nsq.h neigh_list.h neigh_request.h neigh_respa.h neighbor.h output.h pack.h pair.h pair_adp.h pair_airebo.h pair_beck.h pair_body.h pair_bop.h pair_born.h pair_born_coul_wolf.h pair_brownian.h pair_brownian_poly.h pair_buck.h pair_buck_coul_cut.h pair_colloid.h pair_comb.h pair_coul_cut.h pair_coul_debye.h pair_coul_dsf.h pair_coul_wolf.h pair_dipole_cut.h pair_dpd.h pair_dpd_tstat.h pair_dsmc.h pair_eam.h pair_eam_alloy.h pair_eam_alloy_opt.h pair_eam_fs.h pair_eam_fs_opt.h pair_eam_opt.h pair_eim.h pair_gauss.h pair_gayberne.h pair_gran_hertz_history.h pair_gran_hooke.h pair_gran_hooke_history.h pair_hbond_dreiding_lj.h pair_hbond_dreiding_morse.h pair_hybrid.h pair_hybrid_overlay.h pair_lcbop.h pair_line_lj.h pair_lj96_cut.h pair_lj_charmm_coul_charmm.h pair_lj_charmm_coul_charmm_implicit.h pair_lj_class2.h pair_lj_class2_coul_cut.h pair_lj_class2_coul_long.h pair_lj_cubic.h pair_lj_cut.h pair_lj_cut_coul_cut.h pair_lj_cut_coul_debye.h pair_lj_cut_coul_dsf.h pair_lj_cut_opt.h pair_lj_cut_tip4p_cut.h pair_lj_expand.h pair_lj_gromacs.h pair_lj_gromacs_coul_gromacs.h pair_lj_smooth.h pair_lj_smooth_linear.h pair_lubricate.h pair_lubricateU.h pair_lubricateU_poly.h pair_lubricate_poly.h pair_mie_cut.h pair_morse.h pair_morse_opt.h pair_peri_lps.h pair_peri_pmb.h pair_rebo.h pair_resquared.h pair_soft.h pair_sw.h pair_table.h pair_tersoff.h pair_tersoff_zbl.h pair_tri_lj.h pair_yukawa.h pair_yukawa_colloid.h pointers.h prd.h procmap.h random_mars.h random_park.h read_data.h read_dump.h read_restart.h reader.h reader_native.h reader_xyz.h region.h region_block.h region_cone.h region_cylinder.h region_intersect.h region_plane.h region_prism.h region_sphere.h region_union.h replicate.h rerun.h respa.h run.h set.h special.h style_angle.h style_atom.h style_body.h style_bond.h style_command.h style_compute.h style_dihedral.h style_dump.h style_fix.h style_improper.h style_integrate.h style_kspace.h style_minimize.h style_pair.h style_reader.h style_region.h suffix.h tad.h temper.h thermo.h timer.h universe.h update.h variable.h velocity.h verlet.h verlet_split.h version.h write_restart.h xdr_compat.h
+INC = accelerator_cuda.h accelerator_omp.h angle.h angle_charmm.h angle_class2.h angle_cosine.h angle_cosine_delta.h angle_cosine_periodic.h angle_cosine_squared.h angle_harmonic.h angle_hybrid.h angle_table.h atom.h atom_map.h atom_masks.h atom_vec.h atom_vec_angle.h atom_vec_atomic.h atom_vec_body.h atom_vec_bond.h atom_vec_charge.h atom_vec_dipole.h atom_vec_ellipsoid.h atom_vec_full.h atom_vec_hybrid.h atom_vec_line.h atom_vec_molecular.h atom_vec_peri.h atom_vec_sphere.h atom_vec_tri.h balance.h body.h body_nparticle.h bond.h bond_class2.h bond_fene.h bond_fene_expand.h bond_harmonic.h bond_hybrid.h bond_morse.h bond_nonlinear.h bond_quartic.h bond_table.h change_box.h citeme.h comm.h compute.h compute_angle_local.h compute_atom_molecule.h compute_body_local.h compute_bond_local.h compute_centro_atom.h compute_cluster_atom.h compute_cna_atom.h compute_com.h compute_com_molecule.h compute_contact_atom.h compute_coord_atom.h compute_damage_atom.h compute_dihedral_local.h compute_displace_atom.h compute_erotate_asphere.h compute_erotate_rigid.h compute_erotate_sphere.h compute_erotate_sphere_atom.h compute_event_displace.h compute_group_group.h compute_gyration.h compute_gyration_molecule.h compute_heat_flux.h compute_improper_local.h compute_inertia_molecule.h compute_ke.h compute_ke_atom.h compute_ke_rigid.h compute_msd.h compute_msd_molecule.h compute_msd_nongauss.h compute_pair.h compute_pair_local.h compute_pe.h compute_pe_atom.h compute_pressure.h compute_property_atom.h compute_property_local.h compute_property_molecule.h compute_rdf.h compute_reduce.h compute_reduce_region.h compute_slice.h compute_stress_atom.h compute_temp.h compute_temp_asphere.h compute_temp_com.h compute_temp_deform.h compute_temp_partial.h compute_temp_profile.h compute_temp_ramp.h compute_temp_region.h compute_temp_sphere.h compute_ti.h compute_vacf.h create_atoms.h create_box.h delete_atoms.h delete_bonds.h dihedral.h dihedral_charmm.h dihedral_class2.h dihedral_harmonic.h dihedral_helix.h dihedral_hybrid.h dihedral_multi_harmonic.h dihedral_opls.h displace_atoms.h domain.h dump.h dump_atom.h dump_cfg.h dump_custom.h dump_dcd.h dump_image.h dump_local.h dump_movie.h dump_xtc.h dump_xyz.h error.h finish.h fix.h fix_adapt.h fix_addforce.h fix_append_atoms.h fix_ave_atom.h fix_ave_correlate.h fix_ave_histo.h fix_ave_spatial.h fix_ave_time.h fix_aveforce.h fix_balance.h fix_bond_break.h fix_bond_create.h fix_bond_swap.h fix_box_relax.h fix_deform.h fix_deposit.h fix_drag.h fix_dt_reset.h fix_efield.h fix_enforce2d.h fix_evaporate.h fix_event.h fix_event_prd.h fix_event_tad.h fix_external.h fix_freeze.h fix_gcmc.h fix_gld.h fix_gravity.h fix_heat.h fix_indent.h fix_langevin.h fix_lineforce.h fix_minimize.h fix_momentum.h fix_move.h fix_msst.h fix_neb.h fix_nh.h fix_nh_asphere.h fix_nh_sphere.h fix_nph.h fix_nph_asphere.h fix_nph_sphere.h fix_nphug.h fix_npt.h fix_npt_asphere.h fix_npt_sphere.h fix_nve.h fix_nve_asphere.h fix_nve_asphere_noforce.h fix_nve_body.h fix_nve_limit.h fix_nve_line.h fix_nve_noforce.h fix_nve_sphere.h fix_nve_tri.h fix_nvt.h fix_nvt_asphere.h fix_nvt_sllod.h fix_nvt_sphere.h fix_orient_fcc.h fix_peri_neigh.h fix_planeforce.h fix_pour.h fix_press_berendsen.h fix_print.h fix_property_atom.h fix_qeq_comb.h fix_read_restart.h fix_recenter.h fix_respa.h fix_restrain.h fix_rigid.h fix_rigid_nh.h fix_rigid_nph.h fix_rigid_npt.h fix_rigid_nve.h fix_rigid_nvt.h fix_rigid_small.h fix_setforce.h fix_shake.h fix_shear_history.h fix_spring.h fix_spring_rg.h fix_spring_self.h fix_srd.h fix_store.h fix_store_force.h fix_store_state.h fix_temp_berendsen.h fix_temp_rescale.h fix_thermal_conductivity.h fix_tmd.h fix_ttm.h fix_viscosity.h fix_viscous.h fix_wall.h fix_wall_colloid.h fix_wall_gran.h fix_wall_harmonic.h fix_wall_lj1043.h fix_wall_lj126.h fix_wall_lj93.h fix_wall_piston.h fix_wall_reflect.h fix_wall_region.h fix_wall_srd.h force.h group.h image.h improper.h improper_class2.h improper_cvff.h improper_harmonic.h improper_hybrid.h improper_umbrella.h input.h integrate.h irregular.h kspace.h lammps.h lattice.h library.h lmptype.h lmpwindows.h math_complex.h math_const.h math_extra.h math_special.h math_vector.h memory.h min.h min_cg.h min_fire.h min_hftn.h min_linesearch.h min_quickmin.h min_sd.h minimize.h modify.h molecule.h mpiio.h my_page.h my_pool_chunk.h neb.h neigh_bond.h neigh_derive.h neigh_full.h neigh_gran.h neigh_half_bin.h neigh_half_multi.h neigh_half_nsq.h neigh_list.h neigh_request.h neigh_respa.h neighbor.h output.h pack.h pair.h pair_adp.h pair_airebo.h pair_beck.h pair_body.h pair_bop.h pair_born.h pair_born_coul_wolf.h pair_brownian.h pair_brownian_poly.h pair_buck.h pair_buck_coul_cut.h pair_colloid.h pair_colloid_poly.h pair_comb.h pair_comb3.h pair_coul_cut.h pair_coul_debye.h pair_coul_dsf.h pair_coul_wolf.h pair_dipole_cut.h pair_dpd.h pair_dpd_tstat.h pair_dsmc.h pair_eam.h pair_eam_alloy.h pair_eam_alloy_opt.h pair_eam_fs.h pair_eam_fs_opt.h pair_eam_opt.h pair_eim.h pair_gauss.h pair_gayberne.h pair_gran_hertz_history.h pair_gran_hooke.h pair_gran_hooke_history.h pair_hbond_dreiding_lj.h pair_hbond_dreiding_morse.h pair_hybrid.h pair_hybrid_overlay.h pair_lcbop.h pair_line_lj.h pair_lj96_cut.h pair_lj_charmm_coul_charmm.h pair_lj_charmm_coul_charmm_implicit.h pair_lj_class2.h pair_lj_class2_coul_cut.h pair_lj_class2_coul_long.h pair_lj_cubic.h pair_lj_cut.h pair_lj_cut_coul_cut.h pair_lj_cut_coul_debye.h pair_lj_cut_coul_dsf.h pair_lj_cut_dipole_cut.h pair_lj_cut_dipole_long.h pair_lj_cut_opt.h pair_lj_cut_tip4p_cut.h pair_lj_expand.h pair_lj_gromacs.h pair_lj_gromacs_coul_gromacs.h pair_lj_long_dipole_long.h pair_lj_smooth.h pair_lj_smooth_linear.h pair_lubricate.h pair_lubricateU.h pair_lubricateU_poly.h pair_lubricate_poly.h pair_mie_cut.h pair_morse.h pair_morse_opt.h pair_nb3b_harmonic.h pair_nm_cut.h pair_nm_cut_coul_cut.h pair_nm_cut_coul_long.h pair_peri_lps.h pair_peri_pmb.h pair_peri_ves.h pair_rebo.h pair_resquared.h pair_soft.h pair_sw.h pair_table.h pair_tersoff.h pair_tersoff_mod.h pair_tersoff_zbl.h pair_tip4p_cut.h pair_tri_lj.h pair_yukawa.h pair_yukawa_colloid.h pair_zbl.h pointers.h prd.h procmap.h random_mars.h random_park.h read_data.h read_dump.h read_restart.h reader.h reader_native.h reader_xyz.h region.h region_block.h region_cone.h region_cylinder.h region_intersect.h region_plane.h region_prism.h region_sphere.h region_union.h replicate.h rerun.h respa.h run.h set.h special.h style_angle.h style_atom.h style_body.h style_bond.h style_command.h style_compute.h style_dihedral.h style_dump.h style_fix.h style_improper.h style_integrate.h style_kspace.h style_minimize.h style_pair.h style_reader.h style_region.h suffix.h tad.h temper.h thermo.h timer.h universe.h update.h variable.h velocity.h verlet.h verlet_split.h version.h write_data.h write_dump.h write_restart.h xdr_compat.h
OBJ = $(SRC:.cpp=.o)
# Targets
help:
@echo 'Type "make target" where target is one of:'
@echo ''
@files="`ls MAKE/Makefile.*`"; \
for file in $$files; do head -1 $$file; done
clean:
rm -rf Obj_shlib_*
.DEFAULT:
@test -f MAKE/Makefile.$@
@if [ ! -d Obj_shlib_$@ ]; then mkdir Obj_shlib_$@; fi
@cp -p $(SRC) $(INC) Obj_shlib_$@
@cp MAKE/Makefile.$@ Obj_shlib_$@/Makefile
@if [ ! -e Makefile.package ]; \
then cp Makefile.package.empty Makefile.package; fi
@if [ ! -e Makefile.package.settings ]; \
then cp Makefile.package.settings.empty Makefile.package.settings; fi
@cp Makefile.package Makefile.package.settings Obj_shlib_$@
@cd Obj_shlib_$@; \
$(MAKE) $(MFLAGS) "OBJ = $(OBJ)" \
"INC = $(INC)" "EXE = ../$(EXE)" shlib
@rm -f liblammps.so
@ln -s $(EXE) liblammps.so
@if [ -d Obj_shlib_$@ ]; then cd Obj_shlib_$@; \
rm -f $(SRC) $(INC) Makefile*; fi
diff --git a/src/OPT/pair_lj_cut_tip4p_long_opt.cpp b/src/OPT/pair_lj_cut_tip4p_long_opt.cpp
index 30ef31879..e045eeec7 100644
--- a/src/OPT/pair_lj_cut_tip4p_long_opt.cpp
+++ b/src/OPT/pair_lj_cut_tip4p_long_opt.cpp
@@ -1,470 +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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
OPT version: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
#include "math.h"
#include "pair_lj_cut_tip4p_long_opt.h"
#include "atom.h"
#include "domain.h"
#include "force.h"
#include "error.h"
#include "memory.h"
#include "neighbor.h"
#include "neigh_list.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
/* ---------------------------------------------------------------------- */
PairLJCutTIP4PLongOpt::PairLJCutTIP4PLongOpt(LAMMPS *lmp) :
PairLJCutTIP4PLong(lmp)
{
single_enable = 0;
respa_enable = 0;
// 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;
}
/* ---------------------------------------------------------------------- */
void PairLJCutTIP4PLongOpt::compute(int eflag, int vflag)
{
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = vflag_fdotr = 0;
const int nlocal = atom->nlocal;
const int nall = nlocal + atom->nghost;
// reallocate hneigh & newsite if necessary
// initialize hneigh[0] to -1 on steps when reneighboring occurred
// initialize hneigh[2] to 0 every step
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");
}
int i;
if (neighbor->ago == 0)
for (i = 0; i < nall; i++) hneigh[i][0] = -1;
for (i = 0; i < nall; i++) hneigh[i][2] = 0;
if (!ncoultablebits) {
if (evflag) {
if (eflag) {
if (vflag) return eval<1,1,1,1>();
else return eval<1,1,1,0>();
} else {
if (vflag) return eval<1,1,0,1>();
else return eval<1,1,0,0>();
}
} else return eval<1,0,0,0>();
} else {
if (evflag) {
if (eflag) {
if (vflag) return eval<0,1,1,1>();
else return eval<0,1,1,0>();
} else {
if (vflag) return eval<0,1,0,1>();
else return eval<0,1,0,0>();
}
} else return eval<0,0,0,0>();
}
}
/* ---------------------------------------------------------------------- */
template < const int CTABLE, const int EVFLAG,
const int EFLAG, const int VFLAG>
void PairLJCutTIP4PLongOpt::eval()
{
double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul;
double fraction,table;
double r,rsq,r2inv,r6inv,forcecoul,forcelj,cforce;
double factor_coul,factor_lj;
double grij,expm2,prefactor,t,erfc;
double v[6],xH1[3],xH2[3];
double fdx,fdy,fdz,fOx,fOy,fOz,fHx,fHy,fHz;
const double *x1,*x2;
int *ilist,*jlist,*numneigh,**firstneigh;
int i,j,ii,jj,inum,jnum,itype,jtype,itable,key;
int n,vlist[6];
int iH1,iH2,jH1,jH2;
evdwl = ecoul = 0.0;
const double * const * const x = atom->x;
double * const * const f = atom->f;
const double * const q = atom->q;
+ const tagint * const tag = atom->tag;
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;
const double cut_coulsqplus = (cut_coul+2.0*qdist) * (cut_coul+2.0*qdist);
double fxtmp,fytmp,fztmp;
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 atom I = water O, set x1 = offset charge site
// else x1 = x of atom I
if (itype == typeO) {
if (hneigh[i][0] < 0) {
- hneigh[i][0] = iH1 = atom->map(atom->tag[i] + 1);
- hneigh[i][1] = iH2 = atom->map(atom->tag[i] + 2);
+ hneigh[i][0] = iH1 = atom->map(tag[i] + 1);
+ hneigh[i][1] = iH2 = atom->map(tag[i] + 2);
hneigh[i][2] = 1;
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");
compute_newsite_opt(x[i],x[iH1],x[iH2],newsite[i]);
} else {
iH1 = hneigh[i][0];
iH2 = hneigh[i][1];
if (hneigh[i][2] == 0) {
hneigh[i][2] = 1;
compute_newsite_opt(x[i],x[iH1],x[iH2],newsite[i]);
}
}
x1 = newsite[i];
} else x1 = x[i];
jlist = firstneigh[i];
jnum = numneigh[i];
fxtmp=fytmp=fztmp=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];
// 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;
fxtmp += delx*forcelj;
fytmp += dely*forcelj;
fztmp += 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 = */ 1,
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) {
- hneigh[j][0] = jH1 = atom->map(atom->tag[j] + 1);
- hneigh[j][1] = jH2 = atom->map(atom->tag[j] + 2);
+ hneigh[j][0] = jH1 = atom->map(tag[j] + 1);
+ hneigh[j][1] = jH2 = atom->map(tag[j] + 2);
hneigh[j][2] = 1;
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");
compute_newsite_opt(x[j],x[jH1],x[jH2],newsite[j]);
} else {
jH1 = hneigh[j][0];
jH2 = hneigh[j][1];
if (hneigh[j][2] == 0) {
hneigh[j][2] = 1;
compute_newsite_opt(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 / rsq;
if (CTABLE || 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;
}
}
cforce = 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
if (EVFLAG) {
n = 0;
key = 0;
}
if (itype != typeO) {
fxtmp += delx * cforce;
fytmp += dely * cforce;
fztmp += 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;
}
if (EVFLAG) vlist[n++] = i;
} else {
if (EVFLAG) key += 1;
fdx = delx*cforce;
fdy = dely*cforce;
fdz = delz*cforce;
fOx = fdx*(1-alpha);
fOy = fdy*(1-alpha);
fOz = fdz*(1-alpha);
fHx = 0.5 * alpha * fdx;
fHy = 0.5 * alpha * fdy;
fHz = 0.5 * alpha * fdz;
fxtmp += fOx;
fytmp += fOy;
fztmp += fOz;
f[iH1][0] += fHx;
f[iH1][1] += fHy;
f[iH1][2] += fHz;
f[iH2][0] += fHx;
f[iH2][1] += fHy;
f[iH2][2] += fHz;
if (VFLAG) {
domain->closest_image(x[i],x[iH1],xH1);
domain->closest_image(x[i],x[iH2],xH2);
v[0] = x[i][0]*fOx + xH1[0]*fHx + xH2[0]*fHx;
v[1] = x[i][1]*fOy + xH1[1]*fHy + xH2[1]*fHy;
v[2] = x[i][2]*fOz + xH1[2]*fHz + xH2[2]*fHz;
v[3] = x[i][0]*fOy + xH1[0]*fHy + xH2[0]*fHy;
v[4] = x[i][0]*fOz + xH1[0]*fHz + xH2[0]*fHz;
v[5] = x[i][1]*fOz + xH1[1]*fHz + xH2[1]*fHz;
}
if (EVFLAG) {
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;
}
if (EVFLAG) vlist[n++] = j;
} else {
if (EVFLAG) key += 2;
fdx = -delx*cforce;
fdy = -dely*cforce;
fdz = -delz*cforce;
fOx = fdx*(1-alpha);
fOy = fdy*(1-alpha);
fOz = fdz*(1-alpha);
fHx = 0.5 * alpha * fdx;
fHy = 0.5 * alpha * fdy;
fHz = 0.5 * alpha * fdz;
f[j][0] += fOx;
f[j][1] += fOy;
f[j][2] += fOz;
f[jH1][0] += fHx;
f[jH1][1] += fHy;
f[jH1][2] += fHz;
f[jH2][0] += fHx;
f[jH2][1] += fHy;
f[jH2][2] += fHz;
if (VFLAG) {
domain->closest_image(x[j],x[jH1],xH1);
domain->closest_image(x[j],x[jH2],xH2);
v[0] += x[j][0]*fOx + xH1[0]*fHx + xH2[0]*fHx;
v[1] += x[j][1]*fOy + xH1[1]*fHy + xH2[1]*fHy;
v[2] += x[j][2]*fOz + xH1[2]*fHz + xH2[2]*fHz;
v[3] += x[j][0]*fOy + xH1[0]*fHy + xH2[0]*fHy;
v[4] += x[j][0]*fOz + xH1[0]*fHz + xH2[0]*fHz;
v[5] += x[j][1]*fOz + xH1[1]*fHz + xH2[1]*fHz;
}
if (EVFLAG) {
vlist[n++] = j;
vlist[n++] = jH1;
vlist[n++] = jH2;
}
}
if (EFLAG) {
if (CTABLE || 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 (EVFLAG) ev_tally_tip4p(key,vlist,v,ecoul,alpha);
}
}
}
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
}
}
/* ----------------------------------------------------------------------
compute position xM of fictitious charge site for O atom and 2 H atoms
return it as xM
------------------------------------------------------------------------- */
void PairLJCutTIP4PLongOpt::compute_newsite_opt(const double * xO,
const double * xH1,
const double * xH2,
double * xM) const
{
double delx1 = xH1[0] - xO[0];
double dely1 = xH1[1] - xO[1];
double delz1 = xH1[2] - xO[2];
domain->minimum_image(delx1,dely1,delz1);
double delx2 = xH2[0] - xO[0];
double dely2 = xH2[1] - xO[1];
double delz2 = xH2[2] - xO[2];
domain->minimum_image(delx2,dely2,delz2);
const double prefac = alpha * 0.5;
xM[0] = xO[0] + prefac * (delx1 + delx2);
xM[1] = xO[1] + prefac * (dely1 + dely2);
xM[2] = xO[2] + prefac * (delz1 + delz2);
}
/* ---------------------------------------------------------------------- */
double PairLJCutTIP4PLongOpt::memory_usage()
{
double bytes = PairLJCutTIP4PLong::memory_usage();
return bytes;
}
diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp
index 28e7ff1db..c2791ce01 100644
--- a/src/PERI/atom_vec_peri.cpp
+++ b/src/PERI/atom_vec_peri.cpp
@@ -1,923 +1,921 @@
/* ----------------------------------------------------------------------
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 "float.h"
#include "stdlib.h"
#include "atom_vec_peri.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
static const char cite_peri_package[] =
"PERI package for Peridynamics:\n\n"
"@Article{Parks08,\n"
" author = {M. L. Parks, R. B. Lehoucq, S. J. Plimpton, S. A. Silling},\n"
" title = {Implementing peridynamics within a molecular dynamics code},\n"
" journal = {Comp.~Phys.~Comm.},\n"
" year = 2008,\n"
" volume = 179,\n"
" pages = {777--783}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
AtomVecPeri::AtomVecPeri(LAMMPS *lmp) : AtomVec(lmp)
{
if (lmp->citeme) lmp->citeme->add(cite_peri_package);
molecular = 0;
comm_x_only = 0;
comm_f_only = 1;
size_forward = 4;
size_reverse = 3;
size_border = 11;
size_velocity = 3;
size_data_atom = 7;
size_data_vel = 4;
xcol_data = 5;
atom->peri_flag = 1;
atom->vfrac_flag = atom->rmass_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecPeri::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
vfrac = memory->grow(atom->vfrac,nmax,"atom:vfrac");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
s0 = memory->grow(atom->s0,nmax,"atom:s0");
x0 = memory->grow(atom->x0,nmax,3,"atom:x0");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecPeri::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
vfrac = atom->vfrac; rmass = atom->rmass;
s0 = atom->s0; x0 = atom->x0;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecPeri::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
vfrac[j] = vfrac[i];
rmass[j] = rmass[i];
s0[j] = s0[i];
x0[j][0] = x0[i][0];
x0[j][1] = x0[i][1];
x0[j][2] = x0[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = s0[j];
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = s0[j];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = s0[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = s0[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = s0[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = s0[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecPeri::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
s0[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecPeri::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
s0[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
s0[i] = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecPeri::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[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];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[j][2];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[j][2];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = vfrac[j];
buf[m++] = s0[j];
buf[m++] = x0[j][0];
buf[m++] = x0[j][1];
buf[m++] = x0[j][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecPeri::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
vfrac[i] = buf[m++];
s0[i] = buf[m++];
x0[i][0] = buf[m++];
x0[i][1] = buf[m++];
x0[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecPeri::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
vfrac[i] = buf[m++];
s0[i] = buf[m++];
x0[i][0] = buf[m++];
x0[i][1] = buf[m++];
x0[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
vfrac[i] = buf[m++];
s0[i] = buf[m++];
x0[i][0] = buf[m++];
x0[i][1] = buf[m++];
x0[i][2] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecPeri::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = vfrac[i];
buf[m++] = rmass[i];
buf[m++] = s0[i];
buf[m++] = x0[i][0];
buf[m++] = x0[i][1];
buf[m++] = x0[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecPeri::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
vfrac[nlocal] = buf[m++];
rmass[nlocal] = buf[m++];
s0[nlocal] = buf[m++];
x0[nlocal][0] = buf[m++];
x0[nlocal][1] = buf[m++];
x0[nlocal][2] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecPeri::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 17 * nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecPeri::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = vfrac[i];
buf[m++] = rmass[i];
buf[m++] = s0[i];
buf[m++] = x0[i][0];
buf[m++] = x0[i][1];
buf[m++] = x0[i][2];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecPeri::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
vfrac[nlocal] = buf[m++];
rmass[nlocal] = buf[m++];
s0[nlocal] = buf[m++];
x0[nlocal][0] = buf[m++];
x0[nlocal][1] = buf[m++];
x0[nlocal][2] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecPeri::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
vfrac[nlocal] = 1.0;
rmass[nlocal] = 1.0;
s0[nlocal] = DBL_MAX;
x0[nlocal][0] = coord[0];
x0[nlocal][1] = coord[1];
x0[nlocal][2] = coord[2];
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecPeri::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
vfrac[nlocal] = atof(values[2]);
rmass[nlocal] = atof(values[3]);
if (rmass[nlocal] <= 0.0) error->one(FLERR,"Invalid mass value");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
s0[nlocal] = DBL_MAX;
x0[nlocal][0] = coord[0];
x0[nlocal][1] = coord[1];
x0[nlocal][2] = coord[2];
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecPeri::data_atom_hybrid(int nlocal, char **values)
{
vfrac[nlocal] = atof(values[0]);
rmass[nlocal] = atof(values[1]);
if (rmass[nlocal] <= 0.0) error->one(FLERR,"Invalid mass value");
s0[nlocal] = DBL_MAX;
x0[nlocal][0] = x[nlocal][0];
x0[nlocal][1] = x[nlocal][1];
x0[nlocal][2] = x[nlocal][2];
return 2;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecPeri::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = vfrac[i];
buf[i][3] = rmass[i];
buf[i][4] = x[i][0];
buf[i][5] = x[i][1];
buf[i][6] = x[i][2];
buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecPeri::pack_data_hybrid(int i, double *buf)
{
buf[0] = vfrac[i];
buf[1] = rmass[i];
return 2;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecPeri::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4],buf[i][5],buf[i][6],
(int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,
(int) ubuf(buf[i][9]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecPeri::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e",buf[0],buf[1]);
return 2;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecPeri::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("vfrac")) bytes += memory->usage(vfrac,nmax);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("s0")) bytes += memory->usage(s0,nmax);
if (atom->memcheck("x0")) bytes += memory->usage(x0,nmax,3);
return bytes;
}
diff --git a/src/PERI/atom_vec_peri.h b/src/PERI/atom_vec_peri.h
index 710f19ce1..d1ab76413 100644
--- a/src/PERI/atom_vec_peri.h
+++ b/src/PERI/atom_vec_peri.h
@@ -1,92 +1,93 @@
/* -*- 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 ATOM_CLASS
AtomStyle(peri,AtomVecPeri)
#else
#ifndef LMP_ATOM_VEC_PERI_H
#define LMP_ATOM_VEC_PERI_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecPeri : public AtomVec {
public:
AtomVecPeri(class LAMMPS *);
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *vfrac,*density,*rmass,*s0,**x0;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid mass value
Self-explanatory.
*/
diff --git a/src/PERI/compute_damage_atom.cpp b/src/PERI/compute_damage_atom.cpp
index bd8228faf..9b51cd34b 100644
--- a/src/PERI/compute_damage_atom.cpp
+++ b/src/PERI/compute_damage_atom.cpp
@@ -1,131 +1,131 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "compute_damage_atom.h"
#include "atom.h"
#include "update.h"
#include "modify.h"
#include "comm.h"
#include "force.h"
#include "pair_peri_pmb.h"
#include "fix_peri_neigh.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeDamageAtom::ComputeDamageAtom(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg != 3) error->all(FLERR,"Illegal compute damage/atom command");
peratom_flag = 1;
size_peratom_cols = 0;
nmax = 0;
damage = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeDamageAtom::~ComputeDamageAtom()
{
memory->destroy(damage);
}
/* ---------------------------------------------------------------------- */
void ComputeDamageAtom::init()
{
int count = 0;
for (int i = 0; i < modify->ncompute; i++)
if (strcmp(modify->compute[i]->style,"damage/peri") == 0) count++;
if (count > 1 && comm->me == 0)
error->warning(FLERR,"More than one compute damage/atom");
// find associated PERI_NEIGH fix that must exist
ifix_peri = -1;
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,"Compute damage/atom requires peridynamic potential");
}
/* ---------------------------------------------------------------------- */
void ComputeDamageAtom::compute_peratom()
{
invoked_peratom = update->ntimestep;
// grow damage array if necessary
if (atom->nlocal > nmax) {
memory->destroy(damage);
nmax = atom->nmax;
memory->create(damage,nmax,"damage/atom:damage");
vector_atom = damage;
}
// compute damage for each atom in group
int nlocal = atom->nlocal;
int *mask = atom->mask;
double *vfrac = atom->vfrac;
double *vinter = ((FixPeriNeigh *) modify->fix[ifix_peri])->vinter;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
int i,j,jj,jnum;
double damage_temp;
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
jnum = npartner[i];
damage_temp = 0.0;
for (jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
// look up local index of this partner particle
// skip if particle is "lost"
j = atom->map(partner[i][jj]);
if (j < 0) continue;
damage_temp += vfrac[j];
}
}
else damage_temp = vinter[i];
if (vinter[i] != 0.0) damage[i] = 1.0 - damage_temp/vinter[i];
else damage[i] = 0.0;
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputeDamageAtom::memory_usage()
{
double bytes = nmax * sizeof(double);
return bytes;
}
diff --git a/src/PERI/fix_peri_neigh.cpp b/src/PERI/fix_peri_neigh.cpp
index a7ef29414..cd6e3d5c8 100644
--- a/src/PERI/fix_peri_neigh.cpp
+++ b/src/PERI/fix_peri_neigh.cpp
@@ -1,597 +1,597 @@
/* ----------------------------------------------------------------------
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 "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 = 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;
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;
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(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((void *) this);
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;
}
/* ---------------------------------------------------------------------- */
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;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
// only build list of bonds on very first run
if (!first) return;
first = 0;
// invoke full neighbor list (will copy or build if necessary)
neighbor->build_one(list->index);
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(r0);
memory->destroy(npartner);
npartner = NULL;
partner = NULL;
deviatorextention = NULL;
deviatorBackextention = 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;
}
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;
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);
PairPeriPMB *pairpmb = static_cast<PairPeriPMB*>(anypair);
PairPeriVES *pairves = static_cast<PairPeriVES*>(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;
}
}
// 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(int);
bytes += nmax*maxpartner * sizeof(double);
if (isVES) {
bytes += nmax*maxpartner * sizeof(double);
bytes += nmax*maxpartner * 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");
}
memory->grow(r0,nmax,maxpartner,"peri_neigh:r0");
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];
}
r0[j][m] = r0[i][m];
}
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];
}
buf[m++] = r0[i][n];
}
if (isVES) buf[0] = m/4;
else buf[0] = m/2;
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<int> (buf[m++]);
+ partner[nlocal][n] = static_cast<tagint> (buf[m++]);
if (isVES) {
deviatorextention[nlocal][n] = buf[m++];
deviatorBackextention[nlocal][n] = buf[m++];
}
r0[nlocal][n] = buf[m++];
}
vinter[nlocal] = buf[m++];
wvolume[nlocal] = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
int FixPeriNeigh::pack_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 1;
}
/* ---------------------------------------------------------------------- */
void FixPeriNeigh::unpack_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 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];
}
buf[m++] = r0[i][n];
}
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<int> (extra[nlocal][m++]);
+ partner[nlocal][n] = static_cast<tagint> (extra[nlocal][m++]);
if (isVES) {
deviatorextention[nlocal][n] = extra[nlocal][m++];
deviatorBackextention[nlocal][n] = extra[nlocal][m++];
}
r0[nlocal][n] = 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;
return 2*maxpartner + 4;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixPeriNeigh::size_restart(int nlocal)
{
if (isVES) return 4*npartner[nlocal] + 4;
return 2*npartner[nlocal] + 4;
}
diff --git a/src/PERI/fix_peri_neigh.h b/src/PERI/fix_peri_neigh.h
index 70a50131e..cdde88c37 100644
--- a/src/PERI/fix_peri_neigh.h
+++ b/src/PERI/fix_peri_neigh.h
@@ -1,90 +1,90 @@
/* -*- 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 FIX_CLASS
FixStyle(PERI_NEIGH,FixPeriNeigh)
#else
#ifndef LMP_FIX_PERI_NEIGH_H
#define LMP_FIX_PERI_NEIGH_H
#include "fix.h"
namespace LAMMPS_NS {
class FixPeriNeigh : public Fix {
friend class PairPeriPMB;
friend class PairPeriPMBOMP;
friend class PairPeriLPS;
friend class PairPeriVES; //NEW
friend class PairPeriLPSOMP;
friend class ComputeDamageAtom;
public:
FixPeriNeigh(class LAMMPS *,int, char **);
virtual ~FixPeriNeigh();
int setmask();
void init();
void init_list(int, class NeighList *);
void setup(int);
void min_setup(int);
double memory_usage();
void grow_arrays(int);
void copy_arrays(int, int, int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
void write_restart(FILE *);
void restart(char *);
int pack_restart(int, double *);
void unpack_restart(int, int);
int size_restart(int);
int maxsize_restart();
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
protected:
int first; // flag for first time initialization
int maxpartner; // max # of peridynamic neighs for any atom
int *npartner; // # of neighbors for each atom
- int **partner; // neighs for each atom, stored as global IDs
+ tagint **partner; // neighs for each atom, stored as global IDs
double **deviatorextention; // Deviatoric extention
double **deviatorBackextention; // Deviatoric back extention
double **r0; // initial distance to partners
double **r1; // Instanteneous distance to partners *** NEW ***
double *thetaOld; // Dilatation Old one
double *vinter; // sum of vfrac for bonded neighbors
double *wvolume; // weighted volume of particle
int isPMB;
int isLPS;
int isVES;
class NeighList *list;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Duplicate particle in PeriDynamic bond - simulation box is too small
This is likely because your box length is shorter than 2 times
the bond length.
*/
diff --git a/src/PERI/pair_peri_lps.cpp b/src/PERI/pair_peri_lps.cpp
index a140c77e5..639ac6fb4 100644
--- a/src/PERI/pair_peri_lps.cpp
+++ b/src/PERI/pair_peri_lps.cpp
@@ -1,650 +1,650 @@
/* ----------------------------------------------------------------------
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"
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;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ 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]);
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 (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]) *
omega_plus*(deviatoric_extension * deviatoric_extension) *
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
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(arg[0],atom->ntypes,ilo,ihi);
force->bounds(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);
}
/* ----------------------------------------------------------------------
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;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ 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_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 1;
}
/* ---------------------------------------------------------------------- */
void PairPeriLPS::unpack_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_pmb.cpp b/src/PERI/pair_peri_pmb.cpp
index 439f4b5d0..77ca26d1e 100644
--- a/src/PERI/pair_peri_pmb.cpp
+++ b/src/PERI/pair_peri_pmb.cpp
@@ -1,509 +1,509 @@
/* ----------------------------------------------------------------------
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 "float.h"
#include "stdlib.h"
#include "string.h"
#include "pair_peri_pmb.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 "neigh_request.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairPeriPMB::PairPeriPMB(LAMMPS *lmp) : Pair(lmp)
{
for (int i = 0; i < 6; i++) virial[i] = 0.0;
no_virial_fdotr_compute=1;
ifix_peri = -1;
nmax = 0;
s0_new = NULL;
kspring = NULL;
s00 = NULL;
alpha = NULL;
cut = NULL;
}
/* ---------------------------------------------------------------------- */
PairPeriPMB::~PairPeriPMB()
{
if (ifix_peri >= 0) modify->delete_fix("PERI_NEIGH");
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(kspring);
memory->destroy(s00);
memory->destroy(alpha);
memory->destroy(cut);
memory->destroy(s0_new);
}
}
/* ---------------------------------------------------------------------- */
void PairPeriPMB::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 = 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;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
// 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;
rk = (15.0 * kspring[itype][jtype] * 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);
nmax = atom->nmax;
memory->create(s0_new,nmax,"pair:s0_new");
}
// 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;
for (i = 0; i < nlocal; i++) {
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jnum = npartner[i];
s0_new[i] = DBL_MAX;
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;
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;
stretch = dr / r0[i][jj];
rk = (kspring[itype][jtype] * vfrac[j]) * vfrac_scale * stretch;
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
if (eflag) evdwl = 0.5*rk*dr;
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
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 PairPeriPMB::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(kspring,n+1,n+1,"pair:kspring");
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 PairPeriPMB::settings(int narg, char **arg)
{
if (narg) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairPeriPMB::coeff(int narg, char **arg)
{
if (narg != 6) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
double kspring_one = force->numeric(FLERR,arg[2]);
double cut_one = force->numeric(FLERR,arg[3]);
double s00_one = force->numeric(FLERR,arg[4]);
double alpha_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++) {
kspring[i][j] = kspring_one;
s00[i][j] = s00_one;
alpha[i][j] = alpha_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 PairPeriPMB::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
kspring[j][i] = kspring[i][j];
alpha[j][i] = alpha[i][j];
s00[j][i] = s00[i][j];
cut[j][i] = cut[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairPeriPMB::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);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairPeriPMB::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(&kspring[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 PairPeriPMB::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(&kspring[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(&kspring[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);
}
}
}
/* ---------------------------------------------------------------------- */
double PairPeriPMB::single(int i, int j, int itype, int jtype, double rsq,
double factor_coul, double factor_lj,
double &fforce)
{
double delx0,dely0,delz0,rsq0;
double d_ij,r,dr,rk,vfrac_scale;
double *vfrac = atom->vfrac;
double **x0 = atom->x0;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ tagint **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
int *npartner = ((FixPeriNeigh *) modify->fix[ifix_peri])->npartner;
double lc = domain->lattice->xlattice;
double half_lc = 0.5*lc;
delx0 = x0[i][0] - x0[j][0];
dely0 = x0[i][1] - x0[j][1];
delz0 = x0[i][2] - x0[j][2];
int periodic = domain->xperiodic || domain->yperiodic || domain->zperiodic;
if (periodic) domain->minimum_image(delx0,dely0,delz0);
rsq0 = delx0*delx0 + dely0*dely0 + delz0*delz0;
d_ij = MIN(0.9*sqrt(rsq0),1.35*lc);
r = sqrt(rsq);
double energy = 0.0;
fforce = 0.0;
if (r < d_ij) {
dr = r - d_ij;
rk = (15.0 * kspring[itype][jtype] * vfrac[j]) *
(dr / sqrt(cutsq[itype][jtype]));
if (r > 0.0) fforce += -(rk/r);
energy += 0.5*rk*dr;
}
int jnum = npartner[i];
for (int jj = 0; jj < jnum; jj++) {
if (partner[i][jj] == 0) continue;
if (j < 0) continue;
if (j == atom->map(partner[i][jj])) {
dr = r - r0[i][jj];
if (fabs(dr) < 2.2204e-016) dr = 0.0;
if ( (fabs(r0[i][jj] - sqrt(cutsq[itype][jtype]))) <= half_lc)
vfrac_scale = (-1.0/(2*half_lc))*(r0[i][jj]) +
(1.0 + ((sqrt(cutsq[itype][jtype]) - half_lc)/(2*half_lc)));
else vfrac_scale = 1.0;
rk = (kspring[itype][jtype] * vfrac[j] * vfrac_scale) *
(dr / r0[i][jj]);
if (r > 0.0) fforce += -(rk/r);
energy += 0.5*rk*dr;
}
}
return energy;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairPeriPMB::memory_usage()
{
double bytes = nmax * sizeof(double);
return bytes;
}
diff --git a/src/PERI/pair_peri_ves.cpp b/src/PERI/pair_peri_ves.cpp
index 5586abc96..ec7852feb 100644
--- a/src/PERI/pair_peri_ves.cpp
+++ b/src/PERI/pair_peri_ves.cpp
@@ -1,724 +1,724 @@
/* ----------------------------------------------------------------------
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: Ezwanur Rahman, J.T. Foster (UTSA)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "pair_peri_ves.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;
/* ---------------------------------------------------------------------- */
PairPeriVES::PairPeriVES(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;
m_lambdai = NULL;
m_taubi = NULL;
// set comm size needed by this Pair
// comm_reverse not needed
comm_forward = 1;
}
/* ---------------------------------------------------------------------- */
PairPeriVES::~PairPeriVES()
{
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_lambdai);
memory->destroy(m_taubi);
memory->destroy(theta);
memory->destroy(s0_new);
}
}
/* ---------------------------------------------------------------------- */
void PairPeriVES::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,dr1,rk,evdwl,fpair,fbond;
double deltaed,fbondViscoElastic,fbondFinal;
double decay,betai,lambdai,edbNp1,rkNew;
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 timestepsize = update->dt;
double *vfrac = atom->vfrac;
double *s0 = atom->s0;
double **x0 = atom->x0;
double **r0 = ((FixPeriNeigh *) modify->fix[ifix_peri])->r0;
double **deviatorextention =
((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorextention;
double **deviatorBackextention =
((FixPeriNeigh *) modify->fix[ifix_peri])->deviatorBackextention;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ 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]);
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 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;
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]) * vfrac[j] * vfrac_scale *
( (omega_plus * theta[i] / wvolume[i]) +
( omega_minus * theta[j] / wvolume[j] ) ) ) * r0[i][jj];
if (r > 0.0) fbond = -(rk/r);
else fbond = 0.0;
// for viscoelasticity
lambdai=m_lambdai[itype][itype];
double taui = m_taubi[itype][itype];
double c1 = taui/timestepsize;
decay=exp(-1.0/c1);
betai=1.-c1*(1.-decay);
double deviatoric_extension =
dr - (theta[i]* r0[i][jj] / 3.0);
deltaed = deviatoric_extension-deviatorextention[i][jj];
// back extention at current step
edbNp1 = deviatorextention[i][jj]*(1-decay) +
deviatorBackextention[i][jj]*decay+betai*deltaed;
rkNew = ((1-lambdai)*15.0) *
( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) *
deviatoric_extension;
rkNew += (lambdai*15.0) *
( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) *
( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) *
(deviatoric_extension-edbNp1);
if (r > 0.0) fbondViscoElastic = -(rkNew/r);
else fbondViscoElastic = 0.0;
// total Force: elastic + viscoelastic
fbondFinal=fbond+fbondViscoElastic;
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 *
deviatoric_extension) +
(0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) *
omega_plus * (deviatoric_extension-edbNp1) *
(deviatoric_extension-edbNp1)) * 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
// store current deviatoric extention
deviatorextention[i][jj]=deviatoric_extension;
deviatorBackextention[i][jj]=edbNp1;
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 PairPeriVES::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_lambdai,n+1,n+1,"pair:m_lambdai");
memory->create(m_taubi,n+1,n+1,"pair:m_taubi");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairPeriVES::settings(int narg, char **arg)
{
if (narg) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairPeriVES::coeff(int narg, char **arg)
{
if (narg != 9) error->all(FLERR,"Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(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 mlambdai_one = atof(arg[7]);
double mtaui_one = atof(arg[8]);
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_lambdai[i][j] = mlambdai_one;
m_taubi[i][j] = mtaui_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 PairPeriVES::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_lambdai[j][i] = m_lambdai[i][j];
m_taubi[j][i] = m_taubi[i][j];
return cut[i][j];
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairPeriVES::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);
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairPeriVES::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_lambdai[i][j],sizeof(double),1,fp);
fwrite(&m_taubi[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairPeriVES::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_lambdai[i][j],sizeof(double),1,fp);
fread(&m_taubi[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_lambdai[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&m_taubi[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairPeriVES::memory_usage()
{
double bytes = 2 * nmax * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
influence function definition
------------------------------------------------------------------------- */
double PairPeriVES::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 PairPeriVES::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;
- int **partner = ((FixPeriNeigh *) modify->fix[ifix_peri])->partner;
+ 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 PairPeriVES::pack_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 1;
}
/* ---------------------------------------------------------------------- */
void PairPeriVES::unpack_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/POEMS/fix_poems.cpp b/src/POEMS/fix_poems.cpp
index 2c353da23..cb983c8fe 100644
--- a/src/POEMS/fix_poems.cpp
+++ b/src/POEMS/fix_poems.cpp
@@ -1,1606 +1,1609 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
FixPOEMS is a LAMMPS interface to the POEMS coupled multi-body simulator
POEMS authors: Rudranarayan Mukherjee (mukher@rpi.edu)
Kurt Anderson (anderk5@rpi.edu)
------------------------------------------------------------------------- */
#include "mpi.h"
#include "math.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "workspace.h"
#include "fix_poems.h"
#include "atom.h"
#include "domain.h"
#include "update.h"
#include "respa.h"
#include "modify.h"
#include "force.h"
#include "output.h"
#include "group.h"
#include "comm.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define MAXBODY 2 // currently 2 since only linear chains allowed
#define DELTA 128
#define TOLERANCE 1.0e-6
#define EPSILON 1.0e-7
#define MAXJACOBI 50
static const char cite_fix_poems[] =
"fix poems command:\n\n"
"@Article{Mukherjee08,\n"
" author = {R. M. Mukherjee, P. S. Crozier, S. J. Plimpton, K. S. Anderson},\n"
" title = {Substructured molecular dynamics using multibody dynamics algorithms},\n"
" journal = {Intl.~J.~Non-linear Mechanics},\n"
" year = 2008,\n"
" volume = 43,\n"
" pages = {1045--1055}\n"
"}\n\n";
/* ----------------------------------------------------------------------
define rigid bodies and joints, initiate POEMS
------------------------------------------------------------------------- */
FixPOEMS::FixPOEMS(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_poems);
int i,j,ibody;
time_integrate = 1;
rigid_flag = 1;
virial_flag = 1;
MPI_Comm_rank(world,&me);
// perform initial allocation of atom-based arrays
// register with atom class
natom2body = NULL;
atom2body = NULL;
displace = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
// initialize each atom to belong to no rigid bodies
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) natom2body[i] = 0;
// create an atom map if one doesn't exist already
// readfile() and jointbuild() use global atom IDs
int mapflag = 0;
if (atom->map_style == 0) {
mapflag = 1;
atom->map_style = 1;
atom->map_init();
atom->map_set();
}
// parse command-line args
// set natom2body, atom2body for all atoms and nbody = # of rigid bodies
// atoms must also be in fix group to be in a body
if (narg < 4) error->all(FLERR,"Illegal fix poems command");
// group = arg has list of groups
if (strcmp(arg[3],"group") == 0) {
nbody = narg-4;
if (nbody <= 0) error->all(FLERR,"Illegal fix poems command");
int *igroups = new int[nbody];
for (ibody = 0; ibody < nbody; ibody++) {
igroups[ibody] = group->find(arg[ibody+4]);
if (igroups[ibody] == -1)
error->all(FLERR,"Could not find fix poems group ID");
}
int *mask = atom->mask;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
for (ibody = 0; ibody < nbody; ibody++)
if (mask[i] & group->bitmask[igroups[ibody]]) {
if (natom2body[i] < MAXBODY) atom2body[i][natom2body[i]] = ibody;
natom2body[i]++;
}
}
delete [] igroups;
// file = read bodies from file
// file read doesn't pay attention to fix group,
// so after read, reset natom2body = 0 if atom is not in fix group
} else if (strcmp(arg[3],"file") == 0) {
readfile(arg[4]);
int *mask = atom->mask;
for (int i = 0; i < nlocal; i++)
if (!(mask[i] & groupbit)) natom2body[i] = 0;
// each molecule in fix group is a rigid body
// maxmol = largest molecule #
// ncount = # of atoms in each molecule (have to sum across procs)
// nbody = # of non-zero ncount values
// use nall as incremented ptr to set atom2body[] values for each atom
} else if (strcmp(arg[3],"molecule") == 0) {
if (narg != 4) error->all(FLERR,"Illegal fix poems command");
if (atom->molecular == 0)
error->all(FLERR,"Must use a molecular atom style with fix poems molecule");
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int maxmol = -1;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) maxmol = MAX(maxmol,molecule[i]);
int itmp;
MPI_Allreduce(&maxmol,&itmp,1,MPI_INT,MPI_MAX,world);
maxmol = itmp + 1;
int *ncount = new int[maxmol];
for (i = 0; i < maxmol; i++) ncount[i] = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) ncount[molecule[i]]++;
int *nall = new int[maxmol];
MPI_Allreduce(ncount,nall,maxmol,MPI_INT,MPI_SUM,world);
nbody = 0;
for (i = 0; i < maxmol; i++)
if (nall[i]) nall[i] = nbody++;
else nall[i] = -1;
for (i = 0; i < nlocal; i++) {
natom2body[i] = 0;
if (mask[i] & groupbit) {
natom2body[i] = 1;
atom2body[i][0] = nall[molecule[i]];
}
}
delete [] ncount;
delete [] nall;
} else error->all(FLERR,"Illegal fix poems command");
// error if no bodies
// error if any atom in too many bodies
if (nbody == 0) error->all(FLERR,"No rigid bodies defined");
int flag = 0;
for (int i = 0; i < nlocal; i++)
if (natom2body[i] > MAXBODY) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) error->all(FLERR,"Atom in too many rigid bodies - boost MAXBODY");
// create all nbody-length arrays
nrigid = new int[nbody];
masstotal = new double[nbody];
memory->create(xcm,nbody,3,"poems:xcm");
memory->create(vcm,nbody,3,"poems:vcm");
memory->create(fcm,nbody,3,"poems:fcm");
memory->create(inertia,nbody,3,"poems:inertia");
memory->create(ex_space,nbody,3,"poems:ex_space");
memory->create(ey_space,nbody,3,"poems:ey_space");
memory->create(ez_space,nbody,3,"poems:ez_space");
memory->create(angmom,nbody,3,"poems:angmom");
memory->create(omega,nbody,3,"poems:omega");
memory->create(torque,nbody,3,"poems:torque");
memory->create(sum,nbody,6,"poems:sum");
memory->create(all,nbody,6,"poems:all");
// nrigid[n] = # of atoms in Nth rigid body
// double count joint atoms as being in multiple bodies
// error if one or zero atoms
int *ncount = new int[nbody];
for (ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < natom2body[i]; j++)
ncount[atom2body[i][j]]++;
MPI_Allreduce(ncount,nrigid,nbody,MPI_INT,MPI_SUM,world);
delete [] ncount;
for (ibody = 0; ibody < nbody; ibody++)
if (nrigid[ibody] <= 1) error->all(FLERR,"One or zero atoms in rigid body");
// build list of joint connections and check for cycles and trees
jointbuild();
// delete temporary atom map
if (mapflag) {
atom->map_delete();
atom->map_style = 0;
}
// create POEMS instance
poems = new Workspace;
// print statistics
int nsum = 0;
for (ibody = 0; ibody < nbody; ibody++) nsum += nrigid[ibody];
nsum -= njoint;
if (me == 0) {
if (screen)
fprintf(screen,"%d clusters, %d bodies, %d joints, %d atoms\n",
ncluster,nbody,njoint,nsum);
if (logfile)
fprintf(logfile,"%d clusters, %d bodies, %d joints, %d atoms\n",
ncluster,nbody,njoint,nsum);
}
}
/* ----------------------------------------------------------------------
free all memory for rigid bodies, joints, and POEMS
------------------------------------------------------------------------- */
FixPOEMS::~FixPOEMS()
{
// if atom class still exists:
// unregister this fix so atom class doesn't invoke it any more
if (atom) atom->delete_callback(id,0);
// delete locally stored arrays
memory->destroy(natom2body);
memory->destroy(atom2body);
memory->destroy(displace);
// delete nbody-length arrays
delete [] nrigid;
delete [] masstotal;
memory->destroy(xcm);
memory->destroy(vcm);
memory->destroy(fcm);
memory->destroy(inertia);
memory->destroy(ex_space);
memory->destroy(ey_space);
memory->destroy(ez_space);
memory->destroy(angmom);
memory->destroy(omega);
memory->destroy(torque);
memory->destroy(sum);
memory->destroy(all);
// delete joint arrays
memory->destroy(jointbody);
memory->destroy(xjoint);
delete [] freelist;
// delete POEMS object
delete poems;
}
/* ---------------------------------------------------------------------- */
int FixPOEMS::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= FINAL_INTEGRATE;
mask |= PRE_NEIGHBOR;
mask |= POST_FORCE;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE_RESPA;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixPOEMS::init()
{
int i,ibody;
// warn if more than one POEMS fix
int count = 0;
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"poems") == 0) count++;
if (count > 1 && comm->me == 0) error->warning(FLERR,"More than one fix poems");
// error if npt,nph fix comes before rigid 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,"poems") == 0)
error->all(FLERR,"POEMS fix must come before NPT/NPH fix");
}
// timestep info
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
// rRESPA info
if (strstr(update->integrate_style,"respa")) {
step_respa = ((Respa *) update->integrate)->step;
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
// compute masstotal & center-of-mass xcm of each rigid body
// only count joint atoms in 1st body
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double **x = atom->x;
double **v = atom->v;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
int xbox,ybox,zbox;
double massone;
for (ibody = 0; ibody < nbody; ibody++)
for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
massone = mass[type[i]];
sum[ibody][0] += (x[i][0] + xbox*xprd) * massone;
sum[ibody][1] += (x[i][1] + ybox*yprd) * massone;
sum[ibody][2] += (x[i][2] + zbox*zprd) * massone;
sum[ibody][3] += massone;
sum[ibody][4] += massone *
(v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]);
}
}
MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
total_ke = 0.0;
for (ibody = 0; ibody < nbody; ibody++) {
masstotal[ibody] = all[ibody][3];
xcm[ibody][0] = all[ibody][0]/masstotal[ibody];
xcm[ibody][1] = all[ibody][1]/masstotal[ibody];
xcm[ibody][2] = all[ibody][2]/masstotal[ibody];
total_ke += 0.5 * all[ibody][4];
}
// compute 6 moments of inertia of each body
// only count joint atoms in 1st body
// dx,dy,dz = coords relative to center-of-mass
double dx,dy,dz;
for (ibody = 0; ibody < nbody; ibody++)
for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dx = x[i][0] + xbox*xprd - xcm[ibody][0];
dy = x[i][1] + ybox*yprd - xcm[ibody][1];
dz = x[i][2] + zbox*zprd - xcm[ibody][2];
massone = mass[type[i]];
sum[ibody][0] += massone * (dy*dy + dz*dz);
sum[ibody][1] += massone * (dx*dx + dz*dz);
sum[ibody][2] += massone * (dx*dx + dy*dy);
sum[ibody][3] -= massone * dx*dy;
sum[ibody][4] -= massone * dy*dz;
sum[ibody][5] -= massone * dx*dz;
}
}
MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
// inertia = 3 eigenvalues = principal moments of inertia
// ex_space,ey_space,ez_space = 3 eigenvectors = principal axes of rigid body
double **tensor,**evectors;
memory->create(tensor,3,3,"fix_rigid:tensor");
memory->create(evectors,3,3,"fix_rigid:evectors");
int ierror;
double ez0,ez1,ez2;
for (ibody = 0; ibody < nbody; ibody++) {
tensor[0][0] = all[ibody][0];
tensor[1][1] = all[ibody][1];
tensor[2][2] = all[ibody][2];
tensor[0][1] = tensor[1][0] = all[ibody][3];
tensor[1][2] = tensor[2][1] = all[ibody][4];
tensor[0][2] = tensor[2][0] = all[ibody][5];
ierror = jacobi(tensor,inertia[ibody],evectors);
if (ierror) error->all(FLERR,"Insufficient Jacobi rotations for POEMS body");
ex_space[ibody][0] = evectors[0][0];
ex_space[ibody][1] = evectors[1][0];
ex_space[ibody][2] = evectors[2][0];
ey_space[ibody][0] = evectors[0][1];
ey_space[ibody][1] = evectors[1][1];
ey_space[ibody][2] = evectors[2][1];
ez_space[ibody][0] = evectors[0][2];
ez_space[ibody][1] = evectors[1][2];
ez_space[ibody][2] = evectors[2][2];
// if any principal moment < scaled EPSILON, error
// this is b/c POEMS cannot yet handle degenerate bodies
double max;
max = MAX(inertia[ibody][0],inertia[ibody][1]);
max = MAX(max,inertia[ibody][2]);
if (inertia[ibody][0] < EPSILON*max ||
inertia[ibody][1] < EPSILON*max ||
inertia[ibody][2] < EPSILON*max)
error->all(FLERR,"Rigid body has degenerate moment of inertia");
// enforce 3 evectors as a right-handed coordinate system
// flip 3rd evector if needed
ez0 = ex_space[ibody][1]*ey_space[ibody][2] -
ex_space[ibody][2]*ey_space[ibody][1];
ez1 = ex_space[ibody][2]*ey_space[ibody][0] -
ex_space[ibody][0]*ey_space[ibody][2];
ez2 = ex_space[ibody][0]*ey_space[ibody][1] -
ex_space[ibody][1]*ey_space[ibody][0];
if (ez0*ez_space[ibody][0] + ez1*ez_space[ibody][1] +
ez2*ez_space[ibody][2] < 0.0) {
ez_space[ibody][0] = -ez_space[ibody][0];
ez_space[ibody][1] = -ez_space[ibody][1];
ez_space[ibody][2] = -ez_space[ibody][2];
}
}
// free temporary memory
memory->destroy(tensor);
memory->destroy(evectors);
// displace = initial atom coords in basis of principal axes
// only set joint atoms relative to 1st body
// set displace = 0.0 for atoms not in any rigid body
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dx = x[i][0] + xbox*xprd - xcm[ibody][0];
dy = x[i][1] + ybox*yprd - xcm[ibody][1];
dz = x[i][2] + zbox*zprd - xcm[ibody][2];
displace[i][0] = dx*ex_space[ibody][0] + dy*ex_space[ibody][1] +
dz*ex_space[ibody][2];
displace[i][1] = dx*ey_space[ibody][0] + dy*ey_space[ibody][1] +
dz*ey_space[ibody][2];
displace[i][2] = dx*ez_space[ibody][0] + dy*ez_space[ibody][1] +
dz*ez_space[ibody][2];
} else displace[i][0] = displace[i][1] = displace[i][2] = 0.0;
}
// test for valid principal moments & axes
// recompute moments of inertia around new axes
// only count joint atoms in 1st body
// 3 diagonal moments should equal principal moments
// 3 off-diagonal moments should be 0.0
// (ddx,ddy,ddz) is projection of atom within rigid body onto principal axes
// 6 moments use (ddx,ddy,ddz) displacements from principal axes
for (ibody = 0; ibody < nbody; ibody++)
for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
double ddx,ddy,ddz;
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dx = x[i][0] + xbox*xprd - xcm[ibody][0];
dy = x[i][1] + ybox*yprd - xcm[ibody][1];
dz = x[i][2] + zbox*zprd - xcm[ibody][2];
massone = mass[type[i]];
ddx = dx*ex_space[ibody][0] + dy*ex_space[ibody][1] +
dz*ex_space[ibody][2];
ddy = dx*ey_space[ibody][0] + dy*ey_space[ibody][1] +
dz*ey_space[ibody][2];
ddz = dx*ez_space[ibody][0] + dy*ez_space[ibody][1] +
dz*ez_space[ibody][2];
sum[ibody][0] += massone * (ddy*ddy + ddz*ddz);
sum[ibody][1] += massone * (ddx*ddx + ddz*ddz);
sum[ibody][2] += massone * (ddx*ddx + ddy*ddy);
sum[ibody][3] -= massone * ddx*ddy;
sum[ibody][4] -= massone * ddy*ddz;
sum[ibody][5] -= massone * ddx*ddz;
}
}
MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
for (ibody = 0; ibody < nbody; ibody++) {
if (fabs(all[ibody][0]-inertia[ibody][0]) > TOLERANCE ||
fabs(all[ibody][1]-inertia[ibody][1]) > TOLERANCE ||
fabs(all[ibody][2]-inertia[ibody][2]) > TOLERANCE)
error->all(FLERR,"Bad principal moments");
if (fabs(all[ibody][3]) > TOLERANCE ||
fabs(all[ibody][4]) > TOLERANCE ||
fabs(all[ibody][5]) > TOLERANCE)
error->all(FLERR,"Bad principal moments");
}
}
/* ----------------------------------------------------------------------
compute initial rigid body info
make setup call to POEMS
------------------------------------------------------------------------- */
void FixPOEMS::setup(int vflag)
{
int i,n,ibody;
// vcm = velocity of center-of-mass of each rigid body
// angmom = angular momentum of each rigid body
// only count joint atoms in 1st body
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double **x = atom->x;
double **v = atom->v;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
int xbox,ybox,zbox;
double massone,dx,dy,dz;
for (ibody = 0; ibody < nbody; ibody++)
for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
massone = mass[type[i]];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dx = x[i][0] + xbox*xprd - xcm[ibody][0];
dy = x[i][1] + ybox*yprd - xcm[ibody][1];
dz = x[i][2] + zbox*zprd - xcm[ibody][2];
sum[ibody][0] += v[i][0] * massone;
sum[ibody][1] += v[i][1] * massone;
sum[ibody][2] += v[i][2] * massone;
sum[ibody][3] += dy * massone*v[i][2] - dz * massone*v[i][1];
sum[ibody][4] += dz * massone*v[i][0] - dx * massone*v[i][2];
sum[ibody][5] += dx * massone*v[i][1] - dy * massone*v[i][0];
}
}
MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
for (ibody = 0; ibody < nbody; ibody++) {
vcm[ibody][0] = all[ibody][0]/masstotal[ibody];
vcm[ibody][1] = all[ibody][1]/masstotal[ibody];
vcm[ibody][2] = all[ibody][2]/masstotal[ibody];
angmom[ibody][0] = all[ibody][3];
angmom[ibody][1] = all[ibody][4];
angmom[ibody][2] = all[ibody][5];
}
// virial setup before call to set_v
if (vflag) v_setup(vflag);
else evflag = 0;
// set velocities from angmom & omega
for (ibody = 0; ibody < nbody; ibody++)
omega_from_mq(angmom[ibody],ex_space[ibody],ey_space[ibody],
ez_space[ibody],inertia[ibody],omega[ibody]);
set_v();
// guestimate virial as 2x the set_v contribution
if (vflag_global)
for (n = 0; n < 6; n++) virial[n] *= 2.0;
if (vflag_atom) {
for (i = 0; i < nlocal; i++)
for (n = 0; n < 6; n++)
vatom[i][n] *= 2.0;
}
// use post_force() to compute initial fcm & torque
post_force(vflag);
// setup for POEMS
poems->MakeSystem(nbody,masstotal,inertia,xcm,vcm,omega,
ex_space,ey_space,ez_space,
njoint,jointbody,xjoint,nfree,freelist,
dthalf,dtv,force->ftm2v,total_ke);
}
/* ----------------------------------------------------------------------
update vcm,omega by 1/2 step and xcm,orientation by full step
set x,v of body atoms accordingly
---------------------------------------------------------------------- */
void FixPOEMS::initial_integrate(int vflag)
{
// perform POEMS integration
poems->LobattoOne(xcm,vcm,omega,torque,fcm,ex_space,ey_space,ez_space);
// virial setup before call to set_xv
if (vflag) v_setup(vflag);
else evflag = 0;
// set coords and velocities of atoms in rigid bodies
set_xv();
}
/* ----------------------------------------------------------------------
compute fcm,torque on each rigid body
only count joint atoms in 1st body
------------------------------------------------------------------------- */
void FixPOEMS::post_force(int vflag)
{
int i,ibody;
int xbox,ybox,zbox;
double dx,dy,dz;
imageint *image = atom->image;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
for (ibody = 0; ibody < nbody; ibody++)
for (i = 0; i < 6; i++) sum[ibody][i] = 0.0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i]) {
ibody = atom2body[i][0];
sum[ibody][0] += f[i][0];
sum[ibody][1] += f[i][1];
sum[ibody][2] += f[i][2];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dx = x[i][0] + xbox*xprd - xcm[ibody][0];
dy = x[i][1] + ybox*yprd - xcm[ibody][1];
dz = x[i][2] + zbox*zprd - xcm[ibody][2];
sum[ibody][3] += dy*f[i][2] - dz*f[i][1];
sum[ibody][4] += dz*f[i][0] - dx*f[i][2];
sum[ibody][5] += dx*f[i][1] - dy*f[i][0];
}
}
MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world);
for (ibody = 0; ibody < nbody; ibody++) {
fcm[ibody][0] = all[ibody][0];
fcm[ibody][1] = all[ibody][1];
fcm[ibody][2] = all[ibody][2];
torque[ibody][0] = all[ibody][3];
torque[ibody][1] = all[ibody][4];
torque[ibody][2] = all[ibody][5];
}
}
/* ----------------------------------------------------------------------
update vcm,omega by last 1/2 step
set v of body atoms accordingly
------------------------------------------------------------------------- */
void FixPOEMS::final_integrate()
{
// perform POEMS integration
poems->LobattoTwo(vcm,omega,torque,fcm);
// set velocities of atoms in rigid bodies
// virial is already setup from initial_integrate
set_v();
}
/* ---------------------------------------------------------------------- */
void FixPOEMS::initial_integrate_respa(int vflag, int ilevel, int iloop)
{
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dthalf = 0.5 * step_respa[ilevel];
if (ilevel == 0) initial_integrate(vflag);
else final_integrate();
}
/* ---------------------------------------------------------------------- */
void FixPOEMS::post_force_respa(int vflag, int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixPOEMS::final_integrate_respa(int ilevel, int iloop)
{
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
final_integrate();
}
/* ----------------------------------------------------------------------
remap xcm of each rigid body back into periodic simulation box
done during pre_neighbor so will be after call to pbc()
and after fix_deform::pre_exchange() may have flipped box
if don't do this, then atoms of a body which drifts far away
from a triclinic box will be remapped back into box
with huge displacements when the box tilt changes via set_x()
NOTE: cannot do this by changing xcm of each body in cluster
or even 1st body in cluster
b/c POEMS library does not see xcm but only sets xcm
so remap needs to be coordinated with POEMS library
thus this routine does nothing for now
------------------------------------------------------------------------- */
void FixPOEMS::pre_neighbor() {}
/* ----------------------------------------------------------------------
count # of degrees-of-freedom removed by fix_poems for atoms in igroup
------------------------------------------------------------------------- */
int FixPOEMS::dof(int igroup)
{
int groupbit = group->bitmask[igroup];
// ncount = # of atoms in each rigid body that are also in group
// only count joint atoms as part of first body
int *mask = atom->mask;
int nlocal = atom->nlocal;
int *ncount = new int[nbody];
for (int ibody = 0; ibody < nbody; ibody++) ncount[ibody] = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
if (natom2body[i]) ncount[atom2body[i][0]]++;
int *nall = new int[nbody];
MPI_Allreduce(ncount,nall,nbody,MPI_INT,MPI_SUM,world);
// remove 3N - 6 dof for each rigid body if at least 2 atoms are in igroup
int n = 0;
for (int ibody = 0; ibody < nbody; ibody++)
if (nall[ibody] > 2) n += 3*nall[ibody] - 6;
// subtract 3 additional dof for each joint if atom is also in igroup
int m = 0;
for (int i = 0; i < nlocal; i++)
if (natom2body[i] > 1 && (mask[i] & groupbit)) m += 3*(natom2body[i]-1);
int mall;
MPI_Allreduce(&m,&mall,1,MPI_INT,MPI_SUM,world);
n += mall;
// delete local memory
delete [] ncount;
delete [] nall;
return n;
}
/* ----------------------------------------------------------------------
adjust xcm of each cluster due to box deformation
called by various fixes that change box size/shape
flag = 0/1 means map from box to lamda coords or vice versa
NOTE: cannot do this by changing xcm of each body in cluster
or even 1st body in cluster
b/c POEMS library does not see xcm but only sets xcm
so deform needs to be coordinated with POEMS library
thus this routine does nothing for now
------------------------------------------------------------------------- */
void FixPOEMS::deform(int flag) {}
/* ---------------------------------------------------------------------- */
void FixPOEMS::readfile(char *file)
{
FILE *fp;
if (me == 0) {
fp = fopen(file,"r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix poems file %s",file);
error->one(FLERR,str);
}
}
nbody = 0;
char *line = NULL;
int maxline = 0;
char *ptr;
int nlocal = atom->nlocal;
int i,id,nlen;
while (1) {
if (me == 0) nlen = readline(fp,&line,&maxline);
MPI_Bcast(&nlen,1,MPI_INT,0,world);
if (nlen == 0) break;
MPI_Bcast(line,nlen,MPI_CHAR,0,world);
ptr = strtok(line," ,\t\n\0");
if (ptr == NULL || ptr[0] == '#') continue;
ptr = strtok(NULL," ,\t\n\0");
while ((ptr = strtok(NULL," ,\t\n\0"))) {
id = atoi(ptr);
i = atom->map(id);
if (i < 0 || i >= nlocal) continue;
if (natom2body[i] < MAXBODY) atom2body[i][natom2body[i]] = nbody;
natom2body[i]++;
}
nbody++;
}
memory->destroy(line);
fclose(fp);
}
/* ---------------------------------------------------------------------- */
int FixPOEMS::readline(FILE *fp, char **pline, int *pmaxline)
{
int n = 0;
char *line = *pline;
int maxline = *pmaxline;
while (1) {
if (n+1 >= maxline) {
maxline += DELTA;
memory->grow(line,maxline,"fix_poems:line");
}
if (fgets(&line[n],maxline-n,fp) == NULL) {
n = 0;
break;
}
n = strlen(line);
if (n < maxline-1 || line[n-1] == '\n') break;
}
*pmaxline = maxline;
*pline = line;
return n;
}
/* ----------------------------------------------------------------------
build list of joints and error check for cycles and trees
------------------------------------------------------------------------- */
void FixPOEMS::jointbuild()
{
int i,j;
// convert atom2body into list of joint atoms on this proc
// mjoint = # of joint atoms in this proc
// an atom in N rigid bodies, infers N-1 joints between 1st body and others
// mylist = [0],[1] = 2 body indices, [2] = global ID of joint atom
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int mjoint = 0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i] <= 1) continue;
mjoint += natom2body[i]-1;
}
- int **mylist = NULL;
+ tagint **mylist = NULL;
if (mjoint) memory->create(mylist,mjoint,3,"poems:mylist");
mjoint = 0;
for (i = 0; i < nlocal; i++) {
if (natom2body[i] <= 1) continue;
for (j = 1; j < natom2body[i]; j++) {
mylist[mjoint][0] = atom2body[i][0];
mylist[mjoint][1] = atom2body[i][j];
mylist[mjoint][2] = tag[i];
mjoint++;
}
}
// jlist = mylist concatenated across all procs via MPI_Allgatherv
MPI_Allreduce(&mjoint,&njoint,1,MPI_INT,MPI_SUM,world);
- int **jlist = NULL;
+ tagint **jlist = NULL;
if (njoint) memory->create(jlist,njoint,3,"poems:jlist");
int nprocs;
MPI_Comm_size(world,&nprocs);
int *recvcounts = new int[nprocs];
int tmp = 3*mjoint;
MPI_Allgather(&tmp,1,MPI_INT,recvcounts,1,MPI_INT,world);
int *displs = new int[nprocs];
displs[0] = 0;
for (i = 1; i < nprocs; i++) displs[i] = displs[i-1] + recvcounts[i-1];
// allgather the local joint lists
// 2 versions in case mjoint is 0 on this proc
if (njoint) {
if (mjoint)
- MPI_Allgatherv(mylist[0],3*mjoint,MPI_INT,jlist[0],
- recvcounts,displs,MPI_INT,world);
+ MPI_Allgatherv(mylist[0],3*mjoint,MPI_LMP_TAGINT,jlist[0],
+ recvcounts,displs,MPI_LMP_TAGINT,world);
else
- MPI_Allgatherv(NULL,3*mjoint,MPI_INT,jlist[0],
- recvcounts,displs,MPI_INT,world);
+ MPI_Allgatherv(NULL,3*mjoint,MPI_LMP_TAGINT,jlist[0],
+ recvcounts,displs,MPI_LMP_TAGINT,world);
}
delete [] recvcounts;
delete [] displs;
// warning if no joints
if (njoint == 0 && me == 0)
- error->warning(FLERR,"No joints between rigid bodies, use fix rigid instead");
+ error->warning(FLERR,
+ "No joints between rigid bodies, use fix rigid instead");
// sort joint list in ascending order by body indices
// check for loops in joint connections between rigid bodies
// check for trees = same body in more than 2 joints
sortlist(njoint,jlist);
if (loopcheck(nbody,njoint,jlist))
error->all(FLERR,"Cyclic loop in joint connections");
int *bodyflag = new int[nbody];
for (i = 0; i < nbody; i++) bodyflag[i] = 0;
for (i = 0; i < njoint; i++) {
bodyflag[jlist[i][0]]++;
bodyflag[jlist[i][1]]++;
}
for (i = 0; i < nbody; i++)
- if (bodyflag[i] > 2) error->all(FLERR,"Tree structure in joint connections");
+ if (bodyflag[i] > 2)
+ error->all(FLERR,"Tree structure in joint connections");
delete [] bodyflag;
// allocate and setup joint arrays
// jointbody stores body indices from 1 to Nbody to pass to POEMS
// each proc sets myjoint if it owns joint atom
// MPI_Allreduce gives all procs the xjoint coords
jointbody = NULL;
xjoint = NULL;
double **myjoint = NULL;
if (njoint) {
memory->create(jointbody,njoint,2,"poems:jointbody");
memory->create(xjoint,njoint,3,"poems:xjoint");
memory->create(myjoint,njoint,3,"poems:myjoint");
}
double **x = atom->x;
for (i = 0; i < njoint; i++) {
jointbody[i][0] = jlist[i][0] + 1;
jointbody[i][1] = jlist[i][1] + 1;
j = atom->map(jlist[i][2]);
if (j >= 0 && j < nlocal) {
myjoint[i][0] = x[j][0];
myjoint[i][1] = x[j][1];
myjoint[i][2] = x[j][2];
} else myjoint[i][0] = myjoint[i][1] = myjoint[i][2] = 0.0;
}
if (njoint)
MPI_Allreduce(myjoint[0],xjoint[0],3*njoint,MPI_DOUBLE,MPI_SUM,world);
// compute freelist of nfree single unconnected bodies
// POEMS could do this itself
int *mark = new int[nbody];
for (i = 0; i < nbody; i++) mark[i] = 1;
for (i = 0; i < njoint; i++) {
mark[jointbody[i][0]-1] = 0;
mark[jointbody[i][1]-1] = 0;
}
nfree = 0;
for (i = 0; i < nbody; i++)
if (mark[i]) nfree++;
if (nfree) freelist = new int[nfree];
else freelist = NULL;
nfree = 0;
for (i = 0; i < nbody; i++)
if (mark[i]) freelist[nfree++] = i + 1;
delete [] mark;
// free memory local to this routine
memory->destroy(mylist);
memory->destroy(jlist);
memory->destroy(myjoint);
}
/* ----------------------------------------------------------------------
sort joint list (Numerical Recipes shell sort)
sort criterion: sort on 1st body, if equal sort on 2nd body
------------------------------------------------------------------------- */
-void FixPOEMS::sortlist(int n, int **list)
+void FixPOEMS::sortlist(int n, tagint **list)
{
- int i,j,v0,v1,v2,flag;
+ int i,j,flag;
+ tagint v0,v1,v2;
int inc = 1;
while (inc <= n) inc = 3*inc + 1;
do {
inc /= 3;
for (i = inc+1; i <= n; i++) {
v0 = list[i-1][0];
v1 = list[i-1][1];
v2 = list[i-1][2];
j = i;
flag = 0;
if (list[j-inc-1][0] > v0 ||
(list[j-inc-1][0] == v0 && list[j-inc-1][1] > v1)) flag = 1;
while (flag) {
list[j-1][0] = list[j-inc-1][0];
list[j-1][1] = list[j-inc-1][1];
list[j-1][2] = list[j-inc-1][2];
j -= inc;
if (j <= inc) break;
flag = 0;
if (list[j-inc-1][0] > v0 ||
(list[j-inc-1][0] == v0 && list[j-inc-1][1] > v1)) flag = 1;
}
list[j-1][0] = v0;
list[j-1][1] = v1;
list[j-1][2] = v2;
}
} while (inc > 1);
}
/* ----------------------------------------------------------------------
check for cycles in list of joint connections between rigid bodies
treat as graph: vertex = body, edge = joint between 2 bodies
------------------------------------------------------------------------- */
-int FixPOEMS::loopcheck(int nvert, int nedge, int **elist)
+int FixPOEMS::loopcheck(int nvert, int nedge, tagint **elist)
{
int i,j,k;
// ecount[i] = # of vertices connected to vertex i via edge
// elistfull[i][*] = list of vertices connected to vertex i
int *ecount = new int[nvert];
for (i = 0; i < nvert; i++) ecount[i] = 0;
for (i = 0; i < nedge; i++) {
ecount[elist[i][0]]++;
ecount[elist[i][1]]++;
}
int emax = 0;
for (i = 0; i < nvert; i++) emax = MAX(emax,ecount[i]);
int **elistfull;
memory->create(elistfull,nvert,emax,"poems:elistfull");
for (i = 0; i < nvert; i++) ecount[i] = 0;
for (i = 0; i < nedge; i++) {
elistfull[elist[i][0]][ecount[elist[i][0]]++] = elist[i][1];
elistfull[elist[i][1]][ecount[elist[i][1]]++] = elist[i][0];
}
// cycle detection algorithm
// mark = 0/1 marking of each vertex, all initially unmarked
// outer while loop:
// if all vertices are marked, no cycles, exit loop
// push an unmarked vertex on stack and mark it, parent is -1
// while stack is not empty:
// pop vertex I from stack
// loop over vertices J connected to I via edge
// if J is parent (vertex that pushed I on stack), skip it
// else if J is marked, a cycle is found, return 1
// else push J on stack and mark it, parent is I
// increment ncluster each time stack empties since that is new cluster
int *parent = new int[nvert];
int *mark = new int[nvert];
for (i = 0; i < nvert; i++) mark[i] = 0;
int nstack = 0;
int *stack = new int[nvert];
ncluster = 0;
while (1) {
for (i = 0; i < nvert; i++)
if (mark[i] == 0) break;
if (i == nvert) break;
stack[nstack++] = i;
mark[i] = 1;
parent[i] = -1;
while (nstack) {
i = stack[--nstack];
for (k = 0; k < ecount[i]; k++) {
j = elistfull[i][k];
if (j == parent[i]) continue;
if (mark[j]) return 1;
stack[nstack++] = j;
mark[j] = 1;
parent[j] = i;
}
}
ncluster++;
}
// free memory local to this routine
delete [] ecount;
memory->destroy(elistfull);
delete [] parent;
delete [] mark;
delete [] stack;
return 0;
}
/* ----------------------------------------------------------------------
compute evalues and evectors of 3x3 real symmetric matrix
based on Jacobi rotations
adapted from Numerical Recipes jacobi() function
------------------------------------------------------------------------- */
int FixPOEMS::jacobi(double **matrix, double *evalues, double **evectors)
{
int i,j,k;
double tresh,theta,tau,t,sm,s,h,g,c,b[3],z[3];
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) evectors[i][j] = 0.0;
evectors[i][i] = 1.0;
}
for (i = 0; i < 3; i++) {
b[i] = evalues[i] = matrix[i][i];
z[i] = 0.0;
}
for (int iter = 1; iter <= MAXJACOBI; iter++) {
sm = 0.0;
for (i = 0; i < 2; i++)
for (j = i+1; j < 3; j++)
sm += fabs(matrix[i][j]);
if (sm == 0.0) return 0;
if (iter < 4) tresh = 0.2*sm/(3*3);
else tresh = 0.0;
for (i = 0; i < 2; i++) {
for (j = i+1; j < 3; j++) {
g = 100.0*fabs(matrix[i][j]);
if (iter > 4 && fabs(evalues[i])+g == fabs(evalues[i])
&& fabs(evalues[j])+g == fabs(evalues[j]))
matrix[i][j] = 0.0;
else if (fabs(matrix[i][j]) > tresh) {
h = evalues[j]-evalues[i];
if (fabs(h)+g == fabs(h)) t = (matrix[i][j])/h;
else {
theta = 0.5*h/(matrix[i][j]);
t = 1.0/(fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0) t = -t;
}
c = 1.0/sqrt(1.0+t*t);
s = t*c;
tau = s/(1.0+c);
h = t*matrix[i][j];
z[i] -= h;
z[j] += h;
evalues[i] -= h;
evalues[j] += h;
matrix[i][j] = 0.0;
for (k = 0; k < i; k++) rotate(matrix,k,i,k,j,s,tau);
for (k = i+1; k < j; k++) rotate(matrix,i,k,k,j,s,tau);
for (k = j+1; k < 3; k++) rotate(matrix,i,k,j,k,s,tau);
for (k = 0; k < 3; k++) rotate(evectors,k,i,k,j,s,tau);
}
}
}
for (i = 0; i < 3; i++) {
evalues[i] = b[i] += z[i];
z[i] = 0.0;
}
}
return 1;
}
/* ----------------------------------------------------------------------
perform a single Jacobi rotation
------------------------------------------------------------------------- */
void FixPOEMS::rotate(double **matrix, int i, int j, int k, int l,
double s, double tau)
{
double g = matrix[i][j];
double h = matrix[k][l];
matrix[i][j] = g-s*(h+g*tau);
matrix[k][l] = h+s*(g-h*tau);
}
/* ----------------------------------------------------------------------
compute omega from angular momentum
w = omega = angular velocity in space frame
wbody = angular velocity in body frame
set wbody component to 0.0 if inertia component is 0.0
otherwise body can spin easily around that axis
project space-frame angular momentum onto body axes
and divide by principal moments
------------------------------------------------------------------------- */
void FixPOEMS::omega_from_mq(double *m, double *ex, double *ey, double *ez,
double *inertia, double *w)
{
double wbody[3];
if (inertia[0] == 0.0) wbody[0] = 0.0;
else wbody[0] = (m[0]*ex[0] + m[1]*ex[1] + m[2]*ex[2]) / inertia[0];
if (inertia[1] == 0.0) wbody[1] = 0.0;
else wbody[1] = (m[0]*ey[0] + m[1]*ey[1] + m[2]*ey[2]) / inertia[1];
if (inertia[2] == 0.0) wbody[2] = 0.0;
else wbody[2] = (m[0]*ez[0] + m[1]*ez[1] + m[2]*ez[2]) / inertia[2];
w[0] = wbody[0]*ex[0] + wbody[1]*ey[0] + wbody[2]*ez[0];
w[1] = wbody[0]*ex[1] + wbody[1]*ey[1] + wbody[2]*ez[1];
w[2] = wbody[0]*ex[2] + wbody[1]*ey[2] + wbody[2]*ez[2];
}
/* ----------------------------------------------------------------------
set space-frame coords and velocity of each atom in each rigid body
x = Q displace + Xcm, mapped back to periodic box
v = Vcm + (W cross (x - Xcm))
------------------------------------------------------------------------- */
void FixPOEMS::set_xv()
{
int ibody;
int xbox,ybox,zbox;
double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
double vr[6];
imageint *image = atom->image;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *mass = atom->mass;
int *type = atom->type;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
// set x and v of each atom
// only set joint atoms for 1st rigid body they belong to
for (int i = 0; i < nlocal; i++) {
if (natom2body[i] == 0) continue;
ibody = atom2body[i][0];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
// save old positions and velocities for virial
if (evflag) {
x0 = x[i][0] + xbox*xprd;
x1 = x[i][1] + ybox*yprd;
x2 = x[i][2] + zbox*zprd;
v0 = v[i][0];
v1 = v[i][1];
v2 = v[i][2];
}
// x = displacement from center-of-mass, based on body orientation
// v = vcm + omega around center-of-mass
x[i][0] = ex_space[ibody][0]*displace[i][0] +
ey_space[ibody][0]*displace[i][1] +
ez_space[ibody][0]*displace[i][2];
x[i][1] = ex_space[ibody][1]*displace[i][0] +
ey_space[ibody][1]*displace[i][1] +
ez_space[ibody][1]*displace[i][2];
x[i][2] = ex_space[ibody][2]*displace[i][0] +
ey_space[ibody][2]*displace[i][1] +
ez_space[ibody][2]*displace[i][2];
v[i][0] = omega[ibody][1]*x[i][2] - omega[ibody][2]*x[i][1] +
vcm[ibody][0];
v[i][1] = omega[ibody][2]*x[i][0] - omega[ibody][0]*x[i][2] +
vcm[ibody][1];
v[i][2] = omega[ibody][0]*x[i][1] - omega[ibody][1]*x[i][0] +
vcm[ibody][2];
// add center of mass to displacement
// map back into periodic box via xbox,ybox,zbox
x[i][0] += xcm[ibody][0] - xbox*xprd;
x[i][1] += xcm[ibody][1] - ybox*yprd;
x[i][2] += xcm[ibody][2] - zbox*zprd;
// virial = unwrapped coords dotted into body constraint force
// body constraint force = implied force due to v change minus f external
// assume f does not include forces internal to body
// 1/2 factor b/c final_integrate contributes other half
// assume per-atom contribution is due to constraint force on that atom
if (evflag) {
massone = mass[type[i]];
fc0 = massone*(v[i][0] - v0)/dtf - f[i][0];
fc1 = massone*(v[i][1] - v1)/dtf - f[i][1];
fc2 = massone*(v[i][2] - v2)/dtf - f[i][2];
vr[0] = 0.5*fc0*x0;
vr[1] = 0.5*fc1*x1;
vr[2] = 0.5*fc2*x2;
vr[3] = 0.5*fc1*x0;
vr[4] = 0.5*fc2*x0;
vr[5] = 0.5*fc2*x1;
v_tally(1,&i,1.0,vr);
}
}
}
/* ----------------------------------------------------------------------
set space-frame velocity of each atom in a rigid body
v = Vcm + (W cross (x - Xcm))
------------------------------------------------------------------------- */
void FixPOEMS::set_v()
{
int ibody;
int xbox,ybox,zbox;
double dx,dy,dz;
double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
double vr[6];
double *mass = atom->mass;
double **f = atom->f;
double **x = atom->x;
double **v = atom->v;
int *type = atom->type;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
// set v of each atom
// only set joint atoms for 1st rigid body they belong to
for (int i = 0; i < nlocal; i++) {
if (natom2body[i] == 0) continue;
ibody = atom2body[i][0];
dx = ex_space[ibody][0]*displace[i][0] +
ey_space[ibody][0]*displace[i][1] +
ez_space[ibody][0]*displace[i][2];
dy = ex_space[ibody][1]*displace[i][0] +
ey_space[ibody][1]*displace[i][1] +
ez_space[ibody][1]*displace[i][2];
dz = ex_space[ibody][2]*displace[i][0] +
ey_space[ibody][2]*displace[i][1] +
ez_space[ibody][2]*displace[i][2];
// save old velocities for virial
if (evflag) {
v0 = v[i][0];
v1 = v[i][1];
v2 = v[i][2];
}
v[i][0] = omega[ibody][1]*dz - omega[ibody][2]*dy + vcm[ibody][0];
v[i][1] = omega[ibody][2]*dx - omega[ibody][0]*dz + vcm[ibody][1];
v[i][2] = omega[ibody][0]*dy - omega[ibody][1]*dx + vcm[ibody][2];
// virial = unwrapped coords dotted into body constraint force
// body constraint force = implied force due to v change minus f external
// assume f does not include forces internal to body
// 1/2 factor b/c initial_integrate contributes other half
// assume per-atom contribution is due to constraint force on that atom
if (evflag) {
massone = mass[type[i]];
fc0 = massone*(v[i][0] - v0)/dtf - f[i][0];
fc1 = massone*(v[i][1] - v1)/dtf - f[i][1];
fc2 = massone*(v[i][2] - v2)/dtf - f[i][2];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
x0 = x[i][0] + xbox*xprd;
x1 = x[i][1] + ybox*yprd;
x2 = x[i][2] + zbox*zprd;
vr[0] = 0.5*fc0*x0;
vr[1] = 0.5*fc1*x1;
vr[2] = 0.5*fc2*x2;
vr[3] = 0.5*fc1*x0;
vr[4] = 0.5*fc2*x0;
vr[5] = 0.5*fc2*x1;
v_tally(1,&i,1.0,vr);
}
}
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixPOEMS::grow_arrays(int nmax)
{
memory->grow(natom2body,nmax,"fix_poems:natom2body");
memory->grow(atom2body,nmax,MAXBODY,"fix_poems:atom2body");
memory->grow(displace,nmax,3,"fix_poems:displace");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixPOEMS::copy_arrays(int i, int j, int delflag)
{
natom2body[j] = natom2body[i];
for (int k = 0; k < natom2body[j]; k++) atom2body[j][k] = atom2body[i][k];
displace[j][0] = displace[i][0];
displace[j][1] = displace[i][1];
displace[j][2] = displace[i][2];
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixPOEMS::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax * sizeof(int);
bytes += nmax*MAXBODY * sizeof(int);
bytes += nmax*3 * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixPOEMS::pack_exchange(int i, double *buf)
{
int m = 0;
buf[m++] = static_cast<double> (natom2body[i]);
for (int j = 0; j < natom2body[i]; j++)
buf[m++] = static_cast<double> (atom2body[i][j]);
buf[m++] = displace[i][0];
buf[m++] = displace[i][1];
buf[m++] = displace[i][2];
return m;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixPOEMS::unpack_exchange(int nlocal, double *buf)
{
int m = 0;
natom2body[nlocal] = static_cast<int> (buf[m++]);
for (int i = 0; i < natom2body[nlocal]; i++)
atom2body[nlocal][i] = static_cast<int> (buf[m++]);
displace[nlocal][0] = buf[m++];
displace[nlocal][1] = buf[m++];
displace[nlocal][2] = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
void FixPOEMS::reset_dt()
{
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dthalf = 0.5 * update->dt;
}
diff --git a/src/POEMS/fix_poems.h b/src/POEMS/fix_poems.h
index 240650ac9..485cb800f 100644
--- a/src/POEMS/fix_poems.h
+++ b/src/POEMS/fix_poems.h
@@ -1,193 +1,193 @@
/* -*- 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 FIX_CLASS
FixStyle(poems,FixPOEMS)
#else
#ifndef LMP_FIX_POEMS_H
#define LMP_FIX_POEMS_H
#include "fix.h"
namespace LAMMPS_NS {
class FixPOEMS : public Fix {
public:
FixPOEMS(class LAMMPS *, int narg, char **arg);
~FixPOEMS();
int setmask();
void init();
void setup(int);
void initial_integrate(int);
void post_force(int);
void final_integrate();
void initial_integrate_respa(int, int, int);
void post_force_respa(int, int, int);
void final_integrate_respa(int, int);
void grow_arrays(int);
void copy_arrays(int, int, int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
double memory_usage();
void pre_neighbor();
int dof(int);
void deform(int);
void reset_dt();
private:
int me;
double dtv,dtf,dthalf;
double *step_respa;
int nlevels_respa;
double total_ke;
// atom assignment to rigid bodies
// double count joint atoms as being in multiple bodies
int *natom2body; // # of bodies each atom is part of
int **atom2body; // list of bodies each atom is part of
double **displace; // atom displace in body coords for 1st body it's in
// rigid body properties
// only nrigid double counts joint atoms as being in multiple bodies
// other quantities only count a joint atom as being in 1st body
int nbody; // # of rigid bodies
int *nrigid; // # of atoms in each rigid body
double *masstotal; // total mass of each rigid body
double **xcm; // coords of center-of-mass of each rigid body
double **vcm; // velocity of center-of-mass of each
double **fcm; // force on center-of-mass of each
double **inertia; // 6 inertia components of each (xx,yy,zz,xy,yz,xz)
double **ex_space,**ey_space,**ez_space;
// orientation of each body in space coords
double **angmom; // angular momentum of each in space coords
double **omega; // angular velocity of each in space coords
double **torque; // torque on each rigid body in space coords
double **sum,**all; // work vectors
// joint attributes between pairs of rigid bodies
int ncluster; // # of independent clusters of coupled bodies
int njoint; // # of interbody joints
int **jointbody; // indices of 2 rigid bodies in each joint (1-N)
double **xjoint; // coords of each joint point
int nfree; // # of isolated unconnected bodies
int *freelist; // indices of isolated bodies (1-N)
// POEMS object
class Workspace *poems;
// internal class functions
void readfile(char *);
int readline(FILE *, char **, int *);
void jointbuild();
- void sortlist(int, int **);
- int loopcheck(int, int, int **);
+ void sortlist(int, tagint **);
+ int loopcheck(int, int, tagint **);
int jacobi(double **, double *, double **);
void rotate(double **, int, int, int, int, double, double);
void omega_from_mq(double *, double *, double *, double *,
double *, double *);
void set_v();
void set_xv();
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Could not find fix poems group ID
A group ID used in the fix poems command does not exist.
E: Must use a molecular atom style with fix poems molecule
Self-explanatory.
E: No rigid bodies defined
The fix specification did not end up defining any rigid bodies.
E: Atom in too many rigid bodies - boost MAXBODY
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.
E: One or zero atoms in rigid body
Any rigid body defined by the fix rigid command must contain 2 or more
atoms.
W: More than one fix poems
It is not efficient to use fix poems more than once.
E: POEMS fix must come before NPT/NPH fix
NPT/NPH fix must be defined in input script after all poems fixes,
else the fix contribution to the pressure virial is incorrect.
E: Insufficient Jacobi rotations for POEMS body
Eigensolve for rigid body was not sufficiently accurate.
E: Rigid body has degenerate moment of inertia
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.
E: Bad principal moments
Fix rigid did not compute the principal moments of inertia of a rigid
group of atoms correctly.
E: Cannot open fix poems file %s
The specified file cannot be opened. Check that the path and name are
correct.
W: No joints between rigid bodies, use fix rigid instead
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.
E: Cyclic loop in joint connections
Fix poems cannot (yet) work with coupled bodies whose joints connect
the bodies in a ring (or cycle).
E: Tree structure in joint connections
Fix poems cannot (yet) work with coupled bodies whose joints connect
the bodies in a tree structure.
*/
diff --git a/src/REAX/fix_reax_bonds.cpp b/src/REAX/fix_reax_bonds.cpp
index 3e505c8d6..fd7a25432 100644
--- a/src/REAX/fix_reax_bonds.cpp
+++ b/src/REAX/fix_reax_bonds.cpp
@@ -1,253 +1,257 @@
/* ----------------------------------------------------------------------
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: Aidan Thompson (Sandia)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG is not supported by the REAX package
+#endif
+
#include "stdlib.h"
#include "string.h"
#include "fix_reax_bonds.h"
#include "pair_reax_fortran.h"
#include "atom.h"
#include "update.h"
#include "force.h"
#include "modify.h"
#include "compute.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixReaxBonds::FixReaxBonds(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 5) error->all(FLERR,"Illegal fix reax/bonds command");
MPI_Comm_rank(world,&me);
nevery = force->inumeric(FLERR,arg[3]);
if (nevery < 1) error->all(FLERR,"Illegal fix reax/bonds command");
if (me == 0) {
fp = fopen(arg[4],"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix reax/bonds file %s",arg[4]);
error->one(FLERR,str);
}
}
}
/* ---------------------------------------------------------------------- */
FixReaxBonds::~FixReaxBonds()
{
if (me == 0) fclose(fp);
}
/* ---------------------------------------------------------------------- */
int FixReaxBonds::setmask()
{
int mask = 0;
mask |= END_OF_STEP;
return mask;
}
/* ----------------------------------------------------------------------
perform initial write
------------------------------------------------------------------------- */
void FixReaxBonds::setup(int vflag)
{
end_of_step();
}
/* ---------------------------------------------------------------------- */
void FixReaxBonds::init()
{
// insure ReaxFF is defined
if (force->pair_match("reax",1) == NULL)
error->all(FLERR,"Cannot use fix reax/bonds without pair_style reax");
}
/* ---------------------------------------------------------------------- */
void FixReaxBonds::end_of_step()
{
OutputReaxBonds(update->ntimestep,fp);
if (me == 0) fflush(fp);
}
/* ---------------------------------------------------------------------- */
void FixReaxBonds::OutputReaxBonds(bigint ntimestep, FILE *fp)
{
int nparticles,nparticles_tot,nbuf,nbuf_local,most,j;
int ii,jn,mbond,numbonds,nsbmax,nsbmax_most;
int nprocs,nlocal_tmp,itmp;
int k,kk,jj,jbufknum;
double cutof3;
double *buf;
MPI_Request irequest;
MPI_Status istatus;
MPI_Comm_size(world,&nprocs);
nparticles = atom->nlocal;
nparticles_tot = static_cast<int> (atom->natoms);
jn = ReaxParams::nat;
mbond = ReaxParams::mbond;
FORTRAN(getnsbmax,GETNSBMAX)(&nsbmax);
FORTRAN(getcutof3,GETCUTOF3)(&cutof3);
MPI_Allreduce(&nparticles,&most,1,MPI_INT,MPI_MAX,world);
MPI_Allreduce(&nsbmax,&nsbmax_most,1,MPI_INT,MPI_MAX,world);
if (me == 0) {
fprintf(fp,"# Timestep " BIGINT_FORMAT " \n",ntimestep);
fprintf(fp,"# \n");
fprintf(fp,"# Number of particles %d \n",nparticles_tot);
fprintf(fp,"# \n");
fprintf(fp,"# Max number of bonds per atom %d with "
"coarse bond order cutoff %5.3f \n",
nsbmax_most,cutof3);
fprintf(fp,"# Particle connection table and bond orders \n");
fprintf(fp,"# id type nb id_1...id_nb mol bo_1...bo_nb abo nlp q \n");
}
// allocate a temporary buffer for the snapshot info
// big enough for largest number of atoms on any one proc
// nbuf_local = size of local buffer for table of atom bonds
nbuf = 1+(2*nsbmax_most+7)*most;
memory->create(buf,nbuf,"reax/bonds:buf");
j = 0;
buf[j++] = nparticles;
for (int iparticle=0;iparticle<nparticles;iparticle++) {
buf[j++] = atom->tag[iparticle]; //atom tag
buf[j++] = FORTRAN(cbkia,CBKIA).iag[iparticle]; //atom type
jbufknum = j++;
numbonds = FORTRAN(cbkia,CBKIA).iag[iparticle+jn];
// connection table based on coarse bond order cutoff (> cutof3)
kk = 0;
for (k=0;k<numbonds;k++) {
ii = FORTRAN(cbknubon2,CBKNUBON2).nubon1[iparticle+jn*k];
if (FORTRAN(cbkbo,CBKBO).bo[ii-1] > cutof3) {
kk++;
jj = FORTRAN(cbkia,CBKIA).iag[iparticle+jn*(k+2)];
buf[j++] = FORTRAN(cbkc,CBKC).itag[jj-1];
}
}
buf[jbufknum] = kk; //no.bonds
buf[j++]=FORTRAN(cbkia,CBKIA).iag[iparticle+jn*(mbond+2)]; //molec.id
// bond orders (> cutof3)
kk = 0;
for (k=0;k<numbonds;k++) {
ii = FORTRAN(cbknubon2,CBKNUBON2).nubon1[iparticle+jn*k];
if (FORTRAN(cbkbo,CBKBO).bo[ii-1] > cutof3) {
kk++;
buf[j++] = FORTRAN(cbkbo,CBKBO).bo[ii-1];
}
}
// atom bond order (abo), no. of lone pairs (vlp), charge (ch)
buf[j++] = FORTRAN(cbkabo,CBKABO).abo[iparticle];
buf[j++] = FORTRAN(cbklonpar,CBKLONPAR).vlp[iparticle];
buf[j++] = atom->q[iparticle];
}
nbuf_local = j-1;
// node 0 pings each node, receives their buffer, writes to file
// all other nodes wait for ping, send buffer to node 0
if (me == 0) {
for (int inode = 0; inode<nprocs; inode++) {
j = 0;
if (inode == 0) {
nlocal_tmp = nparticles;
j++;
} else {
MPI_Irecv(&buf[0],nbuf,MPI_DOUBLE,inode,0,world,&irequest);
MPI_Send(&itmp,0,MPI_INT,inode,0,world);
MPI_Wait(&irequest,&istatus);
nlocal_tmp = nint(buf[j++]);
}
for (int iparticle=0;iparticle<nlocal_tmp;iparticle++) {
// print atom tag, atom type, no.bonds
numbonds = nint(buf[j+2]);
fprintf(fp," %d %d %d",nint(buf[j]),nint(buf[j+1]),numbonds);
j += 3;
if (numbonds > nsbmax_most) {
char str[128];
sprintf(str,"Fix reax/bonds numbonds > nsbmax_most");
error->one(FLERR,str);
}
// print connection table
for (k=0;k<numbonds;k++)
fprintf(fp," %d",nint(buf[j++]));
// print molecule id
fprintf(fp," %d",nint(buf[j++]));
// print bond orders
for (k=0;k<numbonds;k++)
fprintf(fp,"%14.3f",buf[j++]);
// print sum of bond orders, no. of lone pairs, charge
fprintf(fp,"%14.3f%14.3f%14.3f\n",buf[j],buf[j+1],buf[j+2]);
j+=3;
}
}
} else {
MPI_Recv(&itmp,0,MPI_INT,0,0,world,&istatus);
MPI_Rsend(&buf[0],nbuf_local,MPI_DOUBLE,0,0,world);
}
if (me == 0) fprintf(fp,"# \n");
memory->destroy(buf);
}
/* ---------------------------------------------------------------------- */
int FixReaxBonds::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;
}
diff --git a/src/REPLICA/neb.cpp b/src/REPLICA/neb.cpp
index cbe92d81b..f1f501872 100644
--- a/src/REPLICA/neb.cpp
+++ b/src/REPLICA/neb.cpp
@@ -1,612 +1,612 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "neb.h"
#include "universe.h"
#include "atom.h"
#include "update.h"
#include "domain.h"
#include "comm.h"
#include "min.h"
#include "modify.h"
#include "fix.h"
#include "fix_neb.h"
#include "output.h"
#include "thermo.h"
#include "finish.h"
#include "timer.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
#define MAXLINE 256
#define CHUNK 1024
#define ATTRIBUTE_PERLINE 4
/* ---------------------------------------------------------------------- */
NEB::NEB(LAMMPS *lmp) : Pointers(lmp) {}
/* ----------------------------------------------------------------------
internal NEB constructor, called from TAD
------------------------------------------------------------------------- */
NEB::NEB(LAMMPS *lmp, double etol_in, double ftol_in, int n1steps_in,
int n2steps_in, int nevery_in, double *buf_init, double *buf_final)
: Pointers(lmp)
{
double delx,dely,delz;
etol = etol_in;
ftol = ftol_in;
n1steps = n1steps_in;
n2steps = n2steps_in;
nevery = nevery_in;
// replica info
nreplica = universe->nworlds;
ireplica = universe->iworld;
me_universe = universe->me;
uworld = universe->uworld;
MPI_Comm_rank(world,&me);
// generate linear interpolate replica
double fraction = ireplica/(nreplica-1.0);
double **x = atom->x;
int nlocal = atom->nlocal;
int ii = 0;
for (int i = 0; i < nlocal; i++) {
delx = buf_final[ii] - buf_init[ii];
dely = buf_final[ii+1] - buf_init[ii+1];
delz = buf_final[ii+2] - buf_init[ii+2];
domain->minimum_image(delx,dely,delz);
x[i][0] = buf_init[ii] + fraction*delx;
x[i][1] = buf_init[ii+1] + fraction*dely;
x[i][2] = buf_init[ii+2] + fraction*delz;
ii += 3;
}
}
/* ---------------------------------------------------------------------- */
NEB::~NEB()
{
MPI_Comm_free(&roots);
memory->destroy(all);
delete [] rdist;
}
/* ----------------------------------------------------------------------
perform NEB on multiple replicas
------------------------------------------------------------------------- */
void NEB::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"NEB command before simulation box is defined");
if (narg < 6) error->universe_all(FLERR,"Illegal NEB command");
etol = force->numeric(FLERR,arg[0]);
ftol = force->numeric(FLERR,arg[1]);
n1steps = force->inumeric(FLERR,arg[2]);
n2steps = force->inumeric(FLERR,arg[3]);
nevery = force->inumeric(FLERR,arg[4]);
// error checks
if (etol < 0.0) error->all(FLERR,"Illegal NEB command");
if (ftol < 0.0) error->all(FLERR,"Illegal NEB command");
if (nevery == 0) error->universe_all(FLERR,"Illegal NEB command");
if (n1steps % nevery || n2steps % nevery)
error->universe_all(FLERR,"Illegal NEB command");
// replica info
nreplica = universe->nworlds;
ireplica = universe->iworld;
me_universe = universe->me;
uworld = universe->uworld;
MPI_Comm_rank(world,&me);
// error checks
if (nreplica == 1) error->all(FLERR,"Cannot use NEB with a single replica");
if (nreplica != universe->nprocs)
error->all(FLERR,"Can only use NEB with 1-processor replicas");
if (atom->sortfreq > 0)
error->all(FLERR,"Cannot use NEB with atom_modify sort enabled");
if (atom->map_style == 0)
error->all(FLERR,"Cannot use NEB unless atom map exists");
// process file-style setting to setup initial configs for all replicas
if (strcmp(arg[5],"final") == 0) {
if (narg != 7) error->universe_all(FLERR,"Illegal NEB command");
infile = arg[6];
readfile(infile,0);
} else if (strcmp(arg[5],"each") == 0) {
if (narg != 7) error->universe_all(FLERR,"Illegal NEB command");
infile = arg[6];
readfile(infile,1);
} else if (strcmp(arg[5],"none") == 0) {
if (narg != 6) error->universe_all(FLERR,"Illegal NEB command");
} else error->universe_all(FLERR,"Illegal NEB command");
// run the NEB calculation
run();
}
/* ----------------------------------------------------------------------
run NEB on multiple replicas
------------------------------------------------------------------------- */
void NEB::run()
{
// create MPI communicator for root proc from each world
int color;
if (me == 0) color = 0;
else color = 1;
MPI_Comm_split(uworld,color,0,&roots);
int ineb;
for (ineb = 0; ineb < modify->nfix; ineb++)
if (strcmp(modify->fix[ineb]->style,"neb") == 0) break;
if (ineb == modify->nfix) error->all(FLERR,"NEB requires use of fix neb");
fneb = (FixNEB *) modify->fix[ineb];
nall = 4;
memory->create(all,nreplica,nall,"neb:all");
rdist = new double[nreplica];
// initialize LAMMPS
update->whichflag = 2;
update->etol = etol;
update->ftol = ftol;
update->multireplica = 1;
lmp->init();
if (update->minimize->searchflag)
error->all(FLERR,"NEB requires damped dynamics minimizer");
// setup regular NEB minimization
if (me_universe == 0 && universe->uscreen)
fprintf(universe->uscreen,"Setting up regular NEB ...\n");
update->beginstep = update->firststep = update->ntimestep;
update->endstep = update->laststep = update->firststep + n1steps;
update->nsteps = n1steps;
update->max_eval = n1steps;
if (update->laststep < 0 || update->laststep > MAXBIGINT)
error->all(FLERR,"Too many timesteps for NEB");
update->minimize->setup();
if (me_universe == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce "
"GradV0 GradV1 GradVc "
"EBF EBR RDT "
"RD1 PE1 RD2 PE2 ... RDN PEN\n");
if (universe->ulogfile)
fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce "
"GradV0 GradV1 GradVc "
"EBF EBR RDT "
"RD1 PE1 RD2 PE2 ... RDN PEN\n");
}
print_status();
// perform regular NEB for n1steps or until replicas converge
// retrieve PE values from fix NEB and print every nevery iterations
// break induced if converged
// damped dynamic min styles insure all replicas converge together
timer->init();
timer->barrier_start();
while (update->minimize->niter < n1steps) {
update->minimize->run(nevery);
print_status();
if (update->minimize->stop_condition) break;
}
timer->barrier_stop();
update->minimize->cleanup();
Finish finish(lmp);
finish.end(1);
// switch fix NEB to climbing mode
// top = replica that becomes hill climber
double vmax = all[0][0];
int top = 0;
for (int m = 1; m < nreplica; m++)
if (vmax < all[m][0]) {
vmax = all[m][0];
top = m;
}
// setup climbing NEB minimization
// must reinitialize minimizer so it re-creates its fix MINIMIZE
if (me_universe == 0 && universe->uscreen)
fprintf(universe->uscreen,"Setting up climbing ...\n");
if (me_universe == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,"Climbing replica = %d\n",top+1);
if (universe->ulogfile)
fprintf(universe->ulogfile,"Climbing replica = %d\n",top+1);
}
update->beginstep = update->firststep = update->ntimestep;
update->endstep = update->laststep = update->firststep + n2steps;
update->nsteps = n2steps;
update->max_eval = n2steps;
if (update->laststep < 0 || update->laststep > MAXBIGINT)
error->all(FLERR,"Too many timesteps");
update->minimize->init();
fneb->rclimber = top;
update->minimize->setup();
if (me_universe == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,"Step MaxReplicaForce MaxAtomForce "
"GradV0 GradV1 GradVc "
"EBF EBR RDT "
"RD1 PE1 RD2 PE2 ... RDN PEN\n");
if (universe->ulogfile)
fprintf(universe->ulogfile,"Step MaxReplicaForce MaxAtomForce "
"GradV0 GradV1 GradVc "
"EBF EBR RDT "
"RD1 PE1 RD2 PE2 ... RDN PEN\n");
}
print_status();
// perform climbing NEB for n2steps or until replicas converge
// retrieve PE values from fix NEB and print every nevery iterations
// break induced if converged
// damped dynamic min styles insure all replicas converge together
timer->init();
timer->barrier_start();
while (update->minimize->niter < n2steps) {
update->minimize->run(nevery);
print_status();
if (update->minimize->stop_condition) break;
}
timer->barrier_stop();
update->minimize->cleanup();
finish.end(1);
update->whichflag = 0;
update->multireplica = 0;
update->firststep = update->laststep = 0;
update->beginstep = update->endstep = 0;
}
/* ----------------------------------------------------------------------
read initial config atom coords from file
flag = 0
only first replica opens file and reads it
first replica bcasts lines to all replicas
final replica stores coords
intermediate replicas interpolate from coords
new coord = replica fraction between current and final state
initial replica does nothing
flag = 1
each replica (except first) opens file and reads it
each replica stores coords
initial replica does nothing
------------------------------------------------------------------------- */
void NEB::readfile(char *file, int flag)
{
- int i,j,m,nchunk,tag,eofflag;
- int nlines;
+ int i,j,m,nchunk,eofflag,nlines;
+ tagint tag;
char *eof,*start,*next,*buf;
char line[MAXLINE];
double xx,yy,zz,delx,dely,delz;
if (me_universe == 0 && screen)
fprintf(screen,"Reading NEB coordinate file(s) ...\n");
// flag = 0, universe root reads header of file, bcast to universe
// flag = 1, each replica's root reads header of file, bcast to world
// but explicitly skip first replica
if (flag == 0) {
if (me_universe == 0) {
open(file);
while (1) {
eof = fgets(line,MAXLINE,fp);
if (eof == NULL) error->one(FLERR,"Unexpected end of neb file");
start = &line[strspn(line," \t\n\v\f\r")];
if (*start != '\0' && *start != '#') break;
}
sscanf(line,"%d",&nlines);
}
MPI_Bcast(&nlines,1,MPI_INT,0,uworld);
} else {
if (me == 0) {
if (ireplica) {
open(file);
while (1) {
eof = fgets(line,MAXLINE,fp);
if (eof == NULL) error->one(FLERR,"Unexpected end of neb file");
start = &line[strspn(line," \t\n\v\f\r")];
if (*start != '\0' && *start != '#') break;
}
sscanf(line,"%d",&nlines);
} else nlines = 0;
}
MPI_Bcast(&nlines,1,MPI_INT,0,world);
}
char *buffer = new char[CHUNK*MAXLINE];
char **values = new char*[ATTRIBUTE_PERLINE];
double fraction = ireplica/(nreplica-1.0);
double **x = atom->x;
int nlocal = atom->nlocal;
// loop over chunks of lines read from file
// two versions of read_lines_from_file() for world vs universe bcast
// count # of atom coords changed so can check for invalid atom IDs in file
int ncount = 0;
int nread = 0;
while (nread < nlines) {
nchunk = MIN(nlines-nread,CHUNK);
if (flag == 0)
eofflag = comm->read_lines_from_file_universe(fp,nchunk,MAXLINE,buffer);
else
eofflag = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eofflag) error->all(FLERR,"Unexpected end of neb file");
buf = buffer;
next = strchr(buf,'\n');
*next = '\0';
int nwords = atom->count_words(buf);
*next = '\n';
if (nwords != ATTRIBUTE_PERLINE)
error->all(FLERR,"Incorrect atom format in neb file");
// loop over lines of atom coords
// tokenize the line into values
for (int i = 0; i < nchunk; i++) {
next = strchr(buf,'\n');
values[0] = strtok(buf," \t\n\r\f");
for (j = 1; j < nwords; j++)
values[j] = strtok(NULL," \t\n\r\f");
// adjust atom coord based on replica fraction
// for flag = 0, interpolate for intermediate and final replicas
// for flag = 1, replace existing coord with new coord
// ignore image flags of final x
// for interpolation:
// new x is displacement from old x via minimum image convention
// if final x is across periodic boundary:
// new x may be outside box
// will be remapped back into box when simulation starts
// its image flags will then be adjusted
- tag = atoi(values[0]);
+ tag = ATOTAGINT(values[0]);
m = atom->map(tag);
if (m >= 0 && m < nlocal) {
ncount++;
xx = atof(values[1]);
yy = atof(values[2]);
zz = atof(values[3]);
if (flag == 0) {
delx = xx - x[m][0];
dely = yy - x[m][1];
delz = zz - x[m][2];
domain->minimum_image(delx,dely,delz);
x[m][0] += fraction*delx;
x[m][1] += fraction*dely;
x[m][2] += fraction*delz;
} else {
x[m][0] = xx;
x[m][1] = yy;
x[m][2] = zz;
}
}
buf = next + 1;
}
nread += nchunk;
}
// check that all atom IDs in file were found by a proc
if (flag == 0) {
int ntotal;
MPI_Allreduce(&ncount,&ntotal,1,MPI_INT,MPI_SUM,uworld);
if (ntotal != nreplica*nlines)
error->universe_all(FLERR,"Invalid atom IDs in neb file");
} else {
int ntotal;
MPI_Allreduce(&ncount,&ntotal,1,MPI_INT,MPI_SUM,world);
if (ntotal != nlines)
error->all(FLERR,"Invalid atom IDs in neb file");
}
// clean up
delete [] buffer;
delete [] values;
if (flag == 0) {
if (me_universe == 0) {
if (compressed) pclose(fp);
else fclose(fp);
}
} else {
if (me == 0 && ireplica) {
if (compressed) pclose(fp);
else fclose(fp);
}
}
}
/* ----------------------------------------------------------------------
universe proc 0 opens NEB data file
test if gzipped
------------------------------------------------------------------------- */
void NEB::open(char *file)
{
compressed = 0;
char *suffix = file + strlen(file) - 3;
if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
if (!compressed) fp = fopen(file,"r");
else {
#ifdef LAMMPS_GZIP
char gunzip[128];
sprintf(gunzip,"gzip -c -d %s",file);
#ifdef _WIN32
fp = _popen(gunzip,"rb");
#else
fp = popen(gunzip,"r");
#endif
#else
error->one(FLERR,"Cannot open gzipped file");
#endif
}
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open file %s",file);
error->one(FLERR,str);
}
}
/* ----------------------------------------------------------------------
query fix NEB for info on each replica
proc 0 prints current NEB status
------------------------------------------------------------------------- */
void NEB::print_status()
{
double fnorm2 = sqrt(update->minimize->fnorm_sqr());
double fmaxreplica;
MPI_Allreduce(&fnorm2,&fmaxreplica,1,MPI_DOUBLE,MPI_MAX,roots);
double fnorminf = update->minimize->fnorm_inf();
double fmaxatom;
MPI_Allreduce(&fnorminf,&fmaxatom,1,MPI_DOUBLE,MPI_MAX,roots);
double one[4];
one[0] = fneb->veng;
one[1] = fneb->plen;
one[2] = fneb->nlen;
one[nall-1] = fneb->gradvnorm;
if (output->thermo->normflag) one[0] /= atom->natoms;
if (me == 0)
MPI_Allgather(one,nall,MPI_DOUBLE,&all[0][0],nall,MPI_DOUBLE,roots);
rdist[0] = 0.0;
for (int i = 1; i < nreplica; i++)
rdist[i] = rdist[i-1] + all[i][1];
double endpt = rdist[nreplica-1] = rdist[nreplica-2] + all[nreplica-2][2];
for (int i = 1; i < nreplica; i++)
rdist[i] /= endpt;
// look up GradV for the initial, final, and climbing replicas
// these are identical to fnorm2, but to be safe we
// take them straight from fix_neb
double gradvnorm0, gradvnorm1, gradvnormc;
int irep;
irep = 0;
gradvnorm0 = all[irep][3];
irep = nreplica-1;
gradvnorm1 = all[irep][3];
irep = fneb->rclimber;
if (irep > -1) {
gradvnormc = all[irep][3];
ebf = all[irep][0]-all[0][0];
ebr = all[irep][0]-all[nreplica-1][0];
} else {
double vmax = all[0][0];
int top = 0;
for (int m = 1; m < nreplica; m++)
if (vmax < all[m][0]) {
vmax = all[m][0];
top = m;
}
irep = top;
gradvnormc = all[irep][3];
ebf = all[irep][0]-all[0][0];
ebr = all[irep][0]-all[nreplica-1][0];
}
if (me_universe == 0) {
if (universe->uscreen) {
fprintf(universe->uscreen,BIGINT_FORMAT " %12.8g %12.8g ",
update->ntimestep,fmaxreplica,fmaxatom);
fprintf(universe->uscreen,"%12.8g %12.8g %12.8g ",
gradvnorm0,gradvnorm1,gradvnormc);
fprintf(universe->uscreen,"%12.8g %12.8g %12.8g ",ebf,ebr,endpt);
for (int i = 0; i < nreplica; i++)
fprintf(universe->uscreen,"%12.8g %12.8g ",rdist[i],all[i][0]);
fprintf(universe->uscreen,"\n");
}
if (universe->ulogfile) {
fprintf(universe->ulogfile,BIGINT_FORMAT " %12.8g %12.8g ",
update->ntimestep,fmaxreplica,fmaxatom);
fprintf(universe->ulogfile,"%12.8g %12.8g %12.8g ",
gradvnorm0,gradvnorm1,gradvnormc);
fprintf(universe->ulogfile,"%12.8g %12.8g %12.8g ",ebf,ebr,endpt);
for (int i = 0; i < nreplica; i++)
fprintf(universe->ulogfile,"%12.8g %12.8g ",rdist[i],all[i][0]);
fprintf(universe->ulogfile,"\n");
fflush(universe->ulogfile);
}
}
}
diff --git a/src/REPLICA/prd.cpp b/src/REPLICA/prd.cpp
index 1df75c8f9..9efb68720 100644
--- a/src/REPLICA/prd.cpp
+++ b/src/REPLICA/prd.cpp
@@ -1,845 +1,845 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "prd.h"
#include "universe.h"
#include "update.h"
#include "atom.h"
#include "domain.h"
#include "region.h"
#include "comm.h"
#include "velocity.h"
#include "integrate.h"
#include "min.h"
#include "neighbor.h"
#include "modify.h"
#include "compute.h"
#include "fix.h"
#include "fix_event_prd.h"
#include "force.h"
#include "pair.h"
#include "random_park.h"
#include "random_mars.h"
#include "output.h"
#include "dump.h"
#include "finish.h"
#include "timer.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PRD::PRD(LAMMPS *lmp) : Pointers(lmp) {}
/* ----------------------------------------------------------------------
perform PRD simulation on one or more replicas
------------------------------------------------------------------------- */
void PRD::command(int narg, char **arg)
{
int flag,ireplica;
// error checks
if (domain->box_exist == 0)
error->all(FLERR,"PRD command before simulation box is defined");
if (universe->nworlds != universe->nprocs &&
atom->map_style == 0)
error->all(FLERR,"Cannot use PRD with multi-processor replicas "
"unless atom map exists");
if (universe->nworlds == 1 && comm->me == 0)
error->warning(FLERR,"Running PRD with only one replica");
if (narg < 7) error->universe_all(FLERR,"Illegal prd command");
nsteps = force->inumeric(FLERR,arg[0]);
t_event = force->inumeric(FLERR,arg[1]);
n_dephase = force->inumeric(FLERR,arg[2]);
t_dephase = force->inumeric(FLERR,arg[3]);
t_corr = force->inumeric(FLERR,arg[4]);
char *id_compute = new char[strlen(arg[5])+1];
strcpy(id_compute,arg[5]);
int seed = force->inumeric(FLERR,arg[6]);
options(narg-7,&arg[7]);
// total # of timesteps must be multiple of t_event
if (t_event <= 0) error->universe_all(FLERR,"Invalid t_event in prd command");
if (nsteps % t_event)
error->universe_all(FLERR,"PRD nsteps must be multiple of t_event");
if (t_corr % t_event)
error->universe_all(FLERR,"PRD t_corr must be multiple of t_event");
// local storage
int me_universe = universe->me;
int nprocs_universe = universe->nprocs;
int nreplica = universe->nworlds;
int iworld = universe->iworld;
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
// comm_replica = communicator between all proc 0s across replicas
int color = me;
MPI_Comm_split(universe->uworld,color,0,&comm_replica);
// equal_size_replicas = 1 if all replicas have same # of procs
// no longer used
//flag = 0;
//if (nreplica*nprocs == nprocs_universe) flag = 1;
//MPI_Allreduce(&flag,&equal_size_replicas,1,MPI_INT,MPI_MIN,
// universe->uworld);
// workspace for inter-replica communication via gathers
natoms = atom->natoms;
displacements = NULL;
tagall = NULL;
xall = NULL;
imageall = NULL;
if (nreplica != nprocs_universe) {
displacements = new int[nprocs];
memory->create(tagall,natoms,"prd:tagall");
memory->create(xall,natoms,3,"prd:xall");
memory->create(imageall,natoms,"prd:imageall");
}
// random_select = same RNG for each replica for multiple event selection
// random_dephase = unique RNG for each replica for dephasing
random_select = new RanPark(lmp,seed);
random_dephase = new RanMars(lmp,seed+iworld);
// create ComputeTemp class to monitor temperature
char **args = new char*[3];
args[0] = (char *) "prd_temp";
args[1] = (char *) "all";
args[2] = (char *) "temp";
modify->add_compute(3,args);
temperature = modify->compute[modify->ncompute-1];
// create Velocity class for velocity creation in dephasing
// pass it temperature compute, loop_setting, dist_setting settings
atom->check_mass();
velocity = new Velocity(lmp);
velocity->init_external("all");
args[0] = (char *) "temp";
args[1] = (char *) "prd_temp";
velocity->options(2,args);
args[0] = (char *) "loop";
args[1] = (char *) loop_setting;
if (loop_setting) velocity->options(2,args);
args[0] = (char *) "dist";
args[1] = (char *) dist_setting;
if (dist_setting) velocity->options(2,args);
// create FixEventPRD class to store event and pre-quench states
args[0] = (char *) "prd_event";
args[1] = (char *) "all";
args[2] = (char *) "EVENT/PRD";
modify->add_fix(3,args);
fix_event = (FixEventPRD *) modify->fix[modify->nfix-1];
// create Finish for timing output
finish = new Finish(lmp);
// string clean-up
delete [] args;
delete [] loop_setting;
delete [] dist_setting;
// assign FixEventPRD to event-detection compute
// necessary so it will know atom coords at last event
int icompute = modify->find_compute(id_compute);
if (icompute < 0) error->all(FLERR,"Could not find compute ID for PRD");
compute_event = modify->compute[icompute];
compute_event->reset_extra_compute_fix("prd_event");
// reset reneighboring criteria since will perform minimizations
neigh_every = neighbor->every;
neigh_delay = neighbor->delay;
neigh_dist_check = neighbor->dist_check;
if (neigh_every != 1 || neigh_delay != 0 || neigh_dist_check != 1) {
if (me == 0)
error->warning(FLERR,"Resetting reneighboring criteria during PRD");
}
neighbor->every = 1;
neighbor->delay = 0;
neighbor->dist_check = 1;
// initialize PRD as if one long dynamics run
update->whichflag = 1;
update->nsteps = nsteps;
update->beginstep = update->firststep = update->ntimestep;
update->endstep = update->laststep = update->firststep + nsteps;
update->restrict_output = 1;
if (update->laststep < 0 || update->laststep > MAXBIGINT)
error->all(FLERR,"Too many timesteps");
lmp->init();
// init minimizer settings and minimizer itself
update->etol = etol;
update->ftol = ftol;
update->max_eval = maxeval;
update->minimize->init();
// cannot use PRD with a changing box
if (domain->box_change)
error->all(FLERR,"Cannot use PRD with a changing box");
// cannot use PRD with time-dependent fixes or regions or atom sorting
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->time_depend)
error->all(FLERR,"Cannot use PRD with a time-dependent fix defined");
for (int i = 0; i < domain->nregion; i++)
if (domain->regions[i]->dynamic_check())
error->all(FLERR,"Cannot use PRD with a time-dependent region defined");
if (atom->sortfreq > 0)
error->all(FLERR,"Cannot use PRD with atom_modify sort enabled");
// perform PRD simulation
if (me_universe == 0 && universe->uscreen)
fprintf(universe->uscreen,"Setting up PRD ...\n");
if (me_universe == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,"Step CPU Clock Event "
"Correlated Coincident Replica\n");
if (universe->ulogfile)
fprintf(universe->ulogfile,"Step CPU Clock Event "
"Correlated Coincident Replica\n");
}
// store hot state and quenched event for replica 0
// use share_event() to copy that info to all replicas
// this insures all start from same place
// need this line if quench() does only setup_minimal()
// update->minimize->setup();
fix_event->store_state();
quench();
ncoincident = 0;
share_event(0,0);
timer->init();
timer->barrier_start();
time_start = timer->get_wall(Timer::TOTAL);
log_event();
// do full init/setup since are starting all replicas after event
// replica 0 bcasts temp to all replicas if temp_dephase is not set
update->whichflag = 1;
lmp->init();
update->integrate->setup();
if (temp_flag == 0) {
if (universe->iworld == 0) temp_dephase = temperature->compute_scalar();
MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[0],
universe->uworld);
}
// main loop: look for events until out of time
// (1) dephase independently on each proc after event
// (2) loop: dynamics, store state, quench, check event, restore state
// (3) share and record event
nbuild = ndanger = 0;
time_dephase = time_dynamics = time_quench = time_comm = time_output = 0.0;
timer->barrier_start();
time_start = timer->get_wall(Timer::TOTAL);
while (update->ntimestep < update->endstep) {
dephase();
ireplica = -1;
while (update->ntimestep < update->endstep) {
dynamics();
fix_event->store_state();
quench();
ireplica = check_event();
if (ireplica >= 0) break;
fix_event->restore_state();
}
if (ireplica < 0) break;
// potentially more efficient for correlated events if don't
// share until correlated check has completed
// this will complicate the dump (always on replica 0)
share_event(ireplica,1);
log_event();
int restart_flag = 0;
if (output->restart_flag && universe->iworld == 0) {
if (output->restart_every_single &&
fix_event->event_number % output->restart_every_single == 0)
restart_flag = 1;
if (output->restart_every_double &&
fix_event->event_number % output->restart_every_double == 0)
restart_flag = 1;
}
// correlated event loop
// other procs could be dephasing during this time
int corr_endstep = update->ntimestep + t_corr;
while (update->ntimestep < corr_endstep) {
if (update->ntimestep == update->endstep) {
restart_flag = 0;
break;
}
dynamics();
fix_event->store_state();
quench();
int corr_event_check = check_event(ireplica);
if (corr_event_check >= 0) {
share_event(ireplica,2);
log_event();
corr_endstep = update->ntimestep + t_corr;
} else fix_event->restore_state();
}
// full init/setup since are starting all replicas after event
// event replica bcasts temp to all replicas if temp_dephase is not set
update->whichflag = 1;
lmp->init();
update->integrate->setup();
timer->barrier_start();
if (t_corr > 0) replicate(ireplica);
if (temp_flag == 0) {
if (ireplica == universe->iworld)
temp_dephase = temperature->compute_scalar();
MPI_Bcast(&temp_dephase,1,MPI_DOUBLE,universe->root_proc[ireplica],
universe->uworld);
}
timer->barrier_stop();
time_comm += timer->get_wall(Timer::TOTAL);
// write restart file of hot coords
if (restart_flag) {
timer->barrier_start();
output->write_restart(update->ntimestep);
timer->barrier_stop();
time_output += timer->get_wall(Timer::TOTAL);
}
}
// set total timers and counters so Finish() will process them
timer->set_wall(Timer::TOTAL, time_start);
timer->barrier_stop();
timer->set_wall(Timer::DEPHASE, time_dephase);
timer->set_wall(Timer::DYNAMICS, time_dynamics);
timer->set_wall(Timer::QUENCH, time_quench);
timer->set_wall(Timer::REPCOMM, time_comm);
timer->set_wall(Timer::REPOUT, time_output);
neighbor->ncalls = nbuild;
neighbor->ndanger = ndanger;
if (me_universe == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,
"Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT
" atoms\n",
timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
if (universe->ulogfile)
fprintf(universe->ulogfile,
"Loop time of %g on %d procs for %d steps with " BIGINT_FORMAT
" atoms\n",
timer->get_wall(Timer::TOTAL),nprocs_universe,nsteps,atom->natoms);
}
finish->end(2);
update->whichflag = 0;
update->firststep = update->laststep = 0;
update->beginstep = update->endstep = 0;
update->restrict_output = 0;
// reset reneighboring criteria
neighbor->every = neigh_every;
neighbor->delay = neigh_delay;
neighbor->dist_check = neigh_dist_check;
// clean up
delete [] displacements;
memory->destroy(tagall);
memory->destroy(xall);
memory->destroy(imageall);
delete [] id_compute;
MPI_Comm_free(&comm_replica);
delete random_select;
delete random_dephase;
delete velocity;
delete finish;
modify->delete_compute("prd_temp");
modify->delete_fix("prd_event");
compute_event->reset_extra_compute_fix(NULL);
}
/* ----------------------------------------------------------------------
dephasing = one or more short runs with new random velocities
------------------------------------------------------------------------- */
void PRD::dephase()
{
bigint ntimestep_hold = update->ntimestep;
update->whichflag = 1;
update->nsteps = n_dephase*t_dephase;
timer->barrier_start();
for (int i = 0; i < n_dephase; i++) {
int seed = static_cast<int> (random_dephase->uniform() * MAXSMALLINT);
if (seed == 0) seed = 1;
velocity->create(temp_dephase,seed);
update->integrate->run(t_dephase);
if (temp_flag == 0) temp_dephase = temperature->compute_scalar();
}
timer->barrier_stop();
time_dephase += timer->get_wall(Timer::TOTAL);
update->integrate->cleanup();
finish->end(0);
// reset timestep as if dephase did not occur
// clear timestep storage from computes, since now invalid
update->ntimestep = ntimestep_hold;
for (int i = 0; i < modify->ncompute; i++)
if (modify->compute[i]->timeflag) modify->compute[i]->clearstep();
}
/* ----------------------------------------------------------------------
single short dynamics run
------------------------------------------------------------------------- */
void PRD::dynamics()
{
update->whichflag = 1;
update->nsteps = t_event;
lmp->init();
update->integrate->setup();
// this may be needed if don't do full init
//modify->addstep_compute_all(update->ntimestep);
bigint ncalls = neighbor->ncalls;
timer->barrier_start();
update->integrate->run(t_event);
timer->barrier_stop();
time_dynamics += timer->get_wall(Timer::TOTAL);
nbuild += neighbor->ncalls - ncalls;
ndanger += neighbor->ndanger;
update->integrate->cleanup();
finish->end(0);
}
/* ----------------------------------------------------------------------
quench minimization
------------------------------------------------------------------------- */
void PRD::quench()
{
bigint ntimestep_hold = update->ntimestep;
bigint endstep_hold = update->endstep;
// need to change whichflag so that minimize->setup() calling
// modify->setup() will call fix->min_setup()
update->whichflag = 2;
update->nsteps = maxiter;
update->endstep = update->laststep = update->firststep + maxiter;
if (update->laststep < 0 || update->laststep > MAXBIGINT)
error->all(FLERR,"Too many iterations");
// full init works
lmp->init();
update->minimize->setup();
// partial init does not work
//modify->addstep_compute_all(update->ntimestep);
//update->minimize->setup_minimal(1);
int ncalls = neighbor->ncalls;
timer->barrier_start();
update->minimize->run(maxiter);
timer->barrier_stop();
time_quench += timer->get_wall(Timer::TOTAL);
if (neighbor->ncalls == ncalls) quench_reneighbor = 0;
else quench_reneighbor = 1;
update->minimize->cleanup();
finish->end(0);
// reset timestep as if dephase did not occur
// clear timestep storage from computes, since now invalid
update->ntimestep = ntimestep_hold;
update->endstep = update->laststep = endstep_hold;
for (int i = 0; i < modify->ncompute; i++)
if (modify->compute[i]->timeflag) modify->compute[i]->clearstep();
}
/* ----------------------------------------------------------------------
check for an event in any replica
if replica_num is non-negative only check for event on replica_num
if multiple events, choose one at random
return -1 if no event
else return ireplica = world in which event occured
------------------------------------------------------------------------- */
int PRD::check_event(int replica_num)
{
int worldflag,universeflag,scanflag,replicaflag,ireplica;
worldflag = 0;
if (compute_event->compute_scalar() > 0.0) worldflag = 1;
if (replica_num >= 0 && replica_num != universe->iworld) worldflag = 0;
timer->barrier_start();
if (me == 0) MPI_Allreduce(&worldflag,&universeflag,1,
MPI_INT,MPI_SUM,comm_replica);
MPI_Bcast(&universeflag,1,MPI_INT,0,world);
ncoincident = universeflag;
if (!universeflag) ireplica = -1;
else {
// multiple events, choose one at random
// iwhich = random # from 1 to N, N = # of events to choose from
// scanflag = 1 to N on replicas with an event, 0 on non-event replicas
// exit with worldflag = 1 on chosen replica, 0 on all others
// note worldflag is already 0 on replicas that didn't perform event
if (universeflag > 1) {
int iwhich = static_cast<int>
(universeflag*random_select->uniform()) + 1;
if (me == 0)
MPI_Scan(&worldflag,&scanflag,1,MPI_INT,MPI_SUM,comm_replica);
MPI_Bcast(&scanflag,1,MPI_INT,0,world);
if (scanflag != iwhich) worldflag = 0;
}
if (worldflag) replicaflag = universe->iworld;
else replicaflag = 0;
if (me == 0) MPI_Allreduce(&replicaflag,&ireplica,1,
MPI_INT,MPI_SUM,comm_replica);
MPI_Bcast(&ireplica,1,MPI_INT,0,world);
}
timer->barrier_stop();
time_comm += timer->get_wall(Timer::TOTAL);
return ireplica;
}
/* ----------------------------------------------------------------------
share quenched and hot coords owned by ireplica with all replicas
all replicas store event in fix_event
replica 0 dumps event snapshot
flag = 0 = called before PRD run
flag = 1 = called during PRD run = not correlated event
flag = 2 = called during PRD run = correlated event
------------------------------------------------------------------------- */
void PRD::share_event(int ireplica, int flag)
{
timer->barrier_start();
// communicate quenched coords to all replicas and store as event
// decrement event counter if flag = 0 since not really an event
replicate(ireplica);
timer->barrier_stop();
time_comm += timer->get_wall(Timer::TOTAL);
// adjust time for last correlated event check (not on first event)
int corr_adjust = t_corr;
if (fix_event->event_number < 1 || flag == 2) corr_adjust = 0;
// delta = time since last correlated event check
int delta = update->ntimestep - fix_event->event_timestep - corr_adjust;
// if this is a correlated event, time elapsed only on one partition
if (flag != 2) delta *= universe->nworlds;
delta += corr_adjust;
// don't change the clock or timestep if this is a restart
if (flag == 0 && fix_event->event_number != 0)
fix_event->store_event_prd(fix_event->event_timestep,0);
else {
fix_event->store_event_prd(update->ntimestep,delta);
fix_event->replica_number = ireplica;
fix_event->correlated_event = 0;
if (flag == 2) fix_event->correlated_event = 1;
fix_event->ncoincident = ncoincident;
}
if (flag == 0) fix_event->event_number--;
// dump snapshot of quenched coords, only on replica 0
// must reneighbor and compute forces before dumping
// since replica 0 possibly has new state from another replica
// addstep_compute_all insures eng/virial are calculated if needed
if (output->ndump && universe->iworld == 0) {
timer->barrier_start();
modify->addstep_compute_all(update->ntimestep);
update->integrate->setup_minimal(1);
output->write_dump(update->ntimestep);
timer->barrier_stop();
time_output += timer->get_wall(Timer::TOTAL);
}
// restore and communicate hot coords to all replicas
fix_event->restore_state();
timer->barrier_start();
replicate(ireplica);
timer->barrier_stop();
time_comm += timer->get_wall(Timer::TOTAL);
}
/* ----------------------------------------------------------------------
universe proc 0 prints event info
------------------------------------------------------------------------- */
void PRD::log_event()
{
timer->set_wall(Timer::TOTAL, time_start);
if (universe->me == 0) {
if (universe->uscreen)
fprintf(universe->uscreen,
BIGINT_FORMAT " %.3f %d %d %d %d %d\n",
fix_event->event_timestep,
timer->elapsed(Timer::TOTAL),
fix_event->clock,
fix_event->event_number,fix_event->correlated_event,
fix_event->ncoincident,
fix_event->replica_number);
if (universe->ulogfile)
fprintf(universe->ulogfile,
BIGINT_FORMAT " %.3f %d %d %d %d %d\n",
fix_event->event_timestep,
timer->elapsed(Timer::TOTAL),
fix_event->clock,
fix_event->event_number,fix_event->correlated_event,
fix_event->ncoincident,
fix_event->replica_number);
}
}
/* ----------------------------------------------------------------------
communicate atom coords and image flags in ireplica to all other replicas
one proc per replica:
direct overwrite via bcast
else atoms could be stored in different order or on different procs:
collect to root proc of event replica
bcast to roots of other replicas
bcast within each replica
each proc extracts info for atoms it owns using atom IDs
------------------------------------------------------------------------- */
void PRD::replicate(int ireplica)
{
int nreplica = universe->nworlds;
int nprocs_universe = universe->nprocs;
int i,m,flag,commflag;
if (nreplica == nprocs_universe) {
MPI_Bcast(atom->image,atom->nlocal,MPI_INT,ireplica,comm_replica);
MPI_Bcast(atom->x[0],3*atom->nlocal,MPI_DOUBLE,ireplica,comm_replica);
} else {
int *counts = new int[nprocs];
if (universe->iworld == ireplica) {
MPI_Gather(&atom->nlocal,1,MPI_INT,counts,1,MPI_INT,0,world);
displacements[0] = 0;
for (i = 0; i < nprocs-1; i++)
displacements[i+1] = displacements[i] + counts[i];
- MPI_Gatherv(atom->tag,atom->nlocal,MPI_INT,
- tagall,counts,displacements,MPI_INT,0,world);
+ MPI_Gatherv(atom->tag,atom->nlocal,MPI_LMP_TAGINT,
+ tagall,counts,displacements,MPI_LMP_TAGINT,0,world);
MPI_Gatherv(atom->image,atom->nlocal,MPI_INT,
imageall,counts,displacements,MPI_INT,0,world);
for (i = 0; i < nprocs; i++) counts[i] *= 3;
for (i = 0; i < nprocs-1; i++)
displacements[i+1] = displacements[i] + counts[i];
MPI_Gatherv(atom->x[0],3*atom->nlocal,MPI_DOUBLE,
xall[0],counts,displacements,MPI_DOUBLE,0,world);
}
if (me == 0) {
MPI_Bcast(tagall,natoms,MPI_INT,ireplica,comm_replica);
MPI_Bcast(imageall,natoms,MPI_INT,ireplica,comm_replica);
MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,ireplica,comm_replica);
}
MPI_Bcast(tagall,natoms,MPI_INT,0,world);
MPI_Bcast(imageall,natoms,MPI_INT,0,world);
MPI_Bcast(xall[0],3*natoms,MPI_DOUBLE,0,world);
double **x = atom->x;
int nlocal = atom->nlocal;
for (i = 0; i < natoms; i++) {
m = atom->map(tagall[i]);
if (m >= 0 && m < nlocal) {
x[m][0] = xall[i][0];
x[m][1] = xall[i][1];
x[m][2] = xall[i][2];
atom->image[m] = imageall[i];
}
}
delete [] counts;
}
}
/* ----------------------------------------------------------------------
parse optional parameters at end of PRD input line
------------------------------------------------------------------------- */
void PRD::options(int narg, char **arg)
{
if (narg < 0) error->all(FLERR,"Illegal prd command");
// set defaults
etol = 0.1;
ftol = 0.1;
maxiter = 40;
maxeval = 50;
temp_flag = 0;
char *str = (char *) "geom";
int n = strlen(str) + 1;
loop_setting = new char[n];
strcpy(loop_setting,str);
str = (char *) "gaussian";
n = strlen(str) + 1;
dist_setting = new char[n];
strcpy(dist_setting,str);
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"min") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal prd command");
etol = force->numeric(FLERR,arg[iarg+1]);
ftol = force->numeric(FLERR,arg[iarg+2]);
maxiter = force->inumeric(FLERR,arg[iarg+3]);
maxeval = force->inumeric(FLERR,arg[iarg+4]);
if (maxiter < 0) error->all(FLERR,"Illegal prd command");
iarg += 5;
} else if (strcmp(arg[iarg],"temp") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal prd command");
temp_flag = 1;
temp_dephase = force->numeric(FLERR,arg[iarg+1]);
if (temp_dephase <= 0.0) error->all(FLERR,"Illegal prd command");
iarg += 2;
} else if (strcmp(arg[iarg],"vel") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal prd command");
delete [] loop_setting;
delete [] dist_setting;
if (strcmp(arg[iarg+1],"all") == 0) loop_setting = NULL;
else if (strcmp(arg[iarg+1],"local") == 0) loop_setting = NULL;
else if (strcmp(arg[iarg+1],"geom") == 0) loop_setting = NULL;
else error->all(FLERR,"Illegal prd command");
int n = strlen(arg[iarg+1]) + 1;
loop_setting = new char[n];
strcpy(loop_setting,arg[iarg+1]);
if (strcmp(arg[iarg+2],"uniform") == 0) dist_setting = NULL;
else if (strcmp(arg[iarg+2],"gaussian") == 0) dist_setting = NULL;
else error->all(FLERR,"Illegal prd command");
n = strlen(arg[iarg+2]) + 1;
dist_setting = new char[n];
strcpy(dist_setting,arg[iarg+2]);
iarg += 3;
} else error->all(FLERR,"Illegal prd command");
}
}
diff --git a/src/REPLICA/prd.h b/src/REPLICA/prd.h
index ad979ff22..5f8e83323 100644
--- a/src/REPLICA/prd.h
+++ b/src/REPLICA/prd.h
@@ -1,147 +1,148 @@
/* -*- 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 COMMAND_CLASS
CommandStyle(prd,PRD)
#else
#ifndef LMP_PRD_H
#define LMP_PRD_H
#include "pointers.h"
namespace LAMMPS_NS {
class PRD : protected Pointers {
public:
PRD(class LAMMPS *);
~PRD() {}
void command(int, char **);
private:
int me,nprocs;
int nsteps,t_event,n_dephase,t_dephase,t_corr;
double etol,ftol,temp_dephase;
int maxiter,maxeval,temp_flag;
char *loop_setting,*dist_setting;
int equal_size_replicas,natoms;
int neigh_every,neigh_delay,neigh_dist_check;
int quench_reneighbor;
bigint nbuild,ndanger;
double time_dephase,time_dynamics,time_quench,time_comm,time_output;
double time_start;
MPI_Comm comm_replica;
- int *tagall,*displacements,*imageall;
+ tagint *tagall;
+ int *displacements,*imageall;
double **xall;
int ncoincident;
class RanPark *random_select;
class RanMars *random_dephase;
class Compute *compute_event;
class FixEventPRD *fix_event;
class Velocity *velocity;
class Compute *temperature;
class Finish *finish;
void dephase();
void dynamics();
void quench();
int check_event(int replica = -1);
void share_event(int, int);
void log_event();
void replicate(int);
void options(int, char **);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: PRD command before simulation box is defined
The prd command cannot be used before a read_data,
read_restart, or create_box command.
E: Cannot use PRD with multi-processor replicas unless atom map exists
Use the atom_modify command to create an atom map.
W: Running PRD with only one replica
This is allowed, but you will get no parallel speed-up.
E: Illegal ... command
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.
E: Invalid t_event in prd command
Self-explanatory.
E: PRD nsteps must be multiple of t_event
Self-explanatory.
E: PRD t_corr must be multiple of t_event
Self-explanatory.
E: Could not find compute ID for PRD
Self-explanatory.
W: Resetting reneighboring criteria during PRD
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.
E: Too many timesteps
The cumulative timesteps must fit in a 64-bit integer.
E: Cannot use PRD with a changing box
The current box dimensions are not copied between replicas
E: Cannot use PRD with a time-dependent fix defined
PRD alters the timestep in ways that will mess up these fixes.
E: Cannot use PRD with a time-dependent region defined
PRD alters the timestep in ways that will mess up these regions.
E: Cannot use PRD with atom_modify sort enabled
This is a current restriction of PRD. You must turn off sorting,
which is enabled by default, via the atom_modify command.
E: Too many iterations
You must use a number of iterations that fit in a 32-bit integer
for minimization.
*/
diff --git a/src/REPLICA/verlet_split.cpp b/src/REPLICA/verlet_split.cpp
index 5d341f80f..1b1d06ab0 100644
--- a/src/REPLICA/verlet_split.cpp
+++ b/src/REPLICA/verlet_split.cpp
@@ -1,570 +1,571 @@
/* ----------------------------------------------------------------------
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: Yuxing Peng and Chris Knight (U Chicago)
------------------------------------------------------------------------- */
#include "string.h"
#include "verlet_split.h"
#include "universe.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "kspace.h"
#include "output.h"
#include "update.h"
#include "fix.h"
#include "modify.h"
#include "timer.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
VerletSplit::VerletSplit(LAMMPS *lmp, int narg, char **arg) :
Verlet(lmp, narg, arg)
{
// error checks on partitions
if (universe->nworlds != 2)
error->universe_all(FLERR,"Verlet/split requires 2 partitions");
if (universe->procs_per_world[0] % universe->procs_per_world[1])
error->universe_all(FLERR,"Verlet/split requires Rspace partition "
"size be multiple of Kspace partition size");
// master = 1 for Rspace procs, 0 for Kspace procs
if (universe->iworld == 0) master = 1;
else master = 0;
ratio = universe->procs_per_world[0] / universe->procs_per_world[1];
// Kspace root proc broadcasts info about Kspace proc layout to Rspace procs
int kspace_procgrid[3];
if (universe->me == universe->root_proc[1]) {
kspace_procgrid[0] = comm->procgrid[0];
kspace_procgrid[1] = comm->procgrid[1];
kspace_procgrid[2] = comm->procgrid[2];
}
MPI_Bcast(kspace_procgrid,3,MPI_INT,universe->root_proc[1],universe->uworld);
int ***kspace_grid2proc;
memory->create(kspace_grid2proc,kspace_procgrid[0],
kspace_procgrid[1],kspace_procgrid[2],
"verlet/split:kspace_grid2proc");
if (universe->me == universe->root_proc[1]) {
for (int i = 0; i < comm->procgrid[0]; i++)
for (int j = 0; j < comm->procgrid[1]; j++)
for (int k = 0; k < comm->procgrid[2]; k++)
kspace_grid2proc[i][j][k] = comm->grid2proc[i][j][k];
}
MPI_Bcast(&kspace_grid2proc[0][0][0],
kspace_procgrid[0]*kspace_procgrid[1]*kspace_procgrid[2],MPI_INT,
universe->root_proc[1],universe->uworld);
// Rspace partition must be multiple of Kspace partition in each dim
// so atoms of one Kspace proc coincide with atoms of several Rspace procs
if (master) {
int flag = 0;
if (comm->procgrid[0] % kspace_procgrid[0]) flag = 1;
if (comm->procgrid[1] % kspace_procgrid[1]) flag = 1;
if (comm->procgrid[2] % kspace_procgrid[2]) flag = 1;
if (flag)
error->one(FLERR,
"Verlet/split requires Rspace partition layout be "
"multiple of Kspace partition layout in each dim");
}
// block = 1 Kspace proc with set of Rspace procs it overlays
// me_block = 0 for Kspace proc
// me_block = 1 to ratio for Rspace procs
// block = MPI communicator for that set of procs
int iblock,key;
if (!master) {
iblock = comm->me;
key = 0;
} else {
int kpx = comm->myloc[0] / (comm->procgrid[0]/kspace_procgrid[0]);
int kpy = comm->myloc[1] / (comm->procgrid[1]/kspace_procgrid[1]);
int kpz = comm->myloc[2] / (comm->procgrid[2]/kspace_procgrid[2]);
iblock = kspace_grid2proc[kpx][kpy][kpz];
key = 1;
}
MPI_Comm_split(universe->uworld,iblock,key,&block);
MPI_Comm_rank(block,&me_block);
// output block groupings to universe screen/logfile
// bmap is ordered by block and then by proc within block
int *bmap = new int[universe->nprocs];
for (int i = 0; i < universe->nprocs; i++) bmap[i] = -1;
bmap[iblock*(ratio+1)+me_block] = universe->me;
int *bmapall = new int[universe->nprocs];
MPI_Allreduce(bmap,bmapall,universe->nprocs,MPI_INT,MPI_MAX,universe->uworld);
if (universe->me == 0) {
if (universe->uscreen) {
fprintf(universe->uscreen,
"Per-block Rspace/Kspace proc IDs (original proc IDs):\n");
int m = 0;
for (int i = 0; i < universe->nprocs/(ratio+1); i++) {
fprintf(universe->uscreen," block %d:",i);
int kspace_proc = bmapall[m];
for (int j = 1; j <= ratio; j++)
fprintf(universe->uscreen," %d",bmapall[m+j]);
fprintf(universe->uscreen," %d",kspace_proc);
kspace_proc = bmapall[m];
for (int j = 1; j <= ratio; j++) {
if (j == 1) fprintf(universe->uscreen," (");
else fprintf(universe->uscreen," ");
fprintf(universe->uscreen,"%d",
universe->uni2orig[bmapall[m+j]]);
}
fprintf(universe->uscreen," %d)\n",universe->uni2orig[kspace_proc]);
m += ratio + 1;
}
}
if (universe->ulogfile) {
fprintf(universe->ulogfile,
"Per-block Rspace/Kspace proc IDs (original proc IDs):\n");
int m = 0;
for (int i = 0; i < universe->nprocs/(ratio+1); i++) {
fprintf(universe->ulogfile," block %d:",i);
int kspace_proc = bmapall[m];
for (int j = 1; j <= ratio; j++)
fprintf(universe->ulogfile," %d",bmapall[m+j]);
fprintf(universe->ulogfile," %d",kspace_proc);
kspace_proc = bmapall[m];
for (int j = 1; j <= ratio; j++) {
if (j == 1) fprintf(universe->ulogfile," (");
else fprintf(universe->ulogfile," ");
fprintf(universe->ulogfile,"%d",
universe->uni2orig[bmapall[m+j]]);
}
fprintf(universe->ulogfile," %d)\n",universe->uni2orig[kspace_proc]);
m += ratio + 1;
}
}
}
memory->destroy(kspace_grid2proc);
delete [] bmap;
delete [] bmapall;
// size/disp = vectors for MPI gather/scatter within block
qsize = new int[ratio+1];
qdisp = new int[ratio+1];
xsize = new int[ratio+1];
xdisp = new int[ratio+1];
// f_kspace = Rspace copy of Kspace forces
// allocate dummy version for Kspace partition
maxatom = 0;
f_kspace = NULL;
if (!master) memory->create(f_kspace,1,1,"verlet/split:f_kspace");
}
/* ---------------------------------------------------------------------- */
VerletSplit::~VerletSplit()
{
delete [] qsize;
delete [] qdisp;
delete [] xsize;
delete [] xdisp;
memory->destroy(f_kspace);
MPI_Comm_free(&block);
}
/* ----------------------------------------------------------------------
initialization before run
------------------------------------------------------------------------- */
void VerletSplit::init()
{
if (!force->kspace && comm->me == 0)
error->warning(FLERR,"No Kspace calculation with verlet/split");
if (force->kspace_match("tip4p",0)) tip4p_flag = 1;
else tip4p_flag = 0;
// currently TIP4P does not work with verlet/split, so generate error
// see Axel email on this, also other TIP4P notes below
if (tip4p_flag) error->all(FLERR,"Verlet/split does not yet support TIP4P");
Verlet::init();
}
/* ----------------------------------------------------------------------
setup before run
servant partition only sets up KSpace calculation
------------------------------------------------------------------------- */
void VerletSplit::setup()
{
if (comm->me == 0 && screen) fprintf(screen,"Setting up run ...\n");
if (!master) force->kspace->setup();
else Verlet::setup();
}
/* ----------------------------------------------------------------------
setup without output
flag = 0 = just force calculation
flag = 1 = reneighbor and force calculation
servant partition only sets up KSpace calculation
------------------------------------------------------------------------- */
void VerletSplit::setup_minimal(int flag)
{
if (!master) force->kspace->setup();
else Verlet::setup_minimal(flag);
}
/* ----------------------------------------------------------------------
run for N steps
master partition does everything but Kspace
servant partition does just Kspace
communicate back and forth every step:
atom coords from master -> servant
kspace forces from servant -> master
also box bounds from master -> servant if necessary
------------------------------------------------------------------------- */
void VerletSplit::run(int n)
{
bigint ntimestep;
int nflag,sortflag;
// sync both partitions before start timer
MPI_Barrier(universe->uworld);
timer->init();
timer->barrier_start();
// setup initial Rspace <-> Kspace comm params
rk_setup();
// check if OpenMP support fix defined
Fix *fix_omp;
int ifix = modify->find_fix("package_omp");
if (ifix < 0) fix_omp = NULL;
else fix_omp = modify->fix[ifix];
// flags for timestepping iterations
int n_post_integrate = modify->n_post_integrate;
int n_pre_exchange = modify->n_pre_exchange;
int n_pre_neighbor = modify->n_pre_neighbor;
int n_pre_force = modify->n_pre_force;
int n_post_force = modify->n_post_force;
int n_end_of_step = modify->n_end_of_step;
if (atom->sortfreq > 0) sortflag = 1;
else sortflag = 0;
for (int i = 0; i < n; i++) {
ntimestep = ++update->ntimestep;
ev_set(ntimestep);
// initial time integration
if (master) {
modify->initial_integrate(vflag);
if (n_post_integrate) modify->post_integrate();
}
// regular communication vs neighbor list rebuild
if (master) nflag = neighbor->decide();
MPI_Bcast(&nflag,1,MPI_INT,1,block);
if (master) {
if (nflag == 0) {
timer->stamp();
comm->forward_comm();
timer->stamp(Timer::COMM);
} else {
if (n_pre_exchange) modify->pre_exchange();
if (triclinic) domain->x2lamda(atom->nlocal);
domain->pbc();
if (domain->box_change) {
domain->reset_box();
comm->setup();
if (neighbor->style) neighbor->setup_bins();
}
timer->stamp();
comm->exchange();
if (sortflag && ntimestep >= atom->nextsort) atom->sort();
comm->borders();
if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
timer->stamp(Timer::COMM);
if (n_pre_neighbor) modify->pre_neighbor();
neighbor->build();
timer->stamp(Timer::NEIGH);
}
}
// if reneighboring occurred, re-setup Rspace <-> Kspace comm params
// comm Rspace atom coords to Kspace procs
if (nflag) rk_setup();
r2k_comm();
// force computations
force_clear();
if (master) {
if (n_pre_force) modify->pre_force(vflag);
timer->stamp();
if (force->pair) {
force->pair->compute(eflag,vflag);
timer->stamp(Timer::PAIR);
}
if (atom->molecular) {
if (force->bond) force->bond->compute(eflag,vflag);
if (force->angle) force->angle->compute(eflag,vflag);
if (force->dihedral) force->dihedral->compute(eflag,vflag);
if (force->improper) force->improper->compute(eflag,vflag);
timer->stamp(Timer::BOND);
}
if (force->newton) {
comm->reverse_comm();
timer->stamp(Timer::COMM);
}
} else {
// run FixOMP as sole pre_force fix, if defined
if (fix_omp) fix_omp->pre_force(vflag);
if (force->kspace) {
timer->stamp();
force->kspace->compute(eflag,vflag);
timer->stamp(Timer::KSPACE);
}
// TIP4P PPPM puts forces on ghost atoms, so must reverse_comm()
if (tip4p_flag && force->newton) {
comm->reverse_comm();
timer->stamp(Timer::COMM);
}
}
// comm and sum Kspace forces back to Rspace procs
k2r_comm();
// force modifications, final time integration, diagnostics
// all output
if (master) {
if (n_post_force) modify->post_force(vflag);
modify->final_integrate();
if (n_end_of_step) modify->end_of_step();
if (ntimestep == output->next) {
timer->stamp();
output->write(ntimestep);
timer->stamp(Timer::OUTPUT);
}
}
}
}
/* ----------------------------------------------------------------------
setup params for Rspace <-> Kspace communication
called initially and after every reneighbor
also communcicate atom charges from Rspace to KSpace since static
------------------------------------------------------------------------- */
void VerletSplit::rk_setup()
{
// grow f_kspace array on master procs if necessary
if (master) {
if (atom->nlocal > maxatom) {
memory->destroy(f_kspace);
maxatom = atom->nmax;
memory->create(f_kspace,maxatom,3,"verlet/split:f_kspace");
}
}
// qsize = # of atoms owned by each master proc in block
int n = 0;
if (master) n = atom->nlocal;
MPI_Gather(&n,1,MPI_INT,qsize,1,MPI_INT,0,block);
// setup qdisp, xsize, xdisp based on qsize
// only needed by Kspace proc
// set Kspace nlocal to sum of Rspace nlocals
// insure Kspace atom arrays are large enough
if (!master) {
qsize[0] = qdisp[0] = xsize[0] = xdisp[0] = 0;
for (int i = 1; i <= ratio; i++) {
qdisp[i] = qdisp[i-1]+qsize[i-1];
xsize[i] = 3*qsize[i];
xdisp[i] = xdisp[i-1]+xsize[i-1];
}
atom->nlocal = qdisp[ratio] + qsize[ratio];
while (atom->nmax <= atom->nlocal) atom->avec->grow(0);
atom->nghost = 0;
}
// one-time gather of Rspace atom charges to Kspace proc
MPI_Gatherv(atom->q,n,MPI_DOUBLE,atom->q,qsize,qdisp,MPI_DOUBLE,0,block);
// for TIP4P also need to send atom type and tag
// KSpace procs need to acquire ghost atoms and map all their atoms
// map_clear() call is in lieu of comm->exchange() which performs map_clear
// borders() call acquires ghost atoms and maps them
// NOTE: do atom coords need to be communicated here before borders() call?
// could do this by calling r2k_comm() here and not again from run()
// except that forward_comm() in r2k_comm() is wrong
if (tip4p_flag) {
//r2k_comm();
MPI_Gatherv(atom->type,n,MPI_INT,atom->type,qsize,qdisp,MPI_INT,0,block);
- MPI_Gatherv(atom->tag,n,MPI_INT,atom->tag,qsize,qdisp,MPI_INT,0,block);
+ MPI_Gatherv(atom->tag,n,MPI_LMP_TAGINT,
+ atom->tag,qsize,qdisp,MPI_LMP_TAGINT,0,block);
if (!master) {
if (triclinic) domain->x2lamda(atom->nlocal);
if (domain->box_change) comm->setup();
timer->stamp();
atom->map_clear();
comm->borders();
if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
timer->stamp(Timer::COMM);
}
}
}
/* ----------------------------------------------------------------------
communicate Rspace atom coords to Kspace
also eflag,vflag and box bounds if needed
------------------------------------------------------------------------- */
void VerletSplit::r2k_comm()
{
MPI_Status status;
int n = 0;
if (master) n = atom->nlocal;
MPI_Gatherv(atom->x[0],n*3,MPI_DOUBLE,atom->x[0],xsize,xdisp,
MPI_DOUBLE,0,block);
// send eflag,vflag from Rspace to Kspace
if (me_block == 1) {
int flags[2];
flags[0] = eflag; flags[1] = vflag;
MPI_Send(flags,2,MPI_INT,0,0,block);
} else if (!master) {
int flags[2];
MPI_Recv(flags,2,MPI_DOUBLE,1,0,block,&status);
eflag = flags[0]; vflag = flags[1];
}
// send box bounds from Rspace to Kspace if simulation box is dynamic
if (domain->box_change) {
if (me_block == 1) {
MPI_Send(domain->boxlo,3,MPI_DOUBLE,0,0,block);
MPI_Send(domain->boxhi,3,MPI_DOUBLE,0,0,block);
} else if (!master) {
MPI_Recv(domain->boxlo,3,MPI_DOUBLE,1,0,block,&status);
MPI_Recv(domain->boxhi,3,MPI_DOUBLE,1,0,block,&status);
domain->set_global_box();
domain->set_local_box();
force->kspace->setup();
}
}
// for TIP4P, Kspace partition needs to update its ghost atoms
if (tip4p_flag && !master) {
timer->stamp();
comm->forward_comm();
timer->stamp(Timer::COMM);
}
}
/* ----------------------------------------------------------------------
communicate and sum Kspace atom forces back to Rspace
------------------------------------------------------------------------- */
void VerletSplit::k2r_comm()
{
if (eflag) MPI_Bcast(&force->kspace->energy,1,MPI_DOUBLE,0,block);
if (vflag) MPI_Bcast(force->kspace->virial,6,MPI_DOUBLE,0,block);
int n = 0;
if (master) n = atom->nlocal;
MPI_Scatterv(atom->f[0],xsize,xdisp,MPI_DOUBLE,
f_kspace[0],n*3,MPI_DOUBLE,0,block);
if (master) {
double **f = atom->f;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
f[i][0] += f_kspace[i][0];
f[i][1] += f_kspace[i][1];
f[i][2] += f_kspace[i][2];
}
}
}
/* ----------------------------------------------------------------------
memory usage of Kspace force array on master procs
------------------------------------------------------------------------- */
bigint VerletSplit::memory_usage()
{
bigint bytes = maxatom*3 * sizeof(double);
return bytes;
}
diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp
index 6bda63ba1..f9b22eed0 100644
--- a/src/RIGID/fix_rigid_small.cpp
+++ b/src/RIGID/fix_rigid_small.cpp
@@ -1,3238 +1,3240 @@
/* ----------------------------------------------------------------------
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 "fix_rigid_small.h"
#include "math_extra.h"
#include "atom.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "molecule.h"
#include "domain.h"
#include "update.h"
#include "respa.h"
#include "modify.h"
#include "group.h"
#include "comm.h"
#include "force.h"
#include "output.h"
#include "random_mars.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
#include <map>
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
// allocate space for static class variable
FixRigidSmall *FixRigidSmall::frsptr;
#define MAXLINE 256
#define CHUNK 1024
#define ATTRIBUTE_PERBODY 11
#define TOLERANCE 1.0e-6
#define EPSILON 1.0e-7
#define BIG 1.0e20
#define SINERTIA 0.4 // moment of inertia prefactor for sphere
#define EINERTIA 0.4 // moment of inertia prefactor for ellipsoid
#define LINERTIA (1.0/12.0) // moment of inertia prefactor for line segment
#define DELTA_BODY 10000
enum{FULL_BODY,INITIAL,FINAL,FORCE_TORQUE,VCM_ANGMOM,XCM_MASS,ITENSOR,DOF};
/* ---------------------------------------------------------------------- */
FixRigidSmall::FixRigidSmall(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
int i;
scalar_flag = 1;
extscalar = 0;
global_freq = 1;
time_integrate = 1;
rigid_flag = 1;
virial_flag = 1;
create_attribute = 1;
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
// perform initial allocation of atom-based arrays
// register with Atom class
extended = orientflag = dorientflag = 0;
bodyown = NULL;
bodytag = NULL;
atom2body = NULL;
displace = NULL;
eflags = NULL;
orient = NULL;
dorient = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
// parse args for rigid body specification
if (narg < 4) error->all(FLERR,"Illegal fix rigid/small command");
if (strcmp(arg[3],"molecule") != 0)
error->all(FLERR,"Illegal fix rigid/small command");
if (atom->molecule_flag == 0)
error->all(FLERR,"Fix rigid/small requires atom attribute molecule");
if (atom->map_style == 0)
error->all(FLERR,"Fix rigid/small requires an atom map, see atom_modify");
// maxmol = largest molecule #
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
maxmol = -1;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) maxmol = MAX(maxmol,molecule[i]);
int itmp;
MPI_Allreduce(&maxmol,&itmp,1,MPI_INT,MPI_MAX,world);
maxmol = itmp;
// parse optional args
int seed;
langflag = 0;
infile = NULL;
onemol = NULL;
int iarg = 4;
while (iarg < narg) {
if (strcmp(arg[iarg],"langevin") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal fix rigid/small command");
if (strcmp(style,"rigid/small") != 0)
error->all(FLERR,"Illegal fix rigid/small command");
langflag = 1;
t_start = force->numeric(FLERR,arg[iarg+1]);
t_stop = force->numeric(FLERR,arg[iarg+2]);
t_period = force->numeric(FLERR,arg[iarg+3]);
seed = force->inumeric(FLERR,arg[iarg+4]);
if (t_period <= 0.0)
error->all(FLERR,"Fix rigid/small langevin period must be > 0.0");
if (seed <= 0) error->all(FLERR,"Illegal fix rigid/small command");
iarg += 5;
} else if (strcmp(arg[iarg],"infile") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command");
delete [] infile;
int n = strlen(arg[iarg+1]) + 1;
infile = new char[n];
strcpy(infile,arg[iarg+1]);
restart_file = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix rigid/small command");
int imol = atom->find_molecule(arg[iarg+1]);
if (imol == -1)
error->all(FLERR,"Molecule ID for fix rigid/small does not exist");
onemol = atom->molecules[imol];
iarg += 2;
} else error->all(FLERR,"Illegal fix rigid/small command");
}
// error check and further setup for Molecule template
if (onemol) {
if (onemol->xflag == 0)
error->all(FLERR,"Fix rigid/small molecule must have coordinates");
if (onemol->typeflag == 0)
error->all(FLERR,"Fix rigid/small molecule must have atom types");
// fix rigid/small uses center, masstotal, COM, inertia of molecule
onemol->compute_center();
onemol->compute_mass();
onemol->compute_com();
onemol->compute_inertia();
}
// create rigid bodies based on molecule ID
// sets bodytag for owned atoms
// body attributes are computed later by setup_bodies()
create_bodies();
// set nlocal_body and allocate bodies I own
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
nlocal_body = nghost_body = 0;
for (i = 0; i < nlocal; i++)
if (bodytag[i] == tag[i]) nlocal_body++;
nmax_body = 0;
while (nmax_body < nlocal_body) nmax_body += DELTA_BODY;
body = (Body *) memory->smalloc(nmax_body*sizeof(Body),
"rigid/small:body");
// set bodyown for owned atoms
nlocal_body = 0;
for (i = 0; i < nlocal; i++)
if (bodytag[i] == tag[i]) {
body[nlocal_body].ilocal = i;
bodyown[i] = nlocal_body++;
} else bodyown[i] = -1;
// bodysize = sizeof(Body) in doubles
bodysize = sizeof(Body)/sizeof(double);
if (bodysize*sizeof(double) != sizeof(Body)) bodysize++;
// set max comm sizes needed by this fix
comm_forward = 1 + bodysize;
comm_reverse = 6;
// bitmasks for properties of extended particles
POINT = 1;
SPHERE = 2;
ELLIPSOID = 4;
LINE = 8;
TRIANGLE = 16;
DIPOLE = 32;
OMEGA = 64;
ANGMOM = 128;
TORQUE = 256;
MINUSPI = -MY_PI;
TWOPI = 2.0*MY_PI;
// atom style pointers to particles that store extra info
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_line = (AtomVecLine *) atom->style_match("line");
avec_tri = (AtomVecTri *) atom->style_match("tri");
// print statistics
int one = 0;
bigint atomone = 0;
for (int i = 0; i < nlocal; i++) {
if (bodyown[i] >= 0) one++;
if (bodytag[i] > 0) atomone++;
}
MPI_Allreduce(&one,&nbody,1,MPI_INT,MPI_SUM,world);
bigint atomall;
MPI_Allreduce(&atomone,&atomall,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (me == 0) {
if (screen) {
fprintf(screen,"%d rigid bodies with " BIGINT_FORMAT " atoms\n",
nbody,atomall);
fprintf(screen," %g = max distance from body owner to body atom\n",
maxextent);
}
if (logfile) {
fprintf(logfile,"%d rigid bodies with " BIGINT_FORMAT " atoms\n",
nbody,atomall);
fprintf(logfile," %g = max distance from body owner to body atom\n",
maxextent);
}
}
// initialize Marsaglia RNG with processor-unique seed
maxlang = 0;
langextra = NULL;
random = NULL;
if (langflag) random = new RanMars(lmp,seed + comm->me);
// mass vector for granular pair styles
mass_body = NULL;
nmax_mass = 0;
// firstflag = 1 triggers one-time initialization of rigid body attributes
firstflag = 1;
}
/* ---------------------------------------------------------------------- */
FixRigidSmall::~FixRigidSmall()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
// delete locally stored arrays
memory->sfree(body);
memory->destroy(bodyown);
memory->destroy(bodytag);
memory->destroy(atom2body);
memory->destroy(displace);
memory->destroy(eflags);
memory->destroy(orient);
memory->destroy(dorient);
delete random;
delete [] infile;
memory->destroy(langextra);
memory->destroy(mass_body);
}
/* ---------------------------------------------------------------------- */
int FixRigidSmall::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= FINAL_INTEGRATE;
if (langflag) mask |= POST_FORCE;
mask |= PRE_NEIGHBOR;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::init()
{
int i;
triclinic = domain->triclinic;
// warn if more than one rigid fix
int count = 0;
for (i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"rigid") == 0) count++;
if (count > 1 && me == 0) error->warning(FLERR,"More than one fix rigid");
// error if npt,nph fix comes before rigid 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,"rigid") == 0)
error->all(FLERR,"Rigid fix must come before NPT/NPH fix");
}
// timestep info
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dtq = 0.5 * update->dt;
if (strstr(update->integrate_style,"respa"))
step_respa = ((Respa *) update->integrate)->step;
}
/* ----------------------------------------------------------------------
one-time initialization of rigid body attributes via local comm
extended flags, mass, COM, inertia tensor, displacement of each atom
performed after init() b/c requires communication stencil
has been setup by comm->borders()
------------------------------------------------------------------------- */
void FixRigidSmall::setup_pre_neighbor()
{
if (firstflag) {
firstflag = 0;
setup_bodies_static();
setup_bodies_dynamic();
} else pre_neighbor();
}
/* ----------------------------------------------------------------------
compute initial fcm and torque on bodies, also initial virial
reset all particle velocities to be consistent with vcm and omega
------------------------------------------------------------------------- */
void FixRigidSmall::setup(int vflag)
{
int i,n,ibody;
double massone,radone;
//check(1);
// sum fcm, torque across all rigid bodies
// fcm = force on COM
// torque = torque around COM
double **x = atom->x;
double **f = atom->f;
int *type = atom->type;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double *xcm,*fcm,*tcm;
double dx,dy,dz;
double unwrap[3];
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
fcm = body[ibody].fcm;
fcm[0] = fcm[1] = fcm[2] = 0.0;
tcm = body[ibody].torque;
tcm[0] = tcm[1] = tcm[2] = 0.0;
}
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
fcm = b->fcm;
fcm[0] += f[i][0];
fcm[1] += f[i][1];
fcm[2] += f[i][2];
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
dx = unwrap[0] - xcm[0];
dy = unwrap[1] - xcm[1];
dz = unwrap[2] - xcm[2];
tcm = b->torque;
tcm[0] += dy * f[i][2] - dz * f[i][1];
tcm[1] += dz * f[i][0] - dx * f[i][2];
tcm[2] += dx * f[i][1] - dy * f[i][0];
}
// extended particles add their rotation/torque to angmom/torque of body
if (extended) {
double **torque = atom->torque;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (eflags[i] & TORQUE) {
tcm = b->torque;
tcm[0] += torque[i][0];
tcm[1] += torque[i][1];
tcm[2] += torque[i][2];
}
}
}
// reverse communicate fcm, torque of all bodies
commflag = FORCE_TORQUE;
comm->reverse_comm_variable_fix(this);
// virial setup before call to set_v
if (vflag) v_setup(vflag);
else evflag = 0;
// compute and forward communicate vcm and omega of all bodies
for (ibody = 0; ibody < nlocal_body; ibody++) {
Body *b = &body[ibody];
MathExtra::angmom_to_omega(b->angmom,b->ex_space,b->ey_space,
b->ez_space,b->inertia,b->omega);
}
commflag = FINAL;
comm->forward_comm_variable_fix(this);
// set velocity/rotation of atoms in rigid bodues
set_v();
// guesstimate virial as 2x the set_v contribution
if (vflag_global)
for (n = 0; n < 6; n++) virial[n] *= 2.0;
if (vflag_atom) {
for (i = 0; i < nlocal; i++)
for (n = 0; n < 6; n++)
vatom[i][n] *= 2.0;
}
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::initial_integrate(int vflag)
{
double dtfm;
//check(2);
for (int ibody = 0; ibody < nlocal_body; ibody++) {
Body *b = &body[ibody];
// update vcm by 1/2 step
dtfm = dtf / b->mass;
b->vcm[0] += dtfm * b->fcm[0];
b->vcm[1] += dtfm * b->fcm[1];
b->vcm[2] += dtfm * b->fcm[2];
// update xcm by full step
b->xcm[0] += dtv * b->vcm[0];
b->xcm[1] += dtv * b->vcm[1];
b->xcm[2] += dtv * b->vcm[2];
// update angular momentum by 1/2 step
b->angmom[0] += dtf * b->torque[0];
b->angmom[1] += dtf * b->torque[1];
b->angmom[2] += dtf * b->torque[2];
// compute omega at 1/2 step from angmom at 1/2 step and current q
// update quaternion a full step via Richardson iteration
// returns new normalized quaternion, also updated omega at 1/2 step
// update ex,ey,ez to reflect new quaternion
MathExtra::angmom_to_omega(b->angmom,b->ex_space,b->ey_space,
b->ez_space,b->inertia,b->omega);
MathExtra::richardson(b->quat,b->angmom,b->omega,b->inertia,dtq);
MathExtra::q_to_exyz(b->quat,b->ex_space,b->ey_space,b->ez_space);
}
// virial setup before call to set_xv
if (vflag) v_setup(vflag);
else evflag = 0;
// forward communicate updated info of all bodies
commflag = INITIAL;
comm->forward_comm_variable_fix(this);
// set coords/orient and velocity/rotation of atoms in rigid bodies
set_xv();
}
/* ----------------------------------------------------------------------
apply Langevin thermostat to all 6 DOF of rigid bodies I own
unlike fix langevin, this stores extra force in extra arrays,
which are added in when final_integrate() calculates a new fcm/torque
------------------------------------------------------------------------- */
void FixRigidSmall::post_force(int vflag)
{
double gamma1,gamma2;
// grow langextra if needed
if (nlocal_body > maxlang) {
memory->destroy(langextra);
maxlang = nlocal_body + nghost_body;
memory->create(langextra,maxlang,6,"rigid/small:langextra");
}
double delta = update->ntimestep - update->beginstep;
delta /= update->endstep - update->beginstep;
double t_target = t_start + delta * (t_stop-t_start);
double tsqrt = sqrt(t_target);
double boltz = force->boltz;
double dt = update->dt;
double mvv2e = force->mvv2e;
double ftm2v = force->ftm2v;
double *vcm,*omega,*inertia;
for (int ibody = 0; ibody < nlocal_body; ibody++) {
vcm = body[ibody].vcm;
omega = body[ibody].omega;
inertia = body[ibody].inertia;
gamma1 = -body[ibody].mass / t_period / ftm2v;
gamma2 = sqrt(body[ibody].mass) * tsqrt *
sqrt(24.0*boltz/t_period/dt/mvv2e) / ftm2v;
langextra[ibody][0] = gamma1*vcm[0] + gamma2*(random->uniform()-0.5);
langextra[ibody][1] = gamma1*vcm[1] + gamma2*(random->uniform()-0.5);
langextra[ibody][2] = gamma1*vcm[2] + gamma2*(random->uniform()-0.5);
gamma1 = -1.0 / t_period / ftm2v;
gamma2 = tsqrt * sqrt(24.0*boltz/t_period/dt/mvv2e) / ftm2v;
langextra[ibody][3] = inertia[0]*gamma1*omega[0] +
sqrt(inertia[0])*gamma2*(random->uniform()-0.5);
langextra[ibody][4] = inertia[1]*gamma1*omega[1] +
sqrt(inertia[1])*gamma2*(random->uniform()-0.5);
langextra[ibody][5] = inertia[2]*gamma1*omega[2] +
sqrt(inertia[2])*gamma2*(random->uniform()-0.5);
}
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::final_integrate()
{
int i,ibody;
double dtfm;
//check(3);
// sum over atoms to get force and torque on rigid body
imageint *image = atom->image;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
double dx,dy,dz;
double unwrap[3];
double *xcm,*fcm,*tcm;
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
fcm = body[ibody].fcm;
fcm[0] = fcm[1] = fcm[2] = 0.0;
tcm = body[ibody].torque;
tcm[0] = tcm[1] = tcm[2] = 0.0;
}
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
fcm = b->fcm;
fcm[0] += f[i][0];
fcm[1] += f[i][1];
fcm[2] += f[i][2];
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
dx = unwrap[0] - xcm[0];
dy = unwrap[1] - xcm[1];
dz = unwrap[2] - xcm[2];
tcm = b->torque;
tcm[0] += dy*f[i][2] - dz*f[i][1];
tcm[1] += dz*f[i][0] - dx*f[i][2];
tcm[2] += dx*f[i][1] - dy*f[i][0];
}
// extended particles add their torque to torque of body
if (extended) {
double **torque = atom->torque;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
if (eflags[i] & TORQUE) {
tcm = body[atom2body[i]].torque;
tcm[0] += torque[i][0];
tcm[1] += torque[i][1];
tcm[2] += torque[i][2];
}
}
}
// reverse communicate fcm, torque of all bodies
commflag = FORCE_TORQUE;
comm->reverse_comm_variable_fix(this);
// include Langevin thermostat forces and torques
if (langflag) {
for (int ibody = 0; ibody < nlocal_body; ibody++) {
fcm = body[ibody].fcm;
fcm[0] += langextra[ibody][0];
fcm[1] += langextra[ibody][1];
fcm[2] += langextra[ibody][2];
tcm = body[ibody].torque;
tcm[0] += langextra[ibody][3];
tcm[1] += langextra[ibody][4];
tcm[2] += langextra[ibody][5];
}
}
// update vcm and angmom, recompute omega
for (int ibody = 0; ibody < nlocal_body; ibody++) {
Body *b = &body[ibody];
// update vcm by 1/2 step
dtfm = dtf / b->mass;
b->vcm[0] += dtfm * b->fcm[0];
b->vcm[1] += dtfm * b->fcm[1];
b->vcm[2] += dtfm * b->fcm[2];
// update angular momentum by 1/2 step
b->angmom[0] += dtf * b->torque[0];
b->angmom[1] += dtf * b->torque[1];
b->angmom[2] += dtf * b->torque[2];
MathExtra::angmom_to_omega(b->angmom,b->ex_space,b->ey_space,
b->ez_space,b->inertia,b->omega);
}
// forward communicate updated info of all bodies
commflag = FINAL;
comm->forward_comm_variable_fix(this);
// set velocity/rotation of atoms in rigid bodies
// virial is already setup from initial_integrate
set_v();
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::initial_integrate_respa(int vflag, int ilevel, int iloop)
{
dtv = step_respa[ilevel];
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
dtq = 0.5 * step_respa[ilevel];
if (ilevel == 0) initial_integrate(vflag);
else final_integrate();
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::final_integrate_respa(int ilevel, int iloop)
{
dtf = 0.5 * step_respa[ilevel] * force->ftm2v;
final_integrate();
}
/* ----------------------------------------------------------------------
atom to processor assignments have changed,
so acquire ghost bodies and setup atom2body
remap xcm of each rigid body back into periodic simulation box
done during pre_neighbor so will be after call to pbc()
and after fix_deform::pre_exchange() may have flipped box
use domain->remap() in case xcm is far away from box
due to 1st definition of rigid body or due to box flip
if don't do this, then atoms of a body which drifts far away
from a triclinic box will be remapped back into box
with huge displacements when the box tilt changes via set_x()
adjust image flag of body and image flags of all atoms in body
------------------------------------------------------------------------- */
void FixRigidSmall::pre_neighbor()
{
// remap xcm and image flags of each body as needed
imageint original,oldimage,newimage;
for (int ibody = 0; ibody < nlocal_body; ibody++) {
Body *b = &body[ibody];
original = b->image;
domain->remap(b->xcm,b->image);
if (original == b->image) b->remapflag[3] = 0;
else {
oldimage = original & IMGMASK;
newimage = b->image & IMGMASK;
b->remapflag[0] = newimage - oldimage;
oldimage = (original >> IMGBITS) & IMGMASK;
newimage = (b->image >> IMGBITS) & IMGMASK;
b->remapflag[1] = newimage - oldimage;
oldimage = original >> IMG2BITS;
newimage = b->image >> IMG2BITS;
b->remapflag[2] = newimage - oldimage;
b->remapflag[3] = 1;
}
}
// acquire ghost bodies via forward comm
// also gets new remapflags needed for adjusting atom image flags
// reset atom2body for owned atoms
// forward comm sets atom2body for ghost atoms
nghost_body = 0;
commflag = FULL_BODY;
comm->forward_comm_variable_fix(this);
reset_atom2body();
//check(4);
// adjust image flags of any atom in a rigid body whose xcm was remapped
imageint *image = atom->image;
int nlocal = atom->nlocal;
imageint idim,otherdims;
for (int i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (b->remapflag[3] == 0) continue;
if (b->remapflag[0]) {
idim = image[i] & IMGMASK;
otherdims = image[i] ^ idim;
idim -= b->remapflag[0];
idim &= IMGMASK;
image[i] = otherdims | idim;
}
if (b->remapflag[1]) {
idim = (image[i] >> IMGBITS) & IMGMASK;
otherdims = image[i] ^ (idim << IMGBITS);
idim -= b->remapflag[1];
idim &= IMGMASK;
image[i] = otherdims | (idim << IMGBITS);
}
if (b->remapflag[2]) {
idim = image[i] >> IMG2BITS;
otherdims = image[i] ^ (idim << IMG2BITS);
idim -= b->remapflag[2];
idim &= IMGMASK;
image[i] = otherdims | (idim << IMG2BITS);
}
}
}
/* ----------------------------------------------------------------------
count # of DOF removed by rigid bodies for atoms in igroup
return total count of DOF
------------------------------------------------------------------------- */
int FixRigidSmall::dof(int tgroup)
{
int i,j;
// cannot count DOF correctly unless setup_bodies_static() has been called
if (firstflag) {
if (comm->me == 0)
error->warning(FLERR,"Cannot count rigid body degrees-of-freedom "
"before bodies are fully initialized");
return 0;
}
int tgroupbit = group->bitmask[tgroup];
// counts = 3 values per rigid body I own
// 0 = # of point particles in rigid body and in temperature group
// 1 = # of finite-size particles in rigid body and in temperature group
// 2 = # of particles in rigid body, disregarding temperature group
memory->create(counts,nlocal_body+nghost_body,3,"rigid/small:counts");
for (int i = 0; i < nlocal_body+nghost_body; i++)
counts[i][0] = counts[i][1] = counts[i][2] = 0;
// tally counts from my owned atoms
// 0 = # of point particles in rigid body and in temperature group
// 1 = # of finite-size particles in rigid body and in temperature group
// 2 = # of particles in rigid body, disregarding temperature group
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
j = atom2body[i];
counts[j][2]++;
if (mask[i] & tgroupbit) {
if (extended && eflags[i]) counts[j][1]++;
else counts[j][0]++;
}
}
commflag = DOF;
comm->reverse_comm_variable_fix(this);
// nall = count0 = # of point particles in each rigid body
// mall = count1 = # of finite-size particles in each rigid body
// warn if nall+mall != nrigid for any body included in temperature group
int flag = 0;
for (int ibody = 0; ibody < nlocal_body; ibody++) {
if (counts[ibody][0]+counts[ibody][1] > 0 &&
counts[ibody][0]+counts[ibody][1] != counts[ibody][2]) flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall && me == 0)
error->warning(FLERR,"Computing temperature of portions of rigid bodies");
// remove appropriate DOFs for each rigid body wholly in temperature group
// N = # of point particles in body
// M = # of finite-size particles in body
// 3d body has 3N + 6M dof to start with
// 2d body has 2N + 3M dof to start with
// 3d point-particle body with all non-zero I should have 6 dof, remove 3N-6
// 3d point-particle body (linear) with a 0 I should have 5 dof, remove 3N-5
// 2d point-particle body should have 3 dof, remove 2N-3
// 3d body with any finite-size M should have 6 dof, remove (3N+6M) - 6
// 2d body with any finite-size M should have 3 dof, remove (2N+3M) - 3
double *inertia;
int n = 0;
if (domain->dimension == 3) {
for (int ibody = 0; ibody < nlocal_body; ibody++) {
if (counts[ibody][0]+counts[ibody][1] == counts[ibody][2]) {
n += 3*counts[ibody][0] + 6*counts[ibody][1] - 6;
inertia = body[ibody].inertia;
if (inertia[0] == 0.0 || inertia[1] == 0.0 || inertia[2] == 0.0) n++;
}
}
} else if (domain->dimension == 2) {
for (int ibody = 0; ibody < nlocal_body; ibody++)
if (counts[ibody][0]+counts[ibody][1] == counts[ibody][2])
n += 2*counts[ibody][0] + 3*counts[ibody][1] - 3;
}
memory->destroy(counts);
int nall;
MPI_Allreduce(&n,&nall,1,MPI_INT,MPI_SUM,world);
return nall;
}
/* ----------------------------------------------------------------------
adjust xcm of each rigid body due to box deformation
called by various fixes that change box size/shape
flag = 0/1 means map from box to lamda coords or vice versa
------------------------------------------------------------------------- */
void FixRigidSmall::deform(int flag)
{
if (flag == 0)
for (int ibody = 0; ibody < nlocal_body; ibody++)
domain->x2lamda(body[ibody].xcm,body[ibody].xcm);
else
for (int ibody = 0; ibody < nlocal_body; ibody++)
domain->lamda2x(body[ibody].xcm,body[ibody].xcm);
}
/* ----------------------------------------------------------------------
set space-frame coords and velocity of each atom in each rigid body
set orientation and rotation of extended particles
x = Q displace + Xcm, mapped back to periodic box
v = Vcm + (W cross (x - Xcm))
------------------------------------------------------------------------- */
void FixRigidSmall::set_xv()
{
int xbox,ybox,zbox;
double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
double ione[3],exone[3],eyone[3],ezone[3],vr[6],p[3][3];
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
imageint *image = atom->image;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int nlocal = atom->nlocal;
// set x and v of each atom
for (int i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
// save old positions and velocities for virial
if (evflag) {
if (triclinic == 0) {
x0 = x[i][0] + xbox*xprd;
x1 = x[i][1] + ybox*yprd;
x2 = x[i][2] + zbox*zprd;
} else {
x0 = x[i][0] + xbox*xprd + ybox*xy + zbox*xz;
x1 = x[i][1] + ybox*yprd + zbox*yz;
x2 = x[i][2] + zbox*zprd;
}
v0 = v[i][0];
v1 = v[i][1];
v2 = v[i][2];
}
// x = displacement from center-of-mass, based on body orientation
// v = vcm + omega around center-of-mass
MathExtra::matvec(b->ex_space,b->ey_space,b->ez_space,displace[i],x[i]);
v[i][0] = b->omega[1]*x[i][2] - b->omega[2]*x[i][1] + b->vcm[0];
v[i][1] = b->omega[2]*x[i][0] - b->omega[0]*x[i][2] + b->vcm[1];
v[i][2] = b->omega[0]*x[i][1] - b->omega[1]*x[i][0] + b->vcm[2];
// add center of mass to displacement
// map back into periodic box via xbox,ybox,zbox
// for triclinic, add in box tilt factors as well
if (triclinic == 0) {
x[i][0] += b->xcm[0] - xbox*xprd;
x[i][1] += b->xcm[1] - ybox*yprd;
x[i][2] += b->xcm[2] - zbox*zprd;
} else {
x[i][0] += b->xcm[0] - xbox*xprd - ybox*xy - zbox*xz;
x[i][1] += b->xcm[1] - ybox*yprd - zbox*yz;
x[i][2] += b->xcm[2] - zbox*zprd;
}
// virial = unwrapped coords dotted into body constraint force
// body constraint force = implied force due to v change minus f external
// assume f does not include forces internal to body
// 1/2 factor b/c final_integrate contributes other half
// assume per-atom contribution is due to constraint force on that atom
if (evflag) {
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
fc0 = massone*(v[i][0] - v0)/dtf - f[i][0];
fc1 = massone*(v[i][1] - v1)/dtf - f[i][1];
fc2 = massone*(v[i][2] - v2)/dtf - f[i][2];
vr[0] = 0.5*x0*fc0;
vr[1] = 0.5*x1*fc1;
vr[2] = 0.5*x2*fc2;
vr[3] = 0.5*x0*fc1;
vr[4] = 0.5*x0*fc2;
vr[5] = 0.5*x1*fc2;
v_tally(1,&i,1.0,vr);
}
}
// set orientation, omega, angmom of each extended particle
if (extended) {
double theta_body,theta;
double *shape,*quatatom,*inertiaatom;
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double **omega = atom->omega;
double **angmom = atom->angmom;
double **mu = atom->mu;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
for (int i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (eflags[i] & SPHERE) {
omega[i][0] = b->omega[0];
omega[i][1] = b->omega[1];
omega[i][2] = b->omega[2];
} else if (eflags[i] & ELLIPSOID) {
shape = ebonus[ellipsoid[i]].shape;
quatatom = ebonus[ellipsoid[i]].quat;
MathExtra::quatquat(b->quat,orient[i],quatatom);
MathExtra::qnormalize(quatatom);
ione[0] = EINERTIA*rmass[i] * (shape[1]*shape[1] + shape[2]*shape[2]);
ione[1] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[2]*shape[2]);
ione[2] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[1]*shape[1]);
MathExtra::q_to_exyz(quatatom,exone,eyone,ezone);
MathExtra::omega_to_angmom(b->omega,exone,eyone,ezone,ione,angmom[i]);
} else if (eflags[i] & LINE) {
if (b->quat[3] >= 0.0) theta_body = 2.0*acos(b->quat[0]);
else theta_body = -2.0*acos(b->quat[0]);
theta = orient[i][0] + theta_body;
while (theta <= MINUSPI) theta += TWOPI;
while (theta > MY_PI) theta -= TWOPI;
lbonus[line[i]].theta = theta;
omega[i][0] = b->omega[0];
omega[i][1] = b->omega[1];
omega[i][2] = b->omega[2];
} else if (eflags[i] & TRIANGLE) {
inertiaatom = tbonus[tri[i]].inertia;
quatatom = tbonus[tri[i]].quat;
MathExtra::quatquat(b->quat,orient[i],quatatom);
MathExtra::qnormalize(quatatom);
MathExtra::q_to_exyz(quatatom,exone,eyone,ezone);
MathExtra::omega_to_angmom(b->omega,exone,eyone,ezone,
inertiaatom,angmom[i]);
}
if (eflags[i] & DIPOLE) {
MathExtra::quat_to_mat(b->quat,p);
MathExtra::matvec(p,dorient[i],mu[i]);
MathExtra::snormalize3(mu[i][3],mu[i],mu[i]);
}
}
}
}
/* ----------------------------------------------------------------------
set space-frame velocity of each atom in a rigid body
set omega and angmom of extended particles
v = Vcm + (W cross (x - Xcm))
------------------------------------------------------------------------- */
void FixRigidSmall::set_v()
{
int xbox,ybox,zbox;
double x0,x1,x2,v0,v1,v2,fc0,fc1,fc2,massone;
double ione[3],exone[3],eyone[3],ezone[3],delta[3],vr[6];
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
imageint *image = atom->image;
int nlocal = atom->nlocal;
// set v of each atom
for (int i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
MathExtra::matvec(b->ex_space,b->ey_space,b->ez_space,displace[i],delta);
// save old velocities for virial
if (evflag) {
v0 = v[i][0];
v1 = v[i][1];
v2 = v[i][2];
}
v[i][0] = b->omega[1]*delta[2] - b->omega[2]*delta[1] + b->vcm[0];
v[i][1] = b->omega[2]*delta[0] - b->omega[0]*delta[2] + b->vcm[1];
v[i][2] = b->omega[0]*delta[1] - b->omega[1]*delta[0] + b->vcm[2];
// virial = unwrapped coords dotted into body constraint force
// body constraint force = implied force due to v change minus f external
// assume f does not include forces internal to body
// 1/2 factor b/c initial_integrate contributes other half
// assume per-atom contribution is due to constraint force on that atom
if (evflag) {
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
fc0 = massone*(v[i][0] - v0)/dtf - f[i][0];
fc1 = massone*(v[i][1] - v1)/dtf - f[i][1];
fc2 = massone*(v[i][2] - v2)/dtf - f[i][2];
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
if (triclinic == 0) {
x0 = x[i][0] + xbox*xprd;
x1 = x[i][1] + ybox*yprd;
x2 = x[i][2] + zbox*zprd;
} else {
x0 = x[i][0] + xbox*xprd + ybox*xy + zbox*xz;
x1 = x[i][1] + ybox*yprd + zbox*yz;
x2 = x[i][2] + zbox*zprd;
}
vr[0] = 0.5*x0*fc0;
vr[1] = 0.5*x1*fc1;
vr[2] = 0.5*x2*fc2;
vr[3] = 0.5*x0*fc1;
vr[4] = 0.5*x0*fc2;
vr[5] = 0.5*x1*fc2;
v_tally(1,&i,1.0,vr);
}
}
// set omega, angmom of each extended particle
if (extended) {
double *shape,*quatatom,*inertiaatom;
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double **omega = atom->omega;
double **angmom = atom->angmom;
int *ellipsoid = atom->ellipsoid;
int *tri = atom->tri;
for (int i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (eflags[i] & SPHERE) {
omega[i][0] = b->omega[0];
omega[i][1] = b->omega[1];
omega[i][2] = b->omega[2];
} else if (eflags[i] & ELLIPSOID) {
shape = ebonus[ellipsoid[i]].shape;
quatatom = ebonus[ellipsoid[i]].quat;
ione[0] = EINERTIA*rmass[i] * (shape[1]*shape[1] + shape[2]*shape[2]);
ione[1] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[2]*shape[2]);
ione[2] = EINERTIA*rmass[i] * (shape[0]*shape[0] + shape[1]*shape[1]);
MathExtra::q_to_exyz(quatatom,exone,eyone,ezone);
MathExtra::omega_to_angmom(b->omega,exone,eyone,ezone,ione,
angmom[i]);
} else if (eflags[i] & LINE) {
omega[i][0] = b->omega[0];
omega[i][1] = b->omega[1];
omega[i][2] = b->omega[2];
} else if (eflags[i] & TRIANGLE) {
inertiaatom = tbonus[tri[i]].inertia;
quatatom = tbonus[tri[i]].quat;
MathExtra::q_to_exyz(quatatom,exone,eyone,ezone);
MathExtra::omega_to_angmom(b->omega,exone,eyone,ezone,
inertiaatom,angmom[i]);
}
}
}
}
/* ----------------------------------------------------------------------
one-time identification of which atoms are in which rigid bodies
set bodytag for all owned atoms
------------------------------------------------------------------------- */
void FixRigidSmall::create_bodies()
{
int i,m,n;
double unwrap[3];
// error check on image flags of atoms in rigid bodies
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int *periodicity = domain->periodicity;
int xbox,ybox,zbox;
int flag = 0;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
if ((xbox && !periodicity[0]) || (ybox && !periodicity[1]) ||
(zbox && !periodicity[2])) flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) error->all(FLERR,"Fix rigid/small atom has non-zero image flag "
"in a non-periodic dimension");
// allocate buffer for passing messages around ring of procs
// percount = max number of values to put in buffer for each of ncount
int ncount = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) ncount++;
int percount = 5;
double *buf;
memory->create(buf,ncount*percount,"rigid/small:buf");
// create map hash for storing unique molecule IDs of my atoms
// key = molecule ID
// value = index into per-body data structure
// n = # of entries in hash
hash = new std::map<int,int>();
hash->clear();
// setup hash
// key = body ID
// value = index into N-length data structure
// n = count of unique bodies my atoms are part of
int *molecule = atom->molecule;
n = 0;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
if (hash->find(molecule[i]) == hash->end()) (*hash)[molecule[i]] = n++;
}
// bbox = bounding box of each rigid body my atoms are part of
memory->create(bbox,n,6,"rigid/small:bbox");
for (i = 0; i < n; i++) {
bbox[i][0] = bbox[i][2] = bbox[i][4] = BIG;
bbox[i][1] = bbox[i][3] = bbox[i][5] = -BIG;
}
// pack my atoms into buffer as molecule ID, unwrapped coords
double **x = atom->x;
m = 0;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
domain->unmap(x[i],image[i],unwrap);
buf[m++] = molecule[i];
buf[m++] = unwrap[0];
buf[m++] = unwrap[1];
buf[m++] = unwrap[2];
}
// pass buffer around ring of procs
// func = update bbox with atom coords from every proc
// when done, have full bbox for every rigid body my atoms are part of
frsptr = this;
comm->ring(m,sizeof(double),buf,1,ring_bbox,NULL);
// ctr = center pt of each rigid body my atoms are part of
memory->create(ctr,n,6,"rigid/small:bbox");
for (i = 0; i < n; i++) {
ctr[i][0] = 0.5 * (bbox[i][0] + bbox[i][1]);
ctr[i][1] = 0.5 * (bbox[i][2] + bbox[i][3]);
ctr[i][2] = 0.5 * (bbox[i][4] + bbox[i][5]);
}
// idclose = ID of atom in body closest to center pt (smaller ID if tied)
// rsqclose = distance squared from idclose to center pt
memory->create(idclose,n,"rigid/small:idclose");
memory->create(rsqclose,n,"rigid/small:rsqclose");
for (i = 0; i < n; i++) rsqclose[i] = BIG;
// pack my atoms into buffer as molecule ID, atom ID, unwrapped coords
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
m = 0;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
domain->unmap(x[i],image[i],unwrap);
buf[m++] = molecule[i];
- buf[m++] = tag[i];
+ buf[m++] = ubuf(tag[i]).d;
buf[m++] = unwrap[0];
buf[m++] = unwrap[1];
buf[m++] = unwrap[2];
}
// pass buffer around ring of procs
// func = update idclose,rsqclose with atom IDs from every proc
// when done, have idclose for every rigid body my atoms are part of
frsptr = this;
comm->ring(m,sizeof(double),buf,2,ring_nearest,NULL);
// set bodytag of all owned atoms, based on idclose
// find max value of rsqclose across all procs
double rsqmax = 0.0;
for (i = 0; i < nlocal; i++) {
bodytag[i] = 0;
if (!(mask[i] & groupbit)) continue;
m = hash->find(molecule[i])->second;
bodytag[i] = idclose[m];
rsqmax = MAX(rsqmax,rsqclose[m]);
}
// pack my atoms into buffer as bodytag of owning atom, unwrapped coords
m = 0;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
domain->unmap(x[i],image[i],unwrap);
- buf[m++] = bodytag[i];
+ buf[m++] = ubuf(bodytag[i]).i;
buf[m++] = unwrap[0];
buf[m++] = unwrap[1];
buf[m++] = unwrap[2];
}
// pass buffer around ring of procs
// func = update rsqfar for atoms belonging to bodies I own
// when done, have rsqfar for all atoms in bodies I own
rsqfar = 0.0;
frsptr = this;
comm->ring(m,sizeof(double),buf,3,ring_farthest,NULL);
// find maxextent of rsqfar across all procs
// if defined, include molecule->maxextent
MPI_Allreduce(&rsqfar,&maxextent,1,MPI_DOUBLE,MPI_MAX,world);
maxextent = sqrt(maxextent);
if (onemol) maxextent = MAX(maxextent,onemol->maxextent);
// clean up
delete hash;
memory->destroy(buf);
memory->destroy(bbox);
memory->destroy(ctr);
memory->destroy(idclose);
memory->destroy(rsqclose);
}
/* ----------------------------------------------------------------------
process rigid body atoms from another proc
update bounding box for rigid bodies my atoms are part of
------------------------------------------------------------------------- */
void FixRigidSmall::ring_bbox(int n, char *cbuf)
{
std::map<int,int> *hash = frsptr->hash;
double **bbox = frsptr->bbox;
double *buf = (double *) cbuf;
int ndatums = n/4;
int j,imol;
double *x;
int m = 0;
for (int i = 0; i < ndatums; i++, m += 4) {
imol = static_cast<int> (buf[m]);
if (hash->find(imol) != hash->end()) {
j = hash->find(imol)->second;
x = &buf[m+1];
bbox[j][0] = MIN(bbox[j][0],x[0]);
bbox[j][1] = MAX(bbox[j][1],x[0]);
bbox[j][2] = MIN(bbox[j][2],x[1]);
bbox[j][3] = MAX(bbox[j][3],x[1]);
bbox[j][4] = MIN(bbox[j][4],x[2]);
bbox[j][5] = MAX(bbox[j][5],x[2]);
}
}
}
/* ----------------------------------------------------------------------
process rigid body atoms from another proc
update nearest atom to body center for rigid bodies my atoms are part of
------------------------------------------------------------------------- */
void FixRigidSmall::ring_nearest(int n, char *cbuf)
{
std::map<int,int> *hash = frsptr->hash;
double **ctr = frsptr->ctr;
- int *idclose = frsptr->idclose;
+ tagint *idclose = frsptr->idclose;
double *rsqclose = frsptr->rsqclose;
double *buf = (double *) cbuf;
int ndatums = n/5;
- int j,imol,tag;
+ int j,imol;
+ tagint tag;
double delx,dely,delz,rsq;
double *x;
int m = 0;
for (int i = 0; i < ndatums; i++, m += 5) {
imol = static_cast<int> (buf[m]);
if (hash->find(imol) != hash->end()) {
j = hash->find(imol)->second;
- tag = static_cast<int> (buf[m+1]);
+ tag = (tagint) ubuf(buf[m+1]).i;
x = &buf[m+2];
delx = x[0] - ctr[j][0];
dely = x[1] - ctr[j][1];
delz = x[2] - ctr[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= rsqclose[j]) {
if (rsq == rsqclose[j] && tag > idclose[j]) continue;
idclose[j] = tag;
rsqclose[j] = rsq;
}
}
}
}
/* ----------------------------------------------------------------------
process rigid body atoms from another proc
update rsqfar = distance from owning atom to other atom
------------------------------------------------------------------------- */
void FixRigidSmall::ring_farthest(int n, char *cbuf)
{
double **x = frsptr->atom->x;
imageint *image = frsptr->atom->image;
int nlocal = frsptr->atom->nlocal;
double *buf = (double *) cbuf;
int ndatums = n/4;
- int itag,iowner;
+ int iowner;
+ tagint tag;
double delx,dely,delz,rsq;
double *xx;
double unwrap[3];
int m = 0;
for (int i = 0; i < ndatums; i++, m += 4) {
- itag = static_cast<int> (buf[m]);
- iowner = frsptr->atom->map(itag);
+ tag = (tagint) ubuf(buf[m]).i;
+ iowner = frsptr->atom->map(tag);
if (iowner < 0 || iowner >= nlocal) continue;
frsptr->domain->unmap(x[iowner],image[iowner],unwrap);
xx = &buf[m+1];
delx = xx[0] - unwrap[0];
dely = xx[1] - unwrap[1];
delz = xx[2] - unwrap[2];
rsq = delx*delx + dely*dely + delz*delz;
frsptr->rsqfar = MAX(frsptr->rsqfar,rsq);
}
}
/* ----------------------------------------------------------------------
one-time initialization of rigid body attributes
extended flags, mass, center-of-mass
Cartesian and diagonalized inertia tensor
read per-body attributes from infile if specified
------------------------------------------------------------------------- */
void FixRigidSmall::setup_bodies_static()
{
int i,ibody;
// extended = 1 if any particle in a rigid body is finite size
// or has a dipole moment
extended = orientflag = dorientflag = 0;
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double **mu = atom->mu;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
int *type = atom->type;
int nlocal = atom->nlocal;
if (atom->radius_flag || atom->ellipsoid_flag || atom->line_flag ||
atom->tri_flag || atom->mu_flag) {
int flag = 0;
for (i = 0; i < nlocal; i++) {
if (bodytag[i] == 0) continue;
if (radius && radius[i] > 0.0) flag = 1;
if (ellipsoid && ellipsoid[i] >= 0) flag = 1;
if (line && line[i] >= 0) flag = 1;
if (tri && tri[i] >= 0) flag = 1;
if (mu && mu[i][3] > 0.0) flag = 1;
}
MPI_Allreduce(&flag,&extended,1,MPI_INT,MPI_MAX,world);
}
// extended = 1 if using molecule template with finite-size particles
if (onemol && onemol->radiusflag) extended = 1;
// grow extended arrays and set extended flags for each particle
// orientflag = 4 if any particle stores ellipsoid or tri orientation
// orientflag = 1 if any particle stores line orientation
// dorientflag = 1 if any particle stores dipole orientation
if (extended) {
if (atom->ellipsoid_flag) orientflag = 4;
if (atom->line_flag) orientflag = 1;
if (atom->tri_flag) orientflag = 4;
if (atom->mu_flag) dorientflag = 1;
grow_arrays(atom->nmax);
for (i = 0; i < nlocal; i++) {
eflags[i] = 0;
if (bodytag[i] == 0) continue;
// set to POINT or SPHERE or ELLIPSOID or LINE
if (radius && radius[i] > 0.0) {
eflags[i] |= SPHERE;
eflags[i] |= OMEGA;
eflags[i] |= TORQUE;
} else if (ellipsoid && ellipsoid[i] >= 0) {
eflags[i] |= ELLIPSOID;
eflags[i] |= ANGMOM;
eflags[i] |= TORQUE;
} else if (line && line[i] >= 0) {
eflags[i] |= LINE;
eflags[i] |= OMEGA;
eflags[i] |= TORQUE;
} else if (tri && tri[i] >= 0) {
eflags[i] |= TRIANGLE;
eflags[i] |= ANGMOM;
eflags[i] |= TORQUE;
} else eflags[i] |= POINT;
// set DIPOLE if atom->mu and mu[3] > 0.0
if (atom->mu_flag && mu[i][3] > 0.0)
eflags[i] |= DIPOLE;
}
}
// acquire ghost bodies via forward comm
// set atom2body for ghost atoms via forward comm
// set atom2body for other owned atoms via reset_atom2body()
nghost_body = 0;
commflag = FULL_BODY;
comm->forward_comm_variable_fix(this);
reset_atom2body();
// compute mass & center-of-mass of each rigid body
double **x = atom->x;
imageint *image = atom->image;
double *xcm;
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
xcm = body[ibody].xcm;
xcm[0] = xcm[1] = xcm[2] = 0.0;
body[ibody].mass = 0.0;
}
double unwrap[3];
double massone;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
xcm[0] += unwrap[0] * massone;
xcm[1] += unwrap[1] * massone;
xcm[2] += unwrap[2] * massone;
b->mass += massone;
}
// reverse communicate xcm, mass of all bodies
commflag = XCM_MASS;
comm->reverse_comm_variable_fix(this);
for (ibody = 0; ibody < nlocal_body; ibody++) {
xcm = body[ibody].xcm;
xcm[0] /= body[ibody].mass;
xcm[1] /= body[ibody].mass;
xcm[2] /= body[ibody].mass;
}
// overwrite masstotal and center-of-mass with file values
// inbody[i] = 0/1 if Ith rigid body is initialized by file
int *inbody;
if (infile) {
memory->create(inbody,nlocal_body,"rigid/small:inbody");
for (ibody = 0; ibody < nlocal_body; ibody++) inbody[ibody] = 0;
readfile(0,NULL,inbody);
}
// set image flags for each rigid body to default values
// then remap the xcm of each body back into simulation box if needed
for (ibody = 0; ibody < nlocal_body; ibody++)
body[ibody].image = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
pre_neighbor();
// compute 6 moments of inertia of each body in Cartesian reference frame
// dx,dy,dz = coords relative to center-of-mass
// symmetric 3x3 inertia tensor stored in Voigt notation as 6-vector
memory->create(itensor,nlocal_body+nghost_body,6,"rigid/small:itensor");
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++)
for (i = 0; i < 6; i++) itensor[ibody][i] = 0.0;
double dx,dy,dz;
double *inertia;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
dx = unwrap[0] - xcm[0];
dy = unwrap[1] - xcm[1];
dz = unwrap[2] - xcm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
inertia = itensor[atom2body[i]];
inertia[0] += massone * (dy*dy + dz*dz);
inertia[1] += massone * (dx*dx + dz*dz);
inertia[2] += massone * (dx*dx + dy*dy);
inertia[3] -= massone * dy*dz;
inertia[4] -= massone * dx*dz;
inertia[5] -= massone * dx*dy;
}
// extended particles may contribute extra terms to moments of inertia
if (extended) {
double ivec[6];
double *shape,*quatatom,*inertiaatom;
double length,theta;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
inertia = itensor[atom2body[i]];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (eflags[i] & SPHERE) {
inertia[0] += SINERTIA*massone * radius[i]*radius[i];
inertia[1] += SINERTIA*massone * radius[i]*radius[i];
inertia[2] += SINERTIA*massone * radius[i]*radius[i];
} else if (eflags[i] & ELLIPSOID) {
shape = ebonus[ellipsoid[i]].shape;
quatatom = ebonus[ellipsoid[i]].quat;
MathExtra::inertia_ellipsoid(shape,quatatom,massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
} else if (eflags[i] & LINE) {
length = lbonus[line[i]].length;
theta = lbonus[line[i]].theta;
MathExtra::inertia_line(length,theta,massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
} else if (eflags[i] & TRIANGLE) {
inertiaatom = tbonus[tri[i]].inertia;
quatatom = tbonus[tri[i]].quat;
MathExtra::inertia_triangle(inertiaatom,quatatom,massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
}
}
}
// reverse communicate inertia tensor of all bodies
commflag = ITENSOR;
comm->reverse_comm_variable_fix(this);
// overwrite Cartesian inertia tensor with file values
if (infile) readfile(1,itensor,inbody);
// diagonalize inertia tensor for each body via Jacobi rotations
// inertia = 3 eigenvalues = principal moments of inertia
// evectors and exzy_space = 3 evectors = principal axes of rigid body
int ierror;
double cross[3];
double tensor[3][3],evectors[3][3];
double *ex,*ey,*ez;
for (ibody = 0; ibody < nlocal_body; ibody++) {
tensor[0][0] = itensor[ibody][0];
tensor[1][1] = itensor[ibody][1];
tensor[2][2] = itensor[ibody][2];
tensor[1][2] = tensor[2][1] = itensor[ibody][3];
tensor[0][2] = tensor[2][0] = itensor[ibody][4];
tensor[0][1] = tensor[1][0] = itensor[ibody][5];
inertia = body[ibody].inertia;
ierror = MathExtra::jacobi(tensor,inertia,evectors);
if (ierror) error->all(FLERR,
"Insufficient Jacobi rotations for rigid body");
ex = body[ibody].ex_space;
ex[0] = evectors[0][0];
ex[1] = evectors[1][0];
ex[2] = evectors[2][0];
ey = body[ibody].ey_space;
ey[0] = evectors[0][1];
ey[1] = evectors[1][1];
ey[2] = evectors[2][1];
ez = body[ibody].ez_space;
ez[0] = evectors[0][2];
ez[1] = evectors[1][2];
ez[2] = evectors[2][2];
// if any principal moment < scaled EPSILON, set to 0.0
double max;
max = MAX(inertia[0],inertia[1]);
max = MAX(max,inertia[2]);
if (inertia[0] < EPSILON*max) inertia[0] = 0.0;
if (inertia[1] < EPSILON*max) inertia[1] = 0.0;
if (inertia[2] < EPSILON*max) inertia[2] = 0.0;
// enforce 3 evectors as a right-handed coordinate system
// flip 3rd vector if needed
MathExtra::cross3(ex,ey,cross);
if (MathExtra::dot3(cross,ez) < 0.0) MathExtra::negate3(ez);
// create initial quaternion
MathExtra::exyz_to_q(ex,ey,ez,body[ibody].quat);
}
// forward communicate updated info of all bodies
commflag = INITIAL;
comm->forward_comm_variable_fix(this);
// displace = initial atom coords in basis of principal axes
// set displace = 0.0 for atoms not in any rigid body
// for extended particles, set their orientation wrt to rigid body
double qc[4],delta[3];
double *quatatom;
double theta_body;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) {
displace[i][0] = displace[i][1] = displace[i][2] = 0.0;
continue;
}
Body *b = &body[atom2body[i]];
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
delta[0] = unwrap[0] - xcm[0];
delta[1] = unwrap[1] - xcm[1];
delta[2] = unwrap[2] - xcm[2];
MathExtra::transpose_matvec(b->ex_space,b->ey_space,b->ez_space,
delta,displace[i]);
if (extended) {
if (eflags[i] & ELLIPSOID) {
quatatom = ebonus[ellipsoid[i]].quat;
MathExtra::qconjugate(b->quat,qc);
MathExtra::quatquat(qc,quatatom,orient[i]);
MathExtra::qnormalize(orient[i]);
} else if (eflags[i] & LINE) {
if (b->quat[3] >= 0.0) theta_body = 2.0*acos(b->quat[0]);
else theta_body = -2.0*acos(b->quat[0]);
orient[i][0] = lbonus[line[i]].theta - theta_body;
while (orient[i][0] <= MINUSPI) orient[i][0] += TWOPI;
while (orient[i][0] > MY_PI) orient[i][0] -= TWOPI;
if (orientflag == 4) orient[i][1] = orient[i][2] = orient[i][3] = 0.0;
} else if (eflags[i] & TRIANGLE) {
quatatom = tbonus[tri[i]].quat;
MathExtra::qconjugate(b->quat,qc);
MathExtra::quatquat(qc,quatatom,orient[i]);
MathExtra::qnormalize(orient[i]);
} else if (orientflag == 4) {
orient[i][0] = orient[i][1] = orient[i][2] = orient[i][3] = 0.0;
} else if (orientflag == 1)
orient[i][0] = 0.0;
if (eflags[i] & DIPOLE) {
MathExtra::transpose_matvec(b->ex_space,b->ey_space,b->ez_space,
mu[i],dorient[i]);
MathExtra::snormalize3(mu[i][3],dorient[i],dorient[i]);
} else if (dorientflag)
dorient[i][0] = dorient[i][1] = dorient[i][2] = 0.0;
}
}
// test for valid principal moments & axes
// recompute moments of inertia around new axes
// 3 diagonal moments should equal principal moments
// 3 off-diagonal moments should be 0.0
// extended particles may contribute extra terms to moments of inertia
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++)
for (i = 0; i < 6; i++) itensor[ibody][i] = 0.0;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
inertia = itensor[atom2body[i]];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
inertia[0] += massone *
(displace[i][1]*displace[i][1] + displace[i][2]*displace[i][2]);
inertia[1] += massone *
(displace[i][0]*displace[i][0] + displace[i][2]*displace[i][2]);
inertia[2] += massone *
(displace[i][0]*displace[i][0] + displace[i][1]*displace[i][1]);
inertia[3] -= massone * displace[i][1]*displace[i][2];
inertia[4] -= massone * displace[i][0]*displace[i][2];
inertia[5] -= massone * displace[i][0]*displace[i][1];
}
if (extended) {
double ivec[6];
double *shape,*inertiaatom;
double length;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
inertia = itensor[atom2body[i]];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (eflags[i] & SPHERE) {
inertia[0] += SINERTIA*massone * radius[i]*radius[i];
inertia[1] += SINERTIA*massone * radius[i]*radius[i];
inertia[2] += SINERTIA*massone * radius[i]*radius[i];
} else if (eflags[i] & ELLIPSOID) {
shape = ebonus[ellipsoid[i]].shape;
MathExtra::inertia_ellipsoid(shape,orient[i],massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
} else if (eflags[i] & LINE) {
length = lbonus[line[i]].length;
MathExtra::inertia_line(length,orient[i][0],massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
} else if (eflags[i] & TRIANGLE) {
inertiaatom = tbonus[tri[i]].inertia;
MathExtra::inertia_triangle(inertiaatom,orient[i],massone,ivec);
inertia[0] += ivec[0];
inertia[1] += ivec[1];
inertia[2] += ivec[2];
inertia[3] += ivec[3];
inertia[4] += ivec[4];
inertia[5] += ivec[5];
}
}
}
// reverse communicate inertia tensor of all bodies
commflag = ITENSOR;
comm->reverse_comm_variable_fix(this);
// error check that re-computed momemts of inertia match diagonalized ones
// do not do test for bodies with params read from infile
double norm;
for (ibody = 0; ibody < nlocal_body; ibody++) {
if (infile && inbody[ibody]) continue;
inertia = body[ibody].inertia;
if (inertia[0] == 0.0) {
if (fabs(itensor[ibody][0]) > TOLERANCE)
error->all(FLERR,"Fix rigid: Bad principal moments");
} else {
if (fabs((itensor[ibody][0]-inertia[0])/inertia[0]) >
TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments");
}
if (inertia[1] == 0.0) {
if (fabs(itensor[ibody][1]) > TOLERANCE)
error->all(FLERR,"Fix rigid: Bad principal moments");
} else {
if (fabs((itensor[ibody][1]-inertia[1])/inertia[1]) >
TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments");
}
if (inertia[2] == 0.0) {
if (fabs(itensor[ibody][2]) > TOLERANCE)
error->all(FLERR,"Fix rigid: Bad principal moments");
} else {
if (fabs((itensor[ibody][2]-inertia[2])/inertia[2]) >
TOLERANCE) error->all(FLERR,"Fix rigid: Bad principal moments");
}
norm = (inertia[0] + inertia[1] + inertia[2]) / 3.0;
if (fabs(itensor[ibody][3]/norm) > TOLERANCE ||
fabs(itensor[ibody][4]/norm) > TOLERANCE ||
fabs(itensor[ibody][5]/norm) > TOLERANCE)
error->all(FLERR,"Fix rigid: Bad principal moments");
}
// clean up
memory->destroy(itensor);
if (infile) memory->destroy(inbody);
}
/* ----------------------------------------------------------------------
one-time initialization of dynamic rigid body attributes
Vcm and angmom, computed explicitly from constituent particles
even if wrong for overlapping particles, is OK,
since is just setting initial time=0 Vcm and angmom of the body
which can be estimated value
------------------------------------------------------------------------- */
void FixRigidSmall::setup_bodies_dynamic()
{
int i,n,ibody;
double massone,radone;
// sum vcm, angmom across all rigid bodies
// vcm = velocity of COM
// angmom = angular momentum around COM
double **x = atom->x;
double **v = atom->v;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double *xcm,*vcm,*acm;
double dx,dy,dz;
double unwrap[3];
for (ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
vcm = body[ibody].vcm;
vcm[0] = vcm[1] = vcm[2] = 0.0;
acm = body[ibody].angmom;
acm[0] = acm[1] = acm[2] = 0.0;
}
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
vcm = b->vcm;
vcm[0] += v[i][0] * massone;
vcm[1] += v[i][1] * massone;
vcm[2] += v[i][2] * massone;
domain->unmap(x[i],image[i],unwrap);
xcm = b->xcm;
dx = unwrap[0] - xcm[0];
dy = unwrap[1] - xcm[1];
dz = unwrap[2] - xcm[2];
acm = b->angmom;
acm[0] += dy * massone*v[i][2] - dz * massone*v[i][1];
acm[1] += dz * massone*v[i][0] - dx * massone*v[i][2];
acm[2] += dx * massone*v[i][1] - dy * massone*v[i][0];
}
// extended particles add their rotation to angmom of body
if (extended) {
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
double **omega = atom->omega;
double **angmom = atom->angmom;
double *radius = atom->radius;
int *line = atom->line;
for (i = 0; i < nlocal; i++) {
if (atom2body[i] < 0) continue;
Body *b = &body[atom2body[i]];
if (eflags[i] & OMEGA) {
if (eflags[i] & SPHERE) {
radone = radius[i];
acm = b->angmom;
acm[0] += SINERTIA*rmass[i] * radone*radone * omega[i][0];
acm[1] += SINERTIA*rmass[i] * radone*radone * omega[i][1];
acm[2] += SINERTIA*rmass[i] * radone*radone * omega[i][2];
} else if (eflags[i] & LINE) {
radone = lbonus[line[i]].length;
b->angmom[2] += LINERTIA*rmass[i] * radone*radone * omega[i][2];
}
}
if (eflags[i] & ANGMOM) {
acm = b->angmom;
acm[0] += angmom[i][0];
acm[1] += angmom[i][1];
acm[2] += angmom[i][2];
}
}
}
// reverse communicate vcm, angmom of all bodies
commflag = VCM_ANGMOM;
comm->reverse_comm_variable_fix(this);
// normalize velocity of COM
for (ibody = 0; ibody < nlocal_body; ibody++) {
vcm = body[ibody].vcm;
vcm[0] /= body[ibody].mass;
vcm[1] /= body[ibody].mass;
vcm[2] /= body[ibody].mass;
}
}
/* ----------------------------------------------------------------------
read per rigid body info from user-provided file
which = 0 to read total mass and center-of-mass
which = 1 to read 6 moments of inertia, store in array
flag inbody = 0 for local bodies whose info is read from file
nlines = # of lines of rigid body info
one line = rigid-ID mass xcm ycm zcm ixx iyy izz ixy ixz iyz
and rigid-ID = mol-ID for fix rigid/small
------------------------------------------------------------------------- */
void FixRigidSmall::readfile(int which, double **array, int *inbody)
{
int i,j,m,nchunk,id,eofflag;
int nlines;
FILE *fp;
char *eof,*start,*next,*buf;
char line[MAXLINE];
// create local hash with key/value pairs
// key = mol ID of bodies my atoms own
// value = index into local body array
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
hash = new std::map<int,int>();
for (int i = 0; i < nlocal; i++)
if (bodyown[i] >= 0) (*hash)[atom->molecule[i]] = bodyown[i];
// open file and read header
if (me == 0) {
fp = fopen(infile,"r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix rigid/small infile %s",infile);
error->one(FLERR,str);
}
while (1) {
eof = fgets(line,MAXLINE,fp);
if (eof == NULL)
error->one(FLERR,"Unexpected end of fix rigid/small file");
start = &line[strspn(line," \t\n\v\f\r")];
if (*start != '\0' && *start != '#') break;
}
sscanf(line,"%d",&nlines);
}
MPI_Bcast(&nlines,1,MPI_INT,0,world);
if (nlines == 0) error->all(FLERR,"Fix rigid file has no lines");
char *buffer = new char[CHUNK*MAXLINE];
char **values = new char*[ATTRIBUTE_PERBODY];
int nread = 0;
while (nread < nlines) {
nchunk = MIN(nlines-nread,CHUNK);
eofflag = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eofflag) error->all(FLERR,"Unexpected end of fix rigid/small file");
buf = buffer;
next = strchr(buf,'\n');
*next = '\0';
int nwords = atom->count_words(buf);
*next = '\n';
if (nwords != ATTRIBUTE_PERBODY)
error->all(FLERR,"Incorrect rigid body format in fix rigid/small file");
// loop over lines of rigid body attributes
// tokenize the line into values
// id = rigid body ID = mol-ID
// for which = 0, store mass/com in vec/array
// for which = 1, store interia tensor array, invert 3,4,5 values to Voigt
for (int i = 0; i < nchunk; i++) {
next = strchr(buf,'\n');
values[0] = strtok(buf," \t\n\r\f");
for (j = 1; j < nwords; j++)
values[j] = strtok(NULL," \t\n\r\f");
id = atoi(values[0]);
if (id <= 0 || id > maxmol)
error->all(FLERR,"Invalid rigid body ID in fix rigid/small file");
if (hash->find(id) == hash->end()) {
buf = next + 1;
continue;
}
id = (*hash)[id];
inbody[id] = 1;
if (which == 0) {
body[id].mass = atof(values[1]);
body[id].xcm[0] = atof(values[2]);
body[id].xcm[1] = atof(values[3]);
body[id].xcm[2] = atof(values[4]);
} else {
array[id][0] = atof(values[5]);
array[id][1] = atof(values[6]);
array[id][2] = atof(values[7]);
array[id][3] = atof(values[10]);
array[id][4] = atof(values[9]);
array[id][5] = atof(values[8]);
}
buf = next + 1;
}
nread += nchunk;
}
if (me == 0) fclose(fp);
delete [] buffer;
delete [] values;
delete hash;
}
/* ----------------------------------------------------------------------
write out restart info for mass, COM, inertia tensor to file
identical format to infile option, so info can be read in when restarting
each proc contributes info for rigid bodies it owns
------------------------------------------------------------------------- */
void FixRigidSmall::write_restart_file(char *file)
{
FILE *fp;
// do not write file if bodies have not yet been intialized
if (firstflag) return;
// proc 0 opens file and writes header
if (me == 0) {
char outfile[128];
sprintf(outfile,"%s.rigid",file);
fp = fopen(outfile,"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix rigid restart file %s",outfile);
error->one(FLERR,str);
}
fprintf(fp,"# fix rigid mass, COM, inertia tensor info for "
"%d bodies on timestep " BIGINT_FORMAT "\n\n",
nbody,update->ntimestep);
fprintf(fp,"%d\n",nbody);
}
// communication buffer for all my rigid body info
// max_size = largest buffer needed by any proc
int ncol = 11;
int sendrow = nlocal_body;
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
double **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"rigid/small:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"rigid/small:buf");
// pack my rigid body info into buf
// compute I tensor against xyz axes from diagonalized I and current quat
// Ispace = P Idiag P_transpose
// P is stored column-wise in exyz_space
double p[3][3],pdiag[3][3],ispace[3][3];
for (int i = 0; i < nlocal_body; i++) {
MathExtra::col2mat(body[i].ex_space,body[i].ey_space,body[i].ez_space,p);
MathExtra::times3_diag(p,body[i].inertia,pdiag);
MathExtra::times3_transpose(pdiag,p,ispace);
buf[i][0] = atom->molecule[body[i].ilocal];
buf[i][1] = body[i].mass;
buf[i][2] = body[i].xcm[0];
buf[i][3] = body[i].xcm[1];
buf[i][4] = body[i].xcm[2];
buf[i][5] = ispace[0][0];
buf[i][6] = ispace[1][1];
buf[i][7] = ispace[2][2];
buf[i][8] = ispace[0][1];
buf[i][9] = ispace[0][2];
buf[i][10] = ispace[1][2];
}
// write one chunk of rigid body info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
if (me == 0) {
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
for (int i = 0; i < recvrow; i++)
fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e "
"%-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
static_cast<int> (buf[i][0]),buf[i][1],
buf[i][2],buf[i][3],buf[i][4],
buf[i][5],buf[i][6],buf[i][7],buf[i][8],buf[i][9],buf[i][10]);
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_DOUBLE,0,0,world);
}
// clean up and close file
memory->destroy(buf);
if (me == 0) fclose(fp);
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixRigidSmall::grow_arrays(int nmax)
{
memory->grow(bodyown,nmax,"rigid/small:bodyown");
memory->grow(bodytag,nmax,"rigid/small:bodytag");
memory->grow(atom2body,nmax,"rigid/small:atom2body");
memory->grow(displace,nmax,3,"rigid/small:displace");
if (extended) {
memory->grow(eflags,nmax,"rigid/small:eflags");
if (orientflag) memory->grow(orient,nmax,orientflag,"rigid/small:orient");
if (dorientflag) memory->grow(dorient,nmax,3,"rigid/small:dorient");
}
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixRigidSmall::copy_arrays(int i, int j, int delflag)
{
bodytag[j] = bodytag[i];
displace[j][0] = displace[i][0];
displace[j][1] = displace[i][1];
displace[j][2] = displace[i][2];
if (extended) {
eflags[j] = eflags[i];
for (int k = 0; k < orientflag; k++)
orient[j][k] = orient[i][k];
if (dorientflag) {
dorient[j][0] = dorient[i][0];
dorient[j][1] = dorient[i][1];
dorient[j][2] = dorient[i][2];
}
}
// if deleting atom J via delflag and J owns a body, then delete it
if (delflag && bodyown[j] >= 0) {
bodyown[body[nlocal_body-1].ilocal] = bodyown[j];
memcpy(&body[bodyown[j]],&body[nlocal_body-1],sizeof(Body));
nlocal_body--;
}
// if atom I owns a body, reset I's body.ilocal to loc J
// do NOT do this if self-copy (I=J) since I's body is already deleted
if (bodyown[i] >= 0 && i != j) body[bodyown[i]].ilocal = j;
bodyown[j] = bodyown[i];
}
/* ----------------------------------------------------------------------
initialize one atom's array values, called when atom is created
------------------------------------------------------------------------- */
void FixRigidSmall::set_arrays(int i)
{
bodyown[i] = -1;
bodytag[i] = 0;
atom2body[i] = -1;
displace[i][0] = 0.0;
displace[i][1] = 0.0;
displace[i][2] = 0.0;
}
/* ----------------------------------------------------------------------
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 = geometric center of new molecule
vcm = COM velocity of new molecule
quat = rotation of new molecule (around geometric center)
relative to template in Molecule class
------------------------------------------------------------------------- */
-void FixRigidSmall::set_molecule(int nlocalprev, int tagprev,
+void FixRigidSmall::set_molecule(int nlocalprev, tagint tagprev,
double *xgeom, double *vcm, double *quat)
{
int m;
double ctr2com[3],ctr2com_rotate[3];
double rotmat[3][3];
int nlocal = atom->nlocal;
if (nlocalprev == nlocal) return;
double **x = atom->x;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int i = nlocalprev; i < nlocal; i++) {
bodytag[i] = tagprev + onemol->comatom;
if (tag[i]-tagprev == onemol->comatom) bodyown[i] = nlocal_body;
m = tag[i] - tagprev-1;
displace[i][0] = onemol->dxbody[m][0];
displace[i][1] = onemol->dxbody[m][1];
displace[i][2] = onemol->dxbody[m][2];
eflags[i] = 0;
if (onemol->radiusflag) {
eflags[i] |= SPHERE;
eflags[i] |= OMEGA;
eflags[i] |= TORQUE;
}
if (bodyown[i] >= 0) {
if (nlocal_body == nmax_body) grow_body();
Body *b = &body[nlocal_body];
b->mass = onemol->masstotal;
// new COM = Q (onemol->xcm - onemol->center) + xgeom
// Q = rotation matrix associated with quat
MathExtra::quat_to_mat(quat,rotmat);
MathExtra::sub3(onemol->com,onemol->center,ctr2com);
MathExtra::matvec(rotmat,ctr2com,ctr2com_rotate);
MathExtra::add3(ctr2com_rotate,xgeom,b->xcm);
b->vcm[0] = vcm[0];
b->vcm[1] = vcm[1];
b->vcm[2] = vcm[2];
b->inertia[0] = onemol->inertia[0];
b->inertia[1] = onemol->inertia[1];
b->inertia[2] = onemol->inertia[2];
// final quat is product of insertion quat and original quat
// true even if insertion rotation was not around COM
MathExtra::quatquat(quat,onemol->quat,b->quat);
MathExtra::q_to_exyz(b->quat,b->ex_space,b->ey_space,b->ez_space);
b->angmom[0] = b->angmom[1] = b->angmom[2] = 0.0;
b->omega[0] = b->omega[1] = b->omega[2] = 0.0;
b->image = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
b->ilocal = i;
nlocal_body++;
}
}
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixRigidSmall::pack_exchange(int i, double *buf)
{
- buf[0] = bodytag[i];
+ buf[0] = ubuf(bodytag[i]).d;
buf[1] = displace[i][0];
buf[2] = displace[i][1];
buf[3] = displace[i][2];
// extended attribute info
int m = 4;
if (extended) {
buf[m++] = eflags[i];
for (int j = 0; j < orientflag; j++)
buf[m++] = orient[i][j];
if (dorientflag) {
buf[m++] = dorient[i][0];
buf[m++] = dorient[i][1];
buf[m++] = dorient[i][2];
}
}
// atom not in a rigid body
if (!bodytag[i]) return m;
// atom does not own its rigid body
if (bodyown[i] < 0) {
buf[m++] = 0;
return m;
}
// body info for atom that owns a rigid body
buf[m++] = 1;
memcpy(&buf[m],&body[bodyown[i]],sizeof(Body));
m += bodysize;
return m;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixRigidSmall::unpack_exchange(int nlocal, double *buf)
{
- bodytag[nlocal] = static_cast<int> (buf[0]);
+ bodytag[nlocal] = (tagint) ubuf(buf[0]).i;
displace[nlocal][0] = buf[1];
displace[nlocal][1] = buf[2];
displace[nlocal][2] = buf[3];
// extended attribute info
int m = 4;
if (extended) {
eflags[nlocal] = static_cast<int> (buf[m++]);
for (int j = 0; j < orientflag; j++)
orient[nlocal][j] = buf[m++];
if (dorientflag) {
dorient[nlocal][0] = buf[m++];
dorient[nlocal][1] = buf[m++];
dorient[nlocal][2] = buf[m++];
}
}
// atom not in a rigid body
if (!bodytag[nlocal]) {
bodyown[nlocal] = -1;
return m;
}
// atom does not own its rigid body
bodyown[nlocal] = static_cast<int> (buf[m++]);
if (bodyown[nlocal] == 0) {
bodyown[nlocal] = -1;
return m;
}
// body info for atom that owns a rigid body
if (nlocal_body == nmax_body) grow_body();
memcpy(&body[nlocal_body],&buf[m],sizeof(Body));
m += bodysize;
body[nlocal_body].ilocal = nlocal;
bodyown[nlocal] = nlocal_body++;
return m;
}
/* ----------------------------------------------------------------------
only pack body info if own or ghost atom owns the body
for FULL_BODY, send 0/1 flag with every atom
------------------------------------------------------------------------- */
int FixRigidSmall::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j;
double *xcm,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space;
int m = 0;
if (commflag == INITIAL) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
xcm = body[bodyown[j]].xcm;
buf[m++] = xcm[0];
buf[m++] = xcm[1];
buf[m++] = xcm[2];
vcm = body[bodyown[j]].vcm;
buf[m++] = vcm[0];
buf[m++] = vcm[1];
buf[m++] = vcm[2];
quat = body[bodyown[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
omega = body[bodyown[j]].omega;
buf[m++] = omega[0];
buf[m++] = omega[1];
buf[m++] = omega[2];
ex_space = body[bodyown[j]].ex_space;
buf[m++] = ex_space[0];
buf[m++] = ex_space[1];
buf[m++] = ex_space[2];
ey_space = body[bodyown[j]].ey_space;
buf[m++] = ey_space[0];
buf[m++] = ey_space[1];
buf[m++] = ey_space[2];
ez_space = body[bodyown[j]].ez_space;
buf[m++] = ez_space[0];
buf[m++] = ez_space[1];
buf[m++] = ez_space[2];
}
} else if (commflag == FINAL) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
vcm = body[bodyown[j]].vcm;
buf[m++] = vcm[0];
buf[m++] = vcm[1];
buf[m++] = vcm[2];
omega = body[bodyown[j]].omega;
buf[m++] = omega[0];
buf[m++] = omega[1];
buf[m++] = omega[2];
}
} else if (commflag == FULL_BODY) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) buf[m++] = 0;
else {
buf[m++] = 1;
memcpy(&buf[m],&body[bodyown[j]],sizeof(Body));
m += bodysize;
}
}
}
return m;
}
/* ----------------------------------------------------------------------
only ghost atoms are looped over
for FULL_BODY, store a new ghost body if this atom owns it
for other commflag values, only unpack body info if atom owns it
------------------------------------------------------------------------- */
void FixRigidSmall::unpack_comm(int n, int first, double *buf)
{
int i,j,last;
double *xcm,*vcm,*quat,*omega,*ex_space,*ey_space,*ez_space;
int m = 0;
last = first + n;
if (commflag == INITIAL) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
xcm = body[bodyown[i]].xcm;
xcm[0] = buf[m++];
xcm[1] = buf[m++];
xcm[2] = buf[m++];
vcm = body[bodyown[i]].vcm;
vcm[0] = buf[m++];
vcm[1] = buf[m++];
vcm[2] = buf[m++];
quat = body[bodyown[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
omega = body[bodyown[i]].omega;
omega[0] = buf[m++];
omega[1] = buf[m++];
omega[2] = buf[m++];
ex_space = body[bodyown[i]].ex_space;
ex_space[0] = buf[m++];
ex_space[1] = buf[m++];
ex_space[2] = buf[m++];
ey_space = body[bodyown[i]].ey_space;
ey_space[0] = buf[m++];
ey_space[1] = buf[m++];
ey_space[2] = buf[m++];
ez_space = body[bodyown[i]].ez_space;
ez_space[0] = buf[m++];
ez_space[1] = buf[m++];
ez_space[2] = buf[m++];
}
} else if (commflag == FINAL) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
vcm = body[bodyown[i]].vcm;
vcm[0] = buf[m++];
vcm[1] = buf[m++];
vcm[2] = buf[m++];
omega = body[bodyown[i]].omega;
omega[0] = buf[m++];
omega[1] = buf[m++];
omega[2] = buf[m++];
}
} else if (commflag == FULL_BODY) {
for (i = first; i < last; i++) {
bodyown[i] = static_cast<int> (buf[m++]);
if (bodyown[i] == 0) bodyown[i] = -1;
else {
j = nlocal_body + nghost_body;
if (j == nmax_body) grow_body();
memcpy(&body[j],&buf[m],sizeof(Body));
m += bodysize;
body[j].ilocal = i;
bodyown[i] = j;
nghost_body++;
}
}
}
}
/* ----------------------------------------------------------------------
only ghost atoms are looped over
only pack body info if atom owns it
------------------------------------------------------------------------- */
int FixRigidSmall::pack_reverse_comm(int n, int first, double *buf)
{
int i,j,m,last;
double *fcm,*torque,*vcm,*angmom,*xcm;
m = 0;
last = first + n;
if (commflag == FORCE_TORQUE) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
fcm = body[bodyown[i]].fcm;
buf[m++] = fcm[0];
buf[m++] = fcm[1];
buf[m++] = fcm[2];
torque = body[bodyown[i]].torque;
buf[m++] = torque[0];
buf[m++] = torque[1];
buf[m++] = torque[2];
}
} else if (commflag == VCM_ANGMOM) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
vcm = body[bodyown[i]].vcm;
buf[m++] = vcm[0];
buf[m++] = vcm[1];
buf[m++] = vcm[2];
angmom = body[bodyown[i]].angmom;
buf[m++] = angmom[0];
buf[m++] = angmom[1];
buf[m++] = angmom[2];
}
} else if (commflag == XCM_MASS) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
xcm = body[bodyown[i]].xcm;
buf[m++] = xcm[0];
buf[m++] = xcm[1];
buf[m++] = xcm[2];
buf[m++] = body[bodyown[i]].mass;
}
} else if (commflag == ITENSOR) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
j = bodyown[i];
buf[m++] = itensor[j][0];
buf[m++] = itensor[j][1];
buf[m++] = itensor[j][2];
buf[m++] = itensor[j][3];
buf[m++] = itensor[j][4];
buf[m++] = itensor[j][5];
}
} else if (commflag == DOF) {
for (i = first; i < last; i++) {
if (bodyown[i] < 0) continue;
j = bodyown[i];
buf[m++] = counts[j][0];
buf[m++] = counts[j][1];
buf[m++] = counts[j][2];
}
}
return m;
}
/* ----------------------------------------------------------------------
only unpack body info if own or ghost atom owns the body
------------------------------------------------------------------------- */
void FixRigidSmall::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,k;
double *fcm,*torque,*vcm,*angmom,*xcm;
int m = 0;
if (commflag == FORCE_TORQUE) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
fcm = body[bodyown[j]].fcm;
fcm[0] += buf[m++];
fcm[1] += buf[m++];
fcm[2] += buf[m++];
torque = body[bodyown[j]].torque;
torque[0] += buf[m++];
torque[1] += buf[m++];
torque[2] += buf[m++];
}
} else if (commflag == VCM_ANGMOM) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
vcm = body[bodyown[j]].vcm;
vcm[0] += buf[m++];
vcm[1] += buf[m++];
vcm[2] += buf[m++];
angmom = body[bodyown[j]].angmom;
angmom[0] += buf[m++];
angmom[1] += buf[m++];
angmom[2] += buf[m++];
}
} else if (commflag == XCM_MASS) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
xcm = body[bodyown[j]].xcm;
xcm[0] += buf[m++];
xcm[1] += buf[m++];
xcm[2] += buf[m++];
body[bodyown[j]].mass += buf[m++];
}
} else if (commflag == ITENSOR) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
k = bodyown[j];
itensor[k][0] += buf[m++];
itensor[k][1] += buf[m++];
itensor[k][2] += buf[m++];
itensor[k][3] += buf[m++];
itensor[k][4] += buf[m++];
itensor[k][5] += buf[m++];
}
} else if (commflag == DOF) {
for (i = 0; i < n; i++) {
j = list[i];
if (bodyown[j] < 0) continue;
k = bodyown[j];
counts[k][0] += static_cast<int> (buf[m++]);
counts[k][1] += static_cast<int> (buf[m++]);
counts[k][2] += static_cast<int> (buf[m++]);
}
}
}
/* ----------------------------------------------------------------------
grow body data structure
------------------------------------------------------------------------- */
void FixRigidSmall::grow_body()
{
nmax_body += DELTA_BODY;
body = (Body *) memory->srealloc(body,nmax_body*sizeof(Body),
"rigid/small:body");
}
/* ----------------------------------------------------------------------
reset atom2body for all owned atoms
do this via bodyown of atom that owns the body the owned atom is in
atom2body values can point to original body or any image of the body
------------------------------------------------------------------------- */
void FixRigidSmall::reset_atom2body()
{
int iowner;
// iowner = index of atom that owns the body that atom I is in
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
atom2body[i] = -1;
if (bodytag[i]) {
iowner = atom->map(bodytag[i]);
if (iowner == -1) {
char str[128];
sprintf(str,
- "Rigid body atoms %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ "Rigid body atoms " TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
atom->tag[i],bodytag[i],comm->me,update->ntimestep);
error->one(FLERR,str);
}
atom2body[i] = bodyown[iowner];
}
}
}
/* ---------------------------------------------------------------------- */
void FixRigidSmall::reset_dt()
{
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
dtq = 0.5 * update->dt;
}
/* ----------------------------------------------------------------------
zero linear momentum of each rigid body
set Vcm to 0.0, then reset velocities of particles via set_v()
------------------------------------------------------------------------- */
void FixRigidSmall::zero_momentum()
{
double *vcm;
for (int ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
vcm = body[ibody].vcm;
vcm[0] = vcm[1] = vcm[2] = 0.0;
}
// forward communicate of vcm to all ghost copies
commflag = FINAL;
comm->forward_comm_variable_fix(this);
// set velocity of atoms in rigid bodues
evflag = 0;
set_v();
}
/* ----------------------------------------------------------------------
zero angular momentum of each rigid body
set angmom/omega to 0.0, then reset velocities of particles via set_v()
------------------------------------------------------------------------- */
void FixRigidSmall::zero_rotation()
{
double *angmom,*omega;
for (int ibody = 0; ibody < nlocal_body+nghost_body; ibody++) {
angmom = body[ibody].angmom;
angmom[0] = angmom[1] = angmom[2] = 0.0;
omega = body[ibody].omega;
omega[0] = omega[1] = omega[2] = 0.0;
}
// forward communicate of omega to all ghost copies
commflag = FINAL;
comm->forward_comm_variable_fix(this);
// set velocity of atoms in rigid bodues
evflag = 0;
set_v();
}
/* ---------------------------------------------------------------------- */
void *FixRigidSmall::extract(const char *str, int &dim)
{
if (strcmp(str,"body") == 0) {
dim = 1;
return atom2body;
}
if (strcmp(str,"onemol") == 0) {
dim = 0;
return onemol;
}
// return vector of rigid body masses, for owned+ghost bodies
// used by granular pair styles, indexed by atom2body
if (strcmp(str,"masstotal") == 0) {
dim = 1;
if (nmax_mass < nmax_body) {
memory->destroy(mass_body);
nmax_mass = nmax_body;
memory->create(mass_body,nmax_mass,"rigid:mass_body");
}
int n = nlocal_body + nghost_body;
for (int i = 0; i < n; i++)
mass_body[i] = body[i].mass;
return mass_body;
}
return NULL;
}
/* ----------------------------------------------------------------------
return translational KE for all rigid bodies
KE = 1/2 M Vcm^2
sum local body results across procs
------------------------------------------------------------------------- */
double FixRigidSmall::extract_ke()
{
double *vcm;
double ke = 0.0;
for (int i = 0; i < nlocal_body; i++) {
vcm = body[i].vcm;
ke += body[i].mass * (vcm[0]*vcm[0] + vcm[1]*vcm[1] + vcm[2]*vcm[2]);
}
double keall;
MPI_Allreduce(&ke,&keall,1,MPI_DOUBLE,MPI_SUM,world);
return 0.5*keall;
}
/* ----------------------------------------------------------------------
return rotational KE for all rigid bodies
Erotational = 1/2 I wbody^2
------------------------------------------------------------------------- */
double FixRigidSmall::extract_erotational()
{
double wbody[3],rot[3][3];
double *inertia;
double erotate = 0.0;
for (int i = 0; i < nlocal_body; i++) {
// for Iw^2 rotational term, need wbody = angular velocity in body frame
// not omega = angular velocity in space frame
inertia = body[i].inertia;
MathExtra::quat_to_mat(body[i].quat,rot);
MathExtra::transpose_matvec(rot,body[i].angmom,wbody);
if (inertia[0] == 0.0) wbody[0] = 0.0;
else wbody[0] /= inertia[0];
if (inertia[1] == 0.0) wbody[1] = 0.0;
else wbody[1] /= inertia[1];
if (inertia[2] == 0.0) wbody[2] = 0.0;
else wbody[2] /= inertia[2];
erotate += inertia[0]*wbody[0]*wbody[0] + inertia[1]*wbody[1]*wbody[1] +
inertia[2]*wbody[2]*wbody[2];
}
double erotateall;
MPI_Allreduce(&erotate,&erotateall,1,MPI_DOUBLE,MPI_SUM,world);
return 0.5*erotateall;
}
/* ----------------------------------------------------------------------
return temperature of collection of rigid bodies
non-active DOF are removed by fflag/tflag and in tfactor
------------------------------------------------------------------------- */
double FixRigidSmall::compute_scalar()
{
double wbody[3],rot[3][3];
double *vcm,*inertia;
double t = 0.0;
for (int i = 0; i < nlocal_body; i++) {
vcm = body[i].vcm;
t += body[i].mass * (vcm[0]*vcm[0] + vcm[1]*vcm[1] + vcm[2]*vcm[2]);
// for Iw^2 rotational term, need wbody = angular velocity in body frame
// not omega = angular velocity in space frame
inertia = body[i].inertia;
MathExtra::quat_to_mat(body[i].quat,rot);
MathExtra::transpose_matvec(rot,body[i].angmom,wbody);
if (inertia[0] == 0.0) wbody[0] = 0.0;
else wbody[0] /= inertia[0];
if (inertia[1] == 0.0) wbody[1] = 0.0;
else wbody[1] /= inertia[1];
if (inertia[2] == 0.0) wbody[2] = 0.0;
else wbody[2] /= inertia[2];
t += inertia[0]*wbody[0]*wbody[0] + inertia[1]*wbody[1]*wbody[1] +
inertia[2]*wbody[2]*wbody[2];
}
double tall;
MPI_Allreduce(&t,&tall,1,MPI_DOUBLE,MPI_SUM,world);
double tfactor = force->mvv2e / (6.0*nbody * force->boltz);
tall *= tfactor;
return tall;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixRigidSmall::memory_usage()
{
int nmax = atom->nmax;
double bytes = 2 * nmax * sizeof(int);
bytes += nmax*3 * sizeof(double);
bytes += maxvatom*6 * sizeof(double); // vatom
if (extended) {
bytes += nmax * sizeof(int);
if (orientflag) bytes = nmax*orientflag * sizeof(double);
if (dorientflag) bytes = nmax*3 * sizeof(double);
}
bytes += nmax_body * sizeof(Body);
return bytes;
}
/* ----------------------------------------------------------------------
debug method for sanity checking of atom/body data pointers
------------------------------------------------------------------------- */
/*
void FixRigidSmall::check(int flag)
{
for (int i = 0; i < atom->nlocal; i++) {
if (bodyown[i] >= 0) {
if (bodytag[i] != atom->tag[i]) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD AAA");
}
if (bodyown[i] < 0 || bodyown[i] >= nlocal_body) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD BBB");
}
if (atom2body[i] != bodyown[i]) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD CCC");
}
if (body[bodyown[i]].ilocal != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD DDD");
}
}
}
for (int i = 0; i < atom->nlocal; i++) {
if (bodyown[i] < 0 && bodytag[i] > 0) {
if (atom2body[i] < 0 || atom2body[i] >= nlocal_body+nghost_body) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD EEE");
}
if (bodytag[i] != atom->tag[body[atom2body[i]].ilocal]) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD FFF");
}
}
}
for (int i = atom->nlocal; i < atom->nlocal + atom->nghost; i++) {
if (bodyown[i] >= 0) {
if (bodyown[i] < nlocal_body ||
bodyown[i] >= nlocal_body+nghost_body) {
printf("Values %d %d: %d %d %d\n",
i,atom->tag[i],bodyown[i],nlocal_body,nghost_body);
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD GGG");
}
if (body[bodyown[i]].ilocal != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD HHH");
}
}
}
for (int i = 0; i < nlocal_body; i++) {
if (body[i].ilocal < 0 || body[i].ilocal >= atom->nlocal) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD III");
}
if (bodytag[body[i].ilocal] != atom->tag[body[i].ilocal] ||
bodyown[body[i].ilocal] != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD JJJ");
}
}
for (int i = nlocal_body; i < nlocal_body + nghost_body; i++) {
if (body[i].ilocal < atom->nlocal ||
body[i].ilocal >= atom->nlocal + atom->nghost) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD KKK");
}
if (bodyown[body[i].ilocal] != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD LLL");
}
}
}
*/
diff --git a/src/RIGID/fix_rigid_small.h b/src/RIGID/fix_rigid_small.h
index 5cc63c3dd..6f73a9c03 100644
--- a/src/RIGID/fix_rigid_small.h
+++ b/src/RIGID/fix_rigid_small.h
@@ -1,254 +1,254 @@
/* ----------------------------------------------------------------------
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 FIX_CLASS
FixStyle(rigid/small,FixRigidSmall)
#else
#ifndef LMP_FIX_RIGID_SMALL_H
#define LMP_FIX_RIGID_SMALL_H
#include "fix.h"
// replace this later
#include <map>
namespace LAMMPS_NS {
class FixRigidSmall : public Fix {
public:
// static variable for ring communication callback to access class data
static FixRigidSmall *frsptr;
FixRigidSmall(class LAMMPS *, int, char **);
virtual ~FixRigidSmall();
virtual int setmask();
virtual void init();
virtual void setup(int);
virtual void initial_integrate(int);
void post_force(int);
virtual void final_integrate();
void initial_integrate_respa(int, int, int);
void final_integrate_respa(int, int);
void write_restart_file(char *);
void grow_arrays(int);
void copy_arrays(int, int, int);
void set_arrays(int);
- void set_molecule(int, int, double *, double *, double *);
+ void set_molecule(int, tagint, double *, double *, double *);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int pack_reverse_comm(int, int, double *);
void unpack_reverse_comm(int, int *, double *);
void setup_pre_neighbor();
void pre_neighbor();
int dof(int);
void deform(int);
void reset_dt();
void zero_momentum();
void zero_rotation();
void *extract(const char*, int &);
double extract_ke();
double extract_erotational();
double compute_scalar();
double memory_usage();
protected:
int me,nprocs;
double dtv,dtf,dtq;
double *step_respa;
int triclinic;
double MINUSPI,TWOPI;
char *infile; // file to read rigid body attributes from
int firstflag; // 1 for first-time setup of rigid bodies
int commflag; // various modes of forward/reverse comm
int nbody; // total # of rigid bodies
int maxmol; // max mol-ID
double maxextent; // furthest distance from body owner to body atom
struct Body {
double mass; // total mass of body
double xcm[3]; // COM position
double vcm[3]; // COM velocity
double fcm[3]; // force on COM
double torque[3]; // torque around COM
double quat[4]; // quaternion for orientation of body
double inertia[3]; // 3 principal components of inertia
double ex_space[3]; // principal axes in space coords
double ey_space[3];
double ez_space[3];
double angmom[3]; // space-frame angular momentum of body
double omega[3]; // space-frame omega of body
imageint image; // image flags of xcm
int remapflag[4]; // PBC remap flags
int ilocal; // index of owning atom
};
Body *body; // list of rigid bodies, owned and ghost
int nlocal_body; // # of owned rigid bodies
int nghost_body; // # of ghost rigid bodies
int nmax_body; // max # of bodies that body can hold
int bodysize; // sizeof(Body) in doubles
// per-atom quantities
// only defined for owned atoms, except bodyown for own+ghost
int *bodyown; // index of body if atom owns a body, -1 if not
- int *bodytag; // ID of body this atom is in, 0 if none
+ tagint *bodytag; // ID of body this atom is in, 0 if none
// ID = tag of atom that owns body
int *atom2body; // index of owned/ghost body this atom is in, -1 if not
// can point to original or any image of the body
double **displace; // displacement of each atom in body coords
int *eflags; // flags for extended particles
double **orient; // orientation vector of particle wrt rigid body
double **dorient; // orientation of dipole mu wrt rigid body
int extended; // 1 if any particles have extended attributes
int orientflag; // 1 if particles store spatial orientation
int dorientflag; // 1 if particles store dipole orientation
int POINT,SPHERE,ELLIPSOID,LINE,TRIANGLE,DIPOLE; // bitmasks for eflags
int OMEGA,ANGMOM,TORQUE;
class AtomVecEllipsoid *avec_ellipsoid;
class AtomVecLine *avec_line;
class AtomVecTri *avec_tri;
// temporary per-body storage
int **counts; // counts of atom types in bodies
double **itensor; // 6 space-frame components of inertia tensor
// mass per body, accessed by granular pair styles
double *mass_body;
int nmax_mass;
// Langevin thermostatting
int langflag; // 0/1 = no/yes Langevin thermostat
double t_start,t_stop,t_period; // thermostat params
double **langextra; // Langevin thermostat forces and torques
int maxlang; // max size of langextra
class RanMars *random; // RNG
// molecules added on-the-fly as rigid bodies
class Molecule *onemol;
// class data used by ring communication callbacks
std::map<int,int> *hash;
double **bbox;
double **ctr;
- int *idclose;
+ tagint *idclose;
double *rsqclose;
double rsqfar;
void set_xv();
void set_v();
void create_bodies();
void setup_bodies_static();
void setup_bodies_dynamic();
void readfile(int, double **, int *);
void grow_body();
void reset_atom2body();
// callback functions for ring communication
static void ring_bbox(int, char *);
static void ring_nearest(int, char *);
static void ring_farthest(int, char *);
// debug
//void check(int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Fix rigid/small langevin period must be > 0.0
Self-explanatory.
E: Fix rigid/small requires atom attribute molecule
Self-explanatory.
E: No rigid bodies defined
The fix specification did not end up defining any rigid bodies.
W: More than one fix rigid
It is not efficient to use fix rigid more than once.
E: Rigid fix must come before NPT/NPH fix
NPT/NPH fix must be defined in input script after all rigid fixes,
else the rigid fix contribution to the pressure virial is
incorrect.
W: Cannot count rigid body degrees-of-freedom before bodies are fully initialized
UNDOCUMENTED
W: Computing temperature of portions of rigid bodies
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.
E: Fix rigid/small atom has non-zero image flag in a non-periodic dimension
Image flags for non-periodic dimensions should not be set.
E: Insufficient Jacobi rotations for rigid body
Eigensolve for rigid body was not sufficiently accurate.
E: Fix rigid: Bad principal moments
The principal moments of inertia computed for a rigid body
are not within the required tolerances.
E: Rigid body atoms %d %d missing on proc %d at step %ld
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.
*/
diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp
index 4cc446676..92f63d175 100644
--- a/src/RIGID/fix_shake.cpp
+++ b/src/RIGID/fix_shake.cpp
@@ -1,2576 +1,2580 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "fix_shake.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;
// allocate space for static class variable
FixShake *FixShake::fsptr;
#define BIG 1.0e20
#define MASSDELTA 0.1
/* ---------------------------------------------------------------------- */
FixShake::FixShake(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
virial_flag = 1;
create_attribute = 1;
// error check
if (atom->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 = shake_type = NULL;
+ shake_atom = NULL;
+ shake_type = NULL;
xshake = 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();
// 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
onemol = 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 ID for fix shake does not exist");
onemol = atom->molecules[imol];
iarg += 2;
} else error->all(FLERR,"Illegal fix shake command");
}
// error check for Molecule template
if (onemol && onemol->shakeflag == 0)
error->all(FLERR,"Fix shake molecule 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];
}
// 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 **bond_type = atom->bond_type;
int **angle_type = atom->angle_type;
int nlocal = atom->nlocal;
int n;
for (int i = 0; i < nlocal; i++) {
if (shake_flag[i] == 0) continue;
else if (shake_flag[i] == 1) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = anglefind(i,shake_atom[i][1],shake_atom[i][2]);
if (n >= 0) angle_type[i][n] = -angle_type[i][n];
} else if (shake_flag[i] == 2) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
} else if (shake_flag[i] == 3) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
} else if (shake_flag[i] == 4) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][3]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
}
}
// delete locally stored arrays
memory->destroy(shake_flag);
memory->destroy(shake_atom);
memory->destroy(shake_type);
memory->destroy(xshake);
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
angle = force->angle->equilibrium_angle(i);
rsq = 2.0*bond_distance[bond1_type]*bond_distance[bond2_type] *
(1.0-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;
// half timestep constraint on pre-step, full timestep thereafter
if (strstr(update->integrate_style,"verlet")) {
dtv = update->dt;
dtfsq = 0.5 * update->dt * update->dt * force->ftm2v;
post_force(vflag);
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);
post_force_respa(vflag,ilevel,loop_respa[ilevel]-1);
((Respa *) update->integrate)->copy_f_flevel(ilevel);
}
dtf_inner = step_respa[0] * force->ftm2v;
}
}
/* ----------------------------------------------------------------------
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 %d %d missing on proc %d at step " BIGINT_FORMAT,
+ 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 %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ 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 %d %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ 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);
}
}
/* ----------------------------------------------------------------------
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);
}
}
/* ----------------------------------------------------------------------
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;
- int *tag = atom->tag;
+ 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;
int flag,flag_all,messtag,nbuf,nbufmax,size;
double massone;
- int *buf;
+ tagint *buf;
if (me == 0 && screen) fprintf(screen,"Finding SHAKE clusters ...\n");
// local copies of atom ptrs
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double *mass = atom->mass;
double *rmass = atom->rmass;
int **bond_type = atom->bond_type;
int **angle_type = atom->angle_type;
int **nspecial = atom->nspecial;
- int **special = atom->special;
+ tagint **special = atom->special;
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;
for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]);
int *npartner;
memory->create(npartner,nlocal,"shake:npartner");
memory->create(nshake,nlocal,"shake:nshake");
- int **partner_tag,**partner_mask,**partner_type,**partner_massflag;
- int ** partner_bondtype,**partner_shake,**partner_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
// -----------------------------------------------------
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];
+ for (j = 0; j < npartner[i]; j++)
+ partner_tag[i][j] = special[i][j];
}
// -----------------------------------------------------
// 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 = bondfind(i,tag[i],partner_tag[i][j]);
if (n >= 0) partner_bondtype[i][j] = bond_type[i][n];
else {
n = bondfind(m,tag[i],partner_tag[i][j]);
if (n >= 0) partner_bondtype[i][j] = bond_type[m][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 = bondfind(i,tag[i],partner_tag[i][j]);
if (n >= 0) buf[size+5] = bond_type[i][n];
else buf[size+5] = 0;
size += nper;
}
}
}
// cycle buffer around ring of procs back to self
fsptr = this;
- comm->ring(size,sizeof(int),buf,1,ring_bonds,buf);
+ comm->ring(size,sizeof(tagint),buf,1,ring_bonds,buf);
// 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
fsptr = this;
- comm->ring(size,sizeof(int),buf,2,ring_nshake,buf);
+ comm->ring(size,sizeof(tagint),buf,2,ring_nshake,buf);
// 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 = anglefind(i,shake_atom[i][1],shake_atom[i][2]);
if (n < 0) continue;
if (angle_type[i][n] < 0) continue;
if (angle_flag[angle_type[i][n]]) {
shake_flag[i] = 1;
shake_type[i][2] = angle_type[i][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
fsptr = this;
- comm->ring(size,sizeof(int),buf,3,ring_shake,NULL);
+ comm->ring(size,sizeof(tagint),buf,3,ring_shake,NULL);
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) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = anglefind(i,shake_atom[i][1],shake_atom[i][2]);
if (n >= 0) angle_type[i][n] = -angle_type[i][n];
} else if (shake_flag[i] == 2) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
} else if (shake_flag[i] == 3) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
} else if (shake_flag[i] == 4) {
n = bondfind(i,shake_atom[i][0],shake_atom[i][1]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][2]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
n = bondfind(i,shake_atom[i][0],shake_atom[i][3]);
if (n >= 0) bond_type[i][n] = -bond_type[i][n];
}
}
// -----------------------------------------------------
// 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)
{
Atom *atom = fsptr->atom;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *mask = atom->mask;
int **bond_type = atom->bond_type;
int *type = atom->type;
int nlocal = atom->nlocal;
int nmass = fsptr->nmass;
- int *buf = (int *) cbuf;
+ 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->bondfind(m,buf[i],buf[i+1]);
if (n >= 0) buf[i+5] = bond_type[m][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)
{
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
int *nshake = fsptr->nshake;
- int *buf = (int *) cbuf;
+ 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)
{
Atom *atom = fsptr->atom;
int nlocal = atom->nlocal;
int *shake_flag = fsptr->shake_flag;
- int **shake_atom = fsptr->shake_atom;
+ tagint **shake_atom = fsptr->shake_atom;
int **shake_type = fsptr->shake_type;
- int *buf = (int *) cbuf;
+ 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
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(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
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(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(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;
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
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(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(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(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;
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
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(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(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(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;
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 tags n1 and n2 stored with local atom i
return -1 if don't find it
return bond index if do find it
------------------------------------------------------------------------- */
-int FixShake::bondfind(int i, int n1, int n2)
+int FixShake::bondfind(int i, tagint n1, tagint n2)
{
- int *tag = atom->tag;
- int **bond_atom = atom->bond_atom;
+ tagint *tag = atom->tag;
+ tagint **bond_atom = atom->bond_atom;
int nbonds = atom->num_bond[i];
int m;
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;
}
if (m < nbonds) return m;
return -1;
}
/* ----------------------------------------------------------------------
find an angle with global end atoms n1 and n2 stored with local atom i
return -1 if don't find it
return angle index if do find it
------------------------------------------------------------------------- */
-int FixShake::anglefind(int i, int n1, int n2)
+int FixShake::anglefind(int i, tagint n1, tagint n2)
{
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom3 = atom->angle_atom3;
int nangles = atom->num_angle[i];
int m;
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;
}
if (m < nangles) return m;
return -1;
}
/* ----------------------------------------------------------------------
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");
}
/* ----------------------------------------------------------------------
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, int tagprev,
+void FixShake::set_molecule(int nlocalprev, tagint tagprev,
double *xgeom, double *vcm, double *quat)
{
int m,flag;
int nlocal = atom->nlocal;
if (nlocalprev == nlocal) return;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int **mol_shake_atom = onemol->shake_atom;
int **mol_shake_type = onemol->shake_type;
for (int i = nlocalprev; i < nlocal; i++) {
m = tag[i] - tagprev-1;
flag = shake_flag[i] = onemol->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<int> (buf[m++]);
- shake_atom[nlocal][1] = static_cast<int> (buf[m++]);
- shake_atom[nlocal][2] = static_cast<int> (buf[m++]);
+ 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<int> (buf[m++]);
- shake_atom[nlocal][1] = static_cast<int> (buf[m++]);
+ 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<int> (buf[m++]);
- shake_atom[nlocal][1] = static_cast<int> (buf[m++]);
- shake_atom[nlocal][2] = static_cast<int> (buf[m++]);
+ 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<int> (buf[m++]);
- shake_atom[nlocal][1] = static_cast<int> (buf[m++]);
- shake_atom[nlocal][2] = static_cast<int> (buf[m++]);
- shake_atom[nlocal][3] = static_cast<int> (buf[m++]);
+ 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_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 3;
}
/* ---------------------------------------------------------------------- */
void FixShake::unpack_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;
dtfsq = update->dt * update->dt * force->ftm2v;
} else {
dtv = step_respa[0];
dtf_innerhalf = 0.5 * step_respa[0] * force->ftm2v;
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 onemol;
}
return NULL;
}
diff --git a/src/RIGID/fix_shake.h b/src/RIGID/fix_shake.h
index f84315afb..a88e2b6d3 100644
--- a/src/RIGID/fix_shake.h
+++ b/src/RIGID/fix_shake.h
@@ -1,242 +1,242 @@
/* -*- 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 FIX_CLASS
FixStyle(shake,FixShake)
#else
#ifndef LMP_FIX_SHAKE_H
#define LMP_FIX_SHAKE_H
#include "fix.h"
namespace LAMMPS_NS {
class FixShake : public Fix {
public:
FixShake(class LAMMPS *, int, char **);
~FixShake();
int setmask();
void init();
void setup(int);
void pre_neighbor();
void post_force(int);
void post_force_respa(int, int, int);
double memory_usage();
void grow_arrays(int);
void copy_arrays(int, int, int);
void set_arrays(int);
void update_arrays(int, int);
- void set_molecule(int, int, double *, double *, double *);
+ void set_molecule(int, tagint, double *, double *, double *);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int dof(int);
void reset_dt();
void *extract(const char *, int &);
private:
int me,nprocs;
double tolerance; // SHAKE tolerance
int max_iter; // max # of SHAKE iterations
int output_every; // SHAKE stat output every so often
bigint next_output; // timestep for next output
// settings from input command
int *bond_flag,*angle_flag; // bond/angle types to constrain
int *type_flag; // constrain bonds to these types
double *mass_list; // constrain bonds to these masses
int nmass; // # of masses in mass_list
double *bond_distance,*angle_distance; // constraint distances
int ifix_respa; // rRESPA fix needed by SHAKE
int nlevels_respa; // copies of needed rRESPA variables
int *loop_respa;
double *step_respa;
double **x,**v,**f; // local ptrs to atom class quantities
double *mass,*rmass;
int *type;
int nlocal;
// atom-based arrays
int *shake_flag; // 0 if atom not in SHAKE cluster
// 1 = size 3 angle cluster
// 2,3,4 = size of bond-only cluster
- int **shake_atom; // global IDs of atoms in cluster
+ tagint **shake_atom; // global IDs of atoms in cluster
// central atom is 1st
// lowest global ID is 1st for size 2
int **shake_type; // bondtype of each bond in cluster
// for angle cluster, 3rd value
// is angletype
double **xshake; // unconstrained atom coords
int *nshake; // count
double dtv,dtfsq; // timesteps for trial move
double dtf_inner,dtf_innerhalf; // timesteps for rRESPA trial move
int *list; // list of clusters to SHAKE
int nlist,maxlist; // size and max-size of list
// stat quantities
int *b_count,*b_count_all; // counts for each bond type
double *b_ave,*b_max,*b_min; // ave/max/min dist for each bond type
double *b_ave_all,*b_max_all,*b_min_all; // MPI summing arrays
int *a_count,*a_count_all; // ditto for angle types
double *a_ave,*a_max,*a_min;
double *a_ave_all,*a_max_all,*a_min_all;
// molecules added on-the-fly with SHAKE constraints
class Molecule *onemol;
void find_clusters();
int masscheck(double);
void unconstrained_update();
void unconstrained_update_respa(int);
void shake(int);
void shake3(int);
void shake4(int);
void shake3angle(int);
void stats();
- int bondfind(int, int, int);
- int anglefind(int, int, int);
+ int bondfind(int, tagint, tagint);
+ int anglefind(int, tagint, tagint);
// static variable for ring communication callback to access class data
// callback functions for ring communication
static FixShake *fsptr;
static void ring_bonds(int, char *);
static void ring_nshake(int, char *);
static void ring_shake(int, char *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Cannot use fix shake with non-molecular system
Your choice of atom style does not have bonds.
E: Illegal ... command
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.
E: Invalid bond type index for fix shake
Self-explanatory. Check the fix shake command in the input script.
E: Invalid angle type index for fix shake
Self-explanatory.
E: Invalid atom type index for fix shake
Atom types must range from 1 to Ntypes inclusive.
E: Invalid atom mass for fix shake
Mass specified in fix shake command must be > 0.0.
E: Too many masses for fix shake
The fix shake command cannot list more masses than there are atom
types.
E: More than one fix shake
Only one fix shake can be defined.
E: Fix shake cannot be used with minimization
Cannot use fix shake while doing an energy minimization since
it turns off bonds that should contribute to the energy.
E: Shake fix must come before NPT/NPH fix
NPT fix must be defined in input script after SHAKE fix, else the
SHAKE fix contribution to the pressure virial is incorrect.
E: Bond potential must be defined for SHAKE
Cannot use fix shake unless bond potential is defined.
E: Angle potential must be defined for SHAKE
When shaking angles, an angle_style potential must be used.
E: Shake angles have different bond types
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.
E: Shake atoms %d %d missing on proc %d at step %ld
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.
E: Shake atoms %d %d %d missing on proc %d at step %ld
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.
E: Shake atoms %d %d %d %d missing on proc %d at step %ld
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.
E: Did not find fix shake partner info
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.
E: Shake cluster of more than 4 atoms
A single cluster specified by the fix shake command can have no more
than 4 atoms.
E: Shake clusters are connected
A single cluster specified by the fix shake command must have a single
central atom with up to 3 other atoms bonded to it.
W: Shake determinant < 0.0
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.
E: Shake determinant = 0.0
The determinant of the matrix being solved for a single cluster
specified by the fix shake command is numerically invalid.
*/
diff --git a/src/SHOCK/fix_append_atoms.cpp b/src/SHOCK/fix_append_atoms.cpp
index 44a46aa6f..5e7af01f6 100644
--- a/src/SHOCK/fix_append_atoms.cpp
+++ b/src/SHOCK/fix_append_atoms.cpp
@@ -1,509 +1,509 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "stdlib.h"
#include "fix_append_atoms.h"
#include "atom.h"
#include "atom_vec.h"
#include "comm.h"
#include "modify.h"
#include "domain.h"
#include "lattice.h"
#include "update.h"
#include "random_mars.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define BIG 1.0e30
#define EPSILON 1.0e-6
/* ---------------------------------------------------------------------- */
FixAppendAtoms::FixAppendAtoms(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
force_reneighbor = 1;
next_reneighbor = -1;
box_change_size = 1;
time_depend = 1;
if (narg < 4) error->all(FLERR,"Illegal fix append/atoms command");
// default settings
scaleflag = 1;
spatflag=0;
xloflag = xhiflag = yloflag = yhiflag = zloflag = zhiflag = 0;
tempflag = 0;
ranflag = 0;
ranx = 0.0;
rany = 0.0;
ranz = 0.0;
randomx = NULL;
randomt = NULL;
if (domain->lattice->nbasis == 0)
error->all(FLERR,"Fix append/atoms requires a lattice be defined");
nbasis = domain->lattice->nbasis;
basistype = new int[nbasis];
for (int i = 0; i < nbasis; i++) basistype[i] = 1;
int iarg = 0;
iarg = 3;
while (iarg < narg) {
if (strcmp(arg[iarg],"xlo") == 0) {
error->all(FLERR,"Only zhi currently implemented for fix append/atoms");
xloflag = 1;
iarg++;
if (domain->boundary[0][0] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"xhi") == 0) {
error->all(FLERR,"Only zhi currently implemented for fix append/atoms");
xhiflag = 1;
iarg++;
if (domain->boundary[0][1] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"ylo") == 0) {
error->all(FLERR,"Only zhi currently implemented for fix append/atoms");
yloflag = 1;
iarg++;
if (domain->boundary[1][0] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"yhi") == 0) {
error->all(FLERR,"Only zhi currently implemented for fix append/atoms");
yhiflag = 1;
iarg++;
if (domain->boundary[1][1] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"zlo") == 0) {
error->all(FLERR,"Only zhi currently implemented for fix append/atoms");
zloflag = 1;
iarg++;
if (domain->boundary[2][0] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"zhi") == 0) {
zhiflag = 1;
iarg++;
if (domain->boundary[2][1] != 3)
error->all(FLERR,"Append boundary must be shrink/minimum");
} else if (strcmp(arg[iarg],"freq") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix append/atoms command");
freq = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"spatial") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix append/atoms command");
if (strcmp(arg[iarg+1],"f_") == 0)
error->all(FLERR,
"Bad fix ID in fix append/atoms command");
spatflag = 1;
int n = strlen(arg[iarg+1]);
spatlead = force->numeric(FLERR,arg[iarg+2]);
char *suffix = new char[n];
strcpy(suffix,&arg[iarg+1][2]);
n = strlen(suffix) + 1;
spatialid = new char[n];
strcpy(spatialid,suffix);
delete [] suffix;
iarg += 3;
} else if (strcmp(arg[iarg],"basis") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix append/atoms command");
int ibasis = force->inumeric(FLERR,arg[iarg+1]);
int itype = force->inumeric(FLERR,arg[iarg+2]);
if (ibasis <= 0 || ibasis > nbasis || itype <= 0 || itype > atom->ntypes)
error->all(FLERR,"Invalid basis setting in fix append/atoms command");
basistype[ibasis-1] = itype;
iarg += 3;
} else if (strcmp(arg[iarg],"size") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix append/atoms command");
size = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix append/atoms command");
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
else error->all(FLERR,"Illegal fix append/atoms command");
iarg += 2;
} else if (strcmp(arg[iarg],"random") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal fix append/atoms command");
ranflag = 1;
ranx = force->numeric(FLERR,arg[iarg+1]);
rany = force->numeric(FLERR,arg[iarg+2]);
ranz = force->numeric(FLERR,arg[iarg+3]);
xseed = force->inumeric(FLERR,arg[iarg+4]);
if (xseed <= 0) error->all(FLERR,"Illegal fix append/atoms command");
randomx = new RanMars(lmp,xseed + comm->me);
iarg += 5;
} else if (strcmp(arg[iarg],"temp") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal fix append/atoms command");
tempflag = 1;
t_target = force->numeric(FLERR,arg[iarg+1]);
t_period = force->numeric(FLERR,arg[iarg+2]);
tseed = force->inumeric(FLERR,arg[iarg+3]);
t_extent = force->numeric(FLERR,arg[iarg+4]);
if (t_target <= 0) error->all(FLERR,"Illegal fix append/atoms command");
if (t_period <= 0) error->all(FLERR,"Illegal fix append/atoms command");
if (t_extent <= 0) error->all(FLERR,"Illegal fix append/atoms command");
if (tseed <= 0) error->all(FLERR,"Illegal fix append/atoms command");
randomt = new RanMars(lmp,tseed + comm->me);
gfactor1 = new double[atom->ntypes+1];
gfactor2 = new double[atom->ntypes+1];
iarg += 5;
} else error->all(FLERR,"Illegal fix append/atoms command");
}
if ((xloflag || xhiflag) && domain->xperiodic)
error->all(FLERR,"Cannot use append/atoms in periodic dimension");
if ((yloflag || yhiflag) && domain->yperiodic)
error->all(FLERR,"Cannot use append/atoms in periodic dimension");
if ((zloflag || zhiflag) && domain->zperiodic)
error->all(FLERR,"Cannot use append/atoms in periodic dimension");
if (domain->triclinic == 1)
error->all(FLERR,"Cannot append atoms to a triclinic box");
// setup scaling
double xscale,yscale,zscale;
if (scaleflag) {
xscale = domain->lattice->xlattice;
yscale = domain->lattice->ylattice;
zscale = domain->lattice->zlattice;
}
else xscale = yscale = zscale = 1.0;
if (xloflag || xhiflag) size *= xscale;
if (yloflag || yhiflag) size *= yscale;
if (zloflag || zhiflag) size *= zscale;
if (ranflag) {
ranx *= xscale;
rany *= yscale;
ranz *= zscale;
}
}
/* ---------------------------------------------------------------------- */
FixAppendAtoms::~FixAppendAtoms()
{
delete [] basistype;
if (ranflag) delete randomx;
if (tempflag) {
delete randomt;
delete [] gfactor1;
delete [] gfactor2;
}
}
/* ---------------------------------------------------------------------- */
int FixAppendAtoms::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
mask |= INITIAL_INTEGRATE;
mask |= POST_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixAppendAtoms::initial_integrate(int vflag)
{
if (update->ntimestep % freq == 0) next_reneighbor = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void FixAppendAtoms::setup(int vflag)
{
/*** CALL TO CREATE GROUP? SEE POST_FORCE ***/
post_force(vflag);
}
/* ---------------------------------------------------------------------- */
int FixAppendAtoms::get_spatial()
{
if (update->ntimestep % freq == 0) {
int ifix = modify->find_fix(spatialid);
if (ifix < 0)
error->all(FLERR,"Fix ID for fix ave/spatial does not exist");
Fix *fix = modify->fix[ifix];
int failed = 0;
int count = 0;
while (failed < 2) {
double tmp = fix->compute_vector(2*count);
if (tmp == 0.0) failed++;
else failed = 0;
count++;
}
double *pos = new double[count-2];
double *val = new double[count-2];
for (int loop=0; loop < count-2; loop++) {
pos[loop] = fix->compute_vector(2*loop);
val[loop] = fix->compute_vector(2*loop+1);
}
// always ignore the first and last
double binsize = 2.0;
double min_energy=0.0;
double max_energy=0.0;
int header = static_cast<int> (size / binsize);
advance = 0;
for (int loop=1; loop <= header; loop++) {
max_energy += val[loop];
}
for (int loop=count-2-2*header; loop <=count-3-header; loop++) {
min_energy += val[loop];
}
max_energy /= header;
min_energy /= header;
double shockfront_min = 0.0;
double shockfront_max = 0.0;
double shockfront_loc = 0.0;
int front_found1 = 0;
for (int loop=count-3-header; loop > header; loop--) {
if (front_found1 == 1) continue;
if (val[loop] > min_energy + 0.1*(max_energy - min_energy)) {
shockfront_max = pos[loop];
front_found1=1;
}
}
int front_found2 = 0;
for (int loop=header+1; loop <=count-3-header; loop++) {
if (val[loop] > min_energy + 0.6*(max_energy - min_energy)) {
shockfront_min = pos[loop];
front_found2=1;
}
}
if (front_found1 + front_found2 == 0) shockfront_loc = 0.0;
else if (front_found1 + front_found2 == 1)
shockfront_loc = shockfront_max + shockfront_min;
else if (front_found1 == 1 && front_found2 == 1 &&
shockfront_max-shockfront_min > spatlead/2.0)
shockfront_loc = shockfront_max;
else shockfront_loc = (shockfront_max + shockfront_min) / 2.0;
if (comm->me == 0)
printf("SHOCK: %g %g %g %g %g\n", shockfront_loc, shockfront_min,
shockfront_max, domain->boxlo[2], domain->boxhi[2]);
if (domain->boxhi[2] - shockfront_loc < spatlead) advance = 1;
delete [] pos;
delete [] val;
}
advance_sum = 0;
MPI_Allreduce(&advance,&advance_sum,1,MPI_INT,MPI_SUM,world);
if (advance_sum > 0) return 1;
else return 0;
}
/* ---------------------------------------------------------------------- */
void FixAppendAtoms::post_force(int vflag)
{
double **f = atom->f;
double **v = atom->v;
double **x = atom->x;
int *type = atom->type;
int nlocal = atom->nlocal;
double gamma1,gamma2;
double tsqrt = sqrt(t_target);
if (atom->mass) {
if (tempflag) {
for (int i = 1; i <= atom->ntypes; i++) {
gfactor1[i] = -atom->mass[i] / t_period / force->ftm2v;
gfactor2[i] = sqrt(atom->mass[i]) *
sqrt(24.0*force->boltz/t_period/update->dt/force->mvv2e) /
force->ftm2v;
}
}
for (int i = 0; i < nlocal; i++) {
// SET TEMP AHEAD OF SHOCK
if (tempflag && x[i][2] >= domain->boxhi[2] - t_extent ) {
gamma1 = gfactor1[type[i]];
gamma2 = gfactor2[type[i]] * tsqrt;
f[i][0] += gamma1*v[i][0] + gamma2*(randomt->uniform()-0.5);
f[i][1] += gamma1*v[i][1] + gamma2*(randomt->uniform()-0.5);
f[i][2] += gamma1*v[i][2] + gamma2*(randomt->uniform()-0.5);
}
// FREEZE ATOMS AT BOUNDARY
if (x[i][2] >= domain->boxhi[2] - size) {
f[i][0] = 0.0;
f[i][1] = 0.0;
f[i][2] = 0.0;
v[i][0] = 0.0;
v[i][1] = 0.0;
v[i][2] = 0.0;
}
}
} else {
double *rmass = atom->rmass;
double boltz = force->boltz;
double dt = update->dt;
double mvv2e = force->mvv2e;
double ftm2v = force->ftm2v;
for (int i = 0; i < nlocal; i++) {
// set temp ahead of shock
if (tempflag && x[i][2] >= domain->boxhi[2] - t_extent ) {
gamma1 = -rmass[i] / t_period / ftm2v;
gamma2 = sqrt(rmass[i]) * sqrt(24.0*boltz/t_period/dt/mvv2e) / ftm2v;
gamma2 *= tsqrt;
f[i][0] += gamma1*v[i][0] + gamma2*(randomt->uniform()-0.5);
f[i][1] += gamma1*v[i][1] + gamma2*(randomt->uniform()-0.5);
f[i][2] += gamma1*v[i][2] + gamma2*(randomt->uniform()-0.5);
}
// freeze atoms at boundary
if (x[i][2] >= domain->boxhi[2] - size) {
f[i][0] = 0.0;
f[i][1] = 0.0;
f[i][2] = 0.0;
v[i][0] = 0.0;
v[i][1] = 0.0;
v[i][2] = 0.0;
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixAppendAtoms::pre_exchange()
{
int ntimestep = update->ntimestep;
int addnode = 0;
if (ntimestep % freq == 0) {
if (spatflag==1) if (get_spatial()==0) return;
if (comm->myloc[2] == comm->procgrid[2]-1) {
double bboxlo[3],bboxhi[3];
bboxlo[0] = domain->sublo[0]; bboxhi[0] = domain->subhi[0];
bboxlo[1] = domain->sublo[1]; bboxhi[1] = domain->subhi[1];
bboxlo[2] = domain->subhi[2]; bboxhi[2] = domain->subhi[2]+size;
double xmin,ymin,zmin,xmax,ymax,zmax;
xmin = ymin = zmin = BIG;
xmax = ymax = zmax = -BIG;
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
int ilo,ihi,jlo,jhi,klo,khi;
ilo = static_cast<int> (xmin);
jlo = static_cast<int> (ymin);
klo = static_cast<int> (zmin);
ihi = static_cast<int> (xmax);
jhi = static_cast<int> (ymax);
khi = static_cast<int> (zmax);
if (xmin < 0.0) ilo--;
if (ymin < 0.0) jlo--;
if (zmin < 0.0) klo--;
double **basis = domain->lattice->basis;
double x[3];
double *sublo = domain->sublo;
double *subhi = domain->subhi;
int i,j,k,m;
for (k = klo; k <= khi; k++) {
for (j = jlo; j <= jhi; j++) {
for (i = ilo; i <= ihi; i++) {
for (m = 0; m < nbasis; m++) {
x[0] = i + basis[m][0];
x[1] = j + basis[m][1];
x[2] = k + basis[m][2];
int flag = 0;
// convert from lattice coords to box coords
domain->lattice->lattice2box(x[0],x[1],x[2]);
if (x[0] >= sublo[0] && x[0] < subhi[0] &&
x[1] >= sublo[1] && x[1] < subhi[1] &&
x[2] >= subhi[2] && x[2] < subhi[2]+size) flag = 1;
else if (domain->dimension == 2 && x[1] >= domain->boxhi[1] &&
comm->myloc[1] == comm->procgrid[1]-1 &&
x[0] >= sublo[0] && x[0] < subhi[0]) flag = 1;
if (flag) {
if (ranflag) {
x[0] += ranx * 2.0*(randomx->uniform()-0.5);
x[1] += rany * 2.0*(randomx->uniform()-0.5);
x[2] += ranz * 2.0*(randomx->uniform()-0.5);
}
addnode++;
atom->avec->create_atom(basistype[m],x);
}
}
}
}
}
}
int addtotal = 0;
MPI_Barrier(world);
MPI_Allreduce(&addnode,&addtotal,1,MPI_INT,MPI_SUM,world);
if (addtotal) {
domain->reset_box();
- if (atom->tag_enable) {
- atom->tag_extend();
- atom->natoms += addtotal;
- if (atom->map_style) {
- atom->nghost = 0;
- atom->map_init();
- atom->map_set();
- }
+ atom->natoms += addtotal;
+ if (atom->natoms < 0 || atom->natoms > MAXBIGINT)
+ error->all(FLERR,"Too many total atoms");
+ if (atom->tag_enable) atom->tag_extend();
+ if (atom->map_style) {
+ atom->nghost = 0;
+ atom->map_init();
+ atom->map_set();
}
}
}
}
diff --git a/src/SRD/fix_srd.cpp b/src/SRD/fix_srd.cpp
index d377a3d92..00193b9f9 100644
--- a/src/SRD/fix_srd.cpp
+++ b/src/SRD/fix_srd.cpp
@@ -1,3960 +1,3966 @@
/* ----------------------------------------------------------------------
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: Jeremy Lechman (SNL), Pieter in 't Veld (BASF)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "fix_srd.h"
#include "math_extra.h"
#include "atom.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "group.h"
#include "update.h"
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "neighbor.h"
#include "comm.h"
#include "modify.h"
#include "fix_deform.h"
#include "fix_wall_srd.h"
#include "random_mars.h"
#include "random_park.h"
#include "math_const.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
enum{SLIP,NOSLIP};
enum{SPHERE,ELLIPSOID,LINE,TRIANGLE,WALL};
enum{INSIDE_ERROR,INSIDE_WARN,INSIDE_IGNORE};
enum{BIG_MOVE,SRD_MOVE,SRD_ROTATE};
enum{CUBIC_ERROR,CUBIC_WARN};
enum{SHIFT_NO,SHIFT_YES,SHIFT_POSSIBLE};
enum{NO_REMAP,X_REMAP,V_REMAP}; // same as fix_deform.cpp
#define EINERTIA 0.2 // moment of inertia prefactor for ellipsoid
#define ATOMPERBIN 30
#define BIG 1.0e20
#define VBINSIZE 5
#define TOLERANCE 0.00001
#define MAXITER 20
static const char cite_fix_srd[] =
"fix srd command:\n\n"
"@Article{Petersen10,\n"
" author = {M. K. Petersen, J. B. Lechman, S. J. Plimpton, G. S. Grest, P. J. in 't Veld, P. R. Schunk},\n"
" title = {Mesoscale Hydrodynamics via Stochastic Rotation Dynamics: Comparison with Lennard-Jones Fluid},"
" journal = {J.~Chem.~Phys.},\n"
" year = 2010,\n"
" volume = 132,\n"
" pages = {174106}\n"
"}\n\n";
//#define SRD_DEBUG 1
//#define SRD_DEBUG_ATOMID 58
//#define SRD_DEBUG_TIMESTEP 449
/* ---------------------------------------------------------------------- */
FixSRD::FixSRD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_srd);
if (narg < 8) error->all(FLERR,"Illegal fix srd command");
restart_pbc = 1;
vector_flag = 1;
size_vector = 12;
global_freq = 1;
extvector = 0;
nevery = force->inumeric(FLERR,arg[3]);
bigexist = 1;
if (strcmp(arg[4],"NULL") == 0) bigexist = 0;
else biggroup = group->find(arg[4]);
temperature_srd = force->numeric(FLERR,arg[5]);
gridsrd = force->numeric(FLERR,arg[6]);
int seed = force->inumeric(FLERR,arg[7]);
// parse options
lamdaflag = 0;
collidestyle = NOSLIP;
overlap = 0;
insideflag = INSIDE_ERROR;
exactflag = 1;
radfactor = 1.0;
maxbounceallow = 0;
gridsearch = gridsrd;
cubicflag = CUBIC_ERROR;
cubictol = 0.01;
shiftuser = SHIFT_NO;
shiftseed = 0;
tstat = 0;
rescale_rotate = rescale_collide = 1;
int iarg = 8;
while (iarg < narg) {
if (strcmp(arg[iarg],"lamda") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
lamda = force->numeric(FLERR,arg[iarg+1]);
lamdaflag = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"collision") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"slip") == 0) collidestyle = SLIP;
else if (strcmp(arg[iarg+1],"noslip") == 0) collidestyle = NOSLIP;
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else if (strcmp(arg[iarg],"overlap") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"yes") == 0) overlap = 1;
else if (strcmp(arg[iarg+1],"no") == 0) overlap = 0;
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else if (strcmp(arg[iarg],"inside") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"error") == 0) insideflag = INSIDE_ERROR;
else if (strcmp(arg[iarg+1],"warn") == 0) insideflag = INSIDE_WARN;
else if (strcmp(arg[iarg+1],"ignore") == 0) insideflag = INSIDE_IGNORE;
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else if (strcmp(arg[iarg],"exact") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"yes") == 0) exactflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) exactflag = 0;
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else if (strcmp(arg[iarg],"radius") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
radfactor = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"bounce") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
maxbounceallow = force->inumeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"search") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
gridsearch = force->numeric(FLERR,arg[iarg+1]);
iarg += 2;
} else if (strcmp(arg[iarg],"cubic") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"error") == 0) cubicflag = CUBIC_ERROR;
else if (strcmp(arg[iarg+1],"warn") == 0) cubicflag = CUBIC_WARN;
else error->all(FLERR,"Illegal fix srd command");
cubictol = force->numeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"shift") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal fix srd command");
else if (strcmp(arg[iarg+1],"no") == 0) shiftuser = SHIFT_NO;
else if (strcmp(arg[iarg+1],"yes") == 0) shiftuser = SHIFT_YES;
else if (strcmp(arg[iarg+1],"possible") == 0) shiftuser = SHIFT_POSSIBLE;
else error->all(FLERR,"Illegal fix srd command");
shiftseed = force->inumeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"tstat") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"no") == 0) tstat = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) tstat = 1;
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else if (strcmp(arg[iarg],"rescale") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix srd command");
if (strcmp(arg[iarg+1],"no") == 0)
rescale_rotate = rescale_collide = 0;
else if (strcmp(arg[iarg+1],"yes") == 0)
rescale_rotate = rescale_collide = 1;
else if (strcmp(arg[iarg+1],"rotate") == 0) {
rescale_rotate = 1;
rescale_collide = 0;
} else if (strcmp(arg[iarg+1],"collide") == 0) {
rescale_rotate = 0;
rescale_collide = 1;
}
else error->all(FLERR,"Illegal fix srd command");
iarg += 2;
} else error->all(FLERR,"Illegal fix srd command");
}
// error check
if (nevery <= 0) error->all(FLERR,"Illegal fix srd command");
if (bigexist && biggroup < 0)
error->all(FLERR,"Could not find fix srd group ID");
if (gridsrd <= 0.0) error->all(FLERR,"Illegal fix srd command");
if (temperature_srd <= 0.0) error->all(FLERR,"Illegal fix srd command");
if (seed <= 0) error->all(FLERR,"Illegal fix srd command");
if (radfactor <= 0.0) error->all(FLERR,"Illegal fix srd command");
if (maxbounceallow < 0) error->all(FLERR,"Illegal fix srd command");
if (lamdaflag && lamda <= 0.0) error->all(FLERR,"Illegal fix srd command");
if (gridsearch <= 0.0) error->all(FLERR,"Illegal fix srd command");
if (cubictol < 0.0 || cubictol > 1.0)
error->all(FLERR,"Illegal fix srd command");
if ((shiftuser == SHIFT_YES || shiftuser == SHIFT_POSSIBLE) &&
shiftseed <= 0) error->all(FLERR,"Illegal fix srd command");
// initialize Marsaglia RNG with processor-unique seed
me = comm->me;
nprocs = comm->nprocs;
random = new RanMars(lmp,seed + me);
// if requested, initialize shift RNG, same on every proc
if (shiftuser == SHIFT_YES || shiftuser == SHIFT_POSSIBLE)
randomshift = new RanPark(lmp,shiftseed);
else randomshift = NULL;
// initialize data structs and flags
if (bigexist) biggroupbit = group->bitmask[biggroup];
else biggroupbit = 0;
nmax = 0;
binhead = NULL;
maxbin1 = 0;
binnext = NULL;
maxbuf = 0;
sbuf1 = sbuf2 = rbuf1 = rbuf2 = NULL;
shifts[0].maxvbin = shifts[1].maxvbin = 0;
shifts[0].vbin = shifts[1].vbin = NULL;
shifts[0].maxbinsq = shifts[1].maxbinsq = 0;
for (int ishift = 0; ishift < 2; ishift++)
for (int iswap = 0; iswap < 6; iswap++)
shifts[ishift].bcomm[iswap].sendlist =
shifts[ishift].bcomm[iswap].recvlist = NULL;
maxbin2 = 0;
nbinbig = NULL;
binbig = NULL;
binsrd = NULL;
nstencil = maxstencil = 0;
stencil = NULL;
maxbig = 0;
biglist = NULL;
stats_flag = 1;
for (int i = 0; i < size_vector; i++) stats_all[i] = 0.0;
initflag = 0;
srd_bin_temp = 0.0;
srd_bin_count = 0;
// atom style pointers to particles that store bonus info
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_line = (AtomVecLine *) atom->style_match("line");
avec_tri = (AtomVecTri *) atom->style_match("tri");
// fix parameters
if (collidestyle == SLIP) comm_reverse = 3;
else comm_reverse = 6;
force_reneighbor = 1;
}
/* ---------------------------------------------------------------------- */
FixSRD::~FixSRD()
{
delete random;
delete randomshift;
memory->destroy(binhead);
memory->destroy(binnext);
memory->destroy(sbuf1);
memory->destroy(sbuf2);
memory->destroy(rbuf1);
memory->destroy(rbuf2);
memory->sfree(shifts[0].vbin);
memory->sfree(shifts[1].vbin);
for (int ishift = 0; ishift < 2; ishift++)
for (int iswap = 0; iswap < 6; iswap++) {
memory->destroy(shifts[ishift].bcomm[iswap].sendlist);
memory->destroy(shifts[ishift].bcomm[iswap].recvlist);
}
memory->destroy(nbinbig);
memory->destroy(binbig);
memory->destroy(binsrd);
memory->destroy(stencil);
memory->sfree(biglist);
}
/* ---------------------------------------------------------------------- */
int FixSRD::setmask()
{
int mask = 0;
mask |= PRE_NEIGHBOR;
mask |= POST_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixSRD::init()
{
// error checks
if (force->newton_pair == 0)
error->all(FLERR,"Fix srd requires newton pair on");
if (bigexist && comm->ghost_velocity == 0)
error->all(FLERR,"Fix srd requires ghost atoms store velocity");
if (bigexist && collidestyle == NOSLIP && !atom->torque_flag)
error->all(FLERR,"Fix SRD no-slip requires atom attribute torque");
if (initflag && update->dt != dt_big)
error->all(FLERR,"Cannot change timestep once fix srd is setup");
// orthogonal vs triclinic simulation box
// could be static or shearing box
triclinic = domain->triclinic;
// wallexist = 1 if SRD wall(s) are defined
wallexist = 0;
for (int m = 0; m < modify->nfix; m++) {
if (strcmp(modify->fix[m]->style,"wall/srd") == 0) {
if (wallexist) error->all(FLERR,"Cannot use fix wall/srd more than once");
wallexist = 1;
wallfix = (FixWallSRD *) modify->fix[m];
nwall = wallfix->nwall;
wallvarflag = wallfix->varflag;
wallwhich = wallfix->wallwhich;
xwall = wallfix->xwall;
xwallhold = wallfix->xwallhold;
vwall = wallfix->vwall;
fwall = wallfix->fwall;
walltrigger = 0.5 * neighbor->skin;
if (wallfix->overlap && overlap == 0 && me == 0)
error->warning(FLERR,
"Fix SRD walls overlap but fix srd overlap not set");
}
}
// set change_flags if box size or shape changes
change_size = change_shape = deformflag = 0;
if (domain->nonperiodic == 2) change_size = 1;
for (int i = 0; i < modify->nfix; i++) {
if (modify->fix[i]->box_change_size) change_size = 1;
if (modify->fix[i]->box_change_shape) change_shape = 1;
if (strcmp(modify->fix[i]->style,"deform") == 0) {
deformflag = 1;
FixDeform *deform = (FixDeform *) modify->fix[i];
if (deform->box_change_shape && deform->remapflag != V_REMAP)
error->all(FLERR,"Using fix srd with inconsistent "
"fix deform remap option");
}
}
if (deformflag && tstat == 0 && me == 0)
error->warning(FLERR,
"Using fix srd with box deformation but no SRD thermostat");
// parameterize based on current box volume
dimension = domain->dimension;
parameterize();
// limit initial SRD velocities if necessary
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double vsq;
nrescale = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
if (vsq > vmaxsq) {
nrescale++;
MathExtra::scale3(vmax/sqrt(vsq),v[i]);
}
}
int all;
MPI_Allreduce(&nrescale,&all,1,MPI_INT,MPI_SUM,world);
if (me == 0) {
if (screen)
fprintf(screen," # of rescaled SRD velocities = %d\n",all);
if (logfile)
fprintf(logfile," # of rescaled SRD velocities = %d\n",all);
}
velocity_stats(igroup);
if (bigexist) velocity_stats(biggroup);
// zero per-run stats
nrescale = 0;
bouncemaxnum = 0;
bouncemax = 0;
reneighcount = 0;
initflag = 1;
next_reneighbor = -1;
}
/* ---------------------------------------------------------------------- */
void FixSRD::setup(int vflag)
{
setup_bounds();
if (dist_srd_reneigh < nevery*dt_big*vmax && me == 0)
error->warning(FLERR,
"Fix srd SRD moves may trigger frequent reneighboring");
// setup search bins and search stencil based on these distances
if (bigexist || wallexist) {
setup_search_bins();
setup_search_stencil();
} else nbins2 = 0;
// perform first bining of SRD and big particles and walls
// set reneighflag to turn off SRD rotation
// don't do SRD rotation in setup, only during timestepping
reneighflag = BIG_MOVE;
pre_neighbor();
}
/* ----------------------------------------------------------------------
assign SRD particles to bins
assign big particles to all bins they overlap
------------------------------------------------------------------------- */
void FixSRD::pre_neighbor()
{
int i,j,m,ix,iy,iz,jx,jy,jz,ibin,jbin,lo,hi;
double rsq,cutbinsq;
// grow SRD per-atom bin arrays if necessary
if (atom->nlocal > nmax) {
nmax = atom->nmax;
memory->destroy(binsrd);
memory->destroy(binnext);
memory->create(binsrd,nmax,"fix/srd:binsrd");
memory->create(binnext,nmax,"fix/srd:binnext");
}
// setup and grow BIG info list if necessary
// set index ptrs to BIG particles and to WALLS
// big_static() adds static properties to info list
if (bigexist || wallexist) {
if (bigexist) {
if (biggroup == atom->firstgroup) nbig = atom->nfirst + atom->nghost;
else {
int *mask = atom->mask;
int nlocal = atom->nlocal;
nbig = atom->nghost;
for (i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) nbig++;
}
} else nbig = 0;
int ninfo = nbig;
if (wallexist) ninfo += nwall;
if (ninfo > maxbig) {
maxbig = ninfo;
memory->destroy(biglist);
biglist = (Big *) memory->smalloc(maxbig*sizeof(Big),"fix/srd:biglist");
}
if (bigexist) {
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (biggroup == atom->firstgroup) nlocal = atom->nfirst;
nbig = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) biglist[nbig++].index = i;
int nall = atom->nlocal + atom->nghost;
for (i = atom->nlocal; i < nall; i++)
if (mask[i] & biggroupbit) biglist[nbig++].index = i;
big_static();
}
if (wallexist) {
for (m = 0; m < nwall; m++) {
biglist[nbig+m].index = m;
biglist[nbig+m].type = WALL;
}
wallfix->wall_params(1);
}
}
// if simulation box size changes, reset velocity bins
// if big particles exist, reset search bins if box size or shape changes,
// b/c finite-size particles will overlap different bins as the box tilts
if (change_size) setup_bounds();
if (change_size) setup_velocity_bins();
if ((change_size || change_shape) && (bigexist || wallexist)) {
setup_search_bins();
setup_search_stencil();
}
// map each owned & ghost big particle to search bins it overlaps
// zero out bin counters for big particles
// if firstgroup is defined, only loop over first and ghost particles
// for each big particle: loop over stencil to find overlap bins
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int nfirst = nlocal;
if (bigexist && biggroup == atom->firstgroup) nfirst = atom->nfirst;
if (bigexist || wallexist)
for (i = 0; i < nbins2; i++)
nbinbig[i] = 0;
if (bigexist) {
i = nbig = 0;
while (i < nall) {
if (mask[i] & biggroupbit) {
ix = static_cast<int> ((x[i][0]-xblo2)*bininv2x);
iy = static_cast<int> ((x[i][1]-yblo2)*bininv2y);
iz = static_cast<int> ((x[i][2]-zblo2)*bininv2z);
ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix;
if (ix < 0 || ix >= nbin2x || iy < 0 || iy >= nbin2y ||
iz < 0 || iz >= nbin2z)
error->one(FLERR,"Fix SRD: bad search bin assignment");
cutbinsq = biglist[nbig].cutbinsq;
for (j = 0; j < nstencil; j++) {
jx = ix + stencil[j][0];
jy = iy + stencil[j][1];
jz = iz + stencil[j][2];
if (jx < 0 || jx >= nbin2x || jy < 0 || jy >= nbin2y ||
jz < 0 || jz >= nbin2z) {
- printf("Big particle %d %d %g %g %g\n",
- atom->tag[i],i,x[i][0],x[i][1],x[i][2]);
- printf("Bin indices: %d %d %d, %d %d %d, %d %d %d\n",
- ix,iy,iz,jx,jy,jz,nbin2x,nbin2y,nbin2z);
+ if (screen) {
+ fprintf(screen,"Big particle " TAGINT_FORMAT " %d %g %g %g\n",
+ atom->tag[i],i,x[i][0],x[i][1],x[i][2]);
+ fprintf(screen,"Bin indices: %d %d %d, %d %d %d, %d %d %d\n",
+ ix,iy,iz,jx,jy,jz,nbin2x,nbin2y,nbin2z);
+ }
error->one(FLERR,"Fix SRD: bad stencil bin for big particle");
}
rsq = point_bin_distance(x[i],jx,jy,jz);
if (rsq < cutbinsq) {
jbin = ibin + stencil[j][3];
if (nbinbig[jbin] == ATOMPERBIN)
error->one(FLERR,"Fix SRD: too many big particles in bin");
binbig[jbin][nbinbig[jbin]++] = nbig;
}
}
nbig++;
}
i++;
if (i == nfirst) i = nlocal;
}
}
// map each wall to search bins it covers, up to non-periodic boundary
// if wall moves, add walltrigger to its position
// this insures it is added to all search bins it may move into
// may not overlap any of my search bins
if (wallexist) {
double delta = 0.0;
if (wallvarflag) delta = walltrigger;
for (m = 0; m < nwall; m++) {
int dim = wallwhich[m] / 2;
int side = wallwhich[m] % 2;
if (dim == 0) {
if (side == 0) {
hi = static_cast<int> ((xwall[m]+delta-xblo2)*bininv2x);
if (hi < 0) continue;
if (hi >= nbin2x) error->all(FLERR,
"Fix SRD: bad search bin assignment");
lo = 0;
} else {
lo = static_cast<int> ((xwall[m]-delta-xblo2)*bininv2x);
if (lo >= nbin2x) continue;
if (lo < 0) error->all(FLERR,"Fix SRD: bad search bin assignment");
hi = nbin2x-1;
}
for (ix = lo; ix <= hi; ix++)
for (iy = 0; iy < nbin2y; iy++)
for (iz = 0; iz < nbin2z; iz++) {
ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix;
if (nbinbig[ibin] == ATOMPERBIN)
error->all(FLERR,"Fix SRD: too many walls in bin");
binbig[ibin][nbinbig[ibin]++] = nbig+m;
}
} else if (dim == 1) {
if (side == 0) {
hi = static_cast<int> ((xwall[m]+delta-yblo2)*bininv2y);
if (hi < 0) continue;
if (hi >= nbin2y) error->all(FLERR,
"Fix SRD: bad search bin assignment");
lo = 0;
} else {
lo = static_cast<int> ((xwall[m]-delta-yblo2)*bininv2y);
if (lo >= nbin2y) continue;
if (lo < 0) error->all(FLERR,"Fix SRD: bad search bin assignment");
hi = nbin2y-1;
}
for (iy = lo; iy <= hi; iy++)
for (ix = 0; ix < nbin2x; ix++)
for (iz = 0; iz < nbin2z; iz++) {
ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix;
if (nbinbig[ibin] == ATOMPERBIN)
error->all(FLERR,"Fix SRD: too many walls in bin");
binbig[ibin][nbinbig[ibin]++] = nbig+m;
}
} else if (dim == 2) {
if (side == 0) {
hi = static_cast<int> ((xwall[m]+delta-zblo2)*bininv2z);
if (hi < 0) continue;
if (hi >= nbin2z) error->all(FLERR,
"Fix SRD: bad search bin assignment");
lo = 0;
} else {
lo = static_cast<int> ((xwall[m]-delta-zblo2)*bininv2z);
if (lo >= nbin2z) continue;
if (lo < 0) error->all(FLERR,"Fix SRD: bad search bin assignment");
hi = nbin2z-1;
}
for (iz = lo; iz < hi; iz++)
for (ix = 0; ix < nbin2x; ix++)
for (iy = 0; iy < nbin2y; iy++) {
ibin = iz*nbin2y*nbin2x + iy*nbin2x + ix;
if (nbinbig[ibin] == ATOMPERBIN)
error->all(FLERR,"Fix SRD: too many walls in bin");
binbig[ibin][nbinbig[ibin]++] = nbig+m;
}
}
}
}
// rotate SRD velocities on SRD timestep
// done now since all SRDs are currently inside my sub-domain
if (reneighflag == SRD_ROTATE) reset_velocities();
// log stats if reneighboring occurred b/c SRDs moved too far
if (reneighflag == SRD_MOVE) reneighcount++;
reneighflag = BIG_MOVE;
}
/* ----------------------------------------------------------------------
advect SRD particles and detect collisions between SRD and BIG particles
when collision occurs, change x,v of SRD, force,torque of BIG particle
------------------------------------------------------------------------- */
void FixSRD::post_force(int vflag)
{
int i,m,ix,iy,iz;
// zero per-timestep stats
stats_flag = 0;
ncheck = ncollide = nbounce = ninside = 0;
// zero ghost forces & torques on BIG particles
double **f = atom->f;
double **torque = atom->torque;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if (bigexist == 0) nall = 0;
for (i = nlocal; i < nall; i++)
f[i][0] = f[i][1] = f[i][2] = 0.0;
if (collidestyle == NOSLIP)
for (i = nlocal; i < nall; i++)
torque[i][0] = torque[i][1] = torque[i][2] = 0.0;
// advect SRD particles
// assign to search bins if big particles or walls exist
int *mask = atom->mask;
double **x = atom->x;
double **v = atom->v;
if (bigexist || wallexist) {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
x[i][0] += dt_big*v[i][0];
x[i][1] += dt_big*v[i][1];
x[i][2] += dt_big*v[i][2];
ix = static_cast<int> ((x[i][0]-xblo2)*bininv2x);
iy = static_cast<int> ((x[i][1]-yblo2)*bininv2y);
iz = static_cast<int> ((x[i][2]-zblo2)*bininv2z);
binsrd[i] = iz*nbin2y*nbin2x + iy*nbin2x + ix;
if (ix < 0 || ix >= nbin2x || iy < 0 || iy >= nbin2y ||
iz < 0 || iz >= nbin2z) {
if (screen) {
- fprintf(screen,"SRD particle %d on step " BIGINT_FORMAT "\n",
+ fprintf(screen,"SRD particle " TAGINT_FORMAT
+ " on step " BIGINT_FORMAT "\n",
atom->tag[i],update->ntimestep);
fprintf(screen,"v = %g %g %g\n",v[i][0],v[i][1],v[i][2]);
fprintf(screen,"x = %g %g %g\n",x[i][0],x[i][1],x[i][2]);
fprintf(screen,"ix,iy,iz nx,ny,nz = %d %d %d %d %d %d\n",
ix,iy,iz,nbin2x,nbin2y,nbin2z);
}
error->one(FLERR,"Fix SRD: bad bin assignment for SRD advection");
}
}
} else {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
x[i][0] += dt_big*v[i][0];
x[i][1] += dt_big*v[i][1];
x[i][2] += dt_big*v[i][2];
}
}
// detect collision of SRDs with BIG particles or walls
if (bigexist || wallexist) {
if (bigexist) big_dynamic();
if (wallexist) wallfix->wall_params(0);
if (overlap) collisions_multi();
else collisions_single();
}
// reverse communicate forces & torques on BIG particles
if (bigexist) {
flocal = f;
tlocal = torque;
comm->reverse_comm_fix(this);
}
// if any SRD particle has moved too far, trigger reneigh on next step
// for triclinic, perform check in lamda units
int flag = 0;
if (triclinic) domain->x2lamda(nlocal);
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (x[i][0] < srdlo_reneigh[0] || x[i][0] > srdhi_reneigh[0] ||
x[i][1] < srdlo_reneigh[1] || x[i][1] > srdhi_reneigh[1] ||
x[i][2] < srdlo_reneigh[2] || x[i][2] > srdhi_reneigh[2]) flag = 1;
}
if (triclinic) domain->lamda2x(nlocal);
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) {
next_reneighbor = update->ntimestep + 1;
reneighflag = SRD_MOVE;
}
// if wall has moved too far, trigger reneigh on next step
// analagous to neighbor check for big particle moving 1/2 of skin distance
if (wallexist) {
for (m = 0; m < nwall; m++)
if (fabs(xwall[m]-xwallhold[m]) > walltrigger)
next_reneighbor = update->ntimestep + 1;
}
// if next timestep is SRD timestep, trigger reneigh
if ((update->ntimestep+1) % nevery == 0) {
next_reneighbor = update->ntimestep + 1;
reneighflag = SRD_ROTATE;
}
}
/* ----------------------------------------------------------------------
reset SRD velocities
may perform random shifting by up to 1/2 bin in each dimension
called at pre-neighbor stage when all SRDs are now inside my sub-domain
if tstat, then thermostat SRD particles as well, including streaming effects
------------------------------------------------------------------------- */
void FixSRD::reset_velocities()
{
int i,j,n,ix,iy,iz,ibin,axis,sign,irandom;
double u[3],vsum[3];
double vsq,tbin,scale;
double *vave,*xlamda;
double vstream[3];
// if requested, perform a dynamic shift of bin positions
if (shiftflag) {
double *boxlo;
if (triclinic == 0) boxlo = domain->boxlo;
else boxlo = domain->boxlo_lamda;
shifts[1].corner[0] = boxlo[0] - binsize1x*randomshift->uniform();
shifts[1].corner[1] = boxlo[1] - binsize1y*randomshift->uniform();
if (dimension == 3)
shifts[1].corner[2] = boxlo[2] - binsize1z*randomshift->uniform();
else shifts[1].corner[2] = boxlo[2];
setup_velocity_shift(1,1);
}
double *corner = shifts[shiftflag].corner;
int *binlo = shifts[shiftflag].binlo;
int *binhi = shifts[shiftflag].binhi;
int nbins = shifts[shiftflag].nbins;
int nbinx = shifts[shiftflag].nbinx;
int nbiny = shifts[shiftflag].nbiny;
BinAve *vbin = shifts[shiftflag].vbin;
// binhead = 1st SRD particle in each bin
// binnext = index of next particle in bin
// bin assignment is done in lamda units for triclinic
int *mask = atom->mask;
double **x = atom->x;
double **v = atom->v;
int nlocal = atom->nlocal;
if (triclinic) domain->x2lamda(nlocal);
for (i = 0; i < nbins; i++) binhead[i] = -1;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
ix = static_cast<int> ((x[i][0]-corner[0])*bininv1x);
ix = MAX(ix,binlo[0]);
ix = MIN(ix,binhi[0]);
iy = static_cast<int> ((x[i][1]-corner[1])*bininv1y);
iy = MAX(iy,binlo[1]);
iy = MIN(iy,binhi[1]);
iz = static_cast<int> ((x[i][2]-corner[2])*bininv1z);
iz = MAX(iz,binlo[2]);
iz = MIN(iz,binhi[2]);
ibin = (iz-binlo[2])*nbiny*nbinx + (iy-binlo[1])*nbinx + (ix-binlo[0]);
binnext[i] = binhead[ibin];
binhead[ibin] = i;
}
if (triclinic) domain->lamda2x(nlocal);
// for each bin I have particles contributing to:
// compute summed v of particles in that bin
// if I own the bin, set its random value, else set to 0.0
for (i = 0; i < nbins; i++) {
n = 0;
vsum[0] = vsum[1] = vsum[2] = 0.0;
for (j = binhead[i]; j >= 0; j = binnext[j]) {
vsum[0] += v[j][0];
vsum[1] += v[j][1];
vsum[2] += v[j][2];
n++;
}
vbin[i].vsum[0] = vsum[0];
vbin[i].vsum[1] = vsum[1];
vbin[i].vsum[2] = vsum[2];
vbin[i].n = n;
if (vbin[i].owner) vbin[i].random = random->uniform();
else vbin[i].random = 0.0;
}
// communicate bin info for bins which more than 1 proc contribute to
if (shifts[shiftflag].commflag) vbin_comm(shiftflag);
// for each bin I have particles contributing to:
// compute vave over particles in bin
// thermal velocity of each particle = v - vave
// rotate thermal vel of each particle around one of 6 random axes
// add vave back to each particle
// thermostat if requested:
// if no deformation, rescale thermal vel to temperature
// if deformation, rescale thermal vel and change vave to vstream
// these are settings for extra dof_temp, dof_tstat to subtract
// (not sure why these settings work best)
// no deformation, no tstat: dof_temp = 1
// yes deformation, no tstat: doesn't matter, system will not equilibrate
// no deformation, yes tstat: dof_temp = dof_tstat = 1
// yes deformation, yes tstat: dof_temp = dof_tstat = 0
// accumulate final T_srd for each bin I own
double tfactor = force->mvv2e * mass_srd / (dimension * force->boltz);
int dof_temp = 1;
int dof_tstat;
if (tstat) {
if (deformflag) dof_tstat = dof_temp = 0;
else dof_tstat = 1;
}
srd_bin_temp = 0.0;
srd_bin_count = 0;
if (dimension == 2) axis = 2;
double *h_rate = domain->h_rate;
double *h_ratelo = domain->h_ratelo;
for (i = 0; i < nbins; i++) {
n = vbin[i].n;
if (n == 0) continue;
vave = vbin[i].vsum;
vave[0] /= n;
vave[1] /= n;
vave[2] /= n;
irandom = static_cast<int> (6.0*vbin[i].random);
sign = irandom % 2;
if (dimension == 3) axis = irandom / 2;
vsq = 0.0;
for (j = binhead[i]; j >= 0; j = binnext[j]) {
if (axis == 0) {
u[0] = v[j][0]-vave[0];
u[1] = sign ? v[j][2]-vave[2] : vave[2]-v[j][2];
u[2] = sign ? vave[1]-v[j][1] : v[j][1]-vave[1];
} else if (axis == 1) {
u[1] = v[j][1]-vave[1];
u[0] = sign ? v[j][2]-vave[2] : vave[2]-v[j][2];
u[2] = sign ? vave[0]-v[j][0] : v[j][0]-vave[0];
} else {
u[2] = v[j][2]-vave[2];
u[1] = sign ? v[j][0]-vave[0] : vave[0]-v[j][0];
u[0] = sign ? vave[1]-v[j][1] : v[j][1]-vave[1];
}
vsq += u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
v[j][0] = u[0] + vave[0];
v[j][1] = u[1] + vave[1];
v[j][2] = u[2] + vave[2];
}
// NOTE: vsq needs to be summed across shared bins in parallel
// like vave above via the vbin_comm() call
// else the computed scale factor below is incomplete for a shared bin
if (tstat && n > 1) {
if (deformflag) {
xlamda = vbin[i].xctr;
vstream[0] = h_rate[0]*xlamda[0] + h_rate[5]*xlamda[1] +
h_rate[4]*xlamda[2] + h_ratelo[0];
vstream[1] = h_rate[1]*xlamda[1] + h_rate[3]*xlamda[2] + h_ratelo[1];
vstream[2] = h_rate[2]*xlamda[2] + h_ratelo[2];
} else {
vstream[0] = vave[0];
vstream[1] = vave[1];
vstream[2] = vave[2];
}
// tbin = thermal temperature of particles in bin
// scale = scale factor for thermal velocity
tbin = vsq/(n-dof_tstat) * tfactor;
scale = sqrt(temperature_srd/tbin);
vsq = 0.0;
for (j = binhead[i]; j >= 0; j = binnext[j]) {
u[0] = (v[j][0] - vave[0]) * scale;
u[1] = (v[j][1] - vave[1]) * scale;
u[2] = (v[j][2] - vave[2]) * scale;
vsq += u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
v[j][0] = u[0] + vstream[0];
v[j][1] = u[1] + vstream[1];
v[j][2] = u[2] + vstream[2];
}
}
// sum partial contribution of my particles to T even if I don't own bin
// but only count bin if I own it, so each bin is counted exactly once
if (n > 1) srd_bin_temp += vsq/(n-dof_temp);
if (vbin[i].owner) srd_bin_count++;
}
srd_bin_temp *= tfactor;
// rescale any too-large velocities
if (rescale_rotate) {
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2];
if (vsq > vmaxsq) {
nrescale++;
MathExtra::scale3(vmax/sqrt(vsq),v[i]);
}
}
}
}
/* ----------------------------------------------------------------------
communicate summed particle info for bins that overlap 1 or more procs
------------------------------------------------------------------------- */
void FixSRD::vbin_comm(int ishift)
{
BinComm *bcomm1,*bcomm2;
MPI_Request request1,request2;
MPI_Status status;
// send/recv bins in both directions in each dimension
// don't send if nsend = 0
// due to static bins aliging with proc boundary
// due to dynamic bins across non-periodic global boundary
// copy to self if sendproc = me
// MPI send to another proc if sendproc != me
// don't recv if nrecv = 0
// copy from self if recvproc = me
// MPI recv from another proc if recvproc != me
BinAve *vbin = shifts[ishift].vbin;
int *procgrid = comm->procgrid;
int iswap = 0;
for (int idim = 0; idim < dimension; idim++) {
bcomm1 = &shifts[ishift].bcomm[iswap++];
bcomm2 = &shifts[ishift].bcomm[iswap++];
if (procgrid[idim] == 1) {
if (bcomm1->nsend)
vbin_pack(vbin,bcomm1->nsend,bcomm1->sendlist,sbuf1);
if (bcomm2->nsend)
vbin_pack(vbin,bcomm2->nsend,bcomm2->sendlist,sbuf2);
if (bcomm1->nrecv)
vbin_unpack(sbuf1,vbin,bcomm1->nrecv,bcomm1->recvlist);
if (bcomm2->nrecv)
vbin_unpack(sbuf2,vbin,bcomm2->nrecv,bcomm2->recvlist);
} else {
if (bcomm1->nrecv)
MPI_Irecv(rbuf1,bcomm1->nrecv*VBINSIZE,MPI_DOUBLE,bcomm1->recvproc,0,
world,&request1);
if (bcomm2->nrecv)
MPI_Irecv(rbuf2,bcomm2->nrecv*VBINSIZE,MPI_DOUBLE,bcomm2->recvproc,0,
world,&request2);
if (bcomm1->nsend) {
vbin_pack(vbin,bcomm1->nsend,bcomm1->sendlist,sbuf1);
MPI_Send(sbuf1,bcomm1->nsend*VBINSIZE,MPI_DOUBLE,
bcomm1->sendproc,0,world);
}
if (bcomm2->nsend) {
vbin_pack(vbin,bcomm2->nsend,bcomm2->sendlist,sbuf2);
MPI_Send(sbuf2,bcomm2->nsend*VBINSIZE,MPI_DOUBLE,
bcomm2->sendproc,0,world);
}
if (bcomm1->nrecv) {
MPI_Wait(&request1,&status);
vbin_unpack(rbuf1,vbin,bcomm1->nrecv,bcomm1->recvlist);
}
if (bcomm2->nrecv) {
MPI_Wait(&request2,&status);
vbin_unpack(rbuf2,vbin,bcomm2->nrecv,bcomm2->recvlist);
}
}
}
}
/* ----------------------------------------------------------------------
pack velocity bin data into a message buffer for sending
------------------------------------------------------------------------- */
void FixSRD::vbin_pack(BinAve *vbin, int n, int *list, double *buf)
{
int j;
int m = 0;
for (int i = 0; i < n; i++) {
j = list[i];
buf[m++] = vbin[j].n;
buf[m++] = vbin[j].vsum[0];
buf[m++] = vbin[j].vsum[1];
buf[m++] = vbin[j].vsum[2];
buf[m++] = vbin[j].random;
}
}
/* ----------------------------------------------------------------------
unpack velocity bin data from a message buffer and sum values to my bins
------------------------------------------------------------------------- */
void FixSRD::vbin_unpack(double *buf, BinAve *vbin, int n, int *list)
{
int j;
int m = 0;
for (int i = 0; i < n; i++) {
j = list[i];
vbin[j].n += static_cast<int> (buf[m++]);
vbin[j].vsum[0] += buf[m++];
vbin[j].vsum[1] += buf[m++];
vbin[j].vsum[2] += buf[m++];
vbin[j].random += buf[m++];
}
}
/* ----------------------------------------------------------------------
detect all collisions between SRD and BIG particles or WALLS
assume SRD can be inside at most one BIG particle or WALL at a time
unoverlap SRDs for each collision
------------------------------------------------------------------------- */
void FixSRD::collisions_single()
{
int i,j,k,m,type,nbig,ibin,ibounce,inside,collide_flag;
double dt,t_remain;
double norm[3],xscoll[3],xbcoll[3],vsnew[3];
Big *big;
// outer loop over SRD particles
// inner loop over BIG particles or WALLS that overlap SRD particle bin
// if overlap between SRD and BIG particle or wall:
// for exact, compute collision pt in time
// for inexact, push SRD to surf of BIG particle or WALL
// update x,v of SRD and f,torque on BIG particle
// re-bin SRD particle after collision
// iterate until the SRD particle has no overlaps with BIG particles or WALLS
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
ibin = binsrd[i];
if (nbinbig[ibin] == 0) continue;
ibounce = 0;
collide_flag = 1;
dt = dt_big;
while (collide_flag) {
nbig = nbinbig[ibin];
if (ibounce == 0) ncheck += nbig;
collide_flag = 0;
for (m = 0; m < nbig; m++) {
k = binbig[ibin][m];
big = &biglist[k];
j = big->index;
type = big->type;
if (type == SPHERE) inside = inside_sphere(x[i],x[j],big);
else if (type == ELLIPSOID) inside = inside_ellipsoid(x[i],x[j],big);
else inside = inside_wall(x[i],j);
if (inside) {
if (exactflag) {
if (type == SPHERE)
t_remain = collision_sphere_exact(x[i],x[j],v[i],v[j],big,
xscoll,xbcoll,norm);
else if (type == ELLIPSOID)
t_remain = collision_ellipsoid_exact(x[i],x[j],v[i],v[j],big,
xscoll,xbcoll,norm);
else
t_remain = collision_wall_exact(x[i],j,v[i],xscoll,xbcoll,norm);
} else {
t_remain = 0.5*dt;
if (type == SPHERE)
collision_sphere_inexact(x[i],x[j],big,xscoll,xbcoll,norm);
else if (type == ELLIPSOID)
collision_ellipsoid_inexact(x[i],x[j],big,xscoll,xbcoll,norm);
else
collision_wall_inexact(x[i],j,xscoll,xbcoll,norm);
}
#ifdef SRD_DEBUG
if (update->ntimestep == SRD_DEBUG_TIMESTEP &&
atom->tag[i] == SRD_DEBUG_ATOMID)
print_collision(i,j,ibounce,t_remain,dt,xscoll,xbcoll,norm,type);
#endif
if (t_remain > dt) {
ninside++;
if (insideflag == INSIDE_ERROR || insideflag == INSIDE_WARN) {
char str[128];
if (type != WALL)
sprintf(str,
- "SRD particle %d started "
- "inside big particle %d on step " BIGINT_FORMAT
- " bounce %d",
+ "SRD particle " TAGINT_FORMAT " started "
+ "inside big particle " TAGINT_FORMAT
+ " on step " BIGINT_FORMAT " bounce %d",
atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1);
else
sprintf(str,
- "SRD particle %d started "
- "inside big particle %d on step " BIGINT_FORMAT
- " bounce %d",
+ "SRD particle " TAGINT_FORMAT " started "
+ "inside big particle " TAGINT_FORMAT
+ " on step " BIGINT_FORMAT " bounce %d",
atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1);
if (insideflag == INSIDE_ERROR) error->one(FLERR,str);
error->warning(FLERR,str);
}
break;
}
if (collidestyle == SLIP) {
if (type != WALL) slip(v[i],v[j],x[j],big,xscoll,norm,vsnew);
else slip_wall(v[i],j,norm,vsnew);
} else {
if (type != WALL) noslip(v[i],v[j],x[j],big,-1, xscoll,norm,vsnew);
else noslip(v[i],NULL,x[j],big,j,xscoll,norm,vsnew);
}
if (dimension == 2) vsnew[2] = 0.0;
// check on rescaling of vsnew
if (rescale_collide) {
double vsq = vsnew[0]*vsnew[0] + vsnew[1]*vsnew[1] +
vsnew[2]*vsnew[2];
if (vsq > vmaxsq) {
nrescale++;
MathExtra::scale3(vmax/sqrt(vsq),vsnew);
}
}
// update BIG particle and WALL and SRD
// BIG particle is not torqued if sphere and SLIP collision
if (collidestyle == SLIP && type == SPHERE)
force_torque(v[i],vsnew,xscoll,xbcoll,f[j],NULL);
else if (type != WALL)
force_torque(v[i],vsnew,xscoll,xbcoll,f[j],torque[j]);
else if (type == WALL)
force_wall(v[i],vsnew,j);
ibin = binsrd[i] = update_srd(i,t_remain,xscoll,vsnew,x[i],v[i]);
if (ibounce == 0) ncollide++;
ibounce++;
if (ibounce < maxbounceallow || maxbounceallow == 0)
collide_flag = 1;
dt = t_remain;
break;
}
}
}
nbounce += ibounce;
if (maxbounceallow && ibounce >= maxbounceallow) bouncemaxnum++;
if (ibounce > bouncemax) bouncemax = ibounce;
}
}
/* ----------------------------------------------------------------------
detect all collisions between SRD and big particles
an SRD can be inside more than one big particle at a time
requires finding which big particle SRD collided with first
unoverlap SRDs for each collision
------------------------------------------------------------------------- */
void FixSRD::collisions_multi()
{
int i,j,k,m,type,nbig,ibin,ibounce,inside,jfirst,typefirst,jlast;
double dt,t_remain,t_first;
double norm[3],xscoll[3],xbcoll[3],vsnew[3];
double normfirst[3],xscollfirst[3],xbcollfirst[3];
Big *big;
// outer loop over SRD particles
// inner loop over BIG particles or WALLS that overlap SRD particle bin
// loop over all BIG and WALLS to find which one SRD collided with first
// if overlap between SRD and BIG particle or wall:
// compute collision pt in time
// update x,v of SRD and f,torque on BIG particle
// re-bin SRD particle after collision
// iterate until the SRD particle has no overlaps with BIG particles or WALLS
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) {
if (!(mask[i] & groupbit)) continue;
ibin = binsrd[i];
if (nbinbig[ibin] == 0) continue;
ibounce = 0;
jlast = -1;
dt = dt_big;
while (1) {
nbig = nbinbig[ibin];
if (ibounce == 0) ncheck += nbig;
t_first = 0.0;
for (m = 0; m < nbig; m++) {
k = binbig[ibin][m];
big = &biglist[k];
j = big->index;
if (j == jlast) continue;
type = big->type;
if (type == SPHERE)
inside = inside_sphere(x[i],x[j],big);
else if (type == ELLIPSOID)
inside = inside_ellipsoid(x[i],x[j],big);
else if (type == LINE)
inside = inside_line(x[i],x[j],v[i],v[j],big,dt);
else if (type == TRIANGLE)
inside = inside_tri(x[i],x[j],v[i],v[j],big,dt);
else
inside = inside_wall(x[i],j);
if (inside) {
if (type == SPHERE)
t_remain = collision_sphere_exact(x[i],x[j],v[i],v[j],big,
xscoll,xbcoll,norm);
else if (type == ELLIPSOID)
t_remain = collision_ellipsoid_exact(x[i],x[j],v[i],v[j],big,
xscoll,xbcoll,norm);
else if (type == LINE)
t_remain = collision_line_exact(x[i],x[j],v[i],v[j],big,dt,
xscoll,xbcoll,norm);
else if (type == TRIANGLE)
t_remain = collision_tri_exact(x[i],x[j],v[i],v[j],big,dt,
xscoll,xbcoll,norm);
else
t_remain = collision_wall_exact(x[i],j,v[i],xscoll,xbcoll,norm);
#ifdef SRD_DEBUG
if (update->ntimestep == SRD_DEBUG_TIMESTEP &&
atom->tag[i] == SRD_DEBUG_ATOMID)
print_collision(i,j,ibounce,t_remain,dt,xscoll,xbcoll,norm,type);
#endif
if (t_remain > dt || t_remain < 0.0) {
ninside++;
if (insideflag == INSIDE_ERROR || insideflag == INSIDE_WARN) {
char str[128];
sprintf(str,
- "SRD particle %d started "
- "inside big particle %d on step " BIGINT_FORMAT
- " bounce %d",
+ "SRD particle " TAGINT_FORMAT " started "
+ "inside big particle " TAGINT_FORMAT
+ " on step " BIGINT_FORMAT " bounce %d",
atom->tag[i],atom->tag[j],update->ntimestep,ibounce+1);
if (insideflag == INSIDE_ERROR) error->one(FLERR,str);
error->warning(FLERR,str);
}
t_first = 0.0;
break;
}
if (t_remain > t_first) {
t_first = t_remain;
jfirst = j;
typefirst = type;
xscollfirst[0] = xscoll[0];
xscollfirst[1] = xscoll[1];
xscollfirst[2] = xscoll[2];
xbcollfirst[0] = xbcoll[0];
xbcollfirst[1] = xbcoll[1];
xbcollfirst[2] = xbcoll[2];
normfirst[0] = norm[0];
normfirst[1] = norm[1];
normfirst[2] = norm[2];
}
}
}
if (t_first == 0.0) break;
j = jlast = jfirst;
type = typefirst;
xscoll[0] = xscollfirst[0];
xscoll[1] = xscollfirst[1];
xscoll[2] = xscollfirst[2];
xbcoll[0] = xbcollfirst[0];
xbcoll[1] = xbcollfirst[1];
xbcoll[2] = xbcollfirst[2];
norm[0] = normfirst[0];
norm[1] = normfirst[1];
norm[2] = normfirst[2];
if (collidestyle == SLIP) {
if (type != WALL) slip(v[i],v[j],x[j],big,xscoll,norm,vsnew);
else slip_wall(v[i],j,norm,vsnew);
} else {
if (type != WALL) noslip(v[i],v[j],x[j],big,-1,xscoll,norm,vsnew);
else noslip(v[i],NULL,x[j],big,j,xscoll,norm,vsnew);
}
if (dimension == 2) vsnew[2] = 0.0;
// check on rescaling of vsnew
if (rescale_collide) {
double vsq = vsnew[0]*vsnew[0] + vsnew[1]*vsnew[1] + vsnew[2]*vsnew[2];
if (vsq > vmaxsq) {
nrescale++;
MathExtra::scale3(vmax/sqrt(vsq),vsnew);
}
}
// update BIG particle and WALL and SRD
// BIG particle is not torqued if sphere and SLIP collision
if (collidestyle == SLIP && type == SPHERE)
force_torque(v[i],vsnew,xscoll,xbcoll,f[j],NULL);
else if (type != WALL)
force_torque(v[i],vsnew,xscoll,xbcoll,f[j],torque[j]);
else if (type == WALL)
force_wall(v[i],vsnew,j);
ibin = binsrd[i] = update_srd(i,t_first,xscoll,vsnew,x[i],v[i]);
if (ibounce == 0) ncollide++;
ibounce++;
if (ibounce == maxbounceallow) break;
dt = t_first;
}
nbounce += ibounce;
if (maxbounceallow && ibounce >= maxbounceallow) bouncemaxnum++;
if (ibounce > bouncemax) bouncemax = ibounce;
}
}
/* ----------------------------------------------------------------------
check if SRD particle S is inside spherical big particle B
------------------------------------------------------------------------- */
int FixSRD::inside_sphere(double *xs, double *xb, Big *big)
{
double dx,dy,dz;
dx = xs[0] - xb[0];
dy = xs[1] - xb[1];
dz = xs[2] - xb[2];
if (dx*dx + dy*dy + dz*dz <= big->radsq) return 1;
return 0;
}
/* ----------------------------------------------------------------------
check if SRD particle S is inside ellipsoidal big particle B
------------------------------------------------------------------------- */
int FixSRD::inside_ellipsoid(double *xs, double *xb, Big *big)
{
double x,y,z;
double *ex = big->ex;
double *ey = big->ey;
double *ez = big->ez;
double xs_xb[3];
xs_xb[0] = xs[0] - xb[0];
xs_xb[1] = xs[1] - xb[1];
xs_xb[2] = xs[2] - xb[2];
x = xs_xb[0]*ex[0] + xs_xb[1]*ex[1] + xs_xb[2]*ex[2];
y = xs_xb[0]*ey[0] + xs_xb[1]*ey[1] + xs_xb[2]*ey[2];
z = xs_xb[0]*ez[0] + xs_xb[1]*ez[1] + xs_xb[2]*ez[2];
if (x*x*big->aradsqinv + y*y*big->bradsqinv + z*z*big->cradsqinv <= 1.0)
return 1;
return 0;
}
/* ----------------------------------------------------------------------
check if SRD particle S is inside line big particle B
collision only possible if:
S starts on positive side of infinite line,
which means it will collide with outside of rigid body made of lines
since line segments have outward normals,
when vector from first to last point is crossed with +z axis
S ends on negative side of infinite line
unlike most other inside() routines, then calculate exact collision:
solve for collision pt along infinite line
collision if pt is within endpoints of B
------------------------------------------------------------------------- */
int FixSRD::inside_line(double *xs, double *xb, double *vs, double *vb,
Big *big, double dt_step)
{
double pmc0[2],pmc1[2],n0[2],n1[2];
// 1 and 2 = start and end of timestep
// pmc = P - C, where P = position of S, C = position of B
// n = normal to line = [-sin(theta),cos(theta)], theta = orientation of B
// (P-C) dot N = side of line that S is on
// side0 = -1,0,1 for which side of line B that S is on at start of step
// side1 = -1,0,1 for which side of line B that S is on at end of step
xs1[0] = xs[0];
xs1[1] = xs[1];
xb1[0] = xb[0];
xb1[1] = xb[1];
xs0[0] = xs1[0] - dt_step*vs[0];
xs0[1] = xs1[1] - dt_step*vs[1];
xb0[0] = xb1[0] - dt_step*vb[0];
xb0[1] = xb1[1] - dt_step*vb[1];
theta1 = big->theta;
theta0 = theta1 - dt_step*big->omega[2];
pmc0[0] = xs0[0] - xb0[0];
pmc0[1] = xs0[1] - xb0[1];
n0[0] = sin(theta0);
n0[1] = -cos(theta0);
pmc1[0] = xs1[0] - xb1[0];
pmc1[1] = xs1[1] - xb1[1];
n1[0] = sin(theta1);
n1[1] = -cos(theta1);
double side0 = pmc0[0]*n0[0] + pmc0[1]*n0[1];
double side1 = pmc1[0]*n1[0] + pmc1[1]*n1[1];
if (side0 <= 0.0 || side1 >= 0.0) return 0;
// solve for time t (0 to 1) at which moving particle
// crosses infinite moving/rotating line
// Newton-Raphson solve of full non-linear parametric equation
tfraction = newton_raphson(0.0,1.0);
// quadratic equation solve of approximate parametric equation
/*
n1_n0[0] = n1[0]-n0[0]; n1_n0[1] = n1[1]-n0[1];
pmc1_pmc0[0] = pmc1[0]-pmc0[0]; pmc1_pmc0[1] = pmc1[1]-pmc0[1];
double a = pmc1_pmc0[0]*n1_n0[0] + pmc1_pmc0[1]*n1_n0[1];
double b = pmc1_pmc0[0]*n0[0] + pmc1_pmc0[1]*n0[1] +
n1_n0[0]*pmc0[0] + n1_n0[1]*pmc0[1];
double c = pmc0[0]*n0[0] + pmc0[1]*n0[1];
if (a == 0.0) {
double dot0 = pmc0[0]*n0[0] + pmc0[1]*n0[1];
double dot1 = pmc1[0]*n0[0] + pmc1[1]*n0[1];
double root = -dot0 / (dot1 - dot0);
//printf("Linear root: %g %g\n",root,tfraction);
tfraction = root;
} else {
double term = sqrt(b*b - 4.0*a*c);
double root1 = (-b + term) / (2.0*a);
double root2 = (-b - term) / (2.0*a);
//printf("ABC vecs: %g %g: %g %g\n",
// pmc1_pmc0[0],pmc1_pmc0[1],n1_n0[0],n1_n0[1]);
//printf("ABC vecs: %g %g: %g %g: %g %g %g\n",
// n0[0],n0[1],n1[0],n1[1],theta0,theta1,big->omega[2]);
//printf("ABC root: %g %g %g: %g %g %g\n",a,b,c,root1,root2,tfraction);
if (0.0 <= root1 && root1 <= 1.0) tfraction = root1;
else if (0.0 <= root2 && root2 <= 1.0) tfraction = root2;
else error->one(FLERR,"Bad quadratic solve for particle/line collision");
}
*/
// check if collision pt is within line segment at collision time
xsc[0] = xs0[0] + tfraction*(xs1[0]-xs0[0]);
xsc[1] = xs0[1] + tfraction*(xs1[1]-xs0[1]);
xbc[0] = xb0[0] + tfraction*(xb1[0]-xb0[0]);
xbc[1] = xb0[1] + tfraction*(xb1[1]-xb0[1]);
double delx = xsc[0] - xbc[0];
double dely = xsc[1] - xbc[1];
double rsq = delx*delx + dely*dely;
if (rsq > 0.25*big->length*big->length) return 0;
//nbc[0] = n0[0] + tfraction*(n1[0]-n0[0]);
//nbc[1] = n0[1] + tfraction*(n1[1]-n0[1]);
nbc[0] = sin(theta0 + tfraction*(theta1-theta0));
nbc[1] = -cos(theta0 + tfraction*(theta1-theta0));
return 1;
}
/* ----------------------------------------------------------------------
check if SRD particle S is inside triangle big particle B
collision only possible if:
S starts on positive side of triangle plane,
which means it will collide with outside of rigid body made of tris
since triangles have outward normals,
S ends on negative side of triangle plane
unlike most other inside() routines, then calculate exact collision:
solve for collision pt on triangle plane
collision if pt is inside triangle B
------------------------------------------------------------------------- */
int FixSRD::inside_tri(double *xs, double *xb, double *vs, double *vb,
Big *big, double dt_step)
{
double pmc0[3],pmc1[3],n0[3];
double n1_n0[3],pmc1_pmc0[3];
double excoll[3],eycoll[3],ezcoll[3];
double dc1[3],dc2[3],dc3[3];
double c1[3],c2[3],c3[3];
double c2mc1[3],c3mc2[3],c1mc3[3];
double pvec[3],xproduct[3];
// 1 and 2 = start and end of timestep
// pmc = P - C, where P = position of S, C = position of B
// n = normal to triangle
// (P-C) dot N = side of tri that S is on
// side0 = -1,0,1 for which side of tri B that S is on at start of step
// side1 = -1,0,1 for which side of tri B that S is on at end of step
double *omega = big->omega;
double *n1 = big->norm;
n0[0] = n1[0] - dt_step*(omega[1]*n1[2] - omega[2]*n1[1]);
n0[1] = n1[1] - dt_step*(omega[2]*n1[0] - omega[0]*n1[2]);
n0[2] = n1[2] - dt_step*(omega[0]*n1[1] - omega[1]*n1[0]);
pmc0[0] = xs[0] - dt_step*vs[0] - xb[0] + dt_step*vb[0];
pmc0[1] = xs[1] - dt_step*vs[1] - xb[1] + dt_step*vb[1];
pmc0[2] = xs[2] - dt_step*vs[2] - xb[2] + dt_step*vb[2];
pmc1[0] = xs[0] - xb[0];
pmc1[1] = xs[1] - xb[1];
pmc1[2] = xs[2] - xb[2];
double side0 = MathExtra::dot3(pmc0,n0);
double side1 = MathExtra::dot3(pmc1,n1);
if (side0 <= 0.0 || side1 >= 0.0) return 0;
// solve for time t (0 to 1) at which moving particle
// crosses moving/rotating tri
// quadratic equation solve of approximate parametric equation
n1_n0[0] = n1[0]-n0[0];
n1_n0[1] = n1[1]-n0[1];
n1_n0[2] = n1[2]-n0[2];
pmc1_pmc0[0] = pmc1[0]-pmc0[0];
pmc1_pmc0[1] = pmc1[1]-pmc0[1];
pmc1_pmc0[2] = pmc1[2]-pmc0[2];
double a = MathExtra::dot3(pmc1_pmc0,n1_n0);
double b = MathExtra::dot3(pmc1_pmc0,n0) + MathExtra::dot3(n1_n0,pmc0);
double c = MathExtra::dot3(pmc0,n0);
if (a == 0.0) {
double dot0 = MathExtra::dot3(pmc0,n0);
double dot1 = MathExtra::dot3(pmc1,n0);
double root = -dot0 / (dot1 - dot0);
tfraction = root;
} else {
double term = sqrt(b*b - 4.0*a*c);
double root1 = (-b + term) / (2.0*a);
double root2 = (-b - term) / (2.0*a);
if (0.0 <= root1 && root1 <= 1.0) tfraction = root1;
else if (0.0 <= root2 && root2 <= 1.0) tfraction = root2;
else error->one(FLERR,"Bad quadratic solve for particle/tri collision");
}
// calculate position/orientation of S and B at collision time
// dt = time previous to now at which collision occurs
// point = S position in plane of triangle at collision time
// Excoll,Eycoll,Ezcoll = orientation of tri at collision time
// c1,c2,c3 = corner points of triangle at collision time
// nbc = normal to plane of triangle at collision time
AtomVecTri::Bonus *tbonus;
tbonus = avec_tri->bonus;
double *ex = big->ex;
double *ey = big->ey;
double *ez = big->ez;
int index = atom->tri[big->index];
double *c1body = tbonus[index].c1;
double *c2body = tbonus[index].c2;
double *c3body = tbonus[index].c3;
double dt = (1.0-tfraction)*dt_step;
xsc[0] = xs[0] - dt*vs[0];
xsc[1] = xs[1] - dt*vs[1];
xsc[2] = xs[2] - dt*vs[2];
xbc[0] = xb[0] - dt*vb[0];
xbc[1] = xb[1] - dt*vb[1];
xbc[2] = xb[2] - dt*vb[2];
excoll[0] = ex[0] - dt*(omega[1]*ex[2] - omega[2]*ex[1]);
excoll[1] = ex[1] - dt*(omega[2]*ex[0] - omega[0]*ex[2]);
excoll[2] = ex[2] - dt*(omega[0]*ex[1] - omega[1]*ex[0]);
eycoll[0] = ey[0] - dt*(omega[1]*ey[2] - omega[2]*ey[1]);
eycoll[1] = ey[1] - dt*(omega[2]*ey[0] - omega[0]*ey[2]);
eycoll[2] = ey[2] - dt*(omega[0]*ey[1] - omega[1]*ey[0]);
ezcoll[0] = ez[0] - dt*(omega[1]*ez[2] - omega[2]*ez[1]);
ezcoll[1] = ez[1] - dt*(omega[2]*ez[0] - omega[0]*ez[2]);
ezcoll[2] = ez[2] - dt*(omega[0]*ez[1] - omega[1]*ez[0]);
MathExtra::matvec(excoll,eycoll,ezcoll,c1body,dc1);
MathExtra::matvec(excoll,eycoll,ezcoll,c2body,dc2);
MathExtra::matvec(excoll,eycoll,ezcoll,c3body,dc3);
MathExtra::add3(xbc,dc1,c1);
MathExtra::add3(xbc,dc2,c2);
MathExtra::add3(xbc,dc3,c3);
MathExtra::sub3(c2,c1,c2mc1);
MathExtra::sub3(c3,c2,c3mc2);
MathExtra::sub3(c1,c3,c1mc3);
MathExtra::cross3(c2mc1,c3mc2,nbc);
MathExtra::norm3(nbc);
// check if collision pt is within triangle
// pvec = vector from tri vertex to intersection point
// xproduct = cross product of edge vec with pvec
// if dot product of xproduct with nbc < 0.0 for any of 3 edges,
// intersection point is outside tri
MathExtra::sub3(xsc,c1,pvec);
MathExtra::cross3(c2mc1,pvec,xproduct);
if (MathExtra::dot3(xproduct,nbc) < 0.0) return 0;
MathExtra::sub3(xsc,c2,pvec);
MathExtra::cross3(c3mc2,pvec,xproduct);
if (MathExtra::dot3(xproduct,nbc) < 0.0) return 0;
MathExtra::sub3(xsc,c3,pvec);
MathExtra::cross3(c1mc3,pvec,xproduct);
if (MathExtra::dot3(xproduct,nbc) < 0.0) return 0;
return 1;
}
/* ----------------------------------------------------------------------
check if SRD particle S is inside wall IWALL
------------------------------------------------------------------------- */
int FixSRD::inside_wall(double *xs, int iwall)
{
int dim = wallwhich[iwall] / 2;
int side = wallwhich[iwall] % 2;
if (side == 0 && xs[dim] < xwall[iwall]) return 1;
if (side && xs[dim] > xwall[iwall]) return 1;
return 0;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of spherical big particle B
exact because compute time of collision
dt = time previous to now at which collision occurs
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
double FixSRD::collision_sphere_exact(double *xs, double *xb,
double *vs, double *vb, Big *big,
double *xscoll, double *xbcoll,
double *norm)
{
double vs_dot_vs,vb_dot_vb,vs_dot_vb;
double vs_dot_xb,vb_dot_xs,vs_dot_xs,vb_dot_xb;
double xs_dot_xs,xb_dot_xb,xs_dot_xb;
double a,b,c,scale;
vs_dot_vs = vs[0]*vs[0] + vs[1]*vs[1] + vs[2]*vs[2];
vb_dot_vb = vb[0]*vb[0] + vb[1]*vb[1] + vb[2]*vb[2];
vs_dot_vb = vs[0]*vb[0] + vs[1]*vb[1] + vs[2]*vb[2];
vs_dot_xb = vs[0]*xb[0] + vs[1]*xb[1] + vs[2]*xb[2];
vb_dot_xs = vb[0]*xs[0] + vb[1]*xs[1] + vb[2]*xs[2];
vs_dot_xs = vs[0]*xs[0] + vs[1]*xs[1] + vs[2]*xs[2];
vb_dot_xb = vb[0]*xb[0] + vb[1]*xb[1] + vb[2]*xb[2];
xs_dot_xs = xs[0]*xs[0] + xs[1]*xs[1] + xs[2]*xs[2];
xb_dot_xb = xb[0]*xb[0] + xb[1]*xb[1] + xb[2]*xb[2];
xs_dot_xb = xs[0]*xb[0] + xs[1]*xb[1] + xs[2]*xb[2];
a = vs_dot_vs + vb_dot_vb - 2.0*vs_dot_vb;
b = 2.0 * (vs_dot_xb + vb_dot_xs - vs_dot_xs - vb_dot_xb);
c = xs_dot_xs + xb_dot_xb - 2.0*xs_dot_xb - big->radsq;
double dt = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a);
xscoll[0] = xs[0] - dt*vs[0];
xscoll[1] = xs[1] - dt*vs[1];
xscoll[2] = xs[2] - dt*vs[2];
xbcoll[0] = xb[0] - dt*vb[0];
xbcoll[1] = xb[1] - dt*vb[1];
xbcoll[2] = xb[2] - dt*vb[2];
norm[0] = xscoll[0] - xbcoll[0];
norm[1] = xscoll[1] - xbcoll[1];
norm[2] = xscoll[2] - xbcoll[2];
scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
norm[0] *= scale;
norm[1] *= scale;
norm[2] *= scale;
return dt;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of spherical big particle B
inexact because just push SRD to surface of big particle at end of step
time of collision = end of step
xscoll = collision pt = position of SRD at time of collision
xbcoll = xb = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
void FixSRD::collision_sphere_inexact(double *xs, double *xb,
Big *big,
double *xscoll, double *xbcoll,
double *norm)
{
double scale;
norm[0] = xs[0] - xb[0];
norm[1] = xs[1] - xb[1];
norm[2] = xs[2] - xb[2];
scale = 1.0/sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
norm[0] *= scale;
norm[1] *= scale;
norm[2] *= scale;
xscoll[0] = xb[0] + big->radius*norm[0];
xscoll[1] = xb[1] + big->radius*norm[1];
xscoll[2] = xb[2] + big->radius*norm[2];
xbcoll[0] = xb[0];
xbcoll[1] = xb[1];
xbcoll[2] = xb[2];
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of ellipsoidal big particle B
exact because compute time of collision
dt = time previous to now at which collision occurs
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
double FixSRD::collision_ellipsoid_exact(double *xs, double *xb,
double *vs, double *vb, Big *big,
double *xscoll, double *xbcoll,
double *norm)
{
double vs_vb[3],xs_xb[3],omega_ex[3],omega_ey[3],omega_ez[3];
double excoll[3],eycoll[3],ezcoll[3],delta[3],xbody[3],nbody[3];
double ax,bx,cx,ay,by,cy,az,bz,cz;
double a,b,c;
double *omega = big->omega;
double *ex = big->ex;
double *ey = big->ey;
double *ez = big->ez;
vs_vb[0] = vs[0]-vb[0]; vs_vb[1] = vs[1]-vb[1]; vs_vb[2] = vs[2]-vb[2];
xs_xb[0] = xs[0]-xb[0]; xs_xb[1] = xs[1]-xb[1]; xs_xb[2] = xs[2]-xb[2];
MathExtra::cross3(omega,ex,omega_ex);
MathExtra::cross3(omega,ey,omega_ey);
MathExtra::cross3(omega,ez,omega_ez);
ax = vs_vb[0]*omega_ex[0] + vs_vb[1]*omega_ex[1] + vs_vb[2]*omega_ex[2];
bx = -(vs_vb[0]*ex[0] + vs_vb[1]*ex[1] + vs_vb[2]*ex[2]);
bx -= xs_xb[0]*omega_ex[0] + xs_xb[1]*omega_ex[1] + xs_xb[2]*omega_ex[2];
cx = xs_xb[0]*ex[0] + xs_xb[1]*ex[1] + xs_xb[2]*ex[2];
ay = vs_vb[0]*omega_ey[0] + vs_vb[1]*omega_ey[1] + vs_vb[2]*omega_ey[2];
by = -(vs_vb[0]*ey[0] + vs_vb[1]*ey[1] + vs_vb[2]*ey[2]);
by -= xs_xb[0]*omega_ey[0] + xs_xb[1]*omega_ey[1] + xs_xb[2]*omega_ey[2];
cy = xs_xb[0]*ey[0] + xs_xb[1]*ey[1] + xs_xb[2]*ey[2];
az = vs_vb[0]*omega_ez[0] + vs_vb[1]*omega_ez[1] + vs_vb[2]*omega_ez[2];
bz = -(vs_vb[0]*ez[0] + vs_vb[1]*ez[1] + vs_vb[2]*ez[2]);
bz -= xs_xb[0]*omega_ez[0] + xs_xb[1]*omega_ez[1] + xs_xb[2]*omega_ez[2];
cz = xs_xb[0]*ez[0] + xs_xb[1]*ez[1] + xs_xb[2]*ez[2];
a = (bx*bx + 2.0*ax*cx)*big->aradsqinv +
(by*by + 2.0*ay*cy)*big->bradsqinv +
(bz*bz + 2.0*az*cz)*big->cradsqinv;
b = 2.0 * (bx*cx*big->aradsqinv + by*cy*big->bradsqinv +
bz*cz*big->cradsqinv);
c = cx*cx*big->aradsqinv + cy*cy*big->bradsqinv +
cz*cz*big->cradsqinv - 1.0;
double dt = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a);
xscoll[0] = xs[0] - dt*vs[0];
xscoll[1] = xs[1] - dt*vs[1];
xscoll[2] = xs[2] - dt*vs[2];
xbcoll[0] = xb[0] - dt*vb[0];
xbcoll[1] = xb[1] - dt*vb[1];
xbcoll[2] = xb[2] - dt*vb[2];
// calculate normal to ellipsoid at collision pt
// Excoll,Eycoll,Ezcoll = orientation of ellipsoid at collision time
// nbody = normal in body frame of ellipsoid (Excoll,Eycoll,Ezcoll)
// norm = normal in space frame
// only worry about normalizing final norm vector
excoll[0] = ex[0] - dt*(omega[1]*ex[2] - omega[2]*ex[1]);
excoll[1] = ex[1] - dt*(omega[2]*ex[0] - omega[0]*ex[2]);
excoll[2] = ex[2] - dt*(omega[0]*ex[1] - omega[1]*ex[0]);
eycoll[0] = ey[0] - dt*(omega[1]*ey[2] - omega[2]*ey[1]);
eycoll[1] = ey[1] - dt*(omega[2]*ey[0] - omega[0]*ey[2]);
eycoll[2] = ey[2] - dt*(omega[0]*ey[1] - omega[1]*ey[0]);
ezcoll[0] = ez[0] - dt*(omega[1]*ez[2] - omega[2]*ez[1]);
ezcoll[1] = ez[1] - dt*(omega[2]*ez[0] - omega[0]*ez[2]);
ezcoll[2] = ez[2] - dt*(omega[0]*ez[1] - omega[1]*ez[0]);
MathExtra::sub3(xscoll,xbcoll,delta);
MathExtra::transpose_matvec(excoll,eycoll,ezcoll,delta,xbody);
nbody[0] = xbody[0]*big->aradsqinv;
nbody[1] = xbody[1]*big->bradsqinv;
nbody[2] = xbody[2]*big->cradsqinv;
MathExtra::matvec(excoll,eycoll,ezcoll,nbody,norm);
MathExtra::norm3(norm);
return dt;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of ellipsoidal big particle B
inexact because just push SRD to surface of big particle at end of step
time of collision = end of step
xscoll = collision pt = position of SRD at time of collision
xbcoll = xb = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
void FixSRD::collision_ellipsoid_inexact(double *xs, double *xb,
Big *big,
double *xscoll, double *xbcoll,
double *norm)
{
double xs_xb[3],delta[3],xbody[3],nbody[3];
double *ex = big->ex;
double *ey = big->ey;
double *ez = big->ez;
MathExtra::sub3(xs,xb,xs_xb);
double x = MathExtra::dot3(xs_xb,ex);
double y = MathExtra::dot3(xs_xb,ey);
double z = MathExtra::dot3(xs_xb,ez);
double scale = 1.0/sqrt(x*x*big->aradsqinv + y*y*big->bradsqinv +
z*z*big->cradsqinv);
x *= scale;
y *= scale;
z *= scale;
xscoll[0] = x*ex[0] + y*ey[0] + z*ez[0] + xb[0];
xscoll[1] = x*ex[1] + y*ey[1] + z*ez[1] + xb[1];
xscoll[2] = x*ex[2] + y*ey[2] + z*ez[2] + xb[2];
xbcoll[0] = xb[0];
xbcoll[1] = xb[1];
xbcoll[2] = xb[2];
// calculate normal to ellipsoid at collision pt
// nbody = normal in body frame of ellipsoid
// norm = normal in space frame
// only worry about normalizing final norm vector
MathExtra::sub3(xscoll,xbcoll,delta);
MathExtra::transpose_matvec(ex,ey,ez,delta,xbody);
nbody[0] = xbody[0]*big->aradsqinv;
nbody[1] = xbody[1]*big->bradsqinv;
nbody[2] = xbody[2]*big->cradsqinv;
MathExtra::matvec(ex,ey,ez,nbody,norm);
MathExtra::norm3(norm);
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of line big particle B
exact because compute time of collision
dt = time previous to now at which collision occurs
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
double FixSRD::collision_line_exact(double *xs, double *xb,
double *vs, double *vb, Big *big,
double dt_step,
double *xscoll, double *xbcoll,
double *norm)
{
xscoll[0] = xsc[0];
xscoll[1] = xsc[1];
xscoll[2] = 0.0;
xbcoll[0] = xbc[0];
xbcoll[1] = xbc[1];
xbcoll[2] = 0.0;
norm[0] = nbc[0];
norm[1] = nbc[1];
norm[2] = 0.0;
return (1.0-tfraction)*dt_step;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with surface of triangle big particle B
exact because compute time of collision
dt = time previous to now at which collision occurs
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of big particle at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
double FixSRD::collision_tri_exact(double *xs, double *xb,
double *vs, double *vb, Big *big,
double dt_step,
double *xscoll, double *xbcoll,
double *norm)
{
xscoll[0] = xsc[0];
xscoll[1] = xsc[1];
xscoll[2] = xsc[2];
xbcoll[0] = xbc[0];
xbcoll[1] = xbc[1];
xbcoll[2] = xbc[2];
norm[0] = nbc[0];
norm[1] = nbc[1];
norm[2] = nbc[2];
return (1.0-tfraction)*dt_step;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with wall IWALL
exact because compute time of collision
dt = time previous to now at which collision occurs
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of wall at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
double FixSRD::collision_wall_exact(double *xs, int iwall, double *vs,
double *xscoll, double *xbcoll,
double *norm)
{
int dim = wallwhich[iwall] / 2;
double dt = (xs[dim] - xwall[iwall]) / (vs[dim] - vwall[iwall]);
xscoll[0] = xs[0] - dt*vs[0];
xscoll[1] = xs[1] - dt*vs[1];
xscoll[2] = xs[2] - dt*vs[2];
xbcoll[0] = xbcoll[1] = xbcoll[2] = 0.0;
xbcoll[dim] = xwall[iwall] - dt*vwall[iwall];
int side = wallwhich[iwall] % 2;
norm[0] = norm[1] = norm[2] = 0.0;
if (side == 0) norm[dim] = 1.0;
else norm[dim] = -1.0;
return dt;
}
/* ----------------------------------------------------------------------
collision of SRD particle S with wall IWALL
inexact because just push SRD to surface of wall at end of step
time of collision = end of step
xscoll = collision pt = position of SRD at time of collision
xbcoll = position of wall at time of collision
norm = surface normal of collision pt at time of collision
------------------------------------------------------------------------- */
void FixSRD::collision_wall_inexact(double *xs, int iwall, double *xscoll,
double *xbcoll, double *norm)
{
int dim = wallwhich[iwall] / 2;
xscoll[0] = xs[0];
xscoll[1] = xs[1];
xscoll[2] = xs[2];
xscoll[dim] = xwall[iwall];
xbcoll[0] = xbcoll[1] = xbcoll[2] = 0.0;
xbcoll[dim] = xwall[iwall];
int side = wallwhich[iwall] % 2;
norm[0] = norm[1] = norm[2] = 0.0;
if (side == 0) norm[dim] = 1.0;
else norm[dim] = -1.0;
}
/* ----------------------------------------------------------------------
SLIP collision with BIG particle with omega
vs = velocity of SRD, vb = velocity of BIG
xb = position of BIG, omega = rotation of BIG
xsurf = collision pt on surf of BIG
norm = unit normal from surface of BIG at collision pt
v of BIG particle in direction of surf normal is added to v of SRD
includes component due to rotation of BIG
return vsnew of SRD
------------------------------------------------------------------------- */
void FixSRD::slip(double *vs, double *vb, double *xb, Big *big,
double *xsurf, double *norm, double *vsnew)
{
double r1,r2,vnmag,vs_dot_n,vsurf_dot_n;
double tangent[3],vsurf[3];
double *omega = big->omega;
while (1) {
r1 = sigma * random->gaussian();
r2 = sigma * random->gaussian();
vnmag = sqrt(r1*r1 + r2*r2);
if (vnmag*vnmag <= vmaxsq) break;
}
vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2];
tangent[0] = vs[0] - vs_dot_n*norm[0];
tangent[1] = vs[1] - vs_dot_n*norm[1];
tangent[2] = vs[2] - vs_dot_n*norm[2];
// vsurf = velocity of collision pt = translation/rotation of BIG particle
// NOTE: for sphere could just use vsurf = vb, since w x (xsurf-xb)
// is orthogonal to norm and thus doesn't contribute to vsurf_dot_n
vsurf[0] = vb[0] + omega[1]*(xsurf[2]-xb[2]) - omega[2]*(xsurf[1]-xb[1]);
vsurf[1] = vb[1] + omega[2]*(xsurf[0]-xb[0]) - omega[0]*(xsurf[2]-xb[2]);
vsurf[2] = vb[2] + omega[0]*(xsurf[1]-xb[1]) - omega[1]*(xsurf[0]-xb[0]);
vsurf_dot_n = vsurf[0]*norm[0] + vsurf[1]*norm[1] + vsurf[2]*norm[2];
vsnew[0] = (vnmag+vsurf_dot_n)*norm[0] + tangent[0];
vsnew[1] = (vnmag+vsurf_dot_n)*norm[1] + tangent[1];
vsnew[2] = (vnmag+vsurf_dot_n)*norm[2] + tangent[2];
}
/* ----------------------------------------------------------------------
SLIP collision with wall IWALL
vs = velocity of SRD
norm = unit normal from WALL at collision pt
v of WALL in direction of surf normal is added to v of SRD
return vsnew of SRD
------------------------------------------------------------------------- */
void FixSRD::slip_wall(double *vs, int iwall, double *norm, double *vsnew)
{
double vs_dot_n,scale,r1,r2,vnmag,vtmag1,vtmag2;
double tangent1[3],tangent2[3];
vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2];
tangent1[0] = vs[0] - vs_dot_n*norm[0];
tangent1[1] = vs[1] - vs_dot_n*norm[1];
tangent1[2] = vs[2] - vs_dot_n*norm[2];
scale = 1.0/sqrt(tangent1[0]*tangent1[0] + tangent1[1]*tangent1[1] +
tangent1[2]*tangent1[2]);
tangent1[0] *= scale;
tangent1[1] *= scale;
tangent1[2] *= scale;
tangent2[0] = norm[1]*tangent1[2] - norm[2]*tangent1[1];
tangent2[1] = norm[2]*tangent1[0] - norm[0]*tangent1[2];
tangent2[2] = norm[0]*tangent1[1] - norm[1]*tangent1[0];
while (1) {
r1 = sigma * random->gaussian();
r2 = sigma * random->gaussian();
vnmag = sqrt(r1*r1 + r2*r2);
vtmag1 = sigma * random->gaussian();
vtmag2 = sigma * random->gaussian();
if (vnmag*vnmag + vtmag1*vtmag1 + vtmag2*vtmag2 <= vmaxsq) break;
}
vsnew[0] = vnmag*norm[0] + vtmag1*tangent1[0] + vtmag2*tangent2[0];
vsnew[1] = vnmag*norm[1] + vtmag1*tangent1[1] + vtmag2*tangent2[1];
vsnew[2] = vnmag*norm[2] + vtmag1*tangent1[2] + vtmag2*tangent2[2];
// add in velocity of collision pt = velocity of wall
int dim = wallwhich[iwall] / 2;
vsnew[dim] += vwall[iwall];
}
/* ----------------------------------------------------------------------
NO-SLIP collision with BIG particle including WALL
vs = velocity of SRD, vb = velocity of BIG
xb = position of BIG, omega = rotation of BIG
xsurf = collision pt on surf of BIG
norm = unit normal from surface of BIG at collision pt
v of collision pt is added to v of SRD
includes component due to rotation of BIG
return vsnew of SRD
------------------------------------------------------------------------- */
void FixSRD::noslip(double *vs, double *vb, double *xb, Big *big, int iwall,
double *xsurf, double *norm, double *vsnew)
{
double vs_dot_n,scale,r1,r2,vnmag,vtmag1,vtmag2;
double tangent1[3],tangent2[3];
vs_dot_n = vs[0]*norm[0] + vs[1]*norm[1] + vs[2]*norm[2];
tangent1[0] = vs[0] - vs_dot_n*norm[0];
tangent1[1] = vs[1] - vs_dot_n*norm[1];
tangent1[2] = vs[2] - vs_dot_n*norm[2];
scale = 1.0/sqrt(tangent1[0]*tangent1[0] + tangent1[1]*tangent1[1] +
tangent1[2]*tangent1[2]);
tangent1[0] *= scale;
tangent1[1] *= scale;
tangent1[2] *= scale;
tangent2[0] = norm[1]*tangent1[2] - norm[2]*tangent1[1];
tangent2[1] = norm[2]*tangent1[0] - norm[0]*tangent1[2];
tangent2[2] = norm[0]*tangent1[1] - norm[1]*tangent1[0];
while (1) {
r1 = sigma * random->gaussian();
r2 = sigma * random->gaussian();
vnmag = sqrt(r1*r1 + r2*r2);
vtmag1 = sigma * random->gaussian();
vtmag2 = sigma * random->gaussian();
if (vnmag*vnmag + vtmag1*vtmag1 + vtmag2*vtmag2 <= vmaxsq) break;
}
vsnew[0] = vnmag*norm[0] + vtmag1*tangent1[0] + vtmag2*tangent2[0];
vsnew[1] = vnmag*norm[1] + vtmag1*tangent1[1] + vtmag2*tangent2[1];
vsnew[2] = vnmag*norm[2] + vtmag1*tangent1[2] + vtmag2*tangent2[2];
// add in velocity of collision pt
// for WALL: velocity of wall in one dim
// else: translation/rotation of BIG particle
if (big->type == WALL) {
int dim = wallwhich[iwall] / 2;
vsnew[dim] += vwall[iwall];
} else {
double *omega = big->omega;
vsnew[0] += vb[0] + omega[1]*(xsurf[2]-xb[2]) - omega[2]*(xsurf[1]-xb[1]);
vsnew[1] += vb[1] + omega[2]*(xsurf[0]-xb[0]) - omega[0]*(xsurf[2]-xb[2]);
vsnew[2] += vb[2] + omega[0]*(xsurf[1]-xb[1]) - omega[1]*(xsurf[0]-xb[0]);
}
}
/* ----------------------------------------------------------------------
impart force and torque to BIG particle
force on BIG particle = -dp/dt of SRD particle
torque on BIG particle = r cross (-dp/dt)
------------------------------------------------------------------------- */
void FixSRD::force_torque(double *vsold, double *vsnew,
double *xs, double *xb,
double *fb, double *tb)
{
double dpdt[3],xs_xb[3];
double factor = mass_srd / dt_big / force->ftm2v;
dpdt[0] = factor * (vsnew[0] - vsold[0]);
dpdt[1] = factor * (vsnew[1] - vsold[1]);
dpdt[2] = factor * (vsnew[2] - vsold[2]);
fb[0] -= dpdt[0];
fb[1] -= dpdt[1];
fb[2] -= dpdt[2];
// no torque if SLIP collision and BIG is a sphere
if (tb) {
xs_xb[0] = xs[0]-xb[0];
xs_xb[1] = xs[1]-xb[1];
xs_xb[2] = xs[2]-xb[2];
tb[0] -= xs_xb[1]*dpdt[2] - xs_xb[2]*dpdt[1];
tb[1] -= xs_xb[2]*dpdt[0] - xs_xb[0]*dpdt[2];
tb[2] -= xs_xb[0]*dpdt[1] - xs_xb[1]*dpdt[0];
}
}
/* ----------------------------------------------------------------------
impart force to WALL
force on WALL = -dp/dt of SRD particle
------------------------------------------------------------------------- */
void FixSRD::force_wall(double *vsold, double *vsnew, int iwall)
{
double dpdt[3];
double factor = mass_srd / dt_big / force->ftm2v;
dpdt[0] = factor * (vsnew[0] - vsold[0]);
dpdt[1] = factor * (vsnew[1] - vsold[1]);
dpdt[2] = factor * (vsnew[2] - vsold[2]);
fwall[iwall][0] -= dpdt[0];
fwall[iwall][1] -= dpdt[1];
fwall[iwall][2] -= dpdt[2];
}
/* ----------------------------------------------------------------------
update SRD particle position & velocity & search bin assignment
check if SRD moved outside of valid region
if so, may overlap off-processor BIG particle
------------------------------------------------------------------------- */
int FixSRD::update_srd(int i, double dt, double *xscoll, double *vsnew,
double *xs, double *vs)
{
int ix,iy,iz;
vs[0] = vsnew[0];
vs[1] = vsnew[1];
vs[2] = vsnew[2];
xs[0] = xscoll[0] + dt*vsnew[0];
xs[1] = xscoll[1] + dt*vsnew[1];
xs[2] = xscoll[2] + dt*vsnew[2];
if (triclinic) domain->x2lamda(xs,xs);
if (xs[0] < srdlo[0] || xs[0] > srdhi[0] ||
xs[1] < srdlo[1] || xs[1] > srdhi[1] ||
xs[2] < srdlo[2] || xs[2] > srdhi[2]) {
if (screen) {
error->warning(FLERR,"Fix srd particle moved outside valid domain");
- fprintf(screen," particle %d on proc %d at timestep " BIGINT_FORMAT,
+ fprintf(screen," particle " TAGINT_FORMAT
+ " on proc %d at timestep " BIGINT_FORMAT,
atom->tag[i],me,update->ntimestep);
fprintf(screen," xnew %g %g %g\n",xs[0],xs[1],xs[2]);
fprintf(screen," srdlo/hi x %g %g\n",srdlo[0],srdhi[0]);
fprintf(screen," srdlo/hi y %g %g\n",srdlo[1],srdhi[1]);
fprintf(screen," srdlo/hi z %g %g\n",srdlo[2],srdhi[2]);
}
}
if (triclinic) domain->lamda2x(xs,xs);
ix = static_cast<int> ((xs[0]-xblo2)*bininv2x);
iy = static_cast<int> ((xs[1]-yblo2)*bininv2y);
iz = static_cast<int> ((xs[2]-zblo2)*bininv2z);
return iz*nbin2y*nbin2x + iy*nbin2x + ix;
}
/* ----------------------------------------------------------------------
setup all SRD parameters with big particles
------------------------------------------------------------------------- */
void FixSRD::parameterize()
{
// timesteps
dt_big = update->dt;
dt_srd = nevery * update->dt;
// maxbigdiam,minbigdiam = max/min diameter of any big particle
// big particle must either have radius > 0 or shape > 0 defined
// apply radfactor at end
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double *radius = atom->radius;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int any_ellipsoids = 0;
int any_lines = 0;
int any_tris = 0;
maxbigdiam = 0.0;
minbigdiam = BIG;
for (int i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) {
if (radius && radius[i] > 0.0) {
maxbigdiam = MAX(maxbigdiam,2.0*radius[i]);
minbigdiam = MIN(minbigdiam,2.0*radius[i]);
} else if (ellipsoid && ellipsoid[i] >= 0) {
any_ellipsoids = 1;
double *shape = ebonus[ellipsoid[i]].shape;
maxbigdiam = MAX(maxbigdiam,2.0*shape[0]);
maxbigdiam = MAX(maxbigdiam,2.0*shape[1]);
maxbigdiam = MAX(maxbigdiam,2.0*shape[2]);
minbigdiam = MIN(minbigdiam,2.0*shape[0]);
minbigdiam = MIN(minbigdiam,2.0*shape[1]);
minbigdiam = MIN(minbigdiam,2.0*shape[2]);
} else if (line && line[i] >= 0) {
any_lines = 1;
double length = lbonus[line[i]].length;
maxbigdiam = MAX(maxbigdiam,length);
minbigdiam = MIN(minbigdiam,length);
} else if (tri && tri[i] >= 0) {
any_tris = 1;
double length1 = MathExtra::len3(tbonus[tri[i]].c1);
double length2 = MathExtra::len3(tbonus[tri[i]].c2);
double length3 = MathExtra::len3(tbonus[tri[i]].c3);
double length = MAX(length1,length2);
length = MAX(length,length3);
maxbigdiam = MAX(maxbigdiam,length);
minbigdiam = MIN(minbigdiam,length);
} else
error->one(FLERR,"Big particle in fix srd cannot be point particle");
}
double tmp = maxbigdiam;
MPI_Allreduce(&tmp,&maxbigdiam,1,MPI_DOUBLE,MPI_MAX,world);
tmp = minbigdiam;
MPI_Allreduce(&tmp,&minbigdiam,1,MPI_DOUBLE,MPI_MIN,world);
maxbigdiam *= radfactor;
minbigdiam *= radfactor;
int itmp = any_ellipsoids;
MPI_Allreduce(&itmp,&any_ellipsoids,1,MPI_INT,MPI_MAX,world);
itmp = any_lines;
MPI_Allreduce(&itmp,&any_lines,1,MPI_INT,MPI_MAX,world);
itmp = any_tris;
MPI_Allreduce(&itmp,&any_tris,1,MPI_INT,MPI_MAX,world);
if (any_lines && overlap == 0)
error->all(FLERR,"Cannot use lines with fix srd unless overlap is set");
if (any_tris && overlap == 0)
error->all(FLERR,"Cannot use tris with fix srd unless overlap is set");
// big particles are only torqued if ellipsoids/lines/tris or NOSLIP
if (any_ellipsoids == 0 && any_lines == 0 && any_tris == 0 &&
collidestyle == SLIP) torqueflag = 0;
else torqueflag = 1;
// mass of SRD particles, require monodispersity
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int flag = 0;
mass_srd = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (rmass) {
if (mass_srd == 0.0) mass_srd = rmass[i];
else if (rmass[i] != mass_srd) flag = 1;
} else {
if (mass_srd == 0.0) mass_srd = mass[type[i]];
else if (mass[type[i]] != mass_srd) flag = 1;
}
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall)
error->all(FLERR,"Fix srd requires SRD particles all have same mass");
// set temperature and lamda of SRD particles from each other
// lamda = dt_srd * sqrt(boltz * temperature_srd / mass_srd);
if (lamdaflag == 0)
lamda = dt_srd * sqrt(force->boltz*temperature_srd/mass_srd/force->mvv2e);
else
temperature_srd = force->mvv2e *
(lamda/dt_srd)*(lamda/dt_srd) * mass_srd/force->boltz;
// vmax = maximum velocity of an SRD particle
// dmax = maximum distance an SRD can move = 4*lamda = vmax * dt_srd
sigma = lamda/dt_srd;
dmax = 4.0*lamda;
vmax = dmax/dt_srd;
vmaxsq = vmax*vmax;
// volbig = total volume of all big particles
// LINE/TRI particles have no volume
// incorrect if part of rigid particles, so add fudge factor with WIDTH
// apply radfactor to reduce final volume
double volbig = 0.0;
double WIDTH = 1.0;
if (dimension == 3) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) {
if (radius && radius[i] > 0.0) {
double r = radfactor * radius[i];
volbig += 4.0/3.0*MY_PI * r*r*r;;
} else if (ellipsoid && ellipsoid[i] >= 0) {
double *shape = ebonus[ellipsoid[i]].shape;
volbig += 4.0/3.0*MY_PI * shape[0]*shape[1]*shape[2] *
radfactor*radfactor*radfactor;
} else if (tri && tri[i] >= 0) {
double *c1 = tbonus[tri[i]].c1;
double *c2 = tbonus[tri[i]].c2;
double *c3 = tbonus[tri[i]].c3;
double c2mc1[3],c3mc1[3],cross[3];
MathExtra::sub3(c2,c1,c2mc1);
MathExtra::sub3(c3,c1,c3mc1);
MathExtra::cross3(c2mc1,c3mc1,cross);
volbig += 0.5 * MathExtra::len3(cross);
}
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) {
if (radius && radius[i] > 0.0) {
double r = radfactor * radius[i];
volbig += MY_PI * r*r;
} else if (ellipsoid && ellipsoid[i] >= 0) {
double *shape = ebonus[ellipsoid[i]].shape;
volbig += MY_PI * shape[0]*shape[1] * radfactor*radfactor;
} else if (line && line[i] >= 0) {
double length = lbonus[line[i]].length;
volbig += length * WIDTH;
}
}
}
tmp = volbig;
MPI_Allreduce(&tmp,&volbig,1,MPI_DOUBLE,MPI_SUM,world);
// particle counts
bigint mbig = 0;
if (bigexist) mbig = group->count(biggroup);
bigint nsrd = group->count(igroup);
// mass_big = total mass of all big particles
mass_big = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & biggroupbit) {
if (rmass) mass_big += rmass[i];
else mass_big += mass[type[i]];
}
tmp = mass_big;
MPI_Allreduce(&tmp,&mass_big,1,MPI_DOUBLE,MPI_SUM,world);
// mass density ratio = big / SRD
double density_big = 0.0;
if (bigexist) density_big = mass_big / volbig;
double volsrd,density_srd;
if (dimension == 3) {
volsrd = (domain->xprd * domain->yprd * domain->zprd) - volbig;
density_srd = nsrd * mass_srd /
(domain->xprd*domain->yprd*domain->zprd - volbig);
} else {
volsrd = (domain->xprd * domain->yprd) - volbig;
density_srd = nsrd * mass_srd /
(domain->xprd*domain->yprd - volbig);
}
double mdratio = density_big/density_srd;
// create grid for binning/rotating SRD particles from gridsrd
setup_velocity_bins();
// binsize3 = binsize1 in box units (not lamda units for triclinic)
double binsize3x = binsize1x;
double binsize3y = binsize1y;
double binsize3z = binsize1z;
if (triclinic) {
binsize3x = binsize1x * domain->xprd;
binsize3y = binsize1y * domain->yprd;
binsize3z = binsize1z * domain->zprd;
}
// srd_per_grid = # of SRD particles per SRD grid cell
double ncell;
if (dimension == 3)
ncell = volsrd / (binsize3x*binsize3y*binsize3z);
else
ncell = volsrd / (binsize3x*binsize3y);
srd_per_cell = (double) nsrd / ncell;
// kinematic viscosity of SRD fluid
// output in cm^2/sec units, converted by xxt2kmu
double viscosity;
if (dimension == 3)
viscosity = gridsrd*gridsrd/(18.0*dt_srd) *
(1.0-(1.0-exp(-srd_per_cell))/srd_per_cell) +
(force->boltz*temperature_srd*dt_srd/(4.0*mass_srd*force->mvv2e)) *
((srd_per_cell+2.0)/(srd_per_cell-1.0));
else
viscosity =
(force->boltz*temperature_srd*dt_srd/(2.0*mass_srd*force->mvv2e)) *
(srd_per_cell/(srd_per_cell-1.0 + exp(-srd_per_cell)) - 1.0) +
(gridsrd*gridsrd)/(12.0*dt_srd) *
((srd_per_cell-1.0 + exp(-srd_per_cell))/srd_per_cell);
viscosity *= force->xxt2kmu;
// print SRD parameters
if (me == 0) {
if (screen) {
fprintf(screen,"SRD info:\n");
fprintf(screen,
" SRD/big particles = " BIGINT_FORMAT " " BIGINT_FORMAT "\n",
nsrd,mbig);
fprintf(screen," big particle diameter max/min = %g %g\n",
maxbigdiam,minbigdiam);
fprintf(screen," SRD temperature & lamda = %g %g\n",
temperature_srd,lamda);
fprintf(screen," SRD max distance & max velocity = %g %g\n",dmax,vmax);
fprintf(screen," SRD grid counts: %d %d %d\n",nbin1x,nbin1y,nbin1z);
fprintf(screen," SRD grid size: request, actual (xyz) = %g, %g %g %g\n",
gridsrd,binsize3x,binsize3y,binsize3z);
fprintf(screen," SRD per actual grid cell = %g\n",srd_per_cell);
fprintf(screen," SRD viscosity = %g\n",viscosity);
fprintf(screen," big/SRD mass density ratio = %g\n",mdratio);
}
if (logfile) {
fprintf(logfile,"SRD info:\n");
fprintf(logfile,
" SRD/big particles = " BIGINT_FORMAT " " BIGINT_FORMAT "\n",
nsrd,mbig);
fprintf(logfile," big particle diameter max/min = %g %g\n",
maxbigdiam,minbigdiam);
fprintf(logfile," SRD temperature & lamda = %g %g\n",
temperature_srd,lamda);
fprintf(logfile," SRD max distance & max velocity = %g %g\n",dmax,vmax);
fprintf(logfile," SRD grid counts: %d %d %d\n",nbin1x,nbin1y,nbin1z);
fprintf(logfile," SRD grid size: request, actual (xyz) = %g, %g %g %g\n",
gridsrd,binsize3x,binsize3y,binsize3z);
fprintf(logfile," SRD per actual grid cell = %g\n",srd_per_cell);
fprintf(logfile," SRD viscosity = %g\n",viscosity);
fprintf(logfile," big/SRD mass density ratio = %g\n",mdratio);
}
}
// error if less than 1 SRD bin per processor in some dim
if (nbin1x < comm->procgrid[0] || nbin1y < comm->procgrid[1] ||
nbin1z < comm->procgrid[2])
error->all(FLERR,"Fewer SRD bins than processors in some dimension");
// check if SRD bins are within tolerance for shape and size
int tolflag = 0;
if (binsize3y/binsize3x > 1.0+cubictol ||
binsize3x/binsize3y > 1.0+cubictol) tolflag = 1;
if (dimension == 3) {
if (binsize3z/binsize3x > 1.0+cubictol ||
binsize3x/binsize3z > 1.0+cubictol) tolflag = 1;
}
if (tolflag) {
if (cubicflag == CUBIC_ERROR)
error->all(FLERR,"SRD bins for fix srd are not cubic enough");
if (me == 0)
error->warning(FLERR,"SRD bins for fix srd are not cubic enough");
}
tolflag = 0;
if (binsize3x/gridsrd > 1.0+cubictol || gridsrd/binsize3x > 1.0+cubictol)
tolflag = 1;
if (binsize3y/gridsrd > 1.0+cubictol || gridsrd/binsize3y > 1.0+cubictol)
tolflag = 1;
if (dimension == 3) {
if (binsize3z/gridsrd > 1.0+cubictol || gridsrd/binsize3z > 1.0+cubictol)
tolflag = 1;
}
if (tolflag) {
if (cubicflag == CUBIC_ERROR)
error->all(FLERR,"SRD bin size for fix srd differs from user request");
if (me == 0)
error->warning(FLERR,
"SRD bin size for fix srd differs from user request");
}
// error if lamda < 0.6 of SRD grid size and no shifting allowed
// turn on shifting in this case if allowed
double maxgridsrd = MAX(binsize3x,binsize3y);
if (dimension == 3) maxgridsrd = MAX(maxgridsrd,binsize3z);
shiftflag = 0;
if (lamda < 0.6*maxgridsrd && shiftuser == SHIFT_NO)
error->all(FLERR,"Fix srd lamda must be >= 0.6 of SRD grid size");
else if (lamda < 0.6*maxgridsrd && shiftuser == SHIFT_POSSIBLE) {
shiftflag = 1;
if (me == 0)
error->warning(FLERR,"SRD bin shifting turned on due to small lamda");
} else if (shiftuser == SHIFT_YES) shiftflag = 1;
// warnings
if (bigexist && maxgridsrd > 0.25 * minbigdiam && me == 0)
error->warning(FLERR,"Fix srd grid size > 1/4 of big particle diameter");
if (viscosity < 0.0 && me == 0)
error->warning(FLERR,"Fix srd viscosity < 0.0 due to low SRD density");
if (bigexist && dt_big*vmax > minbigdiam && me == 0)
error->warning(FLERR,"Fix srd particles may move > big particle diameter");
}
/* ----------------------------------------------------------------------
set static parameters of each big particle, owned and ghost
called each reneighboring
use radfactor in distance parameters as appropriate
------------------------------------------------------------------------- */
void FixSRD::big_static()
{
int i;
double rad,arad,brad,crad,length,length1,length2,length3;
double *shape,*c1,*c2,*c3;
double c2mc1[3],c3mc1[3];
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double *radius = atom->radius;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
double skinhalf = 0.5 * neighbor->skin;
for (int k = 0; k < nbig; k++) {
i = biglist[k].index;
// sphere
// set radius and radsq and cutoff based on radius
if (radius && radius[i] > 0.0) {
biglist[k].type = SPHERE;
rad = radfactor*radius[i];
biglist[k].radius = rad;
biglist[k].radsq = rad*rad;
biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf);
// ellipsoid
// set abc radsqinv and cutoff based on max radius
} else if (ellipsoid && ellipsoid[i] >= 0) {
shape = ebonus[ellipsoid[i]].shape;
biglist[k].type = ELLIPSOID;
arad = radfactor*shape[0];
brad = radfactor*shape[1];
crad = radfactor*shape[2];
biglist[k].aradsqinv = 1.0/(arad*arad);
biglist[k].bradsqinv = 1.0/(brad*brad);
biglist[k].cradsqinv = 1.0/(crad*crad);
rad = MAX(arad,brad);
rad = MAX(rad,crad);
biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf);
// line
// set length and cutoff based on 1/2 length
} else if (line && line[i] >= 0) {
length = lbonus[line[i]].length;
biglist[k].type = LINE;
biglist[k].length = length;
rad = 0.5*length;
biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf);
// tri
// set normbody based on c1,c2,c3
// set cutoff based on point furthest from centroid
} else if (tri && tri[i] >= 0) {
biglist[k].type = TRIANGLE;
c1 = tbonus[tri[i]].c1;
c2 = tbonus[tri[i]].c2;
c3 = tbonus[tri[i]].c3;
MathExtra::sub3(c2,c1,c2mc1);
MathExtra::sub3(c3,c1,c3mc1);
MathExtra::cross3(c2mc1,c3mc1,biglist[k].normbody);
length1 = MathExtra::len3(c1);
length2 = MathExtra::len3(c2);
length3 = MathExtra::len3(c3);
rad = MAX(length1,length2);
rad = MAX(rad,length3);
biglist[k].cutbinsq = (rad+skinhalf) * (rad+skinhalf);
}
}
}
/* ----------------------------------------------------------------------
set dynamic parameters of each big particle, owned and ghost
called each timestep
------------------------------------------------------------------------- */
void FixSRD::big_dynamic()
{
int i;
double *shape,*quat,*inertia;
double inertiaone[3];
AtomVecEllipsoid::Bonus *ebonus;
if (avec_ellipsoid) ebonus = avec_ellipsoid->bonus;
AtomVecLine::Bonus *lbonus;
if (avec_line) lbonus = avec_line->bonus;
AtomVecTri::Bonus *tbonus;
if (avec_tri) tbonus = avec_tri->bonus;
double **omega = atom->omega;
double **angmom = atom->angmom;
double *rmass = atom->rmass;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
for (int k = 0; k < nbig; k++) {
i = biglist[k].index;
// sphere
// set omega from atom->omega directly
if (biglist[k].type == SPHERE) {
biglist[k].omega[0] = omega[i][0];
biglist[k].omega[1] = omega[i][1];
biglist[k].omega[2] = omega[i][2];
// ellipsoid
// set ex,ey,ez from quaternion
// set omega from angmom & ex,ey,ez
} else if (biglist[k].type == ELLIPSOID) {
quat = ebonus[ellipsoid[i]].quat;
MathExtra::q_to_exyz(quat,biglist[k].ex,biglist[k].ey,biglist[k].ez);
shape = ebonus[ellipsoid[i]].shape;
inertiaone[0] = EINERTIA*rmass[i] * (shape[1]*shape[1]+shape[2]*shape[2]);
inertiaone[1] = EINERTIA*rmass[i] * (shape[0]*shape[0]+shape[2]*shape[2]);
inertiaone[2] = EINERTIA*rmass[i] * (shape[0]*shape[0]+shape[1]*shape[1]);
MathExtra::angmom_to_omega(angmom[i],
biglist[k].ex,biglist[k].ey,biglist[k].ez,
inertiaone,biglist[k].omega);
// line
// set omega from atom->omega directly
} else if (biglist[k].type == LINE) {
biglist[k].theta = lbonus[line[i]].theta;
biglist[k].omega[0] = omega[i][0];
biglist[k].omega[1] = omega[i][1];
biglist[k].omega[2] = omega[i][2];
// tri
// set ex,ey,ez from quaternion
// set omega from angmom & ex,ey,ez
// set unit space-frame norm from body-frame norm
} else if (biglist[k].type == TRIANGLE) {
quat = tbonus[tri[i]].quat;
MathExtra::q_to_exyz(quat,biglist[k].ex,biglist[k].ey,biglist[k].ez);
inertia = tbonus[tri[i]].inertia;
MathExtra::angmom_to_omega(angmom[i],
biglist[k].ex,biglist[k].ey,biglist[k].ez,
inertia,biglist[k].omega);
MathExtra::matvec(biglist[k].ex,biglist[k].ey,biglist[k].ez,
biglist[k].normbody,biglist[k].norm);
MathExtra::norm3(biglist[k].norm);
}
}
}
/* ----------------------------------------------------------------------
set bounds for big and SRD particle movement
called at setup() and when box size changes (but not shape)
------------------------------------------------------------------------- */
void FixSRD::setup_bounds()
{
// triclinic scale factors
// convert a real distance (perpendicular to box face) to a lamda distance
double length0,length1,length2;
if (triclinic) {
double *h_inv = domain->h_inv;
length0 = sqrt(h_inv[0]*h_inv[0] + h_inv[5]*h_inv[5] + h_inv[4]*h_inv[4]);
length1 = sqrt(h_inv[1]*h_inv[1] + h_inv[3]*h_inv[3]);
length2 = h_inv[2];
}
// collision object = CO = big particle or wall
// big particles can be owned or ghost or unknown, walls are all owned
// dist_ghost = distance from sub-domain (SD) that
// owned/ghost CO may move to before reneigh,
// used to bound search bins in setup_search_bins()
// dist_srd = distance from SD at which SRD could collide with unknown CO,
// used to error check bounds of SRD movement after collisions via srdlo/hi
// dist_srd_reneigh = distance from SD at which an SRD should trigger
// a reneigh, b/c next SRD move might overlap with unknown CO,
// used for SRD triggering of reneighboring via srdlo/hi_reneigh
// onemove = max distance an SRD can move in one step
// if big_particles (and possibly walls):
// dist_ghost = cut + 1/2 skin due to moving away before reneigh
// dist_srd = cut - 1/2 skin - 1/2 diam due to ghost CO moving towards
// dist_reneigh = dist_srd - onemove
// if walls and no big particles:
// dist_ghost = 0.0, since not used
// if no big particles or walls:
// dist_ghost and dist_srd = 0.0, since not used since no search bins
// dist_srd_reneigh = subsize - onemove =
// max distance to move without being lost during comm->exchange()
// subsize = perp distance between sub-domain faces (orthog or triclinic)
double cut = MAX(neighbor->cutneighmax,comm->cutghostuser);
double onemove = dt_big*vmax;
if (bigexist) {
dist_ghost = cut + 0.5*neighbor->skin;
dist_srd = cut - 0.5*neighbor->skin - 0.5*maxbigdiam;
dist_srd_reneigh = dist_srd - onemove;
} else if (wallexist) {
dist_ghost = 4*onemove;
dist_srd = 4*onemove;
dist_srd_reneigh = 4*onemove - onemove;
} else {
dist_ghost = dist_srd = 0.0;
double subsize;
if (triclinic == 0) {
subsize = domain->prd[0]/comm->procgrid[0];
subsize = MIN(subsize,domain->prd[1]/comm->procgrid[1]);
if (dimension == 3)
subsize = MIN(subsize,domain->prd[2]/comm->procgrid[2]);
} else {
subsize = 1.0/comm->procgrid[0]/length0;
subsize = MIN(subsize,1.0/comm->procgrid[1]/length1);
if (dimension == 3)
subsize = MIN(subsize,1.0/comm->procgrid[2]/length2);
}
dist_srd_reneigh = subsize - onemove;
}
// lo/hi = bbox on this proc which SRD particles must stay inside
// lo/hi reneigh = bbox on this proc outside of which SRDs trigger a reneigh
// for triclinic, these bbox are in lamda units
if (triclinic == 0) {
srdlo[0] = domain->sublo[0] - dist_srd;
srdhi[0] = domain->subhi[0] + dist_srd;
srdlo[1] = domain->sublo[1] - dist_srd;
srdhi[1] = domain->subhi[1] + dist_srd;
srdlo[2] = domain->sublo[2] - dist_srd;
srdhi[2] = domain->subhi[2] + dist_srd;
srdlo_reneigh[0] = domain->sublo[0] - dist_srd_reneigh;
srdhi_reneigh[0] = domain->subhi[0] + dist_srd_reneigh;
srdlo_reneigh[1] = domain->sublo[1] - dist_srd_reneigh;
srdhi_reneigh[1] = domain->subhi[1] + dist_srd_reneigh;
srdlo_reneigh[2] = domain->sublo[2] - dist_srd_reneigh;
srdhi_reneigh[2] = domain->subhi[2] + dist_srd_reneigh;
} else {
srdlo[0] = domain->sublo_lamda[0] - dist_srd*length0;
srdhi[0] = domain->subhi_lamda[0] + dist_srd*length0;
srdlo[1] = domain->sublo_lamda[1] - dist_srd*length1;
srdhi[1] = domain->subhi_lamda[1] + dist_srd*length1;
srdlo[2] = domain->sublo_lamda[2] - dist_srd*length2;
srdhi[2] = domain->subhi_lamda[2] + dist_srd*length2;
srdlo_reneigh[0] = domain->sublo_lamda[0] - dist_srd_reneigh*length0;
srdhi_reneigh[0] = domain->subhi_lamda[0] + dist_srd_reneigh*length0;
srdlo_reneigh[1] = domain->sublo_lamda[1] - dist_srd_reneigh*length1;
srdhi_reneigh[1] = domain->subhi_lamda[1] + dist_srd_reneigh*length1;
srdlo_reneigh[2] = domain->sublo_lamda[2] - dist_srd_reneigh*length2;
srdhi_reneigh[2] = domain->subhi_lamda[2] + dist_srd_reneigh*length2;
}
}
/* ----------------------------------------------------------------------
setup bins used for binning SRD particles for velocity reset
gridsrd = desired bin size
also setup bin shifting parameters
also setup comm of bins that straddle processor boundaries
called at beginning of each run
called every reneighbor if box size changes, but not if box shape changes
------------------------------------------------------------------------- */
void FixSRD::setup_velocity_bins()
{
// require integer # of bins across global domain
nbin1x = static_cast<int> (domain->xprd/gridsrd + 0.5);
nbin1y = static_cast<int> (domain->yprd/gridsrd + 0.5);
nbin1z = static_cast<int> (domain->zprd/gridsrd + 0.5);
if (dimension == 2) nbin1z = 1;
if (nbin1x == 0) nbin1x = 1;
if (nbin1y == 0) nbin1y = 1;
if (nbin1z == 0) nbin1z = 1;
if (triclinic == 0) {
binsize1x = domain->xprd / nbin1x;
binsize1y = domain->yprd / nbin1y;
binsize1z = domain->zprd / nbin1z;
bininv1x = 1.0/binsize1x;
bininv1y = 1.0/binsize1y;
bininv1z = 1.0/binsize1z;
} else {
binsize1x = 1.0 / nbin1x;
binsize1y = 1.0 / nbin1y;
binsize1z = 1.0 / nbin1z;
bininv1x = nbin1x;
bininv1y = nbin1y;
bininv1z = nbin1z;
}
nbins1 = nbin1x*nbin1y*nbin1z;
// setup two shifts, 0 = no shift, 1 = shift
// initialize no shift case since static
// shift case is dynamic, has to be initialized each time shift occurs
// setup_velocity_shift allocates memory for vbin and sendlist/recvlist
double *boxlo;
if (triclinic == 0) boxlo = domain->boxlo;
else boxlo = domain->boxlo_lamda;
shifts[0].corner[0] = boxlo[0];
shifts[0].corner[1] = boxlo[1];
shifts[0].corner[2] = boxlo[2];
setup_velocity_shift(0,0);
shifts[1].corner[0] = boxlo[0];
shifts[1].corner[1] = boxlo[1];
shifts[1].corner[2] = boxlo[2];
setup_velocity_shift(1,0);
// allocate binhead based on max # of bins in either shift
int max = shifts[0].nbins;
max = MAX(max,shifts[1].nbins);
if (max > maxbin1) {
memory->destroy(binhead);
maxbin1 = max;
memory->create(binhead,max,"fix/srd:binhead");
}
// allocate sbuf,rbuf based on biggest bin message
max = 0;
for (int ishift = 0; ishift < 2; ishift++)
for (int iswap = 0; iswap < 2*dimension; iswap++) {
max = MAX(max,shifts[ishift].bcomm[iswap].nsend);
max = MAX(max,shifts[ishift].bcomm[iswap].nrecv);
}
if (max > maxbuf) {
memory->destroy(sbuf1);
memory->destroy(sbuf2);
memory->destroy(rbuf1);
memory->destroy(rbuf2);
maxbuf = max;
memory->create(sbuf1,max*VBINSIZE,"fix/srd:sbuf");
memory->create(sbuf2,max*VBINSIZE,"fix/srd:sbuf");
memory->create(rbuf1,max*VBINSIZE,"fix/srd:rbuf");
memory->create(rbuf2,max*VBINSIZE,"fix/srd:rbuf");
}
// commflag = 1 if any comm required due to bins overlapping proc boundaries
shifts[0].commflag = 0;
if (nbin1x % comm->procgrid[0]) shifts[0].commflag = 1;
if (nbin1y % comm->procgrid[1]) shifts[0].commflag = 1;
if (nbin1z % comm->procgrid[2]) shifts[0].commflag = 1;
shifts[1].commflag = 1;
}
/* ----------------------------------------------------------------------
setup velocity shift parameters
set binlo[]/binhi[] and nbins,nbinx,nbiny,nbinz for this proc
set bcomm[6] params based on bin overlaps with proc boundaries
no comm of bins across non-periodic global boundaries
set vbin owner flags for bins I am owner of
ishift = 0, dynamic = 0:
set all settings since are static
allocate and set bcomm params and vbins
do not comm bins that align with proc boundaries
ishift = 1, dynamic = 0:
set max bounds on bin counts and message sizes
allocate and set bcomm params and vbins based on max bounds
other settings will later change dynamically
ishift = 1, dynamic = 1:
set actual bin bounds and counts for specific shift
set bcomm params and vbins (already allocated)
called by setup_velocity_bins() and reset_velocities()
------------------------------------------------------------------------- */
void FixSRD::setup_velocity_shift(int ishift, int dynamic)
{
int i,j,k,m,id,nsend;
int *sendlist;
BinComm *first,*second;
BinAve *vbin;
double *sublo,*subhi;
if (triclinic == 0) {
sublo = domain->sublo;
subhi = domain->subhi;
} else {
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
int *binlo = shifts[ishift].binlo;
int *binhi = shifts[ishift].binhi;
double *corner = shifts[ishift].corner;
int *procgrid = comm->procgrid;
int *myloc = comm->myloc;
binlo[0] = static_cast<int> ((sublo[0]-corner[0])*bininv1x);
binlo[1] = static_cast<int> ((sublo[1]-corner[1])*bininv1y);
binlo[2] = static_cast<int> ((sublo[2]-corner[2])*bininv1z);
if (dimension == 2) shifts[ishift].binlo[2] = 0;
binhi[0] = static_cast<int> ((subhi[0]-corner[0])*bininv1x);
binhi[1] = static_cast<int> ((subhi[1]-corner[1])*bininv1y);
binhi[2] = static_cast<int> ((subhi[2]-corner[2])*bininv1z);
if (dimension == 2) shifts[ishift].binhi[2] = 0;
if (ishift == 0) {
if (myloc[0]*nbin1x % procgrid[0] == 0)
binlo[0] = myloc[0]*nbin1x/procgrid[0];
if (myloc[1]*nbin1y % procgrid[1] == 0)
binlo[1] = myloc[1]*nbin1y/procgrid[1];
if (myloc[2]*nbin1z % procgrid[2] == 0)
binlo[2] = myloc[2]*nbin1z/procgrid[2];
if ((myloc[0]+1)*nbin1x % procgrid[0] == 0)
binhi[0] = (myloc[0]+1)*nbin1x/procgrid[0] - 1;
if ((myloc[1]+1)*nbin1y % procgrid[1] == 0)
binhi[1] = (myloc[1]+1)*nbin1y/procgrid[1] - 1;
if ((myloc[2]+1)*nbin1z % procgrid[2] == 0)
binhi[2] = (myloc[2]+1)*nbin1z/procgrid[2] - 1;
}
int nbinx = binhi[0] - binlo[0] + 1;
int nbiny = binhi[1] - binlo[1] + 1;
int nbinz = binhi[2] - binlo[2] + 1;
// allow for one extra bin if shifting will occur
if (ishift == 1 && dynamic == 0) {
nbinx++;
nbiny++;
if (dimension == 3) nbinz++;
}
int nbins = nbinx*nbiny*nbinz;
int nbinxy = nbinx*nbiny;
int nbinsq = nbinx*nbiny;
nbinsq = MAX(nbiny*nbinz,nbinsq);
nbinsq = MAX(nbinx*nbinz,nbinsq);
shifts[ishift].nbins = nbins;
shifts[ishift].nbinx = nbinx;
shifts[ishift].nbiny = nbiny;
shifts[ishift].nbinz = nbinz;
int reallocflag = 0;
if (dynamic == 0 && nbinsq > shifts[ishift].maxbinsq) {
shifts[ishift].maxbinsq = nbinsq;
reallocflag = 1;
}
// bcomm neighbors
// first = send in lo direction, recv from hi direction
// second = send in hi direction, recv from lo direction
if (dynamic == 0) {
shifts[ishift].bcomm[0].sendproc = comm->procneigh[0][0];
shifts[ishift].bcomm[0].recvproc = comm->procneigh[0][1];
shifts[ishift].bcomm[1].sendproc = comm->procneigh[0][1];
shifts[ishift].bcomm[1].recvproc = comm->procneigh[0][0];
shifts[ishift].bcomm[2].sendproc = comm->procneigh[1][0];
shifts[ishift].bcomm[2].recvproc = comm->procneigh[1][1];
shifts[ishift].bcomm[3].sendproc = comm->procneigh[1][1];
shifts[ishift].bcomm[3].recvproc = comm->procneigh[1][0];
shifts[ishift].bcomm[4].sendproc = comm->procneigh[2][0];
shifts[ishift].bcomm[4].recvproc = comm->procneigh[2][1];
shifts[ishift].bcomm[5].sendproc = comm->procneigh[2][1];
shifts[ishift].bcomm[5].recvproc = comm->procneigh[2][0];
}
// set nsend,nrecv and sendlist,recvlist for each swap in x,y,z
// set nsend,nrecv = 0 if static bins align with proc boundary
// or to prevent dynamic bin swapping across non-periodic global boundary
// allocate sendlist,recvlist only for dynamic = 0
first = &shifts[ishift].bcomm[0];
second = &shifts[ishift].bcomm[1];
first->nsend = first->nrecv = second->nsend = second->nrecv = nbiny*nbinz;
if (ishift == 0) {
if (myloc[0]*nbin1x % procgrid[0] == 0)
first->nsend = second->nrecv = 0;
if ((myloc[0]+1)*nbin1x % procgrid[0] == 0)
second->nsend = first->nrecv = 0;
} else {
if (domain->xperiodic == 0) {
if (myloc[0] == 0) first->nsend = second->nrecv = 0;
if (myloc[0] == procgrid[0]-1) second->nsend = first->nrecv = 0;
}
}
if (reallocflag) {
memory->destroy(first->sendlist);
memory->destroy(first->recvlist);
memory->destroy(second->sendlist);
memory->destroy(second->recvlist);
memory->create(first->sendlist,nbinsq,"fix/srd:sendlist");
memory->create(first->recvlist,nbinsq,"fix/srd:sendlist");
memory->create(second->sendlist,nbinsq,"fix/srd:sendlist");
memory->create(second->recvlist,nbinsq,"fix/srd:sendlist");
}
m = 0;
i = 0;
for (j = 0; j < nbiny; j++)
for (k = 0; k < nbinz; k++) {
id = k*nbinxy + j*nbinx + i;
first->sendlist[m] = second->recvlist[m] = id;
m++;
}
m = 0;
i = nbinx-1;
for (j = 0; j < nbiny; j++)
for (k = 0; k < nbinz; k++) {
id = k*nbinxy + j*nbinx + i;
second->sendlist[m] = first->recvlist[m] = id;
m++;
}
first = &shifts[ishift].bcomm[2];
second = &shifts[ishift].bcomm[3];
first->nsend = first->nrecv = second->nsend = second->nrecv = nbinx*nbinz;
if (ishift == 0) {
if (myloc[1]*nbin1y % procgrid[1] == 0)
first->nsend = second->nrecv = 0;
if ((myloc[1]+1)*nbin1y % procgrid[1] == 0)
second->nsend = first->nrecv = 0;
} else {
if (domain->yperiodic == 0) {
if (myloc[1] == 0) first->nsend = second->nrecv = 0;
if (myloc[1] == procgrid[1]-1) second->nsend = first->nrecv = 0;
}
}
if (reallocflag) {
memory->destroy(first->sendlist);
memory->destroy(first->recvlist);
memory->destroy(second->sendlist);
memory->destroy(second->recvlist);
memory->create(first->sendlist,nbinsq,"fix/srd:sendlist");
memory->create(first->recvlist,nbinsq,"fix/srd:sendlist");
memory->create(second->sendlist,nbinsq,"fix/srd:sendlist");
memory->create(second->recvlist,nbinsq,"fix/srd:sendlist");
}
m = 0;
j = 0;
for (i = 0; i < nbinx; i++)
for (k = 0; k < nbinz; k++) {
id = k*nbinxy + j*nbinx + i;
first->sendlist[m] = second->recvlist[m] = id;
m++;
}
m = 0;
j = nbiny-1;
for (i = 0; i < nbinx; i++)
for (k = 0; k < nbinz; k++) {
id = k*nbinxy + j*nbinx + i;
second->sendlist[m] = first->recvlist[m] = id;
m++;
}
if (dimension == 3) {
first = &shifts[ishift].bcomm[4];
second = &shifts[ishift].bcomm[5];
first->nsend = first->nrecv = second->nsend = second->nrecv = nbinx*nbiny;
if (ishift == 0) {
if (myloc[2]*nbin1z % procgrid[2] == 0)
first->nsend = second->nrecv = 0;
if ((myloc[2]+1)*nbin1z % procgrid[2] == 0)
second->nsend = first->nrecv = 0;
} else {
if (domain->zperiodic == 0) {
if (myloc[2] == 0) first->nsend = second->nrecv = 0;
if (myloc[2] == procgrid[2]-1) second->nsend = first->nrecv = 0;
}
}
if (reallocflag) {
memory->destroy(first->sendlist);
memory->destroy(first->recvlist);
memory->destroy(second->sendlist);
memory->destroy(second->recvlist);
memory->create(first->sendlist,nbinx*nbiny,"fix/srd:sendlist");
memory->create(first->recvlist,nbinx*nbiny,"fix/srd:sendlist");
memory->create(second->sendlist,nbinx*nbiny,"fix/srd:sendlist");
memory->create(second->recvlist,nbinx*nbiny,"fix/srd:sendlist");
}
m = 0;
k = 0;
for (i = 0; i < nbinx; i++)
for (j = 0; j < nbiny; j++) {
id = k*nbinxy + j*nbinx + i;
first->sendlist[m] = second->recvlist[m] = id;
m++;
}
m = 0;
k = nbinz-1;
for (i = 0; i < nbinx; i++)
for (j = 0; j < nbiny; j++) {
id = k*nbinxy + j*nbinx + i;
second->sendlist[m] = first->recvlist[m] = id;
m++;
}
}
// allocate vbins, only for dynamic = 0
if (dynamic == 0 && nbins > shifts[ishift].maxvbin) {
memory->destroy(shifts[ishift].vbin);
shifts[ishift].maxvbin = nbins;
shifts[ishift].vbin = (BinAve *)
memory->smalloc(nbins*sizeof(BinAve),"fix/srd:vbin");
}
// for vbins I own, set owner = 1
// if bin never sent to anyone, I own it
// if bin sent to lower numbered proc, I do not own it
// if bin sent to self, I do not own it on even swap (avoids double counting)
vbin = shifts[ishift].vbin;
for (i = 0; i < nbins; i++) vbin[i].owner = 1;
for (int iswap = 0; iswap < 2*dimension; iswap++) {
if (shifts[ishift].bcomm[iswap].sendproc > me) continue;
if (shifts[ishift].bcomm[iswap].sendproc == me && iswap % 2 == 0) continue;
nsend = shifts[ishift].bcomm[iswap].nsend;
sendlist = shifts[ishift].bcomm[iswap].sendlist;
for (m = 0; m < nsend; m++) vbin[sendlist[m]].owner = 0;
}
// if tstat and deformflag:
// set xctr for all nbins in lamda units so can later compute vstream of bin
if (tstat && deformflag) {
m = 0;
for (k = 0; k < nbinz; k++)
for (j = 0; j < nbiny; j++)
for (i = 0; i < nbinx; i++) {
vbin[m].xctr[0] = corner[0] + (i+binlo[0]+0.5)/nbin1x;
vbin[m].xctr[1] = corner[1] + (j+binlo[1]+0.5)/nbin1y;
vbin[m].xctr[2] = corner[2] + (k+binlo[2]+0.5)/nbin1z;
m++;
}
}
}
/* ----------------------------------------------------------------------
setup bins used for big and SRD particle searching
gridsearch = desired bin size
bins are orthogonal whether simulation box is orthogonal or triclinic
for orthogonal boxes, called at each setup since cutghost may change
for triclinic boxes, called at every reneigh, since tilt may change
sets the following:
nbin2 xyz = # of bins in each dim
binsize2 and bininv2 xyz = size of bins in each dim
xyz blo2 = origin of bins
------------------------------------------------------------------------- */
void FixSRD::setup_search_bins()
{
// subboxlo/hi = real space bbox which
// owned/ghost big particles or walls can be in
// start with bounding box for my sub-domain, add dist_ghost
// for triclinic, need to:
// a) convert dist_ghost to lamda space via length012
// b) lo/hi = sub-domain big particle bbox in lamda space
// c) convert lo/hi to real space bounding box via domain->bbox()
// similar to neighbor::setup_bins() and comm::cutghost[] calculation
double subboxlo[3],subboxhi[3];
if (triclinic == 0) {
subboxlo[0] = domain->sublo[0] - dist_ghost;
subboxlo[1] = domain->sublo[1] - dist_ghost;
subboxlo[2] = domain->sublo[2] - dist_ghost;
subboxhi[0] = domain->subhi[0] + dist_ghost;
subboxhi[1] = domain->subhi[1] + dist_ghost;
subboxhi[2] = domain->subhi[2] + dist_ghost;
} else {
double *h_inv = domain->h_inv;
double length0,length1,length2;
length0 = sqrt(h_inv[0]*h_inv[0] + h_inv[5]*h_inv[5] + h_inv[4]*h_inv[4]);
length1 = sqrt(h_inv[1]*h_inv[1] + h_inv[3]*h_inv[3]);
length2 = h_inv[2];
double lo[3],hi[3];
lo[0] = domain->sublo_lamda[0] - dist_ghost*length0;
lo[1] = domain->sublo_lamda[1] - dist_ghost*length1;
lo[2] = domain->sublo_lamda[2] - dist_ghost*length2;
hi[0] = domain->subhi_lamda[0] + dist_ghost*length0;
hi[1] = domain->subhi_lamda[1] + dist_ghost*length1;
hi[2] = domain->subhi_lamda[2] + dist_ghost*length2;
domain->bbox(lo,hi,subboxlo,subboxhi);
}
// require integer # of bins for that volume
nbin2x = static_cast<int> ((subboxhi[0] - subboxlo[0]) / gridsearch);
nbin2y = static_cast<int> ((subboxhi[1] - subboxlo[1]) / gridsearch);
nbin2z = static_cast<int> ((subboxhi[2] - subboxlo[2]) / gridsearch);
if (dimension == 2) nbin2z = 1;
if (nbin2x == 0) nbin2x = 1;
if (nbin2y == 0) nbin2y = 1;
if (nbin2z == 0) nbin2z = 1;
binsize2x = (subboxhi[0] - subboxlo[0]) / nbin2x;
binsize2y = (subboxhi[1] - subboxlo[1]) / nbin2y;
binsize2z = (subboxhi[2] - subboxlo[2]) / nbin2z;
bininv2x = 1.0/binsize2x;
bininv2y = 1.0/binsize2y;
bininv2z = 1.0/binsize2z;
// add bins on either end due to extent of big particles
// radmax = max distance from central bin that biggest particle overlaps
// includes skin movement
// nx,ny,nz = max # of bins to search away from central bin
double radmax = 0.5*maxbigdiam + 0.5*neighbor->skin;
int nx = static_cast<int> (radmax/binsize2x) + 1;
int ny = static_cast<int> (radmax/binsize2y) + 1;
int nz = static_cast<int> (radmax/binsize2z) + 1;
if (dimension == 2) nz = 0;
nbin2x += 2*nx;
nbin2y += 2*ny;
nbin2z += 2*nz;
xblo2 = subboxlo[0] - nx*binsize2x;
yblo2 = subboxlo[1] - ny*binsize2y;
zblo2 = subboxlo[2] - nz*binsize2z;
if (dimension == 2) zblo2 = domain->boxlo[2];
// allocate bins
// first deallocate previous bins if necessary
nbins2 = nbin2x*nbin2y*nbin2z;
if (nbins2 > maxbin2) {
memory->destroy(nbinbig);
memory->destroy(binbig);
maxbin2 = nbins2;
memory->create(nbinbig,nbins2,"fix/srd:nbinbig");
memory->create(binbig,nbins2,ATOMPERBIN,"fix/srd:binbig");
}
}
/* ----------------------------------------------------------------------
compute stencil of bin offsets for a big particle overlapping search bins
------------------------------------------------------------------------- */
void FixSRD::setup_search_stencil()
{
// radmax = max distance from central bin that any big particle overlaps
// includes skin movement
// nx,ny,nz = max # of bins to search away from central bin
double radmax = 0.5*maxbigdiam + 0.5*neighbor->skin;
double radsq = radmax*radmax;
int nx = static_cast<int> (radmax/binsize2x) + 1;
int ny = static_cast<int> (radmax/binsize2y) + 1;
int nz = static_cast<int> (radmax/binsize2z) + 1;
if (dimension == 2) nz = 0;
// allocate stencil array
// deallocate previous stencil if necessary
int max = (2*nx+1) * (2*ny+1) * (2*nz+1);
if (max > maxstencil) {
memory->destroy(stencil);
maxstencil = max;
memory->create(stencil,max,4,"fix/srd:stencil");
}
// loop over all bins
// add bin to stencil:
// if distance of closest corners of bin and central bin is within cutoff
nstencil = 0;
for (int k = -nz; k <= nz; k++)
for (int j = -ny; j <= ny; j++)
for (int i = -nx; i <= nx; i++)
if (bin_bin_distance(i,j,k) < radsq) {
stencil[nstencil][0] = i;
stencil[nstencil][1] = j;
stencil[nstencil][2] = k;
stencil[nstencil][3] = k*nbin2y*nbin2x + j*nbin2x + i;
nstencil++;
}
}
/* ----------------------------------------------------------------------
compute closest squared distance between point x and bin ibin
------------------------------------------------------------------------- */
double FixSRD::point_bin_distance(double *x, int i, int j, int k)
{
double delx,dely,delz;
double xlo = xblo2 + i*binsize2x;
double xhi = xlo + binsize2x;
double ylo = yblo2 + j*binsize2y;
double yhi = ylo + binsize2y;
double zlo = zblo2 + k*binsize2z;
double zhi = zlo + binsize2z;
if (x[0] < xlo) delx = xlo - x[0];
else if (x[0] > xhi) delx = x[0] - xhi;
else delx = 0.0;
if (x[1] < ylo) dely = ylo - x[1];
else if (x[1] > yhi) dely = x[1] - yhi;
else dely = 0.0;
if (x[2] < zlo) delz = zlo - x[2];
else if (x[2] > zhi) delz = x[2] - zhi;
else delz = 0.0;
return (delx*delx + dely*dely + delz*delz);
}
/* ----------------------------------------------------------------------
compute closest squared distance between 2 bins
central bin (0,0,0) and bin (i,j,k)
------------------------------------------------------------------------- */
double FixSRD::bin_bin_distance(int i, int j, int k)
{
double delx,dely,delz;
if (i > 0) delx = (i-1)*binsize2x;
else if (i == 0) delx = 0.0;
else delx = (i+1)*binsize2x;
if (j > 0) dely = (j-1)*binsize2y;
else if (j == 0) dely = 0.0;
else dely = (j+1)*binsize2y;
if (k > 0) delz = (k-1)*binsize2z;
else if (k == 0) delz = 0.0;
else delz = (k+1)*binsize2z;
return (delx*delx + dely*dely + delz*delz);
}
/* ---------------------------------------------------------------------- */
int FixSRD::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (torqueflag) {
for (i = first; i < last; i++) {
buf[m++] = flocal[i][0];
buf[m++] = flocal[i][1];
buf[m++] = flocal[i][2];
buf[m++] = tlocal[i][0];
buf[m++] = tlocal[i][1];
buf[m++] = tlocal[i][2];
}
} else {
for (i = first; i < last; i++) {
buf[m++] = flocal[i][0];
buf[m++] = flocal[i][1];
buf[m++] = flocal[i][2];
}
}
return comm_reverse;
}
/* ---------------------------------------------------------------------- */
void FixSRD::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
if (torqueflag) {
for (i = 0; i < n; i++) {
j = list[i];
flocal[j][0] += buf[m++];
flocal[j][1] += buf[m++];
flocal[j][2] += buf[m++];
tlocal[j][0] += buf[m++];
tlocal[j][1] += buf[m++];
tlocal[j][2] += buf[m++];
}
} else {
for (i = 0; i < n; i++) {
j = list[i];
flocal[j][0] += buf[m++];
flocal[j][1] += buf[m++];
flocal[j][2] += buf[m++];
}
}
}
/* ----------------------------------------------------------------------
SRD stats
------------------------------------------------------------------------- */
double FixSRD::compute_vector(int n)
{
// only sum across procs one time
if (stats_flag == 0) {
stats[0] = ncheck;
stats[1] = ncollide;
stats[2] = nbounce;
stats[3] = ninside;
stats[4] = nrescale;
stats[5] = nbins2;
stats[6] = nbins1;
stats[7] = srd_bin_count;
stats[8] = srd_bin_temp;
stats[9] = bouncemaxnum;
stats[10] = bouncemax;
stats[11] = reneighcount;
MPI_Allreduce(stats,stats_all,10,MPI_DOUBLE,MPI_SUM,world);
MPI_Allreduce(&stats[10],&stats_all[10],1,MPI_DOUBLE,MPI_MAX,world);
if (stats_all[7] != 0.0) stats_all[8] /= stats_all[7];
stats_all[6] /= nprocs;
stats_flag = 1;
}
return stats_all[n];
}
/* ---------------------------------------------------------------------- */
void FixSRD::velocity_stats(int groupnum)
{
int bitmask = group->bitmask[groupnum];
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double vone;
double vave = 0.0;
double vmax = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & bitmask) {
vone = sqrt(v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]);
vave += vone;
if (vone > vmax) vmax = vone;
}
double all;
MPI_Allreduce(&vave,&all,1,MPI_DOUBLE,MPI_SUM,world);
double count = group->count(groupnum);
if (count != 0.0) vave = all/count;
else vave = 0.0;
MPI_Allreduce(&vmax,&all,1,MPI_DOUBLE,MPI_MAX,world);
vmax = all;
if (me == 0) {
if (screen)
fprintf(screen," ave/max %s velocity = %g %g\n",
group->names[groupnum],vave,vmax);
if (logfile)
fprintf(logfile," ave/max %s velocity = %g %g\n",
group->names[groupnum],vave,vmax);
}
}
/* ---------------------------------------------------------------------- */
double FixSRD::newton_raphson(double t1, double t2)
{
double f1,df,tlo,thi;
lineside(t1,f1,df);
if (f1 < 0.0) {
tlo = t1;
thi = t2;
} else {
thi = t1;
tlo = t2;
}
double f;
double t = 0.5*(t1+t2);
double dtold = fabs(t2-t1);
double dt = dtold;
lineside(t,f,df);
double temp;
for (int i = 0; i < MAXITER; i++) {
if ((((t-thi)*df - f)*((t-tlo)*df - f) > 0.0) ||
(fabs(2.0*f) > fabs(dtold*df))) {
dtold = dt;
dt = 0.5 * (thi-tlo);
t = tlo + dt;
if (tlo == t) return t;
} else {
dtold = dt;
dt = f / df;
temp = t;
t -= dt;
if (temp == t) return t;
}
if (fabs(dt) < TOLERANCE) return t;
lineside(t,f,df);
if (f < 0.0) tlo = t;
else thi = t;
}
return t;
}
/* ---------------------------------------------------------------------- */
void FixSRD::lineside(double t, double &f, double &df)
{
double p[2],c[2];
p[0] = xs0[0] + (xs1[0]-xs0[0])*t;
p[1] = xs0[1] + (xs1[1]-xs0[1])*t;
c[0] = xb0[0] + (xb1[0]-xb0[0])*t;
c[1] = xb0[1] + (xb1[1]-xb0[1])*t;
double dtheta = theta1 - theta0;
double theta = theta0 + dtheta*t;
double cosT = cos(theta);
double sinT = sin(theta);
f = (p[1]-c[1]) * cosT - (p[0]-c[0]) * sinT;
df = ((xs1[1]-xs0[1]) - (xb1[1]-xb0[1]))*cosT - (p[1]-c[1])*sinT*dtheta -
((xs1[0]-xs0[0]) - (xb1[0]-xb0[0]))*sinT - (p[0]-c[0])*cosT*dtheta;
}
/* ---------------------------------------------------------------------- */
void FixSRD::triside(double t, double &f, double &df)
{
double p[2],c[2];
p[0] = xs0[0] + (xs1[0]-xs0[0])*t;
p[1] = xs0[1] + (xs1[1]-xs0[1])*t;
c[0] = xb0[0] + (xb1[0]-xb0[0])*t;
c[1] = xb0[1] + (xb1[1]-xb0[1])*t;
double dtheta = theta1 - theta0;
double theta = theta0 + dtheta*t;
double cosT = cos(theta);
double sinT = sin(theta);
f = (p[1]-c[1]) * cosT - (p[0]-c[0]) * sinT;
df = ((xs1[1]-xs0[1]) - (xb1[1]-xb0[1]))*cosT - (p[1]-c[1])*sinT*dtheta -
((xs1[0]-xs0[0]) - (xb1[0]-xb0[0]))*sinT - (p[0]-c[0])*cosT*dtheta;
}
/* ---------------------------------------------------------------------- */
double FixSRD::memory_usage()
{
double bytes = 0.0;
bytes += (shifts[0].nbins + shifts[1].nbins) * sizeof(BinAve);
bytes += nmax * sizeof(int);
if (bigexist) {
bytes += nbins2 * sizeof(int);
bytes += nbins2*ATOMPERBIN * sizeof(int);
}
bytes += nmax * sizeof(int);
return bytes;
}
/* ----------------------------------------------------------------------
useful debugging functions
------------------------------------------------------------------------- */
double FixSRD::distance(int i, int j)
{
double dx = atom->x[i][0] - atom->x[j][0];
double dy = atom->x[i][1] - atom->x[j][1];
double dz = atom->x[i][2] - atom->x[j][2];
return sqrt(dx*dx + dy*dy + dz*dz);
}
/* ---------------------------------------------------------------------- */
void FixSRD::print_collision(int i, int j, int ibounce,
double t_remain, double dt,
double *xscoll, double *xbcoll, double *norm,
int type)
{
double xsstart[3],xbstart[3];
double **x = atom->x;
double **v = atom->v;
if (type != WALL) {
- printf("COLLISION between SRD %d and BIG %d\n",atom->tag[i],atom->tag[j]);
+ printf("COLLISION between SRD " TAGINT_FORMAT
+ " and BIG " TAGINT_FORMAT "\n",atom->tag[i],atom->tag[j]);
printf(" bounce # = %d\n",ibounce+1);
printf(" local indices: %d %d\n",i,j);
printf(" timestep = %g\n",dt);
printf(" time remaining post-collision = %g\n",t_remain);
xsstart[0] = x[i][0] - dt*v[i][0];
xsstart[1] = x[i][1] - dt*v[i][1];
xsstart[2] = x[i][2] - dt*v[i][2];
xbstart[0] = x[j][0] - dt*v[j][0];
xbstart[1] = x[j][1] - dt*v[j][1];
xbstart[2] = x[j][2] - dt*v[j][2];
printf(" SRD start position = %g %g %g\n",
xsstart[0],xsstart[1],xsstart[2]);
printf(" BIG start position = %g %g %g\n",
xbstart[0],xbstart[1],xbstart[2]);
printf(" SRD coll position = %g %g %g\n",
xscoll[0],xscoll[1],xscoll[2]);
printf(" BIG coll position = %g %g %g\n",
xbcoll[0],xbcoll[1],xbcoll[2]);
printf(" SRD end position = %g %g %g\n",x[i][0],x[i][1],x[i][2]);
printf(" BIG end position = %g %g %g\n",x[j][0],x[j][1],x[j][2]);
printf(" SRD vel = %g %g %g\n",v[i][0],v[i][1],v[i][2]);
printf(" BIG vel = %g %g %g\n",v[j][0],v[j][1],v[j][2]);
printf(" surf norm = %g %g %g\n",norm[0],norm[1],norm[2]);
double rstart = sqrt((xsstart[0]-xbstart[0])*(xsstart[0]-xbstart[0]) +
(xsstart[1]-xbstart[1])*(xsstart[1]-xbstart[1]) +
(xsstart[2]-xbstart[2])*(xsstart[2]-xbstart[2]));
double rcoll = sqrt((xscoll[0]-xbcoll[0])*(xscoll[0]-xbcoll[0]) +
(xscoll[1]-xbcoll[1])*(xscoll[1]-xbcoll[1]) +
(xscoll[2]-xbcoll[2])*(xscoll[2]-xbcoll[2]));
double rend = sqrt((x[i][0]-x[j][0])*(x[i][0]-x[j][0]) +
(x[i][1]-x[j][1])*(x[i][1]-x[j][1]) +
(x[i][2]-x[j][2])*(x[i][2]-x[j][2]));
printf(" separation at start = %g\n",rstart);
printf(" separation at coll = %g\n",rcoll);
printf(" separation at end = %g\n",rend);
} else {
int dim = wallwhich[j] / 2;
- printf("COLLISION between SRD %d and WALL %d\n",atom->tag[i],j);
+ printf("COLLISION between SRD " TAGINT_FORMAT " and WALL %d\n",
+ atom->tag[i],j);
printf(" bounce # = %d\n",ibounce+1);
printf(" local indices: %d %d\n",i,j);
printf(" timestep = %g\n",dt);
printf(" time remaining post-collision = %g\n",t_remain);
xsstart[0] = x[i][0] - dt*v[i][0];
xsstart[1] = x[i][1] - dt*v[i][1];
xsstart[2] = x[i][2] - dt*v[i][2];
xbstart[0] = xbstart[1] = xbstart[2] = 0.0;
xbstart[dim] = xwall[j] - dt*vwall[j];
printf(" SRD start position = %g %g %g\n",
xsstart[0],xsstart[1],xsstart[2]);
printf(" WALL start position = %g\n",xbstart[dim]);
printf(" SRD coll position = %g %g %g\n",
xscoll[0],xscoll[1],xscoll[2]);
printf(" WALL coll position = %g\n",xbcoll[dim]);
printf(" SRD end position = %g %g %g\n",x[i][0],x[i][1],x[i][2]);
printf(" WALL end position = %g\n",xwall[j]);
printf(" SRD vel = %g %g %g\n",v[i][0],v[i][1],v[i][2]);
printf(" WALL vel = %g\n",vwall[j]);
printf(" surf norm = %g %g %g\n",norm[0],norm[1],norm[2]);
double rstart = xsstart[dim]-xbstart[dim];
double rcoll = xscoll[dim]-xbcoll[dim];
double rend = x[dim][0]-xwall[j];
printf(" separation at start = %g\n",rstart);
printf(" separation at coll = %g\n",rcoll);
printf(" separation at end = %g\n",rend);
}
}
diff --git a/src/USER-AWPMD/atom_vec_wavepacket.cpp b/src/USER-AWPMD/atom_vec_wavepacket.cpp
index 35c6e582d..9903e889f 100644
--- a/src/USER-AWPMD/atom_vec_wavepacket.cpp
+++ b/src/USER-AWPMD/atom_vec_wavepacket.cpp
@@ -1,1141 +1,1136 @@
/* ----------------------------------------------------------------------
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: Ilya Valuev (JIHT, Moscow, Russia)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "atom_vec_wavepacket.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecWavepacket::AtomVecWavepacket(LAMMPS *lmp) : AtomVec(lmp)
{
comm_x_only = comm_f_only = 0;
mass_type = 1;
molecular = 0;
size_forward = 4; // coords[3]+radius[1]
size_reverse = 10; // force[3]+erforce[1]+ervelforce[1]+vforce[3]+csforce[2]
size_border = 10; // coords[3]+tag[1]+type[1]+mask[1]+q[1]+spin[1]+eradius[1]+etag[1]
size_velocity = 6; // +velocities[3]+ ervel[1]+cs[2]
size_data_atom = 11; // for input file: 1-tag 2-type 3-q 4-spin 5-eradius 6-etag 7-cs_re 8-cs_im 9-x 10-y 11-z
size_data_vel = 5; // for input file: vx vy vz ervel <??>
xcol_data = 9; // starting column for x data
atom->wavepacket_flag = 1;
atom->electron_flag = 1; // compatible with eff
atom->q_flag = atom->spin_flag = atom->eradius_flag =
atom->ervel_flag = atom->erforce_flag = 1;
atom->cs_flag = atom->csforce_flag = atom->vforce_flag = atom->ervelforce_flag = atom->etag_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom-electron arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecWavepacket::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
q = memory->grow(atom->q,nmax,"atom:q");
spin = memory->grow(atom->spin,nmax,"atom:spin");
eradius = memory->grow(atom->eradius,nmax,"atom:eradius");
ervel = memory->grow(atom->ervel,nmax,"atom:ervel");
erforce = memory->grow(atom->erforce,nmax*comm->nthreads,"atom:erforce");
cs = memory->grow(atom->cs,2*nmax,"atom:cs");
csforce = memory->grow(atom->csforce,2*nmax,"atom:csforce");
vforce = memory->grow(atom->vforce,3*nmax,"atom:vforce");
ervelforce = memory->grow(atom->ervelforce,nmax,"atom:ervelforce");
etag = memory->grow(atom->etag,nmax,"atom:etag");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecWavepacket::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
q = atom->q;
eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce;
cs = atom->cs;
csforce = atom->csforce;
vforce = atom->vforce;
ervelforce = atom->ervelforce;
etag = atom->etag;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecWavepacket::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
q[j] = q[i];
spin[j] = spin[i];
eradius[j] = eradius[i];
ervel[j] = ervel[i];
cs[2*j] = cs[2*i];
cs[2*j+1] = cs[2*i+1];
etag[j] = etag[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
// this will be used as partial pack for unsplit Hartree packets (v, ervel not regarded as separate variables)
int AtomVecWavepacket::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = eradius[j];
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
// this is a complete pack of all 'position' variables of AWPMD
int AtomVecWavepacket::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
} 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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = eradius[j];
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecWavepacket::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
eradius[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecWavepacket::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
eradius[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
ervel[i] = buf[m++];
cs[2*i] = buf[m++];
cs[2*i+1] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++){
eradius[i] = buf[m++];
ervel[i] = buf[m++];
cs[2*i] = buf[m++];
cs[2*i+1] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) { //10
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = erforce[i];
buf[m++] = ervelforce[i];
buf[m++] = vforce[3*i];
buf[m++] = vforce[3*i+1];
buf[m++] = vforce[3*i+2];
buf[m++] = csforce[2*i];
buf[m++] = csforce[2*i+1];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++){
buf[m++] = erforce[i];
buf[m++] = ervelforce[i];
buf[m++] = vforce[3*i];
buf[m++] = vforce[3*i+1];
buf[m++] = vforce[3*i+2];
buf[m++] = csforce[2*i];
buf[m++] = csforce[2*i+1];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecWavepacket::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
erforce[j] += buf[m++];
ervelforce[j] += buf[m++];
vforce[3*j] += buf[m++];
vforce[3*j+1] += buf[m++];
vforce[3*j+2] += buf[m++];
csforce[2*j] += buf[m++];
csforce[2*j+1] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
erforce[j] += buf[m++];
ervelforce[j] += buf[m++];
vforce[3*j] += buf[m++];
vforce[3*j+1] += buf[m++];
vforce[3*j+2] += buf[m++];
csforce[2*j] += buf[m++];
csforce[2*j+1] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
// will be used for Hartree unsplit version (the etag is added however)
int AtomVecWavepacket::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
if (domain->triclinic == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = ubuf(etag[j]).d;
buf[m++] = ervel[j];
buf[m++] = cs[2*j];
buf[m++] = cs[2*j+1];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecWavepacket::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
etag[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecWavepacket::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
etag[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
ervel[i] = buf[m++];
cs[2*i] = buf[m++];
cs[2*i+1] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
etag[i] = (int) ubuf(buf[m++]).i;
ervel[i] = buf[m++];
cs[2*i] = buf[m++];
cs[2*i+1] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecWavepacket::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = q[i];
buf[m++] = ubuf(spin[i]).d;
buf[m++] = eradius[i];
buf[m++] = ervel[i];
buf[m++] = ubuf(etag[i]).d;
buf[m++] = cs[2*i];
buf[m++] = cs[2*i+1];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecWavepacket::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
q[nlocal] = buf[m++];
spin[nlocal] = (int) ubuf(buf[m++]).i;
eradius[nlocal] = buf[m++];
ervel[nlocal] = buf[m++];
etag[nlocal] = (int) ubuf(buf[m++]).i;
cs[2*nlocal] = buf[m++];
cs[2*nlocal+1] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecWavepacket::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 18 * nlocal; // Associated with pack_restart
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecWavepacket::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = q[i];
buf[m++] = ubuf(spin[i]).d;
buf[m++] = eradius[i];
buf[m++] = ervel[i];
buf[m++] = ubuf(etag[i]).d;
buf[m++] = cs[2*i];
buf[m++] = cs[2*i+1];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecWavepacket::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
q[nlocal] = buf[m++];
spin[nlocal] = (int) ubuf(buf[m++]).i;
eradius[nlocal] = buf[m++];
ervel[nlocal] = buf[m++];
etag[nlocal] = (int) ubuf(buf[m++]).i;
cs[2*nlocal] = buf[m++];
cs[2*nlocal+1] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
AWPMD: creates a proton
------------------------------------------------------------------------- */
void AtomVecWavepacket::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
q[nlocal] = 1.;
spin[nlocal] = 0;
eradius[nlocal] = 0.0;
ervel[nlocal] = 0.0;
etag[nlocal] = 0;
cs[2*nlocal] = 0.;
cs[2*nlocal+1] = 0.;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
AWPMD: 0-tag 1-type 2-q 3-spin 4-eradius 5-etag 6-cs_re 7-cs_im
------------------------------------------------------------------------- */
-void AtomVecWavepacket::data_atom(double *coord, imageint imagetmp, char **values)
+void AtomVecWavepacket::data_atom(double *coord, imageint imagetmp,
+ char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of "
- "data file (ID tag must be >0)");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
q[nlocal] = atof(values[2]);
spin[nlocal] = atoi(values[3]);
eradius[nlocal] = atof(values[4]);
if (eradius[nlocal] < 0.0)
error->one(FLERR,"Invalid eradius in Atoms section of data file");
-
etag[nlocal] = atoi(values[5]);
cs[2*nlocal] = atoi(values[6]);
cs[2*nlocal+1] = atof(values[7]);
-
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
ervel[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecWavepacket::data_atom_hybrid(int nlocal, char **values)
{
q[nlocal] = atof(values[0]);
spin[nlocal] = atoi(values[1]);
eradius[nlocal] = atof(values[2]);
if (eradius[nlocal] < 0.0)
error->one(FLERR,"Invalid eradius in Atoms section of data file");
etag[nlocal] = atoi(values[3]);
cs[2*nlocal] = atoi(values[4]);
cs[2*nlocal+1] = atof(values[5]);
-
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
ervel[nlocal] = 0.0;
return 3;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecWavepacket::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
ervel[m] = atof(values[3]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecWavepacket::data_vel_hybrid(int m, char **values)
{
ervel[m] = atof(values[0]);
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecWavepacket::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = q[i];
buf[i][3] = ubuf(spin[i]).d;
buf[i][4] = eradius[i];
buf[i][5] = ubuf(etag[i]).d;
buf[i][6] = cs[2*i];
buf[i][7] = cs[2*i+1];
buf[i][8] = x[i][0];
buf[i][9] = x[i][1];
buf[i][10] = x[i][2];
buf[i][11] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][12] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][13] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecWavepacket::pack_data_hybrid(int i, double *buf)
{
buf[0] = q[i];
buf[1] = ubuf(spin[i]).d;
buf[2] = eradius[i];
buf[3] = ubuf(etag[i]).d;
buf[4] = cs[2*i];
buf[5] = cs[2*i+1];
return 6;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecWavepacket::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %d %-1.16e %d %-1.16e %-1.16e %-1.16e "
+ fprintf(fp,TAGINT_FORMAT
+ " %d %-1.16e %d %-1.16e %d %-1.16e %-1.16e %-1.16e "
"%-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],(int) ubuf(buf[i][3]).i,buf[i][4],
(int) ubuf(buf[i][5]).i,buf[i][6],buf[i][8],
buf[i][8],buf[i][9],buf[i][10],
(int) ubuf(buf[i][11]).i,(int) ubuf(buf[i][12]).i,
(int) ubuf(buf[i][13]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecWavepacket::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %d %-1.16e %d %-1.16e %-1.16e",
buf[0],(int) ubuf(buf[1]).i,buf[2],(int) ubuf(buf[3]).i,
buf[4],buf[5]);
return 6;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecWavepacket::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = ervel[i];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecWavepacket::pack_vel_hybrid(int i, double *buf)
{
buf[0] = ervel[i];
return 1;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecWavepacket::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
+ fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecWavepacket::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e",buf[0]);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecWavepacket::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("q")) bytes += memory->usage(q,nmax);
if (atom->memcheck("spin")) bytes += memory->usage(spin,nmax);
if (atom->memcheck("eradius")) bytes += memory->usage(eradius,nmax);
if (atom->memcheck("ervel")) bytes += memory->usage(ervel,nmax);
if (atom->memcheck("erforce"))
bytes += memory->usage(erforce,nmax*comm->nthreads);
if (atom->memcheck("ervelforce")) bytes += memory->usage(ervelforce,nmax);
if (atom->memcheck("cs")) bytes += memory->usage(cs,2*nmax);
if (atom->memcheck("csforce")) bytes += memory->usage(csforce,2*nmax);
if (atom->memcheck("vforce")) bytes += memory->usage(vforce,3*nmax);
if (atom->memcheck("etag")) bytes += memory->usage(etag,nmax);
return bytes;
}
diff --git a/src/USER-AWPMD/atom_vec_wavepacket.h b/src/USER-AWPMD/atom_vec_wavepacket.h
index 555321691..7773362b9 100644
--- a/src/USER-AWPMD/atom_vec_wavepacket.h
+++ b/src/USER-AWPMD/atom_vec_wavepacket.h
@@ -1,107 +1,108 @@
/* -*- 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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Ilya Valuev (JIHT RAS)
------------------------------------------------------------------------- */
#ifdef ATOM_CLASS
AtomStyle(wavepacket,AtomVecWavepacket)
#else
#ifndef LMP_ATOM_VEC_WAVEPACKET_H
#define LMP_ATOM_VEC_WAVEPACKET_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecWavepacket : public AtomVec {
public:
AtomVecWavepacket(class LAMMPS *);
~AtomVecWavepacket() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
///\en spin: -1 or 1 for electron, 0 for ion (compatible with eff)
int *spin;
///\en charge: must be specified in the corresponding units (-1 for electron in real units, eff compatible)
double *q;
///\en width of the wavepacket (compatible with eff)
double *eradius;
///\en width velocity for the wavepacket (compatible with eff)
double *ervel;
///\en (generalized) force on width (compatible with eff)
double *erforce;
// AWPMD- specific:
///\en electron tag: must be the same for the WPs belonging to the same electron
int *etag;
///\en wavepacket split coeffcients: cre, cim, size is 2*N
double *cs;
///\en force on wavepacket split coeffcients: re, im, size is 2*N
double *csforce;
///\en (generalized) force on velocity, size is 3*N
double *vforce;
///\en (generalized) force on radius velocity, size is N
double *ervelforce;
};
}
#endif
#endif
diff --git a/src/USER-COLVARS/colvarproxy_lammps.cpp b/src/USER-COLVARS/colvarproxy_lammps.cpp
index 03e92528f..25575a34a 100644
--- a/src/USER-COLVARS/colvarproxy_lammps.cpp
+++ b/src/USER-COLVARS/colvarproxy_lammps.cpp
@@ -1,461 +1,464 @@
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
#include "mpi.h"
#include "lammps.h"
#include "atom.h"
#include "comm.h"
#include "error.h"
#include "output.h"
#include "random_park.h"
#include "fix_colvars.h"
#include "colvarmodule.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 void 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;
}
}
////////////////////////////////////////////////////////////////////////
colvarproxy_lammps::colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp,
const char *inp_name,
const char *out_name,
const int seed,
const double temp)
: _lmp(lmp)
{
if (cvm::debug())
log("Initializing the colvars proxy object.\n");
_random = new LAMMPS_NS::RanPark(lmp,seed);
first_timestep=true;
system_force_requested=false;
previous_step=-1;
t_target=temp;
do_exit=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_prefix_str = std::string("rest");
// 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_prefix_str = std::string(outp->restart1);
} else if ((outp->restart_every_double > 0) && (outp->restart2a != 0)) {
restart_prefix_str = std::string(outp->restart2a);
}
// trim off unwanted stuff from the restart prefix
if (restart_prefix_str.rfind(".*") != std::string::npos)
restart_prefix_str.erase(restart_prefix_str.rfind(".*"),2);
}
void colvarproxy_lammps::init(const char *conf_file)
{
// create the colvarmodule instance
colvars = new colvarmodule(conf_file,this);
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("colvars_atoms = "+cvm::to_str(colvars_atoms)+"\n");
log("colvars_atoms_ncopies = "+cvm::to_str(colvars_atoms_ncopies)+"\n");
log("positions = "+cvm::to_str(positions)+"\n");
log("applied_forces = "+cvm::to_str(applied_forces)+"\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
void colvarproxy_lammps::setup()
{
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(cvm::line_marker+
"colvarproxy_lammps, step no. "+cvm::to_str(colvars->it)+"\n"+
"Updating internal data.\n");
}
// backup applied forces if necessary to calculate system forces
if (system_force_requested)
previous_applied_forces = applied_forces;
// zero the forces on the atoms, so that they can be accumulated by the colvars
for (size_t i = 0; i < applied_forces.size(); i++) {
applied_forces[i].x = applied_forces[i].y = applied_forces[i].z = 0.0;
}
// call the collective variable module
colvars->calc();
#if 0
for (int i=0; i < colvars_atoms.size(); ++i) {
fprintf(stderr,"CV: atom %d/%d/%d pos: %g %g %g for: %g %g %g\n",
colvars_atoms[i], colvars_atoms_ncopies[i],
positions[i].type, positions[i].x, positions[i].y, positions[i].z,
applied_forces[i].x, applied_forces[i].y, applied_forces[i].z);
}
#endif
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);
}
inline 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::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;
}
enum e_pdb_field {
e_pdb_none,
e_pdb_occ,
e_pdb_beta,
e_pdb_x,
e_pdb_y,
e_pdb_z,
e_pdb_ntot
};
e_pdb_field pdb_field_str2enum(std::string const &pdb_field_str)
{
e_pdb_field pdb_field = e_pdb_none;
if (colvarparse::to_lower_cppstr(pdb_field_str) ==
colvarparse::to_lower_cppstr("O")) {
pdb_field = e_pdb_occ;
}
if (colvarparse::to_lower_cppstr(pdb_field_str) ==
colvarparse::to_lower_cppstr("B")) {
pdb_field = e_pdb_beta;
}
if (colvarparse::to_lower_cppstr(pdb_field_str) ==
colvarparse::to_lower_cppstr("X")) {
pdb_field = e_pdb_x;
}
if (colvarparse::to_lower_cppstr(pdb_field_str) ==
colvarparse::to_lower_cppstr("Y")) {
pdb_field = e_pdb_y;
}
if (colvarparse::to_lower_cppstr(pdb_field_str) ==
colvarparse::to_lower_cppstr("Z")) {
pdb_field = e_pdb_z;
}
if (pdb_field == e_pdb_none) {
cvm::fatal_error("Error: unsupported PDB field, \""+
pdb_field_str+"\".\n");
}
return pdb_field;
}
void colvarproxy_lammps::load_coords(char const *pdb_filename,
std::vector<cvm::atom_pos> &pos,
const std::vector<int> &indices,
std::string const pdb_field_str,
double const pdb_field_value)
{
cvm::fatal_error("Reading collective variable coordinates "
"from a PDB file is currently not supported.\n");
}
void colvarproxy_lammps::load_atoms(char const *pdb_filename,
std::vector<cvm::atom> &atoms,
std::string const pdb_field_str,
double const pdb_field_value)
{
cvm::fatal_error("Selecting collective variable atoms "
"from a PDB file is currently not supported.\n");
}
void colvarproxy_lammps::backup_file(char const *filename)
{
if (std::string(filename).rfind(std::string(".colvars.state"))
!= std::string::npos) {
my_backup_file(filename, ".old");
} else {
my_backup_file(filename, ".BAK");
}
}
int colvarproxy_lammps::init_lammps_atom(const int &aid, cvm::atom *atom)
{
atom->id = aid;
atom->mass = 0.0;
for (size_t i = 0; i < colvars_atoms.size(); i++) {
if (colvars_atoms[i] == aid) {
// this atom id was already recorded
colvars_atoms_ncopies[i] += 1;
return i;
}
}
// allocate a new slot for this atom
colvars_atoms_ncopies.push_back(1);
colvars_atoms.push_back(aid);
struct commdata c;
c.tag = aid;
c.type = 0;
c.x = c.y = c.z = 0.0;
positions.push_back(c);
total_forces.push_back(c);
applied_forces.push_back(c);
return colvars_atoms.size()-1;
}
// atom member functions, LAMMPS specific implementations
cvm::atom::atom(const int &id)
{
if (cvm::debug())
cvm::log("Adding atom "+cvm::to_str(id)+
" for collective variables calculation.\n");
if (id < 0)
cvm::fatal_error("Error: invalid atom ID specified, "+
cvm::to_str(id)+"\n");
int idx = ((colvarproxy_lammps *) cvm::proxy)->init_lammps_atom(id,this);
if (idx < 0)
cvm::fatal_error("Error: atom ID , "+cvm::to_str(id)+" does not exist.\n");
this->index = idx;
if (cvm::debug())
cvm::log("The index of this atom in the colvarproxy_lammps arrays is "+
cvm::to_str(this->index)+".\n");
this->reset_data();
}
/// For AMBER topologies, the segment id is automatically set to
/// "MAIN" (the segment id assigned by NAMD's AMBER topology parser),
/// and is therefore optional when an AMBER topology is used
cvm::atom::atom(cvm::residue_id const &residue,
std::string const &atom_name,
std::string const &segment_id)
{
cvm::fatal_error("Creating collective variable atoms "
"from a PDB file is currently not supported.\n");
}
// copy constructor
cvm::atom::atom(cvm::atom const &a)
: index(a.index), id(a.id), mass(a.mass)
{
// init_lammps_atom() has already been called by a's constructor, no
// need to call it again
// need to increment the counter anyway
colvarproxy_lammps *cp = (colvarproxy_lammps *) cvm::proxy;
cp->colvars_atoms_ncopies[this->index] += 1;
}
cvm::atom::~atom()
{
if (this->index >= 0) {
colvarproxy_lammps *cp = (colvarproxy_lammps *) cvm::proxy;
if (cp->colvars_atoms_ncopies[this->index] > 0)
cp->colvars_atoms_ncopies[this->index] -= 1;
}
}
void cvm::atom::read_position()
{
colvarproxy_lammps const * const cp = (colvarproxy_lammps *) cvm::proxy;
this->pos.x = cp->positions[this->index].x;
this->pos.y = cp->positions[this->index].y;
this->pos.z = cp->positions[this->index].z;
this->mass = cp->positions[this->index].m;
}
void cvm::atom::read_velocity()
{
cvm::fatal_error("Error: read_velocity is not yet implemented.\n");
}
void cvm::atom::read_system_force()
{
colvarproxy_lammps const * const cp = (colvarproxy_lammps *) cvm::proxy;
this->system_force.x = cp->total_forces[this->index].x
- cp->previous_applied_forces[this->index].x;
this->system_force.y = cp->total_forces[this->index].y
- cp->previous_applied_forces[this->index].y;
this->system_force.z = cp->total_forces[this->index].z
- cp->previous_applied_forces[this->index].z;
}
void cvm::atom::apply_force(cvm::rvector const &new_force)
{
colvarproxy_lammps *cp = (colvarproxy_lammps *) cvm::proxy;
cp->applied_forces[this->index].x += new_force.x;
cp->applied_forces[this->index].y += new_force.y;
cp->applied_forces[this->index].z += new_force.z;
}
diff --git a/src/USER-CUDA/comm_cuda.cpp b/src/USER-CUDA/comm_cuda.cpp
index aea8f7342..672643646 100644
--- a/src/USER-CUDA/comm_cuda.cpp
+++ b/src/USER-CUDA/comm_cuda.cpp
@@ -1,1433 +1,1437 @@
/* ----------------------------------------------------------------------
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) : Pieter in 't Veld (SNL)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include "mpi.h"
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "comm_cuda.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "neighbor.h"
#include "modify.h"
#include "fix.h"
#include "group.h"
#include "compute.h"
#include "cuda.h"
#include "error.h"
#include "memory.h"
#include "comm_cuda_cu.h"
using namespace LAMMPS_NS;
#define BUFFACTOR 1.5
#define BUFMIN 1000
#define BUFEXTRA 1000
#define BIG 1.0e20
enum{SINGLE,MULTI};
/* ----------------------------------------------------------------------
setup MPI and allocate buffer space
------------------------------------------------------------------------- */
CommCuda::CommCuda(LAMMPS *lmp):Comm(lmp)
{
cuda = lmp->cuda;
if(cuda == NULL)
error->all(FLERR,"You cannot use a /cuda class, without activating 'cuda' acceleration. Provide '-c on' as command-line argument to LAMMPS..");
cu_pbc=NULL;
cu_slablo=NULL;
cu_slabhi=NULL;
cu_multilo=NULL;
cu_multihi=NULL;
cu_sendlist=NULL;
memory->sfree(buf_send);
memory->sfree(buf_recv);
buf_send = NULL;
buf_recv = NULL;
Comm::free_swap();
allocate_swap(maxswap);
}
/* ---------------------------------------------------------------------- */
CommCuda::~CommCuda()
{
delete cu_sendlist;
if(cuda->pinned)
{
CudaWrapper_FreePinnedHostData((void*)buf_send);
CudaWrapper_FreePinnedHostData((void*)buf_recv);
}
else
{
memory->sfree(buf_send);
memory->sfree(buf_recv);
}
buf_send=NULL;
buf_recv=NULL;
}
/* ---------------------------------------------------------------------- */
void CommCuda::init()
{
int factor = 1;
if(cuda->shared_data.overlap_comm) factor=maxswap;
if(not buf_send)
grow_send(maxsend,0);
if(not buf_recv)
grow_recv(maxrecv);
if(not cu_sendlist)
{
cu_sendlist=new cCudaData<int, int, xy> ((int*)sendlist,maxswap,BUFMIN);
cuda->shared_data.comm.sendlist.dev_data=cu_sendlist->dev_data();
cuda->shared_data.comm.maxswap=maxswap;
cuda->shared_data.comm.maxlistlength=BUFMIN;
cu_sendlist->upload();
}
delete cu_pbc;
cu_pbc=new cCudaData<int, int, xy> ((int*)pbc,cuda->shared_data.comm.maxswap,6);
cu_pbc->upload();
delete cu_slablo;
cu_slablo = new cCudaData<double, X_FLOAT,x>(slablo,cuda->shared_data.comm.maxswap);
cu_slablo->upload();
delete cu_slabhi;
cu_slabhi = new cCudaData<double, X_FLOAT,x>(slabhi,cuda->shared_data.comm.maxswap);
cu_slabhi->upload();
cuda->shared_data.comm.pbc.dev_data=cu_pbc->dev_data();
cuda->shared_data.comm.slablo.dev_data=cu_slablo->dev_data();
cuda->shared_data.comm.slabhi.dev_data=cu_slabhi->dev_data();
Comm::init();
}
/* ----------------------------------------------------------------------
setup spatial-decomposition communication patterns
function of neighbor cutoff(s) & cutghostuser & current box size
single style sets slab boundaries (slablo,slabhi) based on max cutoff
multi style sets type-dependent slab boundaries (multilo,multihi)
------------------------------------------------------------------------- */
void CommCuda::setup()
{
if(cuda->shared_data.pair.neighall) cutghostuser = MAX(2.0*neighbor->cutneighmax,cutghostuser);
Comm::setup();
//upload changed geometry to device
if(style == SINGLE)
{
if(cu_slablo) cu_slablo->upload();
if(cu_slabhi) cu_slabhi->upload();
}
else
{
if(cu_multilo) cu_multilo->upload();
if(cu_multihi) cu_multihi->upload();
}
}
/* ----------------------------------------------------------------------
forward communication of atom coords every timestep
other per-atom attributes may also be sent via pack/unpack routines
------------------------------------------------------------------------- */
void CommCuda::forward_comm(int mode)
{
if(mode==0) return forward_comm_cuda();
if(mode==1) return forward_comm_pack_cuda();
if(mode==2) return forward_comm_transfer_cuda();
if(mode==3) return forward_comm_unpack_cuda();
}
void CommCuda::forward_comm_cuda()
{
static int count=0;
static double kerneltime=0.0;
static double copytime=0.0;
my_times time1,time2,time3;
int n;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
double **x = atom->x;
cuda->shared_data.domain.xy=domain->xy;
cuda->shared_data.domain.xz=domain->xz;
cuda->shared_data.domain.yz=domain->yz;
cuda->shared_data.domain.prd[0]=domain->prd[0];
cuda->shared_data.domain.prd[1]=domain->prd[1];
cuda->shared_data.domain.prd[2]=domain->prd[2];
cuda->shared_data.domain.triclinic=domain->triclinic;
if(not comm_x_only && not avec->cudable)
{
cuda->downloadAll();
Comm::forward_comm();
cuda->uploadAll();
return;
}
// exchange data with another proc
// if other proc is self, just copy
// if comm_x_only set, exchange or copy directly to x, don't unpack
for (int iswap = 0; iswap < nswap; iswap++) {
if (sendproc[iswap] != me)
{
if (comm_x_only)
{
int size_forward_recv_now=0;
if((sizeof(X_FLOAT)!=sizeof(double)) && size_forward_recv[iswap]) //some complicated way to safe some transfer size if single precision is used
size_forward_recv_now=(size_forward_recv[iswap]+1)*sizeof(X_FLOAT)/sizeof(double);
else
size_forward_recv_now=size_forward_recv[iswap];
my_gettime(CLOCK_REALTIME,&time1);
MPI_Irecv(buf_recv,size_forward_recv_now,MPI_DOUBLE,
recvproc[iswap],0,world,&request);
n = Cuda_CommCuda_PackComm(&cuda->shared_data,sendnum[iswap],iswap,(void*) buf_send,pbc[iswap],pbc_flag[iswap]);
my_gettime(CLOCK_REALTIME,&time2);
if((sizeof(X_FLOAT)!=sizeof(double)) && n) //some complicated way to safe some transfer size if single precision is used
n=(n+1)*sizeof(X_FLOAT)/sizeof(double);
//printf("RecvSize: %i SendSize: %i\n",size_forward_recv_now,n);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
my_gettime(CLOCK_REALTIME,&time3);
cuda->shared_data.cuda_timings.comm_forward_mpi_upper+=
time3.tv_sec-time1.tv_sec+1.0*(time3.tv_nsec-time1.tv_nsec)/1000000000;
cuda->shared_data.cuda_timings.comm_forward_mpi_lower+=
time3.tv_sec-time2.tv_sec+1.0*(time3.tv_nsec-time2.tv_nsec)/1000000000;
Cuda_CommCuda_UnpackComm(&cuda->shared_data,recvnum[iswap],firstrecv[iswap],(void*)buf_recv,iswap); //Unpack for cpu exchange happens implicitely since buf==x[firstrecv]
}
else if (ghost_velocity)
{
MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE,
recvproc[iswap],0,world,&request);
if(avec->cudable)
n = avec->pack_comm_vel(sendnum[iswap],&iswap,
buf_send,pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_comm_vel(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_comm_vel(recvnum[iswap],firstrecv[iswap],buf_recv);
}
else
{
MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE,
recvproc[iswap],0,world,&request);
if(avec->cudable)
n = avec->pack_comm(sendnum[iswap],&iswap,
buf_send,pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_recv);
}
}
else //sendproc == me
{
cuda->self_comm=1;
if (comm_x_only)
{
if (sendnum[iswap])
{
n = Cuda_CommCuda_PackComm_Self(&cuda->shared_data,sendnum[iswap],iswap,firstrecv[iswap],pbc[iswap],pbc_flag[iswap]);
if(n<0) error->all(FLERR," # CUDA ERRROR on PackComm_Self");
if((sizeof(X_FLOAT)!=sizeof(double)) && n)
n=(n+1)*sizeof(X_FLOAT)/sizeof(double);
}
}
else if (ghost_velocity)
{
n = avec->pack_comm_vel(sendnum[iswap],&iswap,
(double*) firstrecv,pbc_flag[iswap],pbc[iswap]);
//avec->unpack_comm_vel(recvnum[iswap],firstrecv[iswap],(double*) firstrecv);
}
else
{
n = avec->pack_comm(sendnum[iswap],&iswap,
(double*) firstrecv,pbc_flag[iswap],pbc[iswap]);
//avec->unpack_comm(recvnum[iswap],firstrecv[iswap],(double*) firstrecv);
}
cuda->self_comm=0;
}
}
}
void CommCuda::forward_comm_pack_cuda()
{
static int count=0;
static double kerneltime=0.0;
static double copytime=0.0;
my_times time1,time2,time3;
int n; // initialize comm buffers & exchange memory
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
double **x = atom->x;
cuda->shared_data.domain.xy=domain->xy;
cuda->shared_data.domain.xz=domain->xz;
cuda->shared_data.domain.yz=domain->yz;
cuda->shared_data.domain.prd[0]=domain->prd[0];
cuda->shared_data.domain.prd[1]=domain->prd[1];
cuda->shared_data.domain.prd[2]=domain->prd[2];
cuda->shared_data.domain.triclinic=domain->triclinic;
if(not comm_x_only && not avec->cudable) cuda->downloadAll(); //if not comm_x_only the communication routine of the atom_vec style class is used
// exchange data with another proc
// if other proc is self, just copy
// if comm_x_only set, exchange or copy directly to x, don't unpack
for (int iswap = 0; iswap < nswap; iswap++) {
if (sendproc[iswap] != me)
{
if (comm_x_only)
{
my_gettime(CLOCK_REALTIME,&time1);
// n = Cuda_CommCuda_PackComm(&cuda->shared_data,sendnum[iswap],iswap,(void*) cuda->shared_data.comm.buf_send[iswap],pbc[iswap],pbc_flag[iswap]);
n = Cuda_CommCuda_PackComm(&cuda->shared_data,sendnum[iswap],iswap,(void*)buf_send,pbc[iswap],pbc_flag[iswap]);
my_gettime(CLOCK_REALTIME,&time2);
if((sizeof(X_FLOAT)!=sizeof(double)) && n) //some complicated way to safe some transfer size if single precision is used
n=(n+1)*sizeof(X_FLOAT)/sizeof(double);
cuda->shared_data.comm.send_size[iswap]=n;
}
else if (ghost_velocity)
{
my_gettime(CLOCK_REALTIME,&time1);
// n = Cuda_CommCuda_PackComm_Vel(&cuda->shared_data,sendnum[iswap],iswap,(void*) &buf_send[iswap*maxsend],pbc[iswap],pbc_flag[iswap]);
my_gettime(CLOCK_REALTIME,&time2);
if((sizeof(X_FLOAT)!=sizeof(double)) && n) //some complicated way to safe some transfer size if single precision is used
n=(n+1)*sizeof(X_FLOAT)/sizeof(double);
cuda->shared_data.comm.send_size[iswap]=n;
}
else
{
MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE,
recvproc[iswap],0,world,&request);
if(avec->cudable)
n = avec->pack_comm(sendnum[iswap],&iswap,
cuda->shared_data.comm.buf_send[iswap],pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
cuda->shared_data.comm.buf_send[iswap],pbc_flag[iswap],pbc[iswap]);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_recv);
}
}
else //sendproc == me
{
if (comm_x_only)
{
if (sendnum[iswap])
{
n = Cuda_CommCuda_PackComm_Self(&cuda->shared_data,sendnum[iswap],iswap,firstrecv[iswap],pbc[iswap],pbc_flag[iswap]);
if(n<0) error->all(FLERR," # CUDA ERRROR on PackComm_Self");
if((sizeof(X_FLOAT)!=sizeof(double)) && n)
n=(n+1)*sizeof(X_FLOAT)/sizeof(double);
}
}
else if (ghost_velocity)
{
n = avec->pack_comm_vel(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
avec->unpack_comm_vel(recvnum[iswap],firstrecv[iswap],buf_send);
}
else
{
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_send);
}
}
}
if(not comm_x_only && not avec->cudable) cuda->uploadAll();
}
void CommCuda::forward_comm_transfer_cuda()
{
static int count=0;
static double kerneltime=0.0;
static double copytime=0.0;
my_times time1,time2,time3;
int n;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
double **x = atom->x;
cuda->shared_data.domain.xy=domain->xy;
cuda->shared_data.domain.xz=domain->xz;
cuda->shared_data.domain.yz=domain->yz;
cuda->shared_data.domain.prd[0]=domain->prd[0];
cuda->shared_data.domain.prd[1]=domain->prd[1];
cuda->shared_data.domain.prd[2]=domain->prd[2];
cuda->shared_data.domain.triclinic=domain->triclinic;
if(not comm_x_only && not avec->cudable) cuda->downloadAll(); //if not comm_x_only the communication routine of the atom_vec style class is used
//printf("A\n");
// exchange data with another proc
// if other proc is self, just copy
// if comm_x_only set, exchange or copy directly to x, don't unpack
for (int iswap = 0; iswap < nswap; iswap++) {
if (sendproc[iswap] != me)
{
if (comm_x_only)
{
int size_forward_recv_now=0;
if((sizeof(X_FLOAT)!=sizeof(double)) && size_forward_recv[iswap]) //some complicated way to safe some transfer size if single precision is used
size_forward_recv_now=(size_forward_recv[iswap]+1)*sizeof(X_FLOAT)/sizeof(double);
else
size_forward_recv_now=size_forward_recv[iswap];
//printf("A: %i \n",size_forward_recv_now/1024*4);
//MPI_Irecv(cuda->shared_data.comm.buf_recv[iswap],size_forward_recv_now,MPI_DOUBLE,
// recvproc[iswap],0,world,&request);
MPI_Irecv(buf_recv,size_forward_recv_now,MPI_DOUBLE,
recvproc[iswap],0,world,&request);
//printf("%p %p %i\n",buf_send, cuda->shared_data.comm.buf_send_dev[iswap], cuda->shared_data.comm.send_size[iswap]*sizeof(double));
//memcpy(buf_send,cuda->shared_data.comm.buf_send[iswap],cuda->shared_data.comm.send_size[iswap]*sizeof(double));
// CudaWrapper_SyncStream(1);
//printf("B: %i \n",cuda->shared_data.comm.send_size[iswap]/1024*4);
CudaWrapper_DownloadCudaDataAsync((void*) buf_send, cuda->shared_data.comm.buf_send_dev[iswap], cuda->shared_data.comm.send_size[iswap]*sizeof(double),2);
//MPI_Send(cuda->shared_data.comm.buf_send[iswap],cuda->shared_data.comm.send_size[iswap],MPI_DOUBLE,sendproc[iswap],0,world);
my_gettime(CLOCK_REALTIME,&time1);
CudaWrapper_SyncStream(2);
//printf("C: %i \n",cuda->shared_data.comm.send_size[iswap]/1024*4);
my_gettime(CLOCK_REALTIME,&time2);
cuda->shared_data.cuda_timings.comm_forward_download+=
time2.tv_sec-time1.tv_sec+1.0*(time2.tv_nsec-time1.tv_nsec)/1000000000;
MPI_Send(buf_send,cuda->shared_data.comm.send_size[iswap],MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
//printf("D: %i \n",cuda->shared_data.comm.send_size[iswap]/1024*4);
CudaWrapper_UploadCudaDataAsync((void*) buf_recv,cuda->shared_data.comm.buf_recv_dev[iswap], size_forward_recv_now*sizeof(double),2);
my_gettime(CLOCK_REALTIME,&time1);
CudaWrapper_SyncStream(2);
//printf("E: %i \n",cuda->shared_data.comm.send_size[iswap]/1024*4);
//memcpy(cuda->shared_data.comm.buf_recv[iswap],buf_recv,size_forward_recv_now*sizeof(double));
//printf("RecvSize: %i SendSize: %i\n",size_forward_recv_now*sizeof(double),cuda->shared_data.comm.send_size[iswap]*sizeof(double));
my_gettime(CLOCK_REALTIME,&time3);
cuda->shared_data.cuda_timings.comm_forward_upload+=
time3.tv_sec-time1.tv_sec+1.0*(time3.tv_nsec-time1.tv_nsec)/1000000000;
cuda->shared_data.cuda_timings.comm_forward_mpi_lower+=
time3.tv_sec-time2.tv_sec+1.0*(time3.tv_nsec-time2.tv_nsec)/1000000000;
my_gettime(CLOCK_REALTIME,&time3);
cuda->shared_data.cuda_timings.comm_forward_mpi_upper+=
time3.tv_sec-time1.tv_sec+1.0*(time3.tv_nsec-time1.tv_nsec)/1000000000;
}
else if (ghost_velocity)
{
/* int size_forward_recv_now=0;
if((sizeof(X_FLOAT)!=sizeof(double)) && size_forward_recv[iswap]) //some complicated way to safe some transfer size if single precision is used
size_forward_recv_now=(size_forward_recv[iswap]+1)*sizeof(X_FLOAT)/sizeof(double);
else
size_forward_recv_now=size_forward_recv[iswap];
my_gettime(CLOCK_REALTIME,&time1);
MPI_Irecv(cuda->shared_data.comm.buf_recv[iswap],size_forward_recv_now,MPI_DOUBLE,
recvproc[iswap],0,world,&request);
my_gettime(CLOCK_REALTIME,&time2);
MPI_Send(cuda->shared_data.comm.buf_send[iswap],cuda->shared_data.comm.send_size[iswap],MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
my_gettime(CLOCK_REALTIME,&time3);
cuda->shared_data.cuda_timings.comm_forward_mpi_upper+=
time3.tv_sec-time1.tv_sec+1.0*(time3.tv_nsec-time1.tv_nsec)/1000000000;
cuda->shared_data.cuda_timings.comm_forward_mpi_lower+=
time3.tv_sec-time2.tv_sec+1.0*(time3.tv_nsec-time2.tv_nsec)/1000000000;*/
}
else
{
MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE,
recvproc[iswap],0,world,&request);
if(avec->cudable)
n = avec->pack_comm(sendnum[iswap],&iswap,
buf_send,pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_recv);
}
}
else //sendproc == me
{
if (comm_x_only)
{
if (sendnum[iswap])
{
}
}
else if (ghost_velocity)
{
}
else
{
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_send);
}
}
}
if(not comm_x_only && not avec->cudable) cuda->uploadAll();
}
void CommCuda::forward_comm_unpack_cuda()
{
static int count=0;
static double kerneltime=0.0;
static double copytime=0.0;
my_times time1,time2,time3;
int n;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
double **x = atom->x;
cuda->shared_data.domain.xy=domain->xy;
cuda->shared_data.domain.xz=domain->xz;
cuda->shared_data.domain.yz=domain->yz;
cuda->shared_data.domain.prd[0]=domain->prd[0];
cuda->shared_data.domain.prd[1]=domain->prd[1];
cuda->shared_data.domain.prd[2]=domain->prd[2];
cuda->shared_data.domain.triclinic=domain->triclinic;
if(not comm_x_only && not avec->cudable) cuda->downloadAll(); //if not comm_x_only the communication routine of the atom_vec style class is used
// exchange data with another proc
// if other proc is self, just copy
// if comm_x_only set, exchange or copy directly to x, don't unpack
for (int iswap = 0; iswap < nswap; iswap++) {
if (sendproc[iswap] != me)
{
if (comm_x_only)
{
//Cuda_CommCuda_UnpackComm(&cuda->shared_data,recvnum[iswap],firstrecv[iswap],cuda->shared_data.comm.buf_recv[iswap],iswap); //Unpack for cpu exchange happens implicitely since buf==x[firstrecv]
Cuda_CommCuda_UnpackComm(&cuda->shared_data,recvnum[iswap],firstrecv[iswap],buf_recv,iswap); //Unpack for cpu exchange happens implicitely since buf==x[firstrecv]
}
else if (ghost_velocity)
{
//Cuda_CommCuda_UnpackComm_Vel(&cuda->shared_data,recvnum[iswap],firstrecv[iswap],(void*)&buf_recv[iswap*maxrecv]); //Unpack for cpu exchange happens implicitely since buf==x[firstrecv]
}
else
{
MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE,
recvproc[iswap],0,world,&request);
if(avec->cudable)
n = avec->pack_comm(sendnum[iswap],&iswap,
buf_send,pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_recv);
}
}
else //sendproc == me
{
if (comm_x_only)
{
if (sendnum[iswap])
{
}
}
else if (ghost_velocity)
{
}
else
{
n = avec->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_send);
}
}
}
if(not comm_x_only && not avec->cudable) cuda->uploadAll();
}
void CommCuda::forward_comm_pair(Pair *pair)
{
if(not cuda->shared_data.pair.cudable_force)
{
return Comm::forward_comm_pair(pair);
}
int iswap,n;
double *buf;
MPI_Request request;
MPI_Status status;
for (iswap = 0; iswap < nswap; iswap++) {
// pack buffer
n = pair->pack_comm(sendnum[iswap],&iswap,
buf_send,pbc_flag[iswap],pbc[iswap]);
int nrecv = recvnum[iswap]*n;
if(nrecv<0) nrecv=-(nrecv+1)/2;
int nsend = sendnum[iswap]*n;
if(nsend<0) nsend=-(nsend+1)/2;
// exchange with another proc
// if self, set recv buffer to send buffer
if (sendproc[iswap] != me) {
MPI_Irecv(buf_recv,nrecv,MPI_DOUBLE,recvproc[iswap],0,
world,&request);
MPI_Send(buf_send,nsend,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
buf = buf_recv;
} else buf = buf_send;
// unpack buffer
pair->unpack_comm(recvnum[iswap],firstrecv[iswap],buf);
}
}
/* ----------------------------------------------------------------------
reverse communication of forces on atoms every timestep
other per-atom attributes may also be sent via pack/unpack routines
------------------------------------------------------------------------- */
void CommCuda::reverse_comm()
{
int n;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
double **f = atom->f;
double *buf;
if(not comm_f_only && not avec->cudable) cuda->downloadAll(); //not yet implemented in CUDA but only needed for non standard atom styles
// exchange data with another proc
// if other proc is self, just copy
// if comm_f_only set, exchange or copy directly from f, don't pack
for (int iswap = nswap-1; iswap >= 0; iswap--) {
if (sendproc[iswap] != me) {
if (comm_f_only) {
int size_recv_now=size_reverse_recv[iswap];
if((sizeof(F_FLOAT)!=sizeof(double))&& size_reverse_recv[iswap])
size_recv_now=(size_recv_now+1)*sizeof(F_FLOAT)/sizeof(double);
MPI_Irecv(buf_recv,size_recv_now,MPI_DOUBLE,
sendproc[iswap],0,world,&request);
buf=buf_send;
if (size_reverse_send[iswap])
{
Cuda_CommCuda_PackReverse(&cuda->shared_data,size_reverse_send[iswap]/3,firstrecv[iswap],buf);
}
else buf=NULL;
int size_reverse_send_now=size_reverse_send[iswap];
if((sizeof(F_FLOAT)!=sizeof(double))&& size_reverse_send[iswap])
size_reverse_send_now=(size_reverse_send_now+1)*sizeof(F_FLOAT)/sizeof(double);
MPI_Send(buf,size_reverse_send_now,MPI_DOUBLE,
recvproc[iswap],0,world);
MPI_Wait(&request,&status);
Cuda_CommCuda_UnpackReverse(&cuda->shared_data,sendnum[iswap],iswap,buf_recv);
} else {
MPI_Irecv(buf_recv,size_reverse_recv[iswap],MPI_DOUBLE,
sendproc[iswap],0,world,&request);
n = avec->pack_reverse(recvnum[iswap],firstrecv[iswap],buf_send);
MPI_Send(buf_send,n,MPI_DOUBLE,recvproc[iswap],0,world);
MPI_Wait(&request,&status);
avec->unpack_reverse(sendnum[iswap],sendlist[iswap],buf_recv);
}
} else {
if (comm_f_only) {
if (sendnum[iswap])
Cuda_CommCuda_UnpackReverse_Self(&cuda->shared_data,sendnum[iswap],iswap,firstrecv[iswap]);
} else {
n = avec->pack_reverse(recvnum[iswap],firstrecv[iswap],buf_send);
avec->unpack_reverse(sendnum[iswap],sendlist[iswap],buf_send);
}
}
}
if(not comm_f_only && not avec->cudable) cuda->uploadAll(); //not yet implemented in CUDA but only needed for non standard atom styles
}
/* ----------------------------------------------------------------------
exchange: move atoms to correct processors
atoms exchanged with all 6 stencil neighbors
send out atoms that have left my box, receive ones entering my box
atoms will be lost if not inside some proc's box
can happen if atom moves outside of non-periodic bounary
or if atom moves more than one proc away
this routine called before every reneighboring
for triclinic, atoms must be in lamda coords (0-1) before exchange is called
------------------------------------------------------------------------- */
void CommCuda::exchange()
{
AtomVec *avec = atom->avec;
if(not cuda->oncpu && avec->cudable)
return exchange_cuda();
if(not cuda->oncpu) cuda->downloadAll();
Comm::exchange();
}
void CommCuda::exchange_cuda()
{
int i,m,nsend,nrecv,nrecv1,nrecv2,nlocal;
double lo,hi,value;
double **x;
double *sublo,*subhi,*buf;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
my_times time1,time2,time3;
// clear global->local map for owned and ghost atoms
// b/c atoms migrate to new procs in exchange() and
// new ghosts are created in borders()
// map_set() is done at end of borders()
if(map_style) cuda->cu_tag->download();
if (map_style) atom->map_clear();
// subbox bounds for orthogonal or triclinic
if (triclinic == 0) {
sublo = domain->sublo;
subhi = domain->subhi;
} else {
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
// loop over dimensions
for (int dim = 0; dim < 3; dim++) {
// fill buffer with atoms leaving my box, using < and >=
// when atom is deleted, fill it in with last atom
cuda->shared_data.exchange_dim=dim;
nlocal = atom->nlocal;
avec->maxsend=&maxsend;
nsend=avec->pack_exchange(dim,(double*) &buf_send);
nlocal = atom->nlocal;
atom->nlocal = nlocal;
// send/recv atoms in both directions
// if 1 proc in dimension, no send/recv, set recv buf to send buf
// if 2 procs in dimension, single send/recv
// if more than 2 procs in dimension, send/recv to both neighbors
my_gettime(CLOCK_REALTIME,&time1);
if (procgrid[dim] == 1) {
nrecv = nsend;
buf = buf_send;
} else {
MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][0],0,
&nrecv1,1,MPI_INT,procneigh[dim][1],0,world,&status);
nrecv = nrecv1;
if (procgrid[dim] > 2) {
MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][1],0,
&nrecv2,1,MPI_INT,procneigh[dim][0],0,world,&status);
nrecv += nrecv2;
}
if (nrecv+1 > maxrecv) grow_recv(nrecv+1);
MPI_Irecv(buf_recv,nrecv1,MPI_DOUBLE,procneigh[dim][1],0,
world,&request);
MPI_Send(buf_send,nsend,MPI_DOUBLE,procneigh[dim][0],0,world);
MPI_Wait(&request,&status);
if (procgrid[dim] > 2) {
MPI_Irecv(&buf_recv[nrecv1],nrecv2,MPI_DOUBLE,procneigh[dim][0],0,
world,&request);
MPI_Send(buf_send,nsend,MPI_DOUBLE,procneigh[dim][1],0,world);
MPI_Wait(&request,&status);
if((nrecv1==0)||(nrecv2==0)) buf_recv[nrecv]=0;
}
buf = buf_recv;
}
//printf("nsend: %i nrecv: %i\n",nsend,nrecv);
// check incoming atoms to see if they are in my box
// if so, add to my list
my_gettime(CLOCK_REALTIME,&time2);
cuda->shared_data.cuda_timings.comm_exchange_mpi+=
time2.tv_sec-time1.tv_sec+1.0*(time2.tv_nsec-time1.tv_nsec)/1000000000;
if(nrecv)
{
avec->maxsend=&maxsend;
avec->unpack_exchange(buf);
}
}
if(atom->firstgroupname) cuda->downloadAll();
if(atom->firstgroupname) atom->first_reorder();
if(atom->firstgroupname) cuda->uploadAll();
}
/* ----------------------------------------------------------------------
borders: list nearby atoms to send to neighboring procs at every timestep
one list is created for every swap that will be made
as list is made, actually do swaps
this does equivalent of a communicate (so don't need to explicitly
call communicate routine on reneighboring timestep)
this routine is called before every reneighboring
for triclinic, atoms must be in lamda coords (0-1) before borders is called
------------------------------------------------------------------------- */
void CommCuda::borders()
{
AtomVec *avec = atom->avec;
if(not cuda->oncpu && avec->cudable)
{
if(cuda->shared_data.overlap_comm&&cuda->finished_setup)
borders_cuda_overlap_forward_comm();
else
borders_cuda();
return;
}
Comm::borders();
cuda->setSystemParams();
if(cuda->finished_setup) {cuda->checkResize(); cuda->uploadAll();}
cuda->shared_data.atom.nghost=atom->nghost;
cu_sendlist->upload();
}
void CommCuda::borders_cuda()
{
int i,n,itype,iswap,dim,ineed,twoneed,smax,rmax;
int nsend,nrecv,nfirst,nlast,ngroup;
double lo,hi;
int *type;
double **x;
double *buf,*mlo,*mhi;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
my_times time1,time2,time3;
// clear old ghosts
atom->nghost = 0;
// do swaps over all 3 dimensions
iswap = 0;
smax = rmax = 0;
cuda->shared_data.comm.nsend=0;
for (dim = 0; dim < 3; dim++) {
nlast = 0;
twoneed = 2*maxneed[dim];
for (ineed = 0; ineed < twoneed; ineed++) {
// find atoms within slab boundaries lo/hi using <= and >=
// check atoms between nfirst and nlast
// for first swaps in a dim, check owned and ghost
// for later swaps in a dim, only check newly arrived ghosts
// store sent atom indices in list for use in future timesteps
x = atom->x;
if (style == SINGLE) {
lo = slablo[iswap];
hi = slabhi[iswap];
} else {
type = atom->type;
mlo = multilo[iswap];
mhi = multihi[iswap];
}
if (ineed % 2 == 0) {
nfirst = nlast;
nlast = atom->nlocal + atom->nghost;
}
nsend = 0;
// find send atoms according to SINGLE vs MULTI
// all atoms eligible versus atoms in bordergroup
// only need to limit loop to bordergroup for first sends (ineed < 2)
// on these sends, break loop in two: owned (in group) and ghost
do
{
if(nsend>=maxsendlist[iswap]) grow_list(iswap,static_cast <int> (nsend*1.05));
nsend=Cuda_CommCuda_BuildSendlist(&cuda->shared_data,bordergroup,ineed,style==SINGLE?1:0,atom->nfirst,nfirst,nlast,dim,iswap);
}while(nsend>=maxsendlist[iswap]);
// pack up list of border atoms
if (nsend*size_border > maxsend)
grow_send(nsend*size_border,0);
if (ghost_velocity)
n = avec->pack_border_vel(nsend,&iswap,buf_send,
pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_border(nsend,&iswap,buf_send,
pbc_flag[iswap],pbc[iswap]);
// swap atoms with other proc
// put incoming ghosts at end of my atom arrays
// if swapping with self, simply copy, no messages
my_gettime(CLOCK_REALTIME,&time1);
if (sendproc[iswap] != me) {
MPI_Sendrecv(&nsend,1,MPI_INT,sendproc[iswap],0,
&nrecv,1,MPI_INT,recvproc[iswap],0,world,&status);
if (nrecv*size_border > maxrecv)
grow_recv(nrecv*size_border);
MPI_Irecv(buf_recv,nrecv*size_border,MPI_DOUBLE,
recvproc[iswap],0,world,&request);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
buf = buf_recv;
} else {
nrecv = nsend;
buf = buf_send;
}
my_gettime(CLOCK_REALTIME,&time2);
cuda->shared_data.cuda_timings.comm_border_mpi+=
time2.tv_sec-time1.tv_sec+1.0*(time2.tv_nsec-time1.tv_nsec)/1000000000;
// unpack buffer
if (ghost_velocity)
avec->unpack_border_vel(nrecv,atom->nlocal+atom->nghost,buf);
else
avec->unpack_border(nrecv,atom->nlocal+atom->nghost,buf);
// set all pointers & counters
smax = MAX(smax,nsend);
rmax = MAX(rmax,nrecv);
sendnum[iswap] = nsend;
recvnum[iswap] = nrecv;
size_forward_recv[iswap] = nrecv*size_forward;
size_reverse_send[iswap] = nrecv*size_reverse;
size_reverse_recv[iswap] = nsend*size_reverse;
firstrecv[iswap] = atom->nlocal + atom->nghost;
atom->nghost += nrecv;
iswap++;
}
}
// insure send/recv buffers are long enough for all forward & reverse comm
int max = MAX(maxforward*smax,maxreverse*rmax);
if (max > maxsend) grow_send(max,0);
max = MAX(maxforward*rmax,maxreverse*smax);
if (max > maxrecv) grow_recv(max);
// reset global->local map
if(map_style)
{
cuda->cu_tag->download();
atom->map_set();
}
cuda->setSystemParams();
cuda->shared_data.atom.nghost+=n;
}
void CommCuda::borders_cuda_overlap_forward_comm()
{
int i,n,itype,iswap,dim,ineed,twoneed,smax,rmax;
int nsend,nrecv,nfirst,nlast,ngroup;
double lo,hi;
int *type;
double **x;
double *buf,*mlo,*mhi;
MPI_Request request;
MPI_Status status;
AtomVec *avec = atom->avec;
my_times time1,time2,time3;
// clear old ghosts
atom->nghost = 0;
// do swaps over all 3 dimensions
iswap = 0;
smax = rmax = 0;
cuda->shared_data.comm.nsend=0;
for (dim = 0; dim < 3; dim++) {
nlast = 0;
twoneed = 2*maxneed[dim];
for (ineed = 0; ineed < twoneed; ineed++) {
// find atoms within slab boundaries lo/hi using <= and >=
// check atoms between nfirst and nlast
// for first swaps in a dim, check owned and ghost
// for later swaps in a dim, only check newly arrived ghosts
// store sent atom indices in list for use in future timesteps
x = atom->x;
if (style == SINGLE) {
lo = slablo[iswap];
hi = slabhi[iswap];
} else {
type = atom->type;
mlo = multilo[iswap];
mhi = multihi[iswap];
}
if (ineed % 2 == 0) {
nfirst = nlast;
nlast = atom->nlocal + atom->nghost;
}
nsend = 0;
// find send atoms according to SINGLE vs MULTI
// all atoms eligible versus atoms in bordergroup
// only need to limit loop to bordergroup for first sends (ineed < 2)
// on these sends, break loop in two: owned (in group) and ghost
do
{
if(nsend>=maxsendlist[iswap]) grow_list(iswap,static_cast <int> (nsend*1.05));
nsend=Cuda_CommCuda_BuildSendlist(&cuda->shared_data,bordergroup,ineed,style==SINGLE?1:0,atom->nfirst,nfirst,nlast,dim,iswap);
}while(nsend>=maxsendlist[iswap]);
cuda->shared_data.comm.nsend_swap[iswap]=nsend;
// pack up list of border atoms
if (nsend*size_border > maxsend)
grow_send(nsend*size_border,0);
if (ghost_velocity)
n = avec->pack_border_vel(nsend,&iswap,buf_send,
pbc_flag[iswap],pbc[iswap]);
else
n = avec->pack_border(nsend,&iswap,buf_send,
pbc_flag[iswap],pbc[iswap]);
// swap atoms with other proc
// put incoming ghosts at end of my atom arrays
// if swapping with self, simply copy, no messages
my_gettime(CLOCK_REALTIME,&time1);
if (sendproc[iswap] != me) {
MPI_Sendrecv(&nsend,1,MPI_INT,sendproc[iswap],0,
&nrecv,1,MPI_INT,recvproc[iswap],0,world,&status);
if (nrecv*size_border > maxrecv)
grow_recv(nrecv*size_border);
MPI_Irecv(buf_recv,nrecv*size_border,MPI_DOUBLE,
recvproc[iswap],0,world,&request);
MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
buf = buf_recv;
} else {
nrecv = nsend;
buf = buf_send;
}
my_gettime(CLOCK_REALTIME,&time2);
cuda->shared_data.cuda_timings.comm_border_mpi+=
time2.tv_sec-time1.tv_sec+1.0*(time2.tv_nsec-time1.tv_nsec)/1000000000;
// unpack buffer
if (ghost_velocity)
avec->unpack_border_vel(nrecv,atom->nlocal+atom->nghost,buf);
else
avec->unpack_border(nrecv,atom->nlocal+atom->nghost,buf);
// set all pointers & counters
smax = MAX(smax,nsend);
rmax = MAX(rmax,nrecv);
sendnum[iswap] = nsend;
recvnum[iswap] = nrecv;
size_forward_recv[iswap] = nrecv*size_forward;
size_reverse_send[iswap] = nrecv*size_reverse;
size_reverse_recv[iswap] = nsend*size_reverse;
firstrecv[iswap] = atom->nlocal + atom->nghost;
atom->nghost += nrecv;
iswap++;
}
}
// insure send/recv buffers are long enough for all forward & reverse comm
int max = MAX(maxforward*smax,maxreverse*rmax);
if (max > maxsend) grow_send(max,0);
max = MAX(maxforward*rmax,maxreverse*smax);
if (max > maxrecv) grow_recv(max);
// reset global->local map
if(map_style)
{
cuda->cu_tag->download();
atom->map_set();
}
cuda->setSystemParams();
cuda->shared_data.atom.nghost+=n;
}
void CommCuda::forward_comm_fix(Fix *fix)
{
int iswap,n;
double *buf;
MPI_Request request;
MPI_Status status;
for (iswap = 0; iswap < nswap; iswap++) {
// pack buffer
if(fix->cudable_comm&&cuda->finished_setup)
{
int swap=iswap;
if(sendproc[iswap] == me) {swap=-iswap-1; buf=(double*)&(firstrecv[iswap]);}
else buf=buf_send;
n = fix->pack_comm(sendnum[iswap],&swap,
buf,pbc_flag[iswap],pbc[iswap]);
if(sendproc[iswap] == me)
{
continue;
}
}
else
n = fix->pack_comm(sendnum[iswap],sendlist[iswap],
buf_send,pbc_flag[iswap],pbc[iswap]);
// exchange with another proc
// if self, set recv buffer to send buffer
if (sendproc[iswap] != me) {
MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0,
world,&request);
MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world);
MPI_Wait(&request,&status);
buf = buf_recv;
} else buf = buf_send;
// unpack buffer
fix->unpack_comm(recvnum[iswap],firstrecv[iswap],buf);
}
}
void CommCuda::grow_send(int n, int flag)
{
int oldmaxsend = (maxsend+BUFEXTRA)*sizeof(double);
maxsend = static_cast<int> (BUFFACTOR * n);
if (flag){
if(cuda->pinned)
{
double* tmp = new double[oldmaxsend];
memcpy((void*) tmp,(void*) buf_send,oldmaxsend*sizeof(double));
if(buf_send) CudaWrapper_FreePinnedHostData((void*) (buf_send));
buf_send = (double*) CudaWrapper_AllocPinnedHostData((maxsend+BUFEXTRA)*sizeof(double),false);
memcpy(buf_send,tmp,oldmaxsend*sizeof(double));
delete [] tmp;
}
else
{
buf_send = (double *)
memory->srealloc(buf_send,(maxsend+BUFEXTRA)*sizeof(double),
"comm:buf_send");printf("srealloc\n");
}
}
else {
if(cuda->pinned)
{
if(buf_send) CudaWrapper_FreePinnedHostData((void*) buf_send);
buf_send = (double*) CudaWrapper_AllocPinnedHostData((maxsend+BUFEXTRA)*sizeof(double),false);
}
else
{
memory->sfree(buf_send);
buf_send = (double *) memory->smalloc((maxsend+BUFEXTRA)*sizeof(double),
"comm:buf_send");
}
for(int i=0;i<maxswap;i++)
{
if(cuda->shared_data.comm.buf_send_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_send_dev[i],oldmaxsend);
cuda->shared_data.comm.buf_send_dev[i]=CudaWrapper_AllocCudaData((maxsend+BUFEXTRA)*sizeof(double));
}
}
}
/* ----------------------------------------------------------------------
free/malloc the size of the recv buffer as needed with BUFFACTOR
------------------------------------------------------------------------- */
void CommCuda::grow_recv(int n)
{
int oldmaxrecv = maxrecv*sizeof(double);
maxrecv = static_cast<int> (BUFFACTOR * n);
if(cuda->pinned)
{
if(buf_recv) CudaWrapper_FreePinnedHostData((void*)buf_recv);
buf_recv = (double*) CudaWrapper_AllocPinnedHostData(maxrecv*sizeof(double), false,true);
}
else
{
memory->sfree(buf_recv);
buf_recv = (double *) memory->smalloc(maxrecv*sizeof(double),
"comm:buf_recv");
}
for(int i=0;i<maxswap;i++)
{
if(cuda->shared_data.comm.buf_recv_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_recv_dev[i],oldmaxrecv);
cuda->shared_data.comm.buf_recv_dev[i]=CudaWrapper_AllocCudaData((maxrecv)*sizeof(double));
}
}
/* ----------------------------------------------------------------------
realloc the size of the iswap sendlist as needed with BUFFACTOR
------------------------------------------------------------------------- */
void CommCuda::grow_list(int iswap, int n)
{
MYDBG(printf(" # CUDA CommCuda::grow_list\n");)
if(cuda->finished_setup&&cu_sendlist) cu_sendlist->download();
if(!cu_sendlist||n*BUFFACTOR>cu_sendlist->get_dim()[1]||n*BUFFACTOR>maxsendlist[iswap])
{
for(int i=0;i<maxswap;i++)
{
maxsendlist[i] = static_cast<int> (BUFFACTOR * n);
sendlist[i] = (int *)
memory->srealloc(sendlist[i],maxsendlist[i]*sizeof(int),
"comm:sendlist[iswap]");
}
delete cu_sendlist;
cu_sendlist=new cCudaData<int, int, xy> ((int*)sendlist,maxswap,maxsendlist[iswap]);
cuda->shared_data.comm.sendlist.dev_data=cu_sendlist->dev_data();
cuda->shared_data.comm.maxlistlength=maxsendlist[iswap];
cu_sendlist->upload();
}
}
/* ----------------------------------------------------------------------
realloc the buffers needed for swaps
------------------------------------------------------------------------- */
void CommCuda::grow_swap(int n)
{
int oldmaxswap=maxswap;
Comm::grow_swap(n);
if(n>cu_sendlist->get_dim()[0])
{
MYDBG(printf(" # CUDA CommCuda::grow_swap\n");)
delete cu_sendlist;
cu_sendlist=new cCudaData<int, int, xy> ((int*)sendlist,n,BUFMIN);
cuda->shared_data.comm.sendlist.dev_data=cu_sendlist->dev_data();
cuda->shared_data.comm.maxlistlength=BUFMIN;
cuda->shared_data.comm.maxswap=n;
cuda->shared_data.comm.nsend_swap=new int[n];
cuda->shared_data.comm.send_size=new int[n];
cuda->shared_data.comm.recv_size=new int[n];
}
for(int i=0;i<oldmaxswap;i++)
{
if(cuda->shared_data.comm.buf_recv_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_recv_dev[i],maxrecv*sizeof(double));
if(cuda->shared_data.comm.buf_send_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_send_dev[i],maxsend*sizeof(double));
cuda->shared_data.comm.buf_recv_dev[i]=NULL;
cuda->shared_data.comm.buf_send_dev[i]=NULL;
}
cuda->shared_data.comm.buf_send= new double*[n];
cuda->shared_data.comm.buf_recv= new double*[n];
cuda->shared_data.comm.buf_send_dev= new void*[n];
cuda->shared_data.comm.buf_recv_dev= new void*[n];
for(int i=0;i<n;i++)
{
cuda->shared_data.comm.buf_recv[i]=NULL;
cuda->shared_data.comm.buf_send[i]=NULL;
cuda->shared_data.comm.buf_recv_dev[i]=NULL;
cuda->shared_data.comm.buf_send_dev[i]=NULL;
}
grow_send(maxsend,0);
grow_recv(maxrecv);
maxswap=n;
}
/* ----------------------------------------------------------------------
allocation of swap info
------------------------------------------------------------------------- */
void CommCuda::allocate_swap(int n)
{
Comm::allocate_swap(n);
delete cu_pbc;
delete cu_slablo;
delete cu_slabhi;
cuda->shared_data.comm.maxswap=n;
if(cu_sendlist)
{
cu_pbc=new cCudaData<int, int, xy> ((int*)pbc,n,6);
cu_slablo = new cCudaData<double, X_FLOAT,x>(slablo,n);
cu_slabhi = new cCudaData<double, X_FLOAT,x>(slabhi,n);
cuda->shared_data.comm.pbc.dev_data=cu_pbc->dev_data();
cuda->shared_data.comm.slablo.dev_data=cu_slablo->dev_data();
cuda->shared_data.comm.slabhi.dev_data=cu_slabhi->dev_data();
}
cuda->shared_data.comm.nsend_swap=new int[n];
cuda->shared_data.comm.send_size=new int[n];
cuda->shared_data.comm.recv_size=new int[n];
cuda->shared_data.comm.buf_send= new double*[n];
cuda->shared_data.comm.buf_recv= new double*[n];
cuda->shared_data.comm.buf_send_dev= new void*[n];
cuda->shared_data.comm.buf_recv_dev= new void*[n];
for(int i=0;i<n;i++) cuda->shared_data.comm.buf_send_dev[i]=NULL;
for(int i=0;i<n;i++) cuda->shared_data.comm.buf_recv_dev[i]=NULL;
}
/* ----------------------------------------------------------------------
allocation of multi-type swap info
------------------------------------------------------------------------- */
void CommCuda::allocate_multi(int n)
{
Comm::allocate_multi(n);
delete cu_multilo;
delete cu_multihi;
cu_multilo = new cCudaData<double, X_FLOAT,xy>(slablo,n,atom->ntypes+1);
cu_multihi = new cCudaData<double, X_FLOAT,xy>(slabhi,n,atom->ntypes+1);
cuda->shared_data.comm.multilo.dev_data=cu_multilo->dev_data();
cuda->shared_data.comm.multihi.dev_data=cu_multihi->dev_data();
}
/* ----------------------------------------------------------------------
free memory for swaps
------------------------------------------------------------------------- */
void CommCuda::free_swap()
{
Comm::free_swap();
delete cuda->shared_data.comm.nsend_swap; cuda->shared_data.comm.nsend_swap=NULL;
delete cu_pbc; cu_pbc = NULL;
delete cu_slablo; cu_slablo = NULL;
delete cu_slabhi; cu_slabhi = NULL;
for(int i=0;i<maxswap;i++)
{
if(cuda->shared_data.comm.buf_recv_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_recv_dev[i],maxrecv*sizeof(double));
if(cuda->shared_data.comm.buf_send_dev[i]) CudaWrapper_FreeCudaData(cuda->shared_data.comm.buf_send_dev[i],maxsend*sizeof(double));
}
}
/* ----------------------------------------------------------------------
free memory for multi-type swaps
------------------------------------------------------------------------- */
void CommCuda::free_multi()
{
Comm::free_multi();
delete cu_multilo; cu_multilo = NULL;
delete cu_multihi; cu_multihi = NULL;
}
diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp
index 1658d4892..c68e34803 100644
--- a/src/USER-EFF/atom_vec_electron.cpp
+++ b/src/USER-EFF/atom_vec_electron.cpp
@@ -1,995 +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 author: Andres Jaramillo-Botero (Caltech)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "atom_vec_electron.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
static const char cite_user_eff_package[] =
"USER-EFF package:\n\n"
"@Article{Jaramillo-Botero11,\n"
" author = {A. Jaramillo-Botero, J. Su, A. Qi, W. A. Goddard III},\n"
" title = {Large-Scale, Long-Term Nonadiabatic Electron Molecular Dynamics for Describing Material Properties and Phenomena in Extreme Environments},\n"
" journal = {J.~Comp.~Chem.},\n"
" year = 2011,\n"
" volume = 32,\n"
" pages = {497--512}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp)
{
if (lmp->citeme) lmp->citeme->add(cite_user_eff_package);
comm_x_only = comm_f_only = 0;
mass_type = 1;
molecular = 0;
size_forward = 4;
size_reverse = 4;
size_border = 9;
size_velocity = 3;
size_data_atom = 8;
size_data_vel = 5;
xcol_data = 6;
atom->ecp_flag = 0;
atom->electron_flag = 1;
atom->q_flag = atom->spin_flag = atom->eradius_flag =
atom->ervel_flag = atom->erforce_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom-electron arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecElectron::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
q = memory->grow(atom->q,nmax,"atom:q");
spin = memory->grow(atom->spin,nmax,"atom:spin");
eradius = memory->grow(atom->eradius,nmax,"atom:eradius");
ervel = memory->grow(atom->ervel,nmax,"atom:ervel");
erforce = memory->grow(atom->erforce,nmax*comm->nthreads,"atom:erforce");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecElectron::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
q = atom->q;
eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecElectron::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
q[j] = q[i];
spin[j] = spin[i];
eradius[j] = eradius[i];
ervel[j] = ervel[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = eradius[j];
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = eradius[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = eradius[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecElectron::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
eradius[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecElectron::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
eradius[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
eradius[i] = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = erforce[i];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
buf[m++] = erforce[i];
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecElectron::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
erforce[j] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
erforce[j] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (domain->triclinic == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
buf[m++] = ubuf(spin[j]).d;
buf[m++] = eradius[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecElectron::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecElectron::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
q[i] = buf[m++];
spin[i] = (int) ubuf(buf[m++]).i;
eradius[i] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecElectron::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = q[i];
buf[m++] = ubuf(spin[i]).d;
buf[m++] = eradius[i];
buf[m++] = ervel[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecElectron::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
q[nlocal] = buf[m++];
spin[nlocal] = (int) ubuf(buf[m++]).i;
eradius[nlocal] = buf[m++];
ervel[nlocal] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecElectron::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 15 * nlocal; // Associated with pack_restart
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecElectron::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = q[i];
buf[m++] = ubuf(spin[i]).d;
buf[m++] = eradius[i];
buf[m++] = ervel[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecElectron::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
q[nlocal] = buf[m++];
spin[nlocal] = (int) ubuf(buf[m++]).i;
eradius[nlocal] = buf[m++];
ervel[nlocal] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecElectron::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
q[nlocal] = 0.0;
spin[nlocal] = 1;
eradius[nlocal] = 1.0;
ervel[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecElectron::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
q[nlocal] = atof(values[2]);
spin[nlocal] = atoi(values[3]);
if (spin[nlocal] == 3) atom->ecp_flag = 1;
eradius[nlocal] = atof(values[4]);
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
ervel[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecElectron::data_atom_hybrid(int nlocal, char **values)
{
q[nlocal] = atof(values[0]);
spin[nlocal] = atoi(values[1]);
eradius[nlocal] = atof(values[2]);
if (eradius[nlocal] < 0.0)
error->one(FLERR,"Invalid eradius in Atoms section of data file");
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
ervel[nlocal] = 0.0;
return 3;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecElectron::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
ervel[m] = atof(values[3]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecElectron::data_vel_hybrid(int m, char **values)
{
ervel[m] = atof(values[0]);
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecElectron::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = q[i];
buf[i][3] = ubuf(spin[i]).d;
buf[i][4] = eradius[i];
buf[i][5] = x[i][0];
buf[i][6] = x[i][1];
buf[i][7] = x[i][2];
buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecElectron::pack_data_hybrid(int i, double *buf)
{
buf[0] = q[i];
buf[1] = ubuf(spin[i]).d;
buf[2] = eradius[i];
return 3;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecElectron::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,buf[i][2],
+ fprintf(fp,TAGINT_FORMAT
+ " %d %-1.16e %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,buf[i][2],
(int) ubuf(buf[i][3]).i,buf[i][4],buf[i][5],buf[i][6],buf[i][7],
(int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i,
(int) ubuf(buf[i][10]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecElectron::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %d %-1.16e",buf[0],(int) ubuf(buf[1]).i,buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecElectron::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = ervel[i];
}
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
int AtomVecElectron::pack_vel_hybrid(int i, double *buf)
{
buf[0] = ervel[i];
return 1;
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
void AtomVecElectron::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
+ fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecElectron::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e",buf[0]);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecElectron::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("q")) bytes += memory->usage(q,nmax);
if (atom->memcheck("spin")) bytes += memory->usage(spin,nmax);
if (atom->memcheck("eradius")) bytes += memory->usage(eradius,nmax);
if (atom->memcheck("ervel")) bytes += memory->usage(ervel,nmax);
if (atom->memcheck("erforce"))
bytes += memory->usage(erforce,nmax*comm->nthreads);
return bytes;
}
diff --git a/src/USER-EFF/atom_vec_electron.h b/src/USER-EFF/atom_vec_electron.h
index a17530de7..a6d606fd0 100644
--- a/src/USER-EFF/atom_vec_electron.h
+++ b/src/USER-EFF/atom_vec_electron.h
@@ -1,81 +1,82 @@
/* -*- 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 ATOM_CLASS
AtomStyle(electron,AtomVecElectron)
#else
#ifndef LMP_ATOM_VEC_ELECTRON_H
#define LMP_ATOM_VEC_ELECTRON_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecElectron : public AtomVec {
public:
AtomVecElectron(class LAMMPS *);
~AtomVecElectron() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *spin;
double *q,*eradius,*ervel,*erforce;
};
}
#endif
#endif
diff --git a/src/USER-EFF/pair_eff_cut.cpp b/src/USER-EFF/pair_eff_cut.cpp
index 12467b57b..121217751 100644
--- a/src/USER-EFF/pair_eff_cut.cpp
+++ b/src/USER-EFF/pair_eff_cut.cpp
@@ -1,1075 +1,1073 @@
/* ----------------------------------------------------------------------
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: Andres Jaramillo-Botero
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_eff_cut.h"
#include "pair_eff_inline.h"
#include "atom.h"
#include "update.h"
#include "min.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
#include "atom_vec_electron.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairEffCut::PairEffCut(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
nmax = 0;
min_eradius = NULL;
min_erforce = NULL;
nextra = 4;
pvector = new double[nextra];
}
/* ---------------------------------------------------------------------- */
PairEffCut::~PairEffCut()
{
delete [] pvector;
memory->destroy(min_eradius);
memory->destroy(min_erforce);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cut);
}
}
/* ---------------------------------------------------------------------- */
void PairEffCut::compute(int eflag, int vflag)
{
int i,j,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,energy;
double eke,ecoul,epauli,errestrain,halfcoul,halfpauli;
double fpair,fx,fy,fz;
double e1rforce,e2rforce,e1rvirial,e2rvirial;
double s_fpair, s_e1rforce, s_e2rforce;
double ecp_epauli, ecp_fpair, ecp_e1rforce, ecp_e2rforce;
double rsq,rc;
int *ilist,*jlist,*numneigh,**firstneigh;
energy = eke = epauli = ecp_epauli = ecoul = errestrain = 0.0;
// pvector = [KE, Pauli, ecoul, radial_restraint]
for (i=0; i<4; i++) pvector[i] = 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 *erforce = atom->erforce;
double *eradius = atom->eradius;
int *spin = atom->spin;
int *type = atom->type;
int nlocal = atom->nlocal;
- int *id = atom->tag;
-
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];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
itype = type[i];
jlist = firstneigh[i];
jnum = numneigh[i];
// add electron wavefuntion kinetic energy (not pairwise)
if (abs(spin[i])==1 || spin[i]==2) {
// reset energy and force temp variables
eke = epauli = ecoul = 0.0;
fpair = e1rforce = e2rforce = 0.0;
s_fpair = 0.0;
KinElec(eradius[i],&eke,&e1rforce);
// Fixed-core
if (spin[i] == 2) {
// KE(2s)+Coul(1s-1s)+Coul(2s-nuclei)+Pauli(2s)
eke *= 2;
ElecNucElec(q[i],0.0,eradius[i],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[i],0.0,eradius[i],&ecoul,&fpair,&e1rforce);
ElecElecElec(0.0,eradius[i],eradius[i],&ecoul,&fpair,&e1rforce,&e2rforce);
// opposite spin electron interactions
PauliElecElec(0,0.0,eradius[i],eradius[i],
&epauli,&s_fpair,&e1rforce,&e2rforce);
// fix core electron size, i.e. don't contribute to ervirial
e2rforce = e1rforce = 0.0;
}
// apply unit conversion factors
eke *= hhmss2e;
ecoul *= qqrd2e;
fpair *= qqrd2e;
epauli *= hhmss2e;
s_fpair *= hhmss2e;
e1rforce *= hhmss2e;
// Sum up contributions
energy = eke + epauli + ecoul;
fpair = fpair + s_fpair;
erforce[i] += e1rforce;
// Tally energy and compute radial atomic virial contribution
if (evflag) {
ev_tally_eff(i,i,nlocal,newton_pair,energy,0.0);
if (pressure_with_evirials_flag) // iff flexible pressure flag on
ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rforce*eradius[i]);
}
if (eflag_global) {
pvector[0] += eke;
pvector[1] += epauli;
pvector[2] += ecoul;
}
}
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;
rc = sqrt(rsq);
jtype = type[j];
if (rsq < cutsq[itype][jtype]) {
energy = ecoul = epauli = ecp_epauli = 0.0;
fx = fy = fz = fpair = s_fpair = ecp_fpair = 0.0;
double taper = sqrt(cutsq[itype][jtype]);
double dist = rc / taper;
double spline = cutoff(dist);
double dspline = dcutoff(dist) / taper;
// nucleus (i) - nucleus (j) Coul interaction
if (spin[i] == 0 && spin[j] == 0) {
double qxq = q[i]*q[j];
ElecNucNuc(qxq, rc, &ecoul, &fpair);
}
// fixed-core (i) - nucleus (j) nuclear Coul interaction
else if (spin[i] == 2 && spin[j] == 0) {
double qxq = q[i]*q[j];
e1rforce = 0.0;
ElecNucNuc(qxq, rc, &ecoul, &fpair);
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce);
}
// nucleus (i) - fixed-core (j) nuclear Coul interaction
else if (spin[i] == 0 && spin[j] == 2) {
double qxq = q[i]*q[j];
e1rforce = 0.0;
ElecNucNuc(qxq, rc, &ecoul, &fpair);
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce);
}
// pseudo-core nucleus (i) - nucleus (j) interaction
else if (spin[i] == 3 && spin[j] == 0) {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[i], &ecoul, &fpair);
}
else if (spin[i] == 4 && spin[j] == 0) {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[i], &ecoul, &fpair);
}
// nucleus (i) - pseudo-core nucleus (j) interaction
else if (spin[i] == 0 && spin[j] == 3) {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair);
}
else if (spin[i] == 0 && spin[j] == 4) {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair);
}
// nucleus (i) - electron (j) Coul interaction
else if (spin[i] == 0 && abs(spin[j]) == 1) {
e1rforce = 0.0;
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce);
e1rforce = spline * qqrd2e * e1rforce;
erforce[j] += e1rforce;
// Radial electron virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e1rvirial = eradius[j] * e1rforce;
ev_tally_eff(j,j,nlocal,newton_pair,0.0,e1rvirial);
}
}
// electron (i) - nucleus (j) Coul interaction
else if (abs(spin[i]) == 1 && spin[j] == 0) {
e1rforce = 0.0;
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce);
e1rforce = spline * qqrd2e * e1rforce;
erforce[i] += e1rforce;
// Radial electron virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e1rvirial = eradius[i] * e1rforce;
ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rvirial);
}
}
// electron (i) - electron (j) interactions
else if (abs(spin[i]) == 1 && abs(spin[j]) == 1) {
e1rforce = e2rforce = 0.0;
s_e1rforce = s_e2rforce = 0.0;
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
PauliElecElec(spin[i] == spin[j],rc,eradius[i],eradius[j],
&epauli,&s_fpair,&s_e1rforce,&s_e2rforce);
// Apply conversion factor
epauli *= hhmss2e;
s_fpair *= hhmss2e;
e1rforce = spline * (qqrd2e * e1rforce + hhmss2e * s_e1rforce);
erforce[i] += e1rforce;
e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce);
erforce[j] += e2rforce;
// Radial electron virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e1rvirial = eradius[i] * e1rforce;
e2rvirial = eradius[j] * e2rforce;
ev_tally_eff(i,j,nlocal,newton_pair,0.0,e1rvirial+e2rvirial);
}
}
// fixed-core (i) - electron (j) interactions
else if (spin[i] == 2 && abs(spin[j]) == 1) {
e1rforce = e2rforce = 0.0;
s_e1rforce = s_e2rforce = 0.0;
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e2rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
PauliElecElec(0,rc,eradius[i],eradius[j],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
PauliElecElec(1,rc,eradius[i],eradius[j],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
// Apply conversion factor
epauli *= hhmss2e;
s_fpair *= hhmss2e;
// only update virial for j electron
e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce);
erforce[j] += e2rforce;
// Radial electron virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e2rvirial = eradius[j] * e2rforce;
ev_tally_eff(j,j,nlocal,newton_pair,0.0,e2rvirial);
}
}
// electron (i) - fixed-core (j) interactions
else if (abs(spin[i]) == 1 && spin[j] == 2) {
e1rforce = e2rforce = 0.0;
s_e1rforce = s_e2rforce = 0.0;
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e2rforce);
ElecElecElec(rc,eradius[j],eradius[i],&ecoul,&fpair,
&e1rforce,&e2rforce);
ElecElecElec(rc,eradius[j],eradius[i],&ecoul,&fpair,
&e1rforce,&e2rforce);
PauliElecElec(0,rc,eradius[j],eradius[i],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
PauliElecElec(1,rc,eradius[j],eradius[i],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
// Apply conversion factor
epauli *= hhmss2e;
s_fpair *= hhmss2e;
// only update virial for i electron
e2rforce = spline * (qqrd2e * e2rforce + hhmss2e * s_e2rforce);
erforce[i] += e2rforce;
// add radial atomic virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e2rvirial = eradius[i] * e2rforce;
ev_tally_eff(i,i,nlocal,newton_pair,0.0,e2rvirial);
}
}
// fixed-core (i) - fixed-core (j) interactions
else if (spin[i] == 2 && spin[j] == 2) {
e1rforce = e2rforce = 0.0;
s_e1rforce = s_e2rforce = 0.0;
double qxq = q[i]*q[j];
ElecNucNuc(qxq, rc, &ecoul, &fpair);
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[i],rc,eradius[j],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce);
ElecNucElec(q[j],rc,eradius[i],&ecoul,&fpair,&e1rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
ElecElecElec(rc,eradius[i],eradius[j],&ecoul,&fpair,
&e1rforce,&e2rforce);
PauliElecElec(0,rc,eradius[i],eradius[j],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
PauliElecElec(1,rc,eradius[i],eradius[j],&epauli,
&s_fpair,&s_e1rforce,&s_e2rforce);
epauli *= 2;
s_fpair *= 2;
// Apply conversion factor
epauli *= hhmss2e;
s_fpair *= hhmss2e;
}
// pseudo-core (i) - electron/fixed-core electrons (j) interactions
else if (spin[i] == 3 && (abs(spin[j]) == 1 || spin[j] == 2)) {
e2rforce = ecp_e2rforce = 0.0;
if (((PAULI_CORE_D[ecp_type[itype]]) == 0.0) && ((PAULI_CORE_E[ecp_type[itype]]) == 0.0)) {
if (abs(spin[j]) == 1) {
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]]);
} else { // add second s electron contribution from fixed-core
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair);
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]]);
PauliCoreElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]]);
}
} else {
if (abs(spin[j]) == 1) {
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]],PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]);
} else { // add second s electron contribution from fixed-core
double qxq = q[i]*q[j];
ElecCoreNuc(qxq, rc, eradius[j], &ecoul, &fpair);
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
ElecCoreElec(q[i],rc,eradius[i],eradius[j],&ecoul,
&fpair,&e2rforce);
PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]);
PauliCorePElec(rc,eradius[j],&ecp_epauli,&ecp_fpair,
&ecp_e2rforce,PAULI_CORE_A[ecp_type[itype]], PAULI_CORE_B[ecp_type[itype]],
PAULI_CORE_C[ecp_type[itype]],PAULI_CORE_D[ecp_type[itype]],PAULI_CORE_E[ecp_type[itype]]);
}
}
// Apply conversion factor from Hartree to kcal/mol
ecp_epauli *= h2e;
ecp_fpair *= h2e;
// only update virial for j electron
e2rforce = spline * (qqrd2e * e2rforce + h2e * ecp_e2rforce);
erforce[j] += e2rforce;
// add radial atomic virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e2rvirial = eradius[j] * e2rforce;
ev_tally_eff(j,j,nlocal,newton_pair,0.0,e2rvirial);
}
}
// electron/fixed-core electrons (i) - pseudo-core (j) interactions
else if ((abs(spin[i]) == 1 || spin[i] == 2) && spin[j] == 3) {
e1rforce = ecp_e1rforce = 0.0;
if (((PAULI_CORE_D[ecp_type[jtype]]) == 0.0) && ((PAULI_CORE_E[ecp_type[jtype]]) == 0.0)) {
if (abs(spin[i]) == 1) {
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]],PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]]);
} else {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq,rc,eradius[i],&ecoul,&fpair);
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]]);
PauliCoreElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]]);
}
} else {
if (abs(spin[i]) == 1) {
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]],PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]);
} else {
double qxq = q[i]*q[j];
ElecCoreNuc(qxq,rc,eradius[i],&ecoul,&fpair);
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
ElecCoreElec(q[j],rc,eradius[j],eradius[i],&ecoul,
&fpair,&e1rforce);
PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]);
PauliCorePElec(rc,eradius[i],&ecp_epauli,&ecp_fpair,
&ecp_e1rforce,PAULI_CORE_A[ecp_type[jtype]], PAULI_CORE_B[ecp_type[jtype]],
PAULI_CORE_C[ecp_type[jtype]],PAULI_CORE_D[ecp_type[jtype]],PAULI_CORE_E[ecp_type[jtype]]);
}
}
// Apply conversion factor from Hartree to kcal/mol
ecp_epauli *= h2e;
ecp_fpair *= h2e;
// only update virial for j electron
e1rforce = spline * (qqrd2e * e1rforce + h2e * ecp_e1rforce);
erforce[i] += e1rforce;
// add radial atomic virial, iff flexible pressure flag set
if (evflag && pressure_with_evirials_flag) {
e1rvirial = eradius[i] * e1rforce;
ev_tally_eff(i,i,nlocal,newton_pair,0.0,e1rvirial);
}
}
// pseudo-core (i) - pseudo-core (j) interactions
else if (spin[i] == 3 && spin[j] == 3) {
double qxq = q[i]*q[j];
ElecCoreCore(qxq,rc,eradius[i],eradius[j],&ecoul,&fpair);
}
// Apply Coulomb conversion factor for all cases
ecoul *= qqrd2e;
fpair *= qqrd2e;
// Sum up energy and force contributions
epauli += ecp_epauli;
energy = ecoul + epauli;
fpair = fpair + s_fpair + ecp_fpair;
// Apply cutoff spline
fpair = fpair * spline - energy * dspline;
energy = spline * energy;
// Tally cartesian forces
SmallRForce(delx,dely,delz,rc,fpair,&fx,&fy,&fz);
f[i][0] += fx;
f[i][1] += fy;
f[i][2] += fz;
if (newton_pair || j < nlocal) {
f[j][0] -= fx;
f[j][1] -= fy;
f[j][2] -= fz;
}
// Tally energy (in ecoul) and compute normal pressure virials
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,0.0,
energy,fx,fy,fz,delx,dely,delz);
if (eflag_global) {
if (newton_pair) {
pvector[1] += spline * epauli;
pvector[2] += spline * ecoul;
}
else {
halfpauli = 0.5 * spline * epauli;
halfcoul = 0.5 * spline * ecoul;
if (i < nlocal) {
pvector[1] += halfpauli;
pvector[2] += halfcoul;
}
if (j < nlocal) {
pvector[1] += halfpauli;
pvector[2] += halfcoul;
}
}
}
}
}
// limit electron stifness (size) for periodic systems, to max=half-box-size
if (abs(spin[i]) == 1 && limit_eradius_flag) {
double half_box_length=0, dr, kfactor=hhmss2e*1.0;
e1rforce = errestrain = 0.0;
if (domain->xperiodic == 1 || domain->yperiodic == 1 ||
domain->zperiodic == 1) {
delx = domain->boxhi[0]-domain->boxlo[0];
dely = domain->boxhi[1]-domain->boxlo[1];
delz = domain->boxhi[2]-domain->boxlo[2];
half_box_length = 0.5 * MIN(delx, MIN(dely, delz));
if (eradius[i] > half_box_length) {
dr = eradius[i]-half_box_length;
errestrain=0.5*kfactor*dr*dr;
e1rforce=-kfactor*dr;
if (eflag_global) pvector[3] += errestrain;
erforce[i] += e1rforce;
// Tally radial restrain energy and add radial restrain virial
if (evflag) {
ev_tally_eff(i,i,nlocal,newton_pair,errestrain,0.0);
if (pressure_with_evirials_flag) // flexible electron pressure
ev_tally_eff(i,i,nlocal,newton_pair,0.0,eradius[i]*e1rforce);
}
}
}
}
}
if (vflag_fdotr) {
virial_fdotr_compute();
if (pressure_with_evirials_flag) virial_eff_compute();
}
}
/* ----------------------------------------------------------------------
eff-specific contribution to global virial
------------------------------------------------------------------------- */
void PairEffCut::virial_eff_compute()
{
double *eradius = atom->eradius;
double *erforce = atom->erforce;
double e_virial;
int *spin = atom->spin;
// 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++) {
if (spin[i]) {
e_virial = erforce[i]*eradius[i]/3;
virial[0] += e_virial;
virial[1] += e_virial;
virial[2] += e_virial;
}
}
// 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++) {
if (spin[i]) {
e_virial = erforce[i]*eradius[i]/3;
virial[0] += e_virial;
virial[1] += e_virial;
virial[2] += e_virial;
}
}
nall = atom->nlocal + atom->nghost;
for (int i = atom->nlocal; i < nall; i++) {
if (spin[i]) {
e_virial = erforce[i]*eradius[i]/3;
virial[0] += e_virial;
virial[1] += e_virial;
virial[2] += e_virial;
}
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into per-atom accumulators
for virial radial electronic contributions
------------------------------------------------------------------------- */
void PairEffCut::ev_tally_eff(int i, int j, int nlocal, int newton_pair,
double energy, double e_virial)
{
double energyhalf;
double partial_evirial = e_virial/3.0;
double half_partial_evirial = partial_evirial/2;
int *spin = atom->spin;
if (eflag_either) {
if (eflag_global) {
if (newton_pair)
eng_coul += energy;
else {
energyhalf = 0.5*energy;
if (i < nlocal)
eng_coul += energyhalf;
if (j < nlocal)
eng_coul += energyhalf;
}
}
if (eflag_atom) {
if (newton_pair || i < nlocal) eatom[i] += 0.5 * energy;
if (newton_pair || j < nlocal) eatom[j] += 0.5 * energy;
}
}
if (vflag_either) {
if (vflag_global) {
if (spin[i] && i < nlocal) {
virial[0] += half_partial_evirial;
virial[1] += half_partial_evirial;
virial[2] += half_partial_evirial;
}
if (spin[j] && j < nlocal) {
virial[0] += half_partial_evirial;
virial[1] += half_partial_evirial;
virial[2] += half_partial_evirial;
}
}
if (vflag_atom) {
if (spin[i]) {
if (newton_pair || i < nlocal) {
vatom[i][0] += half_partial_evirial;
vatom[i][1] += half_partial_evirial;
vatom[i][2] += half_partial_evirial;
}
}
if (spin[j]) {
if (newton_pair || j < nlocal) {
vatom[j][0] += half_partial_evirial;
vatom[j][1] += half_partial_evirial;
vatom[j][2] += half_partial_evirial;
}
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairEffCut::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");
}
/* ---------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairEffCut::settings(int narg, char **arg)
{
if (narg < 1)
error->all(FLERR,"Illegal pair_style command");
// Defaults ECP parameters for C (radius=0.154)
PAULI_CORE_A[6] = 22.721015;
PAULI_CORE_B[6] = 0.728733;
PAULI_CORE_C[6] = 1.103199;
PAULI_CORE_D[6] = 17.695345;
PAULI_CORE_E[6] = 6.693621;
// Defaults ECP parameters for N (radius=0.394732)
PAULI_CORE_A[7] = 16.242367;
PAULI_CORE_B[7] = 0.602818;
PAULI_CORE_C[7] = 1.081856;
PAULI_CORE_D[7] = 7.150803;
PAULI_CORE_E[7] = 5.351936;
// Defaults p-element ECP parameters for Oxygen (radius=0.15)
PAULI_CORE_A[8] = 29.5185;
PAULI_CORE_B[8] = 0.32995;
PAULI_CORE_C[8] = 1.21676;
PAULI_CORE_D[8] = 11.98757;
PAULI_CORE_E[8] = 3.073417;
// Defaults ECP parameters for Al (radius=1.660)
PAULI_CORE_A[13] = 0.486;
PAULI_CORE_B[13] = 1.049;
PAULI_CORE_C[13] = 0.207;
PAULI_CORE_D[13] = 0.0;
PAULI_CORE_E[13] = 0.0;
// Defaults ECP parameters for Si (radius=1.691)
PAULI_CORE_A[14] = 0.320852;
PAULI_CORE_B[14] = 2.283269;
PAULI_CORE_C[14] = 0.814857;
PAULI_CORE_D[14] = 0.0;
PAULI_CORE_E[14] = 0.0;
cut_global = force->numeric(FLERR,arg[0]);
limit_eradius_flag = 0;
pressure_with_evirials_flag = 0;
int atype;
int iarg = 1;
int ecp_found = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"limit/eradius") == 0) {
limit_eradius_flag = 1;
iarg += 1;
}
else if (strcmp(arg[iarg],"pressure/evirials") == 0) {
pressure_with_evirials_flag = 1;
iarg += 1;
}
else if (strcmp(arg[iarg],"ecp") == 0) {
iarg += 1;
while (iarg < narg) {
atype = force->inumeric(FLERR,arg[iarg]);
if (strcmp(arg[iarg+1],"C") == 0) ecp_type[atype] = 6;
else if (strcmp(arg[iarg+1],"N") == 0) ecp_type[atype] = 7;
else if (strcmp(arg[iarg+1],"O") == 0) ecp_type[atype] = 8;
else if (strcmp(arg[iarg+1],"Al") == 0) ecp_type[atype] = 13;
else if (strcmp(arg[iarg+1],"Si") == 0) ecp_type[atype] = 14;
else error->all(FLERR, "Note: there are no default parameters for this atom ECP\n");
iarg += 2;
ecp_found = 1;
}
}
}
if (!ecp_found && atom->ecp_flag)
error->all(FLERR,"Need to specify ECP type on pair_style command");
// Need to introduce 2 new constants w/out changing update.cpp
if (force->qqr2e==332.06371) { // i.e. Real units chosen
h2e = 627.509; // hartree->kcal/mol
hhmss2e = 175.72044219620075; // hartree->kcal/mol * (Bohr->Angstrom)^2
} else if (force->qqr2e==1.0) { // electron units
h2e = 1.0;
hhmss2e = 1.0;
} else error->all(FLERR,"Check your units");
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i+1; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairEffCut::init_style()
{
// error and warning checks
if (!atom->q_flag || !atom->spin_flag ||
!atom->eradius_flag || !atom->erforce_flag)
error->all(FLERR,"Pair eff/cut requires atom attributes "
"q, spin, eradius, erforce");
// add hook to minimizer for eradius and erforce
if (update->whichflag == 2)
int ignore = update->minimize->request(this,1,0.01);
// make sure to use the appropriate timestep when using real units
if (update->whichflag == 1) {
if (force->qqr2e == 332.06371 && update->dt == 1.0)
error->all(FLERR,"You must lower the default real units timestep for pEFF ");
}
// need a half neigh list and optionally a granular history neigh list
int irequest = neighbor->request(this);
}
/* ----------------------------------------------------------------------
set coeffs for one or more type electron pairs (ECP-only)
------------------------------------------------------------------------- */
void PairEffCut::coeff(int narg, char **arg)
{
if (!allocated) allocate();
if ((strcmp(arg[0],"*") == 0) || (strcmp(arg[1],"*") == 0)) {
int ilo,ihi,jlo,jhi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
double cut_one = cut_global;
if (narg == 3) cut_one = force->numeric(FLERR,arg[2]);
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");
} else {
int ecp;
ecp = force->inumeric(FLERR,arg[0]);
if (strcmp(arg[1],"s") ==0) {
PAULI_CORE_A[ecp_type[ecp]] = force->numeric(FLERR,arg[2]);
PAULI_CORE_B[ecp_type[ecp]] = force->numeric(FLERR,arg[3]);
PAULI_CORE_C[ecp_type[ecp]] = force->numeric(FLERR,arg[4]);
PAULI_CORE_D[ecp_type[ecp]] = 0.0;
PAULI_CORE_E[ecp_type[ecp]] = 0.0;
} else if (strcmp(arg[1],"p") ==0) {
PAULI_CORE_A[ecp_type[ecp]] = force->numeric(FLERR,arg[2]);
PAULI_CORE_B[ecp_type[ecp]] = force->numeric(FLERR,arg[3]);
PAULI_CORE_C[ecp_type[ecp]] = force->numeric(FLERR,arg[4]);
PAULI_CORE_D[ecp_type[ecp]] = force->numeric(FLERR,arg[5]);
PAULI_CORE_E[ecp_type[ecp]] = force->numeric(FLERR,arg[6]);
} else error->all(FLERR,"Illegal pair_coeff command");
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairEffCut::init_one(int i, int j)
{
if (setflag[i][j] == 0)
cut[i][j] = mix_distance(cut[i][i],cut[j][j]);
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairEffCut::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(&cut[i][j],sizeof(double),1,fp);
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairEffCut::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(&cut[i][j],sizeof(double),1,fp);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairEffCut::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 PairEffCut::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);
}
/* ----------------------------------------------------------------------
returns pointers to the log() of electron radius and corresponding force
minimizer operates on log(radius) so radius never goes negative
these arrays are stored locally by pair style
------------------------------------------------------------------------- */
void PairEffCut::min_xf_pointers(int ignore, double **xextra, double **fextra)
{
// grow arrays if necessary
// need to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(min_eradius);
memory->destroy(min_erforce);
nmax = atom->nmax;
memory->create(min_eradius,nmax,"pair:min_eradius");
memory->create(min_erforce,nmax,"pair:min_erforce");
}
*xextra = min_eradius;
*fextra = min_erforce;
}
/* ----------------------------------------------------------------------
minimizer requests the log() of electron radius and corresponding force
calculate and store in min_eradius and min_erforce
------------------------------------------------------------------------- */
void PairEffCut::min_xf_get(int ignore)
{
double *eradius = atom->eradius;
double *erforce = atom->erforce;
int *spin = atom->spin;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
if (spin[i]) {
min_eradius[i] = log(eradius[i]);
min_erforce[i] = eradius[i]*erforce[i];
} else min_eradius[i] = min_erforce[i] = 0.0;
}
/* ----------------------------------------------------------------------
minimizer has changed the log() of electron radius
propagate the change back to eradius
------------------------------------------------------------------------- */
void PairEffCut::min_x_set(int ignore)
{
double *eradius = atom->eradius;
int *spin = atom->spin;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
if (spin[i]) eradius[i] = exp(min_eradius[i]);
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double PairEffCut::memory_usage()
{
double bytes = maxeatom * sizeof(double);
bytes += maxvatom*6 * sizeof(double);
bytes += 2 * nmax * sizeof(double);
return bytes;
}
diff --git a/src/USER-MISC/dihedral_cosine_shift_exp.cpp b/src/USER-MISC/dihedral_cosine_shift_exp.cpp
index ea2c5e51e..ec6cc01fb 100644
--- a/src/USER-MISC/dihedral_cosine_shift_exp.cpp
+++ b/src/USER-MISC/dihedral_cosine_shift_exp.cpp
@@ -1,339 +1,341 @@
/* ----------------------------------------------------------------------
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: Carsten Svaneborg, science@zqex.dk
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_cosine_shift_exp.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
DihedralCosineShiftExp::DihedralCosineShiftExp(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralCosineShiftExp::~DihedralCosineShiftExp()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(umin);
memory->destroy(a);
memory->destroy(opt1);
memory->destroy(cost);
memory->destroy(sint);
memory->destroy(theta);
memory->destroy(doExpansion);
}
}
/* ---------------------------------------------------------------------- */
void DihedralCosineShiftExp::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,m,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb;
double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz;
double c,s,p,sx2,sy2,sz2;
double cccpsss,cssmscc,exp2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c,s calculation
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
double aa=a[type];
double uumin=umin[type];
cccpsss = c*cost[type]+s*sint[type];
cssmscc = c*sint[type]-s*cost[type];
// eflag=1;
if (doExpansion[type])
{ // |a|<0.001 so use expansions relative precision <1e-5
if (eflag) edihedral = -0.125*(1+cccpsss)*(4+aa*(cccpsss-1))*uumin;
df=0.5*uumin*( cssmscc + 0.5*aa*cccpsss);
}
else
{
exp2=exp(0.5*aa*(1+cccpsss));
if (eflag) edihedral = opt1[type]*(1-exp2);
df= 0.5*opt1[type]*aa* ( exp2*cssmscc );
}
fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm;
hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm;
fga = fg*ra2inv*rginv;
hgb = hg*rb2inv*rginv;
gaa = -ra2inv*rg;
gbb = rb2inv*rg;
dtfx = gaa*ax;
dtfy = gaa*ay;
dtfz = gaa*az;
dtgx = fga*ax - hgb*bx;
dtgy = fga*ay - hgb*by;
dtgz = fga*az - hgb*bz;
dthx = gbb*bx;
dthy = gbb*by;
dthz = gbb*bz;
sx2 = df*dtgx;
sy2 = df*dtgy;
sz2 = df*dtgz;
f1[0] = df*dtfx;
f1[1] = df*dtfy;
f1[2] = df*dtfz;
f2[0] = sx2 - f1[0];
f2[1] = sy2 - f1[1];
f2[2] = sz2 - f1[2];
f4[0] = df*dthx;
f4[1] = df*dthy;
f4[2] = df*dthz;
f3[0] = -sx2 - f4[0];
f3[1] = -sy2 - f4[1];
f3[2] = -sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralCosineShiftExp::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(doExpansion, n+1, "dihedral:doExpansion");
memory->create(umin,n+1,"dihedral:umin");
memory->create(a,n+1,"dihedral:a");
memory->create(sint,n+1,"dihedral:sind");
memory->create(cost,n+1,"dihedral:cosd");
memory->create(opt1,n+1,"dihedral:opt1");
memory->create(theta,n+1,"dihedral:opt1");
memory->create(setflag, n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralCosineShiftExp::coeff(int narg, char **arg)
{
if (narg != 4) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double umin_ = force->numeric(FLERR,arg[1]);
double theta0_ = force->numeric(FLERR,arg[2]);
double a_ = force->numeric(FLERR,arg[3]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
doExpansion[i]=(fabs(a_)<0.001);
umin[i] = umin_;
a[i] = a_;
cost[i] = cos(theta0_*3.14159265/180);
sint[i] = sin(theta0_*3.14159265/180);
theta[i] = theta0_*3.14159265/180;
if (!doExpansion[i]) opt1[i]=umin_/(exp(a_)-1);
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralCosineShiftExp::write_restart(FILE *fp)
{
fwrite(&umin[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&a[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&cost[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&sint[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&theta[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralCosineShiftExp::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&umin[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&a[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&cost[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&sint[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&theta[1],sizeof(double),atom->ndihedraltypes,fp);
}
MPI_Bcast(&umin[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&a[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&cost[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&sint[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&theta[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) {
setflag[i] = 1;
doExpansion[i]=(fabs(a[i])<0.01);
if (!doExpansion[i]) opt1[i]=umin[i]/(exp(a[i])-1);
}
}
diff --git a/src/USER-MISC/dihedral_fourier.cpp b/src/USER-MISC/dihedral_fourier.cpp
index 3ddf4cd24..c00dcfcfa 100644
--- a/src/USER-MISC/dihedral_fourier.cpp
+++ b/src/USER-MISC/dihedral_fourier.cpp
@@ -1,407 +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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Loukas D. Peristeras (Scienomics SARL)
[ based on dihedral_charmm.cpp Paul Crozier (SNL) ]
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_fourier.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "pair.h"
#include "update.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
/* ---------------------------------------------------------------------- */
DihedralFourier::DihedralFourier(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralFourier::~DihedralFourier()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(nterms);
for (int i=1; i<= atom->ndihedraltypes; i++) {
if ( k[i] ) delete [] k[i];
if ( multiplicity[i] ) delete [] multiplicity[i];
if ( shift[i] ) delete [] shift[i];
if ( cos_shift[i] ) delete [] cos_shift[i];
if ( sin_shift[i] ) delete [] sin_shift[i];
}
delete [] k;
delete [] multiplicity;
delete [] shift;
delete [] cos_shift;
delete [] sin_shift;
}
}
/* ---------------------------------------------------------------------- */
void DihedralFourier::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,i,j,m,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double df,df1_,ddf1_,fg,hg,fga,hgb,gaa,gbb;
double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz;
double c,s,p,p_,sx2,sy2,sz2;
int itype,jtype;
double delx,dely,delz,rsq,r2inv,r6inv;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
double *q = atom->q;
int *atomtype = atom->type;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double qqrd2e = force->qqrd2e;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force and energy
// p = sum(i=1,nterms) k_i*(1+cos(n_i*phi-d_i)
// dp = dp / dphi
edihedral = 0.0;
df = 0.0;
for (j=0; j<nterms[type]; j++)
{
m = multiplicity[type][j];
p_ = 1.0;
df1_ = 0.0;
for (i = 0; i < m; i++) {
ddf1_ = p_*c - df1_*s;
df1_ = p_*s + df1_*c;
p_ = ddf1_;
}
p_ = p_*cos_shift[type][j] + df1_*sin_shift[type][j];
df1_ = df1_*cos_shift[type][j] - ddf1_*sin_shift[type][j];
df1_ *= -m;
p_ += 1.0;
if (m == 0) {
p_ = 1.0 + cos_shift[type][j];
df1_ = 0.0;
}
if (eflag) edihedral += k[type][j] * p_;
df += (-k[type][j] * df1_);
}
fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm;
hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm;
fga = fg*ra2inv*rginv;
hgb = hg*rb2inv*rginv;
gaa = -ra2inv*rg;
gbb = rb2inv*rg;
dtfx = gaa*ax;
dtfy = gaa*ay;
dtfz = gaa*az;
dtgx = fga*ax - hgb*bx;
dtgy = fga*ay - hgb*by;
dtgz = fga*az - hgb*bz;
dthx = gbb*bx;
dthy = gbb*by;
dthz = gbb*bz;
sx2 = df*dtgx;
sy2 = df*dtgy;
sz2 = df*dtgz;
f1[0] = df*dtfx;
f1[1] = df*dtfy;
f1[2] = df*dtfz;
f2[0] = sx2 - f1[0];
f2[1] = sy2 - f1[1];
f2[2] = sz2 - f1[2];
f4[0] = df*dthx;
f4[1] = df*dthy;
f4[2] = df*dthz;
f3[0] = -sx2 - f4[0];
f3[1] = -sy2 - f4[1];
f3[2] = -sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralFourier::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(nterms,n+1,"dihedral:nterms");
k = new double * [n+1];
multiplicity = new int * [n+1];
shift = new double * [n+1];
cos_shift = new double * [n+1];
sin_shift = new double * [n+1];
for (int i = 1; i <= n; i++) {
k[i] = shift[i] = cos_shift[i] = sin_shift[i] = 0;
multiplicity[i] = 0;
}
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralFourier::coeff(int narg, char **arg)
{
if (narg < 4) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
// require integer values of shift for backwards compatibility
// arbitrary phase angle shift could be allowed, but would break
// backwards compatibility and is probably not needed
double k_one;
int multiplicity_one;
double shift_one;
int nterms_one = force->inumeric(FLERR,arg[1]);
if (nterms_one < 1)
error->all(FLERR,"Incorrect number of terms arg for dihedral coefficients");
if (2+3*nterms_one < narg)
error->all(FLERR,"Incorrect number of arguments for dihedral coefficients");
int count = 0;
for (int i = ilo; i <= ihi; i++) {
nterms[i] = nterms_one;
k[i] = new double [nterms_one];
multiplicity[i] = new int [nterms_one];
shift[i] = new double [nterms_one];
cos_shift[i] = new double [nterms_one];
sin_shift[i] = new double [nterms_one];
for (int j = 0; j<nterms_one; j++) {
int offset = 1+3*j;
k_one = force->numeric(FLERR,arg[offset+1]);
multiplicity_one = force->inumeric(FLERR,arg[offset+2]);
shift_one = force->numeric(FLERR,arg[offset+3]);
k[i][j] = k_one;
multiplicity[i][j] = multiplicity_one;
shift[i][j] = shift_one;
cos_shift[i][j] = cos(MY_PI*shift_one/180.0);
sin_shift[i][j] = sin(MY_PI*shift_one/180.0);
}
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralFourier::write_restart(FILE *fp)
{
fwrite(&nterms[1],sizeof(int),atom->ndihedraltypes,fp);
for(int i = 1; i <= atom->ndihedraltypes; i++) {
fwrite(k[i],sizeof(double),nterms[i],fp);
fwrite(multiplicity[i],sizeof(int),nterms[i],fp);
fwrite(shift[i],sizeof(double),nterms[i],fp);
}
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralFourier::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0)
fread(&nterms[1],sizeof(int),atom->ndihedraltypes,fp);
MPI_Bcast(&nterms[1],atom->ndihedraltypes,MPI_INT,0,world);
// allocate
for (int i=1; i<=atom->ndihedraltypes; i++) {
k[i] = new double [nterms[i]];
multiplicity[i] = new int [nterms[i]];
shift[i] = new double [nterms[i]];
cos_shift[i] = new double [nterms[i]];
sin_shift[i] = new double [nterms[i]];
}
if (comm->me == 0) {
for (int i=1; i<=atom->ndihedraltypes; i++) {
fread(k[i],sizeof(double),nterms[i],fp);
fread(multiplicity[i],sizeof(int),nterms[i],fp);
fread(shift[i],sizeof(double),nterms[i],fp);
}
}
for (int i=1; i<=atom->ndihedraltypes; i++) {
MPI_Bcast(k[i],nterms[i],MPI_DOUBLE,0,world);
MPI_Bcast(multiplicity[i],nterms[i],MPI_INT,0,world);
MPI_Bcast(shift[i],nterms[i],MPI_DOUBLE,0,world);
}
for (int i=1; i <= atom->ndihedraltypes; i++) {
setflag[i] = 1;
for (int j = 0; j < nterms[i]; j++) {
cos_shift[i][j] = cos(MY_PI*shift[i][j]/180.0);
sin_shift[i][j] = sin(MY_PI*shift[i][j]/180.0);
}
}
}
diff --git a/src/USER-MISC/dihedral_nharmonic.cpp b/src/USER-MISC/dihedral_nharmonic.cpp
index d06ef08a9..6370b8573 100644
--- a/src/USER-MISC/dihedral_nharmonic.cpp
+++ b/src/USER-MISC/dihedral_nharmonic.cpp
@@ -1,335 +1,337 @@
/* ----------------------------------------------------------------------
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: Loukas D. Peristeras (Scienomics SARL)
[ based on dihedral_multi_harmonic.cpp Mathias Puetz (SNL) and friends ]
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_nharmonic.h"
#include "atom.h"
#include "neighbor.h"
#include "domain.h"
#include "comm.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
DihedralNHarmonic::DihedralNHarmonic(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralNHarmonic::~DihedralNHarmonic()
{
if (allocated) {
memory->destroy(setflag);
for (int i = 1; i <= atom->ndihedraltypes; i++)
delete [] a[i];
delete [] a;
delete [] nterms;
}
}
/* ---------------------------------------------------------------------- */
void DihedralNHarmonic::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,c_,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s12,c,p,pd,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
double s2,sin2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - c1mag*c1mag,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - c2mag*c2mag,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
// p = sum (i=1,n) a_i * c**(i-1)
// pd = dp/dc
c_ = c;
p = this->a[type][0];
pd = this->a[type][1];
for (int i = 1; i < nterms[type]-1; i++) {
p += c_ * this->a[type][i];
pd += c_ * static_cast<double>(i+1) * this->a[type][i+1];
c_ *= c;
}
p += c_ * this->a[type][nterms[type]-1];
if (eflag) edihedral = p;
c = c * pd;
s12 = s12 * pd;
a11 = c*sb1*s1;
a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1*(c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2*(c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralNHarmonic::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(nterms,n+1,"dihedral:nt");
a = new double * [n+1];
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralNHarmonic::coeff(int narg, char **arg)
{
if (narg < 4 ) error->all(FLERR,"Incorrect args for dihedral coefficients");
int n = force->inumeric(FLERR,arg[1]);
if (narg != n + 2 ) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
a[i] = new double [n];
nterms[i] = n;
for (int j = 0; j < n; j++ ) {
a[i][j] = force->numeric(FLERR,arg[2+j]);
setflag[i] = 1;
}
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralNHarmonic::write_restart(FILE *fp)
{
fwrite(&nterms[1],sizeof(int),atom->ndihedraltypes,fp);
for(int i = 1; i <= atom->ndihedraltypes; i++)
fwrite(a[i],sizeof(double),nterms[i],fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralNHarmonic::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0)
fread(&nterms[1],sizeof(int),atom->ndihedraltypes,fp);
MPI_Bcast(&nterms[1],atom->ndihedraltypes,MPI_INT,0,world);
// allocate
for(int i = 1; i <= atom->ndihedraltypes; i++)
a[i] = new double [nterms[i]];
if (comm->me == 0) {
for(int i = 1; i <= atom->ndihedraltypes; i++)
fread(a[i],sizeof(double),nterms[i],fp);
}
for (int i = 1; i <= atom->ndihedraltypes; i++ )
MPI_Bcast(a[i],nterms[i],MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
diff --git a/src/USER-MISC/dihedral_quadratic.cpp b/src/USER-MISC/dihedral_quadratic.cpp
index 06391b712..bec383f21 100644
--- a/src/USER-MISC/dihedral_quadratic.cpp
+++ b/src/USER-MISC/dihedral_quadratic.cpp
@@ -1,334 +1,336 @@
/* ----------------------------------------------------------------------
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: Loukas D. Peristeras (Scienomics SARL)
[ based on dihedral_helix.cpp Paul Crozier (SNL) ]
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "math.h"
#include "stdlib.h"
#include "dihedral_quadratic.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
#define SMALLER 0.00001
/* ---------------------------------------------------------------------- */
DihedralQuadratic::DihedralQuadratic(LAMMPS *lmp) : Dihedral(lmp) {}
/* ---------------------------------------------------------------------- */
DihedralQuadratic::~DihedralQuadratic()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(phi0);
}
}
/* ---------------------------------------------------------------------- */
void DihedralQuadratic::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double edihedral,f1[3],f2[3],f3[3],f4[3];
double sb1,sb2,sb3,rb1,rb3,c0,b1mag2,b1mag,b2mag2;
double b2mag,b3mag2,b3mag,ctmp,r12c1,c1mag,r12c2;
double c2mag,sc1,sc2,s1,s12,c,p,pd,a,a11,a22;
double a33,a12,a13,a23,sx2,sy2,sz2;
double s2,cx,cy,cz,cmag,dx,phi,si,sin2;
edihedral = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **dihedrallist = neighbor->dihedrallist;
int ndihedrallist = neighbor->ndihedrallist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < ndihedrallist; n++) {
i1 = dihedrallist[n][0];
i2 = dihedrallist[n][1];
i3 = dihedrallist[n][2];
i4 = dihedrallist[n][3];
type = dihedrallist[n][4];
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
// c0 calculation
sb1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
sb2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
sb3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
rb1 = sqrt(sb1);
rb3 = sqrt(sb3);
c0 = (vb1x*vb3x + vb1y*vb3y + vb1z*vb3z) * rb1*rb3;
// 1st and 2nd angle
b1mag2 = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z;
b1mag = sqrt(b1mag2);
b2mag2 = vb2x*vb2x + vb2y*vb2y + vb2z*vb2z;
b2mag = sqrt(b2mag2);
b3mag2 = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z;
b3mag = sqrt(b3mag2);
ctmp = vb1x*vb2x + vb1y*vb2y + vb1z*vb2z;
r12c1 = 1.0 / (b1mag*b2mag);
c1mag = ctmp * r12c1;
ctmp = vb2xm*vb3x + vb2ym*vb3y + vb2zm*vb3z;
r12c2 = 1.0 / (b2mag*b3mag);
c2mag = ctmp * r12c2;
// cos and sin of 2 angles and final c
sin2 = MAX(1.0 - c1mag*c1mag,0.0);
sc1 = sqrt(sin2);
if (sc1 < SMALL) sc1 = SMALL;
sc1 = 1.0/sc1;
sin2 = MAX(1.0 - c2mag*c2mag,0.0);
sc2 = sqrt(sin2);
if (sc2 < SMALL) sc2 = SMALL;
sc2 = 1.0/sc2;
s1 = sc1 * sc1;
s2 = sc2 * sc2;
s12 = sc1 * sc2;
c = (c0 + c1mag*c2mag) * s12;
cx = vb1y*vb2z - vb1z*vb2y;
cy = vb1z*vb2x - vb1x*vb2z;
cz = vb1x*vb2y - vb1y*vb2x;
cmag = sqrt(cx*cx + cy*cy + cz*cz);
dx = (cx*vb3x + cy*vb3y + cz*vb3z)/cmag/b3mag;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " %d %d %d %d",
- me,update->ntimestep,
+ sprintf(str,"Dihedral problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
+ me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
// p = k ( phi- phi0)^2
// pd = dp/dc
phi = acos(c);
if (dx < 0.0) phi *= -1.0;
si = sin(phi);
double dphi = phi-phi0[type];
p = k[type]*dphi;
if (fabs(si) < SMALLER) {
pd = - 2.0 * k[type];
} else {
pd = - 2.0 * p / si;
}
p = p * dphi;
if (eflag) edihedral = p;
a = pd;
c = c * a;
s12 = s12 * a;
a11 = c*sb1*s1;
a22 = -sb2 * (2.0*c0*s12 - c*(s1+s2));
a33 = c*sb3*s2;
a12 = -r12c1 * (c1mag*c*s1 + c2mag*s12);
a13 = -rb1*rb3*s12;
a23 = r12c2 * (c2mag*c*s2 + c1mag*s12);
sx2 = a12*vb1x + a22*vb2x + a23*vb3x;
sy2 = a12*vb1y + a22*vb2y + a23*vb3y;
sz2 = a12*vb1z + a22*vb2z + a23*vb3z;
f1[0] = a11*vb1x + a12*vb2x + a13*vb3x;
f1[1] = a11*vb1y + a12*vb2y + a13*vb3y;
f1[2] = a11*vb1z + a12*vb2z + a13*vb3z;
f2[0] = -sx2 - f1[0];
f2[1] = -sy2 - f1[1];
f2[2] = -sz2 - f1[2];
f4[0] = a13*vb1x + a23*vb2x + a33*vb3x;
f4[1] = a13*vb1y + a23*vb2y + a33*vb3y;
f4[2] = a13*vb1z + a23*vb2z + a33*vb3z;
f3[0] = sx2 - f4[0];
f3[1] = sy2 - f4[1];
f3[2] = sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,edihedral,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void DihedralQuadratic::allocate()
{
allocated = 1;
int n = atom->ndihedraltypes;
memory->create(k,n+1,"dihedral:k");
memory->create(phi0,n+1,"dihedral:phi0");
memory->create(setflag,n+1,"dihedral:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void DihedralQuadratic::coeff(int narg, char **arg)
{
if (narg != 3) error->all(FLERR,"Incorrect args for dihedral coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->ndihedraltypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double phi0_one= force->numeric(FLERR,arg[2]);
// require k >= 0
if (k_one < 0.0)
error->all(FLERR,"Incorrect coefficient arg for dihedral coefficients");
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
phi0[i] = phi0_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for dihedral coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void DihedralQuadratic::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fwrite(&phi0[1],sizeof(double),atom->ndihedraltypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void DihedralQuadratic::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->ndihedraltypes,fp);
fread(&phi0[1],sizeof(int),atom->ndihedraltypes,fp);
}
MPI_Bcast(&k[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
MPI_Bcast(&phi0[1],atom->ndihedraltypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->ndihedraltypes; i++) setflag[i] = 1;
}
diff --git a/src/USER-MISC/fix_imd.cpp b/src/USER-MISC/fix_imd.cpp
index 971064fd1..81b733ee2 100644
--- a/src/USER-MISC/fix_imd.cpp
+++ b/src/USER-MISC/fix_imd.cpp
@@ -1,1479 +1,1483 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
The FixIMD class contains code from VMD and NAMD which is copyrighted
by the Board of Trustees of the University of Illinois and is free to
use with LAMMPS according to point 2 of the UIUC license (10% clause):
" Licensee may, at its own expense, create and freely distribute
complimentary works that interoperate with the Software, directing others to
the TCBG server to license and obtain the Software itself. Licensee may, at
its own expense, modify the Software to make derivative works. Except as
explicitly provided below, this License shall apply to any derivative work
as it does to the original Software distributed by Illinois. Any derivative
work should be clearly marked and renamed to notify users that it is a
modified version and not the original Software distributed by Illinois.
Licensee agrees to reproduce the copyright notice and other proprietary
markings on any derivative work and to include in the documentation of such
work the acknowledgement:
"This software includes code developed by the Theoretical and Computational
Biophysics Group in the Beckman Institute for Advanced Science and
Technology at the University of Illinois at Urbana-Champaign."
Licensee may redistribute without restriction works with up to 1/2 of their
non-comment source code derived from at most 1/10 of the non-comment source
code developed by Illinois and contained in the Software, provided that the
above directions for notice and acknowledgement are observed. Any other
distribution of the Software or any derivative work requires a separate
license with Illinois. Licensee may contact Illinois (vmd@ks.uiuc.edu) to
negotiate an appropriate license for such distribution."
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Axel Kohlmeyer (Temple U)
IMD API, hash, and socket code written by: John E. Stone,
Justin Gullingsrud, and James Phillips, (TCBG, Beckman Institute, UIUC)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include "fix_imd.h"
#include "atom.h"
#include "comm.h"
#include "update.h"
#include "respa.h"
#include "domain.h"
#include "force.h"
#include "error.h"
#include "group.h"
#include "memory.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/file.h>
#endif
#include <errno.h>
/* re-usable integer hash table code with static linkage. */
/** hash table top level data structure */
typedef struct inthash_t {
struct inthash_node_t **bucket; /* array of hash nodes */
int size; /* size of the array */
int entries; /* number of entries in table */
int downshift; /* shift cound, used in hash function */
int mask; /* used to select bits for hashing */
} inthash_t;
/** hash table node data structure */
typedef struct inthash_node_t {
int data; /* data in hash node */
int key; /* key for hash lookup */
struct inthash_node_t *next; /* next node in hash chain */
} inthash_node_t;
#define HASH_FAIL -1
#define HASH_LIMIT 0.5
/* initialize new hash table */
static void inthash_init(inthash_t *tptr, int buckets);
/* lookup entry in hash table */
static int inthash_lookup(const inthash_t *tptr, int key);
/* generate list of keys for reverse lookups. */
static int *inthash_keys(inthash_t *tptr);
/* insert an entry into hash table. */
static int inthash_insert(inthash_t *tptr, int key, int data);
/* delete the hash table */
static void inthash_destroy(inthash_t *tptr);
/* adapted sort for in-place sorting of map indices. */
static void id_sort(int *idmap, int left, int right);
/************************************************************************
* integer hash code:
************************************************************************/
/* inthash() - Hash function returns a hash number for a given key.
* tptr: Pointer to a hash table, key: The key to create a hash number for */
static int inthash(const inthash_t *tptr, int key) {
int hashvalue;
hashvalue = (((key*1103515249)>>tptr->downshift) & tptr->mask);
if (hashvalue < 0) {
hashvalue = 0;
}
return hashvalue;
}
/*
* rebuild_table_int() - Create new hash table when old one fills up.
*
* tptr: Pointer to a hash table
*/
static void rebuild_table_int(inthash_t *tptr) {
inthash_node_t **old_bucket, *old_hash, *tmp;
int old_size, h, i;
old_bucket=tptr->bucket;
old_size=tptr->size;
/* create a new table and rehash old buckets */
inthash_init(tptr, old_size<<1);
for (i=0; i<old_size; i++) {
old_hash=old_bucket[i];
while(old_hash) {
tmp=old_hash;
old_hash=old_hash->next;
h=inthash(tptr, tmp->key);
tmp->next=tptr->bucket[h];
tptr->bucket[h]=tmp;
tptr->entries++;
} /* while */
} /* for */
/* free memory used by old table */
free(old_bucket);
return;
}
/*
* inthash_init() - Initialize a new hash table.
*
* tptr: Pointer to the hash table to initialize
* buckets: The number of initial buckets to create
*/
void inthash_init(inthash_t *tptr, int buckets) {
/* make sure we allocate something */
if (buckets==0)
buckets=16;
/* initialize the table */
tptr->entries=0;
tptr->size=2;
tptr->mask=1;
tptr->downshift=29;
/* ensure buckets is a power of 2 */
while (tptr->size<buckets) {
tptr->size<<=1;
tptr->mask=(tptr->mask<<1)+1;
tptr->downshift--;
} /* while */
/* allocate memory for table */
tptr->bucket=(inthash_node_t **) calloc(tptr->size, sizeof(inthash_node_t *));
return;
}
/*
* inthash_lookup() - Lookup an entry in the hash table and return a pointer to
* it or HASH_FAIL if it wasn't found.
*
* tptr: Pointer to the hash table
* key: The key to lookup
*/
int inthash_lookup(const inthash_t *tptr, int key) {
int h;
inthash_node_t *node;
/* find the entry in the hash table */
h=inthash(tptr, key);
for (node=tptr->bucket[h]; node!=NULL; node=node->next) {
if (node->key == key)
break;
}
/* return the entry if it exists, or HASH_FAIL */
return(node ? node->data : HASH_FAIL);
}
/*
* inthash_keys() - Return a list of keys.
* NOTE: the returned list must be freed with free(3).
*/
int *inthash_keys(inthash_t *tptr) {
int *keys;
inthash_node_t *node;
keys = (int *)calloc(tptr->entries, sizeof(int));
for (int i=0; i < tptr->size; ++i) {
for (node=tptr->bucket[i]; node != NULL; node=node->next) {
keys[node->data] = node->key;
}
}
return keys;
}
/*
* inthash_insert() - Insert an entry into the hash table. If the entry already
* exists return a pointer to it, otherwise return HASH_FAIL.
*
* tptr: A pointer to the hash table
* key: The key to insert into the hash table
* data: A pointer to the data to insert into the hash table
*/
int inthash_insert(inthash_t *tptr, int key, int data) {
int tmp;
inthash_node_t *node;
int h;
/* check to see if the entry exists */
if ((tmp=inthash_lookup(tptr, key)) != HASH_FAIL)
return(tmp);
/* expand the table if needed */
while (tptr->entries>=HASH_LIMIT*tptr->size)
rebuild_table_int(tptr);
/* insert the new entry */
h=inthash(tptr, key);
node=(struct inthash_node_t *) malloc(sizeof(inthash_node_t));
node->data=data;
node->key=key;
node->next=tptr->bucket[h];
tptr->bucket[h]=node;
tptr->entries++;
return HASH_FAIL;
}
/*
* inthash_destroy() - Delete the entire table, and all remaining entries.
*
*/
void inthash_destroy(inthash_t *tptr) {
inthash_node_t *node, *last;
int i;
for (i=0; i<tptr->size; i++) {
node = tptr->bucket[i];
while (node != NULL) {
last = node;
node = node->next;
free(last);
}
}
/* free the entire array of buckets */
if (tptr->bucket != NULL) {
free(tptr->bucket);
memset(tptr, 0, sizeof(inthash_t));
}
}
/************************************************************************
* integer list sort code:
************************************************************************/
/* sort for integer map. initial call id_sort(idmap, 0, natoms - 1); */
static void id_sort(int *idmap, int left, int right)
{
int pivot, l_hold, r_hold;
l_hold = left;
r_hold = right;
pivot = idmap[left];
while (left < right) {
while ((idmap[right] >= pivot) && (left < right))
right--;
if (left != right) {
idmap[left] = idmap[right];
left++;
}
while ((idmap[left] <= pivot) && (left < right))
left++;
if (left != right) {
idmap[right] = idmap[left];
right--;
}
}
idmap[left] = pivot;
pivot = left;
left = l_hold;
right = r_hold;
if (left < pivot)
id_sort(idmap, left, pivot-1);
if (right > pivot)
id_sort(idmap, pivot+1, right);
}
/********** API definitions of the VMD/NAMD code ************************
* This code was taken and adapted from VMD-1.8.7/NAMD-2.7 in Sep 2009. *
* If there are any bugs or problems, please contact akohlmey@gmail.com *
************************************************************************/
/***************************************************************************
*cr
*cr (C) Copyright 1995-2009 The Board of Trustees of the
*cr University of Illinois
*cr All Rights Reserved
*cr
***************************************************************************/
/* part 1: Interactive MD (IMD) API */
#include <limits.h>
#if ( INT_MAX == 2147483647 )
typedef int int32;
#else
typedef short int32;
#endif
typedef struct {
int32 type;
int32 length;
} IMDheader;
#define IMDHEADERSIZE 8
#define IMDVERSION 2
typedef enum IMDType_t {
IMD_DISCONNECT, /**< close IMD connection, leaving sim running */
IMD_ENERGIES, /**< energy data block */
IMD_FCOORDS, /**< atom coordinates */
IMD_GO, /**< start the simulation */
IMD_HANDSHAKE, /**< endianism and version check message */
IMD_KILL, /**< kill the simulation job, shutdown IMD */
IMD_MDCOMM, /**< MDComm style force data */
IMD_PAUSE, /**< pause the running simulation */
IMD_TRATE, /**< set IMD update transmission rate */
IMD_IOERROR /**< indicate an I/O error */
} IMDType; /**< IMD command message type enumerations */
typedef struct {
int32 tstep; /**< integer timestep index */
float T; /**< Temperature in degrees Kelvin */
float Etot; /**< Total energy, in Kcal/mol */
float Epot; /**< Potential energy, in Kcal/mol */
float Evdw; /**< Van der Waals energy, in Kcal/mol */
float Eelec; /**< Electrostatic energy, in Kcal/mol */
float Ebond; /**< Bond energy, Kcal/mol */
float Eangle; /**< Angle energy, Kcal/mol */
float Edihe; /**< Dihedral energy, Kcal/mol */
float Eimpr; /**< Improper energy, Kcal/mol */
} IMDEnergies; /**< IMD simulation energy report structure */
/** Send control messages - these consist of a header with no subsequent data */
static int imd_handshake(void *); /**< check endianness, version compat */
/** Receive header and data */
static IMDType imd_recv_header(void *, int32 *);
/** Receive MDComm-style forces, units are Kcal/mol/angstrom */
static int imd_recv_mdcomm(void *, int32, int32 *, float *);
/** Receive energies */
static int imd_recv_energies(void *, IMDEnergies *);
/** Receive atom coordinates. */
static int imd_recv_fcoords(void *, int32, float *);
/** Prepare IMD data packet header */
static void imd_fill_header(IMDheader *header, IMDType type, int32 length);
/** Write data to socket */
static int32 imd_writen(void *s, const char *ptr, int32 n);
/* part 2: abstracts platform-dependent routines/APIs for using sockets */
typedef struct {
struct sockaddr_in addr; /* address of socket provided by bind() */
int addrlen; /* size of the addr struct */
int sd; /* socket file descriptor */
} imdsocket;
static int imdsock_init(void);
static void *imdsock_create(void);
static int imdsock_bind(void *, int);
static int imdsock_listen(void *);
static void *imdsock_accept(void *); /* return new socket */
static int imdsock_write(void *, const void *, int);
static int imdsock_read(void *, void *, int);
static int imdsock_selread(void *, int);
static int imdsock_selwrite(void *, int);
static void imdsock_shutdown(void *);
static void imdsock_destroy(void *);
/***************************************************************
* End of API definitions of the VMD/NAMD code. *
* The implementation follows at the end of the file. *
***************************************************************/
using namespace LAMMPS_NS;
using namespace FixConst;
/* struct for packed data communication of coordinates and forces. */
struct commdata {
int tag;
float x,y,z;
};
/***************************************************************
* create class and parse arguments in LAMMPS script. Syntax:
* fix ID group-ID imd <imd_trate> <imd_port> [unwrap (on|off)] [fscale <imd_fscale>]
***************************************************************/
FixIMD::FixIMD(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 4)
error->all(FLERR,"Illegal fix imd command");
imd_port = force->inumeric(FLERR,arg[3]);
if (imd_port < 1024)
error->all(FLERR,"Illegal fix imd parameter: port < 1024");
/* default values for optional flags */
unwrap_flag = 0;
nowait_flag = 0;
connect_msg = 1;
imd_fscale = 1.0;
imd_trate = 1;
/* parse optional arguments */
int argsdone = 4;
while (argsdone+1 < narg) {
if (0 == strcmp(arg[argsdone], "unwrap")) {
if (0 == strcmp(arg[argsdone+1], "on")) {
unwrap_flag = 1;
} else {
unwrap_flag = 0;
}
} else if (0 == strcmp(arg[argsdone], "nowait")) {
if (0 == strcmp(arg[argsdone+1], "on")) {
nowait_flag = 1;
} else {
nowait_flag = 0;
}
} else if (0 == strcmp(arg[argsdone], "fscale")) {
imd_fscale = force->numeric(FLERR,arg[argsdone+1]);
} else if (0 == strcmp(arg[argsdone], "trate")) {
imd_trate = force->inumeric(FLERR,arg[argsdone+1]);
} else {
error->all(FLERR,"Unknown fix imd parameter");
}
++argsdone; ++argsdone;
}
/* sanity check on parameters */
if (imd_trate < 1)
error->all(FLERR,"Illegal fix imd parameter. trate < 1.");
bigint n = group->count(igroup);
if (n > MAXSMALLINT) error->all(FLERR,"Too many atoms for fix imd");
num_coords = static_cast<int> (n);
MPI_Comm_rank(world,&me);
/* initialize various imd state variables. */
clientsock = NULL;
localsock = NULL;
nlevels_respa = 0;
imd_inactive = 0;
imd_terminate = 0;
imd_forces = 0;
force_buf = NULL;
maxbuf = 0;
msgdata = NULL;
msglen = 0;
comm_buf = NULL;
idmap = NULL;
rev_idmap = NULL;
if (me == 0) {
/* set up incoming socket on MPI rank 0. */
imdsock_init();
localsock = imdsock_create();
clientsock = NULL;
if (imdsock_bind(localsock,imd_port)) {
perror("bind to socket failed");
imdsock_destroy(localsock);
imd_terminate = 1;
} else {
imdsock_listen(localsock);
}
}
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS Terminated on error in IMD.");
/* storage required to communicate a single coordinate or force. */
size_one = sizeof(struct commdata);
#if defined(LAMMPS_ASYNC_IMD)
/* set up for i/o worker thread on MPI rank 0.*/
if (me == 0) {
if (screen)
fputs("Using fix imd with asynchronous I/O.\n",screen);
if (logfile)
fputs("Using fix imd with asynchronous I/O.\n",logfile);
/* set up mutex and condition variable for i/o thread */
/* hold mutex before creating i/o thread to keep it waiting. */
pthread_mutex_init(&read_mutex, NULL);
pthread_mutex_init(&write_mutex, NULL);
pthread_cond_init(&write_cond, NULL);
pthread_mutex_lock(&write_mutex);
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
/* set up and launch i/o thread */
pthread_attr_init(&iot_attr);
pthread_attr_setdetachstate(&iot_attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&iothread, &iot_attr, &fix_imd_ioworker, this);
}
#endif
}
/*********************************
* Clean up on deleting the fix. *
*********************************/
FixIMD::~FixIMD()
{
#if defined(LAMMPS_ASYNC_IMD)
if (me == 0) {
pthread_mutex_lock(&write_mutex);
buf_has_data=-1;
pthread_cond_signal(&write_cond);
pthread_mutex_unlock(&write_mutex);
pthread_join(iothread, NULL);
/* cleanup */
pthread_attr_destroy(&iot_attr);
pthread_mutex_destroy(&write_mutex);
pthread_cond_destroy(&write_cond);
}
#endif
inthash_t *hashtable = (inthash_t *)idmap;
memory->destroy(comm_buf);
memory->destroy(force_buf);
inthash_destroy(hashtable);
delete hashtable;
free(rev_idmap);
// close sockets
imdsock_shutdown(clientsock);
imdsock_destroy(clientsock);
imdsock_shutdown(localsock);
imdsock_destroy(localsock);
clientsock=NULL;
localsock=NULL;
return;
}
/* ---------------------------------------------------------------------- */
int FixIMD::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= POST_FORCE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixIMD::init()
{
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
return;
}
/* ---------------------------------------------------------------------- */
/* (re-)connect to an IMD client (e.g. VMD). return 1 if
new connection was made, 0 if not. */
int FixIMD::reconnect()
{
/* set up IMD communication, but only if needed. */
imd_inactive = 0;
imd_terminate = 0;
if (me == 0) {
if (clientsock) return 1;
if (screen && connect_msg) {
if (nowait_flag) {
fprintf(screen,"Listening for IMD connection on port %d. Transfer rate %d.\n",imd_port, imd_trate);
} else {
fprintf(screen,"Waiting for IMD connection on port %d. Transfer rate %d.\n",imd_port, imd_trate);
}
}
connect_msg = 0;
clientsock = NULL;
if (nowait_flag) {
int retval = imdsock_selread(localsock,0);
if (retval > 0) {
clientsock = imdsock_accept(localsock);
} else {
imd_inactive = 1;
return 0;
}
} else {
int retval=0;
do {
retval = imdsock_selread(localsock, 60);
} while (retval <= 0);
clientsock = imdsock_accept(localsock);
}
if (!imd_inactive && !clientsock) {
if (screen)
fprintf(screen, "IMD socket accept error. Dropping connection.\n");
imd_terminate = 1;
return 0;
} else {
/* check endianness and IMD protocol version. */
if (imd_handshake(clientsock)) {
if (screen)
fprintf(screen, "IMD handshake error. Dropping connection.\n");
imdsock_destroy(clientsock);
imd_terminate = 1;
return 0;
} else {
int32 length;
if (imdsock_selread(clientsock, 1) != 1 ||
imd_recv_header(clientsock, &length) != IMD_GO) {
if (screen)
fprintf(screen, "Incompatible IMD client version? Dropping connection.\n");
imdsock_destroy(clientsock);
imd_terminate = 1;
return 0;
} else {
return 1;
}
}
}
}
return 0;
}
/* ---------------------------------------------------------------------- */
/* wait for IMD client (e.g. VMD) to respond, initialize communication
* buffers and collect tag/id maps. */
void FixIMD::setup(int)
{
/* nme: number of atoms in group on this MPI task
* nmax: max number of atoms in group across all MPI tasks
* nlocal: all local atoms
*/
int i,j;
int nmax,nme,nlocal;
int *mask = atom->mask;
int *tag = atom->tag;
nlocal = atom->nlocal;
nme=0;
for (i=0; i < nlocal; ++i)
if (mask[i] & groupbit) ++nme;
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
memory->destroy(comm_buf);
maxbuf = nmax*size_one;
comm_buf = (void *) memory->smalloc(maxbuf,"imd:comm_buf");
connect_msg = 1;
reconnect();
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on error in setting up IMD connection.");
/* initialize and build hashtable. */
inthash_t *hashtable=new inthash_t;
inthash_init(hashtable, num_coords);
idmap = (void *)hashtable;
MPI_Status status;
MPI_Request request;
int tmp, ndata;
struct commdata *buf = static_cast<struct commdata *>(comm_buf);
if (me == 0) {
int *taglist = new int[num_coords];
int numtag=0; /* counter to map atom tags to a 0-based consecutive index list */
for (i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
taglist[numtag] = tag[i];
++numtag;
}
}
/* loop over procs to receive remote data */
for (i=1; i < comm->nprocs; ++i) {
MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request);
MPI_Send(&tmp, 0, MPI_INT, i, 0, world);
MPI_Wait(&request, &status);
MPI_Get_count(&status, MPI_BYTE, &ndata);
ndata /= size_one;
for (j=0; j < ndata; ++j) {
taglist[numtag] = buf[j].tag;
++numtag;
}
}
/* sort list of tags by value to have consistently the
* same list when running in parallel and build hash table. */
id_sort(taglist, 0, num_coords-1);
for (i=0; i < num_coords; ++i) {
inthash_insert(hashtable, taglist[i], i);
}
delete[] taglist;
/* generate reverse index-to-tag map for communicating
* IMD forces back to the proper atoms */
rev_idmap=inthash_keys(hashtable);
} else {
nme=0;
for (i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
buf[nme].tag = tag[i];
++nme;
}
}
/* blocking receive to wait until it is our turn to send data. */
MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status);
MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world);
}
return;
}
/* worker threads for asynchronous i/o */
#if defined(LAMMPS_ASYNC_IMD)
/* c bindings wrapper */
void *fix_imd_ioworker(void *t)
{
FixIMD *imd=(FixIMD *)t;
imd->ioworker();
return NULL;
}
/* the real i/o worker thread */
void FixIMD::ioworker()
{
while (1) {
pthread_mutex_lock(&write_mutex);
if (buf_has_data < 0) {
/* master told us to go away */
fprintf(screen,"Asynchronous I/O thread is exiting.\n");
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
pthread_exit(NULL);
} else if (buf_has_data > 0) {
/* send coordinate data, if client is able to accept */
if (clientsock && imdsock_selwrite(clientsock,0)) {
imd_writen(clientsock, msgdata, msglen);
}
delete[] msgdata;
buf_has_data=0;
pthread_mutex_unlock(&write_mutex);
} else {
/* nothing to write out yet. wait on condition. */
pthread_cond_wait(&write_cond, &write_mutex);
pthread_mutex_unlock(&write_mutex);
}
}
}
#endif
/* ---------------------------------------------------------------------- */
/* Main IMD protocol handler:
* Send coodinates, energies, and add IMD forces to atoms. */
void FixIMD::post_force(int vflag)
{
/* check for reconnect */
if (imd_inactive) {
reconnect();
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on error in setting up IMD connection.");
if (imd_inactive)
return; /* IMD client has detached and not yet come back. do nothing. */
}
int *tag = atom->tag;
double **x = atom->x;
imageint *image = atom->image;
int nlocal = atom->nlocal;
int *mask = atom->mask;
struct commdata *buf;
if (me == 0) {
/* process all pending incoming data. */
int imd_paused=0;
while ((imdsock_selread(clientsock, 0) > 0) || imd_paused) {
/* if something requested to turn off IMD while paused get out */
if (imd_inactive) break;
int32 length;
int msg = imd_recv_header(clientsock, &length);
switch(msg) {
case IMD_GO:
if (screen)
fprintf(screen, "Ignoring unexpected IMD_GO message.\n");
break;
case IMD_IOERROR:
if (screen)
fprintf(screen, "IMD connection lost.\n");
/* fallthrough */
case IMD_DISCONNECT: {
/* disconnect from client. wait for new connection. */
imd_paused = 0;
imd_forces = 0;
memory->destroy(force_buf);
force_buf = NULL;
imdsock_destroy(clientsock);
clientsock = NULL;
if (screen)
fprintf(screen, "IMD client detached. LAMMPS run continues.\n");
connect_msg = 1;
reconnect();
if (imd_terminate) imd_inactive = 1;
break;
}
case IMD_KILL:
/* stop the simulation job and shutdown IMD */
if (screen)
fprintf(screen, "IMD client requested termination of run.\n");
imd_inactive = 1;
imd_terminate = 1;
imd_paused = 0;
imdsock_destroy(clientsock);
clientsock = NULL;
break;
case IMD_PAUSE:
/* pause the running simulation. wait for second IMD_PAUSE to continue. */
if (imd_paused) {
if (screen)
fprintf(screen, "Continuing run on IMD client request.\n");
imd_paused = 0;
} else {
if (screen)
fprintf(screen, "Pausing run on IMD client request.\n");
imd_paused = 1;
}
break;
case IMD_TRATE:
/* change the IMD transmission data rate */
if (length > 0)
imd_trate = length;
if (screen)
fprintf(screen, "IMD client requested change of transfer rate. Now it is %d.\n", imd_trate);
break;
case IMD_ENERGIES: {
IMDEnergies dummy_energies;
imd_recv_energies(clientsock, &dummy_energies);
break;
}
case IMD_FCOORDS: {
float *dummy_coords = new float[3*length];
imd_recv_fcoords(clientsock, length, dummy_coords);
delete[] dummy_coords;
break;
}
case IMD_MDCOMM: {
int32 *imd_tags = new int32[length];
float *imd_fdat = new float[3*length];
imd_recv_mdcomm(clientsock, length, imd_tags, imd_fdat);
if (imd_forces < length) { /* grow holding space for forces, if needed. */
memory->destroy(force_buf);
force_buf = (void *) memory->smalloc(length*size_one,
"imd:force_buf");
}
imd_forces = length;
buf = static_cast<struct commdata *>(force_buf);
/* compare data to hash table */
for (int ii=0; ii < length; ++ii) {
buf[ii].tag = rev_idmap[imd_tags[ii]];
buf[ii].x = imd_fdat[3*ii];
buf[ii].y = imd_fdat[3*ii+1];
buf[ii].z = imd_fdat[3*ii+2];
}
delete[] imd_tags;
delete[] imd_fdat;
break;
}
default:
if (screen)
fprintf(screen, "Unhandled incoming IMD message #%d. length=%d\n", msg, length);
break;
}
}
}
/* update all tasks with current settings. */
int old_imd_forces = imd_forces;
MPI_Bcast(&imd_trate, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_inactive, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_forces, 1, MPI_INT, 0, world);
MPI_Bcast(&imd_terminate, 1, MPI_INT, 0, world);
if (imd_terminate)
error->all(FLERR,"LAMMPS terminated on IMD request.");
if (imd_forces > 0) {
/* check if we need to readjust the forces comm buffer on the receiving nodes. */
if (me != 0) {
if (old_imd_forces < imd_forces) { /* grow holding space for forces, if needed. */
if (force_buf != NULL)
memory->sfree(force_buf);
force_buf = memory->smalloc(imd_forces*size_one, "imd:force_buf");
}
}
MPI_Bcast(force_buf, imd_forces*size_one, MPI_BYTE, 0, world);
}
/* Check if we need to communicate coordinates to the client.
* Tuning imd_trate allows to keep the overhead for IMD low
* at the expense of a more jumpy display. Rather than using
* end_of_step() we do everything here in one go.
*
* If we don't communicate, only check if we have forces
* stored away and apply them. */
if (update->ntimestep % imd_trate) {
if (imd_forces > 0) {
double **f = atom->f;
buf = static_cast<struct commdata *>(force_buf);
/* XXX. this is in principle O(N**2) == not good.
* however we assume for now that the number of atoms
* that we manipulate via IMD will be small compared
* to the total system size, so we don't hurt too much. */
for (int j=0; j < imd_forces; ++j) {
for (int i=0; i < nlocal; ++i) {
if (mask[i] & groupbit) {
if (buf[j].tag == tag[i]) {
f[i][0] += imd_fscale*buf[j].x;
f[i][1] += imd_fscale*buf[j].y;
f[i][2] += imd_fscale*buf[j].z;
}
}
}
}
}
return;
}
/* check and potentially grow local communication buffers. */
int i, k, nmax, nme=0;
for (i=0; i < nlocal; ++i)
if (mask[i] & groupbit) ++nme;
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
if (nmax*size_one > maxbuf) {
memory->destroy(comm_buf);
maxbuf = nmax*size_one;
comm_buf = memory->smalloc(maxbuf,"imd:comm_buf");
}
MPI_Status status;
MPI_Request request;
int tmp, ndata;
buf = static_cast<struct commdata *>(comm_buf);
if (me == 0) {
/* collect data into new array. we bypass the IMD API to save
* us one extra copy of the data. */
msglen = 3*sizeof(float)*num_coords+IMDHEADERSIZE;
msgdata = new char[msglen];
imd_fill_header((IMDheader *)msgdata, IMD_FCOORDS, num_coords);
/* array pointer, to the offset where we receive the coordinates. */
float *recvcoord = (float *) (msgdata+IMDHEADERSIZE);
/* add local data */
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
const int j = 3*inthash_lookup((inthash_t *)idmap, tag[i]);
if (j != 3*HASH_FAIL) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
recvcoord[j] = x[i][0] + ix * xprd + iy * xy + iz * xz;
recvcoord[j+1] = x[i][1] + iy * yprd + iz * yz;
recvcoord[j+2] = x[i][2] + iz * zprd;
} else {
recvcoord[j] = x[i][0] + ix * xprd;
recvcoord[j+1] = x[i][1] + iy * yprd;
recvcoord[j+2] = x[i][2] + iz * zprd;
}
}
}
}
} else {
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
const int j = 3*inthash_lookup((inthash_t *)idmap, tag[i]);
if (j != 3*HASH_FAIL) {
recvcoord[j] = x[i][0];
recvcoord[j+1] = x[i][1];
recvcoord[j+2] = x[i][2];
}
}
}
}
/* loop over procs to receive remote data */
for (i=1; i < comm->nprocs; ++i) {
MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request);
MPI_Send(&tmp, 0, MPI_INT, i, 0, world);
MPI_Wait(&request, &status);
MPI_Get_count(&status, MPI_BYTE, &ndata);
ndata /= size_one;
for (k=0; k<ndata; ++k) {
const int j = 3*inthash_lookup((inthash_t *)idmap, buf[k].tag);
if (j != 3*HASH_FAIL) {
recvcoord[j] = buf[k].x;
recvcoord[j+1] = buf[k].y;
recvcoord[j+2] = buf[k].z;
}
}
}
/* done collecting frame data now communicate with IMD client. */
#if defined(LAMMPS_ASYNC_IMD)
/* wake up i/o worker thread and release lock on i/o buffer
* we can go back to our MD and let the i/o thread do the rest */
buf_has_data=1;
pthread_cond_signal(&write_cond);
pthread_mutex_unlock(&write_mutex);
#else
/* send coordinate data, if client is able to accept */
if (clientsock && imdsock_selwrite(clientsock,0)) {
imd_writen(clientsock, msgdata, msglen);
}
delete[] msgdata;
#endif
} else {
/* copy coordinate data into communication buffer */
nme = 0;
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0] + ix * xprd + iy * xy + iz * xz;
buf[nme].y = x[i][1] + iy * yprd + iz * yz;
buf[nme].z = x[i][2] + iz * zprd;
} else {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0] + ix * xprd;
buf[nme].y = x[i][1] + iy * yprd;
buf[nme].z = x[i][2] + iz * zprd;
}
++nme;
}
}
} else {
for (i=0; i<nlocal; ++i) {
if (mask[i] & groupbit) {
buf[nme].tag = tag[i];
buf[nme].x = x[i][0];
buf[nme].y = x[i][1];
buf[nme].z = x[i][2];
++nme;
}
}
}
/* blocking receive to wait until it is our turn to send data. */
MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status);
MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world);
}
return;
}
/* ---------------------------------------------------------------------- */
void FixIMD::post_force_respa(int vflag, int ilevel, int iloop)
{
/* only process IMD on the outmost RESPA level. */
if (ilevel == nlevels_respa-1) post_force(vflag);
return;
}
/* ---------------------------------------------------------------------- */
/* local memory usage. approximately. */
double FixIMD::memory_usage(void)
{
return static_cast<double>(num_coords+maxbuf+imd_forces)*size_one;
}
/* End of FixIMD class implementation. */
/***************************************************************************/
/* NOTE: the following code is the based on the example implementation
* of the IMD protocol API from VMD and NAMD. The UIUC license allows
* to re-use up to 10% of a project's code to be used in other software */
/***************************************************************************
* DESCRIPTION:
* Socket interface, abstracts machine dependent APIs/routines.
***************************************************************************/
int imdsock_init(void) {
#if defined(_MSC_VER) || defined(__MINGW32__)
int rc = 0;
static int initialized=0;
if (!initialized) {
WSADATA wsdata;
rc = WSAStartup(MAKEWORD(1,1), &wsdata);
if (rc == 0)
initialized = 1;
}
return rc;
#else
return 0;
#endif
}
void * imdsock_create(void) {
imdsocket * s;
s = (imdsocket *) malloc(sizeof(imdsocket));
if (s != NULL)
memset(s, 0, sizeof(imdsocket));
if ((s->sd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
printf("Failed to open socket.");
free(s);
return NULL;
}
return (void *) s;
}
int imdsock_bind(void * v, int port) {
imdsocket *s = (imdsocket *) v;
memset(&(s->addr), 0, sizeof(s->addr));
s->addr.sin_family = PF_INET;
s->addr.sin_port = htons(port);
return bind(s->sd, (struct sockaddr *) &s->addr, sizeof(s->addr));
}
int imdsock_listen(void * v) {
imdsocket *s = (imdsocket *) v;
return listen(s->sd, 5);
}
void *imdsock_accept(void * v) {
int rc;
imdsocket *new_s = NULL, *s = (imdsocket *) v;
#if defined(ARCH_AIX5) || defined(ARCH_AIX5_64) || defined(ARCH_AIX6_64)
unsigned int len;
#define _SOCKLEN_TYPE unsigned int
#elif defined(SOCKLEN_T)
SOCKLEN_T len;
#define _SOCKLEN_TYPE SOCKLEN_T
#elif defined(_POSIX_SOURCE) || (defined(__APPLE__) && defined(__MACH__)) || defined(__linux)
socklen_t len;
#define _SOCKLEN_TYPE socklen_t
#else
#define _SOCKLEN_TYPE int
int len;
#endif
len = sizeof(s->addr);
rc = accept(s->sd, (struct sockaddr *) &s->addr, ( _SOCKLEN_TYPE * ) &len);
if (rc >= 0) {
new_s = (imdsocket *) malloc(sizeof(imdsocket));
if (new_s != NULL) {
*new_s = *s;
new_s->sd = rc;
}
}
return (void *)new_s;
}
int imdsock_write(void * v, const void *buf, int len) {
imdsocket *s = (imdsocket *) v;
#if defined(_MSC_VER) || defined(__MINGW32__)
return send(s->sd, (const char*) buf, len, 0); /* windows lacks the write() call */
#else
return write(s->sd, buf, len);
#endif
}
int imdsock_read(void * v, void *buf, int len) {
imdsocket *s = (imdsocket *) v;
#if defined(_MSC_VER) || defined(__MINGW32__)
return recv(s->sd, (char*) buf, len, 0); /* windows lacks the read() call */
#else
return read(s->sd, buf, len);
#endif
}
void imdsock_shutdown(void *v) {
imdsocket * s = (imdsocket *) v;
if (s == NULL)
return;
#if defined(_MSC_VER) || defined(__MINGW32__)
shutdown(s->sd, SD_SEND);
#else
shutdown(s->sd, 1); /* complete sends and send FIN */
#endif
}
void imdsock_destroy(void * v) {
imdsocket * s = (imdsocket *) v;
if (s == NULL)
return;
#if defined(_MSC_VER) || defined(__MINGW32__)
closesocket(s->sd);
#else
close(s->sd);
#endif
free(s);
}
int imdsock_selread(void *v, int sec) {
imdsocket *s = (imdsocket *)v;
fd_set rfd;
struct timeval tv;
int rc;
if (v == NULL) return 0;
FD_ZERO(&rfd);
FD_SET(s->sd, &rfd);
memset((void *)&tv, 0, sizeof(struct timeval));
tv.tv_sec = sec;
do {
rc = select(s->sd+1, &rfd, NULL, NULL, &tv);
} while (rc < 0 && errno == EINTR);
return rc;
}
int imdsock_selwrite(void *v, int sec) {
imdsocket *s = (imdsocket *)v;
fd_set wfd;
struct timeval tv;
int rc;
if (v == NULL) return 0;
FD_ZERO(&wfd);
FD_SET(s->sd, &wfd);
memset((void *)&tv, 0, sizeof(struct timeval));
tv.tv_sec = sec;
do {
rc = select(s->sd + 1, NULL, &wfd, NULL, &tv);
} while (rc < 0 && errno == EINTR);
return rc;
}
/* end of socket code. */
/*************************************************************************/
/*************************************************************************/
/* start of imd API code. */
/* Only works with aligned 4-byte quantities, will cause a bus error */
/* on some platforms if used on unaligned data. */
void swap4_aligned(void *v, long ndata) {
int *data = (int *) v;
long i;
int *N;
for (i=0; i<ndata; i++) {
N = data + i;
*N=(((*N>>24)&0xff) | ((*N&0xff)<<24) |
((*N>>8)&0xff00) | ((*N&0xff00)<<8));
}
}
/** structure used to perform byte swapping operations */
typedef union {
int32 i;
struct {
unsigned int highest : 8;
unsigned int high : 8;
unsigned int low : 8;
unsigned int lowest : 8;
} b;
} netint;
static int32 imd_htonl(int32 h) {
netint n;
n.b.highest = h >> 24;
n.b.high = h >> 16;
n.b.low = h >> 8;
n.b.lowest = h;
return n.i;
}
static int32 imd_ntohl(int32 n) {
netint u;
u.i = n;
return (u.b.highest << 24 | u.b.high << 16 | u.b.low << 8 | u.b.lowest);
}
static void imd_fill_header(IMDheader *header, IMDType type, int32 length) {
header->type = imd_htonl((int32)type);
header->length = imd_htonl(length);
}
static void swap_header(IMDheader *header) {
header->type = imd_ntohl(header->type);
header->length= imd_ntohl(header->length);
}
static int32 imd_readn(void *s, char *ptr, int32 n) {
int32 nleft;
int32 nread;
nleft = n;
while (nleft > 0) {
if ((nread = imdsock_read(s, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0; /* and call read() again */
else
return -1;
} else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return n-nleft;
}
static int32 imd_writen(void *s, const char *ptr, int32 n) {
int32 nleft;
int32 nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = imdsock_write(s, ptr, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
int imd_disconnect(void *s) {
IMDheader header;
imd_fill_header(&header, IMD_DISCONNECT, 0);
return (imd_writen(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE);
}
int imd_handshake(void *s) {
IMDheader header;
imd_fill_header(&header, IMD_HANDSHAKE, 1);
header.length = IMDVERSION; /* Not byteswapped! */
return (imd_writen(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE);
}
/* The IMD receive functions */
IMDType imd_recv_header(void *s, int32 *length) {
IMDheader header;
if (imd_readn(s, (char *)&header, IMDHEADERSIZE) != IMDHEADERSIZE)
return IMD_IOERROR;
swap_header(&header);
*length = header.length;
return IMDType(header.type);
}
int imd_recv_mdcomm(void *s, int32 n, int32 *indices, float *forces) {
if (imd_readn(s, (char *)indices, 4*n) != 4*n) return 1;
if (imd_readn(s, (char *)forces, 12*n) != 12*n) return 1;
return 0;
}
int imd_recv_energies(void *s, IMDEnergies *energies) {
return (imd_readn(s, (char *)energies, sizeof(IMDEnergies))
!= sizeof(IMDEnergies));
}
int imd_recv_fcoords(void *s, int32 n, float *coords) {
return (imd_readn(s, (char *)coords, 12*n) != 12*n);
}
// Local Variables:
// mode: c++
// compile-command: "make -j4 openmpi"
// c-basic-offset: 2
// fill-column: 76
// indent-tabs-mode: nil
// End:
diff --git a/src/USER-MISC/improper_cossq.cpp b/src/USER-MISC/improper_cossq.cpp
index 8bd867fd8..e286277b6 100644
--- a/src/USER-MISC/improper_cossq.cpp
+++ b/src/USER-MISC/improper_cossq.cpp
@@ -1,313 +1,315 @@
/* ----------------------------------------------------------------------
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: Georgios G. Vogiatzis (CoMSE, NTU Athens),
gvog@chemeng.ntua.gr
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "improper_cossq.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
#include "math_const.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperCossq::ImproperCossq(LAMMPS *lmp) : Improper(lmp) {}
/* ---------------------------------------------------------------------- */
ImproperCossq::~ImproperCossq()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(chi);
}
}
/* ---------------------------------------------------------------------- */
void ImproperCossq::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z ;
double eimproper,f1[3],f2[3],f3[3],f4[3];
double rjisq, rji, rlksq, rlk, cosphi, angfac;
double cjiji, clkji, clklk, cfact1, cfact2, cfact3;
eimproper = 0.0;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
double **f = atom->f;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
for (n = 0; n < nimproperlist; n++) {
/* Ask the improper list for the atom types. */
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
/* separation vector between i1 and i2, (i2-i1) */
vb1x = x[i2][0] - x[i1][0];
vb1y = x[i2][1] - x[i1][1];
vb1z = x[i2][2] - x[i1][2];
rjisq = vb1x*vb1x + vb1y*vb1y + vb1z*vb1z ;
rji = sqrt(rjisq);
/* separation vector between i2 and i3 (i3-i2) */
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
/* separation vector between i3 and i4, (i4-i3) */
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
rlksq = vb3x*vb3x + vb3y*vb3y + vb3z*vb3z ;
rlk = sqrt(rlksq);
cosphi = (vb3x*vb1x + vb3y*vb1y + vb3z*vb1z)/(rji * rlk);
/* Check that cos(phi) is in the correct limits. */
if (cosphi > 1.0 + TOLERANCE || cosphi < (-1.0 - TOLERANCE))
{
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
- me,update->ntimestep,atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
+ me,update->ntimestep,
+ atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",me,x[i4][0],x[i4][1],x[i4][2]);
}
}
-
/* Apply corrections to round-off errors. */
if (cosphi > 1.0) cosphi -= SMALL;
if (cosphi < -1.0) cosphi += SMALL;
/* Calculate the angle: */
double torangle = acos(cosphi);
cosphi = cos(torangle - chi[type]);
if (eflag) eimproper = 0.5 * k[type] * cosphi * cosphi;
/*
printf("The tags: %d-%d-%d-%d, of type %d .\n",atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4],type);
printf("The ji vector: %f, %f, %f.\nThe lk vector: %f, %f, %f.\n", vb1x,vb1y,vb1z,vb3x,vb3y,vb3z);
printf("The cosine of the angle: %-1.16e.\n", cosphi);
printf("The energy of the improper: %-1.16e with prefactor %-1.16e.\n", eimproper, 0.5*k[type]);
*/
/* Work out forces. */
angfac = - k[type] * cosphi;
cjiji = rjisq;
clklk = rlksq;
/*CLKJI = RXLK * RXJI + RYLK * RYJI + RZLK * RZJI */
clkji = vb3x*vb1x + vb3y*vb1y + vb3z*vb1z;
/*CFACT1 = CLKLK * CJIJI
CFACT1 = SQRT(CFACT1)
CFACT1 = ANGFAC / CFACT1*/
cfact1 = angfac / sqrt(clklk * cjiji);
/*CFACT2 = CLKJI / CLKLK*/
cfact2 = clkji / clklk;
/*CFACT3 = CLKJI / CJIJI*/
cfact3 = clkji / cjiji;
/*FIX = -RXLK + CFACT3 * RXJI
FIY = -RYLK + CFACT3 * RYJI
FIZ = -RZLK + CFACT3 * RZJI*/
f1[0] = - vb3x + cfact3 * vb1x;
f1[1] = - vb3y + cfact3 * vb1y;
f1[2] = - vb3z + cfact3 * vb1z;
/*FJX = -FIX
FJY = -FIY
FJZ = -FIZ*/
f2[0] = - f1[0];
f2[1] = - f1[1];
f2[2] = - f1[2];
/*FKX = CFACT2 * RXLK - RXJI
FKY = CFACT2 * RYLK - RYJI
FKZ = CFACT2 * RZLK - RZJI*/
f3[0] = cfact2 * vb3x - vb1x;
f3[1] = cfact2 * vb3y - vb1y;
f3[2] = cfact2 * vb3z - vb1z;
/*FLX = -FKX
FLY = -FKY
FLZ = -FKZ*/
f4[0] = - f3[0];
f4[1] = - f3[1];
f4[2] = - f3[2];
/*FIX = FIX * CFACT1
FIY = FIY * CFACT1
FIZ = FIZ * CFACT1*/
f1[0] *= cfact1;
f1[1] *= cfact1;
f1[2] *= cfact1;
/*FJX = FJX * CFACT1
FJY = FJY * CFACT1
FJZ = FJZ * CFACT1*/
f2[0] *= cfact1;
f2[1] *= cfact1;
f2[2] *= cfact1;
/*FKX = FKX * CFACT1
FKY = FKY * CFACT1
FKZ = FKZ * CFACT1*/
f3[0] *= cfact1;
f3[1] *= cfact1;
f3[2] *= cfact1;
/*FLX = FLX * CFACT1
FLY = FLY * CFACT1
FLZ = FLZ * CFACT1*/
f4[0] *= cfact1;
f4[1] *= cfact1;
f4[2] *= cfact1;
/* Apply force to each of 4 atoms */
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4,
-vb1x,-vb1y,-vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
}
/* ---------------------------------------------------------------------- */
void ImproperCossq::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k,n+1,"improper:k");
memory->create(chi,n+1,"improper:chi");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperCossq::coeff(int narg, char **arg)
{
/* Check whether there exist sufficient number of arguments.
0: type of improper to be applied to
1: energetic constant
2: equilibrium angle in degrees */
if (narg != 3) error->all(FLERR,"Incorrect args for cossq improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double chi_one = force->numeric(FLERR,arg[2]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
chi[i] = ((chi_one * MY_PI)/180.0);
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperCossq::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&chi[1],sizeof(double),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperCossq::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nimpropertypes,fp);
fread(&chi[1],sizeof(double),atom->nimpropertypes,fp);
}
MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&chi[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
diff --git a/src/USER-MISC/improper_fourier.cpp b/src/USER-MISC/improper_fourier.cpp
index 43944727f..a4be0ea35 100644
--- a/src/USER-MISC/improper_fourier.cpp
+++ b/src/USER-MISC/improper_fourier.cpp
@@ -1,345 +1,346 @@
/* ----------------------------------------------------------------------
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: Loukas D. Peristeras (Scienomics SARL)
[ based on improper_umbrella.cpp Tod A Pascal (Caltech) ]
------------------------------------------------------------------------- */
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "improper_fourier.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "force.h"
#include "update.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define TOLERANCE 0.05
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ImproperFourier::ImproperFourier(LAMMPS *lmp) : Improper(lmp) {}
/* ---------------------------------------------------------------------- */
ImproperFourier::~ImproperFourier()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(k);
memory->destroy(C0);
memory->destroy(C1);
memory->destroy(C2);
}
}
/* ---------------------------------------------------------------------- */
void ImproperFourier::compute(int eflag, int vflag)
{
int i1,i2,i3,i4,n,type;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z;
if (eflag || vflag) ev_setup(eflag,vflag);
else evflag = 0;
double **x = atom->x;
int **improperlist = neighbor->improperlist;
int nimproperlist = neighbor->nimproperlist;
for (n = 0; n < nimproperlist; n++) {
i1 = improperlist[n][0];
i2 = improperlist[n][1];
i3 = improperlist[n][2];
i4 = improperlist[n][3];
type = improperlist[n][4];
// 1st bond
vb1x = x[i2][0] - x[i1][0];
vb1y = x[i2][1] - x[i1][1];
vb1z = x[i2][2] - x[i1][2];
// 2nd bond
vb2x = x[i3][0] - x[i1][0];
vb2y = x[i3][1] - x[i1][1];
vb2z = x[i3][2] - x[i1][2];
// 3rd bond
vb3x = x[i4][0] - x[i1][0];
vb3y = x[i4][1] - x[i1][1];
vb3z = x[i4][2] - x[i1][2];
addone(i1,i2,i3,i4, type,evflag,eflag,
vb1x, vb1y, vb1z,
vb2x, vb2y, vb2z,
vb3x, vb3y, vb3z);
if ( all[type] ) {
addone(i1,i4,i2,i3, type,evflag,eflag,
vb3x, vb3y, vb3z,
vb1x, vb1y, vb1z,
vb2x, vb2y, vb2z);
addone(i1,i3,i4,i2, type,evflag,eflag,
vb2x, vb2y, vb2z,
vb3x, vb3y, vb3z,
vb1x, vb1y, vb1z);
}
}
}
void ImproperFourier::addone(const int &i1,const int &i2,const int &i3,const int &i4,
const int &type,const int &evflag,const int &eflag,
const double &vb1x, const double &vb1y, const double &vb1z,
const double &vb2x, const double &vb2y, const double &vb2z,
const double &vb3x, const double &vb3y, const double &vb3z)
{
int n;
double eimproper,f1[3],f2[3],f3[3],f4[3];
double domega,c,c2,a,s,projhfg,dhax,dhay,dhaz,dahx,dahy,dahz,cotphi;
double ax,ay,az,ra2,rh2,ra,rh,rar,rhr,arx,ary,arz,hrx,hry,hrz;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
eimproper = 0.0;
// c0 calculation
// A = vb1 X vb2 is perpendicular to IJK plane
ax = vb1y*vb2z-vb1z*vb2y;
ay = vb1z*vb2x-vb1x*vb2z;
az = vb1x*vb2y-vb1y*vb2x;
ra2 = ax*ax+ay*ay+az*az;
rh2 = vb3x*vb3x+vb3y*vb3y+vb3z*vb3z;
ra = sqrt(ra2);
rh = sqrt(rh2);
if (ra < SMALL) ra = SMALL;
if (rh < SMALL) rh = SMALL;
rar = 1/ra;
rhr = 1/rh;
arx = ax*rar;
ary = ay*rar;
arz = az*rar;
hrx = vb3x*rhr;
hry = vb3y*rhr;
hrz = vb3z*rhr;
c = arx*hrx+ary*hry+arz*hrz;
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,
- "Improper problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Improper problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str,0);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) s = 1.0;
if (c < -1.0) s = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
cotphi = c/s;
projhfg = (vb3x*vb1x+vb3y*vb1y+vb3z*vb1z) /
sqrt(vb1x*vb1x+vb1y*vb1y+vb1z*vb1z);
projhfg += (vb3x*vb2x+vb3y*vb2y+vb3z*vb2z) /
sqrt(vb2x*vb2x+vb2y*vb2y+vb2z*vb2z);
if (projhfg > 0.0) {
s *= -1.0;
cotphi *= -1.0;
}
// force and energy
// E = k ( C0 + C1 cos(w) + C2 cos(w)
c2 = 2.0*s*s-1.0;
if (eflag) eimproper = k[type]*(C0[type]+C1[type]*s+C2[type]*c2);
// dhax = diffrence between H and A in X direction, etc
a = k[type]*(C1[type]+4.0*C2[type]*s)*cotphi;
dhax = hrx-c*arx;
dhay = hry-c*ary;
dhaz = hrz-c*arz;
dahx = arx-c*hrx;
dahy = ary-c*hry;
dahz = arz-c*hrz;
f2[0] = (dhay*vb1z - dhaz*vb1y)*rar;
f2[1] = (dhaz*vb1x - dhax*vb1z)*rar;
f2[2] = (dhax*vb1y - dhay*vb1x)*rar;
f3[0] = (-dhay*vb2z + dhaz*vb2y)*rar;
f3[1] = (-dhaz*vb2x + dhax*vb2z)*rar;
f3[2] = (-dhax*vb2y + dhay*vb2x)*rar;
f4[0] = dahx*rhr;
f4[1] = dahy*rhr;
f4[2] = dahz*rhr;
f1[0] = -(f2[0] + f3[0] + f4[0]);
f1[1] = -(f2[1] + f3[1] + f4[1]);
f1[2] = -(f2[2] + f3[2] + f4[2]);
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0]*a;
f[i1][1] += f1[1]*a;
f[i1][2] += f1[2]*a;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f3[0]*a;
f[i2][1] += f3[1]*a;
f[i2][2] += f3[2]*a;
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f2[0]*a;
f[i3][1] += f2[1]*a;
f[i3][2] += f2[2]*a;
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0]*a;
f[i4][1] += f4[1]*a;
f[i4][2] += f4[2]*a;
}
if (evflag)
ev_tally(i1,i2,i3,i4,nlocal,newton_bond,eimproper,f1,f3,f4,
vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z);
}
/* ---------------------------------------------------------------------- */
void ImproperFourier::allocate()
{
allocated = 1;
int n = atom->nimpropertypes;
memory->create(k,n+1,"improper:k");
memory->create(C0,n+1,"improper:C0");
memory->create(C1,n+1,"improper:C1");
memory->create(C2,n+1,"improper:C2");
memory->create(all,n+1,"improper:C2");
memory->create(setflag,n+1,"improper:setflag");
for (int i = 1; i <= n; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void ImproperFourier::coeff(int narg, char **arg)
{
if ( narg != 5 && narg != 6 ) error->all(FLERR,"Incorrect args for improper coefficients");
if (!allocated) allocate();
int ilo,ihi;
force->bounds(arg[0],atom->nimpropertypes,ilo,ihi);
double k_one = force->numeric(FLERR,arg[1]);
double C0_one = force->numeric(FLERR,arg[2]);
double C1_one = force->numeric(FLERR,arg[3]);
double C2_one = force->numeric(FLERR,arg[4]);
int all_one = 1;
if ( narg == 6 ) all_one = force->inumeric(FLERR,arg[5]);
// convert w0 from degrees to radians
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k[i] = k_one;
C0[i] = C0_one;
C1[i] = C1_one;
C2[i] = C2_one;
all[i] = all_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR,"Incorrect args for improper coefficients");
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void ImproperFourier::write_restart(FILE *fp)
{
fwrite(&k[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&C0[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&C1[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&C2[1],sizeof(double),atom->nimpropertypes,fp);
fwrite(&all[1],sizeof(int),atom->nimpropertypes,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void ImproperFourier::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
fread(&k[1],sizeof(double),atom->nimpropertypes,fp);
fread(&C0[1],sizeof(double),atom->nimpropertypes,fp);
fread(&C1[1],sizeof(double),atom->nimpropertypes,fp);
fread(&C2[1],sizeof(double),atom->nimpropertypes,fp);
fread(&all[1],sizeof(int),atom->nimpropertypes,fp);
}
MPI_Bcast(&k[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&C0[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&C1[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&C2[1],atom->nimpropertypes,MPI_DOUBLE,0,world);
MPI_Bcast(&all[1],atom->nimpropertypes,MPI_INT,0,world);
for (int i = 1; i <= atom->nimpropertypes; i++) setflag[i] = 1;
}
diff --git a/src/USER-MISC/pair_edip.cpp b/src/USER-MISC/pair_edip.cpp
index a9938f409..4c236649a 100644
--- a/src/USER-MISC/pair_edip.cpp
+++ b/src/USER-MISC/pair_edip.cpp
@@ -1,1064 +1,1062 @@
/* ----------------------------------------------------------------------
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: Luca Ferraro (CASPUR)
email: luca.ferraro@caspur.it
Environment Dependent Interatomic Potential
References:
1) J. F. Justo, M. Z. Bazant, E. Kaxiras, V. V. Bulatov, S. Yip
Phys. Rev. B 58, 2539 (1998)
------------------------------------------------------------------------- */
#include "math.h"
#include "float.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_edip.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
#define DELTA 4
#define GRIDDENSITY 8000
#define GRIDSTART 0.1
// max number of interaction per atom for f(Z) environment potential
#define leadDimInteractionList 64
/* ---------------------------------------------------------------------- */
PairEDIP::PairEDIP(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
restartinfo = 0;
one_coeff = 1;
manybody_flag = 1;
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairEDIP::~PairEDIP()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
deallocateGrids();
deallocatePreLoops();
}
}
/* ---------------------------------------------------------------------- */
void PairEDIP::compute(int eflag, int vflag)
{
int i,j,k,ii,inum,jnum;
int itype,jtype,ktype,ijparam,ikparam,ijkparam;
double xtmp,ytmp,ztmp,evdwl;
int *ilist,*jlist,*numneigh,**firstneigh;
register int preForceCoord_counter;
double invR_ij;
double invR_ik;
double directorCos_ij_x;
double directorCos_ij_y;
double directorCos_ij_z;
double directorCos_ik_x;
double directorCos_ik_y;
double directorCos_ik_z;
double cosTeta;
int interpolIDX;
double interpolTMP;
double interpolDeltaX;
double interpolY1;
double interpolY2;
double invRMinusCutoffA;
double sigmaInvRMinusCutoffA;
double gammInvRMinusCutoffA;
double cosTetaDiff;
double cosTetaDiffCosTetaDiff;
double cutoffFunction_ij;
double exp2B_ij;
double exp2BDerived_ij;
double pow2B_ij;
double pow2BDerived_ij;
double exp3B_ij;
double exp3BDerived_ij;
double exp3B_ik;
double exp3BDerived_ik;
double qFunction;
double qFunctionDerived;
double tauFunction;
double tauFunctionDerived;
double expMinusBetaZeta_iZeta_i;
double qFunctionCosTetaDiffCosTetaDiff;
double expMinusQFunctionCosTetaDiffCosTetaDiff;
double zeta_i;
double zeta_iDerived;
double zeta_iDerivedInvR_ij;
double forceModCoord_factor;
double forceModCoord;
double forceModCoord_ij;
double forceMod2B;
double forceMod3B_factor1_ij;
double forceMod3B_factor2_ij;
double forceMod3B_factor2;
double forceMod3B_factor1_ik;
double forceMod3B_factor2_ik;
double potentia3B_factor;
double potential2B_factor;
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 full neighbor list of my atoms
for (ii = 0; ii < inum; ii++) {
zeta_i = 0.0;
int numForceCoordPairs = 0;
i = ilist[ii];
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
jlist = firstneigh[i];
jnum = numneigh[i];
// pre-loop to compute environment coordination f(Z)
for (int neighbor_j = 0; neighbor_j < jnum; neighbor_j++) {
j = jlist[neighbor_j];
j &= NEIGHMASK;
double dr_ij[3], r_ij;
dr_ij[0] = xtmp - x[j][0];
dr_ij[1] = ytmp - x[j][1];
dr_ij[2] = ztmp - x[j][2];
r_ij = dr_ij[0]*dr_ij[0] + dr_ij[1]*dr_ij[1] + dr_ij[2]*dr_ij[2];
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
if (r_ij > params[ijparam].cutsq) continue;
r_ij = sqrt(r_ij);
invR_ij = 1.0 / r_ij;
preInvR_ij[neighbor_j] = invR_ij;
invRMinusCutoffA = 1.0 / (r_ij - cutoffA);
sigmaInvRMinusCutoffA = sigma * invRMinusCutoffA;
gammInvRMinusCutoffA = gamm * invRMinusCutoffA;
interpolDeltaX = r_ij - GRIDSTART;
interpolTMP = (interpolDeltaX * GRIDDENSITY);
interpolIDX = (int) interpolTMP;
interpolY1 = exp3B[interpolIDX];
interpolY2 = exp3B[interpolIDX+1];
exp3B_ij = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
exp3BDerived_ij = - exp3B_ij * gammInvRMinusCutoffA * invRMinusCutoffA;
preExp3B_ij[neighbor_j] = exp3B_ij;
preExp3BDerived_ij[neighbor_j] = exp3BDerived_ij;
interpolY1 = exp2B[interpolIDX];
interpolY2 = exp2B[interpolIDX+1];
exp2B_ij = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
exp2BDerived_ij = - exp2B_ij * sigmaInvRMinusCutoffA * invRMinusCutoffA;
preExp2B_ij[neighbor_j] = exp2B_ij;
preExp2BDerived_ij[neighbor_j] = exp2BDerived_ij;
interpolY1 = pow2B[interpolIDX];
interpolY2 = pow2B[interpolIDX+1];
pow2B_ij = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
prePow2B_ij[neighbor_j] = pow2B_ij;
// zeta and its derivative
if (r_ij < cutoffC) zeta_i += 1.0;
else {
interpolY1 = cutoffFunction[interpolIDX];
interpolY2 = cutoffFunction[interpolIDX+1];
cutoffFunction_ij = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
zeta_i += cutoffFunction_ij;
interpolY1 = cutoffFunctionDerived[interpolIDX];
interpolY2 = cutoffFunctionDerived[interpolIDX+1];
zeta_iDerived = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
zeta_iDerivedInvR_ij = zeta_iDerived * invR_ij;
preForceCoord_counter=numForceCoordPairs*5;
preForceCoord[preForceCoord_counter+0]=zeta_iDerivedInvR_ij;
preForceCoord[preForceCoord_counter+1]=dr_ij[0];
preForceCoord[preForceCoord_counter+2]=dr_ij[1];
preForceCoord[preForceCoord_counter+3]=dr_ij[2];
preForceCoord[preForceCoord_counter+4]=j;
numForceCoordPairs++;
}
}
// quantities depending on zeta_i
interpolDeltaX = zeta_i;
interpolTMP = (interpolDeltaX * GRIDDENSITY);
interpolIDX = (int) interpolTMP;
interpolY1 = expMinusBetaZeta_iZeta_iGrid[interpolIDX];
interpolY2 = expMinusBetaZeta_iZeta_iGrid[interpolIDX+1];
expMinusBetaZeta_iZeta_i = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
interpolY1 = qFunctionGrid[interpolIDX];
interpolY2 = qFunctionGrid[interpolIDX+1];
qFunction = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
interpolY1 = tauFunctionGrid[interpolIDX];
interpolY2 = tauFunctionGrid[interpolIDX+1];
tauFunction = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
interpolY1 = tauFunctionDerivedGrid[interpolIDX];
interpolY2 = tauFunctionDerivedGrid[interpolIDX+1];
tauFunctionDerived = interpolY1 + (interpolY2 - interpolY1) *
(interpolTMP-interpolIDX);
qFunctionDerived = -mu * qFunction;
forceModCoord_factor = 2.0 * beta * zeta_i * expMinusBetaZeta_iZeta_i;
forceModCoord = 0.0;
// two-body interactions, skip half of them
for (int neighbor_j = 0; neighbor_j < jnum; neighbor_j++) {
double dr_ij[3], r_ij, f_ij[3];
j = jlist[neighbor_j];
j &= NEIGHMASK;
dr_ij[0] = x[j][0] - xtmp;
dr_ij[1] = x[j][1] - ytmp;
dr_ij[2] = x[j][2] - ztmp;
r_ij = dr_ij[0]*dr_ij[0] + dr_ij[1]*dr_ij[1] + dr_ij[2]*dr_ij[2];
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
if (r_ij > params[ijparam].cutsq) continue;
r_ij = sqrt(r_ij);
invR_ij = preInvR_ij[neighbor_j];
pow2B_ij = prePow2B_ij[neighbor_j];
potential2B_factor = pow2B_ij - expMinusBetaZeta_iZeta_i;
exp2B_ij = preExp2B_ij[neighbor_j];
pow2BDerived_ij = - rho * invR_ij * pow2B_ij;
forceModCoord += (forceModCoord_factor*exp2B_ij);
exp2BDerived_ij = preExp2BDerived_ij[neighbor_j];
forceMod2B = exp2BDerived_ij * potential2B_factor +
exp2B_ij * pow2BDerived_ij;
directorCos_ij_x = invR_ij * dr_ij[0];
directorCos_ij_y = invR_ij * dr_ij[1];
directorCos_ij_z = invR_ij * dr_ij[2];
exp3B_ij = preExp3B_ij[neighbor_j];
exp3BDerived_ij = preExp3BDerived_ij[neighbor_j];
f_ij[0] = forceMod2B * directorCos_ij_x;
f_ij[1] = forceMod2B * directorCos_ij_y;
f_ij[2] = forceMod2B * directorCos_ij_z;
f[i][0] += f_ij[0];
f[i][1] += f_ij[1];
f[i][2] += f_ij[2];
f[j][0] -= f_ij[0];
f[j][1] -= f_ij[1];
f[j][2] -= f_ij[2];
// potential energy
evdwl = (exp2B_ij * potential2B_factor);
if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0,
-forceMod2B*invR_ij, dr_ij[0], dr_ij[1], dr_ij[2]);
// three-body Forces
for (int neighbor_k = neighbor_j + 1; neighbor_k < jnum; neighbor_k++) {
double dr_ik[3], r_ik, f_ik[3];
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = x[k][0] - xtmp;
dr_ik[1] = x[k][1] - ytmp;
dr_ik[2] = x[k][2] - ztmp;
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = preInvR_ij[neighbor_k];
directorCos_ik_x = invR_ik * dr_ik[0];
directorCos_ik_y = invR_ik * dr_ik[1];
directorCos_ik_z = invR_ik * dr_ik[2];
cosTeta = directorCos_ij_x * directorCos_ik_x +
directorCos_ij_y * directorCos_ik_y +
directorCos_ij_z * directorCos_ik_z;
cosTetaDiff = cosTeta + tauFunction;
cosTetaDiffCosTetaDiff = cosTetaDiff * cosTetaDiff;
qFunctionCosTetaDiffCosTetaDiff = cosTetaDiffCosTetaDiff * qFunction;
expMinusQFunctionCosTetaDiffCosTetaDiff =
exp(-qFunctionCosTetaDiffCosTetaDiff);
potentia3B_factor = lambda *
((1.0 - expMinusQFunctionCosTetaDiffCosTetaDiff) +
eta * qFunctionCosTetaDiffCosTetaDiff);
exp3B_ik = preExp3B_ij[neighbor_k];
exp3BDerived_ik = preExp3BDerived_ij[neighbor_k];
forceMod3B_factor1_ij = - exp3BDerived_ij * exp3B_ik *
potentia3B_factor;
forceMod3B_factor2 = 2.0 * lambda * exp3B_ij * exp3B_ik *
qFunction * cosTetaDiff *
(eta + expMinusQFunctionCosTetaDiffCosTetaDiff);
forceMod3B_factor2_ij = forceMod3B_factor2 * invR_ij;
f_ij[0] = forceMod3B_factor1_ij * directorCos_ij_x +
forceMod3B_factor2_ij *
(cosTeta * directorCos_ij_x - directorCos_ik_x);
f_ij[1] = forceMod3B_factor1_ij * directorCos_ij_y +
forceMod3B_factor2_ij *
(cosTeta * directorCos_ij_y - directorCos_ik_y);
f_ij[2] = forceMod3B_factor1_ij * directorCos_ij_z +
forceMod3B_factor2_ij *
(cosTeta * directorCos_ij_z - directorCos_ik_z);
forceMod3B_factor1_ik = - exp3BDerived_ik * exp3B_ij *
potentia3B_factor;
forceMod3B_factor2_ik = forceMod3B_factor2 * invR_ik;
f_ik[0] = forceMod3B_factor1_ik * directorCos_ik_x +
forceMod3B_factor2_ik *
(cosTeta * directorCos_ik_x - directorCos_ij_x);
f_ik[1] = forceMod3B_factor1_ik * directorCos_ik_y +
forceMod3B_factor2_ik *
(cosTeta * directorCos_ik_y - directorCos_ij_y);
f_ik[2] = forceMod3B_factor1_ik * directorCos_ik_z +
forceMod3B_factor2_ik *
(cosTeta * directorCos_ik_z - directorCos_ij_z);
forceModCoord += (forceMod3B_factor2 *
(tauFunctionDerived - 0.5 * mu * cosTetaDiff));
f[j][0] += f_ij[0];
f[j][1] += f_ij[1];
f[j][2] += f_ij[2];
f[k][0] += f_ik[0];
f[k][1] += f_ik[1];
f[k][2] += f_ik[2];
f[i][0] -= f_ij[0] + f_ik[0];
f[i][1] -= f_ij[1] + f_ik[1];
f[i][2] -= f_ij[2] + f_ik[2];
// potential energy
evdwl = (exp3B_ij * exp3B_ik * potentia3B_factor);
if (evflag) ev_tally3(i,j,k,evdwl,0.0,f_ij,f_ik,dr_ij,dr_ik);
}
}
// forces due to environment coordination f(Z)
for (int idx = 0; idx < numForceCoordPairs; idx++) {
double dr_ij[3],f_ij[3];
preForceCoord_counter = idx * 5;
zeta_iDerivedInvR_ij=preForceCoord[preForceCoord_counter+0];
dr_ij[0]=preForceCoord[preForceCoord_counter+1];
dr_ij[1]=preForceCoord[preForceCoord_counter+2];
dr_ij[2]=preForceCoord[preForceCoord_counter+3];
j = static_cast<int> (preForceCoord[preForceCoord_counter+4]);
forceModCoord_ij = forceModCoord * zeta_iDerivedInvR_ij;
f_ij[0] = forceModCoord_ij * dr_ij[0];
f_ij[1] = forceModCoord_ij * dr_ij[1];
f_ij[2] = forceModCoord_ij * dr_ij[2];
f[i][0] -= f_ij[0];
f[i][1] -= f_ij[1];
f[i][2] -= f_ij[2];
f[j][0] += f_ij[0];
f[j][1] += f_ij[1];
f[j][2] += f_ij[2];
// potential energy
evdwl = 0.0;
if (evflag) ev_tally(i, j, nlocal, newton_pair, evdwl, 0.0,
-forceModCoord_ij, dr_ij[0], dr_ij[1], dr_ij[2]);
}
}
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairEDIP::allocateGrids(void)
{
int numGridPointsOneCutoffFunction;
int numGridPointsNotOneCutoffFunction;
int numGridPointsCutoffFunction;
int numGridPointsR;
int numGridPointsRTotal;
int numGridPointsQFunctionGrid;
int numGridPointsExpMinusBetaZeta_iZeta_i;
int numGridPointsTauFunctionGrid;
double maxArgumentTauFunctionGrid;
double maxArgumentQFunctionGrid;
double maxArgumentExpMinusBetaZeta_iZeta_i;
double const leftLimitToZero = -DBL_MIN * 1000.0;
// tauFunctionGrid
maxArgumentTauFunctionGrid = leadDimInteractionList;
numGridPointsTauFunctionGrid = (int)
((maxArgumentTauFunctionGrid) * GRIDDENSITY) + 2;
memory->create(tauFunctionGrid,numGridPointsTauFunctionGrid,
"edip:tauFunctionGrid");
memory->create(tauFunctionDerivedGrid,numGridPointsTauFunctionGrid,
"edip:tauFunctionDerivedGrid");
// expMinusBetaZeta_iZeta_iGrid
maxArgumentExpMinusBetaZeta_iZeta_i = leadDimInteractionList;
numGridPointsExpMinusBetaZeta_iZeta_i = (int)
((maxArgumentExpMinusBetaZeta_iZeta_i) * GRIDDENSITY) + 2;
memory->create(expMinusBetaZeta_iZeta_iGrid,
numGridPointsExpMinusBetaZeta_iZeta_i,
"edip:expMinusBetaZeta_iZeta_iGrid");
// qFunctionGrid
maxArgumentQFunctionGrid = leadDimInteractionList;
numGridPointsQFunctionGrid = (int)
((maxArgumentQFunctionGrid) * GRIDDENSITY) + 2;
memory->create(qFunctionGrid,numGridPointsQFunctionGrid,"edip:qFunctionGrid");
// cutoffFunction
numGridPointsOneCutoffFunction = (int) ((cutoffC - GRIDSTART) * GRIDDENSITY);
numGridPointsNotOneCutoffFunction = (int) ((cutoffA-cutoffC) * GRIDDENSITY);
numGridPointsCutoffFunction = numGridPointsOneCutoffFunction +
numGridPointsNotOneCutoffFunction+2;
memory->create(cutoffFunction,numGridPointsCutoffFunction,
"edip:cutoffFunction");
memory->create(cutoffFunctionDerived,numGridPointsCutoffFunction,
"edip:cutoffFunctionDerived");
// pow2B
numGridPointsR = (int)
((cutoffA + leftLimitToZero - GRIDSTART) * GRIDDENSITY);
numGridPointsRTotal = numGridPointsR + 2;
memory->create(pow2B,numGridPointsRTotal,"edip:pow2B");
memory->create(exp2B,numGridPointsRTotal,"edip:exp2B");
memory->create(exp3B,numGridPointsRTotal,"edip:exp3B");
}
/* ----------------------------------------------------------------------
pre-calculated structures
------------------------------------------------------------------------- */
void PairEDIP::allocatePreLoops(void)
{
int nthreads = comm->nthreads;
memory->create(preInvR_ij,nthreads*leadDimInteractionList,"edip:preInvR_ij");
memory->create(preExp3B_ij,nthreads*leadDimInteractionList,"edip:preExp3B_ij");
memory->create(preExp3BDerived_ij,nthreads*leadDimInteractionList,
"edip:preExp3BDerived_ij");
memory->create(preExp2B_ij,nthreads*leadDimInteractionList,"edip:preExp2B_ij");
memory->create(preExp2BDerived_ij,nthreads*leadDimInteractionList,
"edip:preExp2BDerived_ij");
memory->create(prePow2B_ij,nthreads*leadDimInteractionList,"edip:prePow2B_ij");
memory->create(preForceCoord,5*nthreads*leadDimInteractionList,"edip:preForceCoord");
}
/* ----------------------------------------------------------------------
deallocate grids
------------------------------------------------------------------------- */
void PairEDIP::deallocateGrids(void)
{
memory->destroy(cutoffFunction);
memory->destroy(cutoffFunctionDerived);
memory->destroy(pow2B);
memory->destroy(exp2B);
memory->destroy(exp3B);
memory->destroy(qFunctionGrid);
memory->destroy(expMinusBetaZeta_iZeta_iGrid);
memory->destroy(tauFunctionGrid);
memory->destroy(tauFunctionDerivedGrid);
}
/* ----------------------------------------------------------------------
deallocate preLoops
------------------------------------------------------------------------- */
void PairEDIP::deallocatePreLoops(void)
{
memory->destroy(preInvR_ij);
memory->destroy(preExp3B_ij);
memory->destroy(preExp3BDerived_ij);
memory->destroy(preExp2B_ij);
memory->destroy(preExp2BDerived_ij);
memory->destroy(prePow2B_ij);
memory->destroy(preForceCoord);
}
/* ---------------------------------------------------------------------- */
void PairEDIP::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairEDIP::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ---------------------------------------------------------------------- */
void PairEDIP::initGrids(void)
{
int l;
int numGridPointsOneCutoffFunction;
int numGridPointsNotOneCutoffFunction;
int numGridPointsCutoffFunction;
int numGridPointsR;
int numGridPointsRTotal;
int numGridPointsQFunctionGrid;
int numGridPointsExpMinusBetaZeta_iZeta_i;
int numGridPointsTauFunctionGrid;
double maxArgumentTauFunctionGrid;
double maxArgumentQFunctionGrid;
double maxArgumentExpMinusBetaZeta_iZeta_i;
double r;
double temp;
double temp3;
double temp4;
double deltaArgumentR;
double deltaArgumentCutoffFunction;
double deltaArgumentQFunctionGrid;
double deltaArgumentTauFunctionGrid;
double deltaArgumentExpMinusBetaZeta_iZeta_i;
double const leftLimitToZero = -DBL_MIN * 1000.0;
// tauFunctionGrid
maxArgumentTauFunctionGrid = leadDimInteractionList;
numGridPointsTauFunctionGrid = (int)
((maxArgumentTauFunctionGrid) * GRIDDENSITY) + 2;
r = 0.0;
deltaArgumentTauFunctionGrid = 1.0 / GRIDDENSITY;
for (l = 0; l < numGridPointsTauFunctionGrid; l++) {
tauFunctionGrid[l] = u1 + u2 * u3 * exp(-u4 * r) -
u2 * exp(-2.0 * u4 * r);
tauFunctionDerivedGrid[l] = - u2 * u3 * u4 * exp(-u4 * r) +
2.0 * u2 * u4 * exp(-2.0 * u4 * r);
r += deltaArgumentTauFunctionGrid;
}
// expMinusBetaZeta_iZeta_iGrid
maxArgumentExpMinusBetaZeta_iZeta_i = leadDimInteractionList;
numGridPointsExpMinusBetaZeta_iZeta_i = (int)
((maxArgumentExpMinusBetaZeta_iZeta_i) * GRIDDENSITY) + 2;
r = 0.0;
deltaArgumentExpMinusBetaZeta_iZeta_i = 1.0 / GRIDDENSITY;
for (l = 0; l < numGridPointsExpMinusBetaZeta_iZeta_i; l++) {
expMinusBetaZeta_iZeta_iGrid[l] = exp(-beta * r * r);
r += deltaArgumentExpMinusBetaZeta_iZeta_i;
}
// qFunctionGrid
maxArgumentQFunctionGrid = leadDimInteractionList;
numGridPointsQFunctionGrid =
(int) ((maxArgumentQFunctionGrid) * GRIDDENSITY) + 2;
r = 0.0;
deltaArgumentQFunctionGrid = 1.0 / GRIDDENSITY;
for (l = 0; l < numGridPointsQFunctionGrid; l++) {
qFunctionGrid[l] = Q0 * exp(-mu * r);
r += deltaArgumentQFunctionGrid;
}
// cutoffFunction
numGridPointsOneCutoffFunction =
(int) ((cutoffC - GRIDSTART) * GRIDDENSITY);
numGridPointsNotOneCutoffFunction =
(int) ((cutoffA-cutoffC) * GRIDDENSITY);
numGridPointsCutoffFunction =
numGridPointsOneCutoffFunction+numGridPointsNotOneCutoffFunction+2;
r = GRIDSTART;
deltaArgumentCutoffFunction = 1.0 / GRIDDENSITY;
for (l = 0; l < numGridPointsOneCutoffFunction; l++) {
cutoffFunction[l] = 1.0;
cutoffFunctionDerived[l] = 0.0;
r += deltaArgumentCutoffFunction;
}
for (l = numGridPointsOneCutoffFunction;
l < numGridPointsCutoffFunction; l++) {
temp = (cutoffA - cutoffC)/(r - cutoffC);
temp3 = temp * temp * temp;
temp4 = temp3 * temp;
cutoffFunction[l] = exp(alpha/(1.0-temp3));
cutoffFunctionDerived[l] = (-3*alpha/(cutoffA-cutoffC)) *
(temp4/((1-temp3)*(1-temp3)))*exp(alpha/(1.0-temp3));
r += deltaArgumentCutoffFunction;
}
// pow2B
numGridPointsR = (int)
((cutoffA + leftLimitToZero - GRIDSTART) * GRIDDENSITY);
numGridPointsRTotal = numGridPointsR + 2;
r = GRIDSTART;
deltaArgumentR = 1.0 / GRIDDENSITY;
for (l = 0; l < numGridPointsR; l++) {
pow2B[l] = pow((B/r),rho);
exp2B[l] = A * exp(sigma/(r-cutoffA));
exp3B[l] = exp(gamm/(r-cutoffA));
r += deltaArgumentR;
}
pow2B[numGridPointsR] = pow((B/r),rho);
exp2B[numGridPointsR]=0;
exp3B[numGridPointsR]=0;
r += deltaArgumentR;
pow2B[numGridPointsR+1] = pow((B/r),rho);
exp2B[numGridPointsR+1]=0;
exp3B[numGridPointsR+1]=0;
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairEDIP::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
// clear setflag since coeff() called once with I,J = * *
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");
// allocate tables and internal structures
allocatePreLoops();
allocateGrids();
initGrids();
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairEDIP::init_style()
{
- if (atom->tag_enable == 0)
- error->all(FLERR,"Pair style EDIP requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style EDIP requires newton pair on");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairEDIP::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairEDIP::read_file(char *file)
{
int params_per_line = 20;
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 = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open EDIP potential file %s",file);
error->one(FLERR,str);
}
}
// read each set of params from potential file
// one set of params can span multiple lines
// store params if all 3 element tags are in element list
int n,nwords,ielement,jelement,kelement;
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,"Incorrect format in EDIP 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next entry in file
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].A = atof(words[3]);
params[nparams].B = atof(words[4]);
params[nparams].cutoffA = atof(words[5]);
params[nparams].cutoffC = atof(words[6]);
params[nparams].alpha = atof(words[7]);
params[nparams].beta = atof(words[8]);
params[nparams].eta = atof(words[9]);
params[nparams].gamm = atof(words[10]);
params[nparams].lambda = atof(words[11]);
params[nparams].mu = atof(words[12]);
params[nparams].rho = atof(words[13]);
params[nparams].sigma = atof(words[14]);
params[nparams].Q0 = atof(words[15]);
params[nparams].u1 = atof(words[16]);
params[nparams].u2 = atof(words[17]);
params[nparams].u3 = atof(words[18]);
params[nparams].u4 = atof(words[19]);
if (params[nparams].A < 0.0 || params[nparams].B < 0.0 ||
params[nparams].cutoffA < 0.0 || params[nparams].cutoffC < 0.0 ||
params[nparams].alpha < 0.0 || params[nparams].beta < 0.0 ||
params[nparams].eta < 0.0 || params[nparams].gamm < 0.0 ||
params[nparams].lambda < 0.0 || params[nparams].mu < 0.0 ||
params[nparams].rho < 0.0 || params[nparams].sigma < 0.0)
error->all(FLERR,"Illegal EDIP parameter");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairEDIP::setup()
{
int i,j,k,m,n;
double rtmp;
// set elem2param for all triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// set cutoff square
for (m = 0; m < nparams; m++) {
params[m].cutsq = params[m].cutoffA*params[m].cutoffA;
}
// set cutmax to max of all params
cutmax = 0.0;
for (m = 0; m < nparams; m++) {
rtmp = sqrt(params[m].cutsq);
if (rtmp > cutmax) cutmax = rtmp;
}
// this should be removed for multi species parametrizations
A = params[0].A;
B = params[0].B;
rho = params[0].rho;
cutoffA = params[0].cutoffA;
cutoffC = params[0].cutoffC;
sigma = params[0].sigma;
lambda = params[0].lambda;
gamm = params[0].gamm;
eta = params[0].eta;
Q0 = params[0].Q0;
mu = params[0].mu;
beta = params[0].beta;
alpha = params[0].alpha;
u1 = params[0].u1;
u2 = params[0].u2;
u3 = params[0].u3;
u4 = params[0].u4;
}
diff --git a/src/USER-MISC/pair_list.cpp b/src/USER-MISC/pair_list.cpp
index 3b6f5c2d1..265532e56 100644
--- a/src/USER-MISC/pair_list.cpp
+++ b/src/USER-MISC/pair_list.cpp
@@ -1,425 +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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
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;
#if defined(__GNUC__)
#define _noalias __restrict
#else
#define _noalias
#endif
/* ---------------------------------------------------------------------- */
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;
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;
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;
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;
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;
}
if (newton_pair || j < nlocal) {
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");
}
}
/* ----------------------------------------------------------------------
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 = fopen(arg[0],"r");
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;
- int id1, id2, nharm=0, nmorse=0, nlj126=0;
+ 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 = atoi(ptr);
+ id1 = ATOTAGINT(ptr);
ptr = strtok(NULL," \t\n\r\f");
if (!ptr)
error->all(FLERR,"Incorrectly formatted pair list file");
- id2 = atoi(ptr);
+ 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");
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");
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");
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");
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");
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");
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");
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]);
if (logfile)
fprintf(logfile,"Read %d (%d/%d/%d) interacting pairs from %s\n",
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(arg[0],atom->ntypes,ilo,ihi);
force->bounds(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;
} 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);
} 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);
}
}
}
}
/* ----------------------------------------------------------------------
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_list.h b/src/USER-MISC/pair_list.h
index 9d199f5ba..4059b0ef2 100644
--- a/src/USER-MISC/pair_list.h
+++ b/src/USER-MISC/pair_list.h
@@ -1,116 +1,116 @@
/* -*- 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(list,PairList)
#else
#ifndef LMP_PAIR_LIST_H
#define LMP_PAIR_LIST_H
#include "pair.h"
namespace LAMMPS_NS {
class PairList : public Pair {
public:
PairList(class LAMMPS *);
virtual ~PairList();
virtual void compute(int, int);
virtual void settings(int, char **);
virtual void coeff(int, char **);
virtual void init_style();
virtual double init_one(int, int);
virtual double memory_usage();
protected:
void allocate();
enum { NONE=0, HARM, MORSE, LJ126 };
// potential specific parameters
struct harm_p { double k, r0; };
struct morse_p { double d0, alpha, r0; };
struct lj126_p { double epsilon, sigma; };
union parm_u {
struct harm_p harm;
struct morse_p morse;
struct lj126_p lj126;
};
typedef struct {
- int id1,id2; // global atom ids
+ tagint id1,id2; // global atom ids
double cutsq; // cutoff**2 for this pair
double offset; // energy offset
union parm_u parm; // parameters for style
} list_parm_t;
protected:
double cut_global; // global cutoff distance
int *style; // list of styles for pair interactions
list_parm_t *params; // lisf of pair interaction parameters
int npairs; // # of atom pairs in global list
int check_flag; // 1 if checking for missing pairs
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Not all pairs processed in pair_style list
Not all interacting pairs for which coefficients were found. This can be intentional
and then you need to set the 'nocheck' option. If not, it usually means that the
communication cutoff is too small. This can be ameliorated by either increasing
the cutoff in the pair_style command or the communication cutoff.
E: Illegal ... command
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.
E: Cannot open pair list file
Self-explanatory. The file with the list of pairs cannot be open for reading.
Check the path and permissions.
E: Incorrectly formatted ...
Self-explanatory. The content of the pair list file does not match the documented
format. Please re-read the documentation and carefully compare it to your file.
E: Unknown pair list potential style
Self-explanatory. You requested a potential type that is not yet implemented or have a typo.
E: Incorrect args for pair coefficients
Self-explanatory. Check the input script or data file.
E: Pair style list requires atom IDs
Self-explanatory. The pairs in the list are identified via atom IDs, so they need to be present.
E: Pair style list requires an atom map
Self-explanatory. Atoms are looked up via an atom map. Create one using the atom_style map command.
*/
diff --git a/src/USER-MISC/pair_tersoff_table.cpp b/src/USER-MISC/pair_tersoff_table.cpp
index d5850ac81..db58c023b 100644
--- a/src/USER-MISC/pair_tersoff_table.cpp
+++ b/src/USER-MISC/pair_tersoff_table.cpp
@@ -1,1022 +1,1020 @@
/* ----------------------------------------------------------------------
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: Luca Ferraro (CASPUR)
email: luca.ferraro@caspur.it
Tersoff Potential
References: (referenced as tersoff_2 functional form in LAMMPS manual)
1) Tersoff, Phys. Rev. B 39, 5566 (1988)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_tersoff_table.h"
#include "atom.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAXLINE 1024
#define DELTA 4
#define GRIDSTART 0.1
#define GRIDDENSITY_FCUTOFF 5000
#define GRIDDENSITY_EXP 12000
#define GRIDDENSITY_GTETA 12000
#define GRIDDENSITY_BIJ 7500
// max number of interaction per atom for environment potential
#define leadingDimensionInteractionList 64
/* ---------------------------------------------------------------------- */
PairTersoffTable::PairTersoffTable(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
one_coeff = 1;
manybody_flag = 1;
nelements = 0;
elements = NULL;
nparams = maxparam = 0;
params = NULL;
elem2param = NULL;
}
/* ----------------------------------------------------------------------
check if allocated, since class can be destructed when incomplete
------------------------------------------------------------------------- */
PairTersoffTable::~PairTersoffTable()
{
if (elements)
for (int i = 0; i < nelements; i++) delete [] elements[i];
delete [] elements;
memory->destroy(params);
memory->destroy(elem2param);
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
delete [] map;
deallocateGrids();
deallocatePreLoops();
}
}
/* ---------------------------------------------------------------------- */
void PairTersoffTable::compute(int eflag, int vflag)
{
int i,j,k,ii,inum,jnum;
int itype,jtype,ktype,ijparam,ikparam,ijkparam;
double xtmp,ytmp,ztmp;
double fxtmp,fytmp,fztmp;
int *ilist,*jlist,*numneigh,**firstneigh;
int interpolIDX;
double r_ik_x, r_ik_y, r_ik_z;
double directorCos_ij_x, directorCos_ij_y, directorCos_ij_z, directorCos_ik_x, directorCos_ik_y, directorCos_ik_z;
double invR_ij, invR_ik, cosTeta;
double repulsivePotential, attractivePotential;
double exponentRepulsivePotential, exponentAttractivePotential,interpolTMP,interpolDeltaX,interpolY1;
double interpolY2, cutoffFunctionIJ, attractiveExponential, repulsiveExponential, cutoffFunctionDerivedIJ,zeta;
double gtetaFunctionIJK,gtetaFunctionDerivedIJK,cutoffFunctionIK;
double cutoffFunctionDerivedIK,factor_force3_ij,factor_1_force3_ik;
double factor_2_force3_ik,betaZetaPowerIJK,betaZetaPowerDerivedIJK,factor_force_tot;
double factor_force_ij;
double gtetaFunctionDerived_temp,gtetaFunction_temp;
double 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 full neighbor list of my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
itype = map[type[i]];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
fxtmp = fytmp = fztmp = 0.0;
jlist = firstneigh[i];
jnum = numneigh[i];
if (jnum > leadingDimensionInteractionList) {
char errmsg[256];
sprintf(errmsg,"Too many neighbors for interaction list: %d vs %d.\n"
"Check your system or increase 'leadingDimensionInteractionList'",
jnum, leadingDimensionInteractionList);
error->one(FLERR,errmsg);
}
// Pre-calculate gteta and cutoff function
for (int neighbor_j = 0; neighbor_j < jnum; neighbor_j++) {
double dr_ij[3], r_ij;
j = jlist[neighbor_j];
j &= NEIGHMASK;
dr_ij[0] = xtmp - x[j][0];
dr_ij[1] = ytmp - x[j][1];
dr_ij[2] = ztmp - x[j][2];
r_ij = dr_ij[0]*dr_ij[0] + dr_ij[1]*dr_ij[1] + dr_ij[2]*dr_ij[2];
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
if (r_ij > params[ijparam].cutsq) continue;
r_ij = sqrt(r_ij);
invR_ij = 1.0 / r_ij;
directorCos_ij_x = invR_ij * dr_ij[0];
directorCos_ij_y = invR_ij * dr_ij[1];
directorCos_ij_z = invR_ij * dr_ij[2];
// preCutoffFunction
interpolDeltaX = r_ij - GRIDSTART;
interpolTMP = (interpolDeltaX * GRIDDENSITY_FCUTOFF);
interpolIDX = (int) interpolTMP;
interpolY1 = cutoffFunction[itype][jtype][interpolIDX];
interpolY2 = cutoffFunction[itype][jtype][interpolIDX+1];
preCutoffFunction[neighbor_j] = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
// preCutoffFunctionDerived
interpolY1 = cutoffFunctionDerived[itype][jtype][interpolIDX];
interpolY2 = cutoffFunctionDerived[itype][jtype][interpolIDX+1];
preCutoffFunctionDerived[neighbor_j] = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
for (int neighbor_k = neighbor_j + 1; neighbor_k < jnum; neighbor_k++) {
double dr_ik[3], r_ik;
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = xtmp -x[k][0];
dr_ik[1] = ytmp -x[k][1];
dr_ik[2] = ztmp -x[k][2];
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = 1.0 / r_ik;
directorCos_ik_x = invR_ik * dr_ik[0];
directorCos_ik_y = invR_ik * dr_ik[1];
directorCos_ik_z = invR_ik * dr_ik[2];
cosTeta = directorCos_ij_x * directorCos_ik_x + directorCos_ij_y * directorCos_ik_y + directorCos_ij_z * directorCos_ik_z;
// preGtetaFunction
interpolDeltaX=cosTeta+1.0;
interpolTMP = (interpolDeltaX * GRIDDENSITY_GTETA);
interpolIDX = (int) interpolTMP;
interpolY1 = gtetaFunction[itype][interpolIDX];
interpolY2 = gtetaFunction[itype][interpolIDX+1];
gtetaFunction_temp = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
// preGtetaFunctionDerived
interpolY1 = gtetaFunctionDerived[itype][interpolIDX];
interpolY2 = gtetaFunctionDerived[itype][interpolIDX+1];
gtetaFunctionDerived_temp = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
preGtetaFunction[neighbor_j][neighbor_k]=params[ijkparam].gamma*gtetaFunction_temp;
preGtetaFunctionDerived[neighbor_j][neighbor_k]=params[ijkparam].gamma*gtetaFunctionDerived_temp;
preGtetaFunction[neighbor_k][neighbor_j]=params[ijkparam].gamma*gtetaFunction_temp;
preGtetaFunctionDerived[neighbor_k][neighbor_j]=params[ijkparam].gamma*gtetaFunctionDerived_temp;
} // loop on K
} // loop on J
// loop over neighbours of atom i
for (int neighbor_j = 0; neighbor_j < jnum; neighbor_j++) {
double dr_ij[3], r_ij, f_ij[3];
j = jlist[neighbor_j];
j &= NEIGHMASK;
dr_ij[0] = xtmp - x[j][0];
dr_ij[1] = ytmp - x[j][1];
dr_ij[2] = ztmp - x[j][2];
r_ij = dr_ij[0]*dr_ij[0] + dr_ij[1]*dr_ij[1] + dr_ij[2]*dr_ij[2];
jtype = map[type[j]];
ijparam = elem2param[itype][jtype][jtype];
if (r_ij > params[ijparam].cutsq) continue;
r_ij = sqrt(r_ij);
invR_ij = 1.0 / r_ij;
directorCos_ij_x = invR_ij * dr_ij[0];
directorCos_ij_y = invR_ij * dr_ij[1];
directorCos_ij_z = invR_ij * dr_ij[2];
exponentRepulsivePotential = params[ijparam].lam1 * r_ij;
exponentAttractivePotential = params[ijparam].lam2 * r_ij;
// repulsiveExponential
interpolDeltaX = exponentRepulsivePotential - minArgumentExponential;
interpolTMP = (interpolDeltaX * GRIDDENSITY_EXP);
interpolIDX = (int) interpolTMP;
interpolY1 = exponential[interpolIDX];
interpolY2 = exponential[interpolIDX+1];
repulsiveExponential = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
// attractiveExponential
interpolDeltaX = exponentAttractivePotential - minArgumentExponential;
interpolTMP = (interpolDeltaX * GRIDDENSITY_EXP);
interpolIDX = (int) interpolTMP;
interpolY1 = exponential[interpolIDX];
interpolY2 = exponential[interpolIDX+1];
attractiveExponential = interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX);
repulsivePotential = params[ijparam].biga * repulsiveExponential;
attractivePotential = -params[ijparam].bigb * attractiveExponential;
cutoffFunctionIJ = preCutoffFunction[neighbor_j];
cutoffFunctionDerivedIJ = preCutoffFunctionDerived[neighbor_j];
zeta = 0.0;
// first loop over neighbours of atom i except j - part 1/2
for (int neighbor_k = 0; neighbor_k < neighbor_j; neighbor_k++) {
double dr_ik[3], r_ik;
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = xtmp -x[k][0];
dr_ik[1] = ytmp -x[k][1];
dr_ik[2] = ztmp -x[k][2];
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = 1.0 / r_ik;
gtetaFunctionIJK = preGtetaFunction[neighbor_j][neighbor_k];
cutoffFunctionIK = preCutoffFunction[neighbor_k];
zeta += cutoffFunctionIK * gtetaFunctionIJK;
}
// first loop over neighbours of atom i except j - part 2/2
for (int neighbor_k = neighbor_j+1; neighbor_k < jnum; neighbor_k++) {
double dr_ik[3], r_ik;
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = xtmp -x[k][0];
dr_ik[1] = ytmp -x[k][1];
dr_ik[2] = ztmp -x[k][2];
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = 1.0 / r_ik;
directorCos_ik_x = invR_ik * dr_ik[0];
directorCos_ik_y = invR_ik * dr_ik[1];
directorCos_ik_z = invR_ik * dr_ik[2];
gtetaFunctionIJK = preGtetaFunction[neighbor_j][neighbor_k];
cutoffFunctionIK = preCutoffFunction[neighbor_k];
zeta += cutoffFunctionIK * gtetaFunctionIJK;
}
// betaZetaPowerIJK
interpolDeltaX= params[ijparam].beta * zeta;
interpolTMP = (interpolDeltaX * GRIDDENSITY_BIJ);
interpolIDX = (int) interpolTMP;
interpolY1 = betaZetaPower[itype][interpolIDX];
interpolY2 = betaZetaPower[itype][interpolIDX+1];
betaZetaPowerIJK = (interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX));
// betaZetaPowerDerivedIJK
interpolY1 = betaZetaPowerDerived[itype][interpolIDX];
interpolY2 = betaZetaPowerDerived[itype][interpolIDX+1];
betaZetaPowerDerivedIJK = params[ijparam].beta*(interpolY1 + (interpolY2 - interpolY1) * (interpolTMP - interpolIDX));
// Forces and virial
factor_force_ij = 0.5*cutoffFunctionDerivedIJ*(repulsivePotential + attractivePotential * betaZetaPowerIJK)+0.5*cutoffFunctionIJ*(-repulsivePotential*params[ijparam].lam1-betaZetaPowerIJK*attractivePotential*params[ijparam].lam2);
f_ij[0] = factor_force_ij * directorCos_ij_x;
f_ij[1] = factor_force_ij * directorCos_ij_y;
f_ij[2] = factor_force_ij * directorCos_ij_z;
f[j][0] += f_ij[0];
f[j][1] += f_ij[1];
f[j][2] += f_ij[2];
fxtmp -= f_ij[0];
fytmp -= f_ij[1];
fztmp -= f_ij[2];
// potential energy
evdwl = cutoffFunctionIJ * repulsivePotential + cutoffFunctionIJ * attractivePotential * betaZetaPowerIJK;
if (evflag) ev_tally(i, j, nlocal, newton_pair, 0.5 * evdwl, 0.0,
-factor_force_ij*invR_ij, dr_ij[0], dr_ij[1], dr_ij[2]);
factor_force_tot= 0.5*cutoffFunctionIJ*attractivePotential*betaZetaPowerDerivedIJK;
// second loop over neighbours of atom i except j, forces and virial only - part 1/2
for (int neighbor_k = 0; neighbor_k < neighbor_j; neighbor_k++) {
double dr_ik[3], r_ik, f_ik[3];
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = xtmp -x[k][0];
dr_ik[1] = ytmp -x[k][1];
dr_ik[2] = ztmp -x[k][2];
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = 1.0 / r_ik;
directorCos_ik_x = invR_ik * dr_ik[0];
directorCos_ik_y = invR_ik * dr_ik[1];
directorCos_ik_z = invR_ik * dr_ik[2];
cosTeta = directorCos_ij_x * directorCos_ik_x + directorCos_ij_y * directorCos_ik_y + directorCos_ij_z * directorCos_ik_z;
gtetaFunctionIJK = preGtetaFunction[neighbor_j][neighbor_k];
gtetaFunctionDerivedIJK = preGtetaFunctionDerived[neighbor_j][neighbor_k];
cutoffFunctionIK = preCutoffFunction[neighbor_k];
cutoffFunctionDerivedIK = preCutoffFunctionDerived[neighbor_k];
factor_force3_ij= cutoffFunctionIK * gtetaFunctionDerivedIJK * invR_ij *factor_force_tot;
f_ij[0] = factor_force3_ij * (directorCos_ij_x*cosTeta - directorCos_ik_x);
f_ij[1] = factor_force3_ij * (directorCos_ij_y*cosTeta - directorCos_ik_y);
f_ij[2] = factor_force3_ij * (directorCos_ij_z*cosTeta - directorCos_ik_z);
factor_1_force3_ik = (cutoffFunctionIK * gtetaFunctionDerivedIJK * invR_ik)*factor_force_tot;
factor_2_force3_ik = -(cutoffFunctionDerivedIK * gtetaFunctionIJK)*factor_force_tot;
f_ik[0] = factor_1_force3_ik * (directorCos_ik_x*cosTeta - directorCos_ij_x) + factor_2_force3_ik * directorCos_ik_x;
f_ik[1] = factor_1_force3_ik * (directorCos_ik_y*cosTeta - directorCos_ij_y) + factor_2_force3_ik * directorCos_ik_y;
f_ik[2] = factor_1_force3_ik * (directorCos_ik_z*cosTeta - directorCos_ij_z) + factor_2_force3_ik * directorCos_ik_z;
f[j][0] -= f_ij[0];
f[j][1] -= f_ij[1];
f[j][2] -= f_ij[2];
f[k][0] -= f_ik[0];
f[k][1] -= f_ik[1];
f[k][2] -= f_ik[2];
fxtmp += f_ij[0] + f_ik[0];
fytmp += f_ij[1] + f_ik[1];
fztmp += f_ij[2] + f_ik[2];
// potential energy
evdwl = 0.0;
if (evflag) ev_tally3(i,j,k,evdwl,0.0,f_ij,f_ik,dr_ij,dr_ik);
}
// second loop over neighbours of atom i except j, forces and virial only - part 2/2
for (int neighbor_k = neighbor_j+1; neighbor_k < jnum; neighbor_k++) {
double dr_ik[3], r_ik, f_ik[3];
k = jlist[neighbor_k];
k &= NEIGHMASK;
ktype = map[type[k]];
ikparam = elem2param[itype][ktype][ktype];
ijkparam = elem2param[itype][jtype][ktype];
dr_ik[0] = xtmp -x[k][0];
dr_ik[1] = ytmp -x[k][1];
dr_ik[2] = ztmp -x[k][2];
r_ik = dr_ik[0]*dr_ik[0] + dr_ik[1]*dr_ik[1] + dr_ik[2]*dr_ik[2];
if (r_ik > params[ikparam].cutsq) continue;
r_ik = sqrt(r_ik);
invR_ik = 1.0 / r_ik;
directorCos_ik_x = invR_ik * dr_ik[0];
directorCos_ik_y = invR_ik * dr_ik[1];
directorCos_ik_z = invR_ik * dr_ik[2];
cosTeta = directorCos_ij_x * directorCos_ik_x + directorCos_ij_y * directorCos_ik_y + directorCos_ij_z * directorCos_ik_z;
gtetaFunctionIJK = preGtetaFunction[neighbor_j][neighbor_k];
gtetaFunctionDerivedIJK = preGtetaFunctionDerived[neighbor_j][neighbor_k];
cutoffFunctionIK = preCutoffFunction[neighbor_k];
cutoffFunctionDerivedIK = preCutoffFunctionDerived[neighbor_k];
factor_force3_ij= cutoffFunctionIK * gtetaFunctionDerivedIJK * invR_ij *factor_force_tot;
f_ij[0] = factor_force3_ij * (directorCos_ij_x*cosTeta - directorCos_ik_x);
f_ij[1] = factor_force3_ij * (directorCos_ij_y*cosTeta - directorCos_ik_y);
f_ij[2] = factor_force3_ij * (directorCos_ij_z*cosTeta - directorCos_ik_z);
factor_1_force3_ik = (cutoffFunctionIK * gtetaFunctionDerivedIJK * invR_ik)*factor_force_tot;
factor_2_force3_ik = -(cutoffFunctionDerivedIK * gtetaFunctionIJK)*factor_force_tot;
f_ik[0] = factor_1_force3_ik * (directorCos_ik_x*cosTeta - directorCos_ij_x) + factor_2_force3_ik * directorCos_ik_x;
f_ik[1] = factor_1_force3_ik * (directorCos_ik_y*cosTeta - directorCos_ij_y) + factor_2_force3_ik * directorCos_ik_y;
f_ik[2] = factor_1_force3_ik * (directorCos_ik_z*cosTeta - directorCos_ij_z) + factor_2_force3_ik * directorCos_ik_z;
f[j][0] -= f_ij[0];
f[j][1] -= f_ij[1];
f[j][2] -= f_ij[2];
f[k][0] -= f_ik[0];
f[k][1] -= f_ik[1];
f[k][2] -= f_ik[2];
fxtmp += f_ij[0] + f_ik[0];
fytmp += f_ij[1] + f_ik[1];
fztmp += f_ij[2] + f_ik[2];
// potential energy
evdwl = 0.0;
if (evflag) ev_tally3(i,j,k,evdwl,0.0,f_ij,f_ik,dr_ij,dr_ik);
}
} // loop on J
f[i][0] += fxtmp;
f[i][1] += fytmp;
f[i][2] += fztmp;
} // loop on I
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairTersoffTable::deallocatePreLoops(void)
{
memory->destroy (preGtetaFunction);
memory->destroy (preGtetaFunctionDerived);
memory->destroy(preCutoffFunction);
memory->destroy(preCutoffFunctionDerived);
}
void PairTersoffTable::allocatePreLoops(void)
{
memory->create(preGtetaFunction,leadingDimensionInteractionList,leadingDimensionInteractionList,"tersofftable:preGtetaFunction");
memory->create(preGtetaFunctionDerived,leadingDimensionInteractionList,leadingDimensionInteractionList,"tersofftable:preGtetaFunctionDerived");
memory->create(preCutoffFunction,leadingDimensionInteractionList,"tersofftable:preCutoffFunction");
memory->create(preCutoffFunctionDerived,leadingDimensionInteractionList,"tersofftable:preCutoffFunctionDerived");
}
void PairTersoffTable::deallocateGrids()
{
int i,j;
memory->destroy(exponential);
memory->destroy(gtetaFunction);
memory->destroy(gtetaFunctionDerived);
memory->destroy(cutoffFunction);
memory->destroy(cutoffFunctionDerived);
memory->destroy(betaZetaPower);
memory->destroy(betaZetaPowerDerived);
}
void PairTersoffTable::allocateGrids(void)
{
int i, j, l;
int numGridPointsExponential, numGridPointsGtetaFunction, numGridPointsOneCutoffFunction;
int numGridPointsNotOneCutoffFunction, numGridPointsCutoffFunction, numGridPointsBetaZetaPower;
// double minArgumentExponential;
double deltaArgumentCutoffFunction, deltaArgumentExponential, deltaArgumentBetaZetaPower;
double deltaArgumentGtetaFunction;
double r, minMu, maxLambda, maxCutoff;
double const PI=acos(-1.0);
// exponential
// find min and max argument
minMu=params[0].lam2;
maxLambda=params[0].lam1;
for (i=1; i<nparams; i++) {
if (params[i].lam2 < minMu) minMu = params[i].lam2;
if (params[i].lam1 > maxLambda) maxLambda = params[i].lam1;
}
maxCutoff=cutmax;
minArgumentExponential=minMu*GRIDSTART;
numGridPointsExponential=(int)((maxLambda*maxCutoff-minArgumentExponential)*GRIDDENSITY_EXP)+2;
memory->create(exponential,numGridPointsExponential,"tersofftable:exponential");
r = minArgumentExponential;
deltaArgumentExponential = 1.0 / GRIDDENSITY_EXP;
for (i = 0; i < numGridPointsExponential; i++)
{
exponential[i] = exp(-r);
r += deltaArgumentExponential;
}
// gtetaFunction
numGridPointsGtetaFunction=(int)(2.0*GRIDDENSITY_GTETA)+2;
memory->create(gtetaFunction,nelements,numGridPointsGtetaFunction,"tersofftable:gtetaFunction");
memory->create(gtetaFunctionDerived,nelements,numGridPointsGtetaFunction,"tersofftable:gtetaFunctionDerived");
r = minArgumentExponential;
for (i=0; i<nelements; i++) {
r = -1.0;
deltaArgumentGtetaFunction = 1.0 / GRIDDENSITY_GTETA;
int iparam = elem2param[i][i][i];
double c = params[iparam].c;
double d = params[iparam].d;
double h = params[iparam].h;
for (j = 0; j < numGridPointsGtetaFunction; j++) {
gtetaFunction[i][j]=1.0+(c*c)/(d*d)-(c*c)/(d*d+(h-r)*(h-r));
gtetaFunctionDerived[i][j]= -2.0 * c * c * (h-r) / ((d*d+(h-r)*(h-r))*(d*d+(h-r)*(h-r)));
r += deltaArgumentGtetaFunction;
}
}
// cutoffFunction, zetaFunction, find grids.
int ngrid_max = -1;
int zeta_max = -1;
for (i=0; i<nelements; i++) {
int iparam = elem2param[i][i][i];
double c = params[iparam].c;
double d = params[iparam].d;
double beta = params[iparam].beta;
numGridPointsBetaZetaPower=(int)(((1.0+(c*c)/(d*d)-(c*c)/(d*d+4))*beta*leadingDimensionInteractionList*GRIDDENSITY_BIJ))+2;
zeta_max = MAX(zeta_max,numGridPointsBetaZetaPower);
for (j=0; j<nelements; j++) {
for (j=0; j<nelements; j++) {
int ijparam = elem2param[i][j][j];
double cutoffR = params[ijparam].cutoffR;
double cutoffS = params[ijparam].cutoffS;
numGridPointsOneCutoffFunction=(int) ((cutoffR-GRIDSTART)*GRIDDENSITY_FCUTOFF)+1;
numGridPointsNotOneCutoffFunction=(int) ((cutoffS-cutoffR)*GRIDDENSITY_FCUTOFF)+2;
numGridPointsCutoffFunction=numGridPointsOneCutoffFunction+numGridPointsNotOneCutoffFunction;
ngrid_max = MAX(ngrid_max,numGridPointsCutoffFunction);
}
}
}
memory->create(cutoffFunction,nelements,nelements,ngrid_max,"tersoff:cutfunc");
memory->create(cutoffFunctionDerived,nelements,nelements,ngrid_max,"tersoff:cutfuncD");
// cutoffFunction, compute.
for (i=0; i<nelements; i++) {
for (j=0; j<nelements; j++) {
for (j=0; j<nelements; j++) {
int ijparam = elem2param[i][j][j];
double cutoffR = params[ijparam].cutoffR;
double cutoffS = params[ijparam].cutoffS;
numGridPointsOneCutoffFunction=(int) ((cutoffR-GRIDSTART)*GRIDDENSITY_FCUTOFF)+1;
numGridPointsNotOneCutoffFunction=(int) ((cutoffS-cutoffR)*GRIDDENSITY_FCUTOFF)+2;
numGridPointsCutoffFunction=numGridPointsOneCutoffFunction+numGridPointsNotOneCutoffFunction;
r = GRIDSTART;
deltaArgumentCutoffFunction = 1.0 / GRIDDENSITY_FCUTOFF;
for (l = 0; l < numGridPointsOneCutoffFunction; l++) {
cutoffFunction[i][j][l] = 1.0;
cutoffFunctionDerived[i][j][l]=0.0;
r += deltaArgumentCutoffFunction;
}
for (l = numGridPointsOneCutoffFunction; l < numGridPointsCutoffFunction; l++) {
cutoffFunction[i][j][l] = 0.5 + 0.5 * cos (PI * (r - cutoffR)/(cutoffS-cutoffR)) ;
cutoffFunctionDerived[i][j][l] = -0.5 * PI * sin (PI * (r - cutoffR)/(cutoffS-cutoffR)) / (cutoffS-cutoffR) ;
r += deltaArgumentCutoffFunction;
}
}
}
}
// betaZetaPower, compute
memory->create(betaZetaPower,nelements,zeta_max,"tersoff:zetafunc");
memory->create(betaZetaPowerDerived,nelements,zeta_max,"tersoff:zetafuncD");
for (i=0; i<nelements; i++) {
int iparam = elem2param[i][i][i];
double c = params[iparam].c;
double d = params[iparam].d;
double beta = params[iparam].beta;
numGridPointsBetaZetaPower=(int)(((1.0+(c*c)/(d*d)-(c*c)/(d*d+4))*beta*leadingDimensionInteractionList*GRIDDENSITY_BIJ))+2;
r=0.0;
deltaArgumentBetaZetaPower = 1.0 / GRIDDENSITY_BIJ;
betaZetaPower[i][0]=1.0;
r += deltaArgumentBetaZetaPower;
for (j = 1; j < numGridPointsBetaZetaPower; j++) {
double powern=params[iparam].powern;
betaZetaPower[i][j]=pow((1+pow(r,powern)),-1/(2*powern));
betaZetaPowerDerived[i][j]=-0.5*pow(r,powern-1.0)*pow((1+pow(r,powern)),-1/(2*powern)-1) ;
r += deltaArgumentBetaZetaPower;
}
betaZetaPowerDerived[i][0]=(betaZetaPower[i][1]-1.0)*GRIDDENSITY_BIJ;
}
}
void PairTersoffTable::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");
map = new int[n+1];
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairTersoffTable::settings(int narg, char **arg)
{
if (narg != 0) error->all(FLERR,"Illegal pair_style command");
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairTersoffTable::coeff(int narg, char **arg)
{
int i,j,n;
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 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 potential file and initialize potential parameters
read_file(arg[2]);
setup();
// clear setflag since coeff() called once with I,J = * *
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");
// allocate tables and internal structures
allocatePreLoops();
allocateGrids();
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairTersoffTable::init_style()
{
- if (atom->tag_enable == 0)
- error->all(FLERR,"Pair style Tersoff requires atom IDs");
if (force->newton_pair == 0)
error->all(FLERR,"Pair style Tersoff requires newton pair on");
// need a full neighbor list
int irequest = neighbor->request(this);
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairTersoffTable::init_one(int i, int j)
{
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
return cutmax;
}
/* ---------------------------------------------------------------------- */
void PairTersoffTable::read_file(char *file)
{
int params_per_line = 17;
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 = open_potential(file);
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open Tersoff potential file %s",file);
error->one(FLERR,str);
}
}
// read each set of params from potential file
// one set of params can span multiple lines
// store params if all 3 element tags are in element list
int n,nwords,ielement,jelement,kelement;
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,"Incorrect format in Tersoff 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,kelement = 1st args
// if all 3 args are in element list, then parse this line
// else skip to next entry in file
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;
for (kelement = 0; kelement < nelements; kelement++)
if (strcmp(words[2],elements[kelement]) == 0) break;
if (kelement == 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].kelement = kelement;
params[nparams].powerm = atof(words[3]); // not used (only tersoff_2 is implemented)
params[nparams].gamma = atof(words[4]); // not used (only tersoff_2 is implemented)
params[nparams].lam3 = atof(words[5]); // not used (only tersoff_2 is implemented)
params[nparams].c = atof(words[6]);
params[nparams].d = atof(words[7]);
params[nparams].h = atof(words[8]);
params[nparams].powern = atof(words[9]);
params[nparams].beta = atof(words[10]);
params[nparams].lam2 = atof(words[11]);
params[nparams].bigb = atof(words[12]);
// current implementation is based on functional form
// of tersoff_2 as reported in the reference paper
double bigr = atof(words[13]);
double bigd = atof(words[14]);
params[nparams].cutoffR = bigr - bigd;
params[nparams].cutoffS = bigr + bigd;
params[nparams].lam1 = atof(words[15]);
params[nparams].biga = atof(words[16]);
// currently only allow m exponent of 1 or 3
params[nparams].powermint = int(params[nparams].powerm);
if (params[nparams].c < 0.0 || params[nparams].d < 0.0 ||
params[nparams].powern < 0.0 || params[nparams].beta < 0.0 ||
params[nparams].lam2 < 0.0 || params[nparams].bigb < 0.0 ||
params[nparams].cutoffR < 0.0 ||params[nparams].cutoffS < 0.0 ||
params[nparams].cutoffR > params[nparams].cutoffS ||
params[nparams].lam1 < 0.0 || params[nparams].biga < 0.0
) error->all(FLERR,"Illegal Tersoff parameter");
// only tersoff_2 parametrization is implemented
if (params[nparams].gamma != 1.0 || params[nparams].lam3 != 0.0)
error->all(FLERR,"Current tersoff/table pair_style implements only tersoff_2 parametrization");
nparams++;
}
delete [] words;
}
/* ---------------------------------------------------------------------- */
void PairTersoffTable::setup()
{
int i,j,k,m,n;
// set elem2param for all triplet combinations
// must be a single exact match to lines read from file
// do not allow for ACB in place of ABC
memory->destroy(elem2param);
memory->create(elem2param,nelements,nelements,nelements,"pair:elem2param");
for (i = 0; i < nelements; i++)
for (j = 0; j < nelements; j++)
for (k = 0; k < nelements; k++) {
n = -1;
for (m = 0; m < nparams; m++) {
if (i == params[m].ielement && j == params[m].jelement &&
k == params[m].kelement) {
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][k] = n;
}
// set cutoff square
for (m = 0; m < nparams; m++) {
params[m].cut = params[m].cutoffS;
params[m].cutsq = params[m].cut*params[m].cut;
}
// set cutmax to max of all params
cutmax = 0.0;
for (m = 0; m < nparams; m++) {
if (params[m].cut > cutmax) cutmax = params[m].cut;
}
}
diff --git a/src/USER-MOLFILE/dump_molfile.cpp b/src/USER-MOLFILE/dump_molfile.cpp
index 2756abef5..753caf3d3 100644
--- a/src/USER-MOLFILE/dump_molfile.cpp
+++ b/src/USER-MOLFILE/dump_molfile.cpp
@@ -1,461 +1,465 @@
/* ----------------------------------------------------------------------
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)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "dump_molfile.h"
#include "domain.h"
#include "atom.h"
#include "comm.h"
#include "update.h"
#include "output.h"
#include "group.h"
#include "memory.h"
#include "error.h"
#include "molfile_interface.h"
using namespace LAMMPS_NS;
typedef MolfileInterface MFI;
// syntax:
// dump <id> <groupid> molfile <every> <filename> <type> [<path>]
// path defaults to "." -> will look for .so files in CWD.
//
// XXX: potential change: add more options and make them optional
// path <path>
// template <file> <type> (import name and topology information from file)
// bonds <yes|no> (write out bond information)
// topology <yes|no> (write out all topology information)
/* ---------------------------------------------------------------------- */
DumpMolfile::DumpMolfile(LAMMPS *lmp, int narg, char **arg)
: Dump(lmp, narg, arg)
{
if (narg < 6) error->all(FLERR,"Illegal dump molfile command");
if (binary || compressed || multiproc)
error->all(FLERR,"Invalid dump molfile filename");
// required settings
sort_flag = 1;
sortcol = 0;
// storage for collected information
size_one = 4;
if (atom->molecule_flag) ++size_one;
if (atom->q_flag) ++size_one;
if (atom->rmass_flag) ++size_one;
if (atom->radius_flag) ++size_one;
need_structure = 0;
unwrap_flag = 0;
velocity_flag = 0;
topology_flag = 0;
ntotal = 0;
me = comm->me;
coords = vels = masses = charges = radiuses = NULL;
types = molids = NULL;
ntypes = atom->ntypes;
typenames = NULL;
// allocate global array for atom coords
bigint n = group->count(igroup);
if (n > MAXSMALLINT/sizeof(float))
error->all(FLERR,"Too many atoms for dump molfile");
if (n < 1)
error->all(FLERR,"Not enough atoms for dump molfile");
natoms = static_cast<int>(n);
if (me == 0) {
memory->create(types,natoms,"dump:types");
memory->create(coords,3*natoms,"dump:coords");
if (atom->molecule_flag) memory->create(molids,natoms,"dump:molids");
if (atom->q_flag) memory->create(charges,natoms,"dump:charges");
if (atom->rmass_flag) memory->create(masses,natoms,"dump:masses");
if (atom->radius_flag) memory->create(radiuses,natoms,"dump:radiuses");
mf = new MolfileInterface(arg[5],MFI::M_WRITE);
const char *path = (const char *) ".";
if (narg > 6)
path=arg[6];
if (mf->find_plugin(path)!= MFI::E_MATCH)
error->one(FLERR,"No suitable molfile plugin found");
if (screen)
fprintf(screen,"Dump '%s' uses molfile plugin: %s\n",
id, mf->get_plugin_name());
if (logfile)
fprintf(logfile,"Dump '%s' uses molfile plugin: %s\n",
id,mf->get_plugin_name());
}
}
/* ---------------------------------------------------------------------- */
DumpMolfile::~DumpMolfile()
{
if (me == 0) {
mf->close();
memory->destroy(types);
memory->destroy(coords);
memory->destroy(vels);
memory->destroy(masses);
memory->destroy(charges);
memory->destroy(radiuses);
delete mf;
}
if (typenames) {
for (int i = 1; i <= ntypes; i++)
delete [] typenames[i];
delete [] typenames;
typenames = NULL;
}
}
/* ---------------------------------------------------------------------- */
void DumpMolfile::init_style()
{
if (sort_flag == 0 || sortcol != 0)
error->all(FLERR,"Dump molfile requires sorting by atom ID");
if (me == 0) {
/* initialize typenames array to numeric types by default */
if (typenames == NULL) {
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
/* a 32-bit int can be maximally 10 digits plus sign */
typenames[itype] = new char[12];
sprintf(typenames[itype],"%d",itype);
}
}
// open single file, one time only
if (multifile == 0) openfile();
}
}
/* ---------------------------------------------------------------------- */
void DumpMolfile::write()
{
// simulation box dimensions
if (domain->triclinic == 1) {
double *h = domain->h;
double alen = h[0];
double blen = sqrt(h[5]*h[5] + h[1]*h[1]);
double clen = sqrt(h[4]*h[4] + h[3]*h[3] + h[2]*h[2]);
cell[0] = alen;
cell[1] = blen;
cell[2] = clen;
cell[3] = (90.0 - asin((h[5]*h[4] + h[1]*h[3]) / blen/clen)); // alpha
cell[4] = (90.0 - asin((h[0]*h[4]) / alen/clen)); // beta
cell[5] = (90.0 - asin((h[0]*h[5]) / alen/blen)); // gamma
} else {
cell[0] = domain->xprd;
cell[1] = domain->yprd;
cell[2] = domain->zprd;
cell[3] = cell[4] = cell[5] = 90.0f;
}
// nme = # of dump lines this proc will contribute to dump
nme = count();
bigint bnme = nme;
// ntotal = total # of dump lines
// nmax = max # of dump lines on any proc
int nmax;
MPI_Allreduce(&bnme,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
// for single file output, the number of atoms must not change.
if (natoms != ntotal) {
if (multifile == 0) {
error->all(FLERR,"Single file molfile dump needs constant #atoms");
} else {
natoms = ntotal;
}
}
ntotal = 0;
// if file per timestep, open new file
if (multifile) openfile();
// insure proc 0 can receive everyone's info
// limit nmax*size_one to int since used as arg in MPI_Rsend() below
// pack my data into buf
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (nmax > maxbuf) {
if ((bigint) nmax * size_one > MAXSMALLINT)
error->all(FLERR,"Too much per-proc info for dump");
maxbuf = nmax;
memory->destroy(buf);
memory->create(buf,maxbuf*size_one,"dump:buf");
}
if (nmax > maxids) {
maxids = nmax;
memory->destroy(ids);
memory->create(ids,maxids,"dump:ids");
}
pack(ids);
sort();
int tmp,nlines;
MPI_Status status;
MPI_Request request;
if (me == 0) {
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(buf,maxbuf*size_one,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&nlines);
nlines /= size_one;
} else nlines = nme;
write_data(nlines,buf);
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
MPI_Rsend(buf,nme*size_one,MPI_DOUBLE,0,0,world);
}
}
/* ---------------------------------------------------------------------- */
void DumpMolfile::openfile()
{
// single file, already opened, so just return
if (singlefile_opened) return;
if (multifile == 0) singlefile_opened = 1;
need_structure = 1;
if (me == 0) {
// close open file, if needed.
if (mf->is_open()) mf->close();
// if one file per timestep, replace '*' with current timestep
char *filecurrent = new char[strlen(filename) + 16];
if (multifile == 0) {
strcpy(filecurrent,filename);
} else {
char *ptr = strchr(filename,'*');
char *p1 = filename;
char *p2 = filecurrent;
while (p1 != ptr)
*p2++ = *p1++;
if (padflag == 0) {
sprintf(p2,BIGINT_FORMAT "%s",update->ntimestep,ptr+1);
} else {
char bif[8],pad[16];
strcpy(bif,BIGINT_FORMAT);
sprintf(pad,"%%0%d%s%%s",padflag,&bif[1]);
sprintf(p2,pad,update->ntimestep,ptr+1);
}
}
if (mf->open(filecurrent,&natoms))
error->one(FLERR,"Cannot open dump file");
delete[] filecurrent;
}
}
/* ---------------------------------------------------------------------- */
void DumpMolfile::pack(int *ids)
{
int m,n;
int *tag = atom->tag;
int *type = atom->type;
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
m = n = 0;
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
buf[m++] = type[i];
if (domain->triclinic) {
buf[m++] = x[i][0] + ix * xprd + iy * xy + iz * xz;
buf[m++] = x[i][1] + iy * yprd + iz * yz;
buf[m++] = x[i][2] + iz * zprd;
} else {
buf[m++] = x[i][0] + ix * xprd;
buf[m++] = x[i][1] + iy * yprd;
buf[m++] = x[i][2] + iz * zprd;
}
if (atom->molecule_flag) buf[m++] = atom->molecule[i];
if (atom->q_flag) buf[m++] = atom->q[i];
if (atom->rmass_flag) buf[m++] = atom->mass[i];
if (atom->radius_flag) buf[m++] = atom->radius[i];
ids[n++] = tag[i];
}
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = type[i];
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
if (atom->molecule_flag) buf[m++] = atom->molecule[i];
if (atom->q_flag) buf[m++] = atom->q[i];
if (atom->rmass_flag) buf[m++] = atom->mass[i];
if (atom->radius_flag) buf[m++] = atom->radius[i];
ids[n++] = tag[i];
}
}
}
/* ---------------------------------------------------------------------- */
void DumpMolfile::write_data(int n, double *mybuf)
{
if (me == 0) {
// copy buf atom coords into global arrays
int m = 0;
for (int i = 0; i < n; i++) {
types[ntotal] = static_cast<int>(mybuf[m++]);
coords[3*ntotal + 0] = mybuf[m++];
coords[3*ntotal + 1] = mybuf[m++];
coords[3*ntotal + 2] = mybuf[m++];
if (atom->molecule_flag) molids[ntotal] = static_cast<int>(mybuf[m++]);
if (atom->q_flag) charges[ntotal] = mybuf[m++];
if (atom->rmass_flag) masses[ntotal] = mybuf[m++];
if (atom->radius_flag) radiuses[ntotal] = mybuf[m++];
++ntotal;
}
// if last chunk of atoms in this snapshot, write global arrays to file
if (ntotal == natoms) {
ntotal = 0;
if (need_structure) {
mf->property(MFI::P_NAME,types,typenames);
if (atom->molecule_flag)
mf->property(MFI::P_RESI,molids);
if (atom->rmass_flag) {
mf->property(MFI::P_MASS,masses);
} else {
mf->property(MFI::P_MASS,types,atom->mass);
}
if (atom->q_flag)
mf->property(MFI::P_CHRG,charges);
if (atom->radius_flag)
mf->property(MFI::P_RADS,radiuses);
// update/write structure information in plugin
mf->structure();
need_structure = 0;
}
double simtime = update->ntimestep * update->dt;
mf->timestep(coords,NULL,cell,&simtime);
}
}
}
/* ---------------------------------------------------------------------- */
int DumpMolfile::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"unwrap") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"yes") == 0) unwrap_flag = 1;
else if (strcmp(arg[1],"no") == 0) unwrap_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
return 2;
} else if (strcmp(arg[0],"element") == 0) {
if (narg < ntypes+1)
error->all(FLERR, "Dump modify element names do not match atom types");
if (typenames) {
for (int i = 1; i <= ntypes; i++)
delete [] typenames[i];
delete [] typenames;
typenames = NULL;
}
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
int n = strlen(arg[itype]) + 1;
typenames[itype] = new char[n];
strcpy(typenames[itype],arg[itype]);
}
return ntypes+1;
}
return 0;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory in buf and global coords array
------------------------------------------------------------------------- */
bigint DumpMolfile::memory_usage()
{
bigint bytes = Dump::memory_usage();
bytes += memory->usage(coords,natoms*3);
bytes += sizeof(MFI);
return bytes;
}
diff --git a/src/USER-OMP/thr_omp.cpp b/src/USER-OMP/thr_omp.cpp
index 4462f70bf..2a07fcdbd 100644
--- a/src/USER-OMP/thr_omp.cpp
+++ b/src/USER-OMP/thr_omp.cpp
@@ -1,1179 +1,1183 @@
/* -------------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
OpenMP based threading support for LAMMPS
Contributing author: Axel Kohlmeyer (Temple U)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include "atom.h"
#include "comm.h"
#include "error.h"
#include "force.h"
#include "memory.h"
#include "modify.h"
#include "neighbor.h"
#include "timer.h"
#include "thr_omp.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "kspace.h"
#include "math_const.h"
#include <string.h>
using namespace LAMMPS_NS;
using namespace MathConst;
/* ---------------------------------------------------------------------- */
ThrOMP::ThrOMP(LAMMPS *ptr, int style)
: lmp(ptr), fix(NULL), thr_style(style), thr_error(0)
{
// register fix omp with this class
int ifix = lmp->modify->find_fix("package_omp");
if (ifix < 0)
lmp->error->all(FLERR,"The 'package omp' command is required for /omp styles");
fix = static_cast<FixOMP *>(lmp->modify->fix[ifix]);
}
/* ---------------------------------------------------------------------- */
ThrOMP::~ThrOMP()
{
// nothing to do?
}
/* ----------------------------------------------------------------------
Hook up per thread per atom arrays into the tally infrastructure
---------------------------------------------------------------------- */
void ThrOMP::ev_setup_thr(int eflag, int vflag, int nall, double *eatom,
double **vatom, ThrData *thr)
{
const int tid = thr->get_tid();
if (tid == 0) thr_error = 0;
if (thr_style & THR_PAIR) {
if (eflag & 2) {
thr->eatom_pair = eatom + tid*nall;
if (nall > 0)
memset(&(thr->eatom_pair[0]),0,nall*sizeof(double));
}
if (vflag & 4) {
thr->vatom_pair = vatom + tid*nall;
if (nall > 0)
memset(&(thr->vatom_pair[0][0]),0,nall*6*sizeof(double));
}
}
if (thr_style & THR_BOND) {
if (eflag & 2) {
thr->eatom_bond = eatom + tid*nall;
if (nall > 0)
memset(&(thr->eatom_bond[0]),0,nall*sizeof(double));
}
if (vflag & 4) {
thr->vatom_bond = vatom + tid*nall;
if (nall > 0)
memset(&(thr->vatom_bond[0][0]),0,nall*6*sizeof(double));
}
}
if (thr_style & THR_ANGLE) {
if (eflag & 2) {
thr->eatom_angle = eatom + tid*nall;
if (nall > 0)
memset(&(thr->eatom_angle[0]),0,nall*sizeof(double));
}
if (vflag & 4) {
thr->vatom_angle = vatom + tid*nall;
if (nall > 0)
memset(&(thr->vatom_angle[0][0]),0,nall*6*sizeof(double));
}
}
if (thr_style & THR_DIHEDRAL) {
if (eflag & 2) {
thr->eatom_dihed = eatom + tid*nall;
if (nall > 0)
memset(&(thr->eatom_dihed[0]),0,nall*sizeof(double));
}
if (vflag & 4) {
thr->vatom_dihed = vatom + tid*nall;
if (nall > 0)
memset(&(thr->vatom_dihed[0][0]),0,nall*6*sizeof(double));
}
}
if (thr_style & THR_IMPROPER) {
if (eflag & 2) {
thr->eatom_imprp = eatom + tid*nall;
if (nall > 0)
memset(&(thr->eatom_imprp[0]),0,nall*sizeof(double));
}
if (vflag & 4) {
thr->vatom_imprp = vatom + tid*nall;
if (nall > 0)
memset(&(thr->vatom_imprp[0][0]),0,nall*6*sizeof(double));
}
}
// nothing to do for THR_KSPACE
}
/* ----------------------------------------------------------------------
Reduce per thread data into the regular structures
Reduction of global properties is serialized with a "critical"
directive, so that only one thread at a time will access the
global variables. Since we are not synchronized, this should
come with little overhead. The reduction of per-atom properties
in contrast is parallelized over threads in the same way as forces.
---------------------------------------------------------------------- */
void ThrOMP::reduce_thr(void *style, const int eflag, const int vflag,
ThrData *const thr)
{
const int nlocal = lmp->atom->nlocal;
const int nghost = lmp->atom->nghost;
const int nall = nlocal + nghost;
const int nfirst = lmp->atom->nfirst;
const int nthreads = lmp->comm->nthreads;
const int evflag = eflag | vflag;
const int tid = thr->get_tid();
double **f = lmp->atom->f;
double **x = lmp->atom->x;
int need_force_reduce = 1;
if (evflag)
sync_threads();
switch (thr_style) {
case THR_PAIR: {
Pair * const pair = lmp->force->pair;
if (pair->vflag_fdotr) {
// this is a non-hybrid pair style. compute per thread fdotr
if (fix->last_pair_hybrid == NULL) {
if (lmp->neighbor->includegroup == 0)
thr->virial_fdotr_compute(x, nlocal, nghost, -1);
else
thr->virial_fdotr_compute(x, nlocal, nghost, nfirst);
} else {
if (style == fix->last_pair_hybrid) {
// pair_style hybrid will compute fdotr for us
// but we first need to reduce the forces
data_reduce_thr(&(f[0][0]), nall, nthreads, 3, tid);
fix->did_reduce();
need_force_reduce = 0;
}
}
}
if (evflag) {
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
pair->eng_vdwl += thr->eng_vdwl;
pair->eng_coul += thr->eng_coul;
thr->eng_vdwl = 0.0;
thr->eng_coul = 0.0;
}
if (vflag & 3)
for (int i=0; i < 6; ++i) {
pair->virial[i] += thr->virial_pair[i];
thr->virial_pair[i] = 0.0;
}
}
if (eflag & 2) {
data_reduce_thr(&(pair->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(pair->vatom[0][0]), nall, nthreads, 6, tid);
}
}
}
break;
case THR_BOND:
if (evflag) {
Bond * const bond = lmp->force->bond;
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
bond->energy += thr->eng_bond;
thr->eng_bond = 0.0;
}
if (vflag & 3) {
for (int i=0; i < 6; ++i) {
bond->virial[i] += thr->virial_bond[i];
thr->virial_bond[i] = 0.0;
}
}
}
if (eflag & 2) {
data_reduce_thr(&(bond->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(bond->vatom[0][0]), nall, nthreads, 6, tid);
}
}
break;
case THR_ANGLE:
if (evflag) {
Angle * const angle = lmp->force->angle;
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
angle->energy += thr->eng_angle;
thr->eng_angle = 0.0;
}
if (vflag & 3) {
for (int i=0; i < 6; ++i) {
angle->virial[i] += thr->virial_angle[i];
thr->virial_angle[i] = 0.0;
}
}
}
if (eflag & 2) {
data_reduce_thr(&(angle->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(angle->vatom[0][0]), nall, nthreads, 6, tid);
}
}
break;
case THR_DIHEDRAL:
if (evflag) {
Dihedral * const dihedral = lmp->force->dihedral;
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
dihedral->energy += thr->eng_dihed;
thr->eng_dihed = 0.0;
}
if (vflag & 3) {
for (int i=0; i < 6; ++i) {
dihedral->virial[i] += thr->virial_dihed[i];
thr->virial_dihed[i] = 0.0;
}
}
}
if (eflag & 2) {
data_reduce_thr(&(dihedral->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(dihedral->vatom[0][0]), nall, nthreads, 6, tid);
}
}
break;
case THR_DIHEDRAL|THR_CHARMM: // special case for CHARMM dihedrals
if (evflag) {
Dihedral * const dihedral = lmp->force->dihedral;
Pair * const pair = lmp->force->pair;
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
dihedral->energy += thr->eng_dihed;
pair->eng_vdwl += thr->eng_vdwl;
pair->eng_coul += thr->eng_coul;
thr->eng_dihed = 0.0;
thr->eng_vdwl = 0.0;
thr->eng_coul = 0.0;
}
if (vflag & 3) {
for (int i=0; i < 6; ++i) {
dihedral->virial[i] += thr->virial_dihed[i];
pair->virial[i] += thr->virial_pair[i];
thr->virial_dihed[i] = 0.0;
thr->virial_pair[i] = 0.0;
}
}
}
if (eflag & 2) {
data_reduce_thr(&(dihedral->eatom[0]), nall, nthreads, 1, tid);
data_reduce_thr(&(pair->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(dihedral->vatom[0][0]), nall, nthreads, 6, tid);
data_reduce_thr(&(pair->vatom[0][0]), nall, nthreads, 6, tid);
}
}
break;
case THR_IMPROPER:
if (evflag) {
Improper *improper = lmp->force->improper;
#if defined(_OPENMP)
#pragma omp critical
#endif
{
if (eflag & 1) {
improper->energy += thr->eng_imprp;
thr->eng_imprp = 0.0;
}
if (vflag & 3) {
for (int i=0; i < 6; ++i) {
improper->virial[i] += thr->virial_imprp[i];
thr->virial_imprp[i] = 0.0;
}
}
}
if (eflag & 2) {
data_reduce_thr(&(improper->eatom[0]), nall, nthreads, 1, tid);
}
if (vflag & 4) {
data_reduce_thr(&(improper->vatom[0][0]), nall, nthreads, 6, tid);
}
}
break;
case THR_KSPACE:
// nothing to do. XXX may need to add support for per-atom info
break;
case THR_INTGR:
// nothing to do
break;
default:
printf("tid:%d unhandled thr_style case %d\n", tid, thr_style);
break;
}
if (style == fix->last_omp_style) {
if (need_force_reduce) {
data_reduce_thr(&(f[0][0]), nall, nthreads, 3, tid);
fix->did_reduce();
}
if (lmp->atom->torque)
data_reduce_thr(&(lmp->atom->torque[0][0]), nall, nthreads, 3, tid);
}
thr->timer(Timer::COMM);
}
/* ----------------------------------------------------------------------
tally eng_vdwl and eng_coul into per thread global and per-atom accumulators
------------------------------------------------------------------------- */
void ThrOMP::e_tally_thr(Pair * const pair, const int i, const int j,
const int nlocal, const int newton_pair,
const double evdwl, const double ecoul, ThrData * const thr)
{
if (pair->eflag_global) {
if (newton_pair) {
thr->eng_vdwl += evdwl;
thr->eng_coul += ecoul;
} else {
const double evdwlhalf = 0.5*evdwl;
const double ecoulhalf = 0.5*ecoul;
if (i < nlocal) {
thr->eng_vdwl += evdwlhalf;
thr->eng_coul += ecoulhalf;
}
if (j < nlocal) {
thr->eng_vdwl += evdwlhalf;
thr->eng_coul += ecoulhalf;
}
}
}
if (pair->eflag_atom) {
const double epairhalf = 0.5 * (evdwl + ecoul);
if (newton_pair || i < nlocal) thr->eatom_pair[i] += epairhalf;
if (newton_pair || j < nlocal) thr->eatom_pair[j] += epairhalf;
}
}
/* helper functions */
static void v_tally(double * const vout, const double * const vin)
{
vout[0] += vin[0];
vout[1] += vin[1];
vout[2] += vin[2];
vout[3] += vin[3];
vout[4] += vin[4];
vout[5] += vin[5];
}
static void v_tally(double * const vout, const double scale, const double * const vin)
{
vout[0] += scale*vin[0];
vout[1] += scale*vin[1];
vout[2] += scale*vin[2];
vout[3] += scale*vin[3];
vout[4] += scale*vin[4];
vout[5] += scale*vin[5];
}
/* ----------------------------------------------------------------------
tally virial into per thread global and per-atom accumulators
------------------------------------------------------------------------- */
void ThrOMP::v_tally_thr(Pair * const pair, const int i, const int j,
const int nlocal, const int newton_pair,
const double * const v, ThrData * const thr)
{
if (pair->vflag_global) {
double * const va = thr->virial_pair;
if (newton_pair) {
v_tally(va,v);
} else {
if (i < nlocal) v_tally(va,0.5,v);
if (j < nlocal) v_tally(va,0.5,v);
}
}
if (pair->vflag_atom) {
if (newton_pair || i < nlocal) {
double * const va = thr->vatom_pair[i];
v_tally(va,0.5,v);
}
if (newton_pair || j < nlocal) {
double * const va = thr->vatom_pair[j];
v_tally(va,0.5,v);
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into per thread global and per-atom accumulators
need i < nlocal test since called by bond_quartic and dihedral_charmm
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_thr(Pair * const pair, const int i, const int j, const int nlocal,
const int newton_pair, const double evdwl, const double ecoul,
const double fpair, const double delx, const double dely,
const double delz, ThrData * const thr)
{
if (pair->eflag_either)
e_tally_thr(pair, i, j, nlocal, newton_pair, evdwl, ecoul, thr);
if (pair->vflag_either) {
double v[6];
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;
v_tally_thr(pair, i, j, nlocal, newton_pair, v, thr);
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
for virial, have delx,dely,delz and fx,fy,fz
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_xyz_thr(Pair * const pair, const int i, const int j,
const int nlocal, const int newton_pair,
const double evdwl, const double ecoul,
const double fx, const double fy, const double fz,
const double delx, const double dely, const double delz,
ThrData * const thr)
{
if (pair->eflag_either)
e_tally_thr(pair, i, j, nlocal, newton_pair, evdwl, ecoul, thr);
if (pair->vflag_either) {
double v[6];
v[0] = delx*fx;
v[1] = dely*fy;
v[2] = delz*fz;
v[3] = delx*fy;
v[4] = delx*fz;
v[5] = dely*fz;
v_tally_thr(pair, i, j, nlocal, newton_pair, v, thr);
}
}
/* ----------------------------------------------------------------------
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 ThrOMP::ev_tally3_thr(Pair * const pair, const int i, const int j, const int k,
const double evdwl, const double ecoul,
const double * const fj, const double * const fk,
const double * const drji, const double * const drki,
ThrData * const thr)
{
if (pair->eflag_either) {
if (pair->eflag_global) {
thr->eng_vdwl += evdwl;
thr->eng_coul += ecoul;
}
if (pair->eflag_atom) {
const double epairthird = THIRD * (evdwl + ecoul);
thr->eatom_pair[i] += epairthird;
thr->eatom_pair[j] += epairthird;
thr->eatom_pair[k] += epairthird;
}
}
if (pair->vflag_either) {
double v[6];
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 (pair->vflag_global) v_tally(thr->virial_pair,v);
if (pair->vflag_atom) {
v_tally(thr->vatom_pair[i],THIRD,v);
v_tally(thr->vatom_pair[j],THIRD,v);
v_tally(thr->vatom_pair[k],THIRD,v);
}
}
}
/* ----------------------------------------------------------------------
tally eng_vdwl and virial into global and per-atom accumulators
called by AIREBO potential, newton_pair is always on
------------------------------------------------------------------------- */
void ThrOMP::ev_tally4_thr(Pair * const pair, const int i, const int j,
const int k, const int m, const double evdwl,
const double * const fi, const double * const fj,
const double * const fk, const double * const drim,
const double * const drjm, const double * const drkm,
ThrData * const thr)
{
double v[6];
if (pair->eflag_either) {
if (pair->eflag_global) thr->eng_vdwl += evdwl;
if (pair->eflag_atom) {
const double epairfourth = 0.25 * evdwl;
thr->eatom_pair[i] += epairfourth;
thr->eatom_pair[j] += epairfourth;
thr->eatom_pair[k] += epairfourth;
thr->eatom_pair[m] += epairfourth;
}
}
if (pair->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]);
v_tally(thr->vatom_pair[i],v);
v_tally(thr->vatom_pair[j],v);
v_tally(thr->vatom_pair[k],v);
v_tally(thr->vatom_pair[m],v);
}
}
/* ----------------------------------------------------------------------
tally ecoul and virial into each of n atoms in list
called by TIP4P potential, newton_pair is always on
changes v values by dividing by n
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_list_thr(Pair * const pair, const int key,
const int * const list, const double * const v,
const double ecoul, const double alpha,
ThrData * const thr)
{
int i;
if (pair->eflag_either) {
if (pair->eflag_global) thr->eng_coul += ecoul;
if (pair->eflag_atom) {
if (key == 0) {
thr->eatom_pair[list[0]] += 0.5*ecoul;
thr->eatom_pair[list[1]] += 0.5*ecoul;
} else if (key == 1) {
thr->eatom_pair[list[0]] += 0.5*ecoul*(1-alpha);
thr->eatom_pair[list[1]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[2]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[3]] += 0.5*ecoul;
} else if (key == 2) {
thr->eatom_pair[list[0]] += 0.5*ecoul;
thr->eatom_pair[list[1]] += 0.5*ecoul*(1-alpha);
thr->eatom_pair[list[2]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[3]] += 0.25*ecoul*alpha;
} else {
thr->eatom_pair[list[0]] += 0.5*ecoul*(1-alpha);
thr->eatom_pair[list[1]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[2]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[3]] += 0.5*ecoul*(1-alpha);
thr->eatom_pair[list[4]] += 0.25*ecoul*alpha;
thr->eatom_pair[list[5]] += 0.25*ecoul*alpha;
}
}
}
if (pair->vflag_either) {
if (pair->vflag_global)
v_tally(thr->virial_pair,v);
if (pair->vflag_atom) {
if (key == 0) {
for (i = 0; i <= 5; i++) {
thr->vatom_pair[list[0]][i] += 0.5*v[i];
thr->vatom_pair[list[1]][i] += 0.5*v[i];
}
} else if (key == 1) {
for (i = 0; i <= 5; i++) {
thr->vatom_pair[list[0]][i] += 0.5*v[i]*(1-alpha);
thr->vatom_pair[list[1]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[2]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[3]][i] += 0.5*v[i];
}
} else if (key == 2) {
for (i = 0; i <= 5; i++) {
thr->vatom_pair[list[0]][i] += 0.5*v[i];
thr->vatom_pair[list[1]][i] += 0.5*v[i]*(1-alpha);
thr->vatom_pair[list[2]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[3]][i] += 0.25*v[i]*alpha;
}
} else {
for (i = 0; i <= 5; i++) {
thr->vatom_pair[list[0]][i] += 0.5*v[i]*(1-alpha);
thr->vatom_pair[list[1]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[2]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[3]][i] += 0.5*v[i]*(1-alpha);
thr->vatom_pair[list[4]][i] += 0.25*v[i]*alpha;
thr->vatom_pair[list[5]][i] += 0.25*v[i]*alpha;
}
}
}
}
}
/* ----------------------------------------------------------------------
tally energy and virial into global and per-atom accumulators
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_thr(Bond * const bond, const int i, const int j, const int nlocal,
const int newton_bond, const double ebond, const double fbond,
const double delx, const double dely, const double delz,
ThrData * const thr)
{
if (bond->eflag_either) {
const double ebondhalf = 0.5*ebond;
if (newton_bond) {
if (bond->eflag_global)
thr->eng_bond += ebond;
if (bond->eflag_atom) {
thr->eatom_bond[i] += ebondhalf;
thr->eatom_bond[j] += ebondhalf;
}
} else {
if (bond->eflag_global) {
if (i < nlocal) thr->eng_bond += ebondhalf;
if (j < nlocal) thr->eng_bond += ebondhalf;
}
if (bond->eflag_atom) {
if (i < nlocal) thr->eatom_bond[i] += ebondhalf;
if (j < nlocal) thr->eatom_bond[j] += ebondhalf;
}
}
}
if (bond->vflag_either) {
double v[6];
v[0] = delx*delx*fbond;
v[1] = dely*dely*fbond;
v[2] = delz*delz*fbond;
v[3] = delx*dely*fbond;
v[4] = delx*delz*fbond;
v[5] = dely*delz*fbond;
if (bond->vflag_global) {
if (newton_bond)
v_tally(thr->virial_bond,v);
else {
if (i < nlocal)
v_tally(thr->virial_bond,0.5,v);
if (j < nlocal)
v_tally(thr->virial_bond,0.5,v);
}
}
if (bond->vflag_atom) {
v[0] *= 0.5;
v[1] *= 0.5;
v[2] *= 0.5;
v[3] *= 0.5;
v[4] *= 0.5;
v[5] *= 0.5;
if (newton_bond) {
v_tally(thr->vatom_bond[i],v);
v_tally(thr->vatom_bond[j],v);
} else {
if (j < nlocal)
v_tally(thr->vatom_bond[i],v);
if (j < nlocal)
v_tally(thr->vatom_bond[j],v);
}
}
}
}
/* ----------------------------------------------------------------------
tally energy and virial into global and per-atom accumulators
virial = r1F1 + r2F2 + r3F3 = (r1-r2) F1 + (r3-r2) F3 = del1*f1 + del2*f3
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_thr(Angle * const angle, const int i, const int j, const int k,
const int nlocal, const int newton_bond, const double eangle,
const double * const f1, const double * const f3,
const double delx1, const double dely1, const double delz1,
const double delx2, const double dely2, const double delz2,
ThrData * const thr)
{
if (angle->eflag_either) {
const double eanglethird = THIRD*eangle;
if (newton_bond) {
if (angle->eflag_global)
thr->eng_angle += eangle;
if (angle->eflag_atom) {
thr->eatom_angle[i] += eanglethird;
thr->eatom_angle[j] += eanglethird;
thr->eatom_angle[k] += eanglethird;
}
} else {
if (angle->eflag_global) {
if (i < nlocal) thr->eng_angle += eanglethird;
if (j < nlocal) thr->eng_angle += eanglethird;
if (k < nlocal) thr->eng_angle += eanglethird;
}
if (angle->eflag_atom) {
if (i < nlocal) thr->eatom_angle[i] += eanglethird;
if (j < nlocal) thr->eatom_angle[j] += eanglethird;
if (k < nlocal) thr->eatom_angle[k] += eanglethird;
}
}
}
if (angle->vflag_either) {
double v[6];
v[0] = delx1*f1[0] + delx2*f3[0];
v[1] = dely1*f1[1] + dely2*f3[1];
v[2] = delz1*f1[2] + delz2*f3[2];
v[3] = delx1*f1[1] + delx2*f3[1];
v[4] = delx1*f1[2] + delx2*f3[2];
v[5] = dely1*f1[2] + dely2*f3[2];
if (angle->vflag_global) {
if (newton_bond) {
v_tally(thr->virial_angle,v);
} else {
int cnt = 0;
if (i < nlocal) ++cnt;
if (j < nlocal) ++cnt;
if (k < nlocal) ++cnt;
v_tally(thr->virial_angle,cnt*THIRD,v);
}
}
if (angle->vflag_atom) {
v[0] *= THIRD;
v[1] *= THIRD;
v[2] *= THIRD;
v[3] *= THIRD;
v[4] *= THIRD;
v[5] *= THIRD;
if (newton_bond) {
v_tally(thr->vatom_angle[i],v);
v_tally(thr->vatom_angle[j],v);
v_tally(thr->vatom_angle[k],v);
} else {
if (j < nlocal) v_tally(thr->vatom_angle[i],v);
if (j < nlocal) v_tally(thr->vatom_angle[j],v);
if (k < nlocal) v_tally(thr->vatom_angle[k],v);
}
}
}
}
/* ----------------------------------------------------------------------
tally energy and virial from 1-3 repulsion of SDK angle into accumulators
------------------------------------------------------------------------- */
void ThrOMP::ev_tally13_thr(Angle * const angle, const int i1, const int i3,
const int nlocal, const int newton_bond,
const double epair, const double fpair,
const double delx, const double dely,
const double delz, ThrData * const thr)
{
if (angle->eflag_either) {
const double epairhalf = 0.5 * epair;
if (angle->eflag_global) {
if (newton_bond || i1 < nlocal)
thr->eng_angle += epairhalf;
if (newton_bond || i3 < nlocal)
thr->eng_angle += epairhalf;
}
if (angle->eflag_atom) {
if (newton_bond || i1 < nlocal) thr->eatom_angle[i1] += epairhalf;
if (newton_bond || i3 < nlocal) thr->eatom_angle[i3] += epairhalf;
}
}
if (angle->vflag_either) {
double v[6];
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 (angle->vflag_global) {
double * const va = thr->virial_angle;
if (newton_bond || i1 < nlocal) v_tally(va,0.5,v);
if (newton_bond || i3 < nlocal) v_tally(va,0.5,v);
}
if (angle->vflag_atom) {
if (newton_bond || i1 < nlocal) {
double * const va = thr->vatom_angle[i1];
v_tally(va,0.5,v);
}
if (newton_bond || i3 < nlocal) {
double * const va = thr->vatom_angle[i3];
v_tally(va,0.5,v);
}
}
}
}
/* ----------------------------------------------------------------------
tally energy and virial into global and per-atom accumulators
virial = r1F1 + r2F2 + r3F3 + r4F4 = (r1-r2) F1 + (r3-r2) F3 + (r4-r2) F4
= (r1-r2) F1 + (r3-r2) F3 + (r4-r3 + r3-r2) F4
= vb1*f1 + vb2*f3 + (vb3+vb2)*f4
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_thr(Dihedral * const dihed, const int i1, const int i2,
const int i3, const int i4, const int nlocal,
const int newton_bond, const double edihedral,
const double * const f1, const double * const f3,
const double * const f4, const double vb1x,
const double vb1y, const double vb1z, const double vb2x,
const double vb2y, const double vb2z, const double vb3x,
const double vb3y, const double vb3z, ThrData * const thr)
{
if (dihed->eflag_either) {
if (dihed->eflag_global) {
if (newton_bond) {
thr->eng_dihed += edihedral;
} else {
const double edihedralquarter = 0.25*edihedral;
int cnt = 0;
if (i1 < nlocal) ++cnt;
if (i2 < nlocal) ++cnt;
if (i3 < nlocal) ++cnt;
if (i4 < nlocal) ++cnt;
thr->eng_dihed += static_cast<double>(cnt)*edihedralquarter;
}
}
if (dihed->eflag_atom) {
const double edihedralquarter = 0.25*edihedral;
if (newton_bond) {
thr->eatom_dihed[i1] += edihedralquarter;
thr->eatom_dihed[i2] += edihedralquarter;
thr->eatom_dihed[i3] += edihedralquarter;
thr->eatom_dihed[i4] += edihedralquarter;
} else {
if (i1 < nlocal) thr->eatom_dihed[i1] += edihedralquarter;
if (i2 < nlocal) thr->eatom_dihed[i2] += edihedralquarter;
if (i3 < nlocal) thr->eatom_dihed[i3] += edihedralquarter;
if (i4 < nlocal) thr->eatom_dihed[i4] += edihedralquarter;
}
}
}
if (dihed->vflag_either) {
double v[6];
v[0] = vb1x*f1[0] + vb2x*f3[0] + (vb3x+vb2x)*f4[0];
v[1] = vb1y*f1[1] + vb2y*f3[1] + (vb3y+vb2y)*f4[1];
v[2] = vb1z*f1[2] + vb2z*f3[2] + (vb3z+vb2z)*f4[2];
v[3] = vb1x*f1[1] + vb2x*f3[1] + (vb3x+vb2x)*f4[1];
v[4] = vb1x*f1[2] + vb2x*f3[2] + (vb3x+vb2x)*f4[2];
v[5] = vb1y*f1[2] + vb2y*f3[2] + (vb3y+vb2y)*f4[2];
if (dihed->vflag_global) {
if (newton_bond) {
v_tally(thr->virial_dihed,v);
} else {
int cnt = 0;
if (i1 < nlocal) ++cnt;
if (i2 < nlocal) ++cnt;
if (i3 < nlocal) ++cnt;
if (i4 < nlocal) ++cnt;
v_tally(thr->virial_dihed,0.25*static_cast<double>(cnt),v);
}
}
v[0] *= 0.25;
v[1] *= 0.25;
v[2] *= 0.25;
v[3] *= 0.25;
v[4] *= 0.25;
v[5] *= 0.25;
if (dihed->vflag_atom) {
if (newton_bond) {
v_tally(thr->vatom_dihed[i1],v);
v_tally(thr->vatom_dihed[i2],v);
v_tally(thr->vatom_dihed[i3],v);
v_tally(thr->vatom_dihed[i4],v);
} else {
if (i1 < nlocal) v_tally(thr->vatom_dihed[i1],v);
if (i2 < nlocal) v_tally(thr->vatom_dihed[i2],v);
if (i3 < nlocal) v_tally(thr->vatom_dihed[i3],v);
if (i4 < nlocal) v_tally(thr->vatom_dihed[i4],v);
}
}
}
}
/* ----------------------------------------------------------------------
tally energy and virial into global and per-atom accumulators
virial = r1F1 + r2F2 + r3F3 + r4F4 = (r1-r2) F1 + (r3-r2) F3 + (r4-r2) F4
= (r1-r2) F1 + (r3-r2) F3 + (r4-r3 + r3-r2) F4
= vb1*f1 + vb2*f3 + (vb3+vb2)*f4
------------------------------------------------------------------------- */
void ThrOMP::ev_tally_thr(Improper * const imprp, const int i1, const int i2,
const int i3, const int i4, const int nlocal,
const int newton_bond, const double eimproper,
const double * const f1, const double * const f3,
const double * const f4, const double vb1x,
const double vb1y, const double vb1z, const double vb2x,
const double vb2y, const double vb2z, const double vb3x,
const double vb3y, const double vb3z, ThrData * const thr)
{
if (imprp->eflag_either) {
if (imprp->eflag_global) {
if (newton_bond) {
thr->eng_imprp += eimproper;
} else {
const double eimproperquarter = 0.25*eimproper;
int cnt = 0;
if (i1 < nlocal) ++cnt;
if (i2 < nlocal) ++cnt;
if (i3 < nlocal) ++cnt;
if (i4 < nlocal) ++cnt;
thr->eng_imprp += static_cast<double>(cnt)*eimproperquarter;
}
}
if (imprp->eflag_atom) {
const double eimproperquarter = 0.25*eimproper;
if (newton_bond) {
thr->eatom_imprp[i1] += eimproperquarter;
thr->eatom_imprp[i2] += eimproperquarter;
thr->eatom_imprp[i3] += eimproperquarter;
thr->eatom_imprp[i4] += eimproperquarter;
} else {
if (i1 < nlocal) thr->eatom_imprp[i1] += eimproperquarter;
if (i2 < nlocal) thr->eatom_imprp[i2] += eimproperquarter;
if (i3 < nlocal) thr->eatom_imprp[i3] += eimproperquarter;
if (i4 < nlocal) thr->eatom_imprp[i4] += eimproperquarter;
}
}
}
if (imprp->vflag_either) {
double v[6];
v[0] = vb1x*f1[0] + vb2x*f3[0] + (vb3x+vb2x)*f4[0];
v[1] = vb1y*f1[1] + vb2y*f3[1] + (vb3y+vb2y)*f4[1];
v[2] = vb1z*f1[2] + vb2z*f3[2] + (vb3z+vb2z)*f4[2];
v[3] = vb1x*f1[1] + vb2x*f3[1] + (vb3x+vb2x)*f4[1];
v[4] = vb1x*f1[2] + vb2x*f3[2] + (vb3x+vb2x)*f4[2];
v[5] = vb1y*f1[2] + vb2y*f3[2] + (vb3y+vb2y)*f4[2];
if (imprp->vflag_global) {
if (newton_bond) {
v_tally(thr->virial_imprp,v);
} else {
int cnt = 0;
if (i1 < nlocal) ++cnt;
if (i2 < nlocal) ++cnt;
if (i3 < nlocal) ++cnt;
if (i4 < nlocal) ++cnt;
v_tally(thr->virial_imprp,0.25*static_cast<double>(cnt),v);
}
}
v[0] *= 0.25;
v[1] *= 0.25;
v[2] *= 0.25;
v[3] *= 0.25;
v[4] *= 0.25;
v[5] *= 0.25;
if (imprp->vflag_atom) {
if (newton_bond) {
v_tally(thr->vatom_imprp[i1],v);
v_tally(thr->vatom_imprp[i2],v);
v_tally(thr->vatom_imprp[i3],v);
v_tally(thr->vatom_imprp[i4],v);
} else {
if (i1 < nlocal) v_tally(thr->vatom_imprp[i1],v);
if (i2 < nlocal) v_tally(thr->vatom_imprp[i2],v);
if (i3 < nlocal) v_tally(thr->vatom_imprp[i3],v);
if (i4 < nlocal) v_tally(thr->vatom_imprp[i4],v);
}
}
}
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO potential, newton_pair is always on
fpair is magnitude of force on atom I
------------------------------------------------------------------------- */
void ThrOMP::v_tally2_thr(const int i, const int j, const double fpair,
const double * const drij, ThrData * const thr)
{
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;
v_tally(thr->vatom_pair[i],v);
v_tally(thr->vatom_pair[j],v);
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO and Tersoff potential, newton_pair is always on
------------------------------------------------------------------------- */
void ThrOMP::v_tally3_thr(const int i, const int j, const int k,
const double * const fi, const double * const fj,
const double * const drik, const double * const drjk,
ThrData * const thr)
{
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]);
v_tally(thr->vatom_pair[i],v);
v_tally(thr->vatom_pair[j],v);
v_tally(thr->vatom_pair[k],v);
}
/* ----------------------------------------------------------------------
tally virial into per-atom accumulators
called by AIREBO potential, newton_pair is always on
------------------------------------------------------------------------- */
void ThrOMP::v_tally4_thr(const int i, const int j, const int k, const int m,
const double * const fi, const double * const fj,
const double * const fk, const double * const drim,
const double * const drjm, const double * const drkm,
ThrData * const thr)
{
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]);
v_tally(thr->vatom_pair[i],v);
v_tally(thr->vatom_pair[j],v);
v_tally(thr->vatom_pair[k],v);
v_tally(thr->vatom_pair[m],v);
}
/* ---------------------------------------------------------------------- */
double ThrOMP::memory_usage_thr()
{
double bytes=0.0;
return bytes;
}
diff --git a/src/USER-PHONON/fix_phonon.cpp b/src/USER-PHONON/fix_phonon.cpp
index 907d2368f..f1f3e3f42 100644
--- a/src/USER-PHONON/fix_phonon.cpp
+++ b/src/USER-PHONON/fix_phonon.cpp
@@ -1,911 +1,915 @@
/* ----------------------------------------------------------------------
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:
Ling-Ti Kong
Contact:
School of Materials Science and Engineering,
Shanghai Jiao Tong University,
800 Dongchuan Road, Minhang,
Shanghai 200240, CHINA
konglt@sjtu.edu.cn; konglt@gmail.com
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include "string.h"
#include "fix_phonon.h"
#include "atom.h"
#include "compute.h"
#include "domain.h"
#include "fft3d_wrap.h"
#include "force.h"
#include "group.h"
#include "lattice.h"
#include "modify.h"
#include "update.h"
#include "citeme.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define INVOKED_SCALAR 1
#define INVOKED_VECTOR 2
#define MAXLINE 512
static const char cite_fix_phonon[] =
"fix phonon command:\n\n"
"@Article{Kong11,\n"
" author = {L. T. Kong},\n"
" title = {Phonon dispersion measured directly from molecular dynamics simulations},\n"
" journal = {Comp.~Phys.~Comm.},\n"
" year = 2011,\n"
" volume = 182,\n"
" pages = {2201--2207}\n"
"}\n\n";
/* ---------------------------------------------------------------------- */
FixPhonon::FixPhonon(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_phonon);
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
if (narg < 8) error->all(FLERR,"Illegal fix phonon command: number of arguments < 8");
nevery = force->inumeric(FLERR, arg[3]); // Calculate this fix every n steps!
if (nevery < 1) error->all(FLERR,"Illegal fix phonon command");
nfreq = force->inumeric(FLERR, arg[4]); // frequency to output result
if (nfreq < 1) error->all(FLERR,"Illegal fix phonon command");
waitsteps = ATOBIGINT(arg[5]); // Wait this many timesteps before actually measuring
if (waitsteps < 0) error->all(FLERR,"Illegal fix phonon command: waitsteps < 0 !");
int n = strlen(arg[6]) + 1; // map file
mapfile = new char[n];
strcpy(mapfile, arg[6]);
n = strlen(arg[7]) + 1; // prefix of output
prefix = new char[n];
strcpy(prefix, arg[7]);
logfile = new char[n+4];
sprintf(logfile,"%s.log",prefix);
int sdim = sysdim = domain->dimension;
int iarg = 8;
nasr = 20;
// other command line options
while (iarg < narg){
if (strcmp(arg[iarg],"sysdim") == 0){
if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options.");
sdim = force->inumeric(FLERR, arg[iarg]);
if (sdim < 1) error->all(FLERR,"Illegal fix phonon command: sysdim should not be less than 1.");
} else if (strcmp(arg[iarg],"nasr") == 0){
if (++iarg >= narg) error->all(FLERR,"Illegal fix phonon command: incomplete command line options.");
nasr = force->inumeric(FLERR, arg[iarg]);
} else {
error->all(FLERR,"Illegal fix phonon command: unknown option read!");
}
++iarg;
}
// get the dimension of the simulation; 1D is possible by specifying the option of "sysdim 1"
if (sdim < sysdim) sysdim = sdim;
nasr = MAX(0, nasr);
// get the total number of atoms in group
ngroup = static_cast<int>(group->count(igroup));
if (ngroup < 1) error->all(FLERR,"No atom found for fix phonon!");
// MPI gatherv related variables
recvcnts = new int[nprocs];
displs = new int[nprocs];
// mapping index
tag2surf.clear(); // clear map info
surf2tag.clear();
// get the mapping between lattice indices and atom IDs
readmap(); delete []mapfile;
if (nucell == 1) nasr = MIN(1,nasr);
// get the mass matrix for dynamic matrix
getmass();
// create FFT and allocate memory for FFT
// here the parallization is done on the x direction only
nxlo = 0;
int *nx_loc = new int [nprocs];
for (int i = 0; i < nprocs; ++i){
nx_loc[i] = nx/nprocs;
if (i < nx%nprocs) ++nx_loc[i];
}
for (int i = 0; i < me; ++i) nxlo += nx_loc[i];
nxhi = nxlo + nx_loc[me] - 1;
mynpt = nx_loc[me]*ny*nz;
mynq = mynpt;
fft_dim = nucell*sysdim;
fft_dim2 = fft_dim*fft_dim;
fft_nsend = mynpt*fft_dim;
fft_cnts = new int[nprocs];
fft_disp = new int[nprocs];
fft_disp[0] = 0;
for (int i = 0; i < nprocs; ++i) fft_cnts[i] = nx_loc[i]*ny*nz*fft_dim;
for (int i = 1; i < nprocs; ++i) fft_disp[i] = fft_disp[i-1]+fft_cnts[i-1];
delete []nx_loc;
fft = new FFT3d(lmp,world,nz,ny,nx,0,nz-1,0,ny-1,nxlo,nxhi,0,nz-1,0,ny-1,nxlo,nxhi,0,0,&mysize,0);
memory->create(fft_data, MAX(1,mynq)*2, "fix_phonon:fft_data");
// allocate variables; MAX(1,... is used because NULL buffer will result in error for MPI
memory->create(RIloc,ngroup,(sysdim+1),"fix_phonon:RIloc");
memory->create(RIall,ngroup,(sysdim+1),"fix_phonon:RIall");
memory->create(Rsort,ngroup, sysdim, "fix_phonon:Rsort");
memory->create(Rnow, MAX(1,mynpt),fft_dim,"fix_phonon:Rnow");
memory->create(Rsum, MAX(1,mynpt),fft_dim,"fix_phonon:Rsum");
memory->create(basis,nucell, sysdim, "fix_phonon:basis");
// because of hermit, only nearly half of q points are stored
memory->create(Rqnow,MAX(1,mynq),fft_dim, "fix_phonon:Rqnow");
memory->create(Rqsum,MAX(1,mynq),fft_dim2,"fix_phonon:Rqsum");
memory->create(Phi_q,MAX(1,mynq),fft_dim2,"fix_phonon:Phi_q");
// variable to collect all local Phi to root
if (me == 0) memory->create(Phi_all,ntotal,fft_dim2,"fix_phonon:Phi_all");
else memory->create(Phi_all,1,1,"fix_phonon:Phi_all");
// output some information on the system to log file
if (me == 0){
flog = fopen(logfile, "w");
if (flog == NULL) {
char str[MAXLINE];
sprintf(str,"Can not open output file %s",logfile);
error->one(FLERR,str);
}
for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n");
fprintf(flog,"# group name of the atoms under study : %s\n", group->names[igroup]);
fprintf(flog,"# total number of atoms in the group : %d\n", ngroup);
fprintf(flog,"# dimension of the system : %d D\n", sysdim);
fprintf(flog,"# number of atoms per unit cell : %d\n", nucell);
fprintf(flog,"# dimension of the FFT mesh : %d x %d x %d\n", nx, ny, nz);
fprintf(flog,"# number of wait steps before measurement : " BIGINT_FORMAT "\n", waitsteps);
fprintf(flog,"# frequency of the measurement : %d\n", nevery);
fprintf(flog,"# output result after this many measurement: %d\n", nfreq);
fprintf(flog,"# number of processors used by this run : %d\n", nprocs);
for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n");
fprintf(flog,"# mapping information between lattice index and atom id\n");
fprintf(flog,"# nx ny nz nucell\n");
fprintf(flog,"%d %d %d %d\n", nx, ny, nz, nucell);
fprintf(flog,"# l1 l2 l3 k atom_id\n");
int ix, iy, iz, iu;
for (idx = 0; idx < ngroup; ++idx){
itag = surf2tag[idx];
iu = idx%nucell;
iz = (idx/nucell)%nz;
iy = (idx/(nucell*nz))%ny;
ix = (idx/(nucell*nz*ny))%nx;
fprintf(flog,"%d %d %d %d %d\n", ix, iy, iz, iu, itag);
}
for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n");
fflush(flog);
}
surf2tag.clear();
// default temperature is from thermo
TempSum = new double[sysdim];
id_temp = new char[12];
strcpy(id_temp,"thermo_temp");
int icompute = modify->find_compute(id_temp);
temperature = modify->compute[icompute];
inv_nTemp = 1.0/group->count(temperature->igroup);
} // end of constructor
/* ---------------------------------------------------------------------- */
void FixPhonon::post_run()
{
// compute and output final results
if (ifreq > 0 && ifreq != nfreq) postprocess();
if (me == 0) fclose(flog);
}
/* ---------------------------------------------------------------------- */
FixPhonon::~FixPhonon()
{
// delete locally stored array
memory->destroy(RIloc);
memory->destroy(RIall);
memory->destroy(Rsort);
memory->destroy(Rnow);
memory->destroy(Rsum);
memory->destroy(basis);
memory->destroy(Rqnow);
memory->destroy(Rqsum);
memory->destroy(Phi_q);
memory->destroy(Phi_all);
delete []recvcnts;
delete []displs;
delete []prefix;
delete []logfile;
delete []fft_cnts;
delete []fft_disp;
delete []id_temp;
delete []TempSum;
delete []M_inv_sqrt;
delete []basetype;
// destroy FFT
delete fft;
memory->sfree(fft_data);
// clear map info
tag2surf.clear();
surf2tag.clear();
}
/* ---------------------------------------------------------------------- */
int FixPhonon::setmask()
{
int mask = 0;
mask |= END_OF_STEP;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixPhonon::init()
{
// warn if more than one fix-phonon
int count = 0;
for (int i = 0; i < modify->nfix; ++i) if (strcmp(modify->fix[i]->style,"gfc") == 0) ++count;
if (count > 1 && me == 0) error->warning(FLERR,"More than one fix phonon defined"); // just warn, but allowed.
}
/* ---------------------------------------------------------------------- */
void FixPhonon::setup(int flag)
{
// initialize accumulating variables
for (int i = 0; i < sysdim; ++i) TempSum[i] = 0.;
for (int i = 0; i < mynpt; ++i)
for (int j = 0; j < fft_dim; ++j) Rsum[i][j] = 0.;
for (int i =0; i < mynq; ++i)
for (int j =0; j < fft_dim2; ++j) Rqsum[i][j] = std::complex<double> (0.,0.);
for (int i = 0; i < 6; ++i) hsum[i] = 0.;
for (int i = 0; i < nucell; ++i)
for (int j = 0; j < sysdim; ++j) basis[i][j] = 0.;
prev_nstep = update->ntimestep;
neval = ifreq = 0;
}
/* ---------------------------------------------------------------------- */
void FixPhonon::end_of_step()
{
if ( (update->ntimestep-prev_nstep) <= waitsteps) return;
double **x = atom->x;
int *mask = atom->mask;
int *tag = atom->tag;
int *image = atom->image;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double *h = domain->h;
double xbox, ybox, zbox;
int i,idim,jdim,ndim;
double xcur[3];
// to get the current temperature
if (!(temperature->invoked_flag & INVOKED_VECTOR)) temperature->compute_vector();
for (idim = 0; idim < sysdim; ++idim) TempSum[idim] += temperature->vector[idim];
// evaluate R(r) on local proc
nfind = 0;
for (i = 0; i < nlocal; ++i){
if (mask[i] & groupbit){
itag = tag[i];
idx = tag2surf[itag];
domain->unmap(x[i], image[i], xcur);
for (idim = 0; idim < sysdim; ++idim) RIloc[nfind][idim] = xcur[idim];
RIloc[nfind++][sysdim] = double(idx);
}
}
// gather R(r) on local proc, then sort and redistribute to all procs for FFT
nfind *= (sysdim+1);
displs[0] = 0;
for (i = 0; i < nprocs; ++i) recvcnts[i] = 0;
MPI_Gather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,0,world);
for (i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1];
MPI_Gatherv(RIloc[0],nfind,MPI_DOUBLE,RIall[0],recvcnts,displs,MPI_DOUBLE,0,world);
if (me == 0){
for (i = 0; i < ngroup; ++i){
idx = static_cast<int>(RIall[i][sysdim]);
for (idim = 0; idim < sysdim; ++idim) Rsort[idx][idim] = RIall[i][idim];
}
}
MPI_Scatterv(Rsort[0],fft_cnts,fft_disp, MPI_DOUBLE, Rnow[0], fft_nsend, MPI_DOUBLE,0,world);
// get Rsum
for (idx = 0; idx < mynpt; ++idx)
for (idim = 0; idim < fft_dim; ++idim) Rsum[idx][idim] += Rnow[idx][idim];
// FFT R(r) to get R(q)
for (idim = 0; idim < fft_dim; ++idim){
int m=0;
for (idx = 0; idx < mynpt; ++idx){
fft_data[m++] = Rnow[idx][idim];
fft_data[m++] = 0.;
}
fft->compute(fft_data, fft_data, -1);
m = 0;
for (idq = 0; idq < mynq; ++idq){
Rqnow[idq][idim] = std::complex<double>(fft_data[m], fft_data[m+1]);
m += 2;
}
}
// to get sum(R(q).R(q)*)
for (idq = 0; idq < mynq; ++idq){
ndim = 0;
for (idim = 0; idim < fft_dim; ++idim)
for (jdim = 0; jdim < fft_dim; ++jdim) Rqsum[idq][ndim++] += Rqnow[idq][idim]*conj(Rqnow[idq][jdim]);
}
// get basis info
if (fft_dim > sysdim){
double dist2orig[3];
for (idx = 0; idx < mynpt; ++idx){
ndim = sysdim;
for (i = 1; i < nucell; ++i){
for (idim = 0; idim < sysdim; ++idim) dist2orig[idim] = Rnow[idx][ndim++] - Rnow[idx][idim];
domain->minimum_image(dist2orig);
for (idim = 0; idim < sysdim; ++idim) basis[i][idim] += dist2orig[idim];
}
}
}
// get lattice vector info
for (int i = 0; i < 6; ++i) hsum[i] += h[i];
// increment counter
++neval;
// compute and output Phi_q after every nfreq evaluations
if (++ifreq == nfreq) postprocess();
} // end of end_of_step()
/* ---------------------------------------------------------------------- */
double FixPhonon::memory_usage()
{
double bytes = sizeof(double)*2*mynq
+ sizeof(std::map<int,int>)*2*ngroup
+ sizeof(double)*(ngroup*(3*sysdim+2)+mynpt*fft_dim*2)
+ sizeof(std::complex<double>)*MAX(1,mynq)*fft_dim *(1+2*fft_dim)
+ sizeof(std::complex<double>)*ntotal*fft_dim2
+ sizeof(int) * nprocs * 4;
return bytes;
}
/* ---------------------------------------------------------------------- */
int FixPhonon::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all(FLERR,"Illegal fix_modify command");
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all(FLERR,"Could not find fix_modify temp ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all(FLERR,"Fix_modify temp ID does not compute temperature");
inv_nTemp = 1.0/group->count(temperature->igroup);
return 2;
}
return 0;
}
/* ----------------------------------------------------------------------
* private method, to get the mass matrix for dynamic matrix
* --------------------------------------------------------------------*/
void FixPhonon::getmass()
{
int nlocal = atom->nlocal;
int *mask = atom->mask;
int *tag = atom->tag;
int *type = atom->type;
double *rmass = atom->rmass;
double *mass = atom->mass;
double *mass_one, *mass_all;
double *type_one, *type_all;
mass_one = new double[nucell];
mass_all = new double[nucell];
type_one = new double[nucell];
type_all = new double[nucell];
for (int i = 0; i < nucell; ++i) mass_one[i] = type_one[i] = 0.;
if (rmass){
for (int i = 0; i < nlocal; ++i){
if (mask[i] & groupbit){
itag = tag[i];
idx = tag2surf[itag];
int iu = idx%nucell;
mass_one[iu] += rmass[i];
type_one[iu] += double(type[i]);
}
}
} else {
for (int i = 0; i < nlocal; ++i){
if (mask[i] & groupbit){
itag = tag[i];
idx = tag2surf[itag];
int iu = idx%nucell;
mass_one[iu] += mass[type[i]];
type_one[iu] += double(type[i]);
}
}
}
MPI_Allreduce(mass_one,mass_all,nucell,MPI_DOUBLE,MPI_SUM,world);
MPI_Allreduce(type_one,type_all,nucell,MPI_DOUBLE,MPI_SUM,world);
M_inv_sqrt = new double[nucell];
basetype = new int[nucell];
double inv_total = 1./double(ntotal);
for (int i = 0; i < nucell; ++i){
mass_all[i] *= inv_total;
M_inv_sqrt[i] = sqrt(1./mass_all[i]);
basetype[i] = int(type_all[i]*inv_total);
}
delete []mass_one;
delete []mass_all;
delete []type_one;
delete []type_all;
}
/* ----------------------------------------------------------------------
* private method, to read the mapping info from file
* --------------------------------------------------------------------*/
void FixPhonon::readmap()
{
int info = 0;
// auto-generate mapfile for "cluster" (gamma only system)
if (strcmp(mapfile, "GAMMA") == 0){
nx = ny = nz = ntotal = 1;
nucell = ngroup;
int *tag_loc, *tag_all;
memory->create(tag_loc,ngroup,"fix_phonon:tag_loc");
memory->create(tag_all,ngroup,"fix_phonon:tag_all");
// get atom IDs on local proc
int nfind = 0;
for (int i = 0; i < atom->nlocal; ++i){
if (atom->mask[i] & groupbit) tag_loc[nfind++] = atom->tag[i];
}
// gather IDs on local proc
displs[0] = 0;
for (int i = 0; i < nprocs; ++i) recvcnts[i] = 0;
MPI_Allgather(&nfind,1,MPI_INT,recvcnts,1,MPI_INT,world);
for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1];
MPI_Allgatherv(tag_loc,nfind,MPI_INT,tag_all,recvcnts,displs,MPI_INT,world);
for (int i = 0; i < ngroup; ++i){
itag = tag_all[i];
tag2surf[itag] = i;
surf2tag[i] = itag;
}
memory->destroy(tag_loc);
memory->destroy(tag_all);
return;
}
// read from map file for others
char line[MAXLINE];
FILE *fp = fopen(mapfile, "r");
if (fp == NULL){
sprintf(line,"Cannot open input map file %s", mapfile);
error->all(FLERR,line);
}
if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading header of mapping file!");
nx = force->inumeric(FLERR, strtok(line, " \n\t\r\f"));
ny = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
nz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
nucell = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
ntotal = nx*ny*nz;
if (ntotal*nucell != ngroup) error->all(FLERR,"FFT mesh and number of atoms in group mismatch!");
// second line of mapfile is comment
if (fgets(line,MAXLINE,fp) == NULL) error->all(FLERR,"Error while reading comment of mapping file!");
int ix, iy, iz, iu;
// the remaining lines carry the mapping info
for (int i = 0; i < ngroup; ++i){
if (fgets(line,MAXLINE,fp) == NULL) {info = 1; break;}
ix = force->inumeric(FLERR, strtok(line, " \n\t\r\f"));
iy = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
iz = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
iu = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
itag = force->inumeric(FLERR, strtok(NULL, " \n\t\r\f"));
// check if index is in correct range
if (ix < 0 || ix >= nx || iy < 0 || iy >= ny || iz < 0 || iz >= nz|| iu < 0 || iu >= nucell) {info = 2; break;}
// 1 <= itag <= natoms
if (itag < 1 || itag > static_cast<int>(atom->natoms)) {info = 3; break;}
idx = ((ix*ny+iy)*nz+iz)*nucell + iu;
tag2surf[itag] = idx;
surf2tag[idx] = itag;
}
fclose(fp);
if (tag2surf.size() != surf2tag.size() || tag2surf.size() != static_cast<std::size_t>(ngroup) )
error->all(FLERR,"The mapping is incomplete!");
if (info) error->all(FLERR,"Error while reading mapping file!");
// check the correctness of mapping
int *mask = atom->mask;
int *tag = atom->tag;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; ++i) {
if (mask[i] & groupbit){
itag = tag[i];
idx = tag2surf[itag];
if (itag != surf2tag[idx]) error->one(FLERR,"The mapping info read is incorrect!");
}
}
}
/* ----------------------------------------------------------------------
* private method, to output the force constant matrix
* --------------------------------------------------------------------*/
void FixPhonon::postprocess( )
{
if (neval < 1) return;
ifreq = 0;
int idim, jdim, ndim;
double inv_neval = 1.0 /double(neval);
// to get <Rq.Rq*>
for (idq = 0; idq < mynq; ++idq)
for (idim = 0; idim < fft_dim2; ++idim) Phi_q[idq][idim] = Rqsum[idq][idim]*inv_neval;
// to get <R>
for (idx = 0; idx < mynpt; ++idx)
for (idim = 0; idim < fft_dim; ++idim) Rnow[idx][idim] = Rsum[idx][idim] * inv_neval;
// to get <R>q
for (idim = 0; idim < fft_dim; ++idim){
int m = 0;
for (idx = 0; idx < mynpt; ++idx){
fft_data[m++] = Rnow[idx][idim];
fft_data[m++] = 0.;
}
fft->compute(fft_data,fft_data,-1);
m = 0;
for (idq = 0; idq < mynq; ++idq){
Rqnow[idq][idim] = std::complex<double>(fft_data[m], fft_data[m+1]);
m += 2;
}
}
// to get G(q) = <Rq.Rq*> - <R>q.<R*>q
for (idq = 0; idq < mynq; ++idq){
ndim = 0;
for (idim = 0; idim < fft_dim; ++idim)
for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] -= Rqnow[idq][idim]*conj(Rqnow[idq][jdim]);
}
// to get Phi = KT.G^-1; normalization of FFTW data is done here
double boltz = force->boltz, kbtsqrt[sysdim], TempAve = 0.;
double TempFac = inv_neval*inv_nTemp;
double NormFac = TempFac*double(ntotal);
for (idim = 0; idim < sysdim; ++idim){
kbtsqrt[idim] = sqrt(TempSum[idim]*NormFac);
TempAve += TempSum[idim]*TempFac;
}
TempAve /= sysdim*boltz;
for (idq = 0; idq < mynq; ++idq){
GaussJordan(fft_dim, Phi_q[idq]);
ndim =0;
for (idim = 0; idim < fft_dim; ++idim)
for (jdim = 0; jdim < fft_dim; ++jdim) Phi_q[idq][ndim++] *= kbtsqrt[idim%sysdim]*kbtsqrt[jdim%sysdim];
}
// to collect all local Phi_q to root
displs[0]=0;
for (int i = 0; i < nprocs; ++i) recvcnts[i] = fft_cnts[i]*fft_dim*2;
for (int i = 1; i < nprocs; ++i) displs[i] = displs[i-1] + recvcnts[i-1];
MPI_Gatherv(Phi_q[0],mynq*fft_dim2*2,MPI_DOUBLE,Phi_all[0],recvcnts,displs,MPI_DOUBLE,0,world);
// to collect all basis info and averaged it on root
double basis_root[fft_dim];
if (fft_dim > sysdim) MPI_Reduce(&basis[1][0], &basis_root[sysdim], fft_dim-sysdim, MPI_DOUBLE, MPI_SUM, 0, world);
if (me == 0){ // output dynamic matrix by root
// get basis info
for (idim = 0; idim < sysdim; ++idim) basis_root[idim] = 0.;
for (idim = sysdim; idim < fft_dim; ++idim) basis_root[idim] /= double(ntotal)*double(neval);
// get unit cell base vector info; might be incorrect if MD pbc and FixPhonon pbc mismatch.
double basevec[9];
basevec[1] = basevec[2] = basevec[5] = 0.;
basevec[0] = hsum[0] * inv_neval / double(nx);
basevec[4] = hsum[1] * inv_neval / double(ny);
basevec[8] = hsum[2] * inv_neval / double(nz);
basevec[7] = hsum[3] * inv_neval / double(nz);
basevec[6] = hsum[4] * inv_neval / double(nz);
basevec[3] = hsum[5] * inv_neval / double(ny);
// write binary file, in fact, it is the force constants matrix that is written
// Enforcement of ASR and the conversion of dynamical matrix is done in the postprocessing code
char fname[MAXLINE];
sprintf(fname,"%s.bin." BIGINT_FORMAT,prefix,update->ntimestep);
FILE *fp_bin = fopen(fname,"wb");
fwrite(&sysdim, sizeof(int), 1, fp_bin);
fwrite(&nx, sizeof(int), 1, fp_bin);
fwrite(&ny, sizeof(int), 1, fp_bin);
fwrite(&nz, sizeof(int), 1, fp_bin);
fwrite(&nucell, sizeof(int), 1, fp_bin);
fwrite(&boltz, sizeof(double), 1, fp_bin);
fwrite(Phi_all[0],sizeof(double),ntotal*fft_dim2*2,fp_bin);
fwrite(&TempAve, sizeof(double),1, fp_bin);
fwrite(&basevec[0], sizeof(double),9, fp_bin);
fwrite(&basis_root[0],sizeof(double),fft_dim,fp_bin);
fwrite(basetype, sizeof(int), nucell, fp_bin);
fwrite(M_inv_sqrt, sizeof(double),nucell, fp_bin);
fclose(fp_bin);
// write log file, here however, it is the dynamical matrix that is written
for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n");
fprintf(flog, "# Current time step : " BIGINT_FORMAT "\n", update->ntimestep);
fprintf(flog, "# Total number of measurements : %d\n", neval);
fprintf(flog, "# Average temperature of the measurement : %lg\n", TempAve);
fprintf(flog, "# Boltzmann constant under current units : %lg\n", boltz);
fprintf(flog, "# basis vector A1 = [%lg %lg %lg]\n", basevec[0], basevec[1], basevec[2]);
fprintf(flog, "# basis vector A2 = [%lg %lg %lg]\n", basevec[3], basevec[4], basevec[5]);
fprintf(flog, "# basis vector A3 = [%lg %lg %lg]\n", basevec[6], basevec[7], basevec[8]);
for (int i = 0; i < 60; ++i) fprintf(flog,"#"); fprintf(flog,"\n");
fprintf(flog, "# qx\t qy \t qz \t\t Phi(q)\n");
EnforceASR();
// to get D = 1/M x Phi
for (idq = 0; idq < ntotal; ++idq){
ndim =0;
for (idim = 0; idim < fft_dim; ++idim)
for (jdim = 0; jdim < fft_dim; ++jdim) Phi_all[idq][ndim++] *= M_inv_sqrt[idim/sysdim]*M_inv_sqrt[jdim/sysdim];
}
idq =0;
for (int ix = 0; ix < nx; ++ix){
double qx = double(ix)/double(nx);
for (int iy = 0; iy < ny; ++iy){
double qy = double(iy)/double(ny);
for (int iz = 0; iz < nz; ++iz){
double qz = double(iz)/double(nz);
fprintf(flog,"%lg %lg %lg", qx, qy, qz);
for (idim = 0; idim < fft_dim2; ++idim) fprintf(flog, " %lg %lg", real(Phi_all[idq][idim]), imag(Phi_all[idq][idim]));
fprintf(flog, "\n");
++idq;
}
}
}
fflush(flog);
}
} // end of postprocess
/* ----------------------------------------------------------------------
* private method, to get the inverse of a complex matrix by means of
* Gaussian-Jordan Elimination with full pivoting; square matrix required.
*
* Adapted from the Numerical Recipes in Fortran.
* --------------------------------------------------------------------*/
void FixPhonon::GaussJordan(int n, std::complex<double> *Mat)
{
int i,icol,irow,j,k,l,ll,idr,idc;
int *indxc,*indxr,*ipiv;
double big, nmjk;
std::complex<double> dum, pivinv;
indxc = new int[n];
indxr = new int[n];
ipiv = new int[n];
for (i = 0; i < n; ++i) ipiv[i] = 0;
for (i = 0; i < n; ++i){
big = 0.;
for (j = 0; j < n; ++j){
if (ipiv[j] != 1){
for (k = 0; k < n; ++k){
if (ipiv[k] == 0){
idr = j*n+k;
nmjk = norm(Mat[idr]);
if (nmjk >= big){
big = nmjk;
irow = j;
icol = k;
}
} else if (ipiv[k] > 1) error->one(FLERR,"Singular matrix in complex GaussJordan!");
}
}
}
ipiv[icol] += 1;
if (irow != icol){
for (l = 0; l < n; ++l){
idr = irow*n+l;
idc = icol*n+l;
dum = Mat[idr];
Mat[idr] = Mat[idc];
Mat[idc] = dum;
}
}
indxr[i] = irow;
indxc[i] = icol;
idr = icol*n+icol;
if (Mat[idr] == std::complex<double>(0.,0.)) error->one(FLERR,"Singular matrix in complex GaussJordan!");
pivinv = 1./ Mat[idr];
Mat[idr] = std::complex<double>(1.,0.);
idr = icol*n;
for (l = 0; l < n; ++l) Mat[idr+l] *= pivinv;
for (ll = 0; ll < n; ++ll){
if (ll != icol){
idc = ll*n + icol;
dum = Mat[idc];
Mat[idc] = 0.;
idc -= icol;
for (l = 0; l < n; ++l) Mat[idc+l] -= Mat[idr+l]*dum;
}
}
}
for (l = n-1; l >= 0; --l){
int rl = indxr[l];
int cl = indxc[l];
if (rl != cl){
for (k = 0; k < n; ++k){
idr = k*n + rl;
idc = k*n + cl;
dum = Mat[idr];
Mat[idr] = Mat[idc];
Mat[idc] = dum;
}
}
}
delete []indxr;
delete []indxc;
delete []ipiv;
}
/* ----------------------------------------------------------------------
* private method, to apply the acoustic sum rule on force constant matrix
* at gamma point. Should be executed on root only.
* --------------------------------------------------------------------*/
void FixPhonon::EnforceASR()
{
if (nasr < 1) return;
for (int iit = 0; iit < nasr; ++iit){
// simple ASR; the resultant matrix might not be symmetric
for (int a = 0; a < sysdim; ++a)
for (int b = 0; b < sysdim; ++b){
for (int k = 0; k < nucell; ++k){
double sum = 0.;
for (int kp = 0; kp < nucell; ++kp){
int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b;
sum += real(Phi_all[0][idx]);
}
sum /= double(nucell);
for (int kp = 0; kp < nucell; ++kp){
int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b;
real(Phi_all[0][idx]) -= sum;
}
}
}
// symmetrize
for (int k = 0; k < nucell; ++k)
for (int kp = k; kp < nucell; ++kp){
double csum = 0.;
for (int a = 0; a < sysdim; ++a)
for (int b = 0; b < sysdim; ++b){
int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b;
int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a;
csum = (real(Phi_all[0][idx])+real(Phi_all[0][jdx]))*0.5;
real(Phi_all[0][idx]) = real(Phi_all[0][jdx]) = csum;
}
}
}
// symmetric ASR
for (int a = 0; a < sysdim; ++a)
for (int b = 0; b < sysdim; ++b){
for (int k = 0; k < nucell; ++k){
double sum = 0.;
for (int kp = 0; kp < nucell; ++kp){
int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b;
sum += real(Phi_all[0][idx]);
}
sum /= double(nucell-k);
for (int kp = k; kp < nucell; ++kp){
int idx = (k*sysdim+a)*fft_dim + kp*sysdim + b;
int jdx = (kp*sysdim+b)*fft_dim + k*sysdim + a;
real(Phi_all[0][idx]) -= sum;
real(Phi_all[0][jdx]) = real(Phi_all[0][idx]);
}
}
}
}
/* --------------------------------------------------------------------*/
diff --git a/src/USER-REAXC/fix_qeq_reax.cpp b/src/USER-REAXC/fix_qeq_reax.cpp
index b93d872bb..058ce5f84 100644
--- a/src/USER-REAXC/fix_qeq_reax.cpp
+++ b/src/USER-REAXC/fix_qeq_reax.cpp
@@ -1,915 +1,919 @@
/* ----------------------------------------------------------------------
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)
------------------------------------------------------------------------- */
+#ifdef LAMMPS_BIGBIG
+#error LAMMPS_BIGBIG not supported by this file
+#endif
+
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "fix_qeq_reax.h"
#include "pair_reax_c.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "update.h"
#include "force.h"
#include "pair.h"
#include "respa.h"
#include "memory.h"
#include "citeme.h"
#include "error.h"
#include "reaxc_defs.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define EV_TO_KCAL_PER_MOL 14.4
#define DANGER_ZONE 0.95
#define LOOSE_ZONE 0.7
#define SQR(x) ((x)*(x))
#define CUBE(x) ((x)*(x)*(x))
#define MIN_NBRS 100
static const char cite_fix_qeq_reax[] =
"fix qeq/reax 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";
/* ---------------------------------------------------------------------- */
FixQEqReax::FixQEqReax(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (lmp->citeme) lmp->citeme->add(cite_fix_qeq_reax);
if (narg != 8) error->all(FLERR,"Illegal fix qeq/reax command");
nevery = force->inumeric(FLERR,arg[3]);
swa = force->numeric(FLERR,arg[4]);
swb = force->numeric(FLERR,arg[5]);
tolerance = force->numeric(FLERR,arg[6]);
pertype_parameters(arg[7]);
shld = NULL;
n = n_cap = 0;
N = nmax = 0;
m_fill = m_cap = 0;
pack_flag = 0;
s = NULL;
t = NULL;
nprev = 5;
Hdia_inv = NULL;
b_s = NULL;
b_t = NULL;
b_prc = NULL;
b_prm = NULL;
// CG
p = NULL;
q = NULL;
r = NULL;
d = NULL;
// H matrix
H.firstnbr = NULL;
H.numnbrs = NULL;
H.jlist = NULL;
H.val = NULL;
// GMRES
//g = NULL;
//y = NULL;
//hstr = NULL;
//v = NULL;
//h = NULL;
//hc = NULL;
//hs = NULL;
// perform initial allocation of atom-based arrays
// register with Atom class
s_hist = t_hist = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
for( int i = 0; i < atom->nmax; i++ )
for (int j = 0; j < nprev; ++j )
s_hist[i][j] = t_hist[i][j] = 0;
reaxc = NULL;
reaxc = (PairReaxC *) force->pair_match("reax/c",1);
}
/* ---------------------------------------------------------------------- */
FixQEqReax::~FixQEqReax()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
memory->destroy(s_hist);
memory->destroy(t_hist);
deallocate_storage();
deallocate_matrix();
memory->destroy(shld);
if (!reaxflag) {
memory->destroy(chi);
memory->destroy(eta);
memory->destroy(gamma);
}
}
/* ---------------------------------------------------------------------- */
int FixQEqReax::setmask()
{
int mask = 0;
mask |= PRE_FORCE;
mask |= MIN_PRE_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::pertype_parameters(char *arg)
{
if (strcmp(arg,"reax/c") == 0) {
reaxflag = 1;
Pair *pair = force->pair_match("reax/c",1);
if (pair == NULL) error->all(FLERR,"No pair reax/c for fix qeq/reax");
int tmp;
chi = (double *) pair->extract("chi",tmp);
eta = (double *) pair->extract("eta",tmp);
gamma = (double *) pair->extract("gamma",tmp);
if (chi == NULL || eta == NULL || gamma == NULL)
error->all(FLERR,
"Fix qeq/reax could not extract params from pair reax/c");
return;
}
int i,itype,ntypes;
double v1,v2,v3;
FILE *pf;
reaxflag = 0;
ntypes = atom->ntypes;
memory->create(chi,ntypes+1,"qeq/reax:chi");
memory->create(eta,ntypes+1,"qeq/reax:eta");
memory->create(gamma,ntypes+1,"qeq/reax:gamma");
if (comm->me == 0) {
if ((pf = fopen(arg,"r")) == NULL)
error->one(FLERR,"Fix qeq/reax parameter file could not be found");
for (i = 1; i <= ntypes && !feof(pf); i++) {
fscanf(pf,"%d %lg %lg %lg",&itype,&v1,&v2,&v3);
if (itype < 1 || itype > ntypes)
error->one(FLERR,"Fix qeq/reax invalid atom type in param file");
chi[itype] = v1;
eta[itype] = v2;
gamma[itype] = v3;
}
if (i <= ntypes) error->one(FLERR,"Invalid param file for fix qeq/reax");
fclose(pf);
}
MPI_Bcast(&chi[1],ntypes,MPI_DOUBLE,0,world);
MPI_Bcast(&eta[1],ntypes,MPI_DOUBLE,0,world);
MPI_Bcast(&gamma[1],ntypes,MPI_DOUBLE,0,world);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::allocate_storage()
{
nmax = atom->nmax;
memory->create(s,nmax,"qeq:s");
memory->create(t,nmax,"qeq:t");
memory->create(Hdia_inv,nmax,"qeq:Hdia_inv");
memory->create(b_s,nmax,"qeq:b_s");
memory->create(b_t,nmax,"qeq:b_t");
memory->create(b_prc,nmax,"qeq:b_prc");
memory->create(b_prm,nmax,"qeq:b_prm");
memory->create(p,nmax,"qeq:p");
memory->create(q,nmax,"qeq:q");
memory->create(r,nmax,"qeq:r");
memory->create(d,nmax,"qeq:d");
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::deallocate_storage()
{
memory->destroy(s);
memory->destroy(t);
memory->destroy( Hdia_inv );
memory->destroy( b_s );
memory->destroy( b_t );
memory->destroy( b_prc );
memory->destroy( b_prm );
memory->destroy( p );
memory->destroy( q );
memory->destroy( r );
memory->destroy( d );
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::reallocate_storage()
{
deallocate_storage();
allocate_storage();
init_storage();
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::allocate_matrix()
{
int i,ii;
int mincap;
double safezone;
if( reaxflag ) {
mincap = reaxc->system->mincap;
safezone = reaxc->system->safezone;
} else {
mincap = MIN_CAP;
safezone = SAFE_ZONE;
}
n = atom->nlocal;
n_cap = MAX( (int)(n * safezone), mincap );
// determine the total space for the H matrix
int m = 0;
for( ii = 0; ii < list->inum; ii++ ) {
i = list->ilist[ii];
m += list->numneigh[i];
}
m_cap = MAX( (int)(m * safezone), mincap * MIN_NBRS );
H.n = n_cap;
H.m = m_cap;
memory->create(H.firstnbr,n_cap,"qeq:H.firstnbr");
memory->create(H.numnbrs,n_cap,"qeq:H.numnbrs");
memory->create(H.jlist,m_cap,"qeq:H.jlist");
memory->create(H.val,m_cap,"qeq:H.val");
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::deallocate_matrix()
{
memory->destroy( H.firstnbr );
memory->destroy( H.numnbrs );
memory->destroy( H.jlist );
memory->destroy( H.val );
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::reallocate_matrix()
{
deallocate_matrix();
allocate_matrix();
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init()
{
if (!atom->q_flag) error->all(FLERR,"Fix qeq/reax requires atom attribute q");
if (!force->pair_match("reax/c",1))
error->all(FLERR,"Must use pair_style reax/c with fix qeq/reax");
// need a half neighbor list w/ Newton off and ghost neighbors
// built whenever re-neighboring occurs
int irequest = neighbor->request(this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
neighbor->requests[irequest]->newton = 2;
neighbor->requests[irequest]->ghost = 1;
init_shielding();
init_taper();
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init_shielding()
{
int i,j;
int ntypes;
ntypes = atom->ntypes;
memory->create(shld,ntypes+1,ntypes+1,"qeq:shileding");
for( i = 1; i <= ntypes; ++i )
for( j = 1; j <= ntypes; ++j )
shld[i][j] = pow( gamma[i] * gamma[j], -1.5 );
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init_taper()
{
double d7, swa2, swa3, swb2, swb3;
if (fabs(swa) > 0.01 && comm->me == 0)
error->warning(FLERR,"Fix qeq/reax has non-zero lower Taper radius cutoff");
if (swb < 0)
error->all(FLERR, "Fix qeq/reax has negative upper Taper radius cutoff");
else if (swb < 5 && comm->me == 0)
error->warning(FLERR,"Fix qeq/reax has very low Taper radius cutoff");
d7 = pow( swb - swa, 7 );
swa2 = SQR( swa );
swa3 = CUBE( swa );
swb2 = SQR( swb );
swb3 = CUBE( swb );
Tap[7] = 20.0 / d7;
Tap[6] = -70.0 * (swa + swb) / d7;
Tap[5] = 84.0 * (swa2 + 3.0*swa*swb + swb2) / d7;
Tap[4] = -35.0 * (swa3 + 9.0*swa2*swb + 9.0*swa*swb2 + swb3 ) / d7;
Tap[3] = 140.0 * (swa3*swb + 3.0*swa2*swb2 + swa*swb3 ) / d7;
Tap[2] =-210.0 * (swa3*swb2 + swa2*swb3) / d7;
Tap[1] = 140.0 * swa3 * swb3 / d7;
Tap[0] = (-35.0*swa3*swb2*swb2 + 21.0*swa2*swb3*swb2 +
7.0*swa*swb3*swb3 + swb3*swb3*swb ) / d7;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::setup_pre_force(int vflag)
{
neighbor->build_one(list->index);
deallocate_storage();
allocate_storage();
init_storage();
deallocate_matrix();
allocate_matrix();
pre_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::setup_pre_force_respa(int vflag, int ilevel)
{
if (ilevel < nlevels_respa-1) return;
setup_pre_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::min_setup_pre_force(int vflag)
{
setup_pre_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init_storage()
{
N = atom->nlocal + atom->nghost;
for( int i = 0; i < N; i++ ) {
Hdia_inv[i] = 1. / eta[atom->type[i]];
b_s[i] = -chi[atom->type[i]];
b_t[i] = -1.0;
b_prc[i] = 0;
b_prm[i] = 0;
s[i] = t[i] = 0;
}
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::pre_force(int vflag)
{
double t_start, t_end;
if (update->ntimestep % nevery) return;
if( comm->me == 0 ) t_start = MPI_Wtime();
n = atom->nlocal;
N = atom->nlocal + atom->nghost;
// grow arrays if necessary
// need to be atom->nmax in length
if( atom->nmax > nmax ) reallocate_storage();
if( n > n_cap*DANGER_ZONE || m_fill > m_cap*DANGER_ZONE )
reallocate_matrix();
init_matvec();
matvecs = CG(b_s, s); // CG on s - parallel
matvecs += CG(b_t, t); // CG on t - parallel
calculate_Q();
if( comm->me == 0 ) {
t_end = MPI_Wtime();
qeq_time = t_end - t_start;
}
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::pre_force_respa(int vflag, int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) pre_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::min_pre_force(int vflag)
{
pre_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::init_matvec()
{
/* fill-in H matrix */
compute_H();
for( int i = 0; i < n; ++i ) {
/* init pre-conditioner for H and init solution vectors */
Hdia_inv[i] = 1. / eta[ atom->type[i] ];
b_s[i] = -chi[ atom->type[i] ];
b_t[i] = -1.0;
/* linear extrapolation for s & t from previous solutions */
//s[i] = 2 * s_hist[i][0] - s_hist[i][1];
//t[i] = 2 * t_hist[i][0] - t_hist[i][1];
/* quadratic extrapolation for s & t from previous solutions */
//s[i] = s_hist[i][2] + 3 * ( s_hist[i][0] - s_hist[i][1] );
t[i] = t_hist[i][2] + 3 * ( t_hist[i][0] - t_hist[i][1] );
/* cubic extrapolation for s & t from previous solutions */
s[i] = 4*(s_hist[i][0]+s_hist[i][2])-(6*s_hist[i][1]+s_hist[i][3]);
//t[i] = 4*(t_hist[i][0]+t_hist[i][2])-(6*t_hist[i][1]+t_hist[i][3]);
}
pack_flag = 2;
comm->forward_comm_fix(this); //Dist_vector( s );
pack_flag = 3;
comm->forward_comm_fix(this); //Dist_vector( t );
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::compute_H()
{
int inum, jnum, *ilist, *jlist, *numneigh, **firstneigh;
int i, j, ii, jj, flag;
- int *type, *tag;
double **x, SMALL = 0.0001;
double dx, dy, dz, r_sqr;
- type = atom->type;
- tag = atom->tag;
+ int *type = atom->type;
+ tagint *tag = atom->tag;
x = atom->x;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// fill in the H matrix
+
m_fill = 0;
r_sqr = 0;
for( ii = 0; ii < inum; ii++ ) {
i = ilist[ii];
jlist = firstneigh[i];
jnum = numneigh[i];
H.firstnbr[i] = m_fill;
for( jj = 0; jj < jnum; jj++ ) {
j = jlist[jj];
dx = x[j][0] - x[i][0];
dy = x[j][1] - x[i][1];
dz = x[j][2] - x[i][2];
r_sqr = SQR(dx) + SQR(dy) + SQR(dz);
flag = 0;
if (r_sqr <= SQR(swb)) {
if (j < n) flag = 1;
else if (tag[i] < tag[j]) flag = 1;
else if (tag[i] == tag[j]) {
if (dz > SMALL) flag = 1;
else if (fabs(dz) < SMALL) {
if (dy > SMALL) flag = 1;
else if (fabs(dy) < SMALL && dx > SMALL)
flag = 1;
}
}
}
if( flag ) {
H.jlist[m_fill] = j;
H.val[m_fill] = calculate_H( sqrt(r_sqr), shld[type[i]][type[j]] );
m_fill++;
}
}
H.numnbrs[i] = m_fill - H.firstnbr[i];
}
if (m_fill >= H.m) {
char str[128];
sprintf(str,"H matrix size has been exceeded: m_fill=%d H.m=%d\n",
m_fill, H.m );
error->warning(FLERR,str);
error->all(FLERR,"Fix qeq/reax has insufficient QEq matrix size");
}
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::calculate_H( double r, double gamma )
{
double Taper, denom;
Taper = Tap[7] * r + Tap[6];
Taper = Taper * r + Tap[5];
Taper = Taper * r + Tap[4];
Taper = Taper * r + Tap[3];
Taper = Taper * r + Tap[2];
Taper = Taper * r + Tap[1];
Taper = Taper * r + Tap[0];
denom = r * r * r + gamma;
denom = pow(denom,0.3333333333333);
return Taper * EV_TO_KCAL_PER_MOL / denom;
}
/* ---------------------------------------------------------------------- */
int FixQEqReax::CG( double *b, double *x )
{
int i, j, imax;
double tmp, alpha, beta, b_norm;
double sig_old, sig_new, sig0;
imax = 200;
pack_flag = 1;
sparse_matvec( &H, x, q );
comm->reverse_comm_fix( this ); //Coll_Vector( q );
vector_sum( r , 1., b, -1., q, n );
for( j = 0; j < n; ++j )
d[j] = r[j] * Hdia_inv[j]; //pre-condition
b_norm = parallel_norm( b, n );
sig_new = parallel_dot( r, d, n );
sig0 = sig_new;
for( i = 1; i < imax && sqrt(sig_new) / b_norm > tolerance; ++i ) {
comm->forward_comm_fix(this); //Dist_vector( d );
sparse_matvec( &H, d, q );
comm->reverse_comm_fix(this); //Coll_vector( q );
tmp = parallel_dot( d, q, n );
alpha = sig_new / tmp;
// comm->me, i, parallel_norm( d, n ), parallel_norm( q, n ), tmp );
vector_add( x, alpha, d, n );
vector_add( r, -alpha, q, n );
// pre-conditioning
for( j = 0; j < n; ++j )
p[j] = r[j] * Hdia_inv[j];
sig_old = sig_new;
sig_new = parallel_dot( r, p, n );
beta = sig_new / sig_old;
vector_sum( d, 1., p, beta, d, n );
}
if (i >= imax && comm->me == 0) {
char str[128];
sprintf(str,"Fix qeq/reax CG convergence failed after %d iterations at "
BIGINT_FORMAT " step",i,update->ntimestep);
error->warning(FLERR,str);
}
return i;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::sparse_matvec( sparse_matrix *A, double *x, double *b )
{
int i, j, itr_j;
for( i = 0; i < n; ++i )
b[i] = eta[ atom->type[i] ] * x[i];
for( i = n; i < N; ++i )
b[i] = 0;
for( i = 0; i < n; ++i ) {
for( itr_j=A->firstnbr[i]; itr_j<A->firstnbr[i]+A->numnbrs[i]; itr_j++) {
j = A->jlist[itr_j];
b[i] += A->val[itr_j] * x[j];
b[j] += A->val[itr_j] * x[i];
}
}
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::calculate_Q()
{
int i, k;
double u, s_sum, t_sum;
double *q = atom->q;
s_sum = parallel_vector_acc( s, n );
t_sum = parallel_vector_acc( t, n);
u = s_sum / t_sum;
for( i = 0; i < n; ++i ) {
q[i] = s[i] - u * t[i];
/* backup s & t */
for( k = 4; k > 0; --k ) {
s_hist[i][k] = s_hist[i][k-1];
t_hist[i][k] = t_hist[i][k-1];
}
s_hist[i][0] = s[i];
t_hist[i][0] = t[i];
}
pack_flag = 4;
comm->forward_comm_fix( this ); //Dist_vector( atom->q );
}
/* ---------------------------------------------------------------------- */
int FixQEqReax::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int m;
if( pack_flag == 1)
for(m = 0; m < n; m++) buf[m] = d[list[m]];
else if( pack_flag == 2 )
for(m = 0; m < n; m++) buf[m] = s[list[m]];
else if( pack_flag == 3 )
for(m = 0; m < n; m++) buf[m] = t[list[m]];
else if( pack_flag == 4 )
for(m = 0; m < n; m++) buf[m] = atom->q[list[m]];
return 1;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::unpack_comm(int n, int first, double *buf)
{
int i, m;
if( pack_flag == 1)
for(m = 0, i = first; m < n; m++, i++) d[i] = buf[m];
else if( pack_flag == 2)
for(m = 0, i = first; m < n; m++, i++) s[i] = buf[m];
else if( pack_flag == 3)
for(m = 0, i = first; m < n; m++, i++) t[i] = buf[m];
else if( pack_flag == 4)
for(m = 0, i = first; m < n; m++, i++) atom->q[i] = buf[m];
}
/* ---------------------------------------------------------------------- */
int FixQEqReax::pack_reverse_comm(int n, int first, double *buf)
{
int i, m;
for(m = 0, i = first; m < n; m++, i++) buf[m] = q[i];
return 1;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::unpack_reverse_comm(int n, int *list, double *buf)
{
for(int m = 0; m < n; m++) q[list[m]] += buf[m];
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixQEqReax::memory_usage()
{
double bytes;
bytes = atom->nmax*nprev*2 * sizeof(double); // s_hist & t_hist
bytes += atom->nmax*11 * sizeof(double); // storage
bytes += n_cap*2 * sizeof(int); // matrix...
bytes += m_cap * sizeof(int);
bytes += m_cap * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
allocate fictitious charge arrays
------------------------------------------------------------------------- */
void FixQEqReax::grow_arrays(int nmax)
{
memory->grow(s_hist,nmax,nprev,"qeq:s_hist");
memory->grow(t_hist,nmax,nprev,"qeq:t_hist");
}
/* ----------------------------------------------------------------------
copy values within fictitious charge arrays
------------------------------------------------------------------------- */
void FixQEqReax::copy_arrays(int i, int j, int delflag)
{
for (int m = 0; m < nprev; m++) {
s_hist[j][m] = s_hist[i][m];
t_hist[j][m] = t_hist[i][m];
}
}
/* ----------------------------------------------------------------------
pack values in local atom-based array for exchange with another proc
------------------------------------------------------------------------- */
int FixQEqReax::pack_exchange(int i, double *buf)
{
for (int m = 0; m < nprev; m++) buf[m] = s_hist[i][m];
for (int m = 0; m < nprev; m++) buf[nprev+m] = t_hist[i][m];
return nprev*2;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based array from exchange with another proc
------------------------------------------------------------------------- */
int FixQEqReax::unpack_exchange(int nlocal, double *buf)
{
for (int m = 0; m < nprev; m++) s_hist[nlocal][m] = buf[m];
for (int m = 0; m < nprev; m++) t_hist[nlocal][m] = buf[nprev+m];
return nprev*2;
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::parallel_norm( double *v, int n )
{
int i;
double my_sum, norm_sqr;
my_sum = 0;
for( i = 0; i < n; ++i )
my_sum += SQR( v[i] );
MPI_Allreduce( &my_sum, &norm_sqr, 1, MPI_DOUBLE, MPI_SUM, world );
return sqrt( norm_sqr );
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::parallel_dot( double *v1, double *v2, int n )
{
int i;
double my_dot, res;
my_dot = 0;
res = 0;
for( i = 0; i < n; ++i )
my_dot += v1[i] * v2[i];
MPI_Allreduce( &my_dot, &res, 1, MPI_DOUBLE, MPI_SUM, world );
return res;
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::parallel_vector_acc( double *v, int n )
{
int i;
double my_acc, res;
my_acc = 0;
for( i = 0; i < n; ++i )
my_acc += v[i];
MPI_Allreduce( &my_acc, &res, 1, MPI_DOUBLE, MPI_SUM, world );
return res;
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::norm( double* v1, int k )
{
double ret = 0;
for( --k; k>=0; --k )
ret += ( v1[k] * v1[k] );
return sqrt( ret );
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::vector_sum( double* dest, double c, double* v,
double d, double* y, int k )
{
for( --k; k>=0; --k )
dest[k] = c * v[k] + d * y[k];
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::vector_scale( double* dest, double c, double* v, int k )
{
for( --k; k>=0; --k )
dest[k] = c * v[k];
}
/* ---------------------------------------------------------------------- */
double FixQEqReax::dot( double* v1, double* v2, int k )
{
double ret = 0;
for( --k; k>=0; --k )
ret += v1[k] * v2[k];
return ret;
}
/* ---------------------------------------------------------------------- */
void FixQEqReax::vector_add( double* dest, double c, double* v, int k )
{
for( --k; k>=0; --k )
dest[k] += c * v[k];
}
diff --git a/src/USER-REAXC/fix_reaxc_bonds.cpp b/src/USER-REAXC/fix_reaxc_bonds.cpp
index f20c77031..55032aa97 100644
--- a/src/USER-REAXC/fix_reaxc_bonds.cpp
+++ b/src/USER-REAXC/fix_reaxc_bonds.cpp
@@ -1,355 +1,358 @@
/* ----------------------------------------------------------------------
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 (Sandia, tnshan@sandia.gov)
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "stdlib.h"
#include "string.h"
#include "fix_ave_atom.h"
#include "fix_reaxc_bonds.h"
#include "atom.h"
#include "update.h"
#include "pair_reax_c.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"
#include "reaxc_types.h"
#include "reaxc_defs.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixReaxCBonds::FixReaxCBonds(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg != 5) error->all(FLERR,"Illegal fix reax/c/bonds command");
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
ntypes = atom->ntypes;
nmax = atom->nmax;
nevery = force->inumeric(FLERR,arg[3]);
if (nevery <= 0 )
error->all(FLERR,"Illegal fix reax/c/bonds command");
if (me == 0) {
fp = fopen(arg[4],"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix reax/c/bonds file %s",arg[4]);
error->one(FLERR,str);
}
}
if (atom->tag_consecutive() == 0)
error->all(FLERR,"Atom IDs must be consecutive for fix reax/c bonds");
abo = NULL;
neighid = NULL;
numneigh = NULL;
allocate();
-
}
/* ---------------------------------------------------------------------- */
FixReaxCBonds::~FixReaxCBonds()
{
MPI_Comm_rank(world,&me);
destroy();
if (me == 0) fclose(fp);
}
/* ---------------------------------------------------------------------- */
int FixReaxCBonds::setmask()
{
int mask = 0;
mask |= END_OF_STEP;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::setup(int vflag)
{
end_of_step();
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::init()
{
reaxc = (PairReaxC *) force->pair_match("reax/c",1);
if (reaxc == NULL) error->all(FLERR,"Cannot use fix reax/c/bonds without "
"pair_style reax/c");
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::end_of_step()
{
Output_ReaxC_Bonds(update->ntimestep,fp);
if (me == 0) fflush(fp);
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::Output_ReaxC_Bonds(bigint ntimestep, FILE *fp)
{
int i, j;
int nbuf, nbuf_local;
int nlocal_max, numbonds, numbonds_max;
double *buf;
int nlocal = atom->nlocal;
int nlocal_tot = static_cast<int> (atom->natoms);
if (atom->nmax > nmax) {
destroy();
nmax = atom->nmax;
allocate();
}
for (i = 0; i < nmax; i++) {
numneigh[i] = 0;
for (j = 0; j < MAXREAXBOND; j++) {
neighid[i][j] = 0;
abo[i][j] = 0.0;
}
}
numbonds = 0;
FindBond(lists, numbonds);
// allocate a temporary buffer for the snapshot info
MPI_Allreduce(&numbonds,&numbonds_max,1,MPI_INT,MPI_MAX,world);
MPI_Allreduce(&nlocal,&nlocal_max,1,MPI_INT,MPI_MAX,world);
nbuf = 1+(numbonds_max*2+10)*nlocal_max;
memory->create(buf,nbuf,"reax/c/bonds:buf");
for (i = 0; i < nbuf; i ++) buf[i] = 0.0;
// Pass information to buffer
PassBuffer(buf, nbuf_local);
// Receive information from buffer for output
RecvBuffer(buf, nbuf, nbuf_local, nlocal_tot, numbonds_max);
memory->destroy(buf);
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::FindBond(struct _reax_list *lists, int &numbonds)
{
int *ilist, i, ii, inum;
- int j, pj, nj, jtag;
+ int j, pj, nj;
+ tagint jtag;
double bo_tmp,bo_cut;
inum = reaxc->list->inum;
ilist = reaxc->list->ilist;
bond_data *bo_ij;
bo_cut = reaxc->control->bg_cut;
+ tagint *tag = atom->tag;
+
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
nj = 0;
for( pj = Start_Index(i, reaxc->lists); pj < End_Index(i, reaxc->lists); ++pj ) {
bo_ij = &( reaxc->lists->select.bond_list[pj] );
j = bo_ij->nbr;
- jtag = atom->tag[j];
+ jtag = tag[j];
bo_tmp = bo_ij->bo_data.BO;
if (bo_tmp > bo_cut) {
neighid[i][nj] = jtag;
abo[i][nj] = bo_tmp;
nj ++;
}
}
numneigh[i] = nj;
if (nj > numbonds) numbonds = nj;
}
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::PassBuffer(double *buf, int &nbuf_local)
{
int i, j, k, numbonds;
int nlocal = atom->nlocal;
j = 2;
buf[0] = nlocal;
for (i = 0; i < nlocal; i++) {
buf[j-1] = atom->tag[i];
buf[j+0] = atom->type[i];
buf[j+1] = reaxc->workspace->total_bond_order[i];
buf[j+2] = reaxc->workspace->nlp[i];
buf[j+3] = atom->q[i];
buf[j+4] = numneigh[i];
numbonds = nint(buf[j+4]);
for (k = 5; k < 5+numbonds; k++) {
buf[j+k] = neighid[i][k-5];
}
j += (5+numbonds);
if (atom->molecule == NULL ) buf[j] = 0.0;
else buf[j] = atom->molecule[i];
j ++;
for (k = 0; k < numbonds; k++) {
buf[j+k] = abo[i][k];
}
j += (1+numbonds);
}
nbuf_local = j - 1;
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::RecvBuffer(double *buf, int nbuf, int nbuf_local,
- int natoms, int maxnum)
+ int natoms, int maxnum)
{
- int i, j, k, itype, itag, jtag;
+ int i, j, k, itype;
int inode, nlocal_tmp, numbonds;
+ tagint itag,jtag;
int nlocal = atom->nlocal;
bigint ntimestep = update->ntimestep;
double sbotmp, nlptmp, avqtmp, abotmp;
double cutof3 = reaxc->control->bg_cut;
MPI_Request irequest, irequest2;
MPI_Status istatus;
if (me == 0 ){
fprintf(fp,"# Timestep " BIGINT_FORMAT " \n",ntimestep);
fprintf(fp,"# \n");
fprintf(fp,"# Number of particles %d \n",natoms);
fprintf(fp,"# \n");
fprintf(fp,"# Max number of bonds per atom %d with "
"coarse bond order cutoff %5.3f \n",maxnum,cutof3);
fprintf(fp,"# Particle connection table and bond orders \n");
fprintf(fp,"# id type nb id_1...id_nb mol bo_1...bo_nb abo nlp q \n");
}
j = 2;
if (me == 0) {
for (inode = 0; inode < nprocs; inode ++) {
if (inode == 0) {
nlocal_tmp = nlocal;
} else {
MPI_Irecv(&buf[0],nbuf,MPI_DOUBLE,inode,0,world,&irequest);
MPI_Wait(&irequest,&istatus);
nlocal_tmp = nint(buf[0]);
}
j = 2;
for (i = 0; i < nlocal_tmp; i ++) {
- itag = nint(buf[j-1]);
+ itag = static_cast<tagint> (buf[j-1]);
itype = nint(buf[j+0]);
sbotmp = buf[j+1];
nlptmp = buf[j+2];
avqtmp = buf[j+3];
numbonds = nint(buf[j+4]);
fprintf(fp," %d %d %d",itag,itype,numbonds);
for (k = 5; k < 5+numbonds; k++) {
- jtag = nint(buf[j+k]);
+ jtag = static_cast<tagint> (buf[j+k]);
fprintf(fp," %d",jtag);
}
j += (5+numbonds);
fprintf(fp," %d",nint(buf[j]));
j ++;
for (k = 0; k < numbonds; k++) {
abotmp = buf[j+k];
fprintf(fp,"%14.3f",abotmp);
}
j += (1+numbonds);
fprintf(fp,"%14.3f%14.3f%14.3f\n",sbotmp,nlptmp,avqtmp);
}
}
} else {
MPI_Isend(&buf[0],nbuf_local,MPI_DOUBLE,0,0,world,&irequest2);
MPI_Wait(&irequest2,&istatus);
}
if(me ==0) fprintf(fp,"# \n");
}
/* ---------------------------------------------------------------------- */
int FixReaxCBonds::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;
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::destroy()
{
memory->destroy(abo);
memory->destroy(neighid);
memory->destroy(numneigh);
}
/* ---------------------------------------------------------------------- */
void FixReaxCBonds::allocate()
{
memory->create(abo,nmax,MAXREAXBOND,"reax/c/bonds:abo");
memory->create(neighid,nmax,MAXREAXBOND,"reax/c/bonds:neighid");
memory->create(numneigh,nmax,"reax/c/bonds:numneigh");
}
/* ---------------------------------------------------------------------- */
double FixReaxCBonds::memory_usage()
{
double bytes;
bytes = 3.0*nmax*sizeof(double);
bytes += nmax*sizeof(int);
bytes += 1.0*nmax*MAXREAXBOND*sizeof(double);
bytes += 1.0*nmax*MAXREAXBOND*sizeof(int);
return bytes;
}
diff --git a/src/USER-REAXC/fix_reaxc_bonds.h b/src/USER-REAXC/fix_reaxc_bonds.h
index 34aa5d203..d7927ccae 100644
--- a/src/USER-REAXC/fix_reaxc_bonds.h
+++ b/src/USER-REAXC/fix_reaxc_bonds.h
@@ -1,61 +1,62 @@
/* ----------------------------------------------------------------------
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 FIX_CLASS
FixStyle(reax/c/bonds,FixReaxCBonds)
#else
#ifndef LMP_FIX_REAXC_BONDS_H
#define LMP_FIX_REAXC_BONDS_H
#include "stdio.h"
#include "fix.h"
#include "pointers.h"
namespace LAMMPS_NS {
class FixReaxCBonds : public Fix {
public:
FixReaxCBonds(class LAMMPS *, int, char **);
~FixReaxCBonds();
int setmask();
void init();
void setup(int);
void end_of_step();
private:
int me, nprocs, nmax, ntypes, maxsize;
- int *numneigh, **neighid;
+ int *numneigh;
+ tagint **neighid;
double **abo;
FILE *fp;
void allocate();
void destroy();
void Output_ReaxC_Bonds(bigint, FILE *);
void FindBond(struct _reax_list*, int &);
void PassBuffer(double *, int &);
void RecvBuffer(double *, int, int, int, int);
int nint(const double &);
double memory_usage();
bigint nvalid, nextvalid();
struct _reax_list *lists;
class PairReaxC *reaxc;
class NeighList *list;
};
}
#endif
#endif
diff --git a/src/USER-REAXC/pair_reax_c.cpp b/src/USER-REAXC/pair_reax_c.cpp
index 57212a0c4..3df23e865 100644
--- a/src/USER-REAXC/pair_reax_c.cpp
+++ b/src/USER-REAXC/pair_reax_c.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: 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)
------------------------------------------------------------------------- */
#include "pair_reax_c.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_reax_c.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");
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;
fix_reax = NULL;
tmpid = NULL;
tmpbo = NULL;
nextra = 14;
pvector = new double[nextra];
setup_flag = 0;
fixspecies_flag = 0;
nmax = 0;
}
/* ---------------------------------------------------------------------- */
PairReaxC::~PairReaxC()
{
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;
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;
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],"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 + 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
Read_Force_Field(args[2], &(system->reax_param), control);
// 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;
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;
continue;
}
}
int n = atom->ntypes;
// pair_coeff element map
itmp = 0;
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");
int count = 0;
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) {
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 reax/c requires atom attribute q");
// firstwarn = 1;
int iqeq;
for (iqeq = 0; iqeq < modify->nfix; iqeq++)
if (strcmp(modify->fix[iqeq]->style,"qeq/reax") == 0) 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);
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 );
}
}
/* ---------------------------------------------------------------------- */
double PairReaxC::init_one(int i, int j)
{
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();
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].orig_id = static_cast<int> (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, itr_g, i, j, g;
int nlocal, nghost, num_nbrs, num_marked;
int *ilist, *jlist, *numneigh, **firstneigh, *marked;
double d_sqr, g_d_sqr;
rvec dvec, g_dvec;
double *dist, **x;
reax_list *far_nbrs;
far_neighbor_data *far_list;
int mincap = system->mincap;
double safezone = system->safezone;
x = atom->x;
nlocal = atom->nlocal;
nghost = atom->nghost;
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;
num_marked = 0;
marked = (int*) calloc( system->N, sizeof(int) );
dist = (double*) calloc( system->N, sizeof(double) );
int inum = list->inum;
int gnum = list->gnum;
int numall = inum + gnum;
for( itr_i = 0; itr_i < inum+gnum; ++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 );
free( dist );
return static_cast<int> (MAX( num_nbrs*safezone, mincap*MIN_NBRS ));
}
/* ---------------------------------------------------------------------- */
int PairReaxC::write_reax_lists()
{
int itr_i, itr_j, itr_g, i, j, g, flag;
int nlocal, nghost, num_nbrs;
- int *ilist, *jlist, *numneigh, **firstneigh, *marked, *tag;
+ int *ilist, *jlist, *numneigh, **firstneigh, *marked;
double d_sqr, g_d, g_d_sqr;
rvec dvec, g_dvec;
double *dist, **x, SMALL = 0.0001;
reax_list *far_nbrs;
far_neighbor_data *far_list;
x = atom->x;
- tag = atom->tag;
nlocal = atom->nlocal;
nghost = atom->nghost;
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;
marked = (int*) calloc( system->N, sizeof(int) );
dist = (double*) calloc( system->N, sizeof(double) );
int inum = list->inum;
int gnum = list->gnum;
int numall = inum + gnum;
for( itr_i = 0; itr_i < inum+gnum; ++itr_i ){
i = ilist[itr_i];
marked[i] = 1;
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( marked );
free( dist );
return num_nbrs;
}
/* ---------------------------------------------------------------------- */
void PairReaxC::read_reax_forces()
{
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(real);
bytes += 3.0 * system->total_cap * sizeof(int);
double mem1 = bytes;
// 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, ii, j, pj, jtag, nj, jtmp, jj;
+ int i, ii, j, pj, nj, jtmp, jj;
double bo_tmp, bo_cut, rij, rsq, r_tmp;
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;
r_tmp = bo_ij->d;
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-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h
index 83335e786..651f65b2d 100644
--- a/src/USER-REAXC/reaxc_types.h
+++ b/src/USER-REAXC/reaxc_types.h
@@ -1,1005 +1,1006 @@
/*----------------------------------------------------------------------
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 "ctype.h"
#include "math.h"
#include "mpi.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/time.h"
#include "time.h"
/************* SOME DEFS - crucial for reax_types.h *********/
//#define PURE_REAX
#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 real;
typedef real rvec[3];
typedef real rtensor[3][3];
typedef real rvec2[2];
typedef real rvec4[4];
typedef struct {
int step, bigN;
real T, xi, v_xi, v_xi_old, G_xi;
rtensor box;
} restart_header;
typedef struct {
- int orig_id, type;
+ int orig_id;
+ int type;
char name[8];
rvec x, v;
} restart_atom;
typedef struct
{
int orig_id;
int imprt_id;
int type;
int num_bonds;
int num_hbonds;
//int pad; // pad to 8-byte address boundary
char name[8];
rvec x; // position
rvec v; // velocity
rvec f_old; // old force
rvec4 s, t; // for calculating q
} mpi_atom;
typedef struct
{
int orig_id;
int imprt_id;
int type;
int num_bonds;
int num_hbonds;
//int pad;
rvec x; // position
} boundary_atom;
typedef struct
{
//int ncells;
//int *cnt_by_gcell;
int cnt;
//int *block;
int *index;
//MPI_Datatype out_dtype;
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_Request send_req1[REAX_MAX_NBRS];
//MPI_Request send_req2[REAX_MAX_NBRS];
//MPI_Status send_stat1[REAX_MAX_NBRS];
//MPI_Status send_stat2[REAX_MAX_NBRS];
//MPI_Status recv_stat1[REAX_MAX_NBRS];
//MPI_Status recv_stat2[REAX_MAX_NBRS];
mpi_out_data out_buffers[REAX_MAX_NBRS];
void *in1_buffer;
void *in2_buffer;
} mpi_datatypes;
/* Global params mapping */
/*
l[0] = p_boc1
l[1] = p_boc2
l[2] = p_coa2
l[3] = N/A
l[4] = N/A
l[5] = N/A
l[6] = p_ovun6
l[7] = N/A
l[8] = p_ovun7
l[9] = p_ovun8
l[10] = N/A
l[11] = swa
l[12] = swb
l[13] = N/A
l[14] = p_val6
l[15] = p_lp1
l[16] = p_val9
l[17] = p_val10
l[18] = N/A
l[19] = p_pen2
l[20] = p_pen3
l[21] = p_pen4
l[22] = N/A
l[23] = p_tor2
l[24] = p_tor3
l[25] = p_tor4
l[26] = N/A
l[27] = p_cot2
l[28] = p_vdW1
l[29] = v_par30
l[30] = p_coa4
l[31] = p_ovun4
l[32] = p_ovun3
l[33] = p_val8
l[34] = N/A
l[35] = N/A
l[36] = N/A
l[37] = version number
l[38] = p_coa3
*/
typedef struct
{
int n_global;
real* l;
int vdw_type;
} global_parameters;
typedef struct
{
/* Line one in field file */
char name[15]; // Two character atom name
real r_s;
real valency; // Valency of the atom
real mass; // Mass of atom
real r_vdw;
real epsilon;
real gamma;
real r_pi;
real valency_e;
real nlp_opt;
/* Line two in field file */
real alpha;
real gamma_w;
real valency_boc;
real p_ovun5;
real chi;
real eta;
int p_hbond; // 1 for H, 2 for hbonding atoms (O,S,P,N), 0 for others
/* Line three in field file */
real r_pi_pi;
real p_lp2;
real b_o_131;
real b_o_132;
real b_o_133;
/* Line four in the field file */
real p_ovun2;
real p_val3;
real valency_val;
real p_val5;
real rcore2;
real ecore2;
real acore2;
/* Line five in the ffield file, only for lgvdw yes */
real lgcij;
real lgre;
} single_body_parameters;
/* Two Body Parameters */
typedef struct {
/* Bond Order parameters */
real p_bo1,p_bo2,p_bo3,p_bo4,p_bo5,p_bo6;
real r_s, r_p, r_pp; // r_o distances in BO formula
real p_boc3, p_boc4, p_boc5;
/* Bond Energy parameters */
real p_be1, p_be2;
real De_s, De_p, De_pp;
/* Over/Under coordination parameters */
real p_ovun1;
/* Van der Waal interaction parameters */
real D;
real alpha;
real r_vdW;
real gamma_w;
real rcore, ecore, acore;
real lgcij, lgre;
/* electrostatic parameters */
real gamma; // note: this parameter is gamma^-3 and not gamma.
real v13cor, ovc;
} two_body_parameters;
/* 3-body parameters */
typedef struct {
/* valence angle */
real theta_00;
real p_val1, p_val2, p_val4, p_val7;
/* penalty */
real p_pen1;
/* 3-body conjugation */
real 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{
real r0_hb, p_hb1, p_hb2, p_hb3;
} hbond_parameters;
/* 4-body parameters */
typedef struct {
real V1, V2, V3;
/* torsion angle */
real p_tor1;
/* 4-body conjugation */
real 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
{
int orig_id;
int imprt_id;
int type;
char name[8];
rvec x; // position
rvec v; // velocity
rvec f; // force
rvec f_old;
real 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
{
real V;
rvec min, max, box_norms;
rtensor box, box_inv;
rtensor trans, trans_inv;
rtensor g;
} simulation_box;
struct grid_cell
{
real 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;
real 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
{
real ghost_nonb;
real ghost_hbond;
real ghost_bond;
real ghost_cutoff;
} boundary_cutoff;
using LAMMPS_NS::Pair;
struct _reax_system
{
reax_interaction reax_param;
int n, N, bigN, 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;
real safezone, saferzone;
};
typedef _reax_system reax_system;
/* system control parameters */
typedef struct
{
char sim_name[REAX_MAX_STR];
int nprocs;
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;
real dt;
int geo_format;
int restart;
int restrict_bonds;
int remove_CoM_vel;
int random_vel;
int reposition_atoms;
int reneighbor;
real vlist_cut;
real bond_cut;
real nonb_cut, nonb_low;
real hbond_cut;
real user_ghost_cut;
real bg_cut;
real bo_cut;
real thb_cut;
real thb_cutsq;
int tabulate;
int qeq_freq;
real q_err;
int refactor;
real droptol;
real T_init, T_final, T;
real Tau_T;
int T_mode;
real T_rate, T_freq;
int virial;
rvec P, Tau_P, Tau_PT;
int press_mode;
real 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;
} control_params;
typedef struct
{
real T;
real xi;
real v_xi;
real v_xi_old;
real G_xi;
} thermostat;
typedef struct
{
real P;
real eps;
real v_eps;
real v_eps_old;
real a_eps;
} isotropic_barostat;
typedef struct
{
rtensor P;
real P_scalar;
real eps;
real v_eps;
real v_eps_old;
real a_eps;
rtensor h0;
rtensor v_g0;
rtensor v_g0_old;
rtensor a_g0;
} flexible_barostat;
typedef struct
{
real start;
real end;
real elapsed;
real total;
real comm;
real nbrs;
real init_forces;
real bonded;
real nonb;
real qEq;
int s_matvecs;
int t_matvecs;
} reax_timing;
typedef struct
{
real e_tot;
real e_kin; // Total kinetic energy
real e_pot;
real e_bond; // Total bond energy
real e_ov; // Total over coordination
real e_un; // Total under coordination energy
real e_lp; // Total under coordination energy
real e_ang; // Total valance angle energy
real e_pen; // Total penalty energy
real e_coa; // Total three body conjgation energy
real e_hb; // Total Hydrogen bond energy
real e_tor; // Total torsional energy
real e_con; // Total four body conjugation energy
real e_vdW; // Total van der Waals energy
real e_ele; // Total electrostatics energy
real e_pol; // Polarization energy
} energy_data;
typedef struct
{
int step;
int prev_steps;
real time;
real M; // Total Mass
real 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
real etran_cm; // Translational kinetic energy of CoM
real erot_cm; // Rotational kinetic energy of CoM
rtensor kinetic; // Kinetic energy tensor
rtensor virial; // Hydrodynamic virial
energy_data my_en;
energy_data sys_en;
real 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;
real inv_W;
real 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
real theta, cos_theta;
rvec dcos_di, dcos_dj, dcos_dk;
} three_body_interaction_data;
typedef struct {
int nbr;
ivec rel_box;
real 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{
real BO, BO_s, BO_pi, BO_pi2;
real Cdbo, Cdbopi, Cdbopi2;
real C1dbo, C2dbo, C3dbo;
real C1dbopi, C2dbopi, C3dbopi, C4dbopi;
real C1dbopi2, C2dbopi2, C3dbopi2, C4dbopi2;
rvec dBOp, dln_BOp_s, dln_BOp_pi, dln_BOp_pi2;
} bond_order_data;
typedef struct {
int nbr;
int sym_index;
int dbond_index;
ivec rel_box;
// rvec ext_factor;
real d;
rvec dvec;
bond_order_data bo_data;
} bond_data;
typedef struct {
int j;
real 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 */
real *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 */
real *total_bond_order;
real *Deltap, *Deltap_boc;
real *Delta, *Delta_lp, *Delta_lp_temp, *Delta_e, *Delta_boc, *Delta_val;
real *dDelta_lp, *dDelta_lp_temp;
real *nlp, *nlp_temp, *Clp, *vlpex;
rvec *dDeltap_self;
int *bond_mark, *done_after;
/* QEq storage */
sparse_matrix *H, *L, *U;
real *Hdia_inv, *b_s, *b_t, *b_prc, *b_prm, *s, *t;
real *droptol;
rvec2 *b, *x;
/* GMRES storage */
real *y, *z, *g;
real *hc, *hs;
real **h, **v;
/* CG storage */
real *r, *d, *q, *p;
rvec2 *r2, *d2, *q2, *p2;
/* Taper */
real 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 */
real *CdDelta; // coefficient of dDelta
rvec *f;
#ifdef TEST_FORCES
rvec *f_ele;
rvec *f_vdw;
rvec *f_bo;
rvec *f_be;
rvec *f_lp;
rvec *f_ov;
rvec *f_un;
rvec *f_ang;
rvec *f_coa;
rvec *f_pen;
rvec *f_hb;
rvec *f_tor;
rvec *f_con;
rvec *f_tot;
rvec *dDelta; // calculated on the fly in bond_orders.c together with bo'
int *rcounts;
int *displs;
int *id_all;
rvec *f_all;
#endif
reallocate_data realloc;
//int *num_bonds;
/* hydrogen bonds */
//int num_H, Hcap;
//int *Hindex;
//int *num_hbonds;
//int *hash;
//int *rev_hash;
} 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
{
#if defined(PURE_REAX)
MPI_File trj;
#endif
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;
#ifdef TEST_ENERGY
FILE *ebond;
FILE *elp, *eov, *eun;
FILE *eval, *epen, *ecoa;
FILE *ehb;
FILE *etor, *econ;
FILE *evdw, *ecou;
#endif
#ifdef TEST_FORCES
FILE *fbo, *fdbo;
FILE *fbond;
FILE *flp, *fov, *fun;
FILE *fang, *fcoa, *fpen;
FILE *fhb;
FILE *ftor, *fcon;
FILE *fvdw, *fele;
FILE *ftot, *fcomp;
#endif
#if defined(TEST_ENERGY) || defined(TEST_FORCES)
FILE *flist; // far neighbor list
FILE *blist; // bond list
FILE *nlist; // near neighbor list
#endif
} output_controls;
typedef struct
{
int atom_count;
int atom_list[REAX_MAX_MOLECULE_SIZE];
int mtypes[REAX_MAX_ATOM_TYPES];
} molecule;
typedef struct
{
real H;
real e_vdW, CEvd;
real e_ele, CEclmb;
} LR_data;
typedef struct
{
real a, b, c, d;
} cubic_spline_coef;
typedef struct
{
real xmin, xmax;
int n;
real dx, inv_dx;
real a;
real m;
real 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* );
#if defined(PURE_REAX)
evolve_function Evolve;
#endif
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 real (*lookup_function)(real);
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-SPH/atom_vec_meso.cpp b/src/USER-SPH/atom_vec_meso.cpp
index 4df4b1503..bca14645d 100644
--- a/src/USER-SPH/atom_vec_meso.cpp
+++ b/src/USER-SPH/atom_vec_meso.cpp
@@ -1,980 +1,977 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_meso.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecMeso::AtomVecMeso(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
mass_type = 1;
comm_x_only = 0; // we communicate not only x forward but also vest ...
comm_f_only = 0; // we also communicate de and drho in reverse direction
size_forward = 8; // 3 + rho + e + vest[3], that means we may only communicate 5 in hybrid
size_reverse = 5; // 3 + drho + de
size_border = 12; // 6 + rho + e + vest[3] + cv
size_velocity = 3;
size_data_atom = 8;
size_data_vel = 4;
xcol_data = 6;
atom->e_flag = 1;
atom->rho_flag = 1;
atom->cv_flag = 1;
atom->vest_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecMeso::grow(int n) {
if (n == 0)
nmax += DELTA;
else
nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag, nmax, "atom:tag");
type = memory->grow(atom->type, nmax, "atom:type");
mask = memory->grow(atom->mask, nmax, "atom:mask");
image = memory->grow(atom->image, nmax, "atom:image");
x = memory->grow(atom->x, nmax, 3, "atom:x");
v = memory->grow(atom->v, nmax, 3, "atom:v");
f = memory->grow(atom->f, nmax*comm->nthreads, 3, "atom:f");
rho = memory->grow(atom->rho, nmax, "atom:rho");
drho = memory->grow(atom->drho, nmax*comm->nthreads, "atom:drho");
e = memory->grow(atom->e, nmax, "atom:e");
de = memory->grow(atom->de, nmax*comm->nthreads, "atom:de");
vest = memory->grow(atom->vest, nmax, 3, "atom:vest");
cv = memory->grow(atom->cv, nmax, "atom:cv");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecMeso::grow_reset() {
tag = atom->tag;
type = atom->type;
mask = atom->mask;
image = atom->image;
x = atom->x;
v = atom->v;
f = atom->f;
rho = atom->rho;
drho = atom->drho;
e = atom->e;
de = atom->de;
vest = atom->vest;
cv = atom->cv;
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::copy(int i, int j, int delflag) {
//printf("in AtomVecMeso::copy\n");
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
rho[j] = rho[i];
drho[j] = drho[i];
e[j] = e[i];
de[j] = de[i];
cv[j] = cv[i];
vest[j][0] = vest[i][0];
vest[j][1] = vest[i][1];
vest[j][2] = vest[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i, j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_comm_hybrid(int n, int *list, double *buf) {
//printf("in AtomVecMeso::pack_comm_hybrid\n");
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::unpack_comm_hybrid(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_comm_hybrid\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
rho[i] = buf[m++];
e[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_border_hybrid(int n, int *list, double *buf) {
//printf("in AtomVecMeso::pack_border_hybrid\n");
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::unpack_border_hybrid(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_border_hybrid\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
rho[i] = buf[m++];
e[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_reverse_hybrid(int n, int first, double *buf) {
//printf("in AtomVecMeso::pack_reverse_hybrid\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = drho[i];
buf[m++] = de[i];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::unpack_reverse_hybrid(int n, int *list, double *buf) {
//printf("in AtomVecMeso::unpack_reverse_hybrid\n");
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
drho[j] += buf[m++];
de[j] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_comm(int n, int *list, double *buf, int pbc_flag,
int *pbc) {
//printf("in AtomVecMeso::pack_comm\n");
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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_comm_vel(int n, int *list, double *buf, int pbc_flag,
int *pbc) {
//printf("in AtomVecMeso::pack_comm_vel\n");
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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::unpack_comm(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_comm\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
rho[i] = buf[m++];
e[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::unpack_comm_vel(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_comm_vel\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
rho[i] = buf[m++];
e[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_reverse(int n, int first, double *buf) {
//printf("in AtomVecMeso::pack_reverse\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = drho[i];
buf[m++] = de[i];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::unpack_reverse(int n, int *list, double *buf) {
//printf("in AtomVecMeso::unpack_reverse\n");
int i, j, m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
drho[j] += buf[m++];
de[j] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_border(int n, int *list, double *buf, int pbc_flag,
int *pbc) {
//printf("in AtomVecMeso::pack_border\n");
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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = cv[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[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];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = cv[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::pack_border_vel(int n, int *list, double *buf, int pbc_flag,
int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = cv[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = cv[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = rho[j];
buf[m++] = e[j];
buf[m++] = cv[j];
buf[m++] = vest[j][0];
buf[m++] = vest[j][1];
buf[m++] = vest[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::unpack_border(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_border\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax)
grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
rho[i] = buf[m++];
e[i] = buf[m++];
cv[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecMeso::unpack_border_vel(int n, int first, double *buf) {
//printf("in AtomVecMeso::unpack_border_vel\n");
int i, m, last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax)
grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
rho[i] = buf[m++];
e[i] = buf[m++];
cv[i] = buf[m++];
vest[i][0] = buf[m++];
vest[i][1] = buf[m++];
vest[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecMeso::pack_exchange(int i, double *buf) {
//printf("in AtomVecMeso::pack_exchange\n");
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = rho[i];
buf[m++] = e[i];
buf[m++] = cv[i];
buf[m++] = vest[i][0];
buf[m++] = vest[i][1];
buf[m++] = vest[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i, &buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecMeso::unpack_exchange(double *buf) {
//printf("in AtomVecMeso::unpack_exchange\n");
int nlocal = atom->nlocal;
if (nlocal == nmax)
grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
rho[nlocal] = buf[m++];
e[nlocal] = buf[m++];
cv[nlocal] = buf[m++];
vest[nlocal][0] = buf[m++];
vest[nlocal][1] = buf[m++];
vest[nlocal][2] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,
&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecMeso::size_restart() {
int i;
int nlocal = atom->nlocal;
int n = 17 * nlocal; // 11 + rho + e + cv + vest[3]
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecMeso::pack_restart(int i, double *buf) {
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = rho[i];
buf[m++] = e[i];
buf[m++] = cv[i];
buf[m++] = vest[i][0];
buf[m++] = vest[i][1];
buf[m++] = vest[i][2];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i, &buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecMeso::unpack_restart(double *buf) {
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra, nmax, atom->nextra_store, "atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
rho[nlocal] = buf[m++];
e[nlocal] = buf[m++];
cv[nlocal] = buf[m++];
vest[nlocal][0] = buf[m++];
vest[nlocal][1] = buf[m++];
vest[nlocal][2] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++)
extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecMeso::create_atom(int itype, double *coord) {
int nlocal = atom->nlocal;
if (nlocal == nmax)
grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
rho[nlocal] = 0.0;
e[nlocal] = 0.0;
cv[nlocal] = 1.0;
vest[nlocal][0] = 0.0;
vest[nlocal][1] = 0.0;
vest[nlocal][2] = 0.0;
de[nlocal] = 0.0;
drho[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecMeso::data_atom(double *coord, imageint imagetmp, char **values) {
int nlocal = atom->nlocal;
- if (nlocal == nmax)
- grow(0);
-
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
+ if (nlocal == nmax) grow(0);
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
rho[nlocal] = atof(values[2]);
e[nlocal] = atof(values[3]);
cv[nlocal] = atof(values[4]);
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
//printf("rho=%f, e=%f, cv=%f, x=%f\n", rho[nlocal], e[nlocal], cv[nlocal], x[nlocal][0]);
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
vest[nlocal][0] = 0.0;
vest[nlocal][1] = 0.0;
vest[nlocal][2] = 0.0;
de[nlocal] = 0.0;
drho[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecMeso::data_atom_hybrid(int nlocal, char **values) {
rho[nlocal] = atof(values[0]);
e[nlocal] = atof(values[1]);
cv[nlocal] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecMeso::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = rho[i];
buf[i][3] = e[i];
buf[i][4] = cv[i];
buf[i][5] = x[i][0];
buf[i][6] = x[i][1];
buf[i][7] = x[i][2];
buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecMeso::pack_data_hybrid(int i, double *buf)
{
buf[0] = rho[i];
buf[1] = e[i];
buf[2] = cv[i];
return 3;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecMeso::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e "
+ fprintf(fp,TAGINT_FORMAT
+ " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e "
"%d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4],
buf[i][5],buf[i][6],buf[i][7],
(int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i,
(int) ubuf(buf[i][10]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecMeso::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecMeso::memory_usage() {
bigint bytes = 0;
if (atom->memcheck("tag"))
bytes += memory->usage(tag, nmax);
if (atom->memcheck("type"))
bytes += memory->usage(type, nmax);
if (atom->memcheck("mask"))
bytes += memory->usage(mask, nmax);
if (atom->memcheck("image"))
bytes += memory->usage(image, nmax);
if (atom->memcheck("x"))
bytes += memory->usage(x, nmax, 3);
if (atom->memcheck("v"))
bytes += memory->usage(v, nmax, 3);
if (atom->memcheck("f"))
bytes += memory->usage(f, nmax*comm->nthreads, 3);
if (atom->memcheck("rho"))
bytes += memory->usage(rho, nmax);
if (atom->memcheck("drho"))
bytes += memory->usage(drho, nmax*comm->nthreads);
if (atom->memcheck("e"))
bytes += memory->usage(e, nmax);
if (atom->memcheck("de"))
bytes += memory->usage(de, nmax*comm->nthreads);
if (atom->memcheck("cv"))
bytes += memory->usage(cv, nmax);
if (atom->memcheck("vest"))
bytes += memory->usage(vest, nmax);
return bytes;
}
diff --git a/src/USER-SPH/atom_vec_meso.h b/src/USER-SPH/atom_vec_meso.h
index 59c27818d..8f3e66453 100644
--- a/src/USER-SPH/atom_vec_meso.h
+++ b/src/USER-SPH/atom_vec_meso.h
@@ -1,75 +1,76 @@
/* -*- 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 ATOM_CLASS
AtomStyle(meso,AtomVecMeso)
#else
#ifndef LMP_ATOM_VEC_MESO_H
#define LMP_ATOM_VEC_MESO_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecMeso : public AtomVec {
public:
AtomVecMeso(class LAMMPS *);
~AtomVecMeso() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_comm_hybrid(int, int *, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_border_hybrid(int, int *, double *);
int unpack_border_hybrid(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ int *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *rho, *drho, *e, *de, *cv;
double **vest; // estimated velocity during force computation
};
}
#endif
#endif
diff --git a/src/XTC/dump_xtc.cpp b/src/XTC/dump_xtc.cpp
index 80f1013af..f7c2f8ec0 100644
--- a/src/XTC/dump_xtc.cpp
+++ b/src/XTC/dump_xtc.cpp
@@ -1,1192 +1,1192 @@
/* ----------------------------------------------------------------------
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: Naveen Michaud-Agrawal (Johns Hopkins U)
open-source XDR routines from
Frans van Hoesel (http://md.chem.rug.nl/hoesel)
are included in this file
Axel Kohlmeyer (Temple U)
port to platforms without XDR support
added support for unwrapped trajectories
support for groups
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "limits.h"
#include "dump_xtc.h"
#include "domain.h"
#include "atom.h"
#include "update.h"
#include "group.h"
#include "output.h"
#include "error.h"
#include "force.h"
#include "memory.h"
using namespace LAMMPS_NS;
#define EPS 1e-5
#define XTC_MAGIC 1995
#define MYMIN(a,b) ((a) < (b) ? (a) : (b))
#define MYMAX(a,b) ((a) > (b) ? (a) : (b))
int xdropen(XDR *, const char *, const char *);
int xdrclose(XDR *);
void xdrfreebuf();
int xdr3dfcoord(XDR *, float *, int *, float *);
/* ---------------------------------------------------------------------- */
DumpXTC::DumpXTC(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg)
{
if (narg != 5) error->all(FLERR,"Illegal dump xtc command");
if (binary || compressed || multifile || multiproc)
error->all(FLERR,"Invalid dump xtc filename");
size_one = 3;
sort_flag = 1;
sortcol = 0;
format_default = NULL;
flush_flag = 0;
unwrap_flag = 0;
precision = 1000.0;
// allocate global array for atom coords
bigint n = group->count(igroup);
if (n > MAXSMALLINT/3/sizeof(float))
error->all(FLERR,"Too many atoms for dump xtc");
natoms = static_cast<int> (n);
memory->create(coords,3*natoms,"dump:coords");
// sfactor = conversion of coords to XTC units
// GROMACS standard is nanometers, not Angstroms
sfactor = 0.1;
if (strcmp(update->unit_style,"lj") == 0) sfactor = 1.0;
openfile();
nevery_save = 0;
ntotal = 0;
}
/* ---------------------------------------------------------------------- */
DumpXTC::~DumpXTC()
{
memory->destroy(coords);
if (me == 0) {
xdrclose(&xd);
xdrfreebuf();
}
}
/* ---------------------------------------------------------------------- */
void DumpXTC::init_style()
{
if (sort_flag == 0 || sortcol != 0)
error->all(FLERR,"Dump xtc requires sorting by atom ID");
// check that flush_flag is not set since dump::write() will use it
if (flush_flag) error->all(FLERR,"Cannot set dump_modify flush for dump xtc");
// check that dump frequency has not changed and is not a variable
int idump;
for (idump = 0; idump < output->ndump; idump++)
if (strcmp(id,output->dump[idump]->id) == 0) break;
if (output->every_dump[idump] == 0)
error->all(FLERR,"Cannot use variable every setting for dump xtc");
if (nevery_save == 0) nevery_save = output->every_dump[idump];
else if (nevery_save != output->every_dump[idump])
error->all(FLERR,"Cannot change dump_modify every for dump xtc");
}
/* ---------------------------------------------------------------------- */
void DumpXTC::openfile()
{
// XTC maintains it's own XDR file ptr
// set fp to NULL so parent dump class will not use it
fp = NULL;
if (me == 0)
if (xdropen(&xd,filename,"w") == 0) error->one(FLERR,"Cannot open dump file");
}
/* ---------------------------------------------------------------------- */
void DumpXTC::write_header(bigint nbig)
{
if (nbig > MAXSMALLINT) error->all(FLERR,"Too many atoms for dump xtc");
int n = nbig;
if (update->ntimestep > MAXSMALLINT)
error->all(FLERR,"Too big a timestep for dump xtc");
int ntimestep = update->ntimestep;
// all procs realloc coords if total count grew
if (n != natoms) {
natoms = n;
memory->destroy(coords);
memory->create(coords,3*natoms,"dump:coords");
}
// only proc 0 writes header
if (me != 0) return;
int tmp = XTC_MAGIC;
xdr_int(&xd,&tmp);
xdr_int(&xd,&n);
xdr_int(&xd,&ntimestep);
float time_value = ntimestep * update->dt;
xdr_float(&xd,&time_value);
// cell basis vectors
if (domain->triclinic) {
float zero = 0.0;
float xdim = sfactor * (domain->boxhi[0] - domain->boxlo[0]);
float ydim = sfactor * (domain->boxhi[1] - domain->boxlo[1]);
float zdim = sfactor * (domain->boxhi[2] - domain->boxlo[2]);
float xy = sfactor * domain->xy;
float xz = sfactor * domain->xz;
float yz = sfactor * domain->yz;
xdr_float(&xd,&xdim); xdr_float(&xd,&zero); xdr_float(&xd,&zero);
xdr_float(&xd,&xy ); xdr_float(&xd,&ydim); xdr_float(&xd,&zero);
xdr_float(&xd,&xz ); xdr_float(&xd,&yz ); xdr_float(&xd,&zdim);
} else {
float zero = 0.0;
float xdim = sfactor * (domain->boxhi[0] - domain->boxlo[0]);
float ydim = sfactor * (domain->boxhi[1] - domain->boxlo[1]);
float zdim = sfactor * (domain->boxhi[2] - domain->boxlo[2]);
xdr_float(&xd,&xdim); xdr_float(&xd,&zero); xdr_float(&xd,&zero);
xdr_float(&xd,&zero); xdr_float(&xd,&ydim); xdr_float(&xd,&zero);
xdr_float(&xd,&zero); xdr_float(&xd,&zero); xdr_float(&xd,&zdim);
}
}
/* ---------------------------------------------------------------------- */
-void DumpXTC::pack(int *ids)
+void DumpXTC::pack(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
m = n = 0;
if (unwrap_flag == 1) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
buf[m++] = sfactor * (x[i][0] + ix * xprd + iy * xy + iz * xz);
buf[m++] = sfactor * (x[i][1] + iy * yprd + iz * yz);
buf[m++] = sfactor * (x[i][2] + iz * zprd);
} else {
buf[m++] = sfactor * (x[i][0] + ix * xprd);
buf[m++] = sfactor * (x[i][1] + iy * yprd);
buf[m++] = sfactor * (x[i][2] + iz * zprd);
}
ids[n++] = tag[i];
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = sfactor*x[i][0];
buf[m++] = sfactor*x[i][1];
buf[m++] = sfactor*x[i][2];
ids[n++] = tag[i];
}
}
}
/* ---------------------------------------------------------------------- */
void DumpXTC::write_data(int n, double *mybuf)
{
// copy buf atom coords into global array
int m = 0;
int k = 3*ntotal;
for (int i = 0; i < n; i++) {
coords[k++] = mybuf[m++];
coords[k++] = mybuf[m++];
coords[k++] = mybuf[m++];
ntotal++;
}
// if last chunk of atoms in this snapshot, write global arrays to file
if (ntotal == natoms) {
write_frame();
ntotal = 0;
}
}
/* ---------------------------------------------------------------------- */
int DumpXTC::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"unwrap") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"yes") == 0) unwrap_flag = 1;
else if (strcmp(arg[1],"no") == 0) unwrap_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
return 2;
} else if (strcmp(arg[0],"precision") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
precision = force->numeric(FLERR,arg[1]);
if ((fabs(precision-10.0) > EPS) && (fabs(precision-100.0) > EPS) &&
(fabs(precision-1000.0) > EPS) && (fabs(precision-10000.0) > EPS) &&
(fabs(precision-100000.0) > EPS) &&
(fabs(precision-1000000.0) > EPS))
error->all(FLERR,"Illegal dump_modify command");
return 2;
}
return 0;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory in buf and global coords array
------------------------------------------------------------------------- */
bigint DumpXTC::memory_usage()
{
bigint bytes = Dump::memory_usage();
bytes += memory->usage(coords,natoms*3);
return bytes;
}
/* ---------------------------------------------------------------------- */
void DumpXTC::write_frame()
{
xdr3dfcoord(&xd,coords,&natoms,&precision);
}
// ----------------------------------------------------------------------
// C functions that create GROMOS-compatible XDR files
// open-source
// (c) 1995 Frans van Hoesel, hoesel@chem.rug.nl
// ----------------------------------------------------------------------
/*____________________________________________________________________________
|
| Below are the routines to be used by C programmers. Use the 'normal'
| xdr routines to write integers, floats, etc (see man xdr)
|
| int xdropen(XDR *xdrs, const char *filename, const char *type)
| This will open the file with the given filename and the
| given mode. You should pass it an allocated XDR struct
| in xdrs, to be used in all other calls to xdr routines.
| Mode is 'w' to create, or update an file, and for all
| other values of mode the file is opened for reading.
| You need to call xdrclose to flush the output and close
| the file.
|
| Note that you should not use xdrstdio_create, which
| comes with the standard xdr library.
|
| int xdrclose(XDR *xdrs)
| Flush the data to the file, and close the file;
| You should not use xdr_destroy (which comes standard
| with the xdr libraries).
|
| int xdr3dfcoord(XDR *xdrs, float *fp, int *size, float *precision)
| This is \fInot\fR a standard xdr routine. I named it this
| way, because it invites people to use the other xdr
| routines.
|
| (c) 1995 Frans van Hoesel, hoesel@chem.rug.nl
*/
#define MAXID 20
static FILE *xdrfiles[MAXID];
static XDR *xdridptr[MAXID];
static char xdrmodes[MAXID];
static int *ip = NULL;
static int *buf = NULL;
/*___________________________________________________________________________
|
| what follows are the C routines for opening, closing xdr streams
| and the routine to read/write compressed coordinates together
| with some routines to assist in this task (those are marked
| static and cannot be called from user programs)
*/
#define MAXABS INT_MAX-2
#ifndef SQR
#define SQR(x) ((x)*(x))
#endif
static int magicints[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 10, 12, 16, 20, 25, 32, 40, 50, 64,
80, 101, 128, 161, 203, 256, 322, 406, IMGMAX, 645,
812, 1024, 1290, 1625, 2048, 2580, 3250, 4096, 5060, 6501,
8192, 10321, 13003, 16384, 20642, 26007, 32768, 41285, 52015, 65536,
82570, 104031, 131072, 165140, 208063, 262144, 330280, 416127,
524287, 660561,
832255, 1048576, 1321122, 1664510, 2097152, 2642245, 3329021,
4194304, 5284491, 6658042,
8388607, 10568983, 13316085, 16777216 };
#define FIRSTIDX 9
/* note that magicints[FIRSTIDX-1] == 0 */
#define LASTIDX (sizeof(magicints) / sizeof(*magicints))
/*__________________________________________________________________________
|
| xdropen - open xdr file
|
| This versions differs from xdrstdio_create, because I need to know
| the state of the file (read or write) so I can use xdr3dfcoord
| in eigther read or write mode, and the file descriptor
| so I can close the file (something xdr_destroy doesn't do).
|
*/
int xdropen(XDR *xdrs, const char *filename, const char *type)
{
static int init_done = 0;
enum xdr_op lmode;
int xdrid;
if (init_done == 0) {
for (xdrid = 1; xdrid < MAXID; xdrid++) {
xdridptr[xdrid] = NULL;
}
init_done = 1;
}
xdrid = 1;
while (xdrid < MAXID && xdridptr[xdrid] != NULL) {
xdrid++;
}
if (xdrid == MAXID) {
return 0;
}
if (*type == 'w' || *type == 'W') {
type = (char *) "w+";
lmode = XDR_ENCODE;
} else {
type = (char *) "r";
lmode = XDR_DECODE;
}
xdrfiles[xdrid] = fopen(filename, type);
if (xdrfiles[xdrid] == NULL) {
xdrs = NULL;
return 0;
}
xdrmodes[xdrid] = *type;
/* next test isn't usefull in the case of C language
* but is used for the Fortran interface
* (C users are expected to pass the address of an already allocated
* XDR staructure)
*/
if (xdrs == NULL) {
xdridptr[xdrid] = (XDR *) malloc(sizeof(XDR));
xdrstdio_create(xdridptr[xdrid], xdrfiles[xdrid], lmode);
} else {
xdridptr[xdrid] = xdrs;
xdrstdio_create(xdrs, xdrfiles[xdrid], lmode);
}
return xdrid;
}
/*_________________________________________________________________________
|
| xdrclose - close a xdr file
|
| This will flush the xdr buffers, and destroy the xdr stream.
| It also closes the associated file descriptor (this is *not*
| done by xdr_destroy).
|
*/
int xdrclose(XDR *xdrs)
{
int xdrid;
if (xdrs == NULL) {
fprintf(stderr, "xdrclose: passed a NULL pointer\n");
exit(1);
}
for (xdrid = 1; xdrid < MAXID; xdrid++) {
if (xdridptr[xdrid] == xdrs) {
xdr_destroy(xdrs);
fclose(xdrfiles[xdrid]);
xdridptr[xdrid] = NULL;
return 1;
}
}
fprintf(stderr, "xdrclose: no such open xdr file\n");
exit(1);
return 1;
}
/*_________________________________________________________________________
|
| xdrfreebuf - free the buffers used by xdr3dfcoord
|
*/
void xdrfreebuf()
{
if (ip) free(ip);
if (buf) free(buf);
ip = NULL;
buf = NULL;
}
/*____________________________________________________________________________
|
| sendbits - encode num into buf using the specified number of bits
|
| This routines appends the value of num to the bits already present in
| the array buf. You need to give it the number of bits to use and you
| better make sure that this number of bits is enough to hold the value
| Also num must be positive.
|
*/
static void sendbits(int buf[], int num_of_bits, int num)
{
unsigned int cnt, lastbyte;
int lastbits;
unsigned char * cbuf;
cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf);
cnt = (unsigned int) buf[0];
lastbits = buf[1];
lastbyte =(unsigned int) buf[2];
while (num_of_bits >= 8) {
lastbyte = (lastbyte << 8) | ((num >> (num_of_bits -8)) /* & 0xff*/);
cbuf[cnt++] = lastbyte >> lastbits;
num_of_bits -= 8;
}
if (num_of_bits > 0) {
lastbyte = (lastbyte << num_of_bits) | num;
lastbits += num_of_bits;
if (lastbits >= 8) {
lastbits -= 8;
cbuf[cnt++] = lastbyte >> lastbits;
}
}
buf[0] = cnt;
buf[1] = lastbits;
buf[2] = lastbyte;
if (lastbits>0) {
cbuf[cnt] = lastbyte << (8 - lastbits);
}
}
/*_________________________________________________________________________
|
| sizeofint - calculate bitsize of an integer
|
| return the number of bits needed to store an integer with given max size
|
*/
static int sizeofint(const int size)
{
unsigned int num = 1;
int num_of_bits = 0;
while (size >= num && num_of_bits < 32) {
num_of_bits++;
num <<= 1;
}
return num_of_bits;
}
/*___________________________________________________________________________
|
| sizeofints - calculate 'bitsize' of compressed ints
|
| given the number of small unsigned integers and the maximum value
| return the number of bits needed to read or write them with the
| routines receiveints and sendints. You need this parameter when
| calling these routines. Note that for many calls I can use
| the variable 'smallidx' which is exactly the number of bits, and
| So I don't need to call 'sizeofints for those calls.
*/
static int sizeofints( const int num_of_ints, unsigned int sizes[])
{
int i, num;
unsigned int num_of_bytes, num_of_bits, bytes[32], bytecnt, tmp;
num_of_bytes = 1;
bytes[0] = 1;
num_of_bits = 0;
for (i=0; i < num_of_ints; i++) {
tmp = 0;
for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {
tmp = bytes[bytecnt] * sizes[i] + tmp;
bytes[bytecnt] = tmp & 0xff;
tmp >>= 8;
}
while (tmp != 0) {
bytes[bytecnt++] = tmp & 0xff;
tmp >>= 8;
}
num_of_bytes = bytecnt;
}
num = 1;
num_of_bytes--;
while (bytes[num_of_bytes] >= num) {
num_of_bits++;
num *= 2;
}
return num_of_bits + num_of_bytes * 8;
}
/*____________________________________________________________________________
|
| sendints - send a small set of small integers in compressed
|
| this routine is used internally by xdr3dfcoord, to send a set of
| small integers to the buffer.
| Multiplication with fixed (specified maximum ) sizes is used to get
| to one big, multibyte integer. Allthough the routine could be
| modified to handle sizes bigger than 16777216, or more than just
| a few integers, this is not done, because the gain in compression
| isn't worth the effort. Note that overflowing the multiplication
| or the byte buffer (32 bytes) is unchecked and causes bad results.
|
*/
static void sendints(int buf[], const int num_of_ints, const int num_of_bits,
unsigned int sizes[], unsigned int nums[])
{
int i;
unsigned int bytes[32], num_of_bytes, bytecnt, tmp;
tmp = nums[0];
num_of_bytes = 0;
do {
bytes[num_of_bytes++] = tmp & 0xff;
tmp >>= 8;
} while (tmp != 0);
for (i = 1; i < num_of_ints; i++) {
if (nums[i] >= sizes[i]) {
fprintf(stderr,"major breakdown in sendints num %d doesn't "
"match size %d\n", nums[i], sizes[i]);
exit(1);
}
/* use one step multiply */
tmp = nums[i];
for (bytecnt = 0; bytecnt < num_of_bytes; bytecnt++) {
tmp = bytes[bytecnt] * sizes[i] + tmp;
bytes[bytecnt] = tmp & 0xff;
tmp >>= 8;
}
while (tmp != 0) {
bytes[bytecnt++] = tmp & 0xff;
tmp >>= 8;
}
num_of_bytes = bytecnt;
}
if (num_of_bits >= num_of_bytes * 8) {
for (i = 0; i < num_of_bytes; i++) {
sendbits(buf, 8, bytes[i]);
}
sendbits(buf, num_of_bits - num_of_bytes * 8, 0);
} else {
for (i = 0; i < num_of_bytes-1; i++) {
sendbits(buf, 8, bytes[i]);
}
sendbits(buf, num_of_bits- (num_of_bytes -1) * 8, bytes[i]);
}
}
/*___________________________________________________________________________
|
| receivebits - decode number from buf using specified number of bits
|
| extract the number of bits from the array buf and construct an integer
| from it. Return that value.
|
*/
static int receivebits(int buf[], int num_of_bits)
{
int cnt, num;
unsigned int lastbits, lastbyte;
unsigned char * cbuf;
int mask = (1 << num_of_bits) -1;
cbuf = ((unsigned char *)buf) + 3 * sizeof(*buf);
cnt = buf[0];
lastbits = (unsigned int) buf[1];
lastbyte = (unsigned int) buf[2];
num = 0;
while (num_of_bits >= 8) {
lastbyte = ( lastbyte << 8 ) | cbuf[cnt++];
num |= (lastbyte >> lastbits) << (num_of_bits - 8);
num_of_bits -=8;
}
if (num_of_bits > 0) {
if (lastbits < num_of_bits) {
lastbits += 8;
lastbyte = (lastbyte << 8) | cbuf[cnt++];
}
lastbits -= num_of_bits;
num |= (lastbyte >> lastbits) & ((1 << num_of_bits) -1);
}
num &= mask;
buf[0] = cnt;
buf[1] = lastbits;
buf[2] = lastbyte;
return num;
}
/*____________________________________________________________________________
|
| receiveints - decode 'small' integers from the buf array
|
| this routine is the inverse from sendints() and decodes the small integers
| written to buf by calculating the remainder and doing divisions with
| the given sizes[]. You need to specify the total number of bits to be
| used from buf in num_of_bits.
|
*/
static void receiveints(int buf[], const int num_of_ints, int num_of_bits,
unsigned int sizes[], int nums[])
{
int bytes[32];
int i, j, num_of_bytes, p, num;
bytes[1] = bytes[2] = bytes[3] = 0;
num_of_bytes = 0;
while (num_of_bits > 8) {
bytes[num_of_bytes++] = receivebits(buf, 8);
num_of_bits -= 8;
}
if (num_of_bits > 0) {
bytes[num_of_bytes++] = receivebits(buf, num_of_bits);
}
for (i = num_of_ints-1; i > 0; i--) {
num = 0;
for (j = num_of_bytes-1; j >=0; j--) {
num = (num << 8) | bytes[j];
p = num / sizes[i];
bytes[j] = p;
num = num - p * sizes[i];
}
nums[i] = num;
}
nums[0] = bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
}
/*____________________________________________________________________________
|
| xdr3dfcoord - read or write compressed 3d coordinates to xdr file.
|
| this routine reads or writes (depending on how you opened the file with
| xdropen() ) a large number of 3d coordinates (stored in *fp).
| The number of coordinates triplets to write is given by *size. On
| read this number may be zero, in which case it reads as many as were written
| or it may specify the number if triplets to read (which should match the
| number written).
| Compression is achieved by first converting all floating numbers to integer
| using multiplication by *precision and rounding to the nearest integer.
| Then the minimum and maximum value are calculated to determine the range.
| The limited range of integers so found, is used to compress the coordinates.
| In addition the differences between succesive coordinates is calculated.
| If the difference happens to be 'small' then only the difference is saved,
| compressing the data even more. The notion of 'small' is changed dynamically
| and is enlarged or reduced whenever needed or possible.
| Extra compression is achieved in the case of GROMOS and coordinates of
| water molecules. GROMOS first writes out the Oxygen position, followed by
| the two hydrogens. In order to make the differences smaller (and thereby
| compression the data better) the order is changed into first one hydrogen
| then the oxygen, followed by the other hydrogen. This is rather special, but
| it shouldn't harm in the general case.
|
*/
int xdr3dfcoord(XDR *xdrs, float *fp, int *size, float *precision)
{
static int oldsize;
int minint[3], maxint[3], mindiff, *lip, diff;
int lint1, lint2, lint3, oldlint1, oldlint2, oldlint3, smallidx;
int minidx, maxidx;
unsigned sizeint[3], sizesmall[3], bitsizeint[3], size3, *luip;
int flag, k;
int small, smaller, larger, i, is_small, is_smaller, run, prevrun;
float *lfp, lf;
int tmp, *thiscoord, prevcoord[3];
unsigned int tmpcoord[30];
int bufsize, xdrid, lsize;
unsigned int bitsize;
float inv_precision;
int errval = 1;
/* find out if xdrs is opened for reading or for writing */
xdrid = 0;
while (xdridptr[xdrid] != xdrs) {
xdrid++;
if (xdrid >= MAXID) {
fprintf(stderr, "xdr error. no open xdr stream\n");
exit (1);
}
}
if (xdrmodes[xdrid] == 'w') {
/* xdrs is open for writing */
if (xdr_int(xdrs, size) == 0)
return 0;
size3 = *size * 3;
/* when the number of coordinates is small, don't try to compress; just
* write them as floats using xdr_vector
*/
if (*size <= 9 ) {
return (xdr_vector(xdrs, (char *) fp, size3, sizeof(*fp),
(xdrproc_t)xdr_float));
}
xdr_float(xdrs, precision);
if (ip == NULL) {
ip = (int *) malloc(size3 * sizeof(*ip));
if (ip == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
bufsize = (int) (size3 * 1.2);
buf = (int *) malloc(bufsize * sizeof(*buf));
if (buf == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
oldsize = *size;
} else if (*size > oldsize) {
ip = (int *) realloc(ip, size3 * sizeof(*ip));
if (ip == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
bufsize = (int) (size3 * 1.2);
buf = (int *) realloc(buf, bufsize * sizeof(*buf));
if (buf == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
oldsize = *size;
}
/* buf[0-2] are special and do not contain actual data */
buf[0] = buf[1] = buf[2] = 0;
minint[0] = minint[1] = minint[2] = INT_MAX;
maxint[0] = maxint[1] = maxint[2] = INT_MIN;
prevrun = -1;
lfp = fp;
lip = ip;
mindiff = INT_MAX;
oldlint1 = oldlint2 = oldlint3 = 0;
while(lfp < fp + size3 ) {
/* find nearest integer */
if (*lfp >= 0.0)
lf = *lfp * *precision + 0.5;
else
lf = *lfp * *precision - 0.5;
if (fabs(lf) > MAXABS) {
/* scaling would cause overflow */
errval = 0;
}
lint1 = (int) lf;
if (lint1 < minint[0]) minint[0] = lint1;
if (lint1 > maxint[0]) maxint[0] = lint1;
*lip++ = lint1;
lfp++;
if (*lfp >= 0.0)
lf = *lfp * *precision + 0.5;
else
lf = *lfp * *precision - 0.5;
if (fabs(lf) > MAXABS) {
/* scaling would cause overflow */
errval = 0;
}
lint2 = (int) lf;
if (lint2 < minint[1]) minint[1] = lint2;
if (lint2 > maxint[1]) maxint[1] = lint2;
*lip++ = lint2;
lfp++;
if (*lfp >= 0.0)
lf = *lfp * *precision + 0.5;
else
lf = *lfp * *precision - 0.5;
if (fabs(lf) > MAXABS) {
/* scaling would cause overflow */
errval = 0;
}
lint3 = (int) lf;
if (lint3 < minint[2]) minint[2] = lint3;
if (lint3 > maxint[2]) maxint[2] = lint3;
*lip++ = lint3;
lfp++;
diff = abs(oldlint1-lint1)+abs(oldlint2-lint2)+abs(oldlint3-lint3);
if (diff < mindiff && lfp > fp + 3)
mindiff = diff;
oldlint1 = lint1;
oldlint2 = lint2;
oldlint3 = lint3;
}
xdr_int(xdrs, &(minint[0]));
xdr_int(xdrs, &(minint[1]));
xdr_int(xdrs, &(minint[2]));
xdr_int(xdrs, &(maxint[0]));
xdr_int(xdrs, &(maxint[1]));
xdr_int(xdrs, &(maxint[2]));
if ((float)maxint[0] - (float)minint[0] >= MAXABS ||
(float)maxint[1] - (float)minint[1] >= MAXABS ||
(float)maxint[2] - (float)minint[2] >= MAXABS) {
/* turning value in unsigned by subtracting minint
* would cause overflow
*/
errval = 0;
}
sizeint[0] = maxint[0] - minint[0]+1;
sizeint[1] = maxint[1] - minint[1]+1;
sizeint[2] = maxint[2] - minint[2]+1;
/* check if one of the sizes is to big to be multiplied */
if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) {
bitsizeint[0] = sizeofint(sizeint[0]);
bitsizeint[1] = sizeofint(sizeint[1]);
bitsizeint[2] = sizeofint(sizeint[2]);
bitsize = 0; /* flag the use of large sizes */
} else {
bitsize = sizeofints(3, sizeint);
}
lip = ip;
luip = (unsigned int *) ip;
smallidx = FIRSTIDX;
while (smallidx < LASTIDX && magicints[smallidx] < mindiff) {
smallidx++;
}
xdr_int(xdrs, &smallidx);
maxidx = MYMIN(LASTIDX, smallidx + 8) ;
minidx = maxidx - 8; /* often this equal smallidx */
smaller = magicints[MYMAX(FIRSTIDX, smallidx-1)] / 2;
small = magicints[smallidx] / 2;
sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx];
larger = magicints[maxidx] / 2;
i = 0;
while (i < *size) {
is_small = 0;
thiscoord = (int *)(luip) + i * 3;
if (smallidx < maxidx && i >= 1 &&
abs(thiscoord[0] - prevcoord[0]) < larger &&
abs(thiscoord[1] - prevcoord[1]) < larger &&
abs(thiscoord[2] - prevcoord[2]) < larger) {
is_smaller = 1;
} else if (smallidx > minidx) {
is_smaller = -1;
} else {
is_smaller = 0;
}
if (i + 1 < *size) {
if (abs(thiscoord[0] - thiscoord[3]) < small &&
abs(thiscoord[1] - thiscoord[4]) < small &&
abs(thiscoord[2] - thiscoord[5]) < small) {
/* interchange first with second atom for better
* compression of water molecules
*/
tmp = thiscoord[0]; thiscoord[0] = thiscoord[3];
thiscoord[3] = tmp;
tmp = thiscoord[1]; thiscoord[1] = thiscoord[4];
thiscoord[4] = tmp;
tmp = thiscoord[2]; thiscoord[2] = thiscoord[5];
thiscoord[5] = tmp;
is_small = 1;
}
}
tmpcoord[0] = thiscoord[0] - minint[0];
tmpcoord[1] = thiscoord[1] - minint[1];
tmpcoord[2] = thiscoord[2] - minint[2];
if (bitsize == 0) {
sendbits(buf, bitsizeint[0], tmpcoord[0]);
sendbits(buf, bitsizeint[1], tmpcoord[1]);
sendbits(buf, bitsizeint[2], tmpcoord[2]);
} else {
sendints(buf, 3, bitsize, sizeint, tmpcoord);
}
prevcoord[0] = thiscoord[0];
prevcoord[1] = thiscoord[1];
prevcoord[2] = thiscoord[2];
thiscoord = thiscoord + 3;
i++;
run = 0;
if (is_small == 0 && is_smaller == -1)
is_smaller = 0;
while (is_small && run < 8*3) {
if (is_smaller == -1 && (SQR(thiscoord[0] - prevcoord[0]) +
SQR(thiscoord[1] - prevcoord[1]) +
SQR(thiscoord[2] - prevcoord[2]) >=
smaller * smaller)) {
is_smaller = 0;
}
tmpcoord[run++] = thiscoord[0] - prevcoord[0] + small;
tmpcoord[run++] = thiscoord[1] - prevcoord[1] + small;
tmpcoord[run++] = thiscoord[2] - prevcoord[2] + small;
prevcoord[0] = thiscoord[0];
prevcoord[1] = thiscoord[1];
prevcoord[2] = thiscoord[2];
i++;
thiscoord = thiscoord + 3;
is_small = 0;
if (i < *size &&
abs(thiscoord[0] - prevcoord[0]) < small &&
abs(thiscoord[1] - prevcoord[1]) < small &&
abs(thiscoord[2] - prevcoord[2]) < small) {
is_small = 1;
}
}
if (run != prevrun || is_smaller != 0) {
prevrun = run;
sendbits(buf, 1, 1); /* flag the change in run-length */
sendbits(buf, 5, run+is_smaller+1);
} else {
sendbits(buf, 1, 0); /* flag the fact that runlength did not change */
}
for (k=0; k < run; k+=3) {
sendints(buf, 3, smallidx, sizesmall, &tmpcoord[k]);
}
if (is_smaller != 0) {
smallidx += is_smaller;
if (is_smaller < 0) {
small = smaller;
smaller = magicints[smallidx-1] / 2;
} else {
smaller = small;
small = magicints[smallidx] / 2;
}
sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx];
}
}
if (buf[1] != 0) buf[0]++;;
xdr_int(xdrs, &(buf[0])); /* buf[0] holds the length in bytes */
return errval * (xdr_opaque(xdrs, (caddr_t)&(buf[3]), (u_int)buf[0]));
} else {
/* xdrs is open for reading */
if (xdr_int(xdrs, &lsize) == 0)
return 0;
if (*size != 0 && lsize != *size) {
fprintf(stderr, "wrong number of coordinates in xdr3dfcoor; "
"%d arg vs %d in file", *size, lsize);
}
*size = lsize;
size3 = *size * 3;
if (*size <= 9) {
return (xdr_vector(xdrs, (char *) fp, size3, sizeof(*fp),
(xdrproc_t)xdr_float));
}
xdr_float(xdrs, precision);
if (ip == NULL) {
ip = (int *) malloc(size3 * sizeof(*ip));
if (ip == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
bufsize = (int) (size3 * 1.2);
buf = (int *) malloc(bufsize * sizeof(*buf));
if (buf == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
oldsize = *size;
} else if (*size > oldsize) {
ip = (int *)realloc(ip, size3 * sizeof(*ip));
if (ip == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
bufsize = (int) (size3 * 1.2);
buf = (int *)realloc(buf, bufsize * sizeof(*buf));
if (buf == NULL) {
fprintf(stderr,"malloc failed\n");
exit(1);
}
oldsize = *size;
}
buf[0] = buf[1] = buf[2] = 0;
xdr_int(xdrs, &(minint[0]));
xdr_int(xdrs, &(minint[1]));
xdr_int(xdrs, &(minint[2]));
xdr_int(xdrs, &(maxint[0]));
xdr_int(xdrs, &(maxint[1]));
xdr_int(xdrs, &(maxint[2]));
sizeint[0] = maxint[0] - minint[0]+1;
sizeint[1] = maxint[1] - minint[1]+1;
sizeint[2] = maxint[2] - minint[2]+1;
/* check if one of the sizes is to big to be multiplied */
if ((sizeint[0] | sizeint[1] | sizeint[2] ) > 0xffffff) {
bitsizeint[0] = sizeofint(sizeint[0]);
bitsizeint[1] = sizeofint(sizeint[1]);
bitsizeint[2] = sizeofint(sizeint[2]);
bitsize = 0; /* flag the use of large sizes */
} else {
bitsize = sizeofints(3, sizeint);
}
xdr_int(xdrs, &smallidx);
maxidx = MYMIN(LASTIDX, smallidx + 8) ;
minidx = maxidx - 8; /* often this equal smallidx */
smaller = magicints[MYMAX(FIRSTIDX, smallidx-1)] / 2;
small = magicints[smallidx] / 2;
sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ;
larger = magicints[maxidx];
/* buf[0] holds the length in bytes */
if (xdr_int(xdrs, &(buf[0])) == 0)
return 0;
if (xdr_opaque(xdrs, (caddr_t)&(buf[3]), (u_int)buf[0]) == 0)
return 0;
buf[0] = buf[1] = buf[2] = 0;
lfp = fp;
inv_precision = 1.0 / * precision;
run = 0;
i = 0;
lip = ip;
while ( i < lsize ) {
thiscoord = (int *)(lip) + i * 3;
if (bitsize == 0) {
thiscoord[0] = receivebits(buf, bitsizeint[0]);
thiscoord[1] = receivebits(buf, bitsizeint[1]);
thiscoord[2] = receivebits(buf, bitsizeint[2]);
} else {
receiveints(buf, 3, bitsize, sizeint, thiscoord);
}
i++;
thiscoord[0] += minint[0];
thiscoord[1] += minint[1];
thiscoord[2] += minint[2];
prevcoord[0] = thiscoord[0];
prevcoord[1] = thiscoord[1];
prevcoord[2] = thiscoord[2];
flag = receivebits(buf, 1);
is_smaller = 0;
if (flag == 1) {
run = receivebits(buf, 5);
is_smaller = run % 3;
run -= is_smaller;
is_smaller--;
}
if (run > 0) {
thiscoord += 3;
for (k = 0; k < run; k+=3) {
receiveints(buf, 3, smallidx, sizesmall, thiscoord);
i++;
thiscoord[0] += prevcoord[0] - small;
thiscoord[1] += prevcoord[1] - small;
thiscoord[2] += prevcoord[2] - small;
if (k == 0) {
/* interchange first with second atom for better
* compression of water molecules
*/
tmp = thiscoord[0]; thiscoord[0] = prevcoord[0];
prevcoord[0] = tmp;
tmp = thiscoord[1]; thiscoord[1] = prevcoord[1];
prevcoord[1] = tmp;
tmp = thiscoord[2]; thiscoord[2] = prevcoord[2];
prevcoord[2] = tmp;
*lfp++ = prevcoord[0] * inv_precision;
*lfp++ = prevcoord[1] * inv_precision;
*lfp++ = prevcoord[2] * inv_precision;
} else {
prevcoord[0] = thiscoord[0];
prevcoord[1] = thiscoord[1];
prevcoord[2] = thiscoord[2];
}
*lfp++ = thiscoord[0] * inv_precision;
*lfp++ = thiscoord[1] * inv_precision;
*lfp++ = thiscoord[2] * inv_precision;
}
} else {
*lfp++ = thiscoord[0] * inv_precision;
*lfp++ = thiscoord[1] * inv_precision;
*lfp++ = thiscoord[2] * inv_precision;
}
smallidx += is_smaller;
if (is_smaller < 0) {
small = smaller;
if (smallidx > FIRSTIDX) {
smaller = magicints[smallidx - 1] /2;
} else {
smaller = 0;
}
} else if (is_smaller > 0) {
smaller = small;
small = magicints[smallidx] / 2;
}
sizesmall[0] = sizesmall[1] = sizesmall[2] = magicints[smallidx] ;
}
}
return 1;
}
diff --git a/src/XTC/dump_xtc.h b/src/XTC/dump_xtc.h
index 081891b22..f1e960af6 100644
--- a/src/XTC/dump_xtc.h
+++ b/src/XTC/dump_xtc.h
@@ -1,107 +1,107 @@
/* -*- 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 DUMP_CLASS
DumpStyle(xtc,DumpXTC)
#else
#ifndef LMP_DUMP_XTC_H
#define LMP_DUMP_XTC_H
#include "dump.h"
#ifdef LAMMPS_XDR
#include "xdr_compat.h"
#else
#include "rpc/rpc.h"
#include "rpc/xdr.h"
#endif
namespace LAMMPS_NS {
class DumpXTC : public Dump {
public:
DumpXTC(class LAMMPS *, int, char**);
virtual ~DumpXTC();
private:
int natoms,ntotal;
int nevery_save;
int unwrap_flag; // 1 if atom coords are unwrapped, 0 if no
float precision; // user-adjustable precision setting
float *coords;
double sfactor;
XDR xd;
void init_style();
int modify_param(int, char **);
void openfile();
void write_header(bigint);
- void pack(int *);
+ void pack(tagint *);
void write_data(int, double *);
bigint memory_usage();
void write_frame();
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Invalid dump xtc filename
Filenames used with the dump xtc style cannot be binary or compressed
or cause multiple files to be written.
E: Too many atoms for dump xtc
The system size must fit in a 32-bit integer to use this dump
style.
E: Dump xtc requires sorting by atom ID
Use the dump_modify sort command to enable this.
E: Cannot set dump_modify flush for dump xtc
Self-explanatory.
E: Cannot use variable every setting for dump xtc
The format of this file requires snapshots at regular intervals.
E: Cannot change dump_modify every for dump xtc
The frequency of writing dump xtc snapshots cannot be changed.
E: Cannot open dump file
The output file for the dump command cannot be opened. Check that the
path and name are correct.
E: Too big a timestep for dump xtc
The timestep must fit in a 32-bit integer to use this dump style.
*/
diff --git a/src/atom.cpp b/src/atom.cpp
index 75c2bf4a8..aba59b819 100644
--- a/src/atom.cpp
+++ b/src/atom.cpp
@@ -1,1753 +1,1874 @@
/* ----------------------------------------------------------------------
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 "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "limits.h"
#include "atom.h"
#include "style_atom.h"
#include "atom_vec.h"
#include "atom_vec_ellipsoid.h"
#include "comm.h"
#include "neighbor.h"
#include "force.h"
#include "modify.h"
#include "fix.h"
#include "output.h"
#include "thermo.h"
#include "update.h"
#include "domain.h"
#include "group.h"
#include "molecule.h"
#include "accelerator_cuda.h"
#include "atom_masks.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 1
#define DELTA_MOLECULE 1
#define DELTA_MEMSTR 1024
#define EPSILON 1.0e-6
#define CUDA_CHUNK 3000
#define MAXBODY 20 // max # of lines in one body, also in ReadData class
/* ---------------------------------------------------------------------- */
Atom::Atom(LAMMPS *lmp) : Pointers(lmp)
{
natoms = 0;
nlocal = nghost = nmax = 0;
ntypes = 0;
nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 0;
nbonds = nangles = ndihedrals = nimpropers = 0;
- bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0;
- extra_bond_per_atom = 0;
firstgroupname = NULL;
sortfreq = 1000;
nextsort = 0;
userbinsize = 0.0;
maxbin = maxnext = 0;
binhead = NULL;
next = permute = NULL;
// initialize atom arrays
// customize by adding new array
- tag = type = mask = NULL;
+ tag = NULL;
+ type = mask = NULL;
image = NULL;
x = v = f = NULL;
molecule = NULL;
q = NULL;
mu = NULL;
omega = angmom = torque = NULL;
radius = rmass = NULL;
vfrac = s0 = NULL;
x0 = NULL;
ellipsoid = line = tri = body = NULL;
spin = NULL;
eradius = ervel = erforce = NULL;
cs = csforce = vforce = ervelforce = NULL;
etag = NULL;
rho = drho = NULL;
e = de = NULL;
cv = NULL;
vest = NULL;
- maxspecial = 1;
- nspecial = NULL;
- special = NULL;
-
+ bond_per_atom = extra_bond_per_atom = 0;
num_bond = NULL;
- bond_type = bond_atom = NULL;
+ bond_type = NULL;
+ bond_atom = NULL;
+ angle_per_atom = extra_angle_per_atom = 0;
num_angle = NULL;
- angle_type = angle_atom1 = angle_atom2 = angle_atom3 = NULL;
+ angle_type = NULL;
+ angle_atom1 = angle_atom2 = angle_atom3 = NULL;
+ dihedral_per_atom = extra_dihedral_per_atom = 0;
num_dihedral = NULL;
- dihedral_type = dihedral_atom1 = dihedral_atom2 = NULL;
- dihedral_atom3 = dihedral_atom4 = NULL;
+ dihedral_type = NULL;
+ dihedral_atom1 = dihedral_atom2 = dihedral_atom3 = dihedral_atom4 = NULL;
+ improper_per_atom = extra_improper_per_atom = 0;
num_improper = NULL;
- improper_type = improper_atom1 = improper_atom2 = NULL;
- improper_atom3 = improper_atom4 = NULL;
+ improper_type = NULL;
+ improper_atom1 = improper_atom2 = improper_atom3 = improper_atom4 = NULL;
+
+ maxspecial = 1;
+ nspecial = NULL;
+ special = NULL;
// user-defined molecules
nmolecule = maxmol = 0;
molecules = NULL;
// custom atom arrays
nivector = ndvector = 0;
ivector = NULL;
dvector = NULL;
iname = dname = NULL;
// initialize atom style and array existence flags
// customize by adding new flag
sphere_flag = ellipsoid_flag = line_flag = tri_flag = body_flag = 0;
peri_flag = electron_flag = 0;
wavepacket_flag = sph_flag = 0;
molecule_flag = q_flag = mu_flag = 0;
rmass_flag = radius_flag = omega_flag = torque_flag = angmom_flag = 0;
vfrac_flag = spin_flag = eradius_flag = ervel_flag = erforce_flag = 0;
cs_flag = csforce_flag = vforce_flag = ervelforce_flag= etag_flag = 0;
rho_flag = e_flag = cv_flag = vest_flag = 0;
// ntype-length arrays
mass = NULL;
mass_setflag = NULL;
// callback lists & extra restart info
nextra_grow = nextra_restart = nextra_border = 0;
extra_grow = extra_restart = extra_border = NULL;
nextra_grow_max = nextra_restart_max = nextra_border_max = 0;
nextra_store = 0;
extra = NULL;
- // default mapping values
+ // default atom ID and mapping values
tag_enable = 1;
- map_style = 0;
+ map_style = map_user = 0;
map_tag_max = 0;
map_nhash = 0;
- smax = 0;
+ max_same = 0;
sametag = NULL;
map_array = NULL;
map_bucket = NULL;
map_hash = NULL;
atom_style = NULL;
avec = NULL;
datamask = ALL_MASK;
datamask_ext = ALL_MASK;
}
/* ---------------------------------------------------------------------- */
Atom::~Atom()
{
delete [] atom_style;
delete avec;
delete [] firstgroupname;
memory->destroy(binhead);
memory->destroy(next);
memory->destroy(permute);
// delete atom arrays
// customize by adding new array
memory->destroy(tag);
memory->destroy(type);
memory->destroy(mask);
memory->destroy(image);
memory->destroy(x);
memory->destroy(v);
memory->destroy(f);
memory->destroy(q);
memory->destroy(mu);
memory->destroy(omega);
memory->destroy(angmom);
memory->destroy(torque);
memory->destroy(radius);
memory->destroy(rmass);
memory->destroy(vfrac);
memory->destroy(s0);
memory->destroy(x0);
memory->destroy(ellipsoid);
memory->destroy(line);
memory->destroy(tri);
memory->destroy(body);
memory->destroy(spin);
memory->destroy(eradius);
memory->destroy(ervel);
memory->destroy(erforce);
memory->destroy(molecule);
memory->destroy(nspecial);
memory->destroy(special);
memory->destroy(num_bond);
memory->destroy(bond_type);
memory->destroy(bond_atom);
memory->destroy(num_angle);
memory->destroy(angle_type);
memory->destroy(angle_atom1);
memory->destroy(angle_atom2);
memory->destroy(angle_atom3);
memory->destroy(num_dihedral);
memory->destroy(dihedral_type);
memory->destroy(dihedral_atom1);
memory->destroy(dihedral_atom2);
memory->destroy(dihedral_atom3);
memory->destroy(dihedral_atom4);
memory->destroy(num_improper);
memory->destroy(improper_type);
memory->destroy(improper_atom1);
memory->destroy(improper_atom2);
memory->destroy(improper_atom3);
memory->destroy(improper_atom4);
// delete user-defined molecules
for (int i = 0; i < nmolecule; i++) delete molecules[i];
memory->sfree(molecules);
// delete custom atom arrays
for (int i = 0; i < nivector; i++) {
delete [] iname[i];
memory->destroy(ivector[i]);
}
for (int i = 0; i < ndvector; i++) {
delete [] dname[i];
memory->destroy(dvector[i]);
}
memory->sfree(iname);
memory->sfree(dname);
memory->sfree(ivector);
memory->sfree(dvector);
// delete per-type arrays
delete [] mass;
delete [] mass_setflag;
// delete extra arrays
memory->destroy(extra_grow);
memory->destroy(extra_restart);
memory->destroy(extra_border);
memory->destroy(extra);
// delete mapping data structures
map_delete();
}
/* ----------------------------------------------------------------------
copy modify settings from old Atom class to current Atom class
------------------------------------------------------------------------- */
void Atom::settings(Atom *old)
{
- map_style = old->map_style;
+ tag_enable = old->tag_enable;
+ map_user = old->map_user;
}
/* ----------------------------------------------------------------------
create an AtomVec style
called from lammps.cpp, input script, restart file, replicate
------------------------------------------------------------------------- */
void Atom::create_avec(const char *style, int narg, char **arg, char *suffix)
{
delete [] atom_style;
if (avec) delete avec;
// unset atom style and array existence flags
// may have been set by old avec
// customize by adding new flag
sphere_flag = ellipsoid_flag = line_flag = tri_flag = 0;
peri_flag = electron_flag = 0;
molecule_flag = q_flag = mu_flag = 0;
rmass_flag = radius_flag = omega_flag = torque_flag = angmom_flag = 0;
vfrac_flag = spin_flag = eradius_flag = ervel_flag = erforce_flag = 0;
// create instance of AtomVec
// use grow() to initialize atom-based arrays to length 1
// so that x[0][0] can always be referenced even if proc has no atoms
// but reset nmax = 0
// so 2d arrays like bond_type will later be allocated correctly
// since currently, 2nd dimension bond_per_atom = 0
int sflag;
avec = new_avec(style,suffix,sflag);
avec->settings(narg,arg);
avec->grow(1);
nmax = 0;
avec->reset();
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
atom_style = new char[n];
strcpy(atom_style,estyle);
} else {
int n = strlen(style) + 1;
atom_style = new char[n];
strcpy(atom_style,style);
}
- // if molecular system, default is to have array map
+ // if molecular system, atom IDs must be defined
molecular = avec->molecular;
- if (map_style == 0 && molecular) map_style = 1;
+ if (molecular && tag_enable == 0)
+ error->all(FLERR,"Atom IDs must be used for molecular systems");
}
/* ----------------------------------------------------------------------
generate an AtomVec class, first with suffix appended
------------------------------------------------------------------------- */
AtomVec *Atom::new_avec(const char *style, char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (0) return NULL;
#define ATOM_CLASS
#define AtomStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp);
#include "style_atom.h"
#undef AtomStyle
#undef ATOM_CLASS
}
sflag = 0;
if (0) return NULL;
#define ATOM_CLASS
#define AtomStyle(key,Class) \
else if (strcmp(style,#key) == 0) return new Class(lmp);
#include "style_atom.h"
#undef ATOM_CLASS
else error->all(FLERR,"Invalid atom style");
return NULL;
}
/* ---------------------------------------------------------------------- */
void Atom::init()
{
// delete extra array since it doesn't persist past first run
if (nextra_store) {
memory->destroy(extra);
extra = NULL;
nextra_store = 0;
}
// check arrays that are atom type in length
check_mass();
// setup of firstgroup
if (firstgroupname) {
firstgroup = group->find(firstgroupname);
if (firstgroup < 0)
error->all(FLERR,"Could not find atom_modify first group ID");
} else firstgroup = -1;
// init AtomVec
avec->init();
}
/* ---------------------------------------------------------------------- */
void Atom::setup()
{
// setup bins for sorting
// cannot do this in init() because uses neighbor cutoff
if (sortfreq > 0) setup_sort_bins();
}
/* ----------------------------------------------------------------------
return ptr to AtomVec class if matches style or to matching hybrid sub-class
return NULL if no match
------------------------------------------------------------------------- */
AtomVec *Atom::style_match(const char *style)
{
if (strcmp(atom_style,style) == 0) return avec;
else if (strcmp(atom_style,"hybrid") == 0) {
AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) avec;
for (int i = 0; i < avec_hybrid->nstyles; i++)
if (strcmp(avec_hybrid->keywords[i],style) == 0)
return avec_hybrid->styles[i];
}
return NULL;
}
/* ----------------------------------------------------------------------
modify parameters of the atom style
some options can only be invoked before simulation box is defined
first and sort options cannot be used together
------------------------------------------------------------------------- */
void Atom::modify_params(int narg, char **arg)
{
if (narg == 0) error->all(FLERR,"Illegal atom_modify command");
int iarg = 0;
while (iarg < narg) {
- if (strcmp(arg[iarg],"map") == 0) {
+ if (strcmp(arg[iarg],"id") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command");
- if (strcmp(arg[iarg+1],"array") == 0) map_style = 1;
- else if (strcmp(arg[iarg+1],"hash") == 0) map_style = 2;
+ if (domain->box_exist)
+ error->all(FLERR,
+ "Atom_modify id command after simulation box is defined");
+ if (strcmp(arg[iarg+1],"yes") == 0) tag_enable = 1;
+ else if (strcmp(arg[iarg+1],"no") == 0) tag_enable = 2;
else error->all(FLERR,"Illegal atom_modify command");
+ iarg += 2;
+ } if (strcmp(arg[iarg],"map") == 0) {
+ if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command");
if (domain->box_exist)
error->all(FLERR,
"Atom_modify map command after simulation box is defined");
+ if (strcmp(arg[iarg+1],"array") == 0) map_user = 1;
+ else if (strcmp(arg[iarg+1],"hash") == 0) map_user = 2;
+ else error->all(FLERR,"Illegal atom_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"first") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command");
if (strcmp(arg[iarg+1],"all") == 0) {
delete [] firstgroupname;
firstgroupname = NULL;
} else {
int n = strlen(arg[iarg+1]) + 1;
firstgroupname = new char[n];
strcpy(firstgroupname,arg[iarg+1]);
sortfreq = 0;
}
iarg += 2;
} else if (strcmp(arg[iarg],"sort") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal atom_modify command");
sortfreq = force->inumeric(FLERR,arg[iarg+1]);
userbinsize = force->numeric(FLERR,arg[iarg+2]);
if (sortfreq < 0 || userbinsize < 0.0)
error->all(FLERR,"Illegal atom_modify command");
if (sortfreq >= 0 && firstgroupname)
error->all(FLERR,"Atom_modify sort and first options "
"cannot be used together");
iarg += 3;
} else error->all(FLERR,"Illegal atom_modify command");
}
}
+/* ----------------------------------------------------------------------
+ check that atom IDs are valid
+ error if any atom ID < 0 or atom ID = MAXTAGINT
+ if any atom ID > 0, error if any atom ID == 0
+ if all atom IDs = 0, tag_enable must be 0
+ OK if atom IDs > natoms
+ NOTE: not checking that atom IDs are unique
+------------------------------------------------------------------------- */
+
+void Atom::tag_check()
+{
+ int nlocal = atom->nlocal;
+ tagint *tag = atom->tag;
+
+ tagint min = MAXTAGINT;
+ tagint max = 0;
+
+ for (int i = 0; i < nlocal; i++) {
+ min = MIN(min,tag[i]);
+ max = MAX(max,tag[i]);
+ }
+
+ tagint minall,maxall;
+ MPI_Allreduce(&min,&minall,1,MPI_LMP_TAGINT,MPI_MIN,world);
+ MPI_Allreduce(&max,&maxall,1,MPI_LMP_TAGINT,MPI_MAX,world);
+
+ if (minall < 0) error->all(FLERR,"Atom ID is negative");
+ if (maxall >= MAXTAGINT) error->all(FLERR,"Atom ID is too big");
+ if (maxall > 0 && minall == 0) error->all(FLERR,"Atom ID is zero");
+ if (maxall == 0 && tag_enable && natoms)
+ error->all(FLERR,"Not all atom IDs are 0");
+}
+
/* ----------------------------------------------------------------------
add unique tags to any atoms with tag = 0
new tags are grouped by proc and start after max current tag
called after creating new atoms
+ error if new tags will exceed MAXTAGINT
------------------------------------------------------------------------- */
void Atom::tag_extend()
{
// maxtag_all = max tag for all atoms
- int maxtag = 0;
+ tagint maxtag = 0;
for (int i = 0; i < nlocal; i++) maxtag = MAX(maxtag,tag[i]);
- int maxtag_all;
- MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_INT,MPI_MAX,world);
+ tagint maxtag_all;
+ MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world);
+
+ // DEBUG: useful for generating 64-bit IDs even for small systems
+ // use only when LAMMPS is compiled with BIGBIG
+
+ //maxtag_all += 1000000000000;
// notag = # of atoms I own with no tag (tag = 0)
// notag_sum = # of total atoms on procs <= me with no tag
- int notag = 0;
+ bigint notag = 0;
for (int i = 0; i < nlocal; i++) if (tag[i] == 0) notag++;
- int notag_sum;
- MPI_Scan(&notag,&notag_sum,1,MPI_INT,MPI_SUM,world);
+
+ bigint notag_total;
+ MPI_Allreduce(&notag,&notag_total,1,MPI_LMP_BIGINT,MPI_SUM,world);
+ if (notag_total >= MAXTAGINT)
+ error->all(FLERR,"New atom IDs exceed maximum allowed ID");
+
+ bigint notag_sum;
+ MPI_Scan(&notag,&notag_sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
// itag = 1st new tag that my untagged atoms should use
- int itag = maxtag_all + notag_sum - notag + 1;
+ tagint itag = maxtag_all + notag_sum - notag + 1;
for (int i = 0; i < nlocal; i++) if (tag[i] == 0) tag[i] = itag++;
}
/* ----------------------------------------------------------------------
- check that atom IDs span range from 1 to Natoms
+ check that atom IDs span range from 1 to Natoms inclusive
return 0 if mintag != 1 or maxtag != Natoms
return 1 if OK
doesn't actually check if all tag values are used
------------------------------------------------------------------------- */
int Atom::tag_consecutive()
{
- // change this when allow tagint = bigint
- //int idmin = MAXTAGINT;
- int idmin = MAXSMALLINT;
- int idmax = 0;
+ tagint idmin = MAXTAGINT;
+ tagint idmax = 0;
for (int i = 0; i < nlocal; i++) {
idmin = MIN(idmin,tag[i]);
idmax = MAX(idmax,tag[i]);
}
- int idminall,idmaxall;
- MPI_Allreduce(&idmin,&idminall,1,MPI_INT,MPI_MIN,world);
- MPI_Allreduce(&idmax,&idmaxall,1,MPI_INT,MPI_MAX,world);
+ tagint idminall,idmaxall;
+ MPI_Allreduce(&idmin,&idminall,1,MPI_LMP_TAGINT,MPI_MIN,world);
+ MPI_Allreduce(&idmax,&idmaxall,1,MPI_LMP_TAGINT,MPI_MAX,world);
- if (idminall != 1 || idmaxall != static_cast<int> (natoms)) return 0;
+ if (idminall != 1 || idmaxall != natoms) return 0;
return 1;
}
/* ----------------------------------------------------------------------
count and return words in a single line
make copy of line before using strtok so as not to change line
trim anything from '#' onward
------------------------------------------------------------------------- */
int Atom::count_words(const char *line)
{
int n = strlen(line) + 1;
char *copy;
memory->create(copy,n,"atom:copy");
strcpy(copy,line);
char *ptr;
if (ptr = strchr(copy,'#')) *ptr = '\0';
if (strtok(copy," \t\n\r\f") == NULL) {
memory->destroy(copy);
return 0;
}
n = 1;
while (strtok(NULL," \t\n\r\f")) n++;
memory->destroy(copy);
return n;
}
/* ----------------------------------------------------------------------
unpack n lines from Atom section of data file
call style-specific routine to parse line
------------------------------------------------------------------------- */
void Atom::data_atoms(int n, char *buf)
{
int m,xptr,iptr;
imageint imagedata;
double xdata[3],lamda[3];
double *coord;
char *next;
next = strchr(buf,'\n');
*next = '\0';
int nwords = count_words(buf);
*next = '\n';
if (nwords != avec->size_data_atom && nwords != avec->size_data_atom + 3)
error->all(FLERR,"Incorrect atom format in data file");
char **values = new char*[nwords];
// set bounds for my proc
// if periodic and I am lo/hi proc, adjust bounds by EPSILON
// insures all data atoms will be owned even with round-off
int triclinic = domain->triclinic;
double epsilon[3];
if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON;
else {
epsilon[0] = domain->prd[0] * EPSILON;
epsilon[1] = domain->prd[1] * EPSILON;
epsilon[2] = domain->prd[2] * EPSILON;
}
double sublo[3],subhi[3];
if (triclinic == 0) {
sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0];
sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1];
sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2];
} else {
sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0];
sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1];
sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2];
}
if (domain->xperiodic) {
if (comm->myloc[0] == 0) sublo[0] -= epsilon[0];
if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] += epsilon[0];
}
if (domain->yperiodic) {
if (comm->myloc[1] == 0) sublo[1] -= epsilon[1];
if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] += epsilon[1];
}
if (domain->zperiodic) {
if (comm->myloc[2] == 0) sublo[2] -= epsilon[2];
if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] += epsilon[2];
}
// xptr = which word in line starts xyz coords
// iptr = which word in line starts ix,iy,iz image flags
xptr = avec->xcol_data - 1;
int imageflag = 0;
if (nwords > avec->size_data_atom) imageflag = 1;
if (imageflag) iptr = nwords - 3;
// loop over lines of atom data
// tokenize the line into values
// extract xyz coords and image flags
// remap atom into simulation box
// if atom is in my sub-domain, unpack its values
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
values[0] = strtok(buf," \t\n\r\f");
if (values[0] == NULL)
error->all(FLERR,"Incorrect atom format in data file");
for (m = 1; m < nwords; m++) {
values[m] = strtok(NULL," \t\n\r\f");
if (values[m] == NULL)
error->all(FLERR,"Incorrect atom format in data file");
}
if (imageflag)
imagedata = ((imageint) (atoi(values[iptr]) + IMGMAX) & IMGMASK) |
(((imageint) (atoi(values[iptr+1]) + IMGMAX) & IMGMASK) << IMGBITS) |
(((imageint) (atoi(values[iptr+2]) + IMGMAX) & IMGMASK) << IMG2BITS);
else imagedata = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
xdata[0] = atof(values[xptr]);
xdata[1] = atof(values[xptr+1]);
xdata[2] = atof(values[xptr+2]);
domain->remap(xdata,imagedata);
if (triclinic) {
domain->x2lamda(xdata,lamda);
coord = lamda;
} else coord = xdata;
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2])
avec->data_atom(xdata,imagedata,values);
buf = next + 1;
}
delete [] values;
}
/* ----------------------------------------------------------------------
unpack n lines from Velocity section of data file
check that atom IDs are > 0 and <= map_tag_max
call style-specific routine to parse line
------------------------------------------------------------------------- */
void Atom::data_vels(int n, char *buf)
{
- int j,m,tagdata;
+ int j,m;
+ tagint tagdata;
char *next;
next = strchr(buf,'\n');
*next = '\0';
int nwords = count_words(buf);
*next = '\n';
if (nwords != avec->size_data_vel)
error->all(FLERR,"Incorrect velocity format in data file");
char **values = new char*[nwords];
// loop over lines of atom velocities
// tokenize the line into values
// if I own atom tag, unpack its values
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
values[0] = strtok(buf," \t\n\r\f");
for (j = 1; j < nwords; j++)
values[j] = strtok(NULL," \t\n\r\f");
- tagdata = atoi(values[0]);
+ tagdata = ATOTAGINT(values[0]);
if (tagdata <= 0 || tagdata > map_tag_max)
error->one(FLERR,"Invalid atom ID in Velocities section of data file");
if ((m = map(tagdata)) >= 0) avec->data_vel(m,&values[1]);
buf = next + 1;
}
delete [] values;
}
/* ----------------------------------------------------------------------
- unpack n lines from atom-style specific section of data file
- check that atom IDs are > 0 and <= map_tag_max
- call style-specific routine to parse line
-------------------------------------------------------------------------- */
-
-void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus)
-{
- int j,m,tagdata;
- char *next;
-
- next = strchr(buf,'\n');
- *next = '\0';
- int nwords = count_words(buf);
- *next = '\n';
-
- if (nwords != avec_bonus->size_data_bonus)
- error->all(FLERR,"Incorrect bonus data format in data file");
-
- char **values = new char*[nwords];
-
- // loop over lines of bonus atom data
- // tokenize the line into values
- // if I own atom tag, unpack its values
-
- for (int i = 0; i < n; i++) {
- next = strchr(buf,'\n');
-
- values[0] = strtok(buf," \t\n\r\f");
- for (j = 1; j < nwords; j++)
- values[j] = strtok(NULL," \t\n\r\f");
-
- tagdata = atoi(values[0]);
- if (tagdata <= 0 || tagdata > map_tag_max)
- error->one(FLERR,"Invalid atom ID in Bonus section of data file");
-
- // ok to call child's data_atom_bonus() method thru parent avec_bonus,
- // since data_bonus() was called with child ptr, and method is virtual
-
- if ((m = map(tagdata)) >= 0) avec_bonus->data_atom_bonus(m,&values[1]);
-
- buf = next + 1;
- }
-
- delete [] values;
-}
-
-/* ----------------------------------------------------------------------
- unpack n lines from atom-style specific section of data file
+ process N bonds read into buf from data files
+ if count is non-NULL, just count bonds per atom
+ else store them with atoms
check that atom IDs are > 0 and <= map_tag_max
- call style-specific routine to parse line
------------------------------------------------------------------------- */
-void Atom::data_bodies(int n, char *buf, AtomVecBody *avec_body)
+void Atom::data_bonds(int n, char *buf, int *count)
{
- int j,m,tagdata,ninteger,ndouble;
-
- char **ivalues = new char*[10*MAXBODY];
- char **dvalues = new char*[10*MAXBODY];
-
- // loop over lines of body data
- // tokenize the lines into ivalues and dvalues
- // if I own atom tag, unpack its values
-
- for (int i = 0; i < n; i++) {
- if (i == 0) tagdata = atoi(strtok(buf," \t\n\r\f"));
- else tagdata = atoi(strtok(NULL," \t\n\r\f"));
- ninteger = atoi(strtok(NULL," \t\n\r\f"));
- ndouble = atoi(strtok(NULL," \t\n\r\f"));
-
- for (j = 0; j < ninteger; j++)
- ivalues[j] = strtok(NULL," \t\n\r\f");
- for (j = 0; j < ndouble; j++)
- dvalues[j] = strtok(NULL," \t\n\r\f");
-
- if (tagdata <= 0 || tagdata > map_tag_max)
- error->one(FLERR,"Invalid atom ID in Bodies section of data file");
-
- if ((m = map(tagdata)) >= 0)
- avec_body->data_body(m,ninteger,ndouble,ivalues,dvalues);
- }
-
- delete [] ivalues;
- delete [] dvalues;
-}
-
-/* ----------------------------------------------------------------------
- check that atom IDs are > 0 and <= map_tag_max
-------------------------------------------------------------------------- */
-
-void Atom::data_bonds(int n, char *buf)
-{
- int m,tmp,itype,atom1,atom2;
+ int m,tmp,itype;
+ tagint atom1,atom2;
char *next;
int newton_bond = force->newton_bond;
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
- sscanf(buf,"%d %d %d %d",&tmp,&itype,&atom1,&atom2);
+ sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT,
+ &tmp,&itype,&atom1,&atom2);
if (atom1 <= 0 || atom1 > map_tag_max ||
atom2 <= 0 || atom2 > map_tag_max)
error->one(FLERR,"Invalid atom ID in Bonds section of data file");
if (itype <= 0 || itype > nbondtypes)
error->one(FLERR,"Invalid bond type in Bonds section of data file");
if ((m = map(atom1)) >= 0) {
- bond_type[m][num_bond[m]] = itype;
- bond_atom[m][num_bond[m]] = atom2;
- num_bond[m]++;
+ if (count) count[m]++;
+ else {
+ bond_type[m][num_bond[m]] = itype;
+ bond_atom[m][num_bond[m]] = atom2;
+ num_bond[m]++;
+ }
}
if (newton_bond == 0) {
if ((m = map(atom2)) >= 0) {
- bond_type[m][num_bond[m]] = itype;
- bond_atom[m][num_bond[m]] = atom1;
- num_bond[m]++;
+ if (count) count[m]++;
+ else {
+ bond_type[m][num_bond[m]] = itype;
+ bond_atom[m][num_bond[m]] = atom1;
+ num_bond[m]++;
+ }
}
}
buf = next + 1;
}
}
/* ----------------------------------------------------------------------
+ process N angles read into buf from data files
+ if count is non-NULL, just count angles per atom
+ else store them with atoms
check that atom IDs are > 0 and <= map_tag_max
------------------------------------------------------------------------- */
-void Atom::data_angles(int n, char *buf)
+void Atom::data_angles(int n, char *buf, int *count)
{
- int m,tmp,itype,atom1,atom2,atom3;
+ int m,tmp,itype;
+ tagint atom1,atom2,atom3;
char *next;
int newton_bond = force->newton_bond;
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
- sscanf(buf,"%d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3);
+ sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT,
+ &tmp,&itype,&atom1,&atom2,&atom3);
if (atom1 <= 0 || atom1 > map_tag_max ||
atom2 <= 0 || atom2 > map_tag_max ||
atom3 <= 0 || atom3 > map_tag_max)
error->one(FLERR,"Invalid atom ID in Angles section of data file");
if (itype <= 0 || itype > nangletypes)
error->one(FLERR,"Invalid angle type in Angles section of data file");
if ((m = map(atom2)) >= 0) {
- angle_type[m][num_angle[m]] = itype;
- angle_atom1[m][num_angle[m]] = atom1;
- angle_atom2[m][num_angle[m]] = atom2;
- angle_atom3[m][num_angle[m]] = atom3;
- num_angle[m]++;
- }
- if (newton_bond == 0) {
- if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
angle_type[m][num_angle[m]] = itype;
angle_atom1[m][num_angle[m]] = atom1;
angle_atom2[m][num_angle[m]] = atom2;
angle_atom3[m][num_angle[m]] = atom3;
num_angle[m]++;
}
+ }
+ if (newton_bond == 0) {
+ if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
+ angle_type[m][num_angle[m]] = itype;
+ angle_atom1[m][num_angle[m]] = atom1;
+ angle_atom2[m][num_angle[m]] = atom2;
+ angle_atom3[m][num_angle[m]] = atom3;
+ num_angle[m]++;
+ }
+ }
if ((m = map(atom3)) >= 0) {
- angle_type[m][num_angle[m]] = itype;
- angle_atom1[m][num_angle[m]] = atom1;
- angle_atom2[m][num_angle[m]] = atom2;
- angle_atom3[m][num_angle[m]] = atom3;
- num_angle[m]++;
+ if (count) count[m]++;
+ else {
+ angle_type[m][num_angle[m]] = itype;
+ angle_atom1[m][num_angle[m]] = atom1;
+ angle_atom2[m][num_angle[m]] = atom2;
+ angle_atom3[m][num_angle[m]] = atom3;
+ num_angle[m]++;
+ }
}
}
buf = next + 1;
}
}
/* ----------------------------------------------------------------------
+ process N dihedrals read into buf from data files
+ if count is non-NULL, just count diihedrals per atom
+ else store them with atoms
check that atom IDs are > 0 and <= map_tag_max
------------------------------------------------------------------------- */
-void Atom::data_dihedrals(int n, char *buf)
+void Atom::data_dihedrals(int n, char *buf, int *count)
{
- int m,tmp,itype,atom1,atom2,atom3,atom4;
+ int m,tmp,itype;
+ tagint atom1,atom2,atom3,atom4;
char *next;
int newton_bond = force->newton_bond;
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
- sscanf(buf,"%d %d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3,&atom4);
+ sscanf(buf,"%d %d "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT,
+ &tmp,&itype,&atom1,&atom2,&atom3,&atom4);
if (atom1 <= 0 || atom1 > map_tag_max ||
atom2 <= 0 || atom2 > map_tag_max ||
atom3 <= 0 || atom3 > map_tag_max ||
atom4 <= 0 || atom4 > map_tag_max)
error->one(FLERR,"Invalid atom ID in Dihedrals section of data file");
if (itype <= 0 || itype > ndihedraltypes)
error->one(FLERR,
"Invalid dihedral type in Dihedrals section of data file");
if ((m = map(atom2)) >= 0) {
- dihedral_type[m][num_dihedral[m]] = itype;
- dihedral_atom1[m][num_dihedral[m]] = atom1;
- dihedral_atom2[m][num_dihedral[m]] = atom2;
- dihedral_atom3[m][num_dihedral[m]] = atom3;
- dihedral_atom4[m][num_dihedral[m]] = atom4;
- num_dihedral[m]++;
- }
- if (newton_bond == 0) {
- if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
dihedral_type[m][num_dihedral[m]] = itype;
dihedral_atom1[m][num_dihedral[m]] = atom1;
dihedral_atom2[m][num_dihedral[m]] = atom2;
dihedral_atom3[m][num_dihedral[m]] = atom3;
dihedral_atom4[m][num_dihedral[m]] = atom4;
num_dihedral[m]++;
}
+ }
+ if (newton_bond == 0) {
+ if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
+ dihedral_type[m][num_dihedral[m]] = itype;
+ dihedral_atom1[m][num_dihedral[m]] = atom1;
+ dihedral_atom2[m][num_dihedral[m]] = atom2;
+ dihedral_atom3[m][num_dihedral[m]] = atom3;
+ dihedral_atom4[m][num_dihedral[m]] = atom4;
+ num_dihedral[m]++;
+ }
+ }
if ((m = map(atom3)) >= 0) {
- dihedral_type[m][num_dihedral[m]] = itype;
- dihedral_atom1[m][num_dihedral[m]] = atom1;
- dihedral_atom2[m][num_dihedral[m]] = atom2;
- dihedral_atom3[m][num_dihedral[m]] = atom3;
- dihedral_atom4[m][num_dihedral[m]] = atom4;
- num_dihedral[m]++;
+ if (count) count[m]++;
+ else {
+ dihedral_type[m][num_dihedral[m]] = itype;
+ dihedral_atom1[m][num_dihedral[m]] = atom1;
+ dihedral_atom2[m][num_dihedral[m]] = atom2;
+ dihedral_atom3[m][num_dihedral[m]] = atom3;
+ dihedral_atom4[m][num_dihedral[m]] = atom4;
+ num_dihedral[m]++;
+ }
}
if ((m = map(atom4)) >= 0) {
- dihedral_type[m][num_dihedral[m]] = itype;
- dihedral_atom1[m][num_dihedral[m]] = atom1;
- dihedral_atom2[m][num_dihedral[m]] = atom2;
- dihedral_atom3[m][num_dihedral[m]] = atom3;
- dihedral_atom4[m][num_dihedral[m]] = atom4;
- num_dihedral[m]++;
+ if (count) count[m]++;
+ else {
+ dihedral_type[m][num_dihedral[m]] = itype;
+ dihedral_atom1[m][num_dihedral[m]] = atom1;
+ dihedral_atom2[m][num_dihedral[m]] = atom2;
+ dihedral_atom3[m][num_dihedral[m]] = atom3;
+ dihedral_atom4[m][num_dihedral[m]] = atom4;
+ num_dihedral[m]++;
+ }
}
}
buf = next + 1;
}
}
/* ----------------------------------------------------------------------
+ process N impropers read into buf from data files
+ if count is non-NULL, just count impropers per atom
+ else store them with atoms
check that atom IDs are > 0 and <= map_tag_max
------------------------------------------------------------------------- */
-void Atom::data_impropers(int n, char *buf)
+void Atom::data_impropers(int n, char *buf, int *count)
{
- int m,tmp,itype,atom1,atom2,atom3,atom4;
+ int m,tmp,itype;
+ tagint atom1,atom2,atom3,atom4;
char *next;
int newton_bond = force->newton_bond;
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
- sscanf(buf,"%d %d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3,&atom4);
+ sscanf(buf,"%d %d "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT,
+ &tmp,&itype,&atom1,&atom2,&atom3,&atom4);
if (atom1 <= 0 || atom1 > map_tag_max ||
atom2 <= 0 || atom2 > map_tag_max ||
atom3 <= 0 || atom3 > map_tag_max ||
atom4 <= 0 || atom4 > map_tag_max)
error->one(FLERR,"Invalid atom ID in Impropers section of data file");
if (itype <= 0 || itype > nimpropertypes)
error->one(FLERR,
"Invalid improper type in Impropers section of data file");
if ((m = map(atom2)) >= 0) {
- improper_type[m][num_improper[m]] = itype;
- improper_atom1[m][num_improper[m]] = atom1;
- improper_atom2[m][num_improper[m]] = atom2;
- improper_atom3[m][num_improper[m]] = atom3;
- improper_atom4[m][num_improper[m]] = atom4;
- num_improper[m]++;
- }
- if (newton_bond == 0) {
- if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
improper_type[m][num_improper[m]] = itype;
improper_atom1[m][num_improper[m]] = atom1;
improper_atom2[m][num_improper[m]] = atom2;
improper_atom3[m][num_improper[m]] = atom3;
improper_atom4[m][num_improper[m]] = atom4;
num_improper[m]++;
}
+ }
+ if (newton_bond == 0) {
+ if ((m = map(atom1)) >= 0) {
+ if (count) count[m]++;
+ else {
+ improper_type[m][num_improper[m]] = itype;
+ improper_atom1[m][num_improper[m]] = atom1;
+ improper_atom2[m][num_improper[m]] = atom2;
+ improper_atom3[m][num_improper[m]] = atom3;
+ improper_atom4[m][num_improper[m]] = atom4;
+ num_improper[m]++;
+ }
+ }
if ((m = map(atom3)) >= 0) {
- improper_type[m][num_improper[m]] = itype;
- improper_atom1[m][num_improper[m]] = atom1;
- improper_atom2[m][num_improper[m]] = atom2;
- improper_atom3[m][num_improper[m]] = atom3;
- improper_atom4[m][num_improper[m]] = atom4;
- num_improper[m]++;
+ if (count) count[m]++;
+ else {
+ improper_type[m][num_improper[m]] = itype;
+ improper_atom1[m][num_improper[m]] = atom1;
+ improper_atom2[m][num_improper[m]] = atom2;
+ improper_atom3[m][num_improper[m]] = atom3;
+ improper_atom4[m][num_improper[m]] = atom4;
+ num_improper[m]++;
+ }
}
if ((m = map(atom4)) >= 0) {
- improper_type[m][num_improper[m]] = itype;
- improper_atom1[m][num_improper[m]] = atom1;
- improper_atom2[m][num_improper[m]] = atom2;
- improper_atom3[m][num_improper[m]] = atom3;
- improper_atom4[m][num_improper[m]] = atom4;
- num_improper[m]++;
+ if (count) count[m]++;
+ else {
+ improper_type[m][num_improper[m]] = itype;
+ improper_atom1[m][num_improper[m]] = atom1;
+ improper_atom2[m][num_improper[m]] = atom2;
+ improper_atom3[m][num_improper[m]] = atom3;
+ improper_atom4[m][num_improper[m]] = atom4;
+ num_improper[m]++;
+ }
}
}
buf = next + 1;
}
}
+/* ----------------------------------------------------------------------
+ unpack n lines from atom-style specific section of data file
+ check that atom IDs are > 0 and <= map_tag_max
+ call style-specific routine to parse line
+------------------------------------------------------------------------- */
+
+void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus)
+{
+ int j,m,tagdata;
+ char *next;
+
+ next = strchr(buf,'\n');
+ *next = '\0';
+ int nwords = count_words(buf);
+ *next = '\n';
+
+ if (nwords != avec_bonus->size_data_bonus)
+ error->all(FLERR,"Incorrect bonus data format in data file");
+
+ char **values = new char*[nwords];
+
+ // loop over lines of bonus atom data
+ // tokenize the line into values
+ // if I own atom tag, unpack its values
+
+ for (int i = 0; i < n; i++) {
+ next = strchr(buf,'\n');
+
+ values[0] = strtok(buf," \t\n\r\f");
+ for (j = 1; j < nwords; j++)
+ values[j] = strtok(NULL," \t\n\r\f");
+
+ tagdata = ATOTAGINT(values[0]);
+ if (tagdata <= 0 || tagdata > map_tag_max)
+ error->one(FLERR,"Invalid atom ID in Bonus section of data file");
+
+ // ok to call child's data_atom_bonus() method thru parent avec_bonus,
+ // since data_bonus() was called with child ptr, and method is virtual
+
+ if ((m = map(tagdata)) >= 0) avec_bonus->data_atom_bonus(m,&values[1]);
+
+ buf = next + 1;
+ }
+
+ delete [] values;
+}
+
+/* ----------------------------------------------------------------------
+ unpack n lines from atom-style specific section of data file
+ check that atom IDs are > 0 and <= map_tag_max
+ call style-specific routine to parse line
+------------------------------------------------------------------------- */
+
+void Atom::data_bodies(int n, char *buf, AtomVecBody *avec_body)
+{
+ int j,m,tagdata,ninteger,ndouble;
+
+ char **ivalues = new char*[10*MAXBODY];
+ char **dvalues = new char*[10*MAXBODY];
+
+ // loop over lines of body data
+ // tokenize the lines into ivalues and dvalues
+ // if I own atom tag, unpack its values
+
+ for (int i = 0; i < n; i++) {
+ if (i == 0) tagdata = ATOTAGINT(strtok(buf," \t\n\r\f"));
+ else tagdata = ATOTAGINT(strtok(NULL," \t\n\r\f"));
+ ninteger = atoi(strtok(NULL," \t\n\r\f"));
+ ndouble = atoi(strtok(NULL," \t\n\r\f"));
+
+ for (j = 0; j < ninteger; j++)
+ ivalues[j] = strtok(NULL," \t\n\r\f");
+ for (j = 0; j < ndouble; j++)
+ dvalues[j] = strtok(NULL," \t\n\r\f");
+
+ if (tagdata <= 0 || tagdata > map_tag_max)
+ error->one(FLERR,"Invalid atom ID in Bodies section of data file");
+
+ if ((m = map(tagdata)) >= 0)
+ avec_body->data_body(m,ninteger,ndouble,ivalues,dvalues);
+ }
+
+ delete [] ivalues;
+ delete [] dvalues;
+}
+
/* ----------------------------------------------------------------------
allocate arrays of length ntypes
only done after ntypes is set
------------------------------------------------------------------------- */
void Atom::allocate_type_arrays()
{
if (avec->mass_type) {
mass = new double[ntypes+1];
mass_setflag = new int[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) mass_setflag[itype] = 0;
}
}
/* ----------------------------------------------------------------------
set a mass and flag it as set
called from reading of data file
------------------------------------------------------------------------- */
void Atom::set_mass(const char *str)
{
if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style");
int itype;
double mass_one;
int n = sscanf(str,"%d %lg",&itype,&mass_one);
if (n != 2) error->all(FLERR,"Invalid mass line in data file");
if (itype < 1 || itype > ntypes)
error->all(FLERR,"Invalid type for mass set");
mass[itype] = mass_one;
mass_setflag[itype] = 1;
if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value");
}
/* ----------------------------------------------------------------------
set a mass and flag it as set
called from EAM pair routine
------------------------------------------------------------------------- */
void Atom::set_mass(int itype, double value)
{
if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style");
if (itype < 1 || itype > ntypes)
error->all(FLERR,"Invalid type for mass set");
mass[itype] = value;
mass_setflag[itype] = 1;
if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value");
}
/* ----------------------------------------------------------------------
set one or more masses and flag them as set
called from reading of input script
------------------------------------------------------------------------- */
void Atom::set_mass(int narg, char **arg)
{
if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style");
int lo,hi;
force->bounds(arg[0],ntypes,lo,hi);
if (lo < 1 || hi > ntypes) error->all(FLERR,"Invalid type for mass set");
for (int itype = lo; itype <= hi; itype++) {
mass[itype] = atof(arg[1]);
mass_setflag[itype] = 1;
if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value");
}
}
/* ----------------------------------------------------------------------
set all masses as read in from restart file
------------------------------------------------------------------------- */
void Atom::set_mass(double *values)
{
for (int itype = 1; itype <= ntypes; itype++) {
mass[itype] = values[itype];
mass_setflag[itype] = 1;
}
}
/* ----------------------------------------------------------------------
check that all masses have been set
------------------------------------------------------------------------- */
void Atom::check_mass()
{
if (mass == NULL) return;
for (int itype = 1; itype <= ntypes; itype++)
if (mass_setflag[itype] == 0) error->all(FLERR,"All masses are not set");
}
/* ----------------------------------------------------------------------
check that radii of all particles of itype are the same
return 1 if true, else return 0
also return the radius value for that type
------------------------------------------------------------------------- */
int Atom::radius_consistency(int itype, double &rad)
{
double value = -1.0;
int flag = 0;
for (int i = 0; i < nlocal; i++) {
if (type[i] != itype) continue;
if (value < 0.0) value = radius[i];
else if (value != radius[i]) flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) return 0;
MPI_Allreduce(&value,&rad,1,MPI_DOUBLE,MPI_MAX,world);
return 1;
}
/* ----------------------------------------------------------------------
check that shape of all particles of itype are the same
return 1 if true, else return 0
also return the 3 shape params for itype
------------------------------------------------------------------------- */
int Atom::shape_consistency(int itype,
double &shapex, double &shapey, double &shapez)
{
double zero[3] = {0.0, 0.0, 0.0};
double one[3] = {-1.0, -1.0, -1.0};
double *shape;
AtomVecEllipsoid *avec_ellipsoid =
(AtomVecEllipsoid *) style_match("ellipsoid");
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int flag = 0;
for (int i = 0; i < nlocal; i++) {
if (type[i] != itype) continue;
if (ellipsoid[i] < 0) shape = zero;
else shape = bonus[ellipsoid[i]].shape;
if (one[0] < 0.0) {
one[0] = shape[0];
one[1] = shape[1];
one[2] = shape[2];
} else if (one[0] != shape[0] || one[1] != shape[1] || one[2] != shape[2])
flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) return 0;
double oneall[3];
MPI_Allreduce(one,oneall,3,MPI_DOUBLE,MPI_MAX,world);
shapex = oneall[0];
shapey = oneall[1];
shapez = oneall[2];
return 1;
}
/* ----------------------------------------------------------------------
add a new molecule template
------------------------------------------------------------------------- */
void Atom::add_molecule(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal molecule command");
if (find_molecule(arg[0]) >= 0) error->all(FLERR,"Reuse of molecule ID");
// extend molecule list if necessary
if (nmolecule == maxmol) {
maxmol += DELTA_MOLECULE;
molecules = (Molecule **)
memory->srealloc(molecules,maxmol*sizeof(Molecule *),"atom::molecules");
}
molecules[nmolecule++] = new Molecule(lmp,narg,arg);
}
/* ----------------------------------------------------------------------
find which molecule has molecule ID
return -1 if does not exist
------------------------------------------------------------------------- */
int Atom::find_molecule(char *id)
{
int imol;
for (imol = 0; imol < nmolecule; imol++)
if (strcmp(id,molecules[imol]->id) == 0) return imol;
return -1;
}
/* ----------------------------------------------------------------------
add info to current atom ilocal from molecule template onemol and its iatom
offset = atom ID preceeding IDs of atoms in this molecule
------------------------------------------------------------------------- */
void Atom::add_molecule_atom(Molecule *onemol, int iatom,
- int ilocal, int offset)
+ int ilocal, tagint offset)
{
if (onemol->qflag) q[ilocal] = onemol->q[iatom];
if (onemol->radiusflag) radius[ilocal] = onemol->radius[iatom];
if (onemol->rmassflag) rmass[ilocal] = onemol->rmass[iatom];
else if (rmass_flag)
rmass[ilocal] = 4.0*MY_PI/3.0 *
radius[ilocal]*radius[ilocal]*radius[ilocal];
if (onemol->bondflag) {
num_bond[ilocal] = onemol->num_bond[iatom];
for (int i = 0; i < num_bond[ilocal]; i++) {
bond_type[ilocal][i] = onemol->bond_type[iatom][i];
bond_atom[ilocal][i] = onemol->bond_atom[iatom][i] + offset;
}
}
if (onemol->angleflag) {
num_angle[ilocal] = onemol->num_angle[iatom];
for (int i = 0; i < num_angle[ilocal]; i++) {
angle_type[ilocal][i] = onemol->angle_type[iatom][i];
angle_atom1[ilocal][i] = onemol->angle_atom1[iatom][i] + offset;
angle_atom2[ilocal][i] = onemol->angle_atom2[iatom][i] + offset;
angle_atom3[ilocal][i] = onemol->angle_atom3[iatom][i] + offset;
}
}
if (onemol->dihedralflag) {
num_dihedral[ilocal] = onemol->num_dihedral[iatom];
for (int i = 0; i < num_dihedral[ilocal]; i++) {
dihedral_type[ilocal][i] = onemol->dihedral_type[iatom][i];
dihedral_atom1[ilocal][i] = onemol->dihedral_atom1[iatom][i] + offset;
dihedral_atom2[ilocal][i] = onemol->dihedral_atom2[iatom][i] + offset;
dihedral_atom3[ilocal][i] = onemol->dihedral_atom3[iatom][i] + offset;
dihedral_atom4[ilocal][i] = onemol->dihedral_atom4[iatom][i] + offset;
}
}
if (onemol->improperflag) {
num_improper[ilocal] = onemol->num_improper[iatom];
for (int i = 0; i < num_improper[ilocal]; i++) {
improper_type[ilocal][i] = onemol->improper_type[iatom][i];
improper_atom1[ilocal][i] = onemol->improper_atom1[iatom][i] + offset;
improper_atom2[ilocal][i] = onemol->improper_atom2[iatom][i] + offset;
improper_atom3[ilocal][i] = onemol->improper_atom3[iatom][i] + offset;
improper_atom4[ilocal][i] = onemol->improper_atom4[iatom][i] + offset;
}
}
// error check against maxspecial in case user has not done one of these:
// create_box extra/special/per/atom N
// read_data extra special per atom N
// special_bonds extra N
// if explicitly used special_bonds, may not have maintained extra
if (onemol->specialflag) {
if (onemol->maxspecial > maxspecial)
error->one(FLERR,"Molecule file special bond counts are too large");
nspecial[ilocal][0] = onemol->nspecial[iatom][0];
nspecial[ilocal][1] = onemol->nspecial[iatom][1];
int n = nspecial[ilocal][2] = onemol->nspecial[iatom][2];
for (int i = 0; i < n; i++)
special[ilocal][i] = onemol->special[iatom][i] + offset;
}
}
/* ----------------------------------------------------------------------
reorder owned atoms so those in firstgroup appear first
called by comm->exchange() if atom_modify first group is set
only owned atoms exist at this point, no ghost atoms
------------------------------------------------------------------------- */
void Atom::first_reorder()
{
// insure there is one extra atom location at end of arrays for swaps
if (nlocal == nmax) avec->grow(0);
// loop over owned atoms
// nfirst = index of first atom not in firstgroup
// when find firstgroup atom out of place, swap it with atom nfirst
int bitmask = group->bitmask[firstgroup];
nfirst = 0;
while (nfirst < nlocal && mask[nfirst] & bitmask) nfirst++;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & bitmask && i > nfirst) {
avec->copy(i,nlocal,0);
avec->copy(nfirst,i,0);
avec->copy(nlocal,nfirst,0);
while (nfirst < nlocal && mask[nfirst] & bitmask) nfirst++;
}
}
}
/* ----------------------------------------------------------------------
perform spatial sort of atoms within my sub-domain
always called between comm->exchange() and comm->borders()
don't have to worry about clearing/setting atom->map since done in comm
------------------------------------------------------------------------- */
void Atom::sort()
{
int i,m,n,ix,iy,iz,ibin,empty;
// set next timestep for sorting to take place
nextsort = (update->ntimestep/sortfreq)*sortfreq + sortfreq;
// download data from GPU if necessary
if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->downloadAll();
// re-setup sort bins if needed
if (domain->box_change) setup_sort_bins();
if (nbins == 1) return;
// reallocate per-atom vectors if needed
if (nlocal > maxnext) {
memory->destroy(next);
memory->destroy(permute);
maxnext = atom->nmax;
memory->create(next,maxnext,"atom:next");
memory->create(permute,maxnext,"atom:permute");
}
// insure there is one extra atom location at end of arrays for swaps
if (nlocal == nmax) avec->grow(0);
// bin atoms in reverse order so linked list will be in forward order
for (i = 0; i < nbins; i++) binhead[i] = -1;
for (i = nlocal-1; i >= 0; i--) {
ix = static_cast<int> ((x[i][0]-bboxlo[0])*bininvx);
iy = static_cast<int> ((x[i][1]-bboxlo[1])*bininvy);
iz = static_cast<int> ((x[i][2]-bboxlo[2])*bininvz);
ix = MAX(ix,0);
iy = MAX(iy,0);
iz = MAX(iz,0);
ix = MIN(ix,nbinx-1);
iy = MIN(iy,nbiny-1);
iz = MIN(iz,nbinz-1);
ibin = iz*nbiny*nbinx + iy*nbinx + ix;
next[i] = binhead[ibin];
binhead[ibin] = i;
}
// permute = desired permutation of atoms
// permute[I] = J means Ith new atom will be Jth old atom
n = 0;
for (m = 0; m < nbins; m++) {
i = binhead[m];
while (i >= 0) {
permute[n++] = i;
i = next[i];
}
}
// current = current permutation, just reuse next vector
// current[I] = J means Ith current atom is Jth old atom
int *current = next;
for (i = 0; i < nlocal; i++) current[i] = i;
// reorder local atom list, when done, current = permute
// perform "in place" using copy() to extra atom location at end of list
// inner while loop processes one cycle of the permutation
// copy before inner-loop moves an atom to end of atom list
// copy after inner-loop moves atom at end of list back into list
// empty = location in atom list that is currently empty
for (i = 0; i < nlocal; i++) {
if (current[i] == permute[i]) continue;
avec->copy(i,nlocal,0);
empty = i;
while (permute[empty] != i) {
avec->copy(permute[empty],empty,0);
empty = current[empty] = permute[empty];
}
avec->copy(nlocal,empty,0);
current[empty] = permute[empty];
}
// upload data back to GPU if necessary
if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->uploadAll();
// sanity check that current = permute
//int flag = 0;
//for (i = 0; i < nlocal; i++)
// if (current[i] != permute[i]) flag = 1;
//int flagall;
//MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
//if (flagall) error->all(FLERR,"Atom sort did not operate correctly");
}
/* ----------------------------------------------------------------------
setup bins for spatial sorting of atoms
------------------------------------------------------------------------- */
void Atom::setup_sort_bins()
{
// binsize:
// user setting if explicitly set
// 1/2 of neighbor cutoff for non-CUDA
// CUDA_CHUNK atoms/proc for CUDA
// check if neighbor cutoff = 0.0
double binsize;
if (userbinsize > 0.0) binsize = userbinsize;
else if (!lmp->cuda) binsize = 0.5 * neighbor->cutneighmax;
else {
if (domain->dimension == 3) {
double vol = (domain->boxhi[0]-domain->boxlo[0]) *
(domain->boxhi[1]-domain->boxlo[1]) *
(domain->boxhi[2]-domain->boxlo[2]);
binsize = pow(1.0*CUDA_CHUNK/natoms*vol,1.0/3.0);
} else {
double area = (domain->boxhi[0]-domain->boxlo[0]) *
(domain->boxhi[1]-domain->boxlo[1]);
binsize = pow(1.0*CUDA_CHUNK/natoms*area,1.0/2.0);
}
}
if (binsize == 0.0) error->all(FLERR,"Atom sorting has bin size = 0.0");
double bininv = 1.0/binsize;
// nbin xyz = local bins
// bbox lo/hi = bounding box of my sub-domain
if (domain->triclinic)
domain->bbox(domain->sublo_lamda,domain->subhi_lamda,bboxlo,bboxhi);
else {
bboxlo[0] = domain->sublo[0];
bboxlo[1] = domain->sublo[1];
bboxlo[2] = domain->sublo[2];
bboxhi[0] = domain->subhi[0];
bboxhi[1] = domain->subhi[1];
bboxhi[2] = domain->subhi[2];
}
nbinx = static_cast<int> ((bboxhi[0]-bboxlo[0]) * bininv);
nbiny = static_cast<int> ((bboxhi[1]-bboxlo[1]) * bininv);
nbinz = static_cast<int> ((bboxhi[2]-bboxlo[2]) * bininv);
if (domain->dimension == 2) nbinz = 1;
if (nbinx == 0) nbinx = 1;
if (nbiny == 0) nbiny = 1;
if (nbinz == 0) nbinz = 1;
bininvx = nbinx / (bboxhi[0]-bboxlo[0]);
bininvy = nbiny / (bboxhi[1]-bboxlo[1]);
bininvz = nbinz / (bboxhi[2]-bboxlo[2]);
if (1.0*nbinx*nbiny*nbinz > INT_MAX)
error->one(FLERR,"Too many atom sorting bins");
nbins = nbinx*nbiny*nbinz;
// reallocate per-bin memory if needed
if (nbins > maxbin) {
memory->destroy(binhead);
maxbin = nbins;
memory->create(binhead,maxbin,"atom:binhead");
}
}
/* ----------------------------------------------------------------------
register a callback to a fix so it can manage atom-based arrays
happens when fix is created
flag = 0 for grow, 1 for restart, 2 for border comm
------------------------------------------------------------------------- */
void Atom::add_callback(int flag)
{
int ifix;
// find the fix
// if find NULL ptr:
// it's this one, since it is being replaced and has just been deleted
// at this point in re-creation
// if don't find NULL ptr:
// i is set to nfix = new one currently being added at end of list
for (ifix = 0; ifix < modify->nfix; ifix++)
if (modify->fix[ifix] == NULL) break;
// add callback to lists, reallocating if necessary
if (flag == 0) {
if (nextra_grow == nextra_grow_max) {
nextra_grow_max += DELTA;
memory->grow(extra_grow,nextra_grow_max,"atom:extra_grow");
}
extra_grow[nextra_grow] = ifix;
nextra_grow++;
} else if (flag == 1) {
if (nextra_restart == nextra_restart_max) {
nextra_restart_max += DELTA;
memory->grow(extra_restart,nextra_restart_max,"atom:extra_restart");
}
extra_restart[nextra_restart] = ifix;
nextra_restart++;
} else if (flag == 2) {
if (nextra_border == nextra_border_max) {
nextra_border_max += DELTA;
memory->grow(extra_border,nextra_border_max,"atom:extra_border");
}
extra_border[nextra_border] = ifix;
nextra_border++;
}
}
/* ----------------------------------------------------------------------
unregister a callback to a fix
happens when fix is deleted, called by its destructor
flag = 0 for grow, 1 for restart
------------------------------------------------------------------------- */
void Atom::delete_callback(const char *id, int flag)
{
int ifix;
for (ifix = 0; ifix < modify->nfix; ifix++)
if (strcmp(id,modify->fix[ifix]->id) == 0) break;
// compact the list of callbacks
if (flag == 0) {
int match;
for (match = 0; match < nextra_grow; match++)
if (extra_grow[match] == ifix) break;
for (int i = match; i < nextra_grow-1; i++)
extra_grow[i] = extra_grow[i+1];
nextra_grow--;
} else if (flag == 1) {
int match;
for (match = 0; match < nextra_restart; match++)
if (extra_restart[match] == ifix) break;
for (int i = match; i < nextra_restart-1; i++)
extra_restart[i] = extra_restart[i+1];
nextra_restart--;
} else if (flag == 2) {
int match;
for (match = 0; match < nextra_border; match++)
if (extra_border[match] == ifix) break;
for (int i = match; i < nextra_border-1; i++)
extra_border[i] = extra_border[i+1];
nextra_border--;
}
}
/* ----------------------------------------------------------------------
decrement ptrs in callback lists to fixes beyond the deleted ifix
happens after fix is deleted
------------------------------------------------------------------------- */
void Atom::update_callback(int ifix)
{
for (int i = 0; i < nextra_grow; i++)
if (extra_grow[i] > ifix) extra_grow[i]--;
for (int i = 0; i < nextra_restart; i++)
if (extra_restart[i] > ifix) extra_restart[i]--;
for (int i = 0; i < nextra_border; i++)
if (extra_border[i] > ifix) extra_border[i]--;
}
/* ----------------------------------------------------------------------
find custom per-atom vector with name
return index if found, and flag = 0/1 for int/double
return -1 if not found
------------------------------------------------------------------------- */
int Atom::find_custom(char *name, int &flag)
{
for (int i = 0; i < nivector; i++)
if (iname[i] && strcmp(iname[i],name) == 0) {
flag = 0;
return i;
}
for (int i = 0; i < ndvector; i++)
if (dname[i] && strcmp(dname[i],name) == 0) {
flag = 1;
return i;
}
return -1;
}
/* ----------------------------------------------------------------------
add a custom variable with name of type flag = 0/1 for int/double
assumes name does not already exist
return index in ivector or dvector of its location
------------------------------------------------------------------------- */
int Atom::add_custom(char *name, int flag)
{
int index;
if (flag == 0) {
index = nivector;
nivector++;
iname = (char **) memory->srealloc(iname,nivector*sizeof(char *),
"atom:iname");
int n = strlen(name) + 1;
iname[index] = new char[n];
strcpy(iname[index],name);
ivector = (int **) memory->srealloc(ivector,nivector*sizeof(int *),
"atom:ivector");
memory->create(ivector[index],nmax,"atom:ivector");
} else {
index = ndvector;
ndvector++;
dname = (char **) memory->srealloc(dname,ndvector*sizeof(char *),
"atom:dname");
int n = strlen(name) + 1;
dname[index] = new char[n];
strcpy(dname[index],name);
dvector = (double **) memory->srealloc(dvector,ndvector*sizeof(double *),
"atom:dvector");
memory->create(dvector[index],nmax,"atom:dvector");
}
return index;
}
/* ----------------------------------------------------------------------
remove a custom variable of type flag = 0/1 for int/double at index
free memory for vector and name and set ptrs to NULL
ivector/dvector and iname/dname lists never shrink
------------------------------------------------------------------------- */
void Atom::remove_custom(int flag, int index)
{
if (flag == 0) {
memory->destroy(ivector[index]);
ivector[index] = NULL;
delete [] iname[index];
iname[index] = NULL;
} else {
memory->destroy(dvector[index]);
dvector[index] = NULL;
delete [] dname[index];
dname[index] = NULL;
}
}
/* ----------------------------------------------------------------------
return a pointer to a named internal variable
if don't recognize name, return NULL
customize by adding names
------------------------------------------------------------------------- */
void *Atom::extract(char *name)
{
if (strcmp(name,"mass") == 0) return (void *) mass;
if (strcmp(name,"id") == 0) return (void *) tag;
if (strcmp(name,"type") == 0) return (void *) type;
if (strcmp(name,"mask") == 0) return (void *) mask;
if (strcmp(name,"image") == 0) return (void *) image;
if (strcmp(name,"x") == 0) return (void *) x;
if (strcmp(name,"v") == 0) return (void *) v;
if (strcmp(name,"f") == 0) return (void *) f;
if (strcmp(name,"molecule") == 0) return (void *) molecule;
if (strcmp(name,"q") == 0) return (void *) q;
if (strcmp(name,"mu") == 0) return (void *) mu;
if (strcmp(name,"omega") == 0) return (void *) omega;
if (strcmp(name,"amgmom") == 0) return (void *) angmom;
if (strcmp(name,"torque") == 0) return (void *) torque;
if (strcmp(name,"radius") == 0) return (void *) radius;
if (strcmp(name,"rmass") == 0) return (void *) rmass;
if (strcmp(name,"vfrac") == 0) return (void *) vfrac;
if (strcmp(name,"s0") == 0) return (void *) s0;
return NULL;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
call to avec tallies per-atom vectors
add in global to local mapping storage
------------------------------------------------------------------------- */
bigint Atom::memory_usage()
{
memlength = DELTA_MEMSTR;
memory->create(memstr,memlength,"atom:memstr");
memstr[0] = '\0';
bigint bytes = avec->memory_usage();
memory->destroy(memstr);
- bytes += smax*sizeof(int);
+ bytes += max_same*sizeof(int);
if (map_style == 1)
- bytes += memory->usage(map_array,map_tag_max+1);
+ bytes += memory->usage(map_array,max_array);
else if (map_style == 2) {
bytes += map_nbucket*sizeof(int);
bytes += map_nhash*sizeof(HashElem);
}
if (maxnext) {
bytes += memory->usage(next,maxnext);
bytes += memory->usage(permute,maxnext);
}
return bytes;
}
/* ----------------------------------------------------------------------
accumulate per-atom vec names in memstr, padded by spaces
return 1 if padded str is not already in memlist, else 0
------------------------------------------------------------------------- */
int Atom::memcheck(const char *str)
{
int n = strlen(str) + 3;
char *padded = new char[n];
strcpy(padded," ");
strcat(padded,str);
strcat(padded," ");
if (strstr(memstr,padded)) {
delete [] padded;
return 0;
}
if (strlen(memstr) + n >= memlength) {
memlength += DELTA_MEMSTR;
memory->grow(memstr,memlength,"atom:memstr");
}
strcat(memstr,padded);
delete [] padded;
return 1;
}
diff --git a/src/atom.h b/src/atom.h
index 3dfc010d5..8a5a0b643 100644
--- a/src/atom.h
+++ b/src/atom.h
@@ -1,407 +1,413 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_ATOM_H
#define LMP_ATOM_H
#include "pointers.h"
namespace LAMMPS_NS {
class Atom : protected Pointers {
public:
char *atom_style;
class AtomVec *avec;
// atom counts
bigint natoms; // total # of atoms in system, could be 0
// natoms may not be current if atoms lost
int nlocal,nghost; // # of owned and ghost atoms on this proc
int nmax; // max # of owned+ghost in arrays on this proc
int tag_enable; // 0/1 if atom ID tags are defined
int molecular; // 0 = atomic, 1 = molecular system
bigint nbonds,nangles,ndihedrals,nimpropers;
int ntypes,nbondtypes,nangletypes,ndihedraltypes,nimpropertypes;
int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom;
int extra_bond_per_atom,extra_angle_per_atom;
int extra_dihedral_per_atom,extra_improper_per_atom;
int firstgroup; // store atoms in this group first, -1 if unset
int nfirst; // # of atoms in first group on this proc
char *firstgroupname; // group-ID to store first, NULL if unset
// per-atom arrays
// customize by adding new array
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule,*molindex,*molatom;
double *q,**mu;
double **omega,**angmom,**torque;
double *radius,*rmass,*vfrac,*s0;
double **x0;
int *ellipsoid,*line,*tri,*body;
int *spin;
double *eradius,*ervel,*erforce,*ervelforce;
double *cs,*csforce,*vforce;
int *etag;
double *rho, *drho;
double *e, *de;
double **vest;
double *cv;
int **nspecial; // 0,1,2 = cummulative # of 1-2,1-3,1-4 neighs
- int **special; // IDs of 1-2,1-3,1-4 neighs of each atom
+ tagint **special; // IDs of 1-2,1-3,1-4 neighs of each atom
int maxspecial; // special[nlocal][maxspecial]
int *num_bond;
int **bond_type;
- int **bond_atom;
+ tagint **bond_atom;
int *num_angle;
int **angle_type;
- int **angle_atom1,**angle_atom2,**angle_atom3;
+ tagint **angle_atom1,**angle_atom2,**angle_atom3;
int *num_dihedral;
int **dihedral_type;
- int **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
+ tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
int *num_improper;
int **improper_type;
- int **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
+ tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
// custom arrays used by fix property/atom
int **ivector;
double **dvector;
char **iname,**dname;
int nivector,ndvector;
// used by USER-CUDA to flag used per-atom arrays
unsigned int datamask;
unsigned int datamask_ext;
// atom style and per-atom array existence flags
// customize by adding new flag
int sphere_flag,ellipsoid_flag,line_flag,tri_flag,body_flag;
int peri_flag,electron_flag;
int ecp_flag;
int wavepacket_flag,sph_flag;
int molecule_flag,molindex_flag,molatom_flag;
int q_flag,mu_flag;
int rmass_flag,radius_flag,omega_flag,torque_flag,angmom_flag;
int vfrac_flag,spin_flag,eradius_flag,ervel_flag,erforce_flag;
int cs_flag,csforce_flag,vforce_flag,ervelforce_flag,etag_flag;
int rho_flag,e_flag,cv_flag,vest_flag;
// molecules
int nmolecule,maxmol;
class Molecule **molecules;
// extra peratom info in restart file destined for fix & diag
double **extra;
// per-type arrays
double *mass;
int *mass_setflag;
// callback ptrs for atom arrays managed by fix classes
int nextra_grow,nextra_restart,nextra_border; // # of callbacks of each type
int *extra_grow,*extra_restart,*extra_border; // index of fix to callback to
int nextra_grow_max,nextra_restart_max; // size of callback lists
int nextra_border_max;
int nextra_store;
- int map_style; // default or user-specified style of map
- // 0 = none, 1 = array, 2 = hash
- int map_tag_max; // max atom ID that map() is setup for
+ int map_style; // style of atom map: 0=none, 1=array, 2=hash
+ int map_user; // user selected style = same 0,1,2
+ tagint map_tag_max; // max atom ID that map() is setup for
// spatial sorting of atoms
int sortfreq; // sort atoms every this many steps, 0 = off
bigint nextsort; // next timestep to sort on
// indices of atoms with same ID
int *sametag; // sametag[I] = next atom with same ID, -1 if no more
// functions
Atom(class LAMMPS *);
~Atom();
void settings(class Atom *);
void create_avec(const char *, int, char **, char *suffix = NULL);
class AtomVec *new_avec(const char *, char *, int &);
void init();
void setup();
class AtomVec *style_match(const char *);
void modify_params(int, char **);
+ void tag_check();
void tag_extend();
int tag_consecutive();
int parse_data(const char *);
int count_words(const char *);
void data_atoms(int, char *);
void data_vels(int, char *);
+
+ void data_bonds(int, char *, int *);
+ void data_angles(int, char *, int *);
+ void data_dihedrals(int, char *, int *);
+ void data_impropers(int, char *, int *);
+
void data_bonus(int, char *, class AtomVec *);
void data_bodies(int, char *, class AtomVecBody *);
- void data_bonds(int, char *);
- void data_angles(int, char *);
- void data_dihedrals(int, char *);
- void data_impropers(int, char *);
-
void allocate_type_arrays();
void set_mass(const char *);
void set_mass(int, double);
void set_mass(int, char **);
void set_mass(double *);
void check_mass();
int radius_consistency(int, double &);
int shape_consistency(int, double &, double &, double &);
void add_molecule(int, char **);
int find_molecule(char *);
- void add_molecule_atom(class Molecule *, int, int, int);
+ void add_molecule_atom(class Molecule *, int, int, tagint);
void first_reorder();
void sort();
void add_callback(int);
void delete_callback(const char *, int);
void update_callback(int);
int find_custom(char *, int &);
int add_custom(char *, int);
void remove_custom(int, int);
void *extract(char *);
inline int* get_map_array() {return map_array;};
inline int get_map_size() {return map_tag_max+1;};
bigint memory_usage();
int memcheck(const char *);
// functions for global to local ID mapping
// map lookup function inlined for efficiency
// return -1 if no map defined
- inline int map(int global) {
+ inline int map(tagint global) {
if (map_style == 1) return map_array[global];
else if (map_style == 2) return map_find_hash(global);
else return -1;
};
void map_init();
void map_clear();
void map_set();
- void map_one(int, int);
+ void map_one(tagint, int);
void map_delete();
- int map_find_hash(int);
+ int map_find_hash(tagint);
private:
// global to local ID mapping
int *map_array; // direct map of length map_tag_max + 1
- int smax; // max size of sametag
struct HashElem {
- int global; // key to search on = global ID
- int local; // value associated with key = local index
- int next; // next entry in this bucket, -1 if last
+ tagint global; // key to search on = global ID
+ int local; // value associated with key = local index
+ int next; // next entry in this bucket, -1 if last
};
- int map_nhash; // # of entries hash table can hold
- int map_nused; // # of actual entries in hash table
- int map_free; // ptr to 1st unused entry in hash table
- int map_nbucket; // # of hash buckets
- int *map_bucket; // ptr to 1st entry in each bucket
- HashElem *map_hash; // hash table
+ int map_nhash; // # of entries hash table can hold
+ int map_nused; // # of actual entries in hash table
+ int map_free; // ptr to 1st unused entry in hash table
+ int map_nbucket; // # of hash buckets
+ int *map_bucket; // ptr to 1st entry in each bucket
+ HashElem *map_hash; // hash table
+
+ int max_array; // allocated size of map_array (+1)
+ int max_nhash; // allocated size of hash table
+ int max_same; // allocated size of sametag
// spatial sorting of atoms
int nbins; // # of sorting bins
int nbinx,nbiny,nbinz; // bins in each dimension
int maxbin; // max # of bins
int maxnext; // max size of next,permute
int *binhead; // 1st atom in each bin
int *next; // next atom in bin
int *permute; // permutation vector
double userbinsize; // requested sort bin size
double bininvx,bininvy,bininvz; // inverse actual bin sizes
double bboxlo[3],bboxhi[3]; // bounding box of my sub-domain
int memlength; // allocated size of memstr
char *memstr; // string of array names already counted
void setup_sort_bins();
int next_prime(int);
};
}
#endif
/* ERROR/WARNING messages:
E: Invalid atom style
The choice of atom style is unknown.
E: Could not find atom_modify first group ID
Self-explanatory.
E: Illegal ... command
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.
E: Atom_modify map command after simulation box is defined
The atom_modify map command cannot be used after a read_data,
read_restart, or create_box command.
E: Atom_modify sort and first options cannot be used together
Self-explanatory.
E: Incorrect atom format in data file
Number of values per atom line in the data file is not consistent with
the atom style.
E: Incorrect velocity format in data file
Each atom style defines a format for the Velocity section
of the data file. The read-in lines do not match.
E: Invalid atom ID in Velocities section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Incorrect bonus data format in data file
See the read_data doc page for a description of how various kinds of
bonus data must be formatted for certain atom styles.
E: Invalid atom ID in Bonus section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid atom ID in Bodies section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid atom ID in Bonds section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid bond type in Bonds section of data file
Bond type must be positive integer and within range of specified bond
types.
E: Invalid atom ID in Angles section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid angle type in Angles section of data file
Angle type must be positive integer and within range of specified angle
types.
E: Invalid atom ID in Dihedrals section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid dihedral type in Dihedrals section of data file
Dihedral type must be positive integer and within range of specified
dihedral types.
E: Invalid atom ID in Impropers section of data file
Atom IDs must be positive integers and within range of defined
atoms.
E: Invalid improper type in Impropers section of data file
Improper type must be positive integer and within range of specified
improper types.
E: Cannot set mass for this atom style
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.
E: Invalid mass line in data file
Self-explanatory.
E: Invalid type for mass set
Mass command must set a type from 1-N where N is the number of atom
types.
E: Invalid mass value
Self-explanatory.
E: All masses are not set
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.
E: Atom sort did not operate correctly
This is an internal LAMMPS error. Please report it to the
developers.
E: Atom sorting has bin size = 0.0
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.
E: Too many atom sorting bins
This is likely due to an immense simulation box that has blown up
to a large size.
*/
diff --git a/src/atom_map.cpp b/src/atom_map.cpp
index 93c377b81..eab9b226f 100644
--- a/src/atom_map.cpp
+++ b/src/atom_map.cpp
@@ -1,304 +1,360 @@
/* ----------------------------------------------------------------------
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 "atom.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define EXTRA 1000
/* ----------------------------------------------------------------------
allocate and initialize array or hash table for global -> local map
set map_tag_max = largest atom ID (may be larger than natoms)
for array option:
- array length = 1 to largest tag of any atom
+ array length = 1 to map_tag_max
set entire array to -1 as initial values
for hash option:
map_nhash = length of hash table
- map_nbucket = # of hash buckets, prime larger than map_nhash
+ map_nbucket = # of hash buckets, prime larger than map_nhash * 2
so buckets will only be filled with 0 or 1 atoms on average
------------------------------------------------------------------------- */
void Atom::map_init()
{
- map_delete();
-
if (tag_enable == 0)
error->all(FLERR,"Cannot create an atom map unless atoms have IDs");
- int max = 0;
- for (int i = 0; i < nlocal; i++) max = MAX(max,tag[i]);
- MPI_Allreduce(&max,&map_tag_max,1,MPI_INT,MPI_MAX,world);
-
- memory->destroy(sametag);
- smax = nlocal + nghost + EXTRA;
- memory->create(sametag,smax,"atom:sametag");
-
- if (map_style == 1) {
- memory->create(map_array,map_tag_max+1,"atom:map_array");
- for (int i = 0; i <= map_tag_max; i++) map_array[i] = -1;
-
- } else {
-
- // map_nhash = max # of atoms that can be hashed on this proc
- // set to max of ave atoms/proc or atoms I can store
- // multiply by 2, require at least 1000
- // doubling means hash table will be re-init only rarely
+ int map_style_old = map_style;
- int nper = static_cast<int> (natoms/comm->nprocs);
- map_nhash = MAX(nper,nmax);
- map_nhash *= 2;
- map_nhash = MAX(map_nhash,1000);
+ // map_tag_max = max ID of any atom that will be in new map
- // map_nbucket = prime just larger than map_nhash
-
- map_nbucket = next_prime(map_nhash);
-
- // set all buckets to empty
- // set hash to map_nhash in length
- // put all hash entries in free list and point them to each other
+ tagint max = 0;
+ for (int i = 0; i < nlocal; i++) max = MAX(max,tag[i]);
+ MPI_Allreduce(&max,&map_tag_max,1,MPI_LMP_TAGINT,MPI_MAX,world);
+
+ // set map_style for new map
+ // if user-selected, use that setting
+ // else if map_tag_max > 1M, use hash
+ // else use array
+
+ if (map_user) map_style = map_user;
+ else if (map_tag_max > 1000000) map_style = 2;
+ else map_style = 1;
+
+ // recreate = 1 if must delete old map and create new map
+ // recreate = 0 if can re-use old map w/out realloc and just adjust settings
+
+ int recreate = 0;
+ if (map_style != map_style_old) recreate = 1;
+ else if (map_style == 1 && map_tag_max > max_array) recreate = 1;
+ else if (map_style == 2 && nlocal+nghost > map_nhash) recreate = 1;
+
+ // if not recreating:
+ // for array, just initialize current map_tag_max values
+ // for hash, set all buckets to empty, put all entries in free list
+
+ if (!recreate) {
+ if (map_style == 1) {
+ for (int i = 0; i <= map_tag_max; i++) map_array[i] = -1;
+ } else {
+ for (int i = 0; i < map_nbucket; i++) map_bucket[i] = -1;
+ map_nused = 0;
+ map_free = 0;
+ for (int i = 0; i < map_nhash; i++) map_hash[i].next = i+1;
+ map_hash[map_nhash-1].next = -1;
+ }
- map_bucket = new int[map_nbucket];
- for (int i = 0; i < map_nbucket; i++) map_bucket[i] = -1;
+ // delete old map and create new one for array or hash
- map_hash = new HashElem[map_nhash];
- map_nused = 0;
- map_free = 0;
- for (int i = 0; i < map_nhash; i++) map_hash[i].next = i+1;
- map_hash[map_nhash-1].next = -1;
+ } else {
+ map_delete();
+
+ if (map_style == 1) {
+ max_array = map_tag_max;
+ memory->create(map_array,max_array+1,"atom:map_array");
+ for (int i = 0; i <= map_tag_max; i++) map_array[i] = -1;
+
+ } else {
+
+ // map_nhash = max # of atoms that can be hashed on this proc
+ // set to max of ave atoms/proc or atoms I can store
+ // multiply by 2, require at least 1000
+ // doubling means hash table will need to be re-init only rarely
+
+ int nper = static_cast<int> (natoms/comm->nprocs);
+ map_nhash = MAX(nper,nmax);
+ map_nhash *= 2;
+ map_nhash = MAX(map_nhash,1000);
+
+ // map_nbucket = prime just larger than map_nhash
+ // next_prime() should be fast enough,
+ // about 10% of odd integers are prime above 1M
+
+ map_nbucket = next_prime(map_nhash);
+
+ // set all buckets to empty
+ // set hash to map_nhash in length
+ // put all hash entries in free list and point them to each other
+
+ map_bucket = new int[map_nbucket];
+ for (int i = 0; i < map_nbucket; i++) map_bucket[i] = -1;
+
+ map_hash = new HashElem[map_nhash];
+ map_nused = 0;
+ map_free = 0;
+ for (int i = 0; i < map_nhash; i++) map_hash[i].next = i+1;
+ map_hash[map_nhash-1].next = -1;
+ }
}
}
/* ----------------------------------------------------------------------
clear global -> local map for all of my own and ghost atoms
for hash table option:
global ID may not be in table if image atom was already cleared
------------------------------------------------------------------------- */
void Atom::map_clear()
{
if (map_style == 1) {
int nall = nlocal + nghost;
for (int i = 0; i < nall; i++) {
sametag[i] = -1;
map_array[tag[i]] = -1;
}
} else {
- int previous,global,ibucket,index;
+ int previous,ibucket,index;
+ tagint global;
int nall = nlocal + nghost;
for (int i = 0; i < nall; i++) {
sametag[i] = -1;
// search for key
// if don't find it, done
previous = -1;
global = tag[i];
ibucket = global % map_nbucket;
index = map_bucket[ibucket];
while (index > -1) {
if (map_hash[index].global == global) break;
previous = index;
index = map_hash[index].next;
}
if (index == -1) continue;
// delete the hash entry and add it to free list
// special logic if entry is 1st in the bucket
if (previous == -1) map_bucket[ibucket] = map_hash[index].next;
else map_hash[previous].next = map_hash[index].next;
map_hash[index].next = map_free;
map_free = index;
map_nused--;
}
}
}
/* ----------------------------------------------------------------------
set global -> local map for all of my own and ghost atoms
loop in reverse order so that nearby images take precedence over far ones
and owned atoms take precedence over images
this enables valid lookups of bond topology atoms
for hash table option:
if hash table too small, re-init
global ID may already be in table if image atom was set
------------------------------------------------------------------------- */
void Atom::map_set()
{
int nall = nlocal + nghost;
- if (nall > smax) {
- smax = nall + EXTRA;
- memory->destroy(sametag);
- memory->create(sametag,smax,"atom:sametag");
- }
if (map_style == 1) {
+
+ // possible reallocation of sametag must come before loop over atoms
+ // since loop sets sametag
+
+ if (nall > max_same) {
+ max_same = nall + EXTRA;
+ memory->destroy(sametag);
+ memory->create(sametag,max_same,"atom:sametag");
+ }
+
for (int i = nall-1; i >= 0 ; i--) {
sametag[i] = map_array[tag[i]];
map_array[tag[i]] = i;
}
} else {
- int previous,global,ibucket,index;
+
+ // possible reallocation of sametag must come after map_init()
+ // since map_init() will invoke map_delete(), whacking sametag
+
if (nall > map_nhash) map_init();
+ if (nall > max_same) {
+ max_same = nall + EXTRA;
+ memory->destroy(sametag);
+ memory->create(sametag,max_same,"atom:sametag");
+ }
+
+ int previous,ibucket,index;
+ tagint global;
for (int i = nall-1; i >= 0 ; i--) {
sametag[i] = map_find_hash(tag[i]);
// search for key
// if found it, just overwrite local value with index
previous = -1;
global = tag[i];
ibucket = global % map_nbucket;
index = map_bucket[ibucket];
while (index > -1) {
if (map_hash[index].global == global) break;
previous = index;
index = map_hash[index].next;
}
if (index > -1) {
map_hash[index].local = i;
continue;
}
// take one entry from free list
// add the new global/local pair as entry at end of bucket list
// special logic if this entry is 1st in bucket
index = map_free;
map_free = map_hash[map_free].next;
if (previous == -1) map_bucket[ibucket] = index;
else map_hash[previous].next = index;
map_hash[index].global = global;
map_hash[index].local = i;
map_hash[index].next = -1;
map_nused++;
}
}
}
/* ----------------------------------------------------------------------
set global to local map for one atom
for hash table option:
global ID may already be in table if atom was already set
called by Special class
------------------------------------------------------------------------- */
-void Atom::map_one(int global, int local)
+void Atom::map_one(tagint global, int local)
{
if (map_style == 1) map_array[global] = local;
else {
// search for key
// if found it, just overwrite local value with index
int previous = -1;
int ibucket = global % map_nbucket;
int index = map_bucket[ibucket];
while (index > -1) {
if (map_hash[index].global == global) break;
previous = index;
index = map_hash[index].next;
}
if (index > -1) {
map_hash[index].local = local;
return;
}
// take one entry from free list
// add the new global/local pair as entry at end of bucket list
// special logic if this entry is 1st in bucket
index = map_free;
map_free = map_hash[map_free].next;
if (previous == -1) map_bucket[ibucket] = index;
else map_hash[previous].next = index;
map_hash[index].global = global;
map_hash[index].local = local;
map_hash[index].next = -1;
map_nused++;
}
}
/* ----------------------------------------------------------------------
free the array or hash table for global to local mapping
------------------------------------------------------------------------- */
void Atom::map_delete()
{
memory->destroy(sametag);
sametag = NULL;
+ max_same = 0;
if (map_style == 1) {
memory->destroy(map_array);
map_array = NULL;
} else {
if (map_nhash) {
delete [] map_bucket;
delete [] map_hash;
map_bucket = NULL;
map_hash = NULL;
}
map_nhash = 0;
}
- map_tag_max = 0;
}
/* ----------------------------------------------------------------------
lookup global ID in hash table, return local index
called by map() in atom.h
------------------------------------------------------------------------- */
-int Atom::map_find_hash(int global)
+int Atom::map_find_hash(tagint global)
{
int local = -1;
int index = map_bucket[global % map_nbucket];
while (index > -1) {
if (map_hash[index].global == global) {
local = map_hash[index].local;
break;
}
index = map_hash[index].next;
}
return local;
}
/* ----------------------------------------------------------------------
return next prime larger than n
------------------------------------------------------------------------- */
int Atom::next_prime(int n)
{
int factor;
int nprime = n+1;
if (nprime % 2 == 0) nprime++;
int root = static_cast<int> (sqrt(1.0*n)) + 2;
while (nprime <= MAXSMALLINT) {
for (factor = 3; factor < root; factor++)
if (nprime % factor == 0) break;
if (factor == root) return nprime;
nprime += 2;
}
return MAXSMALLINT;
}
diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp
index 04964d5d1..fba68e808 100644
--- a/src/atom_vec.cpp
+++ b/src/atom_vec.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.
------------------------------------------------------------------------- */
#include "stdlib.h"
#include "atom_vec.h"
#include "atom.h"
#include "force.h"
#include "domain.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp)
{
nmax = 0;
bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 0;
mass_type = dipole_type = 0;
size_data_bonus = 0;
cudable = false;
}
/* ----------------------------------------------------------------------
no additional args by default
------------------------------------------------------------------------- */
void AtomVec::settings(int narg, char **arg)
{
if (narg) error->all(FLERR,"Invalid atom_style command");
}
/* ----------------------------------------------------------------------
copy of velocity remap settings from Domain
------------------------------------------------------------------------- */
void AtomVec::init()
{
deform_vremap = domain->deform_vremap;
deform_groupbit = domain->deform_groupbit;
h_rate = domain->h_rate;
if (lmp->cuda != NULL && cudable == false)
error->all(FLERR,"USER-CUDA package requires a cuda enabled atom_style");
}
/* ----------------------------------------------------------------------
reset nmax = 0, called by Atom::create_avec() when new atom style created
------------------------------------------------------------------------- */
void AtomVec::reset()
{
nmax = 0;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVec::data_vel(int m, char **values)
{
double **v = atom->v;
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVec::pack_vel(double **buf)
{
double **v = atom->v;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
}
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVec::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]);
+ fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]);
}
/* ----------------------------------------------------------------------
pack bond info for data file into buf if non-NULL
return count of bonds from this proc
do not count/pack bonds with bondtype = 0
if bondtype is negative, flip back to positive
------------------------------------------------------------------------- */
-int AtomVec::pack_bond(int **buf)
+int AtomVec::pack_bond(tagint **buf)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_bond = atom->num_bond;
int **bond_type = atom->bond_type;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int m = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
if (bond_type[i][j] == 0) continue;
if (buf) {
buf[m][0] = MAX(bond_type[i][j],-bond_type[i][j]);
buf[m][1] = tag[i];
buf[m][2] = bond_atom[i][j];
}
m++;
}
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++)
if (tag[i] < bond_atom[i][j]) {
if (bond_type[i][j] == 0) continue;
if (buf) {
buf[m][0] = MAX(bond_type[i][j],-bond_type[i][j]);
buf[m][1] = tag[i];
buf[m][2] = bond_atom[i][j];
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
write bond info to data file
------------------------------------------------------------------------- */
-void AtomVec::write_bond(FILE *fp, int n, int **buf, int index)
+void AtomVec::write_bond(FILE *fp, int n, tagint **buf, int index)
{
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %d %d %d\n",index,buf[i][0],buf[i][1],buf[i][2]);
+ fprintf(fp,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT "\n",
+ index,buf[i][0],buf[i][1],buf[i][2]);
index++;
}
}
/* ----------------------------------------------------------------------
pack angle info for data file into buf if non-NULL
return count of angles from this proc
do not count/pack angles with angletype = 0
if angletype is negative, flip back to positive
------------------------------------------------------------------------- */
-int AtomVec::pack_angle(int **buf)
+int AtomVec::pack_angle(tagint **buf)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_angle = atom->num_angle;
int **angle_type = atom->angle_type;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int m = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_angle[i]; j++) {
if (angle_type[i][j] == 0) continue;
if (buf) {
buf[m][0] = MAX(angle_type[i][j],-angle_type[i][j]);
buf[m][1] = angle_atom1[i][j];
buf[m][2] = angle_atom2[i][j];
buf[m][3] = angle_atom3[i][j];
}
m++;
}
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_angle[i]; j++)
if (tag[i] == angle_atom2[i][j]) {
if (angle_type[i][j] == 0) continue;
if (buf) {
buf[m][0] = MAX(angle_type[i][j],-angle_type[i][j]);
buf[m][1] = angle_atom1[i][j];
buf[m][2] = angle_atom2[i][j];
buf[m][3] = angle_atom3[i][j];
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
write angle info to data file
------------------------------------------------------------------------- */
-void AtomVec::write_angle(FILE *fp, int n, int **buf, int index)
+void AtomVec::write_angle(FILE *fp, int n, tagint **buf, int index)
{
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %d %d %d %d\n",index,
- buf[i][0],buf[i][1],buf[i][2],buf[i][3]);
+ fprintf(fp,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT "\n",
+ index,buf[i][0],buf[i][1],buf[i][2],buf[i][3]);
index++;
}
}
/* ----------------------------------------------------------------------
pack dihedral info for data file
------------------------------------------------------------------------- */
-void AtomVec::pack_dihedral(int **buf)
+void AtomVec::pack_dihedral(tagint **buf)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_dihedral = atom->num_dihedral;
int **dihedral_type = atom->dihedral_type;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int m = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_dihedral[i]; j++) {
buf[m][0] = dihedral_type[i][j];
buf[m][1] = dihedral_atom1[i][j];
buf[m][2] = dihedral_atom2[i][j];
buf[m][3] = dihedral_atom3[i][j];
buf[m][4] = dihedral_atom4[i][j];
m++;
}
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_dihedral[i]; j++)
if (tag[i] == dihedral_atom2[i][j]) {
buf[m][0] = dihedral_type[i][j];
buf[m][1] = dihedral_atom1[i][j];
buf[m][2] = dihedral_atom2[i][j];
buf[m][3] = dihedral_atom3[i][j];
buf[m][4] = dihedral_atom4[i][j];
m++;
}
}
}
/* ----------------------------------------------------------------------
write dihedral info to data file
------------------------------------------------------------------------- */
-void AtomVec::write_dihedral(FILE *fp, int n, int **buf, int index)
+void AtomVec::write_dihedral(FILE *fp, int n, tagint **buf, int index)
{
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %d %d %d %d %d\n",index,
- buf[i][0],buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
+ fprintf(fp,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT "\n",
+ index,buf[i][0],buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
index++;
}
}
/* ----------------------------------------------------------------------
pack improper info for data file
------------------------------------------------------------------------- */
-void AtomVec::pack_improper(int **buf)
+void AtomVec::pack_improper(tagint **buf)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_improper = atom->num_improper;
int **improper_type = atom->improper_type;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int m = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_improper[i]; j++) {
buf[m][0] = improper_type[i][j];
buf[m][1] = improper_atom1[i][j];
buf[m][2] = improper_atom2[i][j];
buf[m][3] = improper_atom3[i][j];
buf[m][4] = improper_atom4[i][j];
m++;
}
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_improper[i]; j++)
if (tag[i] == improper_atom2[i][j]) {
buf[m][0] = improper_type[i][j];
buf[m][1] = improper_atom1[i][j];
buf[m][2] = improper_atom2[i][j];
buf[m][3] = improper_atom3[i][j];
buf[m][4] = improper_atom4[i][j];
m++;
}
}
}
/* ----------------------------------------------------------------------
write improper info to data file
------------------------------------------------------------------------- */
-void AtomVec::write_improper(FILE *fp, int n, int **buf, int index)
+void AtomVec::write_improper(FILE *fp, int n, tagint **buf, int index)
{
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %d %d %d %d %d\n",index,
- buf[i][0],buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
+ fprintf(fp,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT "\n",
+ index,buf[i][0],buf[i][1],buf[i][2],buf[i][3],buf[i][4]);
index++;
}
}
diff --git a/src/atom_vec.h b/src/atom_vec.h
index 167b56107..4a27b66e6 100644
--- a/src/atom_vec.h
+++ b/src/atom_vec.h
@@ -1,153 +1,153 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_ATOM_VEC_H
#define LMP_ATOM_VEC_H
#include "stdio.h"
#include "pointers.h"
namespace LAMMPS_NS {
class AtomVec : protected Pointers {
public:
int molecular; // 0 = atomic, 1 = molecular system
int bonds_allow,angles_allow; // 1 if bonds, angles are used
int dihedrals_allow,impropers_allow; // 1 if dihedrals, impropers used
int mass_type; // 1 if per-type masses
int dipole_type; // 1 if per-type dipole moments
int comm_x_only; // 1 if only exchange x in forward comm
int comm_f_only; // 1 if only exchange f in reverse comm
int size_forward; // # of values per atom in comm
int size_reverse; // # in reverse comm
int size_border; // # in border comm
int size_velocity; // # of velocity based quantities
int size_data_atom; // number of values in Atom line
int size_data_vel; // number of values in Velocity line
int size_data_bonus; // number of values in Bonus line
int xcol_data; // column (1-N) where x is in Atom line
int cudable; // 1 if atom style is CUDA-enabled
int *maxsend; // CUDA-specific variable
AtomVec(class LAMMPS *);
virtual ~AtomVec() {}
virtual void settings(int, char **);
virtual void init();
virtual void grow(int) = 0;
virtual void grow_reset() = 0;
virtual void copy(int, int, int) = 0;
virtual void clear_bonus() {}
virtual int pack_comm(int, int *, double *, int, int *) = 0;
virtual int pack_comm_vel(int, int *, double *, int, int *) = 0;
virtual int pack_comm_hybrid(int, int *, double *) {return 0;}
virtual void unpack_comm(int, int, double *) = 0;
virtual void unpack_comm_vel(int, int, double *) = 0;
virtual int unpack_comm_hybrid(int, int, double *) {return 0;}
virtual int pack_reverse(int, int, double *) = 0;
virtual int pack_reverse_hybrid(int, int, double *) {return 0;}
virtual void unpack_reverse(int, int *, double *) = 0;
virtual int unpack_reverse_hybrid(int, int *, double *) {return 0;}
virtual int pack_border(int, int *, double *, int, int *) = 0;
virtual int pack_border_vel(int, int *, double *, int, int *) = 0;
virtual int pack_border_hybrid(int, int *, double *) {return 0;}
virtual void unpack_border(int, int, double *) = 0;
virtual void unpack_border_vel(int, int, double *) = 0;
virtual int unpack_border_hybrid(int, int, double *) {return 0;}
virtual int pack_exchange(int, double *) = 0;
virtual int unpack_exchange(double *) = 0;
virtual int size_restart() = 0;
virtual int pack_restart(int, double *) = 0;
virtual int unpack_restart(double *) = 0;
virtual void write_restart_settings(FILE *) {}
virtual void read_restart_settings(FILE *) {}
virtual void create_atom(int, double *) = 0;
virtual void data_atom(double *, imageint, char **) = 0;
virtual void data_atom_bonus(int, char **) {}
virtual int data_atom_hybrid(int, char **) {return 0;}
virtual void data_vel(int, char **);
virtual int data_vel_hybrid(int, char **) {return 0;}
virtual void pack_data(double **) = 0;
virtual int pack_data_hybrid(int, double *) {return 0;}
virtual void write_data(FILE *, int, double **) = 0;
virtual int write_data_hybrid(FILE *, double *) {return 0;}
virtual void pack_vel(double **);
virtual int pack_vel_hybrid(int, double *) {return 0;}
virtual void write_vel(FILE *, int, double **);
virtual int write_vel_hybrid(FILE *, double *) {return 0;}
void reset();
- int pack_bond(int **);
- void write_bond(FILE *, int, int **, int);
- int pack_angle(int **);
- void write_angle(FILE *, int, int **, int);
- void pack_dihedral(int **);
- void write_dihedral(FILE *, int, int **, int);
- void pack_improper(int **);
- void write_improper(FILE *, int, int **, int);
+ int pack_bond(tagint **);
+ void write_bond(FILE *, int, tagint **, int);
+ int pack_angle(tagint **);
+ void write_angle(FILE *, int, tagint **, int);
+ void pack_dihedral(tagint **);
+ void write_dihedral(FILE *, int, tagint **, int);
+ void pack_improper(tagint **);
+ void write_improper(FILE *, int, tagint **, int);
virtual bigint memory_usage() = 0;
protected:
int nmax; // local copy of atom->nmax
int deform_vremap; // local copy of domain properties
int deform_groupbit;
double *h_rate;
// union data struct for packing 32-bit and 64-bit ints into double bufs
// this avoids aliasing issues by having 2 pointers (double,int)
// to same buf memory
// constructor for 32-bit int prevents compiler
// from possibly calling the double constructor when passed an int
// copy to a double *buf:
// buf[m++] = ubuf(foo).d, where foo is a 32-bit or 64-bit int
// copy from a double *buf:
// foo = (int) ubuf(buf[m++]).i;, where (int) or (tagint) match foo
// the cast prevents compiler warnings about possible truncation
union ubuf {
- double d;
- int64_t i;
+ double d;
+ int64_t i;
ubuf(double arg) : d(arg) {}
ubuf(int64_t arg) : i(arg) {}
ubuf(int arg) : i(arg) {}
};
};
}
#endif
/* ERROR/WARNING messages:
E: Invalid atom_style command
Self-explanatory.
E: USER-CUDA package requires a cuda enabled atom_style
Self-explanatory.
*/
diff --git a/src/atom_vec_atomic.cpp b/src/atom_vec_atomic.cpp
index f27178b8f..5d96dc139 100644
--- a/src/atom_vec_atomic.cpp
+++ b/src/atom_vec_atomic.cpp
@@ -1,688 +1,685 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_atomic.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecAtomic::AtomVecAtomic(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 6;
size_velocity = 3;
size_data_atom = 5;
size_data_vel = 4;
xcol_data = 3;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecAtomic::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecAtomic::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecAtomic::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAtomic::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecAtomic::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAtomic::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecAtomic::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecAtomic::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecAtomic::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecAtomic::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecAtomic::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 11 * nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecAtomic::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecAtomic::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecAtomic::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecAtomic::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecAtomic::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = x[i][0];
buf[i][3] = x[i][1];
buf[i][4] = x[i][2];
buf[i][5] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][6] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][7] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecAtomic::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4],
(int) ubuf(buf[i][5]).i,(int) ubuf(buf[i][6]).i,
(int) ubuf(buf[i][7]).i);
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecAtomic::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
return bytes;
}
diff --git a/src/atom_vec_atomic.h b/src/atom_vec_atomic.h
index 6c056ff69..3dd2cd38b 100644
--- a/src/atom_vec_atomic.h
+++ b/src/atom_vec_atomic.h
@@ -1,81 +1,82 @@
/* -*- 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 ATOM_CLASS
AtomStyle(atomic,AtomVecAtomic)
#else
#ifndef LMP_ATOM_VEC_ATOMIC_H
#define LMP_ATOM_VEC_ATOMIC_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecAtomic : public AtomVec {
public:
AtomVecAtomic(class LAMMPS *);
virtual ~AtomVecAtomic() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
virtual int pack_comm(int, int *, double *, int, int *);
virtual int pack_comm_vel(int, int *, double *, int, int *);
virtual void unpack_comm(int, int, double *);
virtual void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
virtual int pack_border(int, int *, double *, int, int *);
virtual int pack_border_vel(int, int *, double *, int, int *);
virtual void unpack_border(int, int, double *);
virtual void unpack_border_vel(int, int, double *);
virtual int pack_exchange(int, double *);
virtual int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
void pack_data(double **);
void write_data(FILE *, int, double **);
bigint memory_usage();
protected:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp
index b91ecdde9..429ac3913 100644
--- a/src/atom_vec_body.cpp
+++ b/src/atom_vec_body.cpp
@@ -1,1596 +1,1593 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "atom_vec_body.h"
#include "style_body.h"
#include "body.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
#define DELTA_BONUS 10000
/* ---------------------------------------------------------------------- */
AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
// size_forward and size_border set in settings(), via Body class
comm_x_only = comm_f_only = 0;
size_forward = 0;
size_reverse = 6;
size_border = 0;
size_velocity = 6;
size_data_atom = 7;
size_data_vel = 7;
xcol_data = 5;
atom->body_flag = 1;
atom->rmass_flag = 1;
atom->angmom_flag = atom->torque_flag = 1;
nlocal_bonus = nghost_bonus = nmax_bonus = 0;
bonus = NULL;
bptr = NULL;
nargcopy = 0;
argcopy = NULL;
copyflag = 1;
if (sizeof(double) == sizeof(int)) intdoubleratio = 1;
else if (sizeof(double) == 2*sizeof(int)) intdoubleratio = 2;
else error->all(FLERR,"Internal error in atom_style body");
}
/* ---------------------------------------------------------------------- */
AtomVecBody::~AtomVecBody()
{
int nall = nlocal_bonus + nghost_bonus;
for (int i = 0; i < nall; i++) {
icp->put(bonus[i].iindex);
dcp->put(bonus[i].dindex);
}
memory->sfree(bonus);
delete bptr;
for (int i = 0; i < nargcopy; i++) delete [] argcopy[i];
delete [] argcopy;
}
/* ----------------------------------------------------------------------
process additional args
instantiate Body class
set size_forward and size_border to max sizes
------------------------------------------------------------------------- */
void AtomVecBody::settings(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Invalid atom_style body command");
if (0) bptr = NULL;
#define BODY_CLASS
#define BodyStyle(key,Class) \
else if (strcmp(arg[0],#key) == 0) bptr = new Class(lmp,narg,arg);
#include "style_body.h"
#undef BodyStyle
#undef BODY_CLASS
else error->all(FLERR,"Invalid body style");
bptr->avec = this;
icp = bptr->icp;
dcp = bptr->dcp;
// max size of forward/border comm
// 7,16 are packed in pack_comm/pack_border
// bptr values = max number of additional ivalues/dvalues from Body class
size_forward = 7 + bptr->size_forward;
size_border = 16 + bptr->size_border;
// make copy of args if called externally, so can write to restart file
// make no copy of args if called from read_restart()
if (copyflag) {
nargcopy = narg;
argcopy = new char*[nargcopy];
for (int i = 0; i < nargcopy; i++) {
int n = strlen(arg[i]) + 1;
argcopy[i] = new char[n];
strcpy(argcopy[i],arg[i]);
}
}
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecBody::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom");
torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque");
body = memory->grow(atom->body,nmax,"atom:body");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecBody::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
rmass = atom->rmass; angmom = atom->angmom; torque = atom->torque;
body = atom->body;
}
/* ----------------------------------------------------------------------
grow bonus data structure
------------------------------------------------------------------------- */
void AtomVecBody::grow_bonus()
{
nmax_bonus += DELTA_BONUS;
if (nmax_bonus < 0 || nmax_bonus > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
bonus = (Bonus *) memory->srealloc(bonus,nmax_bonus*sizeof(Bonus),
"atom:bonus");
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
if delflag and atom J has bonus data, then delete it
------------------------------------------------------------------------- */
void AtomVecBody::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
rmass[j] = rmass[i];
angmom[j][0] = angmom[i][0];
angmom[j][1] = angmom[i][1];
angmom[j][2] = angmom[i][2];
// if deleting atom J via delflag and J has bonus data, then delete it
if (delflag && body[j] >= 0) {
icp->put(bonus[body[j]].iindex);
dcp->put(bonus[body[j]].dindex);
copy_bonus(nlocal_bonus-1,body[j]);
nlocal_bonus--;
}
// if atom I has bonus data, reset I's bonus.ilocal to loc J
// do NOT do this if self-copy (I=J) since I's bonus data is already deleted
if (body[i] >= 0 && i != j) bonus[body[i]].ilocal = j;
body[j] = body[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ----------------------------------------------------------------------
copy bonus data from I to J, effectively deleting the J entry
also reset body that points to I to now point to J
------------------------------------------------------------------------- */
void AtomVecBody::copy_bonus(int i, int j)
{
body[bonus[i].ilocal] = j;
memcpy(&bonus[j],&bonus[i],sizeof(Bonus));
}
/* ----------------------------------------------------------------------
clear ghost info in bonus data
called before ghosts are recommunicated in comm and irregular
------------------------------------------------------------------------- */
void AtomVecBody::clear_bonus()
{
int nall = nlocal_bonus + nghost_bonus;
for (int i = nlocal_bonus; i < nall; i++) {
icp->put(bonus[i].iindex);
dcp->put(bonus[i].dindex);
}
nghost_bonus = 0;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *quat;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (body[j] >= 0) {
quat = bonus[body[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]);
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (body[i] >= 0) {
quat = bonus[body[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]);
}
}
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (body[i] >= 0) {
quat = bonus[body[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]);
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++)
if (body[i] >= 0) {
quat = bonus[body[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]);
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_border(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (body[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[body[j]].quat;
inertia = bonus[body[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[body[j]].ninteger).d;
buf[m++] = ubuf(bonus[body[j]].ndouble).d;
m += bptr->pack_border_body(&bonus[body[j]],&buf[m]);
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::unpack_border(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
body[i] = (int) ubuf(buf[m++]).i;
if (body[i] == 0) body[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ninteger = (int) ubuf(buf[m++]).i;
bonus[j].ndouble = (int) ubuf(buf[m++]).i;
bonus[j].ivalue = icp->get(bonus[j].ninteger,bonus[j].iindex);
bonus[j].dvalue = dcp->get(bonus[j].ndouble,bonus[j].dindex);
m += bptr->unpack_border_body(&bonus[j],&buf[m]);
bonus[j].ilocal = i;
body[i] = j;
nghost_bonus++;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::unpack_border_vel(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
body[i] = (int) ubuf(buf[m++]).i;
if (body[i] == 0) body[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ninteger = (int) ubuf(buf[m++]).i;
bonus[j].ndouble = (int) ubuf(buf[m++]).i;
bonus[j].ivalue = icp->get(bonus[j].ninteger,bonus[j].iindex);
bonus[j].dvalue = dcp->get(bonus[j].ndouble,bonus[j].dindex);
m += bptr->unpack_border_body(&bonus[j],&buf[m]);
bonus[j].ilocal = i;
body[i] = j;
nghost_bonus++;
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::unpack_border_hybrid(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
body[i] = (int) ubuf(buf[m++]).i;
if (body[i] == 0) body[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ninteger = (int) ubuf(buf[m++]).i;
bonus[j].ndouble = (int) ubuf(buf[m++]).i;
bonus[j].ivalue = icp->get(bonus[j].ninteger,bonus[j].iindex);
bonus[j].dvalue = dcp->get(bonus[j].ndouble,bonus[j].dindex);
m += bptr->unpack_border_body(&bonus[j],&buf[m]);
bonus[j].ilocal = i;
body[i] = j;
nghost_bonus++;
}
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecBody::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (body[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = body[i];
double *quat = bonus[j].quat;
double *inertia = bonus[j].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[j].ninteger).d;
buf[m++] = ubuf(bonus[j].ndouble).d;
memcpy(&buf[m],bonus[j].ivalue,bonus[j].ninteger*sizeof(int));
if (intdoubleratio == 1) m += bonus[j].ninteger;
else m += (bonus[j].ninteger+1)/2;
memcpy(&buf[m],bonus[j].dvalue,bonus[j].ndouble*sizeof(double));
m += bonus[j].ndouble;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecBody::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
body[nlocal] = (int) ubuf(buf[m++]).i;
if (body[nlocal] == 0) body[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *quat = bonus[nlocal_bonus].quat;
double *inertia = bonus[nlocal_bonus].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[nlocal_bonus].ninteger = (int) ubuf(buf[m++]).i;
bonus[nlocal_bonus].ndouble = (int) ubuf(buf[m++]).i;
bonus[nlocal_bonus].ivalue = icp->get(bonus[nlocal_bonus].ninteger,
bonus[nlocal_bonus].iindex);
bonus[nlocal_bonus].dvalue = dcp->get(bonus[nlocal_bonus].ndouble,
bonus[nlocal_bonus].dindex);
memcpy(bonus[nlocal_bonus].ivalue,&buf[m],
bonus[nlocal_bonus].ninteger*sizeof(int));
if (intdoubleratio == 1) m += bonus[nlocal_bonus].ninteger;
else m += (bonus[nlocal_bonus].ninteger+1)/2;
memcpy(bonus[nlocal_bonus].dvalue,&buf[m],
bonus[nlocal_bonus].ndouble*sizeof(double));
m += bonus[nlocal_bonus].ndouble;
bonus[nlocal_bonus].ilocal = nlocal;
body[nlocal] = nlocal_bonus++;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecBody::size_restart()
{
int i;
int n = 0;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
if (body[i] >= 0) {
n += 25;
if (intdoubleratio == 1) n += bonus[body[i]].ninteger;
else n += (bonus[body[i]].ninteger+1)/2;
n += bonus[body[i]].ndouble;
} else n += 16;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecBody::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (body[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = body[i];
double *quat = bonus[j].quat;
double *inertia = bonus[j].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
buf[m++] = ubuf(bonus[j].ninteger).d;
buf[m++] = ubuf(bonus[j].ndouble).d;
memcpy(&buf[m],bonus[j].ivalue,bonus[j].ninteger*sizeof(int));
if (intdoubleratio == 1) m += bonus[j].ninteger;
else m += (bonus[j].ninteger+1)/2;
memcpy(&buf[m],bonus[j].dvalue,bonus[j].ndouble*sizeof(double));
m += bonus[j].ndouble;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecBody::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
body[nlocal] = (int) ubuf(buf[m++]).i;
if (body[nlocal] == 0) body[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *quat = bonus[nlocal_bonus].quat;
double *inertia = bonus[nlocal_bonus].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[nlocal_bonus].ninteger = (int) ubuf(buf[m++]).i;
bonus[nlocal_bonus].ndouble = (int) ubuf(buf[m++]).i;
bonus[nlocal_bonus].ivalue = icp->get(bonus[nlocal_bonus].ninteger,
bonus[nlocal_bonus].iindex);
bonus[nlocal_bonus].dvalue = dcp->get(bonus[nlocal_bonus].ndouble,
bonus[nlocal_bonus].dindex);
memcpy(bonus[nlocal_bonus].ivalue,&buf[m],
bonus[nlocal_bonus].ninteger*sizeof(int));
if (intdoubleratio == 1) m += bonus[nlocal_bonus].ninteger;
else m += (bonus[nlocal_bonus].ninteger+1)/2;
memcpy(bonus[nlocal_bonus].dvalue,&buf[m],
bonus[nlocal_bonus].ndouble*sizeof(double));
m += bonus[nlocal_bonus].ndouble;
bonus[nlocal_bonus].ilocal = nlocal;
body[nlocal] = nlocal_bonus++;
}
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::write_restart_settings(FILE *fp)
{
fwrite(&nargcopy,sizeof(int),1,fp);
for (int i = 0; i < nargcopy; i++) {
int n = strlen(argcopy[i]) + 1;
fwrite(&n,sizeof(int),1,fp);
fwrite(argcopy[i],sizeof(char),n,fp);
}
}
/* ---------------------------------------------------------------------- */
void AtomVecBody::read_restart_settings(FILE *fp)
{
int n;
int me = comm->me;
if (me == 0) fread(&nargcopy,sizeof(int),1,fp);
MPI_Bcast(&nargcopy,1,MPI_INT,0,world);
argcopy = new char*[nargcopy];
for (int i = 0; i < nargcopy; i++) {
if (me == 0) fread(&n,sizeof(int),1,fp);
MPI_Bcast(&n,1,MPI_INT,0,world);
argcopy[i] = new char[n];
if (me == 0) fread(argcopy[i],sizeof(char),n,fp);
MPI_Bcast(argcopy[i],n,MPI_CHAR,0,world);
}
copyflag = 0;
settings(nargcopy,argcopy);
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecBody::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
rmass[nlocal] = 1.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
body[nlocal] = -1;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecBody::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
body[nlocal] = atoi(values[2]);
if (body[nlocal] == 0) body[nlocal] = -1;
else if (body[nlocal] == 1) body[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[3]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecBody::data_atom_hybrid(int nlocal, char **values)
{
body[nlocal] = atoi(values[0]);
if (body[nlocal] == 0) body[nlocal] = -1;
else if (body[nlocal] == 1) body[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[1]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
return 2;
}
/* ----------------------------------------------------------------------
unpack one body from Bodies section of data file
------------------------------------------------------------------------- */
void AtomVecBody::data_body(int m, int ninteger, int ndouble,
char **ivalues, char **dvalues)
{
if (body[m]) error->one(FLERR,"Assigning body parameters to non-body atom");
if (nlocal_bonus == nmax_bonus) grow_bonus();
bptr->data_body(nlocal_bonus,ninteger,ndouble,ivalues,dvalues);
bonus[nlocal_bonus].ilocal = m;
body[m] = nlocal_bonus++;
}
/* ----------------------------------------------------------------------
unpack one tri from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecBody::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
angmom[m][0] = atof(values[3]);
angmom[m][1] = atof(values[4]);
angmom[m][2] = atof(values[5]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one body in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecBody::data_vel_hybrid(int m, char **values)
{
angmom[m][0] = atof(values[0]);
angmom[m][1] = atof(values[1]);
angmom[m][2] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecBody::pack_data(double **buf)
{
double c2mc1[2],c3mc1[3],norm[3];
double area;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
if (body[i] < 0) buf[i][2] = ubuf(0).d;
else buf[i][2] = ubuf(1).d;
buf[i][3] = rmass[i];
buf[i][4] = x[i][0];
buf[i][5] = x[i][1];
buf[i][6] = x[i][2];
buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecBody::pack_data_hybrid(int i, double *buf)
{
if (body[i] < 0) buf[0] = ubuf(0).d;
else buf[0] = ubuf(1).d;
buf[1] = rmass[i];
return 2;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecBody::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %g %g %g %g %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %d %g %g %g %g %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],buf[i][6],
(int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,
(int) ubuf(buf[i][9]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecBody::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d %g",(int) ubuf(buf[0]).i,buf[1]);
return 2;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecBody::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = angmom[i][0];
buf[i][5] = angmom[i][1];
buf[i][6] = angmom[i][2];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecBody::pack_vel_hybrid(int i, double *buf)
{
buf[0] = angmom[i][0];
buf[1] = angmom[i][1];
buf[2] = angmom[i][2];
return 3;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecBody::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %g %g %g %g %g %g\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
+ fprintf(fp,TAGINT_FORMAT " %g %g %g %g %g %g\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecBody::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %g %g %g",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecBody::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3);
if (atom->memcheck("torque")) bytes +=
memory->usage(torque,nmax*comm->nthreads,3);
if (atom->memcheck("body")) bytes += memory->usage(body,nmax);
bytes += nmax_bonus*sizeof(Bonus);
bytes += icp->size + dcp->size;
int nall = nlocal_bonus + nghost_bonus;
for (int i = 0; i < nall; i++) {
bytes += bonus[i].ninteger * sizeof(int);
bytes += bonus[i].ndouble * sizeof(double);
}
return bytes;
}
/* ----------------------------------------------------------------------
debug method for sanity checking of own/bonus data pointers
------------------------------------------------------------------------- */
/*
void AtomVecBody::check(int flag)
{
for (int i = 0; i < atom->nlocal; i++) {
if (atom->body[i] >= 0 && atom->body[i] >= nlocal_bonus) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD AAA");
}
}
for (int i = atom->nlocal; i < atom->nlocal+atom->nghost; i++) {
if (atom->body[i] >= 0 &&
(atom->body[i] < nlocal_bonus ||
atom->body[i] >= nlocal_bonus+nghost_bonus)) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD BBB");
}
}
for (int i = 0; i < nlocal_bonus; i++) {
if (bonus[i].ilocal < 0 || bonus[i].ilocal >= atom->nlocal) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD CCC");
}
}
for (int i = 0; i < nlocal_bonus; i++) {
if (atom->body[bonus[i].ilocal] != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD DDD");
}
}
for (int i = nlocal_bonus; i < nlocal_bonus+nghost_bonus; i++) {
if (bonus[i].ilocal < atom->nlocal ||
bonus[i].ilocal >= atom->nlocal+atom->nghost) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD EEE");
}
}
for (int i = nlocal_bonus; i < nlocal_bonus+nghost_bonus; i++) {
if (atom->body[bonus[i].ilocal] != i) {
printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag);
errorx->one(FLERR,"BAD FFF");
}
}
}
*/
diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h
index aad592fe4..c16be4e2c 100644
--- a/src/atom_vec_body.h
+++ b/src/atom_vec_body.h
@@ -1,155 +1,156 @@
/* ----------------------------------------------------------------------
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 ATOM_CLASS
AtomStyle(body,AtomVecBody)
#else
#ifndef LMP_ATOM_VEC_BODY_H
#define LMP_ATOM_VEC_BODY_H
#include "atom_vec.h"
#include "my_pool_chunk.h"
namespace LAMMPS_NS {
class AtomVecBody : public AtomVec {
public:
class Body *bptr;
struct Bonus {
double quat[4];
double inertia[3];
int ninteger,ndouble;
int iindex,dindex;
int *ivalue;
double *dvalue;
int ilocal;
};
struct Bonus *bonus;
AtomVecBody(class LAMMPS *);
~AtomVecBody();
void settings(int, char **);
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void write_restart_settings(FILE *);
void read_restart_settings(FILE *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
// manipulate Bonus data structure for extra atom info
void clear_bonus();
void data_body(int, int, int, char **, char **);
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *rmass;
double **angmom,**torque;
int *body;
int nlocal_bonus,nghost_bonus,nmax_bonus;
int nargcopy; // copy of command-line args
char **argcopy; // for writing to restart file
int copyflag;
int intdoubleratio; // sizeof(double) / sizeof(int)
MyPoolChunk<int> *icp;
MyPoolChunk<double> *dcp;
void grow_bonus();
void copy_bonus(int, int);
//void check(int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Internal error in atom_style body
This error should not occur. Contact the developers.
E: Invalid atom_style body command
No body style argument was provided.
E: Invalid body style
The choice of body style is unknown.
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid density in Atoms section of data file
Density value cannot be <= 0.0.
E: Assigning body parameters to non-body atom
Self-explanatory.
*/
diff --git a/src/atom_vec_charge.cpp b/src/atom_vec_charge.cpp
index 38b4385c9..d8b4b7430 100644
--- a/src/atom_vec_charge.cpp
+++ b/src/atom_vec_charge.cpp
@@ -1,776 +1,773 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_charge.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecCharge::AtomVecCharge(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
mass_type = 1;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 7;
size_velocity = 3;
size_data_atom = 6;
size_data_vel = 4;
xcol_data = 4;
atom->q_flag = 1;
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecCharge::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
q = memory->grow(atom->q,nmax,"atom:q");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecCharge::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
q = atom->q;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecCharge::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
q[j] = q[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecCharge::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecCharge::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecCharge::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = q[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecCharge::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecCharge::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
q[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
q[i] = buf[m++];
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecCharge::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = q[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecCharge::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
q[nlocal] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecCharge::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 12 * nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecCharge::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = q[i];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecCharge::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
q[nlocal] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecCharge::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
q[nlocal] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecCharge::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
q[nlocal] = atof(values[2]);
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecCharge::data_atom_hybrid(int nlocal, char **values)
{
q[nlocal] = atof(values[0]);
return 1;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecCharge::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = q[i];
buf[i][3] = x[i][0];
buf[i][4] = x[i][1];
buf[i][5] = x[i][2];
buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecCharge::pack_data_hybrid(int i, double *buf)
{
buf[0] = q[i];
return 1;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecCharge::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4],buf[i][5],
(int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i,
(int) ubuf(buf[i][8]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecCharge::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e",buf[0]);
return 1;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecCharge::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("q")) bytes += memory->usage(q,nmax);
return bytes;
}
diff --git a/src/atom_vec_charge.h b/src/atom_vec_charge.h
index 2f0e48e2d..9c634eba3 100644
--- a/src/atom_vec_charge.h
+++ b/src/atom_vec_charge.h
@@ -1,87 +1,88 @@
/* -*- 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 ATOM_CLASS
AtomStyle(charge,AtomVecCharge)
#else
#ifndef LMP_ATOM_VEC_CHARGE_H
#define LMP_ATOM_VEC_CHARGE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecCharge : public AtomVec {
public:
AtomVecCharge(class LAMMPS *);
virtual ~AtomVecCharge() {}
void grow(int);
void grow_reset();
void copy(int, int, int);
virtual int pack_comm(int, int *, double *, int, int *);
virtual int pack_comm_vel(int, int *, double *, int, int *);
virtual void unpack_comm(int, int, double *);
virtual void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
virtual int pack_border(int, int *, double *, int, int *);
virtual int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
virtual void unpack_border(int, int, double *);
virtual void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
virtual int pack_exchange(int, double *);
virtual int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
bigint memory_usage();
protected:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *q;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp
index 2eda8b0e6..512f3ba74 100644
--- a/src/atom_vec_ellipsoid.cpp
+++ b/src/atom_vec_ellipsoid.cpp
@@ -1,1405 +1,1404 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "atom_vec_ellipsoid.h"
#include "math_extra.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 10000
#define DELTA_BONUS 10000
/* ---------------------------------------------------------------------- */
AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
comm_x_only = comm_f_only = 0;
size_forward = 7;
size_reverse = 6;
size_border = 14;
size_velocity = 6;
size_data_atom = 7;
size_data_vel = 7;
size_data_bonus = 8;
xcol_data = 5;
atom->ellipsoid_flag = 1;
atom->rmass_flag = atom->angmom_flag = atom->torque_flag = 1;
nlocal_bonus = nghost_bonus = nmax_bonus = 0;
bonus = NULL;
}
/* ---------------------------------------------------------------------- */
AtomVecEllipsoid::~AtomVecEllipsoid()
{
memory->sfree(bonus);
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecEllipsoid::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom");
torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque");
ellipsoid = memory->grow(atom->ellipsoid,nmax,"atom:ellipsoid");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecEllipsoid::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
rmass = atom->rmass; angmom = atom->angmom; torque = atom->torque;
ellipsoid = atom->ellipsoid;
}
/* ----------------------------------------------------------------------
grow bonus data structure
------------------------------------------------------------------------- */
void AtomVecEllipsoid::grow_bonus()
{
nmax_bonus += DELTA_BONUS;
if (nmax_bonus < 0 || nmax_bonus > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
bonus = (Bonus *) memory->srealloc(bonus,nmax_bonus*sizeof(Bonus),
"atom:bonus");
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecEllipsoid::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
rmass[j] = rmass[i];
angmom[j][0] = angmom[i][0];
angmom[j][1] = angmom[i][1];
angmom[j][2] = angmom[i][2];
// if deleting atom J via delflag and J has bonus data, then delete it
if (delflag && ellipsoid[j] >= 0) {
copy_bonus(nlocal_bonus-1,ellipsoid[j]);
nlocal_bonus--;
}
// if atom I has bonus data, reset I's bonus.ilocal to loc J
// do NOT do this if self-copy (I=J) since I's bonus data is already deleted
if (ellipsoid[i] >= 0 && i != j) bonus[ellipsoid[i]].ilocal = j;
ellipsoid[j] = ellipsoid[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ----------------------------------------------------------------------
copy bonus data from I to J, effectively deleting the J entry
also reset ellipsoid that points to I to now point to J
------------------------------------------------------------------------- */
void AtomVecEllipsoid::copy_bonus(int i, int j)
{
ellipsoid[bonus[i].ilocal] = j;
memcpy(&bonus[j],&bonus[i],sizeof(Bonus));
}
/* ----------------------------------------------------------------------
clear ghost info in bonus data
called before ghosts are recommunicated in comm and irregular
------------------------------------------------------------------------- */
void AtomVecEllipsoid::clear_bonus()
{
nghost_bonus = 0;
}
/* ----------------------------------------------------------------------
set shape values in bonus data for particle I
oriented aligned with xyz axes
this may create or delete entry in bonus data
------------------------------------------------------------------------- */
void AtomVecEllipsoid::set_shape(int i,
double shapex, double shapey, double shapez)
{
if (ellipsoid[i] < 0) {
if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) return;
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *shape = bonus[nlocal_bonus].shape;
double *quat = bonus[nlocal_bonus].quat;
shape[0] = shapex;
shape[1] = shapey;
shape[2] = shapez;
quat[0] = 1.0;
quat[1] = 0.0;
quat[2] = 0.0;
quat[3] = 0.0;
bonus[nlocal_bonus].ilocal = i;
ellipsoid[i] = nlocal_bonus++;
} else if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) {
copy_bonus(nlocal_bonus-1,ellipsoid[i]);
nlocal_bonus--;
ellipsoid[i] = -1;
} else {
double *shape = bonus[ellipsoid[i]].shape;
shape[0] = shapex;
shape[1] = shapey;
shape[2] = shapez;
}
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *quat;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (ellipsoid[j] >= 0) {
quat = bonus[ellipsoid[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecEllipsoid::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (ellipsoid[i] >= 0) {
quat = bonus[ellipsoid[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
void AtomVecEllipsoid::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (ellipsoid[i] >= 0) {
quat = bonus[ellipsoid[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (ellipsoid[i] >= 0) {
quat = bonus[ellipsoid[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecEllipsoid::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_border(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *shape,*quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *shape,*quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *shape,*quat;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
shape = bonus[ellipsoid[j]].shape;
quat = bonus[ellipsoid[j]].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecEllipsoid::unpack_border(int n, int first, double *buf)
{
int i,j,m,last;
double *shape,*quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
ellipsoid[i] = (int) ubuf(buf[m++]).i;
if (ellipsoid[i] == 0) ellipsoid[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
shape = bonus[j].shape;
quat = bonus[j].quat;
shape[0] = buf[m++];
shape[1] = buf[m++];
shape[2] = buf[m++];
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
bonus[j].ilocal = i;
ellipsoid[i] = j;
nghost_bonus++;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecEllipsoid::unpack_border_vel(int n, int first, double *buf)
{
int i,j,m,last;
double *shape,*quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
ellipsoid[i] = (int) ubuf(buf[m++]).i;
if (ellipsoid[i] == 0) ellipsoid[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
shape = bonus[j].shape;
quat = bonus[j].quat;
shape[0] = buf[m++];
shape[1] = buf[m++];
shape[2] = buf[m++];
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
bonus[j].ilocal = i;
ellipsoid[i] = j;
nghost_bonus++;
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::unpack_border_hybrid(int n, int first, double *buf)
{
int i,j,m,last;
double *shape,*quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
ellipsoid[i] = (int) ubuf(buf[m++]).i;
if (ellipsoid[i] == 0) ellipsoid[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
shape = bonus[j].shape;
quat = bonus[j].quat;
shape[0] = buf[m++];
shape[1] = buf[m++];
shape[2] = buf[m++];
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
bonus[j].ilocal = i;
ellipsoid[i] = j;
nghost_bonus++;
}
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = ellipsoid[i];
double *shape = bonus[j].shape;
double *quat = bonus[j].quat;
buf[m++] = shape[0];
buf[m++] = shape[1];
buf[m++] = shape[2];
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecEllipsoid::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
ellipsoid[nlocal] = (int) ubuf(buf[m++]).i;
if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *shape = bonus[nlocal_bonus].shape;
double *quat = bonus[nlocal_bonus].quat;
shape[0] = buf[m++];
shape[1] = buf[m++];
shape[2] = buf[m++];
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
ellipsoid[nlocal] = nlocal_bonus++;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecEllipsoid::size_restart()
{
int i;
int n = 0;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
if (ellipsoid[i] >= 0) n += 23;
else n += 16;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including bonus data
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = ellipsoid[i];
buf[m++] = bonus[j].shape[0];
buf[m++] = bonus[j].shape[1];
buf[m++] = bonus[j].shape[2];
buf[m++] = bonus[j].quat[0];
buf[m++] = bonus[j].quat[1];
buf[m++] = bonus[j].quat[2];
buf[m++] = bonus[j].quat[3];
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including bonus data
------------------------------------------------------------------------- */
int AtomVecEllipsoid::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
ellipsoid[nlocal] = (int) ubuf(buf[m++]).i;
if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *shape = bonus[nlocal_bonus].shape;
double *quat = bonus[nlocal_bonus].quat;
shape[0] = buf[m++];
shape[1] = buf[m++];
shape[2] = buf[m++];
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
ellipsoid[nlocal] = nlocal_bonus++;
}
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecEllipsoid::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
rmass[nlocal] = 1.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
ellipsoid[nlocal] = -1;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecEllipsoid::data_atom(double *coord, imageint imagetmp,
char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
ellipsoid[nlocal] = atoi(values[2]);
if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1;
else if (ellipsoid[nlocal] == 1) ellipsoid[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[3]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecEllipsoid::data_atom_hybrid(int nlocal, char **values)
{
ellipsoid[nlocal] = atoi(values[0]);
if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1;
else if (ellipsoid[nlocal] == 1) ellipsoid[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[1]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
return 2;
}
/* ----------------------------------------------------------------------
unpack one line from Ellipsoids section of data file
------------------------------------------------------------------------- */
void AtomVecEllipsoid::data_atom_bonus(int m, char **values)
{
if (ellipsoid[m])
error->one(FLERR,"Assigning ellipsoid parameters to non-ellipsoid atom");
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *shape = bonus[nlocal_bonus].shape;
shape[0] = 0.5 * atof(values[0]);
shape[1] = 0.5 * atof(values[1]);
shape[2] = 0.5 * atof(values[2]);
if (shape[0] <= 0.0 || shape[1] <= 0.0 || shape[2] <= 0.0)
error->one(FLERR,"Invalid shape in Ellipsoids section of data file");
double *quat = bonus[nlocal_bonus].quat;
quat[0] = atof(values[3]);
quat[1] = atof(values[4]);
quat[2] = atof(values[5]);
quat[3] = atof(values[6]);
MathExtra::qnormalize(quat);
// reset ellipsoid mass
// previously stored density in rmass
rmass[m] *= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2];
bonus[nlocal_bonus].ilocal = m;
ellipsoid[m] = nlocal_bonus++;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecEllipsoid::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
angmom[m][0] = atof(values[3]);
angmom[m][1] = atof(values[4]);
angmom[m][2] = atof(values[5]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecEllipsoid::data_vel_hybrid(int m, char **values)
{
angmom[m][0] = atof(values[0]);
angmom[m][1] = atof(values[1]);
angmom[m][2] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecEllipsoid::pack_data(double **buf)
{
double *shape;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
if (ellipsoid[i] < 0) buf[i][2] = ubuf(0).d;
else buf[i][2] = ubuf(1).d;
if (ellipsoid[i] < 0) buf[i][3] = rmass[i];
else {
shape = bonus[ellipsoid[i]].shape;
buf[i][3] = rmass[i] / (4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]);
}
buf[i][4] = x[i][0];
buf[i][5] = x[i][1];
buf[i][6] = x[i][2];
buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_data_hybrid(int i, double *buf)
{
if (ellipsoid[i] < 0) buf[0] = ubuf(0).d;
else buf[0] = ubuf(1).d;
if (ellipsoid[i] < 0) buf[1] = rmass[i];
else {
double *shape = bonus[ellipsoid[i]].shape;
buf[1] = rmass[i] / (4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]);
}
return 2;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecEllipsoid::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,
buf[i][3],buf[i][4],buf[i][5],buf[i][6],
(int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,
(int) ubuf(buf[i][9]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecEllipsoid::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d %-1.16e",(int) ubuf(buf[0]).i,buf[1]);
return 2;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecEllipsoid::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = angmom[i][0];
buf[i][5] = angmom[i][1];
buf[i][6] = angmom[i][2];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecEllipsoid::pack_vel_hybrid(int i, double *buf)
{
buf[0] = angmom[i][0];
buf[1] = angmom[i][1];
buf[2] = angmom[i][2];
return 3;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecEllipsoid::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
+ fprintf(fp,TAGINT_FORMAT
+ " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecEllipsoid::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecEllipsoid::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3);
if (atom->memcheck("torque"))
bytes += memory->usage(torque,nmax*comm->nthreads,3);
if (atom->memcheck("ellipsoid")) bytes += memory->usage(ellipsoid,nmax);
bytes += nmax_bonus*sizeof(Bonus);
return bytes;
}
diff --git a/src/atom_vec_ellipsoid.h b/src/atom_vec_ellipsoid.h
index 077ae6687..306b9eca1 100644
--- a/src/atom_vec_ellipsoid.h
+++ b/src/atom_vec_ellipsoid.h
@@ -1,132 +1,133 @@
/* -*- 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 ATOM_CLASS
AtomStyle(ellipsoid,AtomVecEllipsoid)
#else
#ifndef LMP_ATOM_VEC_ELLIPSOID_H
#define LMP_ATOM_VEC_ELLIPSOID_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecEllipsoid : public AtomVec {
public:
struct Bonus {
double shape[3];
double quat[4];
int ilocal;
};
struct Bonus *bonus;
AtomVecEllipsoid(class LAMMPS *);
~AtomVecEllipsoid();
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
// manipulate Bonus data structure for extra atom info
void clear_bonus();
void data_atom_bonus(int, char **);
// unique to AtomVecEllipsoid
void set_shape(int, double, double, double);
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *rmass;
double **angmom,**torque;
int *ellipsoid;
int nlocal_bonus,nghost_bonus,nmax_bonus;
void grow_bonus();
void copy_bonus(int, int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid density in Atoms section of data file
Density value cannot be <= 0.0.
E: Assigning ellipsoid parameters to non-ellipsoid atom
Self-explanatory.
E: Invalid shape in Ellipsoids section of data file
Self-explanatory.
*/
diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp
index 710d15e2b..d88f67a85 100644
--- a/src/atom_vec_hybrid.cpp
+++ b/src/atom_vec_hybrid.cpp
@@ -1,1060 +1,1057 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "atom_vec_hybrid.h"
#include "atom.h"
#include "domain.h"
#include "modify.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) {}
/* ---------------------------------------------------------------------- */
AtomVecHybrid::~AtomVecHybrid()
{
for (int k = 0; k < nstyles; k++) delete styles[k];
delete [] styles;
for (int k = 0; k < nstyles; k++) delete [] keywords[k];
delete [] keywords;
}
/* ----------------------------------------------------------------------
process sub-style args
------------------------------------------------------------------------- */
void AtomVecHybrid::settings(int narg, char **arg)
{
// build list of all known atom styles
build_styles();
// allocate list of sub-styles as big as possibly needed if no extra args
styles = new AtomVec*[narg];
keywords = new char*[narg];
// allocate each sub-style
// call settings() with set of args that are not atom style names
// use known_style() to determine which args these are
int i,jarg,dummy;
int iarg = 0;
nstyles = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"hybrid") == 0)
error->all(FLERR,"Atom style hybrid cannot have hybrid as an argument");
for (i = 0; i < nstyles; i++)
if (strcmp(arg[iarg],keywords[i]) == 0)
error->all(FLERR,"Atom style hybrid cannot use same atom style twice");
styles[nstyles] = atom->new_avec(arg[iarg],NULL,dummy);
keywords[nstyles] = new char[strlen(arg[iarg])+1];
strcpy(keywords[nstyles],arg[iarg]);
jarg = iarg + 1;
while (jarg < narg && !known_style(arg[jarg])) jarg++;
styles[nstyles]->settings(jarg-iarg-1,&arg[iarg+1]);
iarg = jarg;
nstyles++;
}
// free allstyles created by build_styles()
for (int i = 0; i < nallstyles; i++) delete [] allstyles[i];
delete [] allstyles;
// hybrid settings are MAX or MIN of sub-style settings
// hybrid sizes are minimial values plus extra values for each sub-style
molecular = 0;
comm_x_only = comm_f_only = 1;
size_forward = 3;
size_reverse = 3;
size_border = 6;
size_data_atom = 5;
size_data_vel = 4;
xcol_data = 3;
for (int k = 0; k < nstyles; k++) {
molecular = MAX(molecular,styles[k]->molecular);
bonds_allow = MAX(bonds_allow,styles[k]->bonds_allow);
angles_allow = MAX(angles_allow,styles[k]->angles_allow);
dihedrals_allow = MAX(dihedrals_allow,styles[k]->dihedrals_allow);
impropers_allow = MAX(impropers_allow,styles[k]->impropers_allow);
mass_type = MAX(mass_type,styles[k]->mass_type);
dipole_type = MAX(dipole_type,styles[k]->dipole_type);
comm_x_only = MIN(comm_x_only,styles[k]->comm_x_only);
comm_f_only = MIN(comm_f_only,styles[k]->comm_f_only);
size_forward += styles[k]->size_forward - 3;
size_reverse += styles[k]->size_reverse - 3;
size_border += styles[k]->size_border - 6;
size_data_atom += styles[k]->size_data_atom - 5;
size_data_vel += styles[k]->size_data_vel - 4;
}
size_velocity = 3;
if (atom->omega_flag) size_velocity += 3;
if (atom->angmom_flag) size_velocity += 3;
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::init()
{
AtomVec::init();
for (int k = 0; k < nstyles; k++) styles[k]->init();
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecHybrid::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
// sub-styles perform all reallocation
// turn off nextra_grow so hybrid can do that once below
int tmp = atom->nextra_grow;
atom->nextra_grow = 0;
for (int k = 0; k < nstyles; k++) styles[k]->grow(nmax);
atom->nextra_grow = tmp;
// insure hybrid local ptrs and sub-style ptrs are up to date
// for sub-styles, do this in case
// multiple sub-style reallocs of same array occurred
grow_reset();
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecHybrid::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
omega = atom->omega; angmom = atom->angmom;
for (int k = 0; k < nstyles; k++) styles[k]->grow_reset();
}
/* ----------------------------------------------------------------------
copy atom I info to atom J for all sub-styles
------------------------------------------------------------------------- */
void AtomVecHybrid::copy(int i, int j, int delflag)
{
int tmp = atom->nextra_grow;
atom->nextra_grow = 0;
for (int k = 0; k < nstyles; k++) styles[k]->copy(i,j,delflag);
atom->nextra_grow = tmp;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::clear_bonus()
{
for (int k = 0; k < nstyles; k++) styles[k]->clear_bonus();
}
/* ---------------------------------------------------------------------- */
int AtomVecHybrid::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,k,m;
double dx,dy,dz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
// pack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_comm_hybrid(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecHybrid::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,k,m;
double dx,dy,dz,dvx,dvy,dvz;
int omega_flag = atom->omega_flag;
int angmom_flag = atom->angmom_flag;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
}
// pack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_comm_hybrid(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::unpack_comm(int n, int first, double *buf)
{
int i,k,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
// unpack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->unpack_comm_hybrid(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::unpack_comm_vel(int n, int first, double *buf)
{
int i,k,m,last;
int omega_flag = atom->omega_flag;
int angmom_flag = atom->angmom_flag;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
if (omega_flag) {
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
if (angmom_flag) {
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
}
// unpack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->unpack_comm_hybrid(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecHybrid::pack_reverse(int n, int first, double *buf)
{
int i,k,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
}
// pack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_reverse_hybrid(n,first,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::unpack_reverse(int n, int *list, double *buf)
{
int i,j,k,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
}
// unpack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->unpack_reverse_hybrid(n,list,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecHybrid::pack_border(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,k,m;
double dx,dy,dz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
}
}
// pack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_border_hybrid(n,list,&buf[m]);
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecHybrid::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,k,m;
double dx,dy,dz,dvx,dvy,dvz;
int omega_flag = atom->omega_flag;
int angmom_flag = atom->angmom_flag;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
if (omega_flag) {
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
if (angmom_flag) {
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
}
// pack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_border_hybrid(n,list,&buf[m]);
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::unpack_border(int n, int first, double *buf)
{
int i,k,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
}
// unpack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->unpack_border_hybrid(n,first,&buf[m]);
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::unpack_border_vel(int n, int first, double *buf)
{
int i,k,m,last;
int omega_flag = atom->omega_flag;
int angmom_flag = atom->angmom_flag;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
if (omega_flag) {
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
if (angmom_flag) {
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
}
// unpack sub-style contributions as contiguous chunks
for (k = 0; k < nstyles; k++)
m += styles[k]->unpack_border_hybrid(n,first,&buf[m]);
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
pack each sub-style one after the other
------------------------------------------------------------------------- */
int AtomVecHybrid::pack_exchange(int i, double *buf)
{
int k,m;
int tmp = atom->nextra_grow;
atom->nextra_grow = 0;
m = 0;
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_exchange(i,&buf[m]);
atom->nextra_grow = tmp;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for single atom received from another proc
unpack each sub-style one after the other
grow() occurs here so arrays for all sub-styles are grown
------------------------------------------------------------------------- */
int AtomVecHybrid::unpack_exchange(double *buf)
{
int k,m;
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int tmp = atom->nextra_grow;
atom->nextra_grow = 0;
m = 0;
for (k = 0; k < nstyles; k++) {
m += styles[k]->unpack_exchange(&buf[m]);
atom->nlocal--;
}
atom->nextra_grow = tmp;
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecHybrid::size_restart()
{
int tmp = atom->nextra_restart;
atom->nextra_restart = 0;
int n = 0;
for (int k = 0; k < nstyles; k++)
n += styles[k]->size_restart();
atom->nextra_restart = tmp;
int nlocal = atom->nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (int i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
pack each sub-style one after the other
------------------------------------------------------------------------- */
int AtomVecHybrid::pack_restart(int i, double *buf)
{
int tmp = atom->nextra_restart;
atom->nextra_restart = 0;
int m = 0;
for (int k = 0; k < nstyles; k++)
m += styles[k]->pack_restart(i,&buf[m]);
atom->nextra_restart = tmp;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
unpack each sub-style one after the other
grow() occurs here so arrays for all sub-styles are grown
------------------------------------------------------------------------- */
int AtomVecHybrid::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int tmp = atom->nextra_store;
atom->nextra_store = 0;
int m = 0;
for (int k = 0; k < nstyles; k++) {
m += styles[k]->unpack_restart(&buf[m]);
atom->nlocal--;
}
atom->nextra_store = tmp;
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::write_restart_settings(FILE *fp)
{
for (int k = 0; k < nstyles; k++)
styles[k]->write_restart_settings(fp);
}
/* ---------------------------------------------------------------------- */
void AtomVecHybrid::read_restart_settings(FILE *fp)
{
for (int k = 0; k < nstyles; k++)
styles[k]->read_restart_settings(fp);
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
create each sub-style one after the other
grow() occurs here so arrays for all sub-styles are grown
------------------------------------------------------------------------- */
void AtomVecHybrid::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
for (int k = 0; k < nstyles; k++) {
styles[k]->create_atom(itype,coord);
atom->nlocal--;
}
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
grow() occurs here so arrays for all sub-styles are grown
------------------------------------------------------------------------- */
void AtomVecHybrid::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
if (atom->omega_flag) {
omega[nlocal][0] = 0.0;
omega[nlocal][1] = 0.0;
omega[nlocal][2] = 0.0;
}
if (atom->angmom_flag) {
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
}
// each sub-style parses sub-style specific values
int m = 5;
for (int k = 0; k < nstyles; k++)
m += styles[k]->data_atom_hybrid(nlocal,&values[m]);
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecHybrid::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
// each sub-style parses sub-style specific values
int n = 3;
for (int k = 0; k < nstyles; k++)
n += styles[k]->data_vel_hybrid(m,&values[n]);
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecHybrid::pack_data(double **buf)
{
int k,m;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = x[i][0];
buf[i][3] = x[i][1];
buf[i][4] = x[i][2];
m = 5;
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_data_hybrid(i,&buf[i][m]);
buf[i][m] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][m+1] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][m+2] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecHybrid::write_data(FILE *fp, int n, double **buf)
{
int k,m;
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],buf[i][4]);
m = 5;
for (k = 0; k < nstyles; k++)
m += styles[k]->write_data_hybrid(fp,&buf[i][m]);
fprintf(fp," %d %d %d\n",
(int) ubuf(buf[i][m]).i,(int) ubuf(buf[i][m+1]).i,
(int) ubuf(buf[i][m+2]).i);
}
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecHybrid::pack_vel(double **buf)
{
int k,m;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
m = 4;
for (k = 0; k < nstyles; k++)
m += styles[k]->pack_vel_hybrid(i,&buf[i][m]);
}
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecHybrid::write_vel(FILE *fp, int n, double **buf)
{
int k,m;
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d %g %g %g",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]);
+ fprintf(fp,TAGINT_FORMAT " %g %g %g",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]);
m = 4;
for (k = 0; k < nstyles; k++)
m += styles[k]->write_vel_hybrid(fp,&buf[i][m]);
fprintf(fp,"\n");
}
}
/* ----------------------------------------------------------------------
allstyles = list of all atom styles in this LAMMPS executable
------------------------------------------------------------------------- */
void AtomVecHybrid::build_styles()
{
nallstyles = 0;
#define ATOM_CLASS
#define AtomStyle(key,Class) nallstyles++;
#include "style_atom.h"
#undef AtomStyle
#undef ATOM_CLASS
allstyles = new char*[nallstyles];
int n;
nallstyles = 0;
#define ATOM_CLASS
#define AtomStyle(key,Class) \
n = strlen(#key) + 1; \
allstyles[nallstyles] = new char[n]; \
strcpy(allstyles[nallstyles],#key); \
nallstyles++;
#include "style_atom.h"
#undef AtomStyle
#undef ATOM_CLASS
}
/* ----------------------------------------------------------------------
allstyles = list of all known atom styles
------------------------------------------------------------------------- */
int AtomVecHybrid::known_style(char *str)
{
for (int i = 0; i < nallstyles; i++)
if (strcmp(str,allstyles[i]) == 0) return 1;
return 0;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecHybrid::memory_usage()
{
bigint bytes = 0;
for (int k = 0; k < nstyles; k++) bytes += styles[k]->memory_usage();
return bytes;
}
diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h
index 32f4b4893..ce8e332ec 100644
--- a/src/atom_vec_hybrid.h
+++ b/src/atom_vec_hybrid.h
@@ -1,110 +1,111 @@
/* -*- 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 ATOM_CLASS
AtomStyle(hybrid,AtomVecHybrid)
#else
#ifndef LMP_ATOM_VEC_HYBRID_H
#define LMP_ATOM_VEC_HYBRID_H
#include "stdio.h"
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecHybrid : public AtomVec {
public:
int nstyles;
class AtomVec **styles;
char **keywords;
AtomVecHybrid(class LAMMPS *);
~AtomVecHybrid();
void settings(int, char **);
void init();
void grow(int);
void grow_reset();
void copy(int, int, int);
void clear_bonus();
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int pack_reverse(int, int, double *);
void unpack_reverse(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void write_restart_settings(FILE *);
void read_restart_settings(FILE *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **) {return 0;}
void data_vel(int, char **);
void pack_data(double **);
void write_data(FILE *, int, double **);
void pack_vel(double **);
void write_vel(FILE *, int, double **);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double **omega,**angmom;
int nallstyles;
char **allstyles;
void build_styles();
int known_style(char *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Atom style hybrid cannot have hybrid as an argument
Self-explanatory.
E: Atom style hybrid cannot use same atom style twice
Self-explanatory.
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
*/
diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp
index f8785eed9..5c89d237f 100644
--- a/src/atom_vec_line.cpp
+++ b/src/atom_vec_line.cpp
@@ -1,1306 +1,1304 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "atom_vec_line.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
#define DELTA_BONUS 10000
#define EPSILON 0.001
/* ---------------------------------------------------------------------- */
AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
comm_x_only = comm_f_only = 0;
size_forward = 4;
size_reverse = 6;
size_border = 10;
size_velocity = 6;
size_data_atom = 8;
size_data_vel = 7;
size_data_bonus = 5;
xcol_data = 6;
atom->line_flag = 1;
atom->molecule_flag = atom->rmass_flag = 1;
atom->omega_flag = atom->torque_flag = 1;
nlocal_bonus = nghost_bonus = nmax_bonus = 0;
bonus = NULL;
}
/* ---------------------------------------------------------------------- */
AtomVecLine::~AtomVecLine()
{
memory->sfree(bonus);
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::init()
{
AtomVec::init();
if (domain->dimension != 2)
error->all(FLERR,"Atom_style line can only be used in 2d simulations");
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecLine::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
omega = memory->grow(atom->omega,nmax,3,"atom:omega");
torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque");
line = memory->grow(atom->line,nmax,"atom:line");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecLine::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
molecule = atom->molecule; rmass = atom->rmass;
omega = atom->omega; torque = atom->torque;
line = atom->line;
}
/* ----------------------------------------------------------------------
grow bonus data structure
------------------------------------------------------------------------- */
void AtomVecLine::grow_bonus()
{
nmax_bonus += DELTA_BONUS;
if (nmax_bonus < 0 || nmax_bonus > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
bonus = (Bonus *) memory->srealloc(bonus,nmax_bonus*sizeof(Bonus),
"atom:bonus");
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecLine::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
molecule[j] = molecule[i];
rmass[j] = rmass[i];
omega[j][0] = omega[i][0];
omega[j][1] = omega[i][1];
omega[j][2] = omega[i][2];
// if deleting atom J via delflag and J has bonus data, then delete it
if (delflag && line[j] >= 0) {
copy_bonus(nlocal_bonus-1,line[j]);
nlocal_bonus--;
}
// if atom I has bonus data, reset I's bonus.ilocal to loc J
// do NOT do this if self-copy (I=J) since I's bonus data is already deleted
if (line[i] >= 0 && i != j) bonus[line[i]].ilocal = j;
line[j] = line[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ----------------------------------------------------------------------
copy bonus data from I to J, effectively deleting the J entry
also reset ine that points to I to now point to J
------------------------------------------------------------------------- */
void AtomVecLine::copy_bonus(int i, int j)
{
line[bonus[i].ilocal] = j;
memcpy(&bonus[j],&bonus[i],sizeof(Bonus));
}
/* ----------------------------------------------------------------------
clear ghost info in bonus data
called before ghosts are recommunicated in comm and irregular
------------------------------------------------------------------------- */
void AtomVecLine::clear_bonus()
{
nghost_bonus = 0;
}
/* ----------------------------------------------------------------------
set length value in bonus data for particle I
oriented along x axis
this may create or delete entry in bonus data
------------------------------------------------------------------------- */
void AtomVecLine::set_length(int i, double value)
{
if (line[i] < 0) {
if (value == 0.0) return;
if (nlocal_bonus == nmax_bonus) grow_bonus();
bonus[nlocal_bonus].length = value;
bonus[nlocal_bonus].theta = 0.0;
bonus[nlocal_bonus].ilocal = i;
line[i] = nlocal_bonus++;
} else if (value == 0.0) {
copy_bonus(nlocal_bonus-1,line[i]);
nlocal_bonus--;
line[i] = -1;
} else bonus[line[i]].length = value;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (line[j] >= 0) buf[m++] = bonus[line[j]].theta;
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (line[i] >= 0) bonus[line[i]].theta = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (line[i] >= 0) bonus[line[i]].theta = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++)
if (line[i] >= 0) bonus[line[i]].theta = buf[m++];
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = molecule[j];
if (line[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
buf[m++] = bonus[line[j]].length;
buf[m++] = bonus[line[j]].theta;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::unpack_border(int n, int first, double *buf)
{
int i,j,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
line[i] = (int) ubuf(buf[m++]).i;
if (line[i] == 0) line[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
bonus[j].length = buf[m++];
bonus[j].theta = buf[m++];
bonus[j].ilocal = i;
line[i] = j;
nghost_bonus++;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecLine::unpack_border_vel(int n, int first, double *buf)
{
int i,j,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
line[i] = (int) ubuf(buf[m++]).i;
if (line[i] == 0) line[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
bonus[j].length = buf[m++];
bonus[j].theta = buf[m++];
bonus[j].ilocal = i;
line[i] = j;
nghost_bonus++;
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::unpack_border_hybrid(int n, int first, double *buf)
{
int i,j,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
molecule[i] = (int) ubuf(buf[m++]).i;
line[i] = (int) ubuf(buf[m++]).i;
if (line[i] == 0) line[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
bonus[j].length = buf[m++];
bonus[j].theta = buf[m++];
bonus[j].ilocal = i;
line[i] = j;
nghost_bonus++;
}
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecLine::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = rmass[i];
buf[m++] = omega[i][0];
buf[m++] = omega[i][1];
buf[m++] = omega[i][2];
if (line[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = line[i];
buf[m++] = bonus[j].length;
buf[m++] = bonus[j].theta;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecLine::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
molecule[nlocal] = (int) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
omega[nlocal][0] = buf[m++];
omega[nlocal][1] = buf[m++];
omega[nlocal][2] = buf[m++];
line[nlocal] = (int) ubuf(buf[m++]).i;
if (line[nlocal] == 0) line[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
bonus[nlocal_bonus].length = buf[m++];
bonus[nlocal_bonus].theta = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
line[nlocal] = nlocal_bonus++;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecLine::size_restart()
{
int i;
int n = 0;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
if (line[i] >= 0) n += 19;
else n += 17;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecLine::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = rmass[i];
buf[m++] = omega[i][0];
buf[m++] = omega[i][1];
buf[m++] = omega[i][2];
if (line[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = line[i];
buf[m++] = bonus[j].length;
buf[m++] = bonus[j].theta;
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecLine::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
omega[nlocal][0] = buf[m++];
omega[nlocal][1] = buf[m++];
omega[nlocal][2] = buf[m++];
line[nlocal] = (int) ubuf(buf[m++]).i;
if (line[nlocal] == 0) line[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
bonus[nlocal_bonus].length = buf[m++];
bonus[nlocal_bonus].theta = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
line[nlocal] = nlocal_bonus++;
}
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecLine::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
molecule[nlocal] = 0;
rmass[nlocal] = 1.0;
omega[nlocal][0] = 0.0;
omega[nlocal][1] = 0.0;
omega[nlocal][2] = 0.0;
line[nlocal] = -1;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecLine::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
line[nlocal] = atoi(values[3]);
if (line[nlocal] == 0) line[nlocal] = -1;
else if (line[nlocal] == 1) line[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[4]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
omega[nlocal][0] = 0.0;
omega[nlocal][1] = 0.0;
omega[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecLine::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
line[nlocal] = atoi(values[1]);
if (line[nlocal] == 0) line[nlocal] = -1;
else if (line[nlocal] == 1) line[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[2]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
return 3;
}
/* ----------------------------------------------------------------------
unpack one line from Lines section of data file
------------------------------------------------------------------------- */
void AtomVecLine::data_atom_bonus(int m, char **values)
{
if (line[m]) error->one(FLERR,"Assigning line parameters to non-line atom");
if (nlocal_bonus == nmax_bonus) grow_bonus();
double x1 = atof(values[0]);
double y1 = atof(values[1]);
double x2 = atof(values[2]);
double y2 = atof(values[3]);
double dx = x2 - x1;
double dy = y2 - y1;
double length = sqrt(dx*dx + dy*dy);
bonus[nlocal_bonus].length = length;
if (dy >= 0.0) bonus[nlocal_bonus].theta = acos(dx/length);
else bonus[nlocal_bonus].theta = -acos(dx/length);
double xc = 0.5*(x1+x2);
double yc = 0.5*(y1+y2);
dx = xc - x[m][0];
dy = yc - x[m][1];
double delta = sqrt(dx*dx + dy*dy);
if (delta/length > EPSILON)
error->one(FLERR,"Inconsistent line segment in data file");
x[m][0] = xc;
x[m][1] = yc;
// reset line mass
// previously stored density in rmass
rmass[m] *= length;
bonus[nlocal_bonus].ilocal = m;
line[m] = nlocal_bonus++;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecLine::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
omega[m][0] = atof(values[3]);
omega[m][1] = atof(values[4]);
omega[m][2] = atof(values[5]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecLine::data_vel_hybrid(int m, char **values)
{
omega[m][0] = atof(values[0]);
omega[m][1] = atof(values[1]);
omega[m][2] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecLine::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
if (line[i] < 0) buf[i][3] = ubuf(0).d;
else buf[i][3] = ubuf(1).d;
if (line[i] < 0) buf[i][4] = rmass[i];
else buf[i][4] = rmass[i]/bonus[line[i]].length;
buf[i][5] = x[i][0];
buf[i][6] = x[i][1];
buf[i][7] = x[i][2];
buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecLine::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
if (line[i] < 0) buf[1] = ubuf(0).d;
else buf[1] = ubuf(1).d;
if (line[i] < 0) buf[2] = rmass[i];
else buf[2] = rmass[i]/bonus[line[i]].length;
return 3;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecLine::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,(int) ubuf(buf[i][3]).i,
buf[i][4],buf[i][5],buf[i][6],buf[i][7],
(int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i,
(int) ubuf(buf[i][10]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecLine::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d %d %-1.16e",(int) ubuf(buf[0]).i,(int) ubuf(buf[1]).i,buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecLine::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = omega[i][0];
buf[i][5] = omega[i][1];
buf[i][6] = omega[i][2];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecLine::pack_vel_hybrid(int i, double *buf)
{
buf[0] = omega[i][0];
buf[1] = omega[i][1];
buf[2] = omega[i][2];
return 3;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecLine::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
+ fprintf(fp,TAGINT_FORMAT
+ " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecLine::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecLine::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3);
if (atom->memcheck("torque"))
bytes += memory->usage(torque,nmax*comm->nthreads,3);
if (atom->memcheck("line")) bytes += memory->usage(line,nmax);
bytes += nmax_bonus*sizeof(Bonus);
return bytes;
}
/* ----------------------------------------------------------------------
check consistency of internal Bonus data structure
n = # of atoms in regular structure to check against
------------------------------------------------------------------------- */
/*
void AtomVecLine::consistency_check(int n, char *str)
{
int iflag = 0;
int count = 0;
for (int i = 0; i < n; i++) {
if (line[i] >= 0) {
count++;
if (line[i] >= nlocal_bonus) iflag++;
if (bonus[line[i]].ilocal != i) iflag++;
//if (comm->me == 1 && update->ntimestep == 873)
// printf("CCHK %s: %d %d: %d %d: %d %d\n",
// str,i,n,line[i],nlocal_bonus,bonus[line[i]].ilocal,iflag);
}
}
if (iflag) {
printf("BAD vecline ptrs: %s: %d %d: %d\n",str,comm->me,
update->ntimestep,iflag);
MPI_Abort(world,1);
}
if (count != nlocal_bonus) {
char msg[128];
printf("BAD vecline count: %s: %d %d: %d %d\n",
str,comm->me,update->ntimestep,count,nlocal_bonus);
MPI_Abort(world,1);
}
}
*/
diff --git a/src/atom_vec_line.h b/src/atom_vec_line.h
index 890a0f1be..845db6081 100644
--- a/src/atom_vec_line.h
+++ b/src/atom_vec_line.h
@@ -1,139 +1,140 @@
/* -*- 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 ATOM_CLASS
AtomStyle(line,AtomVecLine)
#else
#ifndef LMP_ATOM_VEC_LINE_H
#define LMP_ATOM_VEC_LINE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecLine : public AtomVec {
public:
struct Bonus {
double length,theta;
int ilocal;
};
struct Bonus *bonus;
AtomVecLine(class LAMMPS *);
~AtomVecLine();
void init();
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
// manipulate Bonus data structure for extra atom info
void clear_bonus();
void data_atom_bonus(int, char **);
// unique to AtomVecLine
void set_length(int, double);
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule;
double *rmass;
double **omega,**torque;
int *line;
int nlocal_bonus,nghost_bonus,nmax_bonus;
void grow_bonus();
void copy_bonus(int, int);
// void consistency_check(int, char *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Atom_style line can only be used in 2d simulations
Self-explanatory.
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid density in Atoms section of data file
Density value cannot be <= 0.0.
E: Assigning line parameters to non-line atom
Self-explanatory.
E: Inconsistent line segment in data file
The end points of the line segment are not equal distances from the
center point which is the atom coordinate.
*/
diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp
index c1d7e3a1d..acb125198 100644
--- a/src/atom_vec_sphere.cpp
+++ b/src/atom_vec_sphere.cpp
@@ -1,1191 +1,1190 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "atom_vec_sphere.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "fix_adapt.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
comm_x_only = 1;
comm_f_only = 0;
size_forward = 3;
size_reverse = 6;
size_border = 8;
size_velocity = 6;
size_data_atom = 7;
size_data_vel = 7;
xcol_data = 5;
atom->sphere_flag = 1;
atom->radius_flag = atom->rmass_flag = atom->omega_flag =
atom->torque_flag = 1;
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::init()
{
AtomVec::init();
// set radvary if particle diameters are time-varying due to fix adapt
radvary = 0;
comm_x_only = 1;
size_forward = 3;
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"adapt") == 0) {
FixAdapt *fix = (FixAdapt *) modify->fix[i];
if (fix->diamflag) {
radvary = 1;
comm_x_only = 0;
size_forward = 5;
}
}
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecSphere::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
radius = memory->grow(atom->radius,nmax,"atom:radius");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
omega = memory->grow(atom->omega,nmax,3,"atom:omega");
torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecSphere::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
radius = atom->radius; rmass = atom->rmass;
omega = atom->omega; torque = atom->torque;
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
------------------------------------------------------------------------- */
void AtomVecSphere::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
radius[j] = radius[i];
rmass[j] = rmass[i];
omega[j][0] = omega[i][0];
omega[j][1] = omega[i][1];
omega[j][2] = omega[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
if (radvary == 0) {
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
}
}
} else {
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
if (radvary == 0) {
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
}
}
} else {
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = radius[j];
buf[m++] = rmass[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = radius[j];
buf[m++] = rmass[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = radius[j];
buf[m++] = rmass[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
if (radvary == 0) return 0;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
if (radvary == 0) {
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
}
} else {
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
radius[i] = buf[m++];
rmass[i] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
if (radvary == 0) {
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
} else {
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
radius[i] = buf[m++];
rmass[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
if (radvary == 0) return 0;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
radius[i] = buf[m++];
rmass[i] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_border(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++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
} else {
if (domain->triclinic == 0) {
dx = pbc[0]*domain->xprd;
dy = pbc[1]*domain->yprd;
dz = pbc[2]*domain->zprd;
} else {
dx = pbc[0];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = radius[j];
buf[m++] = rmass[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = radius[j];
buf[m++] = rmass[j];
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = radius[j];
buf[m++] = rmass[j];
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = omega[j][0];
buf[m++] = omega[j][1];
buf[m++] = omega[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = radius[j];
buf[m++] = rmass[j];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::unpack_border(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
radius[i] = buf[m++];
rmass[i] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecSphere::unpack_border_vel(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
radius[i] = buf[m++];
rmass[i] = buf[m++];
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
omega[i][0] = buf[m++];
omega[i][1] = buf[m++];
omega[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::unpack_border_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
radius[i] = buf[m++];
rmass[i] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecSphere::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = radius[i];
buf[m++] = rmass[i];
buf[m++] = omega[i][0];
buf[m++] = omega[i][1];
buf[m++] = omega[i][2];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecSphere::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
radius[nlocal] = buf[m++];
rmass[nlocal] = buf[m++];
omega[nlocal][0] = buf[m++];
omega[nlocal][1] = buf[m++];
omega[nlocal][2] = buf[m++];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecSphere::size_restart()
{
int i;
int nlocal = atom->nlocal;
int n = 16 * nlocal;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecSphere::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = radius[i];
buf[m++] = rmass[i];
buf[m++] = omega[i][0];
buf[m++] = omega[i][1];
buf[m++] = omega[i][2];
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecSphere::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
radius[nlocal] = buf[m++];
rmass[nlocal] = buf[m++];
omega[nlocal][0] = buf[m++];
omega[nlocal][1] = buf[m++];
omega[nlocal][2] = buf[m++];
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecSphere::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
radius[nlocal] = 0.5;
rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal];
omega[nlocal][0] = 0.0;
omega[nlocal][1] = 0.0;
omega[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecSphere::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
type[nlocal] = atoi(values[1]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
radius[nlocal] = 0.5 * atof(values[2]);
if (radius[nlocal] < 0.0)
error->one(FLERR,"Invalid radius in Atoms section of data file");
double density = atof(values[3]);
if (density <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
if (radius[nlocal] == 0.0) rmass[nlocal] = density;
else
rmass[nlocal] = 4.0*MY_PI/3.0 *
radius[nlocal]*radius[nlocal]*radius[nlocal] * density;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
omega[nlocal][0] = 0.0;
omega[nlocal][1] = 0.0;
omega[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecSphere::data_atom_hybrid(int nlocal, char **values)
{
radius[nlocal] = 0.5 * atof(values[0]);
if (radius[nlocal] < 0.0)
error->one(FLERR,"Invalid radius in Atoms section of data file");
double density = atof(values[1]);
if (density <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
if (radius[nlocal] == 0.0) rmass[nlocal] = density;
else
rmass[nlocal] = 4.0*MY_PI/3.0 *
radius[nlocal]*radius[nlocal]*radius[nlocal] * density;
return 2;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecSphere::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
omega[m][0] = atof(values[3]);
omega[m][1] = atof(values[4]);
omega[m][2] = atof(values[5]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one line in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecSphere::data_vel_hybrid(int m, char **values)
{
omega[m][0] = atof(values[0]);
omega[m][1] = atof(values[1]);
omega[m][2] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecSphere::pack_data(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(type[i]).d;
buf[i][2] = 2.0*radius[i];
if (radius[i] == 0.0) buf[i][3] = rmass[i];
else
buf[i][3] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]);
buf[i][4] = x[i][0];
buf[i][5] = x[i][1];
buf[i][6] = x[i][2];
buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecSphere::pack_data_hybrid(int i, double *buf)
{
buf[0] = 2.0*radius[i];
if (radius[i] == 0.0) buf[1] = rmass[i];
else buf[1] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]);
return 2;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecSphere::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6],
(int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,
(int) ubuf(buf[i][9]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecSphere::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e",buf[0],buf[1]);
return 2;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecSphere::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = omega[i][0];
buf[i][5] = omega[i][1];
buf[i][6] = omega[i][2];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecSphere::pack_vel_hybrid(int i, double *buf)
{
buf[0] = omega[i][0];
buf[1] = omega[i][1];
buf[2] = omega[i][2];
return 3;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecSphere::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
+ fprintf(fp,TAGINT_FORMAT
+ " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecSphere::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecSphere::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3);
if (atom->memcheck("torque"))
bytes += memory->usage(torque,nmax*comm->nthreads,3);
return bytes;
}
diff --git a/src/atom_vec_sphere.h b/src/atom_vec_sphere.h
index f5f680aa1..2b0d056dd 100644
--- a/src/atom_vec_sphere.h
+++ b/src/atom_vec_sphere.h
@@ -1,108 +1,109 @@
/* -*- 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 ATOM_CLASS
AtomStyle(sphere,AtomVecSphere)
#else
#ifndef LMP_ATOM_VEC_SPHERE_H
#define LMP_ATOM_VEC_SPHERE_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecSphere : public AtomVec {
public:
AtomVecSphere(class LAMMPS *);
~AtomVecSphere() {}
void init();
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
double *radius,*density,*rmass;
double **omega,**torque;
int radvary;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid radius in Atoms section of data file
Radius must be >= 0.0.
E: Invalid density in Atoms section of data file
Density value cannot be <= 0.0.
*/
diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp
index 591ad3197..d170c8b5d 100644
--- a/src/atom_vec_tri.cpp
+++ b/src/atom_vec_tri.cpp
@@ -1,1717 +1,1715 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "atom_vec_tri.h"
#include "math_extra.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "force.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
#define DELTA_BONUS 10000
#define EPSILON 0.001
/* ---------------------------------------------------------------------- */
AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp)
{
molecular = 0;
comm_x_only = comm_f_only = 0;
size_forward = 7;
size_reverse = 6;
size_border = 24;
size_velocity = 6;
size_data_atom = 8;
size_data_vel = 7;
size_data_bonus = 10;
xcol_data = 6;
atom->tri_flag = 1;
atom->molecule_flag = atom->rmass_flag = 1;
atom->angmom_flag = atom->torque_flag = 1;
nlocal_bonus = nghost_bonus = nmax_bonus = 0;
bonus = NULL;
}
/* ---------------------------------------------------------------------- */
AtomVecTri::~AtomVecTri()
{
memory->sfree(bonus);
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::init()
{
AtomVec::init();
if (domain->dimension != 3)
error->all(FLERR,"Atom_style tri can only be used in 3d simulations");
}
/* ----------------------------------------------------------------------
grow atom arrays
n = 0 grows arrays by DELTA
n > 0 allocates arrays to size n
------------------------------------------------------------------------- */
void AtomVecTri::grow(int n)
{
if (n == 0) nmax += DELTA;
else nmax = n;
atom->nmax = nmax;
if (nmax < 0 || nmax > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
tag = memory->grow(atom->tag,nmax,"atom:tag");
type = memory->grow(atom->type,nmax,"atom:type");
mask = memory->grow(atom->mask,nmax,"atom:mask");
image = memory->grow(atom->image,nmax,"atom:image");
x = memory->grow(atom->x,nmax,3,"atom:x");
v = memory->grow(atom->v,nmax,3,"atom:v");
f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f");
molecule = memory->grow(atom->molecule,nmax,"atom:molecule");
rmass = memory->grow(atom->rmass,nmax,"atom:rmass");
angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom");
torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque");
tri = memory->grow(atom->tri,nmax,"atom:tri");
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax);
}
/* ----------------------------------------------------------------------
reset local array ptrs
------------------------------------------------------------------------- */
void AtomVecTri::grow_reset()
{
tag = atom->tag; type = atom->type;
mask = atom->mask; image = atom->image;
x = atom->x; v = atom->v; f = atom->f;
molecule = atom->molecule; rmass = atom->rmass;
angmom = atom->angmom; torque = atom->torque;
tri = atom->tri;
}
/* ----------------------------------------------------------------------
grow bonus data structure
------------------------------------------------------------------------- */
void AtomVecTri::grow_bonus()
{
nmax_bonus += DELTA_BONUS;
if (nmax_bonus < 0 || nmax_bonus > MAXSMALLINT)
error->one(FLERR,"Per-processor system is too big");
bonus = (Bonus *) memory->srealloc(bonus,nmax_bonus*sizeof(Bonus),
"atom:bonus");
}
/* ----------------------------------------------------------------------
copy atom I info to atom J
if delflag and atom J has bonus data, then delete it
------------------------------------------------------------------------- */
void AtomVecTri::copy(int i, int j, int delflag)
{
tag[j] = tag[i];
type[j] = type[i];
mask[j] = mask[i];
image[j] = image[i];
x[j][0] = x[i][0];
x[j][1] = x[i][1];
x[j][2] = x[i][2];
v[j][0] = v[i][0];
v[j][1] = v[i][1];
v[j][2] = v[i][2];
molecule[j] = molecule[i];
rmass[j] = rmass[i];
angmom[j][0] = angmom[i][0];
angmom[j][1] = angmom[i][1];
angmom[j][2] = angmom[i][2];
// if deleting atom J via delflag and J has bonus data, then delete it
if (delflag && tri[j] >= 0) {
copy_bonus(nlocal_bonus-1,tri[j]);
nlocal_bonus--;
}
// if atom I has bonus data, reset I's bonus.ilocal to loc J
// do NOT do this if self-copy (I=J) since I's bonus data is already deleted
if (tri[i] >= 0 && i != j) bonus[tri[i]].ilocal = j;
tri[j] = tri[i];
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag);
}
/* ----------------------------------------------------------------------
copy bonus data from I to J, effectively deleting the J entry
also reset tri that points to I to now point to J
------------------------------------------------------------------------- */
void AtomVecTri::copy_bonus(int i, int j)
{
tri[bonus[i].ilocal] = j;
memcpy(&bonus[j],&bonus[i],sizeof(Bonus));
}
/* ----------------------------------------------------------------------
clear ghost info in bonus data
called before ghosts are recommunicated in comm and irregular
------------------------------------------------------------------------- */
void AtomVecTri::clear_bonus()
{
nghost_bonus = 0;
}
/* ----------------------------------------------------------------------
set equilateral tri of size in bonus data for particle I
oriented symmetrically in xy plane
this may create or delete entry in bonus data
------------------------------------------------------------------------- */
void AtomVecTri::set_equilateral(int i, double size)
{
if (tri[i] < 0) {
if (size == 0.0) return;
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *quat = bonus[nlocal_bonus].quat;
double *c1 = bonus[nlocal_bonus].c1;
double *c2 = bonus[nlocal_bonus].c2;
double *c3 = bonus[nlocal_bonus].c3;
double *inertia = bonus[nlocal_bonus].inertia;
quat[0] = 1.0;
quat[1] = 0.0;
quat[2] = 0.0;
quat[3] = 0.0;
c1[0] = -size/2.0;
c1[1] = -sqrt(3.0)/2.0 * size / 3.0;
c1[2] = 0.0;
c2[0] = size/2.0;
c2[1] = -sqrt(3.0)/2.0 * size / 3.0;
c2[2] = 0.0;
c3[0] = 0.0;
c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0;
c3[2] = 0.0;
inertia[0] = sqrt(3.0)/96.0 * size*size*size*size;
inertia[1] = sqrt(3.0)/96.0 * size*size*size*size;
inertia[2] = sqrt(3.0)/48.0 * size*size*size*size;
bonus[nlocal_bonus].ilocal = i;
tri[i] = nlocal_bonus++;
} else if (size == 0.0) {
copy_bonus(nlocal_bonus-1,tri[i]);
nlocal_bonus--;
tri[i] = -1;
} else {
double *c1 = bonus[tri[i]].c1;
double *c2 = bonus[tri[i]].c2;
double *c3 = bonus[tri[i]].c3;
double *inertia = bonus[tri[i]].inertia;
c1[0] = -size/2.0;
c1[1] = -sqrt(3.0)/2.0 * size / 3.0;
c1[2] = 0.0;
c2[0] = size/2.0;
c2[1] = -sqrt(3.0)/2.0 * size / 3.0;
c2[2] = 0.0;
c3[0] = 0.0;
c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0;
c3[2] = 0.0;
inertia[0] = sqrt(3.0)/96.0 * size*size*size*size;
inertia[1] = sqrt(3.0)/96.0 * size*size*size*size;
inertia[2] = sqrt(3.0)/48.0 * size*size*size*size;
}
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
} 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++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_comm_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *quat;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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;
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_comm_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *quat;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (tri[j] >= 0) {
quat = bonus[tri[j]].quat;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (tri[i] >= 0) {
quat = bonus[tri[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::unpack_comm_vel(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
if (tri[i] >= 0) {
quat = bonus[tri[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::unpack_comm_hybrid(int n, int first, double *buf)
{
int i,m,last;
double *quat;
m = 0;
last = first + n;
for (i = first; i < last; i++)
if (tri[i] >= 0) {
quat = bonus[tri[i]].quat;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_reverse(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = f[i][0];
buf[m++] = f[i][1];
buf[m++] = f[i][2];
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_reverse_hybrid(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = torque[i][0];
buf[m++] = torque[i][1];
buf[m++] = torque[i][2];
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::unpack_reverse(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
f[j][0] += buf[m++];
f[j][1] += buf[m++];
f[j][2] += buf[m++];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::unpack_reverse_hybrid(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
torque[j][0] += buf[m++];
torque[j][1] += buf[m++];
torque[j][2] += buf[m++];
}
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_border(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[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];
dy = pbc[1];
dz = pbc[2];
}
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_border_vel(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
double dx,dy,dz,dvx,dvy,dvz;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
if (pbc_flag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0];
buf[m++] = x[j][1];
buf[m++] = x[j][2];
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[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];
dy = pbc[1];
dz = pbc[2];
}
if (!deform_vremap) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
} else {
dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4];
dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3];
dvz = pbc[2]*h_rate[2];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = x[j][0] + dx;
buf[m++] = x[j][1] + dy;
buf[m++] = x[j][2] + dz;
buf[m++] = ubuf(tag[j]).d;
buf[m++] = ubuf(type[j]).d;
buf[m++] = ubuf(mask[j]).d;
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
if (mask[i] & deform_groupbit) {
buf[m++] = v[j][0] + dvx;
buf[m++] = v[j][1] + dvy;
buf[m++] = v[j][2] + dvz;
} else {
buf[m++] = v[j][0];
buf[m++] = v[j][1];
buf[m++] = v[j][2];
}
buf[m++] = angmom[j][0];
buf[m++] = angmom[j][1];
buf[m++] = angmom[j][2];
}
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]);
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::pack_border_hybrid(int n, int *list, double *buf)
{
int i,j,m;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = ubuf(molecule[j]).d;
if (tri[j] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
quat = bonus[tri[j]].quat;
c1 = bonus[tri[j]].c1;
c2 = bonus[tri[j]].c2;
c3 = bonus[tri[j]].c3;
inertia = bonus[tri[j]].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::unpack_border(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
tri[i] = (int) ubuf(buf[m++]).i;
if (tri[i] == 0) tri[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
c1 = bonus[j].c1;
c2 = bonus[j].c2;
c3 = bonus[j].c3;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
c1[0] = buf[m++];
c1[1] = buf[m++];
c1[2] = buf[m++];
c2[0] = buf[m++];
c2[1] = buf[m++];
c2[2] = buf[m++];
c3[0] = buf[m++];
c3[1] = buf[m++];
c3[2] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ilocal = i;
tri[i] = j;
nghost_bonus++;
}
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
void AtomVecTri::unpack_border_vel(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
if (i == nmax) grow(0);
x[i][0] = buf[m++];
x[i][1] = buf[m++];
x[i][2] = buf[m++];
- tag[i] = (int) ubuf(buf[m++]).i;
+ tag[i] = (tagint) ubuf(buf[m++]).i;
type[i] = (int) ubuf(buf[m++]).i;
mask[i] = (int) ubuf(buf[m++]).i;
molecule[i] = (int) ubuf(buf[m++]).i;
tri[i] = (int) ubuf(buf[m++]).i;
if (tri[i] == 0) tri[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
c1 = bonus[j].c1;
c2 = bonus[j].c2;
c3 = bonus[j].c3;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
c1[0] = buf[m++];
c1[1] = buf[m++];
c1[2] = buf[m++];
c2[0] = buf[m++];
c2[1] = buf[m++];
c2[2] = buf[m++];
c3[0] = buf[m++];
c3[1] = buf[m++];
c3[2] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ilocal = i;
tri[i] = j;
nghost_bonus++;
}
v[i][0] = buf[m++];
v[i][1] = buf[m++];
v[i][2] = buf[m++];
angmom[i][0] = buf[m++];
angmom[i][1] = buf[m++];
angmom[i][2] = buf[m++];
}
if (atom->nextra_border)
for (int iextra = 0; iextra < atom->nextra_border; iextra++)
m += modify->fix[atom->extra_border[iextra]]->
unpack_border(n,first,&buf[m]);
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::unpack_border_hybrid(int n, int first, double *buf)
{
int i,j,m,last;
double *quat,*c1,*c2,*c3,*inertia;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
molecule[i] = (int) ubuf(buf[m++]).i;
tri[i] = (int) ubuf(buf[m++]).i;
if (tri[i] == 0) tri[i] = -1;
else {
j = nlocal_bonus + nghost_bonus;
if (j == nmax_bonus) grow_bonus();
quat = bonus[j].quat;
c1 = bonus[j].c1;
c2 = bonus[j].c2;
c3 = bonus[j].c3;
inertia = bonus[j].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
c1[0] = buf[m++];
c1[1] = buf[m++];
c1[2] = buf[m++];
c2[0] = buf[m++];
c2[1] = buf[m++];
c2[2] = buf[m++];
c3[0] = buf[m++];
c3[1] = buf[m++];
c3[2] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[j].ilocal = i;
tri[i] = j;
nghost_bonus++;
}
}
return m;
}
/* ----------------------------------------------------------------------
pack data for atom I for sending to another proc
xyz must be 1st 3 values, so comm::exchange() can test on them
------------------------------------------------------------------------- */
int AtomVecTri::pack_exchange(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (tri[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = tri[i];
double *quat = bonus[j].quat;
double *c1 = bonus[j].c1;
double *c2 = bonus[j].c2;
double *c3 = bonus[j].c3;
double *inertia = bonus[j].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]);
buf[0] = m;
return m;
}
/* ---------------------------------------------------------------------- */
int AtomVecTri::unpack_exchange(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
molecule[nlocal] = (int) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
tri[nlocal] = (int) ubuf(buf[m++]).i;
if (tri[nlocal] == 0) tri[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *quat = bonus[nlocal_bonus].quat;
double *c1 = bonus[nlocal_bonus].c1;
double *c2 = bonus[nlocal_bonus].c2;
double *c3 = bonus[nlocal_bonus].c3;
double *inertia = bonus[nlocal_bonus].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
c1[0] = buf[m++];
c1[1] = buf[m++];
c1[2] = buf[m++];
c2[0] = buf[m++];
c2[1] = buf[m++];
c2[2] = buf[m++];
c3[0] = buf[m++];
c3[1] = buf[m++];
c3[2] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
tri[nlocal] = nlocal_bonus++;
}
if (atom->nextra_grow)
for (int iextra = 0; iextra < atom->nextra_grow; iextra++)
m += modify->fix[atom->extra_grow[iextra]]->
unpack_exchange(nlocal,&buf[m]);
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
size of restart data for all atoms owned by this proc
include extra data stored by fixes
------------------------------------------------------------------------- */
int AtomVecTri::size_restart()
{
int i;
int n = 0;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
if (tri[i] >= 0) n += 33;
else n += 17;
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
for (i = 0; i < nlocal; i++)
n += modify->fix[atom->extra_restart[iextra]]->size_restart(i);
return n;
}
/* ----------------------------------------------------------------------
pack atom I's data for restart file including extra quantities
xyz must be 1st 3 values, so that read_restart can test on them
molecular types may be negative, but write as positive
------------------------------------------------------------------------- */
int AtomVecTri::pack_restart(int i, double *buf)
{
int m = 1;
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = ubuf(tag[i]).d;
buf[m++] = ubuf(type[i]).d;
buf[m++] = ubuf(mask[i]).d;
buf[m++] = ubuf(image[i]).d;
buf[m++] = v[i][0];
buf[m++] = v[i][1];
buf[m++] = v[i][2];
buf[m++] = ubuf(molecule[i]).d;
buf[m++] = rmass[i];
buf[m++] = angmom[i][0];
buf[m++] = angmom[i][1];
buf[m++] = angmom[i][2];
if (tri[i] < 0) buf[m++] = ubuf(0).d;
else {
buf[m++] = ubuf(1).d;
int j = tri[i];
double *quat = bonus[j].quat;
double *c1 = bonus[j].c1;
double *c2 = bonus[j].c2;
double *c3 = bonus[j].c3;
double *inertia = bonus[j].inertia;
buf[m++] = quat[0];
buf[m++] = quat[1];
buf[m++] = quat[2];
buf[m++] = quat[3];
buf[m++] = c1[0];
buf[m++] = c1[1];
buf[m++] = c1[2];
buf[m++] = c2[0];
buf[m++] = c2[1];
buf[m++] = c2[2];
buf[m++] = c3[0];
buf[m++] = c3[1];
buf[m++] = c3[2];
buf[m++] = inertia[0];
buf[m++] = inertia[1];
buf[m++] = inertia[2];
}
if (atom->nextra_restart)
for (int iextra = 0; iextra < atom->nextra_restart; iextra++)
m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]);
buf[0] = m;
return m;
}
/* ----------------------------------------------------------------------
unpack data for one atom from restart file including extra quantities
------------------------------------------------------------------------- */
int AtomVecTri::unpack_restart(double *buf)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) {
grow(0);
if (atom->nextra_store)
memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra");
}
int m = 1;
x[nlocal][0] = buf[m++];
x[nlocal][1] = buf[m++];
x[nlocal][2] = buf[m++];
- tag[nlocal] = (int) ubuf(buf[m++]).i;
+ tag[nlocal] = (tagint) ubuf(buf[m++]).i;
type[nlocal] = (int) ubuf(buf[m++]).i;
mask[nlocal] = (int) ubuf(buf[m++]).i;
image[nlocal] = (imageint) ubuf(buf[m++]).i;
v[nlocal][0] = buf[m++];
v[nlocal][1] = buf[m++];
v[nlocal][2] = buf[m++];
molecule[nlocal] = (int) ubuf(buf[m++]).i;
rmass[nlocal] = buf[m++];
angmom[nlocal][0] = buf[m++];
angmom[nlocal][1] = buf[m++];
angmom[nlocal][2] = buf[m++];
tri[nlocal] = (int) ubuf(buf[m++]).i;
if (tri[nlocal] == 0) tri[nlocal] = -1;
else {
if (nlocal_bonus == nmax_bonus) grow_bonus();
double *quat = bonus[nlocal_bonus].quat;
double *c1 = bonus[nlocal_bonus].c1;
double *c2 = bonus[nlocal_bonus].c2;
double *c3 = bonus[nlocal_bonus].c3;
double *inertia = bonus[nlocal_bonus].inertia;
quat[0] = buf[m++];
quat[1] = buf[m++];
quat[2] = buf[m++];
quat[3] = buf[m++];
c1[0] = buf[m++];
c1[1] = buf[m++];
c1[2] = buf[m++];
c2[0] = buf[m++];
c2[1] = buf[m++];
c2[2] = buf[m++];
c3[0] = buf[m++];
c3[1] = buf[m++];
c3[2] = buf[m++];
inertia[0] = buf[m++];
inertia[1] = buf[m++];
inertia[2] = buf[m++];
bonus[nlocal_bonus].ilocal = nlocal;
tri[nlocal] = nlocal_bonus++;
}
double **extra = atom->extra;
if (atom->nextra_store) {
int size = static_cast<int> (buf[0]) - m;
for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++];
}
atom->nlocal++;
return m;
}
/* ----------------------------------------------------------------------
create one atom of itype at coord
set other values to defaults
------------------------------------------------------------------------- */
void AtomVecTri::create_atom(int itype, double *coord)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
tag[nlocal] = 0;
type[nlocal] = itype;
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
mask[nlocal] = 1;
image[nlocal] = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
molecule[nlocal] = 0;
rmass[nlocal] = 1.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
tri[nlocal] = -1;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack one line from Atoms section of data file
initialize other atom quantities
------------------------------------------------------------------------- */
void AtomVecTri::data_atom(double *coord, imageint imagetmp, char **values)
{
int nlocal = atom->nlocal;
if (nlocal == nmax) grow(0);
- tag[nlocal] = atoi(values[0]);
- if (tag[nlocal] <= 0)
- error->one(FLERR,"Invalid atom ID in Atoms section of data file");
-
+ tag[nlocal] = ATOTAGINT(values[0]);
molecule[nlocal] = atoi(values[1]);
-
type[nlocal] = atoi(values[2]);
if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file");
tri[nlocal] = atoi(values[3]);
if (tri[nlocal] == 0) tri[nlocal] = -1;
else if (tri[nlocal] == 1) tri[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[4]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
x[nlocal][0] = coord[0];
x[nlocal][1] = coord[1];
x[nlocal][2] = coord[2];
image[nlocal] = imagetmp;
mask[nlocal] = 1;
v[nlocal][0] = 0.0;
v[nlocal][1] = 0.0;
v[nlocal][2] = 0.0;
angmom[nlocal][0] = 0.0;
angmom[nlocal][1] = 0.0;
angmom[nlocal][2] = 0.0;
atom->nlocal++;
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one tri in Atoms section of data file
initialize other atom quantities for this sub-style
------------------------------------------------------------------------- */
int AtomVecTri::data_atom_hybrid(int nlocal, char **values)
{
molecule[nlocal] = atoi(values[0]);
tri[nlocal] = atoi(values[1]);
if (tri[nlocal] == 0) tri[nlocal] = -1;
else if (tri[nlocal] == 1) tri[nlocal] = 0;
else error->one(FLERR,"Invalid atom type in Atoms section of data file");
rmass[nlocal] = atof(values[2]);
if (rmass[nlocal] <= 0.0)
error->one(FLERR,"Invalid density in Atoms section of data file");
return 3;
}
/* ----------------------------------------------------------------------
unpack one line from Tris section of data file
------------------------------------------------------------------------- */
void AtomVecTri::data_atom_bonus(int m, char **values)
{
if (tri[m]) error->one(FLERR,"Assigning tri parameters to non-tri atom");
if (nlocal_bonus == nmax_bonus) grow_bonus();
double c1[3],c2[3],c3[3];
c1[0] = atof(values[0]);
c1[1] = atof(values[1]);
c1[2] = atof(values[2]);
c2[0] = atof(values[3]);
c2[1] = atof(values[4]);
c2[2] = atof(values[5]);
c3[0] = atof(values[6]);
c3[1] = atof(values[7]);
c3[2] = atof(values[8]);
// check for duplicate points
if (c1[0] == c2[0] && c1[1] == c2[1] && c1[2] == c2[2])
error->one(FLERR,"Invalid shape in Triangles section of data file");
if (c1[0] == c3[0] && c1[1] == c3[1] && c1[2] == c3[2])
error->one(FLERR,"Invalid shape in Triangles section of data file");
if (c2[0] == c3[0] && c2[1] == c3[1] && c2[2] == c3[2])
error->one(FLERR,"Invalid shape in Triangles section of data file");
// size = length of one edge
double c2mc1[2],c3mc1[3];
MathExtra::sub3(c2,c1,c2mc1);
MathExtra::sub3(c3,c1,c3mc1);
double size = MAX(MathExtra::len3(c2mc1),MathExtra::len3(c3mc1));
// centroid = 1/3 of sum of vertices
double centroid[3];
centroid[0] = (c1[0]+c2[0]+c3[0]) / 3.0;
centroid[1] = (c1[1]+c2[1]+c3[1]) / 3.0;
centroid[2] = (c1[2]+c2[2]+c3[2]) / 3.0;
double dx = centroid[0] - x[m][0];
double dy = centroid[1] - x[m][1];
double dz = centroid[2] - x[m][2];
double delta = sqrt(dx*dx + dy*dy + dz*dz);
if (delta/size > EPSILON)
error->one(FLERR,"Inconsistent triangle in data file");
x[m][0] = centroid[0];
x[m][1] = centroid[1];
x[m][2] = centroid[2];
// reset tri mass
// previously stored density in rmass
// tri area = 0.5 len(U x V), where U,V are edge vectors from one vertex
double norm[3];
MathExtra::cross3(c2mc1,c3mc1,norm);
double area = 0.5 * MathExtra::len3(norm);
rmass[m] *= area;
// inertia = inertia tensor of triangle as 6-vector in Voigt notation
double inertia[6];
MathExtra::inertia_triangle(c1,c2,c3,rmass[m],inertia);
// diagonalize inertia tensor via Jacobi rotations
// bonus[].inertia = 3 eigenvalues = principal moments of inertia
// evectors and exzy_space = 3 evectors = principal axes of triangle
double tensor[3][3],evectors[3][3];
tensor[0][0] = inertia[0];
tensor[1][1] = inertia[1];
tensor[2][2] = inertia[2];
tensor[1][2] = tensor[2][1] = inertia[3];
tensor[0][2] = tensor[2][0] = inertia[4];
tensor[0][1] = tensor[1][0] = inertia[5];
int ierror = MathExtra::jacobi(tensor,bonus[nlocal_bonus].inertia,evectors);
if (ierror) error->one(FLERR,"Insufficient Jacobi rotations for triangle");
double ex_space[3],ey_space[3],ez_space[3];
ex_space[0] = evectors[0][0];
ex_space[1] = evectors[1][0];
ex_space[2] = evectors[2][0];
ey_space[0] = evectors[0][1];
ey_space[1] = evectors[1][1];
ey_space[2] = evectors[2][1];
ez_space[0] = evectors[0][2];
ez_space[1] = evectors[1][2];
ez_space[2] = evectors[2][2];
// enforce 3 orthogonal vectors as a right-handed coordinate system
// flip 3rd vector if needed
MathExtra::cross3(ex_space,ey_space,norm);
if (MathExtra::dot3(norm,ez_space) < 0.0) MathExtra::negate3(ez_space);
// create initial quaternion
MathExtra::exyz_to_q(ex_space,ey_space,ez_space,bonus[nlocal_bonus].quat);
// bonus c1,c2,c3 = displacement of c1,c2,c3 from centroid
// in basis of principal axes
double disp[3];
MathExtra::sub3(c1,centroid,disp);
MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
disp,bonus[nlocal_bonus].c1);
MathExtra::sub3(c2,centroid,disp);
MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
disp,bonus[nlocal_bonus].c2);
MathExtra::sub3(c3,centroid,disp);
MathExtra::transpose_matvec(ex_space,ey_space,ez_space,
disp,bonus[nlocal_bonus].c3);
bonus[nlocal_bonus].ilocal = m;
tri[m] = nlocal_bonus++;
}
/* ----------------------------------------------------------------------
unpack one line from Velocities section of data file
------------------------------------------------------------------------- */
void AtomVecTri::data_vel(int m, char **values)
{
v[m][0] = atof(values[0]);
v[m][1] = atof(values[1]);
v[m][2] = atof(values[2]);
angmom[m][0] = atof(values[3]);
angmom[m][1] = atof(values[4]);
angmom[m][2] = atof(values[5]);
}
/* ----------------------------------------------------------------------
unpack hybrid quantities from one tri in Velocities section of data file
------------------------------------------------------------------------- */
int AtomVecTri::data_vel_hybrid(int m, char **values)
{
angmom[m][0] = atof(values[0]);
angmom[m][1] = atof(values[1]);
angmom[m][2] = atof(values[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack atom info for data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecTri::pack_data(double **buf)
{
double c2mc1[2],c3mc1[3],norm[3];
double area;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = ubuf(molecule[i]).d;
buf[i][2] = ubuf(type[i]).d;
if (tri[i] < 0) buf[i][3] = ubuf(0).d;
else buf[i][3] = ubuf(1).d;
if (tri[i] < 0) buf[i][4] = rmass[i];
else {
MathExtra::sub3(bonus[tri[i]].c2,bonus[tri[i]].c1,c2mc1);
MathExtra::sub3(bonus[tri[i]].c3,bonus[tri[i]].c1,c3mc1);
MathExtra::cross3(c2mc1,c3mc1,norm);
area = 0.5 * MathExtra::len3(norm);
buf[i][4] = rmass[i]/area;
}
buf[i][5] = x[i][0];
buf[i][6] = x[i][1];
buf[i][7] = x[i][2];
buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d;
buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d;
buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d;
}
}
/* ----------------------------------------------------------------------
pack hybrid atom info for data file
------------------------------------------------------------------------- */
int AtomVecTri::pack_data_hybrid(int i, double *buf)
{
buf[0] = ubuf(molecule[i]).d;
if (tri[i] < 0) buf[1] = ubuf(0).d;
else buf[1] = ubuf(1).d;
if (tri[i] < 0) buf[2] = rmass[i];
else {
double c2mc1[2],c3mc1[3],norm[3];
MathExtra::sub3(bonus[tri[i]].c2,bonus[tri[i]].c1,c2mc1);
MathExtra::sub3(bonus[tri[i]].c3,bonus[tri[i]].c1,c3mc1);
MathExtra::cross3(c2mc1,c3mc1,norm);
double area = 0.5 * MathExtra::len3(norm);
buf[2] = rmass[i]/area;
}
return 3;
}
/* ----------------------------------------------------------------------
write atom info to data file including 3 image flags
------------------------------------------------------------------------- */
void AtomVecTri::write_data(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
- (int) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
+ fprintf(fp,TAGINT_FORMAT
+ " %d %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n",
+ (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,
(int) ubuf(buf[i][2]).i,(int) ubuf(buf[i][3]).i,
buf[i][4],buf[i][5],buf[i][6],buf[i][7],
(int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i,
(int) ubuf(buf[i][10]).i);
}
/* ----------------------------------------------------------------------
write hybrid atom info to data file
------------------------------------------------------------------------- */
int AtomVecTri::write_data_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %d %d %-1.16e",(int) ubuf(buf[0]).i,(int) ubuf(buf[1]).i,buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
pack velocity info for data file
------------------------------------------------------------------------- */
void AtomVecTri::pack_vel(double **buf)
{
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
buf[i][0] = ubuf(tag[i]).d;
buf[i][1] = v[i][0];
buf[i][2] = v[i][1];
buf[i][3] = v[i][2];
buf[i][4] = angmom[i][0];
buf[i][5] = angmom[i][1];
buf[i][6] = angmom[i][2];
}
}
/* ----------------------------------------------------------------------
pack hybrid velocity info for data file
------------------------------------------------------------------------- */
int AtomVecTri::pack_vel_hybrid(int i, double *buf)
{
buf[0] = angmom[i][0];
buf[1] = angmom[i][1];
buf[2] = angmom[i][2];
return 3;
}
/* ----------------------------------------------------------------------
write velocity info to data file
------------------------------------------------------------------------- */
void AtomVecTri::write_vel(FILE *fp, int n, double **buf)
{
for (int i = 0; i < n; i++)
- fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
- (int) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
+ fprintf(fp,TAGINT_FORMAT
+ " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n",
+ (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],
buf[i][4],buf[i][5],buf[i][6]);
}
/* ----------------------------------------------------------------------
write hybrid velocity info to data file
------------------------------------------------------------------------- */
int AtomVecTri::write_vel_hybrid(FILE *fp, double *buf)
{
fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]);
return 3;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint AtomVecTri::memory_usage()
{
bigint bytes = 0;
if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax);
if (atom->memcheck("type")) bytes += memory->usage(type,nmax);
if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax);
if (atom->memcheck("image")) bytes += memory->usage(image,nmax);
if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3);
if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3);
if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3);
if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax);
if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax);
if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3);
if (atom->memcheck("torque")) bytes +=
memory->usage(torque,nmax*comm->nthreads,3);
if (atom->memcheck("tri")) bytes += memory->usage(tri,nmax);
bytes += nmax_bonus*sizeof(Bonus);
return bytes;
}
diff --git a/src/atom_vec_tri.h b/src/atom_vec_tri.h
index 91cf27be8..da3311367 100644
--- a/src/atom_vec_tri.h
+++ b/src/atom_vec_tri.h
@@ -1,149 +1,150 @@
/* -*- 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 ATOM_CLASS
AtomStyle(tri,AtomVecTri)
#else
#ifndef LMP_ATOM_VEC_TRI_H
#define LMP_ATOM_VEC_TRI_H
#include "atom_vec.h"
namespace LAMMPS_NS {
class AtomVecTri : public AtomVec {
public:
struct Bonus {
double quat[4];
double c1[3],c2[3],c3[3];
double inertia[3];
int ilocal;
};
struct Bonus *bonus;
AtomVecTri(class LAMMPS *);
~AtomVecTri();
void init();
void grow(int);
void grow_reset();
void copy(int, int, int);
int pack_comm(int, int *, double *, int, int *);
int pack_comm_vel(int, int *, double *, int, int *);
int pack_comm_hybrid(int, int *, double *);
void unpack_comm(int, int, double *);
void unpack_comm_vel(int, int, double *);
int unpack_comm_hybrid(int, int, double *);
int pack_reverse(int, int, double *);
int pack_reverse_hybrid(int, int, double *);
void unpack_reverse(int, int *, double *);
int unpack_reverse_hybrid(int, int *, double *);
int pack_border(int, int *, double *, int, int *);
int pack_border_vel(int, int *, double *, int, int *);
int pack_border_hybrid(int, int *, double *);
void unpack_border(int, int, double *);
void unpack_border_vel(int, int, double *);
int unpack_border_hybrid(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(double *);
int size_restart();
int pack_restart(int, double *);
int unpack_restart(double *);
void create_atom(int, double *);
void data_atom(double *, imageint, char **);
int data_atom_hybrid(int, char **);
void data_vel(int, char **);
int data_vel_hybrid(int, char **);
void pack_data(double **);
int pack_data_hybrid(int, double *);
void write_data(FILE *, int, double **);
int write_data_hybrid(FILE *, double *);
void pack_vel(double **);
int pack_vel_hybrid(int, double *);
void write_vel(FILE *, int, double **);
int write_vel_hybrid(FILE *, double *);
bigint memory_usage();
// manipulate Bonus data structure for extra atom info
void clear_bonus();
void data_atom_bonus(int, char **);
// unique to AtomVecTri
void set_equilateral(int, double);
private:
- int *tag,*type,*mask;
+ tagint *tag;
+ int *type,*mask;
imageint *image;
double **x,**v,**f;
int *molecule;
double *rmass;
double **angmom,**torque;
int *tri;
int nlocal_bonus,nghost_bonus,nmax_bonus;
void grow_bonus();
void copy_bonus(int, int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Atom_style tri can only be used in 3d simulations
Self-explanatory.
E: Per-processor system is too big
The number of owned atoms plus ghost atoms on a single
processor must fit in 32-bit integer.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Invalid atom type in Atoms section of data file
Atom types must range from 1 to specified # of types.
E: Invalid density in Atoms section of data file
Density value cannot be <= 0.0.
E: Assigning tri parameters to non-tri atom
Self-explanatory.
E: Invalid shape in Triangles section of data file
Two or more of the triangle corners are duplicate points.
E: Inconsistent triangle in data file
The centroid of the triangle as defined by the corner points is not
the atom coordinate.
E: Insufficient Jacobi rotations for triangle
The calculation of the intertia tensor of the triangle failed. This
should not happen if it is a reasonably shaped triangle.
*/
diff --git a/src/compute_angle_local.cpp b/src/compute_angle_local.cpp
index 626fc7df8..6e2cd5732 100644
--- a/src/compute_angle_local.cpp
+++ b/src/compute_angle_local.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 "math.h"
#include "string.h"
#include "compute_angle_local.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "domain.h"
#include "force.h"
#include "angle.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 10000
/* ---------------------------------------------------------------------- */
ComputeAngleLocal::ComputeAngleLocal(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute angle/local command");
if (atom->avec->angles_allow == 0)
error->all(FLERR,"Compute angle/local used when angles are not allowed");
local_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_local_cols = 0;
else size_local_cols = nvalues;
tflag = eflag = -1;
nvalues = 0;
int i;
for (int iarg = 3; iarg < narg; iarg++) {
i = iarg-3;
if (strcmp(arg[iarg],"theta") == 0) tflag = nvalues++;
else if (strcmp(arg[iarg],"eng") == 0) eflag = nvalues++;
else error->all(FLERR,"Invalid keyword in compute angle/local command");
}
nmax = 0;
vector = NULL;
array = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeAngleLocal::~ComputeAngleLocal()
{
memory->destroy(vector);
memory->destroy(array);
}
/* ---------------------------------------------------------------------- */
void ComputeAngleLocal::init()
{
if (force->angle == NULL)
error->all(FLERR,"No angle style is defined for compute angle/local");
// do initial memory allocation so that memory_usage() is correct
ncount = compute_angles(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
}
/* ---------------------------------------------------------------------- */
void ComputeAngleLocal::compute_local()
{
invoked_local = update->ntimestep;
// count local entries and compute angle info
ncount = compute_angles(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
ncount = compute_angles(1);
}
/* ----------------------------------------------------------------------
count angles and compute angle info on this proc
only count angle once if newton_angle is off
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if angle is deleted (type = 0), do not count
if angle is turned off (type < 0), still count
if flag is set, compute requested info about angle
if angle is turned off (type < 0), energy = 0.0
------------------------------------------------------------------------- */
int ComputeAngleLocal::compute_angles(int flag)
{
int i,m,n,atom1,atom2,atom3;
double delx1,dely1,delz1,delx2,dely2,delz2;
double rsq1,rsq2,r1,r2,c;
double *tbuf,*ebuf;
double **x = atom->x;
int *num_angle = atom->num_angle;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (flag) {
if (nvalues == 1) {
if (tflag >= 0) tbuf = vector;
if (eflag >= 0) ebuf = vector;
} else {
if (tflag >= 0 && array) tbuf = &array[0][tflag];
else tbuf = NULL;
if (eflag >= 0 && array) ebuf = &array[0][eflag];
else ebuf = NULL;
}
}
Angle *angle = force->angle;
m = n = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_angle[atom2]; i++) {
if (tag[atom2] != angle_atom2[atom2][i]) continue;
atom1 = atom->map(angle_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(angle_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
if (angle_type[atom2][i] == 0) continue;
if (flag) {
if (tflag >= 0) {
delx1 = x[atom1][0] - x[atom2][0];
dely1 = x[atom1][1] - x[atom2][1];
delz1 = x[atom1][2] - x[atom2][2];
domain->minimum_image(delx1,dely1,delz1);
rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1;
r1 = sqrt(rsq1);
delx2 = x[atom3][0] - x[atom2][0];
dely2 = x[atom3][1] - x[atom2][1];
delz2 = x[atom3][2] - x[atom2][2];
domain->minimum_image(delx2,dely2,delz2);
rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2;
r2 = sqrt(rsq2);
// c = cosine of angle
c = delx1*delx2 + dely1*dely2 + delz1*delz2;
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
tbuf[n] = 180.0*acos(c)/MY_PI;
}
if (eflag >= 0) {
if (angle_type[atom2][i] > 0)
ebuf[n] = angle->single(angle_type[atom2][i],atom1,atom2,atom3);
else ebuf[n] = 0.0;
}
n += nvalues;
}
m++;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeAngleLocal::reallocate(int n)
{
// grow vector or array and indices array
while (nmax < n) nmax += DELTA;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"bond/local:vector");
vector_local = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"bond/local:array");
array_local = array;
}
}
/* ----------------------------------------------------------------------
memory usage of local data
------------------------------------------------------------------------- */
double ComputeAngleLocal::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
return bytes;
}
diff --git a/src/compute_bond_local.cpp b/src/compute_bond_local.cpp
index 344157eec..ad6697e04 100644
--- a/src/compute_bond_local.cpp
+++ b/src/compute_bond_local.cpp
@@ -1,209 +1,209 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "compute_bond_local.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "domain.h"
#include "force.h"
#include "bond.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define DELTA 10000
enum{DIST,ENG,FORCE};
/* ---------------------------------------------------------------------- */
ComputeBondLocal::ComputeBondLocal(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute bond/local command");
if (atom->avec->bonds_allow == 0)
error->all(FLERR,"Compute bond/local used when bonds are not allowed");
local_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_local_cols = 0;
else size_local_cols = nvalues;
bstyle = new int[nvalues];
nvalues = 0;
for (int iarg = 3; iarg < narg; iarg++) {
if (strcmp(arg[iarg],"dist") == 0) bstyle[nvalues++] = DIST;
else if (strcmp(arg[iarg],"eng") == 0) bstyle[nvalues++] = ENG;
else if (strcmp(arg[iarg],"force") == 0) bstyle[nvalues++] = FORCE;
else error->all(FLERR,"Invalid keyword in compute bond/local command");
}
// set singleflag if need to call bond->single()
singleflag = 0;
for (int i = 0; i < nvalues; i++)
if (bstyle[i] != DIST) singleflag = 1;
nmax = 0;
vector = NULL;
array = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeBondLocal::~ComputeBondLocal()
{
memory->destroy(vector);
memory->destroy(array);
delete [] bstyle;
}
/* ---------------------------------------------------------------------- */
void ComputeBondLocal::init()
{
if (force->bond == NULL)
error->all(FLERR,"No bond style is defined for compute bond/local");
// do initial memory allocation so that memory_usage() is correct
ncount = compute_bonds(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
}
/* ---------------------------------------------------------------------- */
void ComputeBondLocal::compute_local()
{
invoked_local = update->ntimestep;
// count local entries and compute bond info
ncount = compute_bonds(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
ncount = compute_bonds(1);
}
/* ----------------------------------------------------------------------
count bonds and compute bond info on this proc
only count bond once if newton_bond is off
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if bond is deleted (type = 0), do not count
if bond is turned off (type < 0), still count
if flag is set, compute requested info about bond
if bond is turned off (type < 0), energy = 0.0
------------------------------------------------------------------------- */
int ComputeBondLocal::compute_bonds(int flag)
{
int i,m,n,atom1,atom2;
double delx,dely,delz,rsq;
double *dbuf,*ebuf,*fbuf;
double *ptr;
double **x = atom->x;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
Bond *bond = force->bond;
double eng,fbond;
m = n = 0;
for (atom1 = 0; atom1 < nlocal; atom1++) {
if (!(mask[atom1] & groupbit)) continue;
for (i = 0; i < num_bond[atom1]; i++) {
atom2 = atom->map(bond_atom[atom1][i]);
if (atom2 < 0 || !(mask[atom2] & groupbit)) continue;
if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue;
if (bond_type[atom1][i] == 0) continue;
if (flag) {
delx = x[atom1][0] - x[atom2][0];
dely = x[atom1][1] - x[atom2][1];
delz = x[atom1][2] - x[atom2][2];
domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
if (singleflag) {
if (bond_type[atom1][i] > 0)
eng = bond->single(bond_type[atom1][i],rsq,atom1,atom2,fbond);
else eng = fbond = 0.0;
}
if (nvalues == 1) ptr = &vector[m];
else ptr = array[m];
for (n = 0; n < nvalues; n++) {
switch (bstyle[n]) {
case DIST:
ptr[n] = sqrt(rsq);
break;
case ENG:
ptr[n] = eng;
break;
case FORCE:
ptr[n] = sqrt(rsq)*fbond;
break;
}
}
}
m++;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeBondLocal::reallocate(int n)
{
// grow vector or array and indices array
while (nmax < n) nmax += DELTA;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"bond/local:vector");
vector_local = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"bond/local:array");
array_local = array;
}
}
/* ----------------------------------------------------------------------
memory usage of local data
------------------------------------------------------------------------- */
double ComputeBondLocal::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
return bytes;
}
diff --git a/src/compute_cluster_atom.cpp b/src/compute_cluster_atom.cpp
index 030090dcb..b1713873b 100644
--- a/src/compute_cluster_atom.cpp
+++ b/src/compute_cluster_atom.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 "math.h"
#include "string.h"
#include "stdlib.h"
#include "compute_cluster_atom.h"
#include "atom.h"
#include "update.h"
#include "modify.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "force.h"
#include "pair.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeClusterAtom::ComputeClusterAtom(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg != 4) error->all(FLERR,"Illegal compute cluster/atom command");
double cutoff = force->numeric(FLERR,arg[3]);
cutsq = cutoff*cutoff;
peratom_flag = 1;
size_peratom_cols = 0;
comm_forward = 1;
nmax = 0;
clusterID = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeClusterAtom::~ComputeClusterAtom()
{
memory->destroy(clusterID);
}
/* ---------------------------------------------------------------------- */
void ComputeClusterAtom::init()
{
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use compute cluster/atom unless atoms have IDs");
if (force->pair == NULL)
error->all(FLERR,"Compute cluster/atom requires a pair style be defined");
if (sqrt(cutsq) > force->pair->cutforce)
error->all(FLERR,
"Compute cluster/atom cutoff is longer than pairwise cutoff");
// need an occasional full neighbor list
// full required so that pair of atoms on 2 procs both set their clusterID
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->compute = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->occasional = 1;
int count = 0;
for (int i = 0; i < modify->ncompute; i++)
if (strcmp(modify->compute[i]->style,"cluster/atom") == 0) count++;
if (count > 1 && comm->me == 0)
error->warning(FLERR,"More than one compute cluster/atom");
}
/* ---------------------------------------------------------------------- */
void ComputeClusterAtom::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void ComputeClusterAtom::compute_peratom()
{
int i,j,ii,jj,inum,jnum,n;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *ilist,*jlist,*numneigh,**firstneigh;
invoked_peratom = update->ntimestep;
// grow clusterID array if necessary
if (atom->nlocal+atom->nghost > nmax) {
memory->destroy(clusterID);
nmax = atom->nmax;
memory->create(clusterID,nmax,"cluster/atom:clusterID");
vector_atom = clusterID;
}
// invoke full neighbor list (will copy or build if necessary)
neighbor->build_one(list->index);
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// every atom starts in its own cluster, with clusterID = atomID
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit) clusterID[i] = tag[i];
else clusterID[i] = 0;
}
// loop until no more changes on any proc:
// acquire clusterIDs of ghost atoms
// loop over my atoms, checking distance to neighbors
// if both atoms are in cluster, assign lowest clusterID to both
// iterate until no changes in my atoms
// then check if any proc made changes
double **x = atom->x;
int change,done,anychange;
while (1) {
comm->forward_comm_compute(this);
change = 0;
while (1) {
done = 1;
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];
jlist = firstneigh[i];
jnum = numneigh[i];
n = 0;
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
if (!(mask[j] & groupbit)) continue;
if (clusterID[i] == clusterID[j]) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < cutsq) {
clusterID[i] = clusterID[j] = MIN(clusterID[i],clusterID[j]);
done = 0;
}
}
}
if (!done) change = 1;
if (done) break;
}
// stop if all procs are done
MPI_Allreduce(&change,&anychange,1,MPI_INT,MPI_MAX,world);
if (!anychange) break;
}
}
/* ---------------------------------------------------------------------- */
int ComputeClusterAtom::pack_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];
}
return 1;
}
/* ---------------------------------------------------------------------- */
void ComputeClusterAtom::unpack_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++];
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputeClusterAtom::memory_usage()
{
double bytes = nmax * sizeof(double);
return bytes;
}
diff --git a/src/compute_dihedral_local.cpp b/src/compute_dihedral_local.cpp
index e0f600521..438f665da 100644
--- a/src/compute_dihedral_local.cpp
+++ b/src/compute_dihedral_local.cpp
@@ -1,234 +1,234 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "compute_dihedral_local.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "domain.h"
#include "force.h"
#include "dihedral.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 10000
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ComputeDihedralLocal::ComputeDihedralLocal(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute dihedral/local command");
if (atom->avec->dihedrals_allow == 0)
error->all(FLERR,
"Compute dihedral/local used when dihedrals are not allowed");
local_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_local_cols = 0;
else size_local_cols = nvalues;
pflag = -1;
nvalues = 0;
int i;
for (int iarg = 3; iarg < narg; iarg++) {
i = iarg-3;
if (strcmp(arg[iarg],"phi") == 0) pflag = nvalues++;
else error->all(FLERR,"Invalid keyword in compute dihedral/local command");
}
nmax = 0;
vector = NULL;
array = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeDihedralLocal::~ComputeDihedralLocal()
{
memory->destroy(vector);
memory->destroy(array);
}
/* ---------------------------------------------------------------------- */
void ComputeDihedralLocal::init()
{
if (force->dihedral == NULL)
error->all(FLERR,"No dihedral style is defined for compute dihedral/local");
// do initial memory allocation so that memory_usage() is correct
ncount = compute_dihedrals(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
}
/* ---------------------------------------------------------------------- */
void ComputeDihedralLocal::compute_local()
{
invoked_local = update->ntimestep;
// count local entries and compute dihedral info
ncount = compute_dihedrals(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
ncount = compute_dihedrals(1);
}
/* ----------------------------------------------------------------------
count dihedrals on this proc
only count if 2nd atom is the one storing the dihedral
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if flag is set, compute requested info about dihedral
------------------------------------------------------------------------- */
int ComputeDihedralLocal::compute_dihedrals(int flag)
{
int i,m,n,atom1,atom2,atom3,atom4;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double s,c;
double *pbuf;
double **x = atom->x;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
- int *tag = atom->tag;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (flag) {
if (nvalues == 1) {
if (pflag >= 0) pbuf = vector;
} else {
if (pflag >= 0 && array) pbuf = &array[0][pflag];
else pbuf = NULL;
}
}
m = n = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_dihedral[atom2]; i++) {
if (tag[atom2] != dihedral_atom2[atom2][i]) continue;
atom1 = atom->map(dihedral_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(dihedral_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
atom4 = atom->map(dihedral_atom4[atom2][i]);
if (atom4 < 0 || !(mask[atom4] & groupbit)) continue;
if (flag) {
// phi calculation from dihedral style harmonic
if (pflag >= 0) {
vb1x = x[atom1][0] - x[atom2][0];
vb1y = x[atom1][1] - x[atom2][1];
vb1z = x[atom1][2] - x[atom2][2];
domain->minimum_image(vb1x,vb1y,vb1z);
vb2x = x[atom3][0] - x[atom2][0];
vb2y = x[atom3][1] - x[atom2][1];
vb2z = x[atom3][2] - x[atom2][2];
domain->minimum_image(vb2x,vb2y,vb2z);
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
domain->minimum_image(vb2xm,vb2ym,vb2zm);
vb3x = x[atom4][0] - x[atom3][0];
vb3y = x[atom4][1] - x[atom3][1];
vb3z = x[atom4][2] - x[atom3][2];
domain->minimum_image(vb3x,vb3y,vb3z);
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
pbuf[n] = 180.0*atan2(s,c)/MY_PI;
}
n += nvalues;
}
m++;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeDihedralLocal::reallocate(int n)
{
// grow vector or array and indices array
while (nmax < n) nmax += DELTA;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"bond/local:vector");
vector_local = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"bond/local:array");
array_local = array;
}
}
/* ----------------------------------------------------------------------
memory usage of local data
------------------------------------------------------------------------- */
double ComputeDihedralLocal::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
return bytes;
}
diff --git a/src/compute_improper_local.cpp b/src/compute_improper_local.cpp
index 862169fbb..4e66856df 100644
--- a/src/compute_improper_local.cpp
+++ b/src/compute_improper_local.cpp
@@ -1,232 +1,232 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "compute_improper_local.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "domain.h"
#include "force.h"
#include "improper.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define DELTA 10000
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
ComputeImproperLocal::ComputeImproperLocal(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute improper/local command");
if (atom->avec->impropers_allow == 0)
error->all(FLERR,
"Compute improper/local used when impropers are not allowed");
local_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_local_cols = 0;
else size_local_cols = nvalues;
cflag = -1;
nvalues = 0;
int i;
for (int iarg = 3; iarg < narg; iarg++) {
i = iarg-3;
if (strcmp(arg[iarg],"chi") == 0) cflag = nvalues++;
else error->all(FLERR,"Invalid keyword in compute improper/local command");
}
nmax = 0;
vector = NULL;
array = NULL;
}
/* ---------------------------------------------------------------------- */
ComputeImproperLocal::~ComputeImproperLocal()
{
memory->destroy(vector);
memory->destroy(array);
}
/* ---------------------------------------------------------------------- */
void ComputeImproperLocal::init()
{
if (force->improper == NULL)
error->all(FLERR,"No improper style is defined for compute improper/local");
// do initial memory allocation so that memory_usage() is correct
ncount = compute_impropers(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
}
/* ---------------------------------------------------------------------- */
void ComputeImproperLocal::compute_local()
{
invoked_local = update->ntimestep;
// count local entries and compute improper info
ncount = compute_impropers(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
ncount = compute_impropers(1);
}
/* ----------------------------------------------------------------------
count impropers on this proc
only count if 2nd atom is the one storing the improper
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if flag is set, compute requested info about improper
------------------------------------------------------------------------- */
int ComputeImproperLocal::compute_impropers(int flag)
{
int i,m,n,atom1,atom2,atom3,atom4;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z;
double ss1,ss2,ss3,r1,r2,r3,c0,c1,c2,s1,s2;
double s12,c;
double *cbuf;
double **x = atom->x;
int *num_improper = atom->num_improper;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
- int *tag = atom->tag;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (flag) {
if (nvalues == 1) {
if (cflag >= 0) cbuf = vector;
} else {
if (cflag >= 0 && array) cbuf = &array[0][cflag];
else cbuf = NULL;
}
}
m = n = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_improper[atom2]; i++) {
if (tag[atom2] != improper_atom2[atom2][i]) continue;
atom1 = atom->map(improper_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(improper_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
atom4 = atom->map(improper_atom4[atom2][i]);
if (atom4 < 0 || !(mask[atom4] & groupbit)) continue;
if (flag) {
// chi calculation from improper style harmonic
if (cflag >= 0) {
vb1x = x[atom1][0] - x[atom2][0];
vb1y = x[atom1][1] - x[atom2][1];
vb1z = x[atom1][2] - x[atom2][2];
domain->minimum_image(vb1x,vb1y,vb1z);
vb2x = x[atom3][0] - x[atom2][0];
vb2y = x[atom3][1] - x[atom2][1];
vb2z = x[atom3][2] - x[atom2][2];
domain->minimum_image(vb2x,vb2y,vb2z);
vb3x = x[atom4][0] - x[atom3][0];
vb3y = x[atom4][1] - x[atom3][1];
vb3z = x[atom4][2] - x[atom3][2];
domain->minimum_image(vb3x,vb3y,vb3z);
ss1 = 1.0 / (vb1x*vb1x + vb1y*vb1y + vb1z*vb1z);
ss2 = 1.0 / (vb2x*vb2x + vb2y*vb2y + vb2z*vb2z);
ss3 = 1.0 / (vb3x*vb3x + vb3y*vb3y + vb3z*vb3z);
r1 = sqrt(ss1);
r2 = sqrt(ss2);
r3 = sqrt(ss3);
c0 = (vb1x * vb3x + vb1y * vb3y + vb1z * vb3z) * r1 * r3;
c1 = (vb1x * vb2x + vb1y * vb2y + vb1z * vb2z) * r1 * r2;
c2 = -(vb3x * vb2x + vb3y * vb2y + vb3z * vb2z) * r3 * r2;
s1 = 1.0 - c1*c1;
if (s1 < SMALL) s1 = SMALL;
s1 = 1.0 / s1;
s2 = 1.0 - c2*c2;
if (s2 < SMALL) s2 = SMALL;
s2 = 1.0 / s2;
s12 = sqrt(s1*s2);
c = (c1*c2 + c0) * s12;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
cbuf[n] = 180.0*acos(c)/MY_PI;
}
n += nvalues;
}
m++;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputeImproperLocal::reallocate(int n)
{
// grow vector or array and indices array
while (nmax < n) nmax += DELTA;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"bond/local:vector");
vector_local = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"bond/local:array");
array_local = array;
}
}
/* ----------------------------------------------------------------------
memory usage of local data
------------------------------------------------------------------------- */
double ComputeImproperLocal::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
return bytes;
}
diff --git a/src/compute_property_atom.cpp b/src/compute_property_atom.cpp
index 9b3dc754b..250451950 100644
--- a/src/compute_property_atom.cpp
+++ b/src/compute_property_atom.cpp
@@ -1,1716 +1,1716 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "compute_property_atom.h"
#include "math_extra.h"
#include "atom.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "atom_vec_body.h"
#include "update.h"
#include "domain.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputePropertyAtom::ComputePropertyAtom(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute property/atom command");
peratom_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_peratom_cols = 0;
else size_peratom_cols = nvalues;
// parse input values
// customize a new keyword by adding to if statement
pack_choice = new FnPtrPack[nvalues];
index = new int[nvalues];
int i;
for (int iarg = 3; iarg < narg; iarg++) {
i = iarg-3;
if (strcmp(arg[iarg],"id") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_id;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (!atom->molecule_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_molecule;
} else if (strcmp(arg[iarg],"type") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_type;
} else if (strcmp(arg[iarg],"mass") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_mass;
} else if (strcmp(arg[iarg],"x") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_x;
} else if (strcmp(arg[iarg],"y") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_y;
} else if (strcmp(arg[iarg],"z") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_z;
} else if (strcmp(arg[iarg],"xs") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_xs_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_xs;
} else if (strcmp(arg[iarg],"ys") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_ys_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_ys;
} else if (strcmp(arg[iarg],"zs") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_zs_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_zs;
} else if (strcmp(arg[iarg],"xu") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_xu_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_xu;
} else if (strcmp(arg[iarg],"yu") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_yu_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_yu;
} else if (strcmp(arg[iarg],"zu") == 0) {
if (domain->triclinic)
pack_choice[i] = &ComputePropertyAtom::pack_zu_triclinic;
else pack_choice[i] = &ComputePropertyAtom::pack_zu;
} else if (strcmp(arg[iarg],"ix") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_ix;
} else if (strcmp(arg[iarg],"iy") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_iy;
} else if (strcmp(arg[iarg],"iz") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_iz;
} else if (strcmp(arg[iarg],"vx") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_vx;
} else if (strcmp(arg[iarg],"vy") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_vy;
} else if (strcmp(arg[iarg],"vz") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_vz;
} else if (strcmp(arg[iarg],"fx") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_fx;
} else if (strcmp(arg[iarg],"fy") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_fy;
} else if (strcmp(arg[iarg],"fz") == 0) {
pack_choice[i] = &ComputePropertyAtom::pack_fz;
} else if (strcmp(arg[iarg],"q") == 0) {
if (!atom->q_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_q;
} else if (strcmp(arg[iarg],"mux") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_mux;
} else if (strcmp(arg[iarg],"muy") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_muy;
} else if (strcmp(arg[iarg],"muz") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_muz;
} else if (strcmp(arg[iarg],"mu") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_mu;
} else if (strcmp(arg[iarg],"radius") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_radius;
} else if (strcmp(arg[iarg],"diameter") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_diameter;
} else if (strcmp(arg[iarg],"omegax") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_omegax;
} else if (strcmp(arg[iarg],"omegay") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_omegay;
} else if (strcmp(arg[iarg],"omegaz") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_omegaz;
} else if (strcmp(arg[iarg],"angmomx") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_angmomx;
} else if (strcmp(arg[iarg],"angmomy") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_angmomy;
} else if (strcmp(arg[iarg],"angmomz") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_angmomz;
} else if (strcmp(arg[iarg],"shapex") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
if (!avec_ellipsoid) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_shapex;
} else if (strcmp(arg[iarg],"shapey") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
if (!avec_ellipsoid) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_shapey;
} else if (strcmp(arg[iarg],"shapez") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
if (!avec_ellipsoid) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_shapez;
} else if (strcmp(arg[iarg],"quatw") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_ellipsoid && !avec_body)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_quatw;
} else if (strcmp(arg[iarg],"quati") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_ellipsoid && !avec_body)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_quati;
} else if (strcmp(arg[iarg],"quatj") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_ellipsoid && !avec_body)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_quatj;
} else if (strcmp(arg[iarg],"quatk") == 0) {
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_ellipsoid && !avec_body)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_quatk;
} else if (strcmp(arg[iarg],"tqx") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_tqx;
} else if (strcmp(arg[iarg],"tqy") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_tqy;
} else if (strcmp(arg[iarg],"tqz") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_tqz;
} else if (strcmp(arg[iarg],"spin") == 0) {
if (!atom->spin_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_spin;
} else if (strcmp(arg[iarg],"eradius") == 0) {
if (!atom->eradius_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_eradius;
} else if (strcmp(arg[iarg],"ervel") == 0) {
if (!atom->ervel_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_ervel;
} else if (strcmp(arg[iarg],"erforce") == 0) {
if (!atom->erforce_flag)
error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_erforce;
} else if (strcmp(arg[iarg],"end1x") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end1x;
} else if (strcmp(arg[iarg],"end1y") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end1y;
} else if (strcmp(arg[iarg],"end1z") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end1z;
} else if (strcmp(arg[iarg],"end2x") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end2x;
} else if (strcmp(arg[iarg],"end2y") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end2y;
} else if (strcmp(arg[iarg],"end2z") == 0) {
avec_line = (AtomVecLine *) atom->style_match("line");
if (!avec_line) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_end2z;
} else if (strcmp(arg[iarg],"corner1x") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner1x;
} else if (strcmp(arg[iarg],"corner1y") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner1y;
} else if (strcmp(arg[iarg],"corner1z") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner1z;
} else if (strcmp(arg[iarg],"corner2x") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner2x;
} else if (strcmp(arg[iarg],"corner2y") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner2y;
} else if (strcmp(arg[iarg],"corner2z") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner2z;
} else if (strcmp(arg[iarg],"corner3x") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner3x;
} else if (strcmp(arg[iarg],"corner3y") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner3y;
} else if (strcmp(arg[iarg],"corner3z") == 0) {
avec_tri = (AtomVecTri *) atom->style_match("tri");
if (!avec_tri) error->all(FLERR,"Compute property/atom for "
"atom property that isn't allocated");
pack_choice[i] = &ComputePropertyAtom::pack_corner3z;
} else if (strstr(arg[iarg],"i_") == arg[iarg]) {
int flag;
index[i] = atom->find_custom(&arg[iarg][2],flag);
if (index[i] < 0 || flag != 0)
error->all(FLERR,"Compute property/atom floating point "
"vector does not exist");
pack_choice[i] = &ComputePropertyAtom::pack_iname;
} else if (strstr(arg[iarg],"d_") == arg[iarg]) {
int flag;
index[i] = atom->find_custom(&arg[iarg][2],flag);
if (index[i] < 0 || flag != 1)
error->all(FLERR,"Compute property/atom integer "
"vector does not exist");
pack_choice[i] = &ComputePropertyAtom::pack_dname;
} else error->all(FLERR,"Invalid keyword in compute property/atom command");
}
nmax = 0;
vector = NULL;
array = NULL;
}
/* ---------------------------------------------------------------------- */
ComputePropertyAtom::~ComputePropertyAtom()
{
delete [] pack_choice;
delete [] index;
memory->destroy(vector);
memory->destroy(array);
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::init()
{
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
avec_line = (AtomVecLine *) atom->style_match("line");
avec_tri = (AtomVecTri *) atom->style_match("tri");
avec_body = (AtomVecBody *) atom->style_match("body");
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::compute_peratom()
{
invoked_peratom = update->ntimestep;
// grow vector or array if necessary
if (atom->nlocal > nmax) {
nmax = atom->nmax;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"property/atom:vector");
vector_atom = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"property/atom:array");
array_atom = array;
}
}
// fill vector or array with per-atom values
if (nvalues == 1) {
buf = vector;
(this->*pack_choice[0])(0);
} else {
if (nmax) buf = &array[0][0];
else buf = NULL;
for (int n = 0; n < nvalues; n++)
(this->*pack_choice[n])(n);
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double ComputePropertyAtom::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
one method for every keyword compute property/atom can output
the atom property is packed into buf starting at n with stride nvalues
customize a new keyword by adding a method
------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_id(int n)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = tag[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_molecule(int n)
{
int *molecule = atom->molecule;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = molecule[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_type(int n)
{
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = type[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_mass(int n)
{
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = rmass[i];
else buf[n] = 0.0;
n += nvalues;
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = mass[type[i]];
else buf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_x(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = x[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_y(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = x[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_z(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = x[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_xs(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (x[i][0] - boxxlo) * invxprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_ys(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (x[i][1] - boxylo) * invyprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_zs(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (x[i][2] - boxzlo) * invzprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_xs_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = h_inv[0]*(x[i][0]-boxlo[0]) +
h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_ys_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_zs_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = h_inv[2]*(x[i][2]-boxlo[2]);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_xu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = x[i][0] + ((image[i] & IMGMASK) - IMGMAX) * xprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_yu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double yprd = domain->yprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = x[i][1] + ((image[i] >> IMGBITS & IMGMASK) - IMGMAX) * yprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_zu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double zprd = domain->zprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
buf[n] = x[i][2] + ((image[i] >> IMG2BITS) - IMGMAX) * zprd;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_xu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int xbox,ybox,zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
buf[n] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_yu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int ybox,zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
buf[n] = x[i][1] + h[1]*ybox + h[3]*zbox;
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_zu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
zbox = (image[i] >> IMG2BITS) - IMGMAX;
buf[n] = x[i][2] + h[2]*zbox;
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_ix(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (image[i] & IMGMASK) - IMGMAX;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_iy(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_iz(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = (image[i] >> IMG2BITS) - IMGMAX;
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_vx(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = v[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_vy(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = v[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_vz(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = v[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_fx(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = f[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_fy(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = f[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_fz(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = f[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_q(int n)
{
double *q = atom->q;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = q[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_mux(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = mu[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_muy(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = mu[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_muz(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = mu[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_mu(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = mu[i][3];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_radius(int n)
{
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = radius[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_diameter(int n)
{
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = 2.0*radius[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_omegax(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = omega[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_omegay(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = omega[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_omegaz(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = omega[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_angmomx(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = angmom[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_angmomy(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = angmom[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_angmomz(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = angmom[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_shapex(int n)
{
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].shape[0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_shapey(int n)
{
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].shape[1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_shapez(int n)
{
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].shape[2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_quatw(int n)
{
if (avec_ellipsoid) {
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].quat[0];
else buf[n] = 0.0;
n += nvalues;
}
} else {
AtomVecBody::Bonus *bonus = avec_body->bonus;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && body[i] >= 0)
buf[n] = bonus[body[i]].quat[0];
else buf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_quati(int n)
{
if (avec_ellipsoid) {
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].quat[1];
else buf[n] = 0.0;
n += nvalues;
}
} else {
AtomVecBody::Bonus *bonus = avec_body->bonus;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && body[i] >= 0)
buf[n] = bonus[body[i]].quat[1];
else buf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_quatj(int n)
{
if (avec_ellipsoid) {
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].quat[2];
else buf[n] = 0.0;
n += nvalues;
}
} else {
AtomVecBody::Bonus *bonus = avec_body->bonus;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && body[i] >= 0)
buf[n] = bonus[body[i]].quat[2];
else buf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_quatk(int n)
{
if (avec_ellipsoid) {
AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus;
int *ellipsoid = atom->ellipsoid;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && ellipsoid[i] >= 0)
buf[n] = bonus[ellipsoid[i]].quat[3];
else buf[n] = 0.0;
n += nvalues;
}
} else {
AtomVecBody::Bonus *bonus = avec_body->bonus;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && body[i] >= 0)
buf[n] = bonus[body[i]].quat[3];
else buf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_tqx(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = torque[i][0];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_tqy(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = torque[i][1];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_tqz(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = torque[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_spin(int n)
{
int *spin = atom->spin;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = spin[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_eradius(int n)
{
double *eradius = atom->eradius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = eradius[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_ervel(int n)
{
double *ervel = atom->ervel;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = ervel[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_erforce(int n)
{
double *erforce = atom->erforce;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = erforce[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end1x(int n)
{
AtomVecLine::Bonus *bonus = avec_line->bonus;
int *line = atom->line;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && line[i] >= 0)
buf[n] = x[i][0] - 0.5*bonus[line[i]].length*cos(bonus[line[i]].theta);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end1y(int n)
{
AtomVecLine::Bonus *bonus = avec_line->bonus;
int *line = atom->line;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && line[i] >= 0)
buf[n] = x[i][1] - 0.5*bonus[line[i]].length*sin(bonus[line[i]].theta);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end1z(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = x[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end2x(int n)
{
AtomVecLine::Bonus *bonus = avec_line->bonus;
int *line = atom->line;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && line[i] >= 0)
buf[n] = x[i][0] + 0.5*bonus[line[i]].length*cos(bonus[line[i]].theta);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end2y(int n)
{
AtomVecLine::Bonus *bonus = avec_line->bonus;
int *line = atom->line;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && line[i] >= 0)
buf[n] = x[i][1] + 0.5*bonus[line[i]].length*sin(bonus[line[i]].theta);
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_end2z(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = x[i][2];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner1x(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c1,c);
buf[n] = x[i][0] + c[0];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner1y(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c1,c);
buf[n] = x[i][1] + c[1];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner1z(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c1,c);
buf[n] = x[i][2] + c[2];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner2x(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c2,c);
buf[n] = x[i][0] + c[0];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner2y(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c2,c);
buf[n] = x[i][1] + c[1];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner2z(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c2,c);
buf[n] = x[i][2] + c[2];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner3x(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c3,c);
buf[n] = x[i][0] + c[0];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner3y(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c3,c);
buf[n] = x[i][1] + c[1];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_corner3z(int n)
{
AtomVecTri::Bonus *bonus = avec_tri->bonus;
int *tri = atom->tri;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double p[3][3],c[3];
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && tri[i] >= 0) {
MathExtra::quat_to_mat(bonus[tri[i]].quat,p);
MathExtra::matvec(p,bonus[tri[i]].c3,c);
buf[n] = x[i][2] + c[2];
} else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_iname(int n)
{
int *ivector = atom->ivector[index[n]];
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = ivector[i];
else buf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyAtom::pack_dname(int n)
{
double *dvector = atom->dvector[index[n]];
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) buf[n] = dvector[i];
else buf[n] = 0.0;
n += nvalues;
}
}
diff --git a/src/compute_property_local.cpp b/src/compute_property_local.cpp
index fa1fbbabd..b9fc3ab4d 100644
--- a/src/compute_property_local.cpp
+++ b/src/compute_property_local.cpp
@@ -1,913 +1,912 @@
/* ----------------------------------------------------------------------
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_property_local.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "force.h"
#include "pair.h"
#include "neighbor.h"
#include "neigh_request.h"
#include "neigh_list.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NONE,NEIGH,PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER};
#define DELTA 10000
/* ---------------------------------------------------------------------- */
ComputePropertyLocal::ComputePropertyLocal(LAMMPS *lmp, int narg, char **arg) :
Compute(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal compute property/local command");
local_flag = 1;
nvalues = narg - 3;
if (nvalues == 1) size_local_cols = 0;
else size_local_cols = nvalues;
pack_choice = new FnPtrPack[nvalues];
kindflag = NONE;
int i;
for (int iarg = 3; iarg < narg; iarg++) {
i = iarg-3;
if (strcmp(arg[iarg],"natom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_patom1;
if (kindflag != NONE && kindflag != NEIGH)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = NEIGH;
} else if (strcmp(arg[iarg],"natom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_patom2;
if (kindflag != NONE && kindflag != NEIGH)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = NEIGH;
} else if (strcmp(arg[iarg],"ntype1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_ptype1;
if (kindflag != NONE && kindflag != NEIGH)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = NEIGH;
} else if (strcmp(arg[iarg],"ntype2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_ptype2;
if (kindflag != NONE && kindflag != NEIGH)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = NEIGH;
} else if (strcmp(arg[iarg],"patom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_patom1;
if (kindflag != NONE && kindflag != PAIR)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = PAIR;
} else if (strcmp(arg[iarg],"patom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_patom2;
if (kindflag != NONE && kindflag != PAIR)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = PAIR;
} else if (strcmp(arg[iarg],"ptype1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_ptype1;
if (kindflag != NONE && kindflag != PAIR)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = PAIR;
} else if (strcmp(arg[iarg],"ptype2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_ptype2;
if (kindflag != NONE && kindflag != PAIR)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = PAIR;
} else if (strcmp(arg[iarg],"batom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_batom1;
if (kindflag != NONE && kindflag != BOND)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = BOND;
} else if (strcmp(arg[iarg],"batom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_batom2;
if (kindflag != NONE && kindflag != BOND)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = BOND;
} else if (strcmp(arg[iarg],"btype") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_btype;
if (kindflag != NONE && kindflag != BOND)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = BOND;
} else if (strcmp(arg[iarg],"aatom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_aatom1;
if (kindflag != NONE && kindflag != ANGLE)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = ANGLE;
} else if (strcmp(arg[iarg],"aatom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_aatom2;
if (kindflag != NONE && kindflag != ANGLE)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = ANGLE;
} else if (strcmp(arg[iarg],"aatom3") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_aatom3;
if (kindflag != NONE && kindflag != ANGLE)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = ANGLE;
} else if (strcmp(arg[iarg],"atype") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_atype;
if (kindflag != NONE && kindflag != ANGLE)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = ANGLE;
} else if (strcmp(arg[iarg],"datom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_datom1;
if (kindflag != NONE && kindflag != DIHEDRAL)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = DIHEDRAL;
} else if (strcmp(arg[iarg],"datom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_datom2;
if (kindflag != NONE && kindflag != DIHEDRAL)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = DIHEDRAL;
} else if (strcmp(arg[iarg],"datom3") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_datom3;
if (kindflag != NONE && kindflag != DIHEDRAL)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = DIHEDRAL;
} else if (strcmp(arg[iarg],"datom4") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_datom4;
if (kindflag != NONE && kindflag != DIHEDRAL)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = DIHEDRAL;
} else if (strcmp(arg[iarg],"dtype") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_dtype;
if (kindflag != NONE && kindflag != DIHEDRAL)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = DIHEDRAL;
} else if (strcmp(arg[iarg],"iatom1") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_iatom1;
if (kindflag != NONE && kindflag != IMPROPER)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = IMPROPER;
} else if (strcmp(arg[iarg],"iatom2") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_iatom2;
if (kindflag != NONE && kindflag != IMPROPER)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = IMPROPER;
} else if (strcmp(arg[iarg],"iatom3") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_iatom3;
if (kindflag != NONE && kindflag != IMPROPER)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = IMPROPER;
} else if (strcmp(arg[iarg],"iatom4") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_iatom4;
if (kindflag != NONE && kindflag != IMPROPER)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = IMPROPER;
} else if (strcmp(arg[iarg],"itype") == 0) {
pack_choice[i] = &ComputePropertyLocal::pack_itype;
if (kindflag != NONE && kindflag != IMPROPER)
error->all(FLERR,
"Compute property/local cannot use these inputs together");
kindflag = IMPROPER;
} else error->all(FLERR,
"Invalid keyword in compute property/local command");
}
// error check
if (kindflag == BOND && atom->avec->bonds_allow == 0)
error->all(FLERR,
"Compute property/local for property that isn't allocated");
if (kindflag == ANGLE && atom->avec->angles_allow == 0)
error->all(FLERR,
"Compute property/local for property that isn't allocated");
if (kindflag == DIHEDRAL && atom->avec->dihedrals_allow == 0)
error->all(FLERR,
"Compute property/local for property that isn't allocated");
if (kindflag == IMPROPER && atom->avec->impropers_allow == 0)
error->all(FLERR,
"Compute property/local for property that isn't allocated");
nmax = 0;
vector = NULL;
array = NULL;
indices = NULL;
}
/* ---------------------------------------------------------------------- */
ComputePropertyLocal::~ComputePropertyLocal()
{
delete [] pack_choice;
memory->destroy(vector);
memory->destroy(array);
memory->destroy(indices);
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::init()
{
if (kindflag == NEIGH || kindflag == PAIR) {
if (force->pair == NULL)
error->all(FLERR,"No pair style is defined for compute property/local");
if (force->pair->single_enable == 0)
error->all(FLERR,"Pair style does not support compute property/local");
}
// for NEIGH/PAIR need an occasional half neighbor list
if (kindflag == NEIGH || kindflag == PAIR) {
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->compute = 1;
neighbor->requests[irequest]->occasional = 1;
}
// do initial memory allocation so that memory_usage() is correct
// cannot be done yet for NEIGH/PAIR, since neigh list does not exist
if (kindflag == NEIGH) ncount = 0;
else if (kindflag == PAIR) ncount = 0;
else if (kindflag == BOND) ncount = count_bonds(0);
else if (kindflag == ANGLE) ncount = count_angles(0);
else if (kindflag == DIHEDRAL) ncount = count_dihedrals(0);
else if (kindflag == IMPROPER) ncount = count_impropers(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::compute_local()
{
invoked_local = update->ntimestep;
// count local entries and generate list of indices
if (kindflag == NEIGH) ncount = count_pairs(0,0);
else if (kindflag == PAIR) ncount = count_pairs(0,1);
else if (kindflag == BOND) ncount = count_bonds(0);
else if (kindflag == ANGLE) ncount = count_angles(0);
else if (kindflag == DIHEDRAL) ncount = count_dihedrals(0);
else if (kindflag == IMPROPER) ncount = count_impropers(0);
if (ncount > nmax) reallocate(ncount);
size_local_rows = ncount;
if (kindflag == NEIGH) ncount = count_pairs(1,0);
else if (kindflag == PAIR) ncount = count_pairs(1,1);
else if (kindflag == BOND) ncount = count_bonds(1);
else if (kindflag == ANGLE) ncount = count_angles(1);
else if (kindflag == DIHEDRAL) ncount = count_dihedrals(1);
else if (kindflag == IMPROPER) ncount = count_impropers(1);
// fill vector or array with local values
if (nvalues == 1) {
buf = vector;
(this->*pack_choice[0])(0);
} else {
if (array) buf = &array[0][0];
for (int n = 0; n < nvalues; n++)
(this->*pack_choice[n])(n);
}
}
/* ----------------------------------------------------------------------
count pairs and compute pair info on this proc
only count pair once if newton_pair is off
both atom I,J must be in group
if allflag is set, compute requested info about pair
if forceflag = 1, pair must be within force cutoff, else neighbor cutoff
------------------------------------------------------------------------- */
int ComputePropertyLocal::count_pairs(int allflag, int forceflag)
{
int i,j,m,n,ii,jj,inum,jnum,itype,jtype;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *ilist,*jlist,*numneigh,**firstneigh;
double **x = atom->x;
- int *tag = atom->tag;
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;
// invoke half neighbor list (will copy or build if necessary)
if (allflag == 0) neighbor->build_one(list->index);
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// loop over neighbors of my atoms
// skip if I or J are not in group
double **cutsq = force->pair->cutsq;
m = n = 0;
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];
j &= NEIGHMASK;
if (!(mask[j] & groupbit)) continue;
if (newton_pair == 0 && j >= nlocal) continue;
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 (forceflag && rsq >= cutsq[itype][jtype]) continue;
if (allflag) {
indices[m][0] = i;
indices[m][1] = j;
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
count bonds on this proc
only count bond once if newton_bond is off
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if bond is deleted (type = 0), do not count
if bond is turned off (type < 0), still count
------------------------------------------------------------------------- */
int ComputePropertyLocal::count_bonds(int flag)
{
int i,atom1,atom2;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int m = 0;
for (atom1 = 0; atom1 < nlocal; atom1++) {
if (!(mask[atom1] & groupbit)) continue;
for (i = 0; i < num_bond[atom1]; i++) {
atom2 = atom->map(bond_atom[atom1][i]);
if (atom2 < 0 || !(mask[atom2] & groupbit)) continue;
if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue;
if (bond_type[atom1][i] == 0) continue;
if (flag) {
indices[m][0] = atom1;
indices[m][1] = i;
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
count angles on this proc
only count if 2nd atom is the one storing the angle
all atoms in interaction must be in group
all atoms in interaction must be known to proc
if angle is deleted (type = 0), do not count
if angle is turned off (type < 0), still count
------------------------------------------------------------------------- */
int ComputePropertyLocal::count_angles(int flag)
{
int i,atom1,atom2,atom3;
int *num_angle = atom->num_angle;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int m = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_angle[atom2]; i++) {
if (tag[atom2] != angle_atom2[atom2][i]) continue;
atom1 = atom->map(angle_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(angle_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
if (angle_type[atom2][i] == 0) continue;
if (flag) {
indices[m][0] = atom2;
indices[m][1] = i;
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
count dihedrals on this proc
only count if 2nd atom is the one storing the dihedral
all atoms in interaction must be in group
all atoms in interaction must be known to proc
------------------------------------------------------------------------- */
int ComputePropertyLocal::count_dihedrals(int flag)
{
int i,atom1,atom2,atom3,atom4;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
- int *tag = atom->tag;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int m = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_dihedral[atom2]; i++) {
if (tag[atom2] != dihedral_atom2[atom2][i]) continue;
atom1 = atom->map(dihedral_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(dihedral_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
atom4 = atom->map(dihedral_atom4[atom2][i]);
if (atom4 < 0 || !(mask[atom4] & groupbit)) continue;
if (flag) {
indices[m][0] = atom2;
indices[m][1] = i;
}
m++;
}
}
return m;
}
/* ----------------------------------------------------------------------
count impropers on this proc
only count if 2nd atom is the one storing the improper
all atoms in interaction must be in group
all atoms in interaction must be known to proc
------------------------------------------------------------------------- */
int ComputePropertyLocal::count_impropers(int flag)
{
int i,atom1,atom2,atom3,atom4;
int *num_improper = atom->num_improper;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
- int *tag = atom->tag;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int m = 0;
for (atom2 = 0; atom2 < nlocal; atom2++) {
if (!(mask[atom2] & groupbit)) continue;
for (i = 0; i < num_improper[atom2]; i++) {
if (tag[atom2] != improper_atom2[atom2][i]) continue;
atom1 = atom->map(improper_atom1[atom2][i]);
if (atom1 < 0 || !(mask[atom1] & groupbit)) continue;
atom3 = atom->map(improper_atom3[atom2][i]);
if (atom3 < 0 || !(mask[atom3] & groupbit)) continue;
atom4 = atom->map(improper_atom4[atom2][i]);
if (atom4 < 0 || !(mask[atom4] & groupbit)) continue;
if (flag) {
indices[m][0] = atom2;
indices[m][1] = i;
}
m++;
}
}
return m;
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::reallocate(int n)
{
// grow vector or array and indices array
while (nmax < n) nmax += DELTA;
if (nvalues == 1) {
memory->destroy(vector);
memory->create(vector,nmax,"property/local:vector");
vector_local = vector;
} else {
memory->destroy(array);
memory->create(array,nmax,nvalues,"property/local:array");
array_local = array;
}
memory->destroy(indices);
memory->create(indices,nmax,2,"property/local:indices");
}
/* ----------------------------------------------------------------------
memory usage of local data
------------------------------------------------------------------------- */
double ComputePropertyLocal::memory_usage()
{
double bytes = nmax*nvalues * sizeof(double);
bytes += nmax*2 * sizeof(int);
return bytes;
}
/* ----------------------------------------------------------------------
one method for every keyword compute property/local can output
the atom property is packed into buf starting at n with stride nvalues
customize a new keyword by adding a method
------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_patom1(int n)
{
int i;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
buf[n] = tag[i];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_patom2(int n)
{
int i;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int m = 0; m < ncount; m++) {
i = indices[m][1];
buf[n] = tag[i];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_ptype1(int n)
{
int i;
int *type = atom->type;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
buf[n] = type[i];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_ptype2(int n)
{
int i;
int *type = atom->type;
for (int m = 0; m < ncount; m++) {
i = indices[m][1];
buf[n] = type[i];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_batom1(int n)
{
int i;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
buf[n] = tag[i];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_batom2(int n)
{
int i,j;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = bond_atom[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_btype(int n)
{
int i,j;
int **bond_type = atom->bond_type;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = bond_type[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_aatom1(int n)
{
int i,j;
- int **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom1 = atom->angle_atom1;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = angle_atom1[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_aatom2(int n)
{
int i,j;
- int **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom2 = atom->angle_atom2;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = angle_atom2[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_aatom3(int n)
{
int i,j;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom3 = atom->angle_atom3;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = angle_atom3[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_atype(int n)
{
int i,j;
int **angle_type = atom->angle_type;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = angle_type[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_datom1(int n)
{
int i,j;
- int **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = dihedral_atom1[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_datom2(int n)
{
int i,j;
- int **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = dihedral_atom2[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_datom3(int n)
{
int i,j;
- int **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = dihedral_atom3[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_datom4(int n)
{
int i,j;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = dihedral_atom4[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_dtype(int n)
{
int i,j;
int **dihedral_type = atom->dihedral_type;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = dihedral_type[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_iatom1(int n)
{
int i,j;
- int **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom1 = atom->improper_atom1;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = improper_atom1[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_iatom2(int n)
{
int i,j;
- int **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom2 = atom->improper_atom2;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = improper_atom2[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_iatom3(int n)
{
int i,j;
- int **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom3 = atom->improper_atom3;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = improper_atom3[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_iatom4(int n)
{
int i,j;
- int **improper_atom4 = atom->improper_atom4;
+ tagint **improper_atom4 = atom->improper_atom4;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = improper_atom4[i][j];
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void ComputePropertyLocal::pack_itype(int n)
{
int i,j;
int **improper_type = atom->improper_type;
for (int m = 0; m < ncount; m++) {
i = indices[m][0];
j = indices[m][1];
buf[n] = improper_type[i][j];
n += nvalues;
}
}
diff --git a/src/create_atoms.cpp b/src/create_atoms.cpp
index f83edfa63..1e1f5716d 100644
--- a/src/create_atoms.cpp
+++ b/src/create_atoms.cpp
@@ -1,671 +1,672 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "create_atoms.h"
#include "atom.h"
#include "atom_vec.h"
#include "molecule.h"
#include "comm.h"
#include "irregular.h"
#include "modify.h"
#include "force.h"
+#include "special.h"
#include "fix.h"
#include "domain.h"
#include "lattice.h"
#include "region.h"
#include "random_park.h"
#include "random_mars.h"
#include "math_extra.h"
#include "math_const.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define BIG 1.0e30
#define EPSILON 1.0e-6
enum{BOX,REGION,SINGLE,RANDOM};
enum{ATOM,MOLECULE};
/* ---------------------------------------------------------------------- */
CreateAtoms::CreateAtoms(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void CreateAtoms::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"Create_atoms command before simulation box is defined");
if (modify->nfix_restart_peratom)
error->all(FLERR,"Cannot create_atoms after "
"reading restart file with per-atom info");
// parse arguments
if (narg < 2) error->all(FLERR,"Illegal create_atoms command");
ntype = force->inumeric(FLERR,arg[0]);
int iarg;
if (strcmp(arg[1],"box") == 0) {
style = BOX;
iarg = 2;
} else if (strcmp(arg[1],"region") == 0) {
style = REGION;
if (narg < 3) error->all(FLERR,"Illegal create_atoms command");
nregion = domain->find_region(arg[2]);
if (nregion == -1) error->all(FLERR,
"Create_atoms region ID does not exist");
domain->regions[nregion]->init();
iarg = 3;;
} else if (strcmp(arg[1],"single") == 0) {
style = SINGLE;
if (narg < 5) error->all(FLERR,"Illegal create_atoms command");
xone[0] = force->numeric(FLERR,arg[2]);
xone[1] = force->numeric(FLERR,arg[3]);
xone[2] = force->numeric(FLERR,arg[4]);
iarg = 5;
} else if (strcmp(arg[1],"random") == 0) {
style = RANDOM;
if (narg < 5) error->all(FLERR,"Illegal create_atoms command");
nrandom = force->inumeric(FLERR,arg[2]);
seed = force->inumeric(FLERR,arg[3]);
if (strcmp(arg[4],"NULL") == 0) nregion = -1;
else {
nregion = domain->find_region(arg[4]);
if (nregion == -1) error->all(FLERR,
"Create_atoms region ID does not exist");
domain->regions[nregion]->init();
}
iarg = 5;
} else error->all(FLERR,"Illegal create_atoms command");
// process optional keywords
int scaleflag = 1;
remapflag = 0;
mode = ATOM;
int molseed;
nbasis = domain->lattice->nbasis;
basistype = new int[nbasis];
for (int i = 0; i < nbasis; i++) basistype[i] = ntype;
while (iarg < narg) {
if (strcmp(arg[iarg],"basis") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
int ibasis = force->inumeric(FLERR,arg[iarg+1]);
int itype = force->inumeric(FLERR,arg[iarg+2]);
if (ibasis <= 0 || ibasis > nbasis || itype <= 0 || itype > atom->ntypes)
error->all(FLERR,"Invalid basis setting in create_atoms command");
basistype[ibasis-1] = itype;
iarg += 3;
} else if (strcmp(arg[iarg],"remap") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal create_atoms command");
if (strcmp(arg[iarg+1],"yes") == 0) remapflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) remapflag = 0;
else error->all(FLERR,"Illegal create_atoms command");
iarg += 2;
} else if (strcmp(arg[iarg],"mol") == 0) {
- if (iarg+3 > narg) error->all(FLERR,"Illegal fix create_atoms command");
+ if (iarg+3 > narg) error->all(FLERR,"Illegal create_atoms command");
int imol = atom->find_molecule(arg[iarg+1]);
if (imol == -1)
error->all(FLERR,"Molecule ID for create_atoms does not exist");
mode = MOLECULE;
onemol = atom->molecules[imol];
molseed = force->inumeric(FLERR,arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal create_atoms command");
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
else error->all(FLERR,"Illegal create_atoms command");
iarg += 2;
} else error->all(FLERR,"Illegal create_atoms command");
}
// error checks
if (mode == ATOM && (ntype <= 0 || ntype > atom->ntypes))
error->all(FLERR,"Invalid atom type in create_atoms command");
if (style == RANDOM) {
if (nrandom < 0) error->all(FLERR,"Illegal create_atoms command");
if (seed <= 0) error->all(FLERR,"Illegal create_atoms command");
}
// error check and further setup for mode = MOLECULE
ranmol = NULL;
if (mode == MOLECULE) {
- if (atom->molecule_flag == 0)
- error->all(FLERR,"Create_atoms mol requires atom attribute molecule");
if (onemol->xflag == 0)
error->all(FLERR,"Create_atoms molecule must have coordinates");
if (onemol->typeflag == 0)
error->all(FLERR,"Create_atoms molecule must have atom types");
if (ntype+onemol->maxtype <= 0 || ntype+onemol->maxtype > atom->ntypes)
error->all(FLERR,"Invalid atom type in create_atoms mol command");
+ if (onemol->tag_require && !atom->tag_enable)
+ error->all(FLERR,
+ "Create_atoms molecule has atom IDs, but system does not");
// create_atoms uses geoemetric center of molecule for insertion
onemol->compute_center();
- // molecule random number generator, same for all procs
+ // molecule random number generator, different for each proc
ranmol = new RanMars(lmp,molseed+comm->me);
}
// demand non-none lattice be defined for BOX and REGION
// else setup scaling for SINGLE and RANDOM
// could use domain->lattice->lattice2box() to do conversion of
// lattice to box, but not consistent with other uses of units=lattice
// triclinic remapping occurs in add_single()
if (style == BOX || style == REGION) {
if (nbasis == 0)
error->all(FLERR,"Cannot create atoms with undefined lattice");
} else if (scaleflag == 1) {
xone[0] *= domain->lattice->xlattice;
xone[1] *= domain->lattice->ylattice;
xone[2] *= domain->lattice->zlattice;
}
// set bounds for my proc in sublo[3] & subhi[3]
// if periodic and style = BOX or REGION, i.e. using lattice:
// should create exactly 1 atom when 2 images are both "on" the boundary
// either image may be slightly inside/outside true box due to round-off
// if I am lo proc, decrement lower bound by EPSILON
// this will insure lo image is created
// if I am hi proc, decrement upper bound by 2.0*EPSILON
// this will insure hi image is not created
// thus insertion box is EPSILON smaller than true box
// and is shifted away from true boundary
// which is where atoms are likely to be generated
triclinic = domain->triclinic;
double epsilon[3];
if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON;
else {
epsilon[0] = domain->prd[0] * EPSILON;
epsilon[1] = domain->prd[1] * EPSILON;
epsilon[2] = domain->prd[2] * EPSILON;
}
if (triclinic == 0) {
sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0];
sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1];
sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2];
} else {
sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0];
sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1];
sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2];
}
if (style == BOX || style == REGION) {
if (domain->xperiodic) {
if (comm->myloc[0] == 0) sublo[0] -= epsilon[0];
if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] -= 2.0*epsilon[0];
}
if (domain->yperiodic) {
if (comm->myloc[1] == 0) sublo[1] -= epsilon[1];
if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] -= 2.0*epsilon[1];
}
if (domain->zperiodic) {
if (comm->myloc[2] == 0) sublo[2] -= epsilon[2];
if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] -= 2.0*epsilon[2];
}
}
// add atoms/molecules in one of 3 ways
bigint natoms_previous = atom->natoms;
int nlocal_previous = atom->nlocal;
if (style == SINGLE) add_single();
else if (style == RANDOM) add_random();
else add_lattice();
// invoke set_arrays() for fixes that need initialization of new atoms
int nlocal = atom->nlocal;
for (int m = 0; m < modify->nfix; m++) {
Fix *fix = modify->fix[m];
if (fix->create_attribute)
for (int i = nlocal_previous; i < nlocal; i++)
fix->set_arrays(i);
}
- // new total # of atoms and error check
- // for MOLECULE mode, require atom IDs
+ // set new total # of atoms and error check
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
- if (atom->natoms < 0 || atom->natoms > MAXBIGINT)
+ if (atom->natoms < 0 || atom->natoms >= MAXBIGINT)
error->all(FLERR,"Too many total atoms");
- if (atom->natoms > MAXSMALLINT) {
- if (mode == ATOM) {
- if (comm->me == 0)
- error->warning(FLERR,"Total atom count exceeds ID limit, "
- "atoms will not have individual IDs");
- atom->tag_enable = 0;
- } else error->all(FLERR,"Total atom count exceeds ID limit");
- }
- // for ATOM mode:
- // add IDs for newly created atoms if IDs are still enabled
- // if global map exists, reset it
+ // add IDs for newly created atoms
+ // check that atom IDs are valid
- if (mode == ATOM) {
- if (atom->natoms <= MAXSMALLINT) atom->tag_extend();
- if (atom->map_style) {
- atom->nghost = 0;
- atom->map_init();
- atom->map_set();
- }
+ if (atom->tag_enable) atom->tag_extend();
+ atom->tag_check();
+
+ // if molecular system or user-requested, create global mapping of atoms
+ // zero nghost in case are adding new atoms to existing atoms
+
+ if (atom->molecular || atom->map_user) {
+ atom->nghost = 0;
+ atom->map_init();
+ atom->map_set();
}
// for MOLECULE mode:
- // set atom and molecule IDs for created atoms
+ // set molecule IDs for created atoms if used
+ // reset new molecule bond,angle,etc and special values
// send atoms to new owning procs via irregular comm
- // since not all created atoms will be within my sub-domain
+ // since not all atoms I created will be within my sub-domain
+ // perform special list build if needed
if (mode == MOLECULE) {
- // add atom IDs for newly created atoms and reset global map
- // global map must exist since atom->molecular is required to be set
-
- atom->tag_extend();
- atom->nghost = 0;
- atom->map_init();
- atom->map_set();
-
- // maxmol = max molecule ID across all procs, for previous atoms
+ // molcreate = # of molecules I created
- int *molecule = atom->molecule;
+ int molcreate = (atom->nlocal - nlocal_previous) / onemol->natoms;
- int max = 0;
- for (int i = 0; i < nlocal_previous; i++) max = MAX(max,molecule[i]);
- int maxmol;
- MPI_Allreduce(&max,&maxmol,1,MPI_INT,MPI_MAX,world);
-
- // molcreate = # of molecules I created
+ // maxmol = max molecule ID across all procs, for previous atoms
// moloffset = max molecule ID for all molecules owned by previous procs
// including molecules existing before this creation
- int molcreate = (atom->nlocal - nlocal_previous) / onemol->natoms;
int moloffset;
- MPI_Scan(&molcreate,&moloffset,1,MPI_INT,MPI_SUM,world);
- moloffset = moloffset - molcreate + maxmol;
+ int *molecule = atom->molecule;
+ if (molecule) {
+ int max = 0;
+ for (int i = 0; i < nlocal_previous; i++) max = MAX(max,molecule[i]);
+ int maxmol;
+ MPI_Allreduce(&max,&maxmol,1,MPI_INT,MPI_MAX,world);
+ MPI_Scan(&molcreate,&moloffset,1,MPI_INT,MPI_SUM,world);
+ moloffset = moloffset - molcreate + maxmol;
+ }
// loop over molecules I created
// set their molecule ID
// reset their bond,angle,etc and special values
int natoms = onemol->natoms;
+ tagint offset = 0;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_bond = atom->num_bond;
int *num_angle = atom->num_angle;
int *num_dihedral = atom->num_dihedral;
int *num_improper = atom->num_improper;
- int **bond_atom = atom->bond_atom;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
+ tagint **bond_atom = atom->bond_atom;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
int **nspecial = atom->nspecial;
- int **special = atom->special;
+ tagint **special = atom->special;
int ilocal = nlocal_previous;
for (int i = 0; i < molcreate; i++) {
- int offset = tag[ilocal]-1;
+ if (tag) offset = tag[ilocal]-1;
for (int m = 0; m < natoms; m++) {
- molecule[ilocal] = moloffset + i+1;
+ if (molecule) molecule[ilocal] = moloffset + i+1;
if (onemol->bondflag)
for (int j = 0; j < num_bond[ilocal]; j++)
bond_atom[ilocal][j] += offset;
if (onemol->angleflag)
for (int j = 0; j < num_angle[ilocal]; j++) {
angle_atom1[ilocal][j] += offset;
angle_atom2[ilocal][j] += offset;
angle_atom3[ilocal][j] += offset;
}
if (onemol->dihedralflag)
for (int j = 0; j < num_dihedral[ilocal]; j++) {
dihedral_atom1[ilocal][j] += offset;
dihedral_atom2[ilocal][j] += offset;
dihedral_atom3[ilocal][j] += offset;
dihedral_atom4[ilocal][j] += offset;
}
if (onemol->improperflag)
for (int j = 0; j < num_improper[ilocal]; j++) {
improper_atom1[ilocal][j] += offset;
improper_atom2[ilocal][j] += offset;
improper_atom3[ilocal][j] += offset;
improper_atom4[ilocal][j] += offset;
}
if (onemol->specialflag)
for (int j = 0; j < nspecial[ilocal][2]; j++)
special[ilocal][j] += offset;
ilocal++;
}
}
// perform irregular comm to migrate atoms to new owning procs
double **x = atom->x;
imageint *image = atom->image;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);
if (domain->triclinic) domain->x2lamda(atom->nlocal);
domain->reset_box();
Irregular *irregular = new Irregular(lmp);
irregular->migrate_atoms();
delete irregular;
if (domain->triclinic) domain->lamda2x(atom->nlocal);
}
// clean up
delete ranmol;
if (domain->lattice) delete [] basistype;
// print status
if (comm->me == 0) {
if (screen)
fprintf(screen,"Created " BIGINT_FORMAT " atoms\n",
atom->natoms-natoms_previous);
if (logfile)
fprintf(logfile,"Created " BIGINT_FORMAT " atoms\n",
atom->natoms-natoms_previous);
}
+
+ // for MOLECULE mode:
+ // create special bond lists for molecular systems
+ // only if onemol added bonds but not special info
+
+ if (mode == MOLECULE) {
+ if (atom->molecular && onemol->bondflag && !onemol->specialflag) {
+ Special special(lmp);
+ special.build();
+ }
+ }
}
/* ----------------------------------------------------------------------
add single atom with coords at xone if it's in my sub-box
if triclinic, xone is in lamda coords
------------------------------------------------------------------------- */
void CreateAtoms::add_single()
{
// remap atom if requested
if (remapflag) {
imageint imagetmp = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
domain->remap(xone,imagetmp);
}
// if triclinic, convert to lamda coords (0-1)
double lamda[3],*coord;
if (triclinic) {
domain->x2lamda(xone,lamda);
coord = lamda;
} else coord = xone;
// if atom/molecule is in my subbox, create it
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2]) {
if (mode == ATOM) atom->avec->create_atom(ntype,xone);
else add_molecule(xone);
}
}
-
/* ----------------------------------------------------------------------
add Nrandom atoms at random locations
------------------------------------------------------------------------- */
void CreateAtoms::add_random()
{
double xlo,ylo,zlo,xhi,yhi,zhi,zmid;
double lamda[3],*coord;
double *boxlo,*boxhi;
// random number generator, same for all procs
RanPark *random = new RanPark(lmp,seed);
// bounding box for atom creation
// in real units, even if triclinic
// only limit bbox by region if its bboxflag is set (interior region)
if (triclinic == 0) {
xlo = domain->boxlo[0]; xhi = domain->boxhi[0];
ylo = domain->boxlo[1]; yhi = domain->boxhi[1];
zlo = domain->boxlo[2]; zhi = domain->boxhi[2];
zmid = zlo + 0.5*(zhi-zlo);
} else {
xlo = domain->boxlo_bound[0]; xhi = domain->boxhi_bound[0];
ylo = domain->boxlo_bound[1]; yhi = domain->boxhi_bound[1];
zlo = domain->boxlo_bound[2]; zhi = domain->boxhi_bound[2];
zmid = zlo + 0.5*(zhi-zlo);
boxlo = domain->boxlo_lamda;
boxhi = domain->boxhi_lamda;
}
if (nregion >= 0 && domain->regions[nregion]->bboxflag) {
xlo = MAX(xlo,domain->regions[nregion]->extent_xlo);
xhi = MIN(xhi,domain->regions[nregion]->extent_xhi);
ylo = MAX(ylo,domain->regions[nregion]->extent_ylo);
yhi = MIN(yhi,domain->regions[nregion]->extent_yhi);
zlo = MAX(zlo,domain->regions[nregion]->extent_zlo);
zhi = MIN(zhi,domain->regions[nregion]->extent_zhi);
}
// generate random positions for each new atom/molecule within bounding box
// iterate until atom is within region and triclinic simulation box
// if final atom position is in my subbox, create it
if (xlo > xhi || ylo > yhi || zlo > zhi)
error->all(FLERR,"No overlap of box and region for create_atoms");
int valid;
for (int i = 0; i < nrandom; i++) {
while (1) {
xone[0] = xlo + random->uniform() * (xhi-xlo);
xone[1] = ylo + random->uniform() * (yhi-ylo);
xone[2] = zlo + random->uniform() * (zhi-zlo);
if (domain->dimension == 2) xone[2] = zmid;
valid = 1;
if (nregion >= 0 &&
domain->regions[nregion]->match(xone[0],xone[1],xone[2]) == 0)
valid = 0;
if (triclinic) {
domain->x2lamda(xone,lamda);
coord = lamda;
if (coord[0] < boxlo[0] || coord[0] >= boxhi[0] ||
coord[1] < boxlo[1] || coord[1] >= boxhi[1] ||
coord[2] < boxlo[2] || coord[2] >= boxhi[2]) valid = 0;
} else coord = xone;
if (valid) break;
}
// if triclinic, coord is now in lamda units
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2]) {
if (mode == ATOM) atom->avec->create_atom(ntype,xone);
else add_molecule(xone);
}
}
// clean-up
delete random;
}
/* ----------------------------------------------------------------------
add many atoms by looping over lattice
------------------------------------------------------------------------- */
void CreateAtoms::add_lattice()
{
// convert 8 corners of my subdomain from box coords to lattice coords
// for orthogonal, use corner pts of my subbox
// for triclinic, use bounding box of my subbox
// xyz min to max = bounding box around the domain corners in lattice space
double bboxlo[3],bboxhi[3];
if (triclinic == 0) {
bboxlo[0] = domain->sublo[0]; bboxhi[0] = domain->subhi[0];
bboxlo[1] = domain->sublo[1]; bboxhi[1] = domain->subhi[1];
bboxlo[2] = domain->sublo[2]; bboxhi[2] = domain->subhi[2];
} else domain->bbox(domain->sublo_lamda,domain->subhi_lamda,bboxlo,bboxhi);
double xmin,ymin,zmin,xmax,ymax,zmax;
xmin = ymin = zmin = BIG;
xmax = ymax = zmax = -BIG;
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxlo[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxlo[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxlo[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
domain->lattice->bbox(1,bboxhi[0],bboxhi[1],bboxhi[2],
xmin,ymin,zmin,xmax,ymax,zmax);
// ilo:ihi,jlo:jhi,klo:khi = loop bounds for lattice overlap of my subbox
// overlap = any part of a unit cell (face,edge,pt) in common with my subbox
// in lattice space, subbox is a tilted box
// but bbox of subbox is aligned with lattice axes
// so ilo:khi unit cells should completely tile bounding box
// decrement lo, increment hi to avoid round-off issues in lattice->bbox(),
// which can lead to missing atoms in rare cases
// extra decrement of lo if min < 0, since static_cast(-1.5) = -1
int ilo,ihi,jlo,jhi,klo,khi;
ilo = static_cast<int> (xmin) - 1;
jlo = static_cast<int> (ymin) - 1;
klo = static_cast<int> (zmin) - 1;
ihi = static_cast<int> (xmax) + 1;
jhi = static_cast<int> (ymax) + 1;
khi = static_cast<int> (zmax) + 1;
if (xmin < 0.0) ilo--;
if (ymin < 0.0) jlo--;
if (zmin < 0.0) klo--;
// iterate on 3d periodic lattice of unit cells using loop bounds
// iterate on nbasis atoms in each unit cell
// convert lattice coords to box coords
// add atom or molecule (on each basis point) if it meets all criteria
double **basis = domain->lattice->basis;
double x[3],lamda[3];
double *coord;
int i,j,k,m;
for (k = klo; k <= khi; k++)
for (j = jlo; j <= jhi; j++)
for (i = ilo; i <= ihi; i++)
for (m = 0; m < nbasis; m++) {
x[0] = i + basis[m][0];
x[1] = j + basis[m][1];
x[2] = k + basis[m][2];
// convert from lattice coords to box coords
domain->lattice->lattice2box(x[0],x[1],x[2]);
// if a region was specified, test if atom is in it
if (style == REGION)
if (!domain->regions[nregion]->match(x[0],x[1],x[2])) continue;
// test if atom/molecule position is in my subbox
if (triclinic) {
domain->x2lamda(x,lamda);
coord = lamda;
} else coord = x;
if (coord[0] < sublo[0] || coord[0] >= subhi[0] ||
coord[1] < sublo[1] || coord[1] >= subhi[1] ||
coord[2] < sublo[2] || coord[2] >= subhi[2]) continue;
// add the atom or entire molecule to my list of atoms
if (mode == ATOM) atom->avec->create_atom(basistype[m],x);
else add_molecule(x);
}
}
/* ----------------------------------------------------------------------
add a randomly rotated molecule with its center at center
------------------------------------------------------------------------- */
void CreateAtoms::add_molecule(double *center)
{
int n;
double r[3],rotmat[3][3],quat[4],xnew[3];
if (domain->dimension == 3) {
r[0] = ranmol->uniform() - 0.5;
r[1] = ranmol->uniform() - 0.5;
r[2] = ranmol->uniform() - 0.5;
} else {
r[0] = r[1] = 0.0;
r[2] = 1.0;
}
double theta = ranmol->uniform() * MY_2PI;
MathExtra::norm3(r);
MathExtra::axisangle_to_quat(r,theta,quat);
MathExtra::quat_to_mat(quat,rotmat);
// create atoms in molecule with atom ID = 0 and mol ID = 0
// reset in caller after all moleclues created by all procs
// pass add_molecule_atom an offset of 0 since don't know
// max tag of atoms in previous molecules at this point
int natoms = onemol->natoms;
for (int m = 0; m < natoms; m++) {
MathExtra::matvec(rotmat,onemol->dx[m],xnew);
MathExtra::add3(xnew,center,xnew);
atom->avec->create_atom(ntype+onemol->type[m],xnew);
n = atom->nlocal - 1;
atom->add_molecule_atom(onemol,m,n,0);
}
}
diff --git a/src/delete_atoms.cpp b/src/delete_atoms.cpp
index db752d0b2..ac1c354d2 100644
--- a/src/delete_atoms.cpp
+++ b/src/delete_atoms.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.
------------------------------------------------------------------------- */
#include "stdlib.h"
#include "string.h"
#include "delete_atoms.h"
#include "atom.h"
#include "atom_vec.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "group.h"
#include "region.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
#include <map>
using namespace LAMMPS_NS;
// allocate space for static class variable
DeleteAtoms *DeleteAtoms::cptr;
/* ---------------------------------------------------------------------- */
DeleteAtoms::DeleteAtoms(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void DeleteAtoms::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"Delete_atoms command before simulation box is defined");
if (narg < 1) error->all(FLERR,"Illegal delete_atoms command");
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use delete_atoms unless atoms have IDs");
// store state before delete
bigint natoms_previous = atom->natoms;
// delete the atoms
if (strcmp(arg[0],"group") == 0) delete_group(narg,arg);
else if (strcmp(arg[0],"region") == 0) delete_region(narg,arg);
else if (strcmp(arg[0],"overlap") == 0) delete_overlap(narg,arg);
else if (strcmp(arg[0],"porosity") == 0) delete_porosity(narg,arg);
else error->all(FLERR,"Illegal delete_atoms command");
// delete local atoms flagged in dlist
// reset nlocal
AtomVec *avec = atom->avec;
int nlocal = atom->nlocal;
int i = 0;
while (i < nlocal) {
if (dlist[i]) {
avec->copy(nlocal-1,i,1);
dlist[i] = dlist[nlocal-1];
nlocal--;
} else i++;
}
atom->nlocal = nlocal;
memory->destroy(dlist);
// if non-molecular system and compress flag set,
// reset atom tags to be contiguous
// set all atom IDs to 0, call tag_extend()
if (atom->molecular == 0 && compress_flag) {
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (i = 0; i < nlocal; i++) tag[i] = 0;
atom->tag_extend();
}
// reset atom->natoms
// reset atom->map if it exists
// set nghost to 0 so old ghosts of deleted atoms won't be mapped
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (atom->map_style) {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
// print before and after atom count
bigint ndelete = natoms_previous - atom->natoms;
if (comm->me == 0) {
if (screen) fprintf(screen,"Deleted " BIGINT_FORMAT
" atoms, new total = " BIGINT_FORMAT "\n",
ndelete,atom->natoms);
if (logfile) fprintf(logfile,"Deleted " BIGINT_FORMAT
" atoms, new total = " BIGINT_FORMAT "\n",
ndelete,atom->natoms);
}
}
/* ----------------------------------------------------------------------
delete all atoms in group
group will still exist
------------------------------------------------------------------------- */
void DeleteAtoms::delete_group(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal delete_atoms command");
int igroup = group->find(arg[1]);
if (igroup == -1) error->all(FLERR,"Could not find delete_atoms group ID");
options(narg-2,&arg[2]);
// allocate and initialize deletion list
int nlocal = atom->nlocal;
memory->create(dlist,nlocal,"delete_atoms:dlist");
for (int i = 0; i < nlocal; i++) dlist[i] = 0;
int *mask = atom->mask;
int groupbit = group->bitmask[igroup];
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) dlist[i] = 1;
}
/* ----------------------------------------------------------------------
delete all atoms in region
if mol_flag is set, also delete atoms in molecules with any deletions
------------------------------------------------------------------------- */
void DeleteAtoms::delete_region(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal delete_atoms command");
int iregion = domain->find_region(arg[1]);
if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID");
options(narg-2,&arg[2]);
// allocate and initialize deletion list
int nlocal = atom->nlocal;
memory->create(dlist,nlocal,"delete_atoms:dlist");
for (int i = 0; i < nlocal; i++) dlist[i] = 0;
double **x = atom->x;
for (int i = 0; i < nlocal; i++)
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) dlist[i] = 1;
if (mol_flag == 0) return;
// delete entire molecules if any atom in molecule was deleted
// store list of molecule IDs I delete atoms from in list
// pass list from proc to proc via ring communication
hash = new std::map<int,int>();
int *molecule = atom->molecule;
for (int i = 0; i < nlocal; i++)
if (dlist[i] && hash->find(molecule[i]) == hash->end())
(*hash)[molecule[i]] = 1;
int n = hash->size();
int *list;
memory->create(list,n,"delete_atoms:list");
n = 0;
std::map<int,int>::iterator pos;
for (pos = hash->begin(); pos != hash->end(); ++pos) list[n++] = pos->first;
cptr = this;
comm->ring(n,sizeof(int),list,1,molring,NULL);
delete hash;
memory->destroy(list);
}
/* ----------------------------------------------------------------------
callback from comm->ring()
cbuf = list of N molecule IDs, put them in hash
loop over my atoms, if matches moleculed ID in hash, delete that atom
------------------------------------------------------------------------- */
void DeleteAtoms::molring(int n, char *cbuf)
{
int *list = (int *) cbuf;
int *dlist = cptr->dlist;
std::map<int,int> *hash = cptr->hash;
int nlocal = cptr->atom->nlocal;
int *molecule = cptr->atom->molecule;
hash->clear();
for (int i = 0; i < n; i++) (*hash)[list[i]] = 1;
for (int i = 0; i < nlocal; i++)
if (hash->find(molecule[i]) != hash->end()) dlist[i] = 1;
}
/* ----------------------------------------------------------------------
delete atoms so there are no pairs within cutoff
which atoms are deleted depends on ordering of atoms within proc
deletions can vary with processor count
no guarantee that minimium number of atoms will be deleted
------------------------------------------------------------------------- */
void DeleteAtoms::delete_overlap(int narg, char **arg)
{
if (narg < 4) error->all(FLERR,"Illegal delete_atoms command");
// read args
double cut = force->numeric(FLERR,arg[1]);
double cutsq = cut*cut;
int igroup1 = group->find(arg[2]);
int igroup2 = group->find(arg[3]);
if (igroup1 < 0 || igroup2 < 0)
error->all(FLERR,"Could not find delete_atoms group ID");
options(narg-4,&arg[4]);
int group1bit = group->bitmask[igroup1];
int group2bit = group->bitmask[igroup2];
if (comm->me == 0 && screen)
fprintf(screen,"System init for delete_atoms ...\n");
// request a full neighbor list for use by this command
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->command = 1;
neighbor->requests[irequest]->half = 0;
neighbor->requests[irequest]->full = 1;
neighbor->requests[irequest]->occasional = 1;
// init entire system since comm->borders and neighbor->build is done
// comm::init needs neighbor::init needs pair::init needs kspace::init, etc
lmp->init();
// error check on cutoff
// if no pair style, neighbor list will be empty
if (force->pair == NULL)
error->all(FLERR,"Delete_atoms requires a pair style be defined");
if (cut > neighbor->cutneighmax)
error->all(FLERR,"Delete_atoms cutoff > neighbor cutoff");
// setup domain, communication and neighboring
// acquire ghosts
// build neighbor list based on earlier request
if (domain->triclinic) domain->x2lamda(atom->nlocal);
domain->pbc();
domain->reset_box();
comm->setup();
if (neighbor->style) neighbor->setup_bins();
comm->exchange();
comm->borders();
if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
NeighList *list = neighbor->lists[irequest];
neighbor->build_one(irequest);
// allocate and initialize deletion list
// must be after exchange potentially changes nlocal
int nlocal = atom->nlocal;
memory->create(dlist,nlocal,"delete_atoms:dlist");
for (int i = 0; i < nlocal; i++) dlist[i] = 0;
// double loop over owned atoms and their full neighbor list
// at end of loop, there are no more overlaps
// only ever delete owned atom I, never J even if owned
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
double **x = atom->x;
double *special_coul = force->special_coul;
double *special_lj = force->special_lj;
int i,j,ii,jj,inum,jnum;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *ilist,*jlist,*numneigh,**firstneigh;
double factor_lj,factor_coul;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
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];
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;
// only consider deletion if I,J distance < cutoff
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq >= cutsq) continue;
// only consider deletion if I,J are in groups 1,2 respectively
// true whether J is owned or ghost atom
if (!(mask[i] & group1bit)) continue;
if (!(mask[j] & group2bit)) continue;
// J is owned atom:
// delete atom I if atom J has not already been deleted
// J is ghost atom:
// delete atom I if J,I is not a candidate deletion pair
// due to being in groups 1,2 respectively
// if they are candidate pair, then either:
// another proc owns J and could delete J
// J is a ghost of another of my owned atoms, and I could delete J
// test on tags of I,J insures that only I or J is deleted
if (j < nlocal) {
if (dlist[j]) continue;
} else if ((mask[i] & group2bit) && (mask[j] & group1bit)) {
if (tag[i] > tag[j]) continue;
}
dlist[i] = 1;
break;
}
}
}
/* ----------------------------------------------------------------------
create porosity by deleting atoms in a specified region
------------------------------------------------------------------------- */
void DeleteAtoms::delete_porosity(int narg, char **arg)
{
if (narg < 4) error->all(FLERR,"Illegal delete_atoms command");
int iregion = domain->find_region(arg[1]);
if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID");
double porosity_fraction = force->numeric(FLERR,arg[2]);
int seed = force->inumeric(FLERR,arg[3]);
options(narg-4,&arg[4]);
RanMars *random = new RanMars(lmp,seed + comm->me);
// allocate and initialize deletion list
int nlocal = atom->nlocal;
memory->create(dlist,nlocal,"delete_atoms:dlist");
for (int i = 0; i < nlocal; i++) dlist[i] = 0;
double **x = atom->x;
for (int i = 0; i < nlocal; i++)
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
if (random->uniform() <= porosity_fraction) dlist[i] = 1;
}
/* ----------------------------------------------------------------------
process command options
------------------------------------------------------------------------- */
void DeleteAtoms::options(int narg, char **arg)
{
compress_flag = 1;
mol_flag = 0;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"compress") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal delete_atoms command");
if (strcmp(arg[iarg+1],"yes") == 0) compress_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) compress_flag = 0;
else error->all(FLERR,"Illegal delete_atoms command");
iarg += 2;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal delete_atoms command");
if (strcmp(arg[iarg+1],"yes") == 0) mol_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) mol_flag = 0;
else error->all(FLERR,"Illegal delete_atoms command");
iarg += 2;
} else error->all(FLERR,"Illegal delete_atoms command");
}
}
diff --git a/src/domain.cpp b/src/domain.cpp
index 862aa75c3..135591b11 100644
--- a/src/domain.cpp
+++ b/src/domain.cpp
@@ -1,1667 +1,1667 @@
/* ----------------------------------------------------------------------
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) : Pieter in 't Veld (SNL)
------------------------------------------------------------------------- */
#include "mpi.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "math.h"
#include "domain.h"
#include "style_region.h"
#include "atom.h"
#include "force.h"
#include "kspace.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "fix_deform.h"
#include "region.h"
#include "lattice.h"
#include "comm.h"
#include "output.h"
#include "thermo.h"
#include "universe.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define BIG 1.0e20
#define SMALL 1.0e-4
#define DELTAREGION 4
#define BONDSTRETCH 1.1
enum{NO_REMAP,X_REMAP,V_REMAP}; // same as fix_deform.cpp
enum{IGNORE,WARN,ERROR}; // same as thermo.cpp
/* ----------------------------------------------------------------------
default is periodic
------------------------------------------------------------------------- */
Domain::Domain(LAMMPS *lmp) : Pointers(lmp)
{
box_exist = 0;
dimension = 3;
nonperiodic = 0;
xperiodic = yperiodic = zperiodic = 1;
periodicity[0] = xperiodic;
periodicity[1] = yperiodic;
periodicity[2] = zperiodic;
boundary[0][0] = boundary[0][1] = 0;
boundary[1][0] = boundary[1][1] = 0;
boundary[2][0] = boundary[2][1] = 0;
triclinic = 0;
tiltsmall = 1;
boxlo[0] = boxlo[1] = boxlo[2] = -0.5;
boxhi[0] = boxhi[1] = boxhi[2] = 0.5;
xy = xz = yz = 0.0;
h[3] = h[4] = h[5] = 0.0;
h_inv[3] = h_inv[4] = h_inv[5] = 0.0;
h_rate[0] = h_rate[1] = h_rate[2] =
h_rate[3] = h_rate[4] = h_rate[5] = 0.0;
h_ratelo[0] = h_ratelo[1] = h_ratelo[2] = 0.0;
prd_lamda[0] = prd_lamda[1] = prd_lamda[2] = 1.0;
prd_half_lamda[0] = prd_half_lamda[1] = prd_half_lamda[2] = 0.5;
boxlo_lamda[0] = boxlo_lamda[1] = boxlo_lamda[2] = 0.0;
boxhi_lamda[0] = boxhi_lamda[1] = boxhi_lamda[2] = 1.0;
lattice = NULL;
char **args = new char*[2];
args[0] = (char *) "none";
args[1] = (char *) "1.0";
set_lattice(2,args);
delete [] args;
nregion = maxregion = 0;
regions = NULL;
}
/* ---------------------------------------------------------------------- */
Domain::~Domain()
{
delete lattice;
for (int i = 0; i < nregion; i++) delete regions[i];
memory->sfree(regions);
}
/* ---------------------------------------------------------------------- */
void Domain::init()
{
// set box_change flags if box size/shape/sub-domains ever change
// due to shrink-wrapping or fixes that change box size/shape/sub-domains
box_change_size = box_change_shape = box_change_domain = 0;
if (nonperiodic == 2) box_change_size = 1;
for (int i = 0; i < modify->nfix; i++) {
if (modify->fix[i]->box_change_size) box_change_size = 1;
if (modify->fix[i]->box_change_shape) box_change_shape = 1;
if (modify->fix[i]->box_change_domain) box_change_domain = 1;
}
box_change = 0;
if (box_change_size || box_change_shape || box_change_domain) box_change = 1;
// check for fix deform
deform_flag = deform_vremap = deform_groupbit = 0;
for (int i = 0; i < modify->nfix; i++)
if (strcmp(modify->fix[i]->style,"deform") == 0) {
deform_flag = 1;
if (((FixDeform *) modify->fix[i])->remapflag == V_REMAP) {
deform_vremap = 1;
deform_groupbit = modify->fix[i]->groupbit;
}
}
// region inits
for (int i = 0; i < nregion; i++) regions[i]->init();
}
/* ----------------------------------------------------------------------
set initial global box
assumes boxlo/hi and triclinic tilts are already set
------------------------------------------------------------------------- */
void Domain::set_initial_box()
{
// error checks for orthogonal and triclinic domains
if (boxlo[0] >= boxhi[0] || boxlo[1] >= boxhi[1] || boxlo[2] >= boxhi[2])
error->one(FLERR,"Box bounds are invalid");
if (domain->dimension == 2 && (xz != 0.0 || yz != 0.0))
error->all(FLERR,"Cannot skew triclinic box in z for 2d simulation");
// error check or warning on triclinic tilt factors
if (triclinic) {
if ((fabs(xy/(boxhi[0]-boxlo[0])) > 0.5 && xperiodic) ||
(fabs(xz/(boxhi[0]-boxlo[0])) > 0.5 && xperiodic) ||
(fabs(yz/(boxhi[1]-boxlo[1])) > 0.5 && yperiodic)) {
if (tiltsmall)
error->all(FLERR,"Triclinic box skew is too large");
else if (comm->me == 0)
error->warning(FLERR,"Triclinic box skew is large");
}
}
// set small based on box size and SMALL
// this works for any unit system
small[0] = SMALL * (boxhi[0] - boxlo[0]);
small[1] = SMALL * (boxhi[1] - boxlo[1]);
small[2] = SMALL * (boxhi[2] - boxlo[2]);
// adjust box lo/hi for shrink-wrapped dims
if (boundary[0][0] == 2) boxlo[0] -= small[0];
else if (boundary[0][0] == 3) minxlo = boxlo[0];
if (boundary[0][1] == 2) boxhi[0] += small[0];
else if (boundary[0][1] == 3) minxhi = boxhi[0];
if (boundary[1][0] == 2) boxlo[1] -= small[1];
else if (boundary[1][0] == 3) minylo = boxlo[1];
if (boundary[1][1] == 2) boxhi[1] += small[1];
else if (boundary[1][1] == 3) minyhi = boxhi[1];
if (boundary[2][0] == 2) boxlo[2] -= small[2];
else if (boundary[2][0] == 3) minzlo = boxlo[2];
if (boundary[2][1] == 2) boxhi[2] += small[2];
else if (boundary[2][1] == 3) minzhi = boxhi[2];
}
/* ----------------------------------------------------------------------
set global box params
assumes boxlo/hi and triclinic tilts are already set
------------------------------------------------------------------------- */
void Domain::set_global_box()
{
prd[0] = xprd = boxhi[0] - boxlo[0];
prd[1] = yprd = boxhi[1] - boxlo[1];
prd[2] = zprd = boxhi[2] - boxlo[2];
h[0] = xprd;
h[1] = yprd;
h[2] = zprd;
h_inv[0] = 1.0/h[0];
h_inv[1] = 1.0/h[1];
h_inv[2] = 1.0/h[2];
prd_half[0] = xprd_half = 0.5*xprd;
prd_half[1] = yprd_half = 0.5*yprd;
prd_half[2] = zprd_half = 0.5*zprd;
if (triclinic) {
h[3] = yz;
h[4] = xz;
h[5] = xy;
h_inv[3] = -h[3] / (h[1]*h[2]);
h_inv[4] = (h[3]*h[5] - h[1]*h[4]) / (h[0]*h[1]*h[2]);
h_inv[5] = -h[5] / (h[0]*h[1]);
boxlo_bound[0] = MIN(boxlo[0],boxlo[0]+xy);
boxlo_bound[0] = MIN(boxlo_bound[0],boxlo_bound[0]+xz);
boxlo_bound[1] = MIN(boxlo[1],boxlo[1]+yz);
boxlo_bound[2] = boxlo[2];
boxhi_bound[0] = MAX(boxhi[0],boxhi[0]+xy);
boxhi_bound[0] = MAX(boxhi_bound[0],boxhi_bound[0]+xz);
boxhi_bound[1] = MAX(boxhi[1],boxhi[1]+yz);
boxhi_bound[2] = boxhi[2];
}
}
/* ----------------------------------------------------------------------
set lamda box params
assumes global box is defined and proc assignment has been made
uses comm->xyz_split to define subbox boundaries in consistent manner
------------------------------------------------------------------------- */
void Domain::set_lamda_box()
{
int *myloc = comm->myloc;
double *xsplit = comm->xsplit;
double *ysplit = comm->ysplit;
double *zsplit = comm->zsplit;
sublo_lamda[0] = xsplit[myloc[0]];
subhi_lamda[0] = xsplit[myloc[0]+1];
sublo_lamda[1] = ysplit[myloc[1]];
subhi_lamda[1] = ysplit[myloc[1]+1];
sublo_lamda[2] = zsplit[myloc[2]];
subhi_lamda[2] = zsplit[myloc[2]+1];
}
/* ----------------------------------------------------------------------
set local subbox params for orthogonal boxes
assumes global box is defined and proc assignment has been made
uses comm->xyz_split to define subbox boundaries in consistent manner
insure subhi[max] = boxhi
------------------------------------------------------------------------- */
void Domain::set_local_box()
{
int *myloc = comm->myloc;
int *procgrid = comm->procgrid;
double *xsplit = comm->xsplit;
double *ysplit = comm->ysplit;
double *zsplit = comm->zsplit;
if (triclinic == 0) {
sublo[0] = boxlo[0] + xprd*xsplit[myloc[0]];
if (myloc[0] < procgrid[0]-1)
subhi[0] = boxlo[0] + xprd*xsplit[myloc[0]+1];
else subhi[0] = boxhi[0];
sublo[1] = boxlo[1] + yprd*ysplit[myloc[1]];
if (myloc[1] < procgrid[1]-1)
subhi[1] = boxlo[1] + yprd*ysplit[myloc[1]+1];
else subhi[1] = boxhi[1];
sublo[2] = boxlo[2] + zprd*zsplit[myloc[2]];
if (myloc[2] < procgrid[2]-1)
subhi[2] = boxlo[2] + zprd*zsplit[myloc[2]+1];
else subhi[2] = boxhi[2];
}
}
/* ----------------------------------------------------------------------
reset global & local boxes due to global box boundary changes
if shrink-wrapped, determine atom extent and reset boxlo/hi
for triclinic, atoms must be in lamda coords (0-1) before reset_box is called
------------------------------------------------------------------------- */
void Domain::reset_box()
{
// perform shrink-wrapping
// compute extent of atoms on this proc
// for triclinic, this is done in lamda space
if (nonperiodic == 2) {
double extent[3][2],all[3][2];
extent[2][0] = extent[1][0] = extent[0][0] = BIG;
extent[2][1] = extent[1][1] = extent[0][1] = -BIG;
double **x = atom->x;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
extent[0][0] = MIN(extent[0][0],x[i][0]);
extent[0][1] = MAX(extent[0][1],x[i][0]);
extent[1][0] = MIN(extent[1][0],x[i][1]);
extent[1][1] = MAX(extent[1][1],x[i][1]);
extent[2][0] = MIN(extent[2][0],x[i][2]);
extent[2][1] = MAX(extent[2][1],x[i][2]);
}
// compute extent across all procs
// flip sign of MIN to do it in one Allreduce MAX
extent[0][0] = -extent[0][0];
extent[1][0] = -extent[1][0];
extent[2][0] = -extent[2][0];
MPI_Allreduce(extent,all,6,MPI_DOUBLE,MPI_MAX,world);
// for triclinic, convert back to box coords before changing box
if (triclinic) lamda2x(atom->nlocal);
// in shrink-wrapped dims, set box by atom extent
// if minimum set, enforce min box size settings
// for triclinic, convert lamda extent to box coords, then set box lo/hi
// decided NOT to do the next comment - don't want to sneakily change tilt
// for triclinic, adjust tilt factors if 2nd dim is shrink-wrapped,
// so that displacement in 1st dim stays the same
if (triclinic == 0) {
if (xperiodic == 0) {
if (boundary[0][0] == 2) boxlo[0] = -all[0][0] - small[0];
else if (boundary[0][0] == 3)
boxlo[0] = MIN(-all[0][0]-small[0],minxlo);
if (boundary[0][1] == 2) boxhi[0] = all[0][1] + small[0];
else if (boundary[0][1] == 3) boxhi[0] = MAX(all[0][1]+small[0],minxhi);
if (boxlo[0] > boxhi[0]) error->all(FLERR,"Illegal simulation box");
}
if (yperiodic == 0) {
if (boundary[1][0] == 2) boxlo[1] = -all[1][0] - small[1];
else if (boundary[1][0] == 3)
boxlo[1] = MIN(-all[1][0]-small[1],minylo);
if (boundary[1][1] == 2) boxhi[1] = all[1][1] + small[1];
else if (boundary[1][1] == 3) boxhi[1] = MAX(all[1][1]+small[1],minyhi);
if (boxlo[1] > boxhi[1]) error->all(FLERR,"Illegal simulation box");
}
if (zperiodic == 0) {
if (boundary[2][0] == 2) boxlo[2] = -all[2][0] - small[2];
else if (boundary[2][0] == 3)
boxlo[2] = MIN(-all[2][0]-small[2],minzlo);
if (boundary[2][1] == 2) boxhi[2] = all[2][1] + small[2];
else if (boundary[2][1] == 3) boxhi[2] = MAX(all[2][1]+small[2],minzhi);
if (boxlo[2] > boxhi[2]) error->all(FLERR,"Illegal simulation box");
}
} else {
double lo[3],hi[3];
if (xperiodic == 0) {
lo[0] = -all[0][0]; lo[1] = 0.0; lo[2] = 0.0;
lamda2x(lo,lo);
hi[0] = all[0][1]; hi[1] = 0.0; hi[2] = 0.0;
lamda2x(hi,hi);
if (boundary[0][0] == 2) boxlo[0] = lo[0] - small[0];
else if (boundary[0][0] == 3) boxlo[0] = MIN(lo[0]-small[0],minxlo);
if (boundary[0][1] == 2) boxhi[0] = hi[0] + small[0];
else if (boundary[0][1] == 3) boxhi[0] = MAX(hi[0]+small[0],minxhi);
if (boxlo[0] > boxhi[0]) error->all(FLERR,"Illegal simulation box");
}
if (yperiodic == 0) {
lo[0] = 0.0; lo[1] = -all[1][0]; lo[2] = 0.0;
lamda2x(lo,lo);
hi[0] = 0.0; hi[1] = all[1][1]; hi[2] = 0.0;
lamda2x(hi,hi);
if (boundary[1][0] == 2) boxlo[1] = lo[1] - small[1];
else if (boundary[1][0] == 3) boxlo[1] = MIN(lo[1]-small[1],minylo);
if (boundary[1][1] == 2) boxhi[1] = hi[1] + small[1];
else if (boundary[1][1] == 3) boxhi[1] = MAX(hi[1]+small[1],minyhi);
if (boxlo[1] > boxhi[1]) error->all(FLERR,"Illegal simulation box");
//xy *= (boxhi[1]-boxlo[1]) / yprd;
}
if (zperiodic == 0) {
lo[0] = 0.0; lo[1] = 0.0; lo[2] = -all[2][0];
lamda2x(lo,lo);
hi[0] = 0.0; hi[1] = 0.0; hi[2] = all[2][1];
lamda2x(hi,hi);
if (boundary[2][0] == 2) boxlo[2] = lo[2] - small[2];
else if (boundary[2][0] == 3) boxlo[2] = MIN(lo[2]-small[2],minzlo);
if (boundary[2][1] == 2) boxhi[2] = hi[2] + small[2];
else if (boundary[2][1] == 3) boxhi[2] = MAX(hi[2]+small[2],minzhi);
if (boxlo[2] > boxhi[2]) error->all(FLERR,"Illegal simulation box");
//xz *= (boxhi[2]-boxlo[2]) / xprd;
//yz *= (boxhi[2]-boxlo[2]) / yprd;
}
}
}
// reset box whether shrink-wrapping or not
set_global_box();
set_local_box();
// if shrink-wrapped & kspace is defined (i.e. using MSM) call setup()
if (nonperiodic == 2 && force->kspace) force->kspace->setup();
// if shrink-wrapped & triclinic, re-convert to lamda coords for new box
// re-invoke pbc() b/c x2lamda result can be outside [0,1] due to roundoff
if (nonperiodic == 2 && triclinic) {
x2lamda(atom->nlocal);
pbc();
}
}
/* ----------------------------------------------------------------------
enforce PBC and modify box image flags for each atom
called every reneighboring and by other commands that change atoms
resulting coord must satisfy lo <= coord < hi
MAX is important since coord - prd < lo can happen when coord = hi
if fix deform, remap velocity of fix group atoms by box edge velocities
for triclinic, atoms must be in lamda coords (0-1) before pbc is called
image = 10 bits for each dimension
increment/decrement in wrap-around fashion
------------------------------------------------------------------------- */
void Domain::pbc()
{
int i;
imageint idim,otherdims;
double *lo,*hi,*period;
int nlocal = atom->nlocal;
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
imageint *image = atom->image;
if (triclinic == 0) {
lo = boxlo;
hi = boxhi;
period = prd;
} else {
lo = boxlo_lamda;
hi = boxhi_lamda;
period = prd_lamda;
}
for (i = 0; i < nlocal; i++) {
if (xperiodic) {
if (x[i][0] < lo[0]) {
x[i][0] += period[0];
if (deform_vremap && mask[i] & deform_groupbit) v[i][0] += h_rate[0];
idim = image[i] & IMGMASK;
otherdims = image[i] ^ idim;
idim--;
idim &= IMGMASK;
image[i] = otherdims | idim;
}
if (x[i][0] >= hi[0]) {
x[i][0] -= period[0];
x[i][0] = MAX(x[i][0],lo[0]);
if (deform_vremap && mask[i] & deform_groupbit) v[i][0] -= h_rate[0];
idim = image[i] & IMGMASK;
otherdims = image[i] ^ idim;
idim++;
idim &= IMGMASK;
image[i] = otherdims | idim;
}
}
if (yperiodic) {
if (x[i][1] < lo[1]) {
x[i][1] += period[1];
if (deform_vremap && mask[i] & deform_groupbit) {
v[i][0] += h_rate[5];
v[i][1] += h_rate[1];
}
idim = (image[i] >> IMGBITS) & IMGMASK;
otherdims = image[i] ^ (idim << IMGBITS);
idim--;
idim &= IMGMASK;
image[i] = otherdims | (idim << IMGBITS);
}
if (x[i][1] >= hi[1]) {
x[i][1] -= period[1];
x[i][1] = MAX(x[i][1],lo[1]);
if (deform_vremap && mask[i] & deform_groupbit) {
v[i][0] -= h_rate[5];
v[i][1] -= h_rate[1];
}
idim = (image[i] >> IMGBITS) & IMGMASK;
otherdims = image[i] ^ (idim << IMGBITS);
idim++;
idim &= IMGMASK;
image[i] = otherdims | (idim << IMGBITS);
}
}
if (zperiodic) {
if (x[i][2] < lo[2]) {
x[i][2] += period[2];
if (deform_vremap && mask[i] & deform_groupbit) {
v[i][0] += h_rate[4];
v[i][1] += h_rate[3];
v[i][2] += h_rate[2];
}
idim = image[i] >> IMG2BITS;
otherdims = image[i] ^ (idim << IMG2BITS);
idim--;
idim &= IMGMASK;
image[i] = otherdims | (idim << IMG2BITS);
}
if (x[i][2] >= hi[2]) {
x[i][2] -= period[2];
x[i][2] = MAX(x[i][2],lo[2]);
if (deform_vremap && mask[i] & deform_groupbit) {
v[i][0] -= h_rate[4];
v[i][1] -= h_rate[3];
v[i][2] -= h_rate[2];
}
idim = image[i] >> IMG2BITS;
otherdims = image[i] ^ (idim << IMG2BITS);
idim++;
idim &= IMGMASK;
image[i] = otherdims | (idim << IMG2BITS);
}
}
}
}
/* ----------------------------------------------------------------------
warn if image flags of any bonded atoms are inconsistent
could be a problem when using replicate or fix rigid
------------------------------------------------------------------------- */
void Domain::image_check()
{
int i,j,k;
// only need to check if system is molecular and some dimension is periodic
// if running verlet/split, don't check on KSpace partition since
// it has no ghost atoms and thus bond partners won't exist
if (!atom->molecular) return;
if (!xperiodic && !yperiodic && (dimension == 2 || !zperiodic)) return;
if (strcmp(update->integrate_style,"verlet/split") == 0 &&
universe->iworld != 0) return;
// communicate unwrapped position of owned atoms to ghost atoms
double **unwrap;
memory->create(unwrap,atom->nmax,3,"domain:unwrap");
double **x = atom->x;
imageint *image = atom->image;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
unmap(x[i],image[i],unwrap[i]);
comm->forward_comm_array(3,unwrap);
// compute unwrapped extent of each bond
// flag if any bond component is longer than 1/2 of periodic box length
// flag if any bond component is longer than non-periodic box length
// which means image flags in that dimension were different
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
double delx,dely,delz;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
int flag = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
k = atom->map(bond_atom[i][j]);
if (k == -1) {
nmissing++;
if (lostbond == ERROR)
error->one(FLERR,"Bond atom missing in image check");
continue;
}
delx = unwrap[i][0] - unwrap[k][0];
dely = unwrap[i][1] - unwrap[k][1];
delz = unwrap[i][2] - unwrap[k][2];
if (xperiodic && delx > xprd_half) flag = 1;
if (xperiodic && dely > yprd_half) flag = 1;
if (dimension == 3 && zperiodic && delz > zprd_half) flag = 1;
if (!xperiodic && delx > xprd) flag = 1;
if (!yperiodic && dely > yprd) flag = 1;
if (dimension == 3 && !zperiodic && delz > zprd) flag = 1;
}
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall && comm->me == 0)
error->warning(FLERR,"Inconsistent image flags");
if (lostbond == WARN) {
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all && comm->me == 0)
error->warning(FLERR,"Bond atoms missing in image check");
}
memory->destroy(unwrap);
}
/* ----------------------------------------------------------------------
warn if end atoms in any bonded interaction
are further apart than half a periodic box length
could cause problems when bonded neighbor list is built since
closest_image() could return wrong image
------------------------------------------------------------------------- */
void Domain::box_too_small_check()
{
int i,j,k;
// only need to check if system is molecular and some dimension is periodic
// if running verlet/split, don't check on KSpace partition since
// it has no ghost atoms and thus bond partners won't exist
if (!atom->molecular) return;
if (!xperiodic && !yperiodic && (dimension == 2 || !zperiodic)) return;
if (strcmp(update->integrate_style,"verlet/split") == 0 &&
universe->iworld != 0) return;
// maxbondall = longest current bond length
// if periodic box dim is tiny (less than 2 * bond-length),
// minimum_image() itself may compute bad bond lengths
// in this case, image_check() should warn,
// assuming 2 atoms have consistent image flags
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
double **x = atom->x;
int nlocal = atom->nlocal;
double delx,dely,delz,rsq;
double maxbondme = 0.0;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
if (bond_type[i][j] <= 0) continue;
k = atom->map(bond_atom[i][j]);
if (k == -1) {
nmissing++;
if (lostbond == ERROR)
error->one(FLERR,"Bond atom missing in box size check");
continue;
}
delx = x[i][0] - x[k][0];
dely = x[i][1] - x[k][1];
delz = x[i][2] - x[k][2];
minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
maxbondme = MAX(maxbondme,rsq);
}
if (lostbond == WARN) {
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all && comm->me == 0)
error->warning(FLERR,"Bond atoms missing in box size check");
}
double maxbondall;
MPI_Allreduce(&maxbondme,&maxbondall,1,MPI_DOUBLE,MPI_MAX,world);
maxbondall = sqrt(maxbondall);
// maxdelta = furthest apart 2 atoms in a bonded interaction can be
// include BONDSTRETCH factor to account for dynamics
double maxdelta = maxbondall * BONDSTRETCH;
if (atom->nangles) maxdelta = 2.0 * maxbondall * BONDSTRETCH;
if (atom->ndihedrals) maxdelta = 3.0 * maxbondall * BONDSTRETCH;
// warn if maxdelta > than half any periodic box length
// since atoms in the interaction could rotate into that dimension
int flag = 0;
if (xperiodic && maxdelta > xprd_half) flag = 1;
if (yperiodic && maxdelta > yprd_half) flag = 1;
if (dimension == 3 && zperiodic && maxdelta > zprd_half) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_MAX,world);
if (flagall && comm->me == 0)
error->warning(FLERR,
"Bond/angle/dihedral extent > half of periodic box length");
}
/* ----------------------------------------------------------------------
minimum image convention
use 1/2 of box size as test
for triclinic, also add/subtract tilt factors in other dims as needed
------------------------------------------------------------------------- */
void Domain::minimum_image(double &dx, double &dy, double &dz)
{
if (triclinic == 0) {
if (xperiodic) {
if (fabs(dx) > xprd_half) {
if (dx < 0.0) dx += xprd;
else dx -= xprd;
}
}
if (yperiodic) {
if (fabs(dy) > yprd_half) {
if (dy < 0.0) dy += yprd;
else dy -= yprd;
}
}
if (zperiodic) {
if (fabs(dz) > zprd_half) {
if (dz < 0.0) dz += zprd;
else dz -= zprd;
}
}
} else {
if (zperiodic) {
if (fabs(dz) > zprd_half) {
if (dz < 0.0) {
dz += zprd;
dy += yz;
dx += xz;
} else {
dz -= zprd;
dy -= yz;
dx -= xz;
}
}
}
if (yperiodic) {
if (fabs(dy) > yprd_half) {
if (dy < 0.0) {
dy += yprd;
dx += xy;
} else {
dy -= yprd;
dx -= xy;
}
}
}
if (xperiodic) {
if (fabs(dx) > xprd_half) {
if (dx < 0.0) dx += xprd;
else dx -= xprd;
}
}
}
}
/* ----------------------------------------------------------------------
minimum image convention
use 1/2 of box size as test
for triclinic, also add/subtract tilt factors in other dims as needed
------------------------------------------------------------------------- */
void Domain::minimum_image(double *delta)
{
if (triclinic == 0) {
if (xperiodic) {
if (fabs(delta[0]) > xprd_half) {
if (delta[0] < 0.0) delta[0] += xprd;
else delta[0] -= xprd;
}
}
if (yperiodic) {
if (fabs(delta[1]) > yprd_half) {
if (delta[1] < 0.0) delta[1] += yprd;
else delta[1] -= yprd;
}
}
if (zperiodic) {
if (fabs(delta[2]) > zprd_half) {
if (delta[2] < 0.0) delta[2] += zprd;
else delta[2] -= zprd;
}
}
} else {
if (zperiodic) {
if (fabs(delta[2]) > zprd_half) {
if (delta[2] < 0.0) {
delta[2] += zprd;
delta[1] += yz;
delta[0] += xz;
} else {
delta[2] -= zprd;
delta[1] -= yz;
delta[0] -= xz;
}
}
}
if (yperiodic) {
if (fabs(delta[1]) > yprd_half) {
if (delta[1] < 0.0) {
delta[1] += yprd;
delta[0] += xy;
} else {
delta[1] -= yprd;
delta[0] -= xy;
}
}
}
if (xperiodic) {
if (fabs(delta[0]) > xprd_half) {
if (delta[0] < 0.0) delta[0] += xprd;
else delta[0] -= xprd;
}
}
}
}
/* ----------------------------------------------------------------------
return local index of atom J or any of its images that is closest to atom I
if J is not a valid index like -1, just return it
------------------------------------------------------------------------- */
int Domain::closest_image(int i, int j)
{
if (j < 0) return j;
int *sametag = atom->sametag;
double **x = atom->x;
double *xi = x[i];
int closest = j;
double delx = xi[0] - x[j][0];
double dely = xi[1] - x[j][1];
double delz = xi[2] - x[j][2];
double rsqmin = delx*delx + dely*dely + delz*delz;
double rsq;
while (sametag[j] >= 0) {
j = sametag[j];
delx = xi[0] - x[j][0];
dely = xi[1] - x[j][1];
delz = xi[2] - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq < rsqmin) {
rsqmin = rsq;
closest = j;
}
}
return closest;
}
/* ----------------------------------------------------------------------
find and return Xj image = periodic image of Xj that is closest to Xi
for triclinic, add/subtract tilt factors in other dims as needed
------------------------------------------------------------------------- */
void Domain::closest_image(const double * const xi, const double * const xj,
double * const xjimage)
{
double dx = xj[0] - xi[0];
double dy = xj[1] - xi[1];
double dz = xj[2] - xi[2];
if (triclinic == 0) {
if (xperiodic) {
if (dx < 0.0) {
while (dx < 0.0) dx += xprd;
if (dx > xprd_half) dx -= xprd;
} else {
while (dx > 0.0) dx -= xprd;
if (dx < -xprd_half) dx += xprd;
}
}
if (yperiodic) {
if (dy < 0.0) {
while (dy < 0.0) dy += yprd;
if (dy > yprd_half) dy -= yprd;
} else {
while (dy > 0.0) dy -= yprd;
if (dy < -yprd_half) dy += yprd;
}
}
if (zperiodic) {
if (dz < 0.0) {
while (dz < 0.0) dz += zprd;
if (dz > zprd_half) dz -= zprd;
} else {
while (dz > 0.0) dz -= zprd;
if (dz < -zprd_half) dz += zprd;
}
}
} else {
if (zperiodic) {
if (dz < 0.0) {
while (dz < 0.0) {
dz += zprd;
dy += yz;
dx += xz;
}
if (dz > zprd_half) {
dz -= zprd;
dy -= yz;
dx -= xz;
}
} else {
while (dz > 0.0) {
dz -= zprd;
dy -= yz;
dx -= xz;
}
if (dz < -zprd_half) {
dz += zprd;
dy += yz;
dx += xz;
}
}
}
if (yperiodic) {
if (dy < 0.0) {
while (dy < 0.0) {
dy += yprd;
dx += xy;
}
if (dy > yprd_half) {
dy -= yprd;
dx -= xy;
}
} else {
while (dy > 0.0) {
dy -= yprd;
dx -= xy;
}
if (dy < -yprd_half) {
dy += yprd;
dx += xy;
}
}
}
if (xperiodic) {
if (dx < 0.0) {
while (dx < 0.0) dx += xprd;
if (dx > xprd_half) dx -= xprd;
} else {
while (dx > 0.0) dx -= xprd;
if (dx < -xprd_half) dx += xprd;
}
}
}
xjimage[0] = xi[0] + dx;
xjimage[1] = xi[1] + dy;
xjimage[2] = xi[2] + dz;
}
/* ----------------------------------------------------------------------
remap the point into the periodic box no matter how far away
adjust 3 image flags encoded in image accordingly
resulting coord must satisfy lo <= coord < hi
MAX is important since coord - prd < lo can happen when coord = hi
for triclinic, point is converted to lamda coords (0-1) before doing remap
image = 10 bits for each dimension
increment/decrement in wrap-around fashion
------------------------------------------------------------------------- */
void Domain::remap(double *x, imageint &image)
{
double *lo,*hi,*period,*coord;
double lamda[3];
imageint idim,otherdims;
if (triclinic == 0) {
lo = boxlo;
hi = boxhi;
period = prd;
coord = x;
} else {
lo = boxlo_lamda;
hi = boxhi_lamda;
period = prd_lamda;
x2lamda(x,lamda);
coord = lamda;
}
if (xperiodic) {
while (coord[0] < lo[0]) {
coord[0] += period[0];
idim = image & IMGMASK;
otherdims = image ^ idim;
idim--;
idim &= IMGMASK;
image = otherdims | idim;
}
while (coord[0] >= hi[0]) {
coord[0] -= period[0];
idim = image & IMGMASK;
otherdims = image ^ idim;
idim++;
idim &= IMGMASK;
image = otherdims | idim;
}
coord[0] = MAX(coord[0],lo[0]);
}
if (yperiodic) {
while (coord[1] < lo[1]) {
coord[1] += period[1];
idim = (image >> IMGBITS) & IMGMASK;
otherdims = image ^ (idim << IMGBITS);
idim--;
idim &= IMGMASK;
image = otherdims | (idim << IMGBITS);
}
while (coord[1] >= hi[1]) {
coord[1] -= period[1];
idim = (image >> IMGBITS) & IMGMASK;
otherdims = image ^ (idim << IMGBITS);
idim++;
idim &= IMGMASK;
image = otherdims | (idim << IMGBITS);
}
coord[1] = MAX(coord[1],lo[1]);
}
if (zperiodic) {
while (coord[2] < lo[2]) {
coord[2] += period[2];
idim = image >> IMG2BITS;
otherdims = image ^ (idim << IMG2BITS);
idim--;
idim &= IMGMASK;
image = otherdims | (idim << IMG2BITS);
}
while (coord[2] >= hi[2]) {
coord[2] -= period[2];
idim = image >> IMG2BITS;
otherdims = image ^ (idim << IMG2BITS);
idim++;
idim &= IMGMASK;
image = otherdims | (idim << IMG2BITS);
}
coord[2] = MAX(coord[2],lo[2]);
}
if (triclinic) lamda2x(coord,x);
}
/* ----------------------------------------------------------------------
remap the point into the periodic box no matter how far away
no image flag calculation
resulting coord must satisfy lo <= coord < hi
MAX is important since coord - prd < lo can happen when coord = hi
for triclinic, point is converted to lamda coords (0-1) before remap
------------------------------------------------------------------------- */
void Domain::remap(double *x)
{
double *lo,*hi,*period,*coord;
double lamda[3];
if (triclinic == 0) {
lo = boxlo;
hi = boxhi;
period = prd;
coord = x;
} else {
lo = boxlo_lamda;
hi = boxhi_lamda;
period = prd_lamda;
x2lamda(x,lamda);
coord = lamda;
}
if (xperiodic) {
while (coord[0] < lo[0]) coord[0] += period[0];
while (coord[0] >= hi[0]) coord[0] -= period[0];
coord[0] = MAX(coord[0],lo[0]);
}
if (yperiodic) {
while (coord[1] < lo[1]) coord[1] += period[1];
while (coord[1] >= hi[1]) coord[1] -= period[1];
coord[1] = MAX(coord[1],lo[1]);
}
if (zperiodic) {
while (coord[2] < lo[2]) coord[2] += period[2];
while (coord[2] >= hi[2]) coord[2] -= period[2];
coord[2] = MAX(coord[2],lo[2]);
}
if (triclinic) lamda2x(coord,x);
}
/* ----------------------------------------------------------------------
remap xnew to be within half box length of xold
do it directly, not iteratively, in case is far away
for triclinic, both points are converted to lamda coords (0-1) before remap
------------------------------------------------------------------------- */
void Domain::remap_near(double *xnew, double *xold)
{
int n;
double *coordnew,*coordold,*period,*half;
double lamdanew[3],lamdaold[3];
if (triclinic == 0) {
period = prd;
half = prd_half;
coordnew = xnew;
coordold = xold;
} else {
period = prd_lamda;
half = prd_half_lamda;
x2lamda(xnew,lamdanew);
coordnew = lamdanew;
x2lamda(xold,lamdaold);
coordold = lamdaold;
}
// iterative form
// if (xperiodic) {
// while (coordnew[0]-coordold[0] > half[0]) coordnew[0] -= period[0];
// while (coordold[0]-coordnew[0] > half[0]) coordnew[0] += period[0];
// }
if (xperiodic) {
if (coordnew[0]-coordold[0] > period[0]) {
n = static_cast<int> ((coordnew[0]-coordold[0])/period[0]);
coordnew[0] -= n*period[0];
}
while (coordnew[0]-coordold[0] > half[0]) coordnew[0] -= period[0];
if (coordold[0]-coordnew[0] > period[0]) {
n = static_cast<int> ((coordold[0]-coordnew[0])/period[0]);
coordnew[0] += n*period[0];
}
while (coordold[0]-coordnew[0] > half[0]) coordnew[0] += period[0];
}
if (yperiodic) {
if (coordnew[1]-coordold[1] > period[1]) {
n = static_cast<int> ((coordnew[1]-coordold[1])/period[1]);
coordnew[1] -= n*period[1];
}
while (coordnew[1]-coordold[1] > half[1]) coordnew[1] -= period[1];
if (coordold[1]-coordnew[1] > period[1]) {
n = static_cast<int> ((coordold[1]-coordnew[1])/period[1]);
coordnew[1] += n*period[1];
}
while (coordold[1]-coordnew[1] > half[1]) coordnew[1] += period[1];
}
if (zperiodic) {
if (coordnew[2]-coordold[2] > period[2]) {
n = static_cast<int> ((coordnew[2]-coordold[2])/period[2]);
coordnew[2] -= n*period[2];
}
while (coordnew[2]-coordold[2] > half[2]) coordnew[2] -= period[2];
if (coordold[2]-coordnew[2] > period[2]) {
n = static_cast<int> ((coordold[2]-coordnew[2])/period[2]);
coordnew[2] += n*period[2];
}
while (coordold[2]-coordnew[2] > half[2]) coordnew[2] += period[2];
}
if (triclinic) lamda2x(coordnew,xnew);
}
/* ----------------------------------------------------------------------
unmap the point via image flags
x overwritten with result, don't reset image flag
for triclinic, use h[] to add in tilt factors in other dims as needed
------------------------------------------------------------------------- */
void Domain::unmap(double *x, imageint image)
{
int xbox = (image & IMGMASK) - IMGMAX;
int ybox = (image >> IMGBITS & IMGMASK) - IMGMAX;
int zbox = (image >> IMG2BITS) - IMGMAX;
if (triclinic == 0) {
x[0] += xbox*xprd;
x[1] += ybox*yprd;
x[2] += zbox*zprd;
} else {
x[0] += h[0]*xbox + h[5]*ybox + h[4]*zbox;
x[1] += h[1]*ybox + h[3]*zbox;
x[2] += h[2]*zbox;
}
}
/* ----------------------------------------------------------------------
unmap the point via image flags
result returned in y, don't reset image flag
for triclinic, use h[] to add in tilt factors in other dims as needed
------------------------------------------------------------------------- */
void Domain::unmap(double *x, imageint image, double *y)
{
int xbox = (image & IMGMASK) - IMGMAX;
int ybox = (image >> IMGBITS & IMGMASK) - IMGMAX;
int zbox = (image >> IMG2BITS) - IMGMAX;
if (triclinic == 0) {
y[0] = x[0] + xbox*xprd;
y[1] = x[1] + ybox*yprd;
y[2] = x[2] + zbox*zprd;
} else {
y[0] = x[0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
y[1] = x[1] + h[1]*ybox + h[3]*zbox;
y[2] = x[2] + h[2]*zbox;
}
}
/* ----------------------------------------------------------------------
adjust image flags due to triclinic box flip
flip operation is changing box vectors A,B,C to new A',B',C'
A' = A (A does not change)
B' = B + mA (B shifted by A)
C' = C + pB + nA (C shifted by B and/or A)
this requires the image flags change from (a,b,c) to (a',b',c')
so that x_unwrap for each atom is same before/after
x_unwrap_before = xlocal + aA + bB + cC
x_unwrap_after = xlocal + a'A' + b'B' + c'C'
this requires:
c' = c
b' = b - cp
a' = a - (b-cp)m - cn = a - b'm - cn
in other words, for xy flip, change in x flag depends on current y flag
this is b/c the xy flip dramatically changes which tiled image of
simulation box an unwrapped point maps to
------------------------------------------------------------------------- */
void Domain::image_flip(int m, int n, int p)
{
imageint *image = atom->image;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
int xbox = (image[i] & IMGMASK) - IMGMAX;
int ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int zbox = (image[i] >> IMG2BITS) - IMGMAX;
ybox -= p*zbox;
xbox -= m*ybox + n*zbox;
image[i] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
}
}
/* ----------------------------------------------------------------------
create a lattice
------------------------------------------------------------------------- */
void Domain::set_lattice(int narg, char **arg)
{
if (lattice) delete lattice;
lattice = new Lattice(lmp,narg,arg);
}
/* ----------------------------------------------------------------------
create a new region
------------------------------------------------------------------------- */
void Domain::add_region(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal region command");
if (strcmp(arg[1],"delete") == 0) {
delete_region(narg,arg);
return;
}
if (find_region(arg[0]) >= 0) error->all(FLERR,"Reuse of region ID");
// extend Region list if necessary
if (nregion == maxregion) {
maxregion += DELTAREGION;
regions = (Region **)
memory->srealloc(regions,maxregion*sizeof(Region *),"domain:regions");
}
// create the Region
if (strcmp(arg[1],"none") == 0) error->all(FLERR,"Invalid region style");
#define REGION_CLASS
#define RegionStyle(key,Class) \
else if (strcmp(arg[1],#key) == 0) \
regions[nregion] = new Class(lmp,narg,arg);
#include "style_region.h"
#undef REGION_CLASS
else error->all(FLERR,"Invalid region style");
// initialize any region variables via init()
// in case region is used between runs, e.g. to print a variable
regions[nregion]->init();
nregion++;
}
/* ----------------------------------------------------------------------
delete a region
------------------------------------------------------------------------- */
void Domain::delete_region(int narg, char **arg)
{
if (narg != 2) error->all(FLERR,"Illegal region command");
int iregion = find_region(arg[0]);
if (iregion == -1) error->all(FLERR,"Delete region ID does not exist");
delete regions[iregion];
regions[iregion] = regions[nregion-1];
nregion--;
}
/* ----------------------------------------------------------------------
return region index if name matches existing region ID
return -1 if no such region
------------------------------------------------------------------------- */
int Domain::find_region(char *name)
{
for (int iregion = 0; iregion < nregion; iregion++)
if (strcmp(name,regions[iregion]->id) == 0) return iregion;
return -1;
}
/* ----------------------------------------------------------------------
(re)set boundary settings
flag = 0, called from the input script
flag = 1, called from change box command
------------------------------------------------------------------------- */
void Domain::set_boundary(int narg, char **arg, int flag)
{
if (narg != 3) error->all(FLERR,"Illegal boundary command");
char c;
for (int idim = 0; idim < 3; idim++)
for (int iside = 0; iside < 2; iside++) {
if (iside == 0) c = arg[idim][0];
else if (iside == 1 && strlen(arg[idim]) == 1) c = arg[idim][0];
else c = arg[idim][1];
if (c == 'p') boundary[idim][iside] = 0;
else if (c == 'f') boundary[idim][iside] = 1;
else if (c == 's') boundary[idim][iside] = 2;
else if (c == 'm') boundary[idim][iside] = 3;
else {
if (flag == 0) error->all(FLERR,"Illegal boundary command");
if (flag == 1) error->all(FLERR,"Illegal change_box command");
}
}
for (int idim = 0; idim < 3; idim++)
if ((boundary[idim][0] == 0 && boundary[idim][1]) ||
(boundary[idim][0] && boundary[idim][1] == 0))
error->all(FLERR,"Both sides of boundary must be periodic");
if (boundary[0][0] == 0) xperiodic = 1;
else xperiodic = 0;
if (boundary[1][0] == 0) yperiodic = 1;
else yperiodic = 0;
if (boundary[2][0] == 0) zperiodic = 1;
else zperiodic = 0;
periodicity[0] = xperiodic;
periodicity[1] = yperiodic;
periodicity[2] = zperiodic;
nonperiodic = 0;
if (xperiodic == 0 || yperiodic == 0 || zperiodic == 0) {
nonperiodic = 1;
if (boundary[0][0] >= 2 || boundary[0][1] >= 2 ||
boundary[1][0] >= 2 || boundary[1][1] >= 2 ||
boundary[2][0] >= 2 || boundary[2][1] >= 2) nonperiodic = 2;
}
}
/* ----------------------------------------------------------------------
set domain attributes
------------------------------------------------------------------------- */
void Domain::set_box(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal box command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"tilt") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal box command");
if (strcmp(arg[iarg+1],"small") == 0) tiltsmall = 1;
else if (strcmp(arg[iarg+1],"large") == 0) tiltsmall = 0;
else error->all(FLERR,"Illegal box command");
iarg += 2;
} else error->all(FLERR,"Illegal box command");
}
}
/* ----------------------------------------------------------------------
print box info, orthogonal or triclinic
------------------------------------------------------------------------- */
void Domain::print_box(const char *str)
{
if (comm->me == 0) {
if (screen) {
if (triclinic == 0)
fprintf(screen,"%sorthogonal box = (%g %g %g) to (%g %g %g)\n",
str,boxlo[0],boxlo[1],boxlo[2],boxhi[0],boxhi[1],boxhi[2]);
else {
char *format = (char *)
"%striclinic box = (%g %g %g) to (%g %g %g) with tilt (%g %g %g)\n";
fprintf(screen,format,
str,boxlo[0],boxlo[1],boxlo[2],boxhi[0],boxhi[1],boxhi[2],
xy,xz,yz);
}
}
if (logfile) {
if (triclinic == 0)
fprintf(logfile,"%sorthogonal box = (%g %g %g) to (%g %g %g)\n",
str,boxlo[0],boxlo[1],boxlo[2],boxhi[0],boxhi[1],boxhi[2]);
else {
char *format = (char *)
"%striclinic box = (%g %g %g) to (%g %g %g) with tilt (%g %g %g)\n";
fprintf(logfile,format,
str,boxlo[0],boxlo[1],boxlo[2],boxhi[0],boxhi[1],boxhi[2],
xy,xz,yz);
}
}
}
}
/* ----------------------------------------------------------------------
format boundary string for output
assume str is 9 chars or more in length
------------------------------------------------------------------------- */
void Domain::boundary_string(char *str)
{
int m = 0;
for (int idim = 0; idim < 3; idim++) {
for (int iside = 0; iside < 2; iside++) {
if (boundary[idim][iside] == 0) str[m++] = 'p';
else if (boundary[idim][iside] == 1) str[m++] = 'f';
else if (boundary[idim][iside] == 2) str[m++] = 's';
else if (boundary[idim][iside] == 3) str[m++] = 'm';
}
str[m++] = ' ';
}
str[8] = '\0';
}
/* ----------------------------------------------------------------------
convert triclinic 0-1 lamda coords to box coords for all N atoms
x = H lamda + x0;
------------------------------------------------------------------------- */
void Domain::lamda2x(int n)
{
double * const * const x = atom->x;
const int num = n;
int i;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) schedule(static)
#endif
for (i = 0; i < num; i++) {
x[i][0] = h[0]*x[i][0] + h[5]*x[i][1] + h[4]*x[i][2] + boxlo[0];
x[i][1] = h[1]*x[i][1] + h[3]*x[i][2] + boxlo[1];
x[i][2] = h[2]*x[i][2] + boxlo[2];
}
}
/* ----------------------------------------------------------------------
convert box coords to triclinic 0-1 lamda coords for all N atoms
lamda = H^-1 (x - x0)
------------------------------------------------------------------------- */
void Domain::x2lamda(int n)
{
double * const * const x = atom->x;
const int num = n;
int i;
#if defined(_OPENMP)
#pragma omp parallel for private(i) default(none) schedule(static)
#endif
for (i = 0; i < num; i++) {
double delta0 = x[i][0] - boxlo[0];
double delta1 = x[i][1] - boxlo[1];
double delta2 = x[i][2] - boxlo[2];
x[i][0] = h_inv[0]*delta0 + h_inv[5]*delta1 + h_inv[4]*delta2;
x[i][1] = h_inv[1]*delta1 + h_inv[3]*delta2;
x[i][2] = h_inv[2]*delta2;
}
}
/* ----------------------------------------------------------------------
convert triclinic 0-1 lamda coords to box coords for one atom
x = H lamda + x0;
lamda and x can point to same 3-vector
------------------------------------------------------------------------- */
void Domain::lamda2x(double *lamda, double *x)
{
x[0] = h[0]*lamda[0] + h[5]*lamda[1] + h[4]*lamda[2] + boxlo[0];
x[1] = h[1]*lamda[1] + h[3]*lamda[2] + boxlo[1];
x[2] = h[2]*lamda[2] + boxlo[2];
}
/* ----------------------------------------------------------------------
convert box coords to triclinic 0-1 lamda coords for one atom
lamda = H^-1 (x - x0)
x and lamda can point to same 3-vector
------------------------------------------------------------------------- */
void Domain::x2lamda(double *x, double *lamda)
{
double delta[3];
delta[0] = x[0] - boxlo[0];
delta[1] = x[1] - boxlo[1];
delta[2] = x[2] - boxlo[2];
lamda[0] = h_inv[0]*delta[0] + h_inv[5]*delta[1] + h_inv[4]*delta[2];
lamda[1] = h_inv[1]*delta[1] + h_inv[3]*delta[2];
lamda[2] = h_inv[2]*delta[2];
}
/* ----------------------------------------------------------------------
convert box coords to triclinic 0-1 lamda coords for one atom
use my_boxlo & my_h_inv stored by caller for previous state of box
lamda = H^-1 (x - x0)
x and lamda can point to same 3-vector
------------------------------------------------------------------------- */
void Domain::x2lamda(double *x, double *lamda,
double *my_boxlo, double *my_h_inv)
{
double delta[3];
delta[0] = x[0] - my_boxlo[0];
delta[1] = x[1] - my_boxlo[1];
delta[2] = x[2] - my_boxlo[2];
lamda[0] = my_h_inv[0]*delta[0] + my_h_inv[5]*delta[1] + my_h_inv[4]*delta[2];
lamda[1] = my_h_inv[1]*delta[1] + my_h_inv[3]*delta[2];
lamda[2] = my_h_inv[2]*delta[2];
}
/* ----------------------------------------------------------------------
convert 8 lamda corner pts of lo/hi box to box coords
return bboxlo/hi = bounding box around 8 corner pts in box coords
------------------------------------------------------------------------- */
void Domain::bbox(double *lo, double *hi, double *bboxlo, double *bboxhi)
{
double x[3];
bboxlo[0] = bboxlo[1] = bboxlo[2] = BIG;
bboxhi[0] = bboxhi[1] = bboxhi[2] = -BIG;
x[0] = lo[0]; x[1] = lo[1]; x[2] = lo[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = hi[0]; x[1] = lo[1]; x[2] = lo[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = lo[0]; x[1] = hi[1]; x[2] = lo[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = hi[0]; x[1] = hi[1]; x[2] = lo[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = lo[0]; x[1] = lo[1]; x[2] = hi[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = hi[0]; x[1] = lo[1]; x[2] = hi[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = lo[0]; x[1] = hi[1]; x[2] = hi[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
x[0] = hi[0]; x[1] = hi[1]; x[2] = hi[2];
lamda2x(x,x);
bboxlo[0] = MIN(bboxlo[0],x[0]); bboxhi[0] = MAX(bboxhi[0],x[0]);
bboxlo[1] = MIN(bboxlo[1],x[1]); bboxhi[1] = MAX(bboxhi[1],x[1]);
bboxlo[2] = MIN(bboxlo[2],x[2]); bboxhi[2] = MAX(bboxhi[2],x[2]);
}
/* ----------------------------------------------------------------------
compute 8 corner pts of triclinic box
8 are ordered with x changing fastest, then y, finally z
could be more efficient if just coded with xy,yz,xz explicitly
------------------------------------------------------------------------- */
void Domain::box_corners()
{
corners[0][0] = 0.0; corners[0][1] = 0.0; corners[0][2] = 0.0;
lamda2x(corners[0],corners[0]);
corners[1][0] = 1.0; corners[1][1] = 0.0; corners[1][2] = 0.0;
lamda2x(corners[1],corners[1]);
corners[2][0] = 0.0; corners[2][1] = 1.0; corners[2][2] = 0.0;
lamda2x(corners[2],corners[2]);
corners[3][0] = 1.0; corners[3][1] = 1.0; corners[3][2] = 0.0;
lamda2x(corners[3],corners[3]);
corners[4][0] = 0.0; corners[4][1] = 0.0; corners[4][2] = 1.0;
lamda2x(corners[4],corners[4]);
corners[5][0] = 1.0; corners[5][1] = 0.0; corners[5][2] = 1.0;
lamda2x(corners[5],corners[5]);
corners[6][0] = 0.0; corners[6][1] = 1.0; corners[6][2] = 1.0;
lamda2x(corners[6],corners[6]);
corners[7][0] = 1.0; corners[7][1] = 1.0; corners[7][2] = 1.0;
lamda2x(corners[7],corners[7]);
}
diff --git a/src/dump.cpp b/src/dump.cpp
index c37a32456..965aa29a7 100644
--- a/src/dump.cpp
+++ b/src/dump.cpp
@@ -1,883 +1,889 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "dump.h"
#include "atom.h"
#include "irregular.h"
#include "update.h"
#include "domain.h"
#include "group.h"
#include "output.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
// allocate space for static class variable
Dump *Dump::dumpptr;
#define BIG 1.0e20
-#define IBIG 2147483647
#define EPSILON 1.0e-6
enum{ASCEND,DESCEND};
/* ---------------------------------------------------------------------- */
Dump::Dump(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
int n = strlen(arg[0]) + 1;
id = new char[n];
strcpy(id,arg[0]);
igroup = group->find(arg[1]);
groupbit = group->bitmask[igroup];
n = strlen(arg[2]) + 1;
style = new char[n];
strcpy(style,arg[2]);
n = strlen(arg[4]) + 1;
filename = new char[n];
strcpy(filename,arg[4]);
comm_forward = comm_reverse = 0;
first_flag = 0;
flush_flag = 1;
format = NULL;
format_user = NULL;
format_default = NULL;
clearstep = 0;
sort_flag = 0;
append_flag = 0;
buffer_allow = 0;
buffer_flag = 0;
padflag = 0;
maxbuf = maxids = maxsort = maxproc = 0;
buf = bufsort = NULL;
- ids = idsort = index = proclist = NULL;
+ ids = idsort = NULL;
+ index = proclist = NULL;
irregular = NULL;
maxsbuf = 0;
sbuf = NULL;
// parse filename for special syntax
// if contains '%', write one file per proc and replace % with proc-ID
// if contains '*', write one file per timestep and replace * with timestep
// check file suffixes
// if ends in .bin = binary file
// else if ends in .gz = gzipped text file
// else ASCII text file
fp = NULL;
singlefile_opened = 0;
compressed = 0;
binary = 0;
multifile = 0;
multiproc = 0;
nclusterprocs = nprocs;
filewriter = 0;
if (me == 0) filewriter = 1;
fileproc = 0;
multiname = NULL;
char *ptr;
if (ptr = strchr(filename,'%')) {
multiproc = 1;
nclusterprocs = 1;
filewriter = 1;
fileproc = me;
MPI_Comm_split(world,me,0,&clustercomm);
multiname = new char[strlen(filename) + 16];
*ptr = '\0';
sprintf(multiname,"%s%d%s",filename,me,ptr+1);
*ptr = '%';
}
if (strchr(filename,'*')) multifile = 1;
char *suffix = filename + strlen(filename) - strlen(".bin");
if (suffix > filename && strcmp(suffix,".bin") == 0) binary = 1;
suffix = filename + strlen(filename) - strlen(".gz");
if (suffix > filename && strcmp(suffix,".gz") == 0) compressed = 1;
}
/* ---------------------------------------------------------------------- */
Dump::~Dump()
{
delete [] id;
delete [] style;
delete [] filename;
delete [] multiname;
delete [] format;
delete [] format_default;
delete [] format_user;
memory->destroy(buf);
memory->destroy(bufsort);
memory->destroy(ids);
memory->destroy(idsort);
memory->destroy(index);
memory->destroy(proclist);
delete irregular;
memory->destroy(sbuf);
if (multiproc) MPI_Comm_free(&clustercomm);
// XTC style sets fp to NULL since it closes file in its destructor
if (multifile == 0 && fp != NULL) {
if (compressed) {
if (filewriter) pclose(fp);
} else {
if (filewriter) fclose(fp);
}
}
}
/* ---------------------------------------------------------------------- */
void Dump::init()
{
init_style();
if (!sort_flag) {
memory->destroy(bufsort);
memory->destroy(ids);
memory->destroy(idsort);
memory->destroy(index);
memory->destroy(proclist);
delete irregular;
maxids = maxsort = maxproc = 0;
bufsort = NULL;
- ids = idsort = index = proclist = NULL;
+ ids = idsort = NULL;
+ index = proclist = NULL;
irregular = NULL;
}
if (sort_flag) {
if (multiproc > 1)
error->all(FLERR,
"Cannot dump sort when multiple procs write the dump file");
if (sortcol == 0 && atom->tag_enable == 0)
error->all(FLERR,"Cannot dump sort on atom IDs with no atom IDs defined");
if (sortcol && sortcol > size_one)
error->all(FLERR,"Dump sort column is invalid");
if (nprocs > 1 && irregular == NULL)
irregular = new Irregular(lmp);
bigint size = group->count(igroup);
if (size > MAXSMALLINT) error->all(FLERR,"Too many atoms to dump sort");
+ int isize = static_cast<int> (size);
// set reorderflag = 1 if can simply reorder local atoms rather than sort
// criteria: sorting by ID, atom IDs are consecutive from 1 to Natoms
// min/max IDs of group match size of group
// compute ntotal_reorder, nme_reorder, idlo/idhi to test against later
reorderflag = 0;
if (sortcol == 0 && atom->tag_consecutive()) {
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
- int min = IBIG;
- int max = 0;
+ tagint min = MAXTAGINT;
+ tagint max = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
min = MIN(min,tag[i]);
max = MAX(max,tag[i]);
}
- int minall,maxall;
- MPI_Allreduce(&min,&minall,1,MPI_INT,MPI_MIN,world);
- MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
- int isize = static_cast<int> (size);
+ tagint minall,maxall;
+ MPI_Allreduce(&min,&minall,1,MPI_LMP_TAGINT,MPI_MIN,world);
+ MPI_Allreduce(&max,&maxall,1,MPI_LMP_TAGINT,MPI_MAX,world);
if (maxall-minall+1 == isize) {
reorderflag = 1;
double range = maxall-minall + EPSILON;
idlo = static_cast<int> (range*me/nprocs + minall);
- int idhi = static_cast<int> (range*(me+1)/nprocs + minall);
+ tagint idhi = static_cast<tagint> (range*(me+1)/nprocs + minall);
- int lom1 = static_cast<int> ((idlo-1-minall)/range * nprocs);
- int lo = static_cast<int> ((idlo-minall)/range * nprocs);
- int him1 = static_cast<int> ((idhi-1-minall)/range * nprocs);
- int hi = static_cast<int> ((idhi-minall)/range * nprocs);
+ tagint lom1 = static_cast<tagint> ((idlo-1-minall)/range * nprocs);
+ tagint lo = static_cast<tagint> ((idlo-minall)/range * nprocs);
+ tagint him1 = static_cast<tagint> ((idhi-1-minall)/range * nprocs);
+ tagint hi = static_cast<tagint> ((idhi-minall)/range * nprocs);
if (me && me == lom1) idlo--;
else if (me && me != lo) idlo++;
if (me+1 == him1) idhi--;
else if (me+1 != hi) idhi++;
nme_reorder = idhi-idlo;
ntotal_reorder = isize;
}
}
}
}
/* ---------------------------------------------------------------------- */
int Dump::count()
{
if (igroup == 0) return atom->nlocal;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int m = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) m++;
return m;
}
/* ---------------------------------------------------------------------- */
void Dump::write()
{
// if file per timestep, open new file
if (multifile) openfile();
// simulation box bounds
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
}
// nme = # of dump lines this proc contributes to dump
nme = count();
// ntotal = total # of dump lines in snapshot
// nmax = max # of dump lines on any proc
bigint bnme = nme;
MPI_Allreduce(&bnme,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
int nmax;
if (multiproc != nprocs) MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
else nmax = nme;
// write timestep header
// for multiproc,
// nheader = # of lines in this file via Allreduce on clustercomm
bigint nheader = ntotal;
if (multiproc)
MPI_Allreduce(&bnme,&nheader,1,MPI_LMP_BIGINT,MPI_SUM,clustercomm);
if (filewriter) write_header(nheader);
// insure buf is sized for packing and communicating
// use nmax to insure filewriter proc can receive info from others
// limit nmax*size_one to int since used as arg in MPI calls
if (nmax > maxbuf) {
if ((bigint) nmax * size_one > MAXSMALLINT)
error->all(FLERR,"Too much per-proc info for dump");
maxbuf = nmax;
memory->destroy(buf);
memory->create(buf,maxbuf*size_one,"dump:buf");
}
// insure ids buffer is sized for sorting
if (sort_flag && sortcol == 0 && nmax > maxids) {
maxids = nmax;
memory->destroy(ids);
memory->create(ids,maxids,"dump:ids");
}
// pack my data into buf
// if sorting on IDs also request ID list from pack()
// sort buf as needed
if (sort_flag && sortcol == 0) pack(ids);
else pack(NULL);
if (sort_flag) sort();
// if buffering, convert doubles into strings
// insure sbuf is sized for communicating
// cannot buffer if output is to binary file
if (buffer_flag && !binary) {
nsme = convert_string(nme,buf);
int nsmin,nsmax;
MPI_Allreduce(&nsme,&nsmin,1,MPI_INT,MPI_MIN,world);
if (nsmin < 0) error->all(FLERR,"Too much buffered per-proc info for dump");
if (multiproc != nprocs)
MPI_Allreduce(&nsme,&nsmax,1,MPI_INT,MPI_MAX,world);
else nsmax = nsme;
if (nsmax > maxsbuf) {
maxsbuf = nsmax;
memory->grow(sbuf,maxsbuf,"dump:sbuf");
}
}
// filewriter = 1 = this proc writes to file
// ping each proc in my cluster, receive its data, write data to file
// else wait for ping from fileproc, send my data to fileproc
int tmp,nlines,nchars;
MPI_Status status;
MPI_Request request;
// comm and output buf of doubles
if (buffer_flag == 0 || binary) {
if (filewriter) {
for (int iproc = 0; iproc < nclusterprocs; iproc++) {
if (iproc) {
MPI_Irecv(buf,maxbuf*size_one,MPI_DOUBLE,me+iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,me+iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&nlines);
nlines /= size_one;
} else nlines = nme;
write_data(nlines,buf);
}
if (flush_flag) fflush(fp);
} else {
MPI_Recv(&tmp,0,MPI_INT,fileproc,0,world,&status);
MPI_Rsend(buf,nme*size_one,MPI_DOUBLE,fileproc,0,world);
}
// comm and output sbuf = one big string of formatted values per proc
} else {
if (filewriter) {
for (int iproc = 0; iproc < nclusterprocs; iproc++) {
if (iproc) {
MPI_Irecv(sbuf,maxsbuf,MPI_CHAR,me+iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,me+iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_CHAR,&nchars);
} else nchars = nsme;
write_data(nchars,(double *) sbuf);
}
if (flush_flag) fflush(fp);
} else {
MPI_Recv(&tmp,0,MPI_INT,fileproc,0,world,&status);
MPI_Rsend(sbuf,nsme,MPI_CHAR,fileproc,0,world);
}
}
// if file per timestep, close file if I am filewriter
if (multifile) {
if (compressed) {
if (filewriter) pclose(fp);
} else {
if (filewriter) fclose(fp);
}
}
}
/* ----------------------------------------------------------------------
generic opening of a dump file
ASCII or binary or gzipped
some derived classes override this function
------------------------------------------------------------------------- */
void Dump::openfile()
{
// single file, already opened, so just return
if (singlefile_opened) return;
if (multifile == 0) singlefile_opened = 1;
// if one file per timestep, replace '*' with current timestep
char *filecurrent = filename;
if (multiproc) filecurrent = multiname;
if (multifile) {
char *filestar = filecurrent;
filecurrent = new char[strlen(filestar) + 16];
char *ptr = strchr(filestar,'*');
*ptr = '\0';
if (padflag == 0)
sprintf(filecurrent,"%s" BIGINT_FORMAT "%s",
filestar,update->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,filestar,update->ntimestep,ptr+1);
}
*ptr = '*';
}
// each proc with filewriter = 1 opens a file
if (filewriter) {
if (compressed) {
#ifdef LAMMPS_GZIP
char gzip[128];
sprintf(gzip,"gzip -6 > %s",filecurrent);
#ifdef _WIN32
fp = _popen(gzip,"wb");
#else
fp = popen(gzip,"w");
#endif
#else
error->one(FLERR,"Cannot open gzipped file");
#endif
} else if (binary) {
fp = fopen(filecurrent,"wb");
} else if (append_flag) {
fp = fopen(filecurrent,"a");
} else {
fp = fopen(filecurrent,"w");
}
if (fp == NULL) error->one(FLERR,"Cannot open dump file");
} else fp = NULL;
// delete string with timestep replaced
if (multifile) delete [] filecurrent;
}
/* ----------------------------------------------------------------------
parallel sort of buf across all procs
changes nme, reorders datums in buf, grows buf if necessary
------------------------------------------------------------------------- */
void Dump::sort()
{
int i,iproc;
double value;
// if single proc, swap ptrs to buf,ids <-> bufsort,idsort
if (nprocs == 1) {
if (nme > maxsort) {
maxsort = nme;
memory->destroy(bufsort);
memory->create(bufsort,maxsort*size_one,"dump:bufsort");
memory->destroy(index);
memory->create(index,maxsort,"dump:index");
if (sortcol == 0) {
memory->destroy(idsort);
memory->create(idsort,maxsort,"dump:idsort");
}
}
double *dptr = buf;
buf = bufsort;
bufsort = dptr;
if (sortcol == 0) {
- int *iptr = ids;
+ tagint *iptr = ids;
ids = idsort;
idsort = iptr;
}
// if multiple procs, exchange datums between procs via irregular
} else {
// grow proclist if necessary
if (nme > maxproc) {
maxproc = nme;
memory->destroy(proclist);
memory->create(proclist,maxproc,"dump:proclist");
}
// proclist[i] = which proc Ith datum will be sent to
if (sortcol == 0) {
- int min = IBIG;
- int max = 0;
+ tagint min = MAXTAGINT;
+ tagint max = 0;
for (i = 0; i < nme; i++) {
min = MIN(min,ids[i]);
max = MAX(max,ids[i]);
}
- int minall,maxall;
- MPI_Allreduce(&min,&minall,1,MPI_INT,MPI_MIN,world);
- MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
- double range = maxall-minall + EPSILON;
+ tagint minall,maxall;
+ MPI_Allreduce(&min,&minall,1,MPI_LMP_TAGINT,MPI_MIN,world);
+ MPI_Allreduce(&max,&maxall,1,MPI_LMP_TAGINT,MPI_MAX,world);
+
+ // use 0.5 instead of EPSILON since atom IDs are integers
+ // if use EPSILON, it can be lost if 64-bit maxall-minall is too big
+ // then iproc == nprocs for largest ID, causing irregular to crash
+
+ double range = maxall-minall + 0.5;
for (i = 0; i < nme; i++) {
iproc = static_cast<int> ((ids[i]-minall)/range * nprocs);
proclist[i] = iproc;
}
} else {
double min = BIG;
double max = -BIG;
for (i = 0; i < nme; i++) {
value = buf[i*size_one + sortcolm1];
min = MIN(min,value);
max = MAX(max,value);
}
double minall,maxall;
MPI_Allreduce(&min,&minall,1,MPI_DOUBLE,MPI_MIN,world);
MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world);
double range = maxall-minall + EPSILON*(maxall-minall);
if (range == 0.0) range = EPSILON;
for (i = 0; i < nme; i++) {
value = buf[i*size_one + sortcolm1];
iproc = static_cast<int> ((value-minall)/range * nprocs);
proclist[i] = iproc;
}
}
// create comm plan, grow recv bufs if necessary,
// exchange datums, destroy plan
// if sorting on atom IDs, exchange IDs also
nme = irregular->create_data(nme,proclist);
if (nme > maxsort) {
maxsort = nme;
memory->destroy(bufsort);
memory->create(bufsort,maxsort*size_one,"dump:bufsort");
memory->destroy(index);
memory->create(index,maxsort,"dump:index");
if (sortcol == 0) {
memory->destroy(idsort);
memory->create(idsort,maxsort,"dump:idsort");
}
}
irregular->exchange_data((char *) buf,size_one*sizeof(double),
(char *) bufsort);
if (sortcol == 0)
- irregular->exchange_data((char *) ids,sizeof(int),(char *) idsort);
+ irregular->exchange_data((char *) ids,sizeof(tagint),(char *) idsort);
irregular->destroy_data();
}
// if reorder flag is set & total/per-proc counts match pre-computed values,
// then create index directly from idsort
// else quicksort of index using IDs or buf column as comparator
if (reorderflag) {
if (ntotal != ntotal_reorder) reorderflag = 0;
int flag = 0;
if (nme != nme_reorder) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) reorderflag = 0;
if (reorderflag)
for (i = 0; i < nme; i++)
index[idsort[i]-idlo] = i;
}
if (!reorderflag) {
dumpptr = this;
for (i = 0; i < nme; i++) index[i] = i;
if (sortcol == 0) qsort(index,nme,sizeof(int),idcompare);
else if (sortorder == ASCEND) qsort(index,nme,sizeof(int),bufcompare);
else qsort(index,nme,sizeof(int),bufcompare_reverse);
}
// reset buf size and maxbuf to largest of any post-sort nme values
// this insures proc 0 can receive everyone's info
int nmax;
MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world);
if (nmax > maxbuf) {
maxbuf = nmax;
memory->destroy(buf);
memory->create(buf,maxbuf*size_one,"dump:buf");
}
// copy data from bufsort to buf using index
int nbytes = size_one*sizeof(double);
for (i = 0; i < nme; i++)
memcpy(&buf[i*size_one],&bufsort[index[i]*size_one],nbytes);
}
/* ----------------------------------------------------------------------
compare two atom IDs
called via qsort() in sort() method
is a static method so access data via dumpptr
------------------------------------------------------------------------- */
int Dump::idcompare(const void *pi, const void *pj)
{
- int *idsort = dumpptr->idsort;
+ tagint *idsort = dumpptr->idsort;
int i = *((int *) pi);
int j = *((int *) pj);
if (idsort[i] < idsort[j]) return -1;
if (idsort[i] > idsort[j]) return 1;
return 0;
}
/* ----------------------------------------------------------------------
compare two buffer values with size_one stride
called via qsort() in sort() method
is a static method so access data via dumpptr
sort in ASCENDing order
------------------------------------------------------------------------- */
int Dump::bufcompare(const void *pi, const void *pj)
{
double *bufsort = dumpptr->bufsort;
int size_one = dumpptr->size_one;
int sortcolm1 = dumpptr->sortcolm1;
int i = *((int *) pi)*size_one + sortcolm1;
int j = *((int *) pj)*size_one + sortcolm1;
if (bufsort[i] < bufsort[j]) return -1;
if (bufsort[i] > bufsort[j]) return 1;
return 0;
}
/* ----------------------------------------------------------------------
compare two buffer values with size_one stride
called via qsort() in sort() method
is a static method so access data via dumpptr
sort in DESCENDing order
------------------------------------------------------------------------- */
int Dump::bufcompare_reverse(const void *pi, const void *pj)
{
double *bufsort = dumpptr->bufsort;
int size_one = dumpptr->size_one;
int sortcolm1 = dumpptr->sortcolm1;
int i = *((int *) pi)*size_one + sortcolm1;
int j = *((int *) pj)*size_one + sortcolm1;
if (bufsort[i] > bufsort[j]) return -1;
if (bufsort[i] < bufsort[j]) return 1;
return 0;
}
/* ----------------------------------------------------------------------
process params common to all dumps here
if unknown param, call modify_param specific to the dump
------------------------------------------------------------------------- */
void Dump::modify_params(int narg, char **arg)
{
if (narg == 0) error->all(FLERR,"Illegal dump_modify command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"append") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) append_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) append_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"buffer") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) buffer_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) buffer_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
if (buffer_flag && buffer_allow == 0)
error->all(FLERR,"Dump_modify buffer yes not allowed for this style");
iarg += 2;
} else if (strcmp(arg[iarg],"every") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
int idump;
for (idump = 0; idump < output->ndump; idump++)
if (strcmp(id,output->dump[idump]->id) == 0) break;
int n;
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
delete [] output->var_dump[idump];
n = strlen(&arg[iarg+1][2]) + 1;
output->var_dump[idump] = new char[n];
strcpy(output->var_dump[idump],&arg[iarg+1][2]);
n = 0;
} else {
n = force->inumeric(FLERR,arg[iarg+1]);
if (n <= 0) error->all(FLERR,"Illegal dump_modify command");
}
output->every_dump[idump] = n;
iarg += 2;
} else if (strcmp(arg[iarg],"first") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) first_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) first_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"fileper") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (!multiproc)
error->all(FLERR,"Cannot use dump_modify fileper "
"without % in dump file name");
int nper = force->inumeric(FLERR,arg[iarg+1]);
if (nper <= 0) error->all(FLERR,"Illegal dump_modify command");
multiproc = nprocs/nper;
if (nprocs % nper) multiproc++;
fileproc = me/nper * nper;
int fileprocnext = MIN(fileproc+nper,nprocs);
nclusterprocs = fileprocnext - fileproc;
if (me == fileproc) filewriter = 1;
else filewriter = 0;
int icluster = fileproc/nper;
MPI_Comm_free(&clustercomm);
MPI_Comm_split(world,icluster,0,&clustercomm);
delete [] multiname;
multiname = new char[strlen(filename) + 16];
char *ptr = strchr(filename,'%');
*ptr = '\0';
sprintf(multiname,"%s%d%s",filename,icluster,ptr+1);
*ptr = '%';
iarg += 2;
} else if (strcmp(arg[iarg],"flush") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[iarg+1],"yes") == 0) flush_flag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) flush_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"format") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
delete [] format_user;
format_user = NULL;
if (strcmp(arg[iarg+1],"none")) {
int n = strlen(arg[iarg+1]) + 1;
format_user = new char[n];
strcpy(format_user,arg[iarg+1]);
}
iarg += 2;
} else if (strcmp(arg[iarg],"nfile") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (!multiproc)
error->all(FLERR,"Cannot use dump_modify nfile "
"without % in dump file name");
int nfile = force->inumeric(FLERR,arg[iarg+1]);
if (nfile <= 0) error->all(FLERR,"Illegal dump_modify command");
nfile = MIN(nfile,nprocs);
multiproc = nfile;
int icluster = static_cast<int> ((bigint) me * nfile/nprocs);
fileproc = static_cast<int> ((bigint) icluster * nprocs/nfile);
int fcluster = static_cast<int> ((bigint) fileproc * nfile/nprocs);
if (fcluster < icluster) fileproc++;
int fileprocnext =
static_cast<int> ((bigint) (icluster+1) * nprocs/nfile);
fcluster = static_cast<int> ((bigint) fileprocnext * nfile/nprocs);
if (fcluster < icluster+1) fileprocnext++;
nclusterprocs = fileprocnext - fileproc;
if (me == fileproc) filewriter = 1;
else filewriter = 0;
MPI_Comm_free(&clustercomm);
MPI_Comm_split(world,icluster,0,&clustercomm);
delete [] multiname;
multiname = new char[strlen(filename) + 16];
char *ptr = strchr(filename,'%');
*ptr = '\0';
sprintf(multiname,"%s%d%s",filename,icluster,ptr+1);
*ptr = '%';
iarg += 2;
} else if (strcmp(arg[iarg],"pad") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
padflag = force->inumeric(FLERR,arg[iarg+1]);
if (padflag < 0) error->all(FLERR,"Illegal dump_modify command");
iarg += 2;
} else if (strcmp(arg[iarg],"sort") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[iarg+1],"off") == 0) sort_flag = 0;
else if (strcmp(arg[iarg+1],"id") == 0) {
sort_flag = 1;
sortcol = 0;
sortorder = ASCEND;
} else {
sort_flag = 1;
sortcol = force->inumeric(FLERR,arg[iarg+1]);
sortorder = ASCEND;
if (sortcol == 0) error->all(FLERR,"Illegal dump_modify command");
if (sortcol < 0) {
sortorder = DESCEND;
sortcol = -sortcol;
}
sortcolm1 = sortcol - 1;
}
iarg += 2;
} else {
int n = modify_param(narg-iarg,&arg[iarg]);
if (n == 0) error->all(FLERR,"Illegal dump_modify command");
iarg += n;
}
}
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory
------------------------------------------------------------------------- */
bigint Dump::memory_usage()
{
bigint bytes = memory->usage(buf,size_one*maxbuf);
bytes += memory->usage(sbuf,maxsbuf);
if (sort_flag) {
if (sortcol == 0) bytes += memory->usage(ids,maxids);
bytes += memory->usage(bufsort,size_one*maxsort);
if (sortcol == 0) bytes += memory->usage(idsort,maxsort);
bytes += memory->usage(index,maxsort);
bytes += memory->usage(proclist,maxproc);
if (irregular) bytes += irregular->memory_usage();
}
return bytes;
}
diff --git a/src/dump.h b/src/dump.h
index ce2f0dc4e..1c8017ee9 100644
--- a/src/dump.h
+++ b/src/dump.h
@@ -1,182 +1,183 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_DUMP_H
#define LMP_DUMP_H
#include "mpi.h"
#include "stdio.h"
#include "pointers.h"
namespace LAMMPS_NS {
class Dump : protected Pointers {
public:
char *id; // user-defined name of Dump
char *style; // style of Dump
int igroup,groupbit; // group that Dump is performed on
int first_flag; // 0 if no initial dump, 1 if yes initial dump
int clearstep; // 1 if dump invokes computes, 0 if not
int comm_forward; // size of forward communication (0 if none)
int comm_reverse; // size of reverse communication (0 if none)
// static variable across all Dump objects
static Dump *dumpptr; // holds a ptr to Dump currently being used
Dump(class LAMMPS *, int, char **);
virtual ~Dump();
void init();
virtual void write();
virtual int pack_comm(int, int *, double *, int, int *) {return 0;}
virtual void unpack_comm(int, int, double *) {}
virtual int pack_reverse_comm(int, int, double *) {return 0;}
virtual void unpack_reverse_comm(int, int *, double *) {}
void modify_params(int, char **);
virtual bigint memory_usage();
protected:
int me,nprocs; // proc info
char *filename; // user-specified file
int compressed; // 1 if dump file is written compressed, 0 no
int binary; // 1 if dump file is written binary, 0 no
int multifile; // 0 = one big file, 1 = one file per timestep
int multiproc; // 0 = proc 0 writes for all
// else # of procs writing files
int nclusterprocs; // # of procs in my cluster that write to one file
int filewriter; // 1 if this proc writes a file, else 0
int fileproc; // ID of proc in my cluster who writes to file
char *multiname; // filename with % converted to cluster ID
MPI_Comm clustercomm; // MPI communicator within my cluster of procs
int header_flag; // 0 = item, 2 = xyz
int flush_flag; // 0 if no flush, 1 if flush every dump
int sort_flag; // 1 if sorted output
int append_flag; // 1 if open file in append mode, 0 if not
int buffer_allow; // 1 if style allows for buffer_flag, 0 if not
int buffer_flag; // 1 if buffer output as one big string, 0 if not
int padflag; // timestep padding in filename
int singlefile_opened; // 1 = one big file, already opened, else 0
int sortcol; // 0 to sort on ID, 1-N on columns
int sortcolm1; // sortcol - 1
int sortorder; // ASCEND or DESCEND
char boundstr[9]; // encoding of boundary flags
char *format_default; // default format string
char *format_user; // format string set by user
char *format; // format string for the file write
FILE *fp; // file to write dump to
int size_one; // # of quantities for one atom
int nme; // # of atoms in this dump from me
int nsme; // # of chars in string output from me
double boxxlo,boxxhi; // local copies of domain values
double boxylo,boxyhi; // lo/hi are bounding box for triclinic
double boxzlo,boxzhi;
double boxxy,boxxz,boxyz;
bigint ntotal; // total # of per-atom lines in snapshot
int reorderflag; // 1 if OK to reorder instead of sort
int ntotal_reorder; // # of atoms that must be in snapshot
int nme_reorder; // # of atoms I must own in snapshot
- int idlo; // lowest ID I own when reordering
+ tagint idlo; // lowest ID I own when reordering
int maxbuf; // size of buf
double *buf; // memory for atom quantities
int maxsbuf; // size of sbuf
char *sbuf; // memory for atom quantities in string format
int maxids; // size of ids
int maxsort; // size of bufsort, idsort, index
int maxproc; // size of proclist
- int *ids; // list of atom IDs, if sorting on IDs
+ tagint *ids; // list of atom IDs, if sorting on IDs
double *bufsort;
- int *idsort,*index,*proclist;
+ tagint *idsort;
+ int *index,*proclist;
class Irregular *irregular;
virtual void init_style() = 0;
virtual void openfile();
virtual int modify_param(int, char **) {return 0;}
virtual void write_header(bigint) = 0;
virtual int count();
- virtual void pack(int *) = 0;
+ virtual void pack(tagint *) = 0;
virtual int convert_string(int, double *) {return 0;}
virtual void write_data(int, double *) = 0;
void sort();
static int idcompare(const void *, const void *);
static int bufcompare(const void *, const void *);
static int bufcompare_reverse(const void *, const void *);
};
}
#endif
/* ERROR/WARNING messages:
E: Cannot dump sort when multiple procs write the dump file
UNDOCUMENTED
E: Cannot dump sort on atom IDs with no atom IDs defined
Self-explanatory.
E: Dump sort column is invalid
Self-explanatory.
E: Too many atoms to dump sort
Cannot sort when running with more than 2^31 atoms.
E: Too much per-proc info for dump
Number of local atoms times number of columns must fit in a 32-bit
integer for dump.
E: Cannot open gzipped file
LAMMPS was compiled without support for reading and writing gzipped
files through a pipeline to the gzip program with -DLAMMPS_GZIP.
E: Cannot open dump file
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.
E: Illegal ... command
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.
E: Cannot use dump_modify fileper without % in dump file name
UNDOCUMENTED
E: Cannot use dump_modify nfile without % in dump file name
UNDOCUMENTED
*/
diff --git a/src/dump_atom.cpp b/src/dump_atom.cpp
index 1a1313e3a..068c4e3df 100644
--- a/src/dump_atom.cpp
+++ b/src/dump_atom.cpp
@@ -1,501 +1,501 @@
/* ----------------------------------------------------------------------
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 "dump_atom.h"
#include "domain.h"
#include "atom.h"
#include "update.h"
#include "group.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define ONELINE 256
#define DELTA 1048576
/* ---------------------------------------------------------------------- */
DumpAtom::DumpAtom(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg)
{
if (narg != 5) error->all(FLERR,"Illegal dump atom command");
scale_flag = 1;
image_flag = 0;
buffer_allow = 1;
buffer_flag = 1;
format_default = NULL;
}
/* ---------------------------------------------------------------------- */
void DumpAtom::init_style()
{
if (image_flag == 0) size_one = 5;
else size_one = 8;
// default format depends on image flags
delete [] format;
if (format_user) {
int n = strlen(format_user) + 2;
format = new char[n];
strcpy(format,format_user);
strcat(format,"\n");
} else {
char *str;
- if (image_flag == 0) str = (char *) "%d %d %g %g %g";
- else str = (char *) "%d %d %g %g %g %d %d %d";
+ if (image_flag == 0) str = (char *) TAGINT_FORMAT " %d %g %g %g";
+ else str = (char *) TAGINT_FORMAT " %d %g %g %g %d %d %d";
int n = strlen(str) + 2;
format = new char[n];
strcpy(format,str);
strcat(format,"\n");
}
// setup boundary string
domain->boundary_string(boundstr);
// setup column string
if (scale_flag == 0 && image_flag == 0)
columns = (char *) "id type x y z";
else if (scale_flag == 0 && image_flag == 1)
columns = (char *) "id type x y z ix iy iz";
else if (scale_flag == 1 && image_flag == 0)
columns = (char *) "id type xs ys zs";
else if (scale_flag == 1 && image_flag == 1)
columns = (char *) "id type xs ys zs ix iy iz";
// setup function ptrs
if (binary && domain->triclinic == 0)
header_choice = &DumpAtom::header_binary;
else if (binary && domain->triclinic == 1)
header_choice = &DumpAtom::header_binary_triclinic;
else if (!binary && domain->triclinic == 0)
header_choice = &DumpAtom::header_item;
else if (!binary && domain->triclinic == 1)
header_choice = &DumpAtom::header_item_triclinic;
if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0)
pack_choice = &DumpAtom::pack_scale_noimage;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0)
pack_choice = &DumpAtom::pack_scale_image;
else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1)
pack_choice = &DumpAtom::pack_scale_noimage_triclinic;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1)
pack_choice = &DumpAtom::pack_scale_image_triclinic;
else if (scale_flag == 0 && image_flag == 0)
pack_choice = &DumpAtom::pack_noscale_noimage;
else if (scale_flag == 0 && image_flag == 1)
pack_choice = &DumpAtom::pack_noscale_image;
if (image_flag == 0) convert_choice = &DumpAtom::convert_noimage;
else convert_choice = &DumpAtom::convert_image;
if (binary) write_choice = &DumpAtom::write_binary;
else if (buffer_flag == 1) write_choice = &DumpAtom::write_string;
else if (image_flag == 0) write_choice = &DumpAtom::write_lines_noimage;
else if (image_flag == 1) write_choice = &DumpAtom::write_lines_image;
// open single file, one time only
if (multifile == 0) openfile();
}
/* ---------------------------------------------------------------------- */
int DumpAtom::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"scale") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"yes") == 0) scale_flag = 1;
else if (strcmp(arg[1],"no") == 0) scale_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
return 2;
} else if (strcmp(arg[0],"image") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"yes") == 0) image_flag = 1;
else if (strcmp(arg[1],"no") == 0) image_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
return 2;
}
return 0;
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_header(bigint ndump)
{
if (multiproc) (this->*header_choice)(ndump);
else if (me == 0) (this->*header_choice)(ndump);
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack(int *ids)
+void DumpAtom::pack(tagint *ids)
{
(this->*pack_choice)(ids);
}
/* ---------------------------------------------------------------------- */
int DumpAtom::convert_string(int n, double *mybuf)
{
return (this->*convert_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_data(int n, double *mybuf)
{
(this->*write_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_binary(bigint ndump)
{
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp);
fwrite(&boxxlo,sizeof(double),1,fp);
fwrite(&boxxhi,sizeof(double),1,fp);
fwrite(&boxylo,sizeof(double),1,fp);
fwrite(&boxyhi,sizeof(double),1,fp);
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_binary_triclinic(bigint ndump)
{
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp);
fwrite(&boxxlo,sizeof(double),1,fp);
fwrite(&boxxhi,sizeof(double),1,fp);
fwrite(&boxylo,sizeof(double),1,fp);
fwrite(&boxyhi,sizeof(double),1,fp);
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&boxxy,sizeof(double),1,fp);
fwrite(&boxxz,sizeof(double),1,fp);
fwrite(&boxyz,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_item(bigint ndump)
{
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF ATOMS\n");
fprintf(fp,BIGINT_FORMAT "\n",ndump);
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: ATOMS %s\n",columns);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_item_triclinic(bigint ndump)
{
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF ATOMS\n");
fprintf(fp,BIGINT_FORMAT "\n",ndump);
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);
fprintf(fp,"ITEM: ATOMS %s\n",columns);
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_scale_image(int *ids)
+void DumpAtom::pack_scale_image(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
imageint *image = atom->image;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
double invxprd = 1.0/domain->xprd;
double invyprd = 1.0/domain->yprd;
double invzprd = 1.0/domain->zprd;
m = n = 00;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
buf[m++] = (x[i][0] - boxxlo) * invxprd;
buf[m++] = (x[i][1] - boxylo) * invyprd;
buf[m++] = (x[i][2] - boxzlo) * invzprd;
buf[m++] = (image[i] & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMG2BITS) - IMGMAX;
if (ids) ids[n++] = tag[i];
}
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_scale_noimage(int *ids)
+void DumpAtom::pack_scale_noimage(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
double invxprd = 1.0/domain->xprd;
double invyprd = 1.0/domain->yprd;
double invzprd = 1.0/domain->zprd;
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
buf[m++] = (x[i][0] - boxxlo) * invxprd;
buf[m++] = (x[i][1] - boxylo) * invyprd;
buf[m++] = (x[i][2] - boxzlo) * invzprd;
if (ids) ids[n++] = tag[i];
}
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_scale_image_triclinic(int *ids)
+void DumpAtom::pack_scale_image_triclinic(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
imageint *image = atom->image;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
double lamda[3];
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
domain->x2lamda(x[i],lamda);
buf[m++] = lamda[0];
buf[m++] = lamda[1];
buf[m++] = lamda[2];
buf[m++] = (image[i] & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMG2BITS) - IMGMAX;
if (ids) ids[n++] = tag[i];
}
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_scale_noimage_triclinic(int *ids)
+void DumpAtom::pack_scale_noimage_triclinic(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
double lamda[3];
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
domain->x2lamda(x[i],lamda);
buf[m++] = lamda[0];
buf[m++] = lamda[1];
buf[m++] = lamda[2];
if (ids) ids[n++] = tag[i];
}
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_noscale_image(int *ids)
+void DumpAtom::pack_noscale_image(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
imageint *image = atom->image;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
buf[m++] = (image[i] & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
buf[m++] = (image[i] >> IMG2BITS) - IMGMAX;
if (ids) ids[n++] = tag[i];
}
}
/* ---------------------------------------------------------------------- */
-void DumpAtom::pack_noscale_noimage(int *ids)
+void DumpAtom::pack_noscale_noimage(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
if (ids) ids[n++] = tag[i];
}
}
/* ----------------------------------------------------------------------
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 DumpAtom::convert_image(int n, double *mybuf)
{
int offset = 0;
int m = 0;
for (int i = 0; i < n; i++) {
if (offset + ONELINE > maxsbuf) {
if ((bigint) maxsbuf + DELTA > MAXSMALLINT) return -1;
maxsbuf += DELTA;
memory->grow(sbuf,maxsbuf,"dump:sbuf");
}
offset += sprintf(&sbuf[offset],format,
- static_cast<int> (mybuf[m]),
+ static_cast<tagint> (mybuf[m]),
static_cast<int> (mybuf[m+1]),
mybuf[m+2],mybuf[m+3],mybuf[m+4],
static_cast<int> (mybuf[m+5]),
static_cast<int> (mybuf[m+6]),
static_cast<int> (mybuf[m+7]));
m += size_one;
}
return offset;
}
/* ---------------------------------------------------------------------- */
int DumpAtom::convert_noimage(int n, double *mybuf)
{
int offset = 0;
int m = 0;
for (int i = 0; i < n; i++) {
if (offset + ONELINE > maxsbuf) {
if ((bigint) maxsbuf + DELTA > MAXSMALLINT) return -1;
maxsbuf += DELTA;
memory->grow(sbuf,maxsbuf,"dump:sbuf");
}
offset += sprintf(&sbuf[offset],format,
- static_cast<int> (mybuf[m]),
+ static_cast<tagint> (mybuf[m]),
static_cast<int> (mybuf[m+1]),
mybuf[m+2],mybuf[m+3],mybuf[m+4]);
m += size_one;
}
return offset;
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_binary(int n, double *mybuf)
{
n *= size_one;
fwrite(&n,sizeof(int),1,fp);
fwrite(mybuf,sizeof(double),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_string(int n, double *mybuf)
{
fwrite(mybuf,sizeof(char),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_lines_image(int n, double *mybuf)
{
int m = 0;
for (int i = 0; i < n; i++) {
fprintf(fp,format,
- static_cast<int> (mybuf[m]), static_cast<int> (mybuf[m+1]),
+ static_cast<tagint> (mybuf[m]), static_cast<int> (mybuf[m+1]),
mybuf[m+2],mybuf[m+3],mybuf[m+4], static_cast<int> (mybuf[m+5]),
static_cast<int> (mybuf[m+6]), static_cast<int> (mybuf[m+7]));
m += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpAtom::write_lines_noimage(int n, double *mybuf)
{
int m = 0;
for (int i = 0; i < n; i++) {
fprintf(fp,format,
- static_cast<int> (mybuf[m]), static_cast<int> (mybuf[m+1]),
+ static_cast<tagint> (mybuf[m]), static_cast<int> (mybuf[m+1]),
mybuf[m+2],mybuf[m+3],mybuf[m+4]);
m += size_one;
}
}
diff --git a/src/dump_atom.h b/src/dump_atom.h
index 055e7787c..ce317fea4 100644
--- a/src/dump_atom.h
+++ b/src/dump_atom.h
@@ -1,86 +1,86 @@
/* -*- 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 DUMP_CLASS
DumpStyle(atom,DumpAtom)
#else
#ifndef LMP_DUMP_ATOM_H
#define LMP_DUMP_ATOM_H
#include "dump.h"
namespace LAMMPS_NS {
class DumpAtom : public Dump {
public:
DumpAtom(LAMMPS *, int, char**);
protected:
int scale_flag; // 1 if atom coords are scaled, 0 if no
int image_flag; // 1 if append box count to atom coords, 0 if no
char *columns; // column labels
void init_style();
int modify_param(int, char **);
void write_header(bigint);
- void pack(int *);
+ void pack(tagint *);
int convert_string(int, double *);
void write_data(int, double *);
typedef void (DumpAtom::*FnPtrHeader)(bigint);
FnPtrHeader header_choice; // ptr to write header functions
void header_binary(bigint);
void header_binary_triclinic(bigint);
void header_item(bigint);
void header_item_triclinic(bigint);
- typedef void (DumpAtom::*FnPtrPack)(int *);
+ typedef void (DumpAtom::*FnPtrPack)(tagint *);
FnPtrPack pack_choice; // ptr to pack functions
- void pack_scale_image(int *);
- void pack_scale_noimage(int *);
- void pack_noscale_image(int *);
- void pack_noscale_noimage(int *);
- void pack_scale_image_triclinic(int *);
- void pack_scale_noimage_triclinic(int *);
+ void pack_scale_image(tagint *);
+ void pack_scale_noimage(tagint *);
+ void pack_noscale_image(tagint *);
+ void pack_noscale_noimage(tagint *);
+ void pack_scale_image_triclinic(tagint *);
+ void pack_scale_noimage_triclinic(tagint *);
typedef int (DumpAtom::*FnPtrConvert)(int, double *);
FnPtrConvert convert_choice; // ptr to convert data functions
int convert_image(int, double *);
int convert_noimage(int, double *);
typedef void (DumpAtom::*FnPtrWrite)(int, double *);
FnPtrWrite write_choice; // ptr to write data functions
void write_binary(int, double *);
void write_string(int, double *);
void write_lines_image(int, double *);
void write_lines_noimage(int, double *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
*/
diff --git a/src/dump_cfg.cpp b/src/dump_cfg.cpp
index 6ebf9c898..558512ace 100644
--- a/src/dump_cfg.cpp
+++ b/src/dump_cfg.cpp
@@ -1,310 +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 author: Liang Wan (Chinese Academy of Sciences)
Memory efficiency improved by Ray Shan (Sandia)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "dump_cfg.h"
#include "atom.h"
#include "domain.h"
#include "comm.h"
#include "modify.h"
#include "compute.h"
#include "input.h"
#include "fix.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
-enum{INT,DOUBLE,STRING}; // same as in DumpCustom
+enum{INT,DOUBLE,STRING,BIGINT}; // same as in DumpCustom
#define UNWRAPEXPAND 10.0
#define ONEFIELD 32
#define DELTA 1048576
/* ---------------------------------------------------------------------- */
DumpCFG::DumpCFG(LAMMPS *lmp, int narg, char **arg) :
DumpCustom(lmp, narg, arg)
{
if (narg < 10 ||
strcmp(arg[5],"mass") != 0 || strcmp(arg[6],"type") != 0 ||
(strcmp(arg[7],"xs") != 0 && strcmp(arg[7],"xsu") != 0) ||
(strcmp(arg[8],"ys") != 0 && strcmp(arg[8],"ysu") != 0) ||
(strcmp(arg[9],"zs") != 0 && strcmp(arg[9],"zsu") != 0))
error->all(FLERR,"Dump cfg arguments must start with "
"'mass type xs ys zs' or 'mass type xsu ysu zsu'");
if (strcmp(arg[7],"xs") == 0)
if (strcmp(arg[8],"ysu") == 0 || strcmp(arg[9],"zsu") == 0)
error->all(FLERR,
"Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu");
else unwrapflag = 0;
else if (strcmp(arg[8],"ys") == 0 || strcmp(arg[9],"zs") == 0)
error->all(FLERR,
"Dump cfg arguments can not mix xs|ys|zs with xsu|ysu|zsu");
else unwrapflag = 1;
// setup auxiliary property name strings
// convert 'X_ID[m]' (X=c,f,v) to 'ID_m'
if (narg > 10) auxname = new char*[narg-10];
else auxname = NULL;
int i = 0;
for (int iarg = 10; iarg < narg; iarg++, i++) {
if (strncmp(arg[iarg],"c_",2) == 0 ||
strncmp(arg[iarg],"f_",2) == 0 ||
strncmp(arg[iarg],"v_",2) == 0) {
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 keyword in dump cfg command");
*ptr = '\0';
*(ptr+2) = '\0';
auxname[i] = new char[strlen(suffix) + 3];
strcpy(auxname[i],suffix);
strcat(auxname[i],"_");
strcat(auxname[i],ptr+1);
} else {
auxname[i] = new char[strlen(suffix) + 1];
strcpy(auxname[i],suffix);
}
delete [] suffix;
} else {
auxname[i] = new char[strlen(arg[iarg]) + 1];
strcpy(auxname[i],arg[iarg]);
}
}
}
/* ---------------------------------------------------------------------- */
DumpCFG::~DumpCFG()
{
if (auxname) {
for (int i = 0; i < nfield-5; i++) delete [] auxname[i];
delete [] auxname;
}
}
/* ---------------------------------------------------------------------- */
void DumpCFG::init_style()
{
if (multifile == 0)
error->all(FLERR,"Dump cfg requires one snapshot per file");
DumpCustom::init_style();
// setup function ptrs
if (buffer_flag == 1) write_choice = &DumpCFG::write_string;
else write_choice = &DumpCFG::write_lines;
}
/* ---------------------------------------------------------------------- */
void DumpCFG::write_header(bigint n)
{
// special handling for atom style peri
// use average volume of particles to scale particles to mimic C atoms
// scale box dimension to sc lattice for C with sigma = 1.44 Angstroms
// special handling for unwrapped coordinates
double scale;
if (atom->peri_flag) {
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) scale = 1.44 / pow(vave,1.0/3.0);
} else if (unwrapflag == 1) scale = UNWRAPEXPAND;
else scale = 1.0;
char str[64];
sprintf(str,"Number of particles = %s\n",BIGINT_FORMAT);
fprintf(fp,str,n);
fprintf(fp,"A = %g Angstrom (basic length-scale)\n",scale);
fprintf(fp,"H0(1,1) = %g A\n",domain->xprd);
fprintf(fp,"H0(1,2) = 0 A \n");
fprintf(fp,"H0(1,3) = 0 A \n");
fprintf(fp,"H0(2,1) = %g A \n",domain->xy);
fprintf(fp,"H0(2,2) = %g A\n",domain->yprd);
fprintf(fp,"H0(2,3) = 0 A \n");
fprintf(fp,"H0(3,1) = %g A \n",domain->xz);
fprintf(fp,"H0(3,2) = %g A \n",domain->yz);
fprintf(fp,"H0(3,3) = %g A\n",domain->zprd);
fprintf(fp,".NO_VELOCITY.\n");
fprintf(fp,"entry_count = %d\n",nfield-2);
for (int i = 0; i < nfield-5; i++)
fprintf(fp,"auxiliary[%d] = %s\n",i,auxname[i]);
}
/* ----------------------------------------------------------------------
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 DumpCFG::convert_string(int n, double *mybuf)
{
int i,j;
int offset = 0;
int m = 0;
if (unwrapflag == 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 (j == 0) {
offset += sprintf(&sbuf[offset],"%f \n",mybuf[m]);
} else if (j == 1) {
offset += sprintf(&sbuf[offset],"%s \n",typenames[(int) mybuf[m]]);
} else if (j >= 2) {
if (vtype[j] == INT)
offset +=
sprintf(&sbuf[offset],vformat[j],static_cast<int> (mybuf[m]));
else if (vtype[j] == DOUBLE)
offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
offset +=
sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ offset +=
+ sprintf(&sbuf[offset],vformat[j],static_cast<bigint> (mybuf[m]));
}
m++;
}
offset += sprintf(&sbuf[offset],"\n");
}
} else if (unwrapflag == 1) {
double unwrap_coord;
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 (j == 0) {
offset += sprintf(&sbuf[offset],"%f \n",mybuf[m]);
} else if (j == 1) {
offset += sprintf(&sbuf[offset],"%s \n",typenames[(int) mybuf[m]]);
} else if (j >= 2 && j <= 4) {
unwrap_coord = (mybuf[m] - 0.5)/UNWRAPEXPAND + 0.5;
offset += sprintf(&sbuf[offset],vformat[j],unwrap_coord);
} else if (j >= 5 ) {
if (vtype[j] == INT)
offset +=
sprintf(&sbuf[offset],vformat[j],static_cast<int> (mybuf[m]));
else if (vtype[j] == DOUBLE)
offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
offset +=
sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ offset +=
+ sprintf(&sbuf[offset],vformat[j],static_cast<bigint> (mybuf[m]));
}
m++;
}
offset += sprintf(&sbuf[offset],"\n");
}
}
return offset;
}
/* ---------------------------------------------------------------------- */
void DumpCFG::write_data(int n, double *mybuf)
{
(this->*write_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpCFG::write_string(int n, double *mybuf)
{
fwrite(mybuf,sizeof(char),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpCFG::write_lines(int n, double *mybuf)
{
int i,j,m;
if (unwrapflag == 0) {
m = 0;
for (i = 0; i < n; i++) {
for (j = 0; j < size_one; j++) {
if (j == 0) {
fprintf(fp,"%f \n",mybuf[m]);
} else if (j == 1) {
fprintf(fp,"%s \n",typenames[(int) mybuf[m]]);
} else if (j >= 2) {
if (vtype[j] == INT)
fprintf(fp,vformat[j],static_cast<int> (mybuf[m]));
else if (vtype[j] == DOUBLE)
fprintf(fp,vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
fprintf(fp,vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ fprintf(fp,vformat[j],static_cast<bigint> (mybuf[m]));
}
m++;
}
fprintf(fp,"\n");
}
} else if (unwrapflag == 1) {
m = 0;
double unwrap_coord;
for (i = 0; i < n; i++) {
for (j = 0; j < size_one; j++) {
if (j == 0) {
fprintf(fp,"%f \n",mybuf[m]);
} else if (j == 1) {
fprintf(fp,"%s \n",typenames[(int) mybuf[m]]);
} else if (j >= 2 && j <= 4) {
unwrap_coord = (mybuf[m] - 0.5)/UNWRAPEXPAND + 0.5;
fprintf(fp,vformat[j],unwrap_coord);
} else if (j >= 5 ) {
if (vtype[j] == INT)
fprintf(fp,vformat[j],static_cast<int> (mybuf[m]));
else if (vtype[j] == DOUBLE)
fprintf(fp,vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
fprintf(fp,vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ fprintf(fp,vformat[j],static_cast<bigint> (mybuf[m]));
}
m++;
}
fprintf(fp,"\n");
}
}
}
diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp
index 32b3e4eb3..f0c037104 100644
--- a/src/dump_custom.cpp
+++ b/src/dump_custom.cpp
@@ -1,2460 +1,2467 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "dump_custom.h"
#include "atom.h"
#include "force.h"
#include "domain.h"
#include "region.h"
#include "group.h"
#include "input.h"
#include "variable.h"
#include "update.h"
#include "modify.h"
#include "compute.h"
#include "fix.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
// customize by adding keyword
// also customize compute_atom_property.cpp
enum{ID,MOL,TYPE,ELEMENT,MASS,
X,Y,Z,XS,YS,ZS,XSTRI,YSTRI,ZSTRI,XU,YU,ZU,XUTRI,YUTRI,ZUTRI,
XSU,YSU,ZSU,XSUTRI,YSUTRI,ZSUTRI,
IX,IY,IZ,
VX,VY,VZ,FX,FY,FZ,
Q,MUX,MUY,MUZ,MU,RADIUS,DIAMETER,
OMEGAX,OMEGAY,OMEGAZ,ANGMOMX,ANGMOMY,ANGMOMZ,
TQX,TQY,TQZ,SPIN,ERADIUS,ERVEL,ERFORCE,
COMPUTE,FIX,VARIABLE};
enum{LT,LE,GT,GE,EQ,NEQ};
-enum{INT,DOUBLE,STRING}; // same as in DumpCFG
+enum{INT,DOUBLE,STRING,BIGINT}; // same as in DumpCFG
#define INVOKED_PERATOM 8
#define ONEFIELD 32
#define DELTA 1048576
/* ---------------------------------------------------------------------- */
DumpCustom::DumpCustom(LAMMPS *lmp, int narg, char **arg) :
Dump(lmp, narg, arg)
{
if (narg == 5) error->all(FLERR,"No dump custom arguments specified");
clearstep = 1;
nevery = force->inumeric(FLERR,arg[3]);
// size_one may be shrunk below if additional optional args exist
size_one = nfield = narg - 5;
pack_choice = new FnPtrPack[nfield];
vtype = new int[nfield];
buffer_allow = 1;
buffer_flag = 1;
iregion = -1;
idregion = NULL;
nthresh = 0;
thresh_array = NULL;
thresh_op = NULL;
thresh_value = NULL;
// computes, fixes, variables which the dump accesses
memory->create(field2index,nfield,"dump:field2index");
memory->create(argindex,nfield,"dump:argindex");
ncompute = 0;
id_compute = NULL;
compute = NULL;
nfix = 0;
id_fix = NULL;
fix = NULL;
nvariable = 0;
id_variable = NULL;
variable = NULL;
vbuf = NULL;
// process attributes
// ioptional = start of additional optional args
// only dump image and dump movie styles process optional args
ioptional = parse_fields(narg,arg);
if (ioptional < narg &&
strcmp(style,"image") != 0 && strcmp(style,"movie") != 0)
error->all(FLERR,"Invalid attribute in dump custom command");
size_one = nfield = ioptional - 5;
// atom selection arrays
maxlocal = 0;
choose = NULL;
dchoose = NULL;
clist = NULL;
// element names
ntypes = atom->ntypes;
typenames = NULL;
// 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 ");
else if (vtype[i] == STRING) strcat(format_default,"%s ");
+ else if (vtype[i] == BIGINT) strcat(format_default,BIGINT_FORMAT " ");
vformat[i] = NULL;
}
// setup column string
int n = 0;
for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2;
columns = new char[n];
columns[0] = '\0';
for (int iarg = 5; iarg < narg; iarg++) {
strcat(columns,arg[iarg]);
strcat(columns," ");
}
}
/* ---------------------------------------------------------------------- */
DumpCustom::~DumpCustom()
{
delete [] pack_choice;
delete [] vtype;
memory->destroy(field2index);
memory->destroy(argindex);
delete [] idregion;
memory->destroy(thresh_array);
memory->destroy(thresh_op);
memory->destroy(thresh_value);
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 < nvariable; i++) delete [] id_variable[i];
memory->sfree(id_variable);
delete [] variable;
for (int i = 0; i < nvariable; i++) memory->destroy(vbuf[i]);
delete [] vbuf;
memory->destroy(choose);
memory->destroy(dchoose);
memory->destroy(clist);
if (typenames) {
for (int i = 1; i <= ntypes; i++) delete [] typenames[i];
delete [] typenames;
}
for (int i = 0; i < size_one; i++) delete [] vformat[i];
delete [] vformat;
delete [] columns;
}
/* ---------------------------------------------------------------------- */
void DumpCustom::init_style()
{
delete [] format;
char *str;
if (format_user) str = format_user;
else str = format_default;
int n = strlen(str) + 1;
format = new char[n];
strcpy(format,str);
// default for element names = C
if (typenames == NULL) {
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
typenames[itype] = new char[2];
strcpy(typenames[itype],"C");
}
}
// tokenize the format string and add space at end of each format element
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 string is too short");
delete [] vformat[i];
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 (binary && domain->triclinic == 0)
header_choice = &DumpCustom::header_binary;
else if (binary && domain->triclinic == 1)
header_choice = &DumpCustom::header_binary_triclinic;
else if (!binary && domain->triclinic == 0)
header_choice = &DumpCustom::header_item;
else if (!binary && domain->triclinic == 1)
header_choice = &DumpCustom::header_item_triclinic;
if (binary) write_choice = &DumpCustom::write_binary;
else if (buffer_flag == 1) write_choice = &DumpCustom::write_string;
else write_choice = &DumpCustom::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 custom 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 custom fix ID");
fix[i] = modify->fix[ifix];
if (nevery % modify->fix[ifix]->peratom_freq)
error->all(FLERR,"Dump custom and fix not computed at compatible times");
}
int ivariable;
for (int i = 0; i < nvariable; i++) {
ivariable = input->variable->find(id_variable[i]);
if (ivariable < 0)
error->all(FLERR,"Could not find dump custom variable name");
variable[i] = ivariable;
}
// set index and check validity of region
if (iregion >= 0) {
iregion = domain->find_region(idregion);
if (iregion == -1)
error->all(FLERR,"Region ID for dump custom does not exist");
}
// open single file, one time only
if (multifile == 0) openfile();
}
/* ---------------------------------------------------------------------- */
void DumpCustom::write_header(bigint ndump)
{
if (multiproc) (this->*header_choice)(ndump);
else if (me == 0) (this->*header_choice)(ndump);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_binary(bigint ndump)
{
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp);
fwrite(&boxxlo,sizeof(double),1,fp);
fwrite(&boxxhi,sizeof(double),1,fp);
fwrite(&boxylo,sizeof(double),1,fp);
fwrite(&boxyhi,sizeof(double),1,fp);
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_binary_triclinic(bigint ndump)
{
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
fwrite(&domain->boundary[0][0],6*sizeof(int),1,fp);
fwrite(&boxxlo,sizeof(double),1,fp);
fwrite(&boxxhi,sizeof(double),1,fp);
fwrite(&boxylo,sizeof(double),1,fp);
fwrite(&boxyhi,sizeof(double),1,fp);
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&boxxy,sizeof(double),1,fp);
fwrite(&boxxz,sizeof(double),1,fp);
fwrite(&boxyz,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_item(bigint ndump)
{
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF ATOMS\n");
fprintf(fp,BIGINT_FORMAT "\n",ndump);
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: ATOMS %s\n",columns);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_item_triclinic(bigint ndump)
{
fprintf(fp,"ITEM: TIMESTEP\n");
fprintf(fp,BIGINT_FORMAT "\n",update->ntimestep);
fprintf(fp,"ITEM: NUMBER OF ATOMS\n");
fprintf(fp,BIGINT_FORMAT "\n",ndump);
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);
fprintf(fp,"ITEM: ATOMS %s\n",columns);
}
/* ---------------------------------------------------------------------- */
int DumpCustom::count()
{
int i;
// grow choose and variable vbuf arrays if needed
int nlocal = atom->nlocal;
if (nlocal > maxlocal) {
maxlocal = atom->nmax;
memory->destroy(choose);
memory->destroy(dchoose);
memory->destroy(clist);
memory->create(choose,maxlocal,"dump:choose");
memory->create(dchoose,maxlocal,"dump:dchoose");
memory->create(clist,maxlocal,"dump:clist");
for (i = 0; i < nvariable; i++) {
memory->destroy(vbuf[i]);
memory->create(vbuf[i],maxlocal,"dump:vbuf");
}
}
// invoke Computes for per-atom quantities
if (ncompute) {
for (i = 0; i < ncompute; i++)
if (!(compute[i]->invoked_flag & INVOKED_PERATOM)) {
compute[i]->compute_peratom();
compute[i]->invoked_flag |= INVOKED_PERATOM;
}
}
// evaluate atom-style Variables for per-atom quantities
if (nvariable)
for (i = 0; i < nvariable; i++)
input->variable->compute_atom(variable[i],igroup,vbuf[i],1,0);
// choose all local atoms for output
for (i = 0; i < nlocal; i++) choose[i] = 1;
// un-choose if not in group
if (igroup) {
int *mask = atom->mask;
for (i = 0; i < nlocal; i++)
if (!(mask[i] & groupbit))
choose[i] = 0;
}
// un-choose if not in region
if (iregion >= 0) {
Region *region = domain->regions[iregion];
double **x = atom->x;
for (i = 0; i < nlocal; i++)
if (choose[i] && region->match(x[i][0],x[i][1],x[i][2]) == 0)
choose[i] = 0;
}
// un-choose if any threshhold criterion isn't met
if (nthresh) {
double *ptr;
double value;
int nstride;
int nlocal = atom->nlocal;
for (int ithresh = 0; ithresh < nthresh; ithresh++) {
// customize by adding to if statement
if (thresh_array[ithresh] == ID) {
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (i = 0; i < nlocal; i++) dchoose[i] = tag[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == MOL) {
if (!atom->molecule_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
int *molecule = atom->molecule;
for (i = 0; i < nlocal; i++) dchoose[i] = molecule[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == TYPE) {
int *type = atom->type;
for (i = 0; i < nlocal; i++) dchoose[i] = type[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ELEMENT) {
int *type = atom->type;
for (i = 0; i < nlocal; i++) dchoose[i] = type[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == MASS) {
if (atom->rmass) {
ptr = atom->rmass;
nstride = 1;
} else {
double *mass = atom->mass;
int *type = atom->type;
for (i = 0; i < nlocal; i++) dchoose[i] = mass[type[i]];
ptr = dchoose;
nstride = 1;
}
} else if (thresh_array[ithresh] == X) {
ptr = &atom->x[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == Y) {
ptr = &atom->x[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == Z) {
ptr = &atom->x[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == XS) {
double **x = atom->x;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = (x[i][0] - boxxlo) * invxprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YS) {
double **x = atom->x;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = (x[i][1] - boxylo) * invyprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZS) {
double **x = atom->x;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = (x[i][2] - boxzlo) * invzprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == XSTRI) {
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[0]*(x[i][0]-boxlo[0]) +
h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]);
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YSTRI) {
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[1]*(x[i][1]-boxlo[1]) +
h_inv[3]*(x[i][2]-boxlo[2]);
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZSTRI) {
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[2]*(x[i][2]-boxlo[2]);
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == XU) {
double **x = atom->x;
imageint *image = atom->image;
double xprd = domain->xprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = x[i][0] + ((image[i] & IMGMASK) - IMGMAX) * xprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YU) {
double **x = atom->x;
imageint *image = atom->image;
double yprd = domain->yprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = x[i][1] +
((image[i] >> IMGBITS & IMGMASK) - IMGMAX) * yprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZU) {
double **x = atom->x;
imageint *image = atom->image;
double zprd = domain->zprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = x[i][2] + ((image[i] >> IMG2BITS) - IMGMAX) * zprd;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == XUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int xbox,ybox,zbox;
for (i = 0; i < nlocal; i++) {
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dchoose[i] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
}
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int ybox,zbox;
for (i = 0; i < nlocal; i++) {
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dchoose[i] = x[i][1] + h[1]*ybox + h[3]*zbox;
}
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int zbox;
for (i = 0; i < nlocal; i++) {
zbox = (image[i] >> IMG2BITS) - IMGMAX;
dchoose[i] = x[i][2] + h[2]*zbox;
}
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == XSU) {
double **x = atom->x;
imageint *image = atom->image;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = (x[i][0] - boxxlo) * invxprd +
(image[i] & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YSU) {
double **x = atom->x;
imageint *image = atom->image;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (i = 0; i < nlocal; i++)
dchoose[i] =
(x[i][1] - boxylo) * invyprd +
(image[i] >> IMGBITS & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZSU) {
double **x = atom->x;
imageint *image = atom->image;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (i = 0; i < nlocal; i++)
dchoose[i] = (x[i][2] - boxzlo) * invzprd +
(image[i] >> IMG2BITS) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == XSUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[0]*(x[i][0]-boxlo[0]) +
h_inv[5]*(x[i][1]-boxlo[1]) +
h_inv[4]*(x[i][2]-boxlo[2]) +
(image[i] & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == YSUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[1]*(x[i][1]-boxlo[1]) +
h_inv[3]*(x[i][2]-boxlo[2]) +
(image[i] >> IMGBITS & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ZSUTRI) {
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (i = 0; i < nlocal; i++)
dchoose[i] = h_inv[2]*(x[i][2]-boxlo[2]) +
(image[i] >> IMG2BITS) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == IX) {
imageint *image = atom->image;
for (i = 0; i < nlocal; i++)
dchoose[i] = (image[i] & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == IY) {
imageint *image = atom->image;
for (i = 0; i < nlocal; i++)
dchoose[i] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == IZ) {
imageint *image = atom->image;
for (i = 0; i < nlocal; i++)
dchoose[i] = (image[i] >> IMG2BITS) - IMGMAX;
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == VX) {
ptr = &atom->v[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == VY) {
ptr = &atom->v[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == VZ) {
ptr = &atom->v[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == FX) {
ptr = &atom->f[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == FY) {
ptr = &atom->f[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == FZ) {
ptr = &atom->f[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == Q) {
if (!atom->q_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = atom->q;
nstride = 1;
} else if (thresh_array[ithresh] == MUX) {
if (!atom->mu_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->mu[0][0];
nstride = 4;
} else if (thresh_array[ithresh] == MUY) {
if (!atom->mu_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->mu[0][1];
nstride = 4;
} else if (thresh_array[ithresh] == MUZ) {
if (!atom->mu_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->mu[0][2];
nstride = 4;
} else if (thresh_array[ithresh] == MU) {
if (!atom->mu_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->mu[0][3];
nstride = 4;
} else if (thresh_array[ithresh] == RADIUS) {
if (!atom->radius_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = atom->radius;
nstride = 1;
} else if (thresh_array[ithresh] == DIAMETER) {
if (!atom->radius_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
double *radius = atom->radius;
for (i = 0; i < nlocal; i++) dchoose[i] = 2.0*radius[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == OMEGAX) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->omega[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == OMEGAY) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->omega[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == OMEGAZ) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->omega[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMX) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->angmom[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMY) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->angmom[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMZ) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->angmom[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == TQX) {
if (!atom->torque_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->torque[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == TQY) {
if (!atom->torque_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->torque[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == TQZ) {
if (!atom->torque_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = &atom->torque[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == SPIN) {
if (!atom->spin_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
int *spin = atom->spin;
for (i = 0; i < nlocal; i++) dchoose[i] = spin[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == ERADIUS) {
if (!atom->eradius_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = atom->eradius;
nstride = 1;
} else if (thresh_array[ithresh] == ERVEL) {
if (!atom->ervel_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = atom->ervel;
nstride = 1;
} else if (thresh_array[ithresh] == ERFORCE) {
if (!atom->erforce_flag)
error->all(FLERR,
"Threshhold for an atom property that isn't allocated");
ptr = atom->erforce;
nstride = 1;
} else if (thresh_array[ithresh] == COMPUTE) {
i = nfield + ithresh;
if (argindex[i] == 0) {
ptr = compute[field2index[i]]->vector_atom;
nstride = 1;
} else {
ptr = &compute[field2index[i]]->array_atom[0][argindex[i]-1];
nstride = compute[field2index[i]]->size_peratom_cols;
}
} else if (thresh_array[ithresh] == FIX) {
i = nfield + ithresh;
if (argindex[i] == 0) {
ptr = fix[field2index[i]]->vector_atom;
nstride = 1;
} else {
ptr = &fix[field2index[i]]->array_atom[0][argindex[i]-1];
nstride = fix[field2index[i]]->size_peratom_cols;
}
} else if (thresh_array[ithresh] == VARIABLE) {
i = nfield + ithresh;
ptr = vbuf[field2index[i]];
nstride = 1;
}
// unselect atoms that don't meet threshhold criterion
value = thresh_value[ithresh];
if (thresh_op[ithresh] == LT) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr >= value) choose[i] = 0;
} else if (thresh_op[ithresh] == LE) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr > value) choose[i] = 0;
} else if (thresh_op[ithresh] == GT) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr <= value) choose[i] = 0;
} else if (thresh_op[ithresh] == GE) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr < value) choose[i] = 0;
} else if (thresh_op[ithresh] == EQ) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr != value) choose[i] = 0;
} else if (thresh_op[ithresh] == NEQ) {
for (i = 0; i < nlocal; i++, ptr += nstride)
if (choose[i] && *ptr == value) choose[i] = 0;
}
}
}
// compress choose flags into clist
// nchoose = # of selected atoms
// clist[i] = local index of each selected atom
nchoose = 0;
for (i = 0; i < nlocal; i++)
if (choose[i]) clist[nchoose++] = i;
return nchoose;
}
/* ---------------------------------------------------------------------- */
-void DumpCustom::pack(int *ids)
+void DumpCustom::pack(tagint *ids)
{
for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n);
if (ids) {
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int i = 0; i < nchoose; i++)
ids[i] = tag[clist[i]];
}
}
/* ----------------------------------------------------------------------
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 DumpCustom::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 if (vtype[j] == DOUBLE)
offset += sprintf(&sbuf[offset],vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
offset += sprintf(&sbuf[offset],vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ offset += sprintf(&sbuf[offset],vformat[j],
+ static_cast<bigint> (mybuf[m]));
m++;
}
offset += sprintf(&sbuf[offset],"\n");
}
return offset;
}
/* ---------------------------------------------------------------------- */
void DumpCustom::write_data(int n, double *mybuf)
{
(this->*write_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::write_binary(int n, double *mybuf)
{
n *= size_one;
fwrite(&n,sizeof(int),1,fp);
fwrite(mybuf,sizeof(double),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::write_string(int n, double *mybuf)
{
fwrite(mybuf,sizeof(char),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::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 if (vtype[j] == DOUBLE) fprintf(fp,vformat[j],mybuf[m]);
else if (vtype[j] == STRING)
fprintf(fp,vformat[j],typenames[(int) mybuf[m]]);
+ else if (vtype[j] == BIGINT)
+ fprintf(fp,vformat[j],static_cast<bigint> (mybuf[m]));
m++;
}
fprintf(fp,"\n");
}
}
/* ---------------------------------------------------------------------- */
int DumpCustom::parse_fields(int narg, char **arg)
{
// customize by adding to if statement
int i;
for (int iarg = 5; iarg < narg; iarg++) {
i = iarg-5;
if (strcmp(arg[iarg],"id") == 0) {
pack_choice[i] = &DumpCustom::pack_id;
- vtype[i] = INT;
+ if (sizeof(tagint) == sizeof(smallint)) vtype[i] = INT;
+ else vtype[i] = BIGINT;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (!atom->molecule_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_molecule;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"type") == 0) {
pack_choice[i] = &DumpCustom::pack_type;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"element") == 0) {
pack_choice[i] = &DumpCustom::pack_type;
vtype[i] = STRING;
} else if (strcmp(arg[iarg],"mass") == 0) {
pack_choice[i] = &DumpCustom::pack_mass;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"x") == 0) {
pack_choice[i] = &DumpCustom::pack_x;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"y") == 0) {
pack_choice[i] = &DumpCustom::pack_y;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"z") == 0) {
pack_choice[i] = &DumpCustom::pack_z;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"xs") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xs_triclinic;
else pack_choice[i] = &DumpCustom::pack_xs;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"ys") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_ys_triclinic;
else pack_choice[i] = &DumpCustom::pack_ys;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"zs") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zs_triclinic;
else pack_choice[i] = &DumpCustom::pack_zs;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"xu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xu_triclinic;
else pack_choice[i] = &DumpCustom::pack_xu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"yu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_yu_triclinic;
else pack_choice[i] = &DumpCustom::pack_yu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"zu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zu_triclinic;
else pack_choice[i] = &DumpCustom::pack_zu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"xsu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_xsu_triclinic;
else pack_choice[i] = &DumpCustom::pack_xsu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"ysu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_ysu_triclinic;
else pack_choice[i] = &DumpCustom::pack_ysu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"zsu") == 0) {
if (domain->triclinic) pack_choice[i] = &DumpCustom::pack_zsu_triclinic;
else pack_choice[i] = &DumpCustom::pack_zsu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"ix") == 0) {
pack_choice[i] = &DumpCustom::pack_ix;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"iy") == 0) {
pack_choice[i] = &DumpCustom::pack_iy;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"iz") == 0) {
pack_choice[i] = &DumpCustom::pack_iz;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"vx") == 0) {
pack_choice[i] = &DumpCustom::pack_vx;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"vy") == 0) {
pack_choice[i] = &DumpCustom::pack_vy;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"vz") == 0) {
pack_choice[i] = &DumpCustom::pack_vz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"fx") == 0) {
pack_choice[i] = &DumpCustom::pack_fx;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"fy") == 0) {
pack_choice[i] = &DumpCustom::pack_fy;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"fz") == 0) {
pack_choice[i] = &DumpCustom::pack_fz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"q") == 0) {
if (!atom->q_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_q;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"mux") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_mux;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"muy") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_muy;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"muz") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_muz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"mu") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_mu;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"radius") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_radius;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"diameter") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_diameter;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"omegax") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_omegax;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"omegay") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_omegay;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"omegaz") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_omegaz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"angmomx") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_angmomx;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"angmomy") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_angmomy;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"angmomz") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_angmomz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"tqx") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_tqx;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"tqy") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_tqy;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"tqz") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
pack_choice[i] = &DumpCustom::pack_tqz;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"spin") == 0) {
if (!atom->spin_flag)
error->all(FLERR,"Dumping an atom quantity that isn't allocated");
pack_choice[i] = &DumpCustom::pack_spin;
vtype[i] = INT;
} else if (strcmp(arg[iarg],"eradius") == 0) {
if (!atom->eradius_flag)
error->all(FLERR,"Dumping an atom quantity that isn't allocated");
pack_choice[i] = &DumpCustom::pack_eradius;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"ervel") == 0) {
if (!atom->ervel_flag)
error->all(FLERR,"Dumping an atom quantity that isn't allocated");
pack_choice[i] = &DumpCustom::pack_ervel;
vtype[i] = DOUBLE;
} else if (strcmp(arg[iarg],"erforce") == 0) {
if (!atom->erforce_flag)
error->all(FLERR,"Dumping an atom quantity that isn't allocated");
pack_choice[i] = &DumpCustom::pack_erforce;
vtype[i] = DOUBLE;
// 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) {
pack_choice[i] = &DumpCustom::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 custom 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 custom compute ID");
if (modify->compute[n]->peratom_flag == 0)
error->all(FLERR,"Dump custom compute does not compute per-atom info");
if (argindex[i] == 0 && modify->compute[n]->size_peratom_cols > 0)
error->all(FLERR,
"Dump custom compute does not calculate per-atom vector");
if (argindex[i] > 0 && modify->compute[n]->size_peratom_cols == 0)
error->all(FLERR,\
"Dump custom compute does not calculate per-atom array");
if (argindex[i] > 0 &&
argindex[i] > modify->compute[n]->size_peratom_cols)
error->all(FLERR,"Dump custom 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) {
pack_choice[i] = &DumpCustom::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 custom 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 custom fix ID");
if (modify->fix[n]->peratom_flag == 0)
error->all(FLERR,"Dump custom fix does not compute per-atom info");
if (argindex[i] == 0 && modify->fix[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump custom fix does not compute per-atom vector");
if (argindex[i] > 0 && modify->fix[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump custom fix does not compute per-atom array");
if (argindex[i] > 0 &&
argindex[i] > modify->fix[n]->size_peratom_cols)
error->all(FLERR,"Dump custom fix vector is accessed out-of-range");
field2index[i] = add_fix(suffix);
delete [] suffix;
// variable value = v_name
} else if (strncmp(arg[iarg],"v_",2) == 0) {
pack_choice[i] = &DumpCustom::pack_variable;
vtype[i] = DOUBLE;
int n = strlen(arg[iarg]);
char *suffix = new char[n];
strcpy(suffix,&arg[iarg][2]);
argindex[i] = 0;
n = input->variable->find(suffix);
if (n < 0) error->all(FLERR,"Could not find dump custom variable name");
if (input->variable->atomstyle(n) == 0)
error->all(FLERR,"Dump custom variable is not atom-style variable");
field2index[i] = add_variable(suffix);
delete [] suffix;
} else return iarg;
}
return narg;
}
/* ----------------------------------------------------------------------
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 DumpCustom::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 DumpCustom::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;
}
/* ----------------------------------------------------------------------
add Variable to list of Variables used by dump
return index of where this Variable is in list
if already in list, do not add, just return index, else add to list
------------------------------------------------------------------------- */
int DumpCustom::add_variable(char *id)
{
int ivariable;
for (ivariable = 0; ivariable < nvariable; ivariable++)
if (strcmp(id,id_variable[ivariable]) == 0) break;
if (ivariable < nvariable) return ivariable;
id_variable = (char **)
memory->srealloc(id_variable,(nvariable+1)*sizeof(char *),
"dump:id_variable");
delete [] variable;
variable = new int[nvariable+1];
delete [] vbuf;
vbuf = new double*[nvariable+1];
for (int i = 0; i <= nvariable; i++) vbuf[i] = NULL;
int n = strlen(id) + 1;
id_variable[nvariable] = new char[n];
strcpy(id_variable[nvariable],id);
nvariable++;
return nvariable-1;
}
/* ---------------------------------------------------------------------- */
int DumpCustom::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"region") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"none") == 0) iregion = -1;
else {
iregion = domain->find_region(arg[1]);
if (iregion == -1)
error->all(FLERR,"Dump_modify region ID does not exist");
int n = strlen(arg[1]) + 1;
idregion = new char[n];
strcpy(idregion,arg[1]);
}
return 2;
}
if (strcmp(arg[0],"element") == 0) {
if (narg < ntypes+1)
error->all(FLERR,"Dump modify element names do not match atom types");
if (typenames) {
for (int i = 1; i <= ntypes; i++) delete [] typenames[i];
delete [] typenames;
typenames = NULL;
}
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
int n = strlen(arg[itype]) + 1;
typenames[itype] = new char[n];
strcpy(typenames[itype],arg[itype]);
}
return ntypes+1;
}
if (strcmp(arg[0],"thresh") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"none") == 0) {
if (nthresh) {
memory->destroy(thresh_array);
memory->destroy(thresh_op);
memory->destroy(thresh_value);
thresh_array = NULL;
thresh_op = NULL;
thresh_value = NULL;
}
nthresh = 0;
return 2;
}
if (narg < 4) error->all(FLERR,"Illegal dump_modify command");
// grow threshhold arrays
memory->grow(thresh_array,nthresh+1,"dump:thresh_array");
memory->grow(thresh_op,(nthresh+1),"dump:thresh_op");
memory->grow(thresh_value,(nthresh+1),"dump:thresh_value");
// set attribute type of threshhold
// customize by adding to if statement
if (strcmp(arg[1],"id") == 0) thresh_array[nthresh] = ID;
else if (strcmp(arg[1],"mol") == 0) thresh_array[nthresh] = MOL;
else if (strcmp(arg[1],"type") == 0) thresh_array[nthresh] = TYPE;
else if (strcmp(arg[1],"mass") == 0) thresh_array[nthresh] = MASS;
else if (strcmp(arg[1],"x") == 0) thresh_array[nthresh] = X;
else if (strcmp(arg[1],"y") == 0) thresh_array[nthresh] = Y;
else if (strcmp(arg[1],"z") == 0) thresh_array[nthresh] = Z;
else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = XS;
else if (strcmp(arg[1],"xs") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = XSTRI;
else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = YS;
else if (strcmp(arg[1],"ys") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = YSTRI;
else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = ZS;
else if (strcmp(arg[1],"zs") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = ZSTRI;
else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = XU;
else if (strcmp(arg[1],"xu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = XUTRI;
else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = YU;
else if (strcmp(arg[1],"yu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = YUTRI;
else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = ZU;
else if (strcmp(arg[1],"zu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = ZUTRI;
else if (strcmp(arg[1],"xsu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = XSU;
else if (strcmp(arg[1],"xsu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = XSUTRI;
else if (strcmp(arg[1],"ysu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = YSU;
else if (strcmp(arg[1],"ysu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = YSUTRI;
else if (strcmp(arg[1],"zsu") == 0 && domain->triclinic == 0)
thresh_array[nthresh] = ZSU;
else if (strcmp(arg[1],"zsu") == 0 && domain->triclinic == 1)
thresh_array[nthresh] = ZSUTRI;
else if (strcmp(arg[1],"ix") == 0) thresh_array[nthresh] = IX;
else if (strcmp(arg[1],"iy") == 0) thresh_array[nthresh] = IY;
else if (strcmp(arg[1],"iz") == 0) thresh_array[nthresh] = IZ;
else if (strcmp(arg[1],"vx") == 0) thresh_array[nthresh] = VX;
else if (strcmp(arg[1],"vy") == 0) thresh_array[nthresh] = VY;
else if (strcmp(arg[1],"vz") == 0) thresh_array[nthresh] = VZ;
else if (strcmp(arg[1],"fx") == 0) thresh_array[nthresh] = FX;
else if (strcmp(arg[1],"fy") == 0) thresh_array[nthresh] = FY;
else if (strcmp(arg[1],"fz") == 0) thresh_array[nthresh] = FZ;
else if (strcmp(arg[1],"q") == 0) thresh_array[nthresh] = Q;
else if (strcmp(arg[1],"mux") == 0) thresh_array[nthresh] = MUX;
else if (strcmp(arg[1],"muy") == 0) thresh_array[nthresh] = MUY;
else if (strcmp(arg[1],"muz") == 0) thresh_array[nthresh] = MUZ;
else if (strcmp(arg[1],"mu") == 0) thresh_array[nthresh] = MU;
else if (strcmp(arg[1],"radius") == 0) thresh_array[nthresh] = RADIUS;
else if (strcmp(arg[1],"diameter") == 0) thresh_array[nthresh] = DIAMETER;
else if (strcmp(arg[1],"omegax") == 0) thresh_array[nthresh] = OMEGAX;
else if (strcmp(arg[1],"omegay") == 0) thresh_array[nthresh] = OMEGAY;
else if (strcmp(arg[1],"omegaz") == 0) thresh_array[nthresh] = OMEGAZ;
else if (strcmp(arg[1],"angmomx") == 0) thresh_array[nthresh] = ANGMOMX;
else if (strcmp(arg[1],"angmomy") == 0) thresh_array[nthresh] = ANGMOMY;
else if (strcmp(arg[1],"angmomz") == 0) thresh_array[nthresh] = ANGMOMZ;
else if (strcmp(arg[1],"tqx") == 0) thresh_array[nthresh] = TQX;
else if (strcmp(arg[1],"tqy") == 0) thresh_array[nthresh] = TQY;
else if (strcmp(arg[1],"tqz") == 0) thresh_array[nthresh] = TQZ;
else if (strcmp(arg[1],"spin") == 0) thresh_array[nthresh] = SPIN;
else if (strcmp(arg[1],"eradius") == 0) thresh_array[nthresh] = ERADIUS;
else if (strcmp(arg[1],"ervel") == 0) thresh_array[nthresh] = ERVEL;
else if (strcmp(arg[1],"erforce") == 0) thresh_array[nthresh] = ERFORCE;
// compute value = c_ID
// if no trailing [], then arg is set to 0, else arg is between []
// must grow field2index and argindex arrays, since access is beyond nfield
else if (strncmp(arg[1],"c_",2) == 0) {
thresh_array[nthresh] = COMPUTE;
memory->grow(field2index,nfield+nthresh+1,"dump:field2index");
memory->grow(argindex,nfield+nthresh+1,"dump:argindex");
int n = strlen(arg[1]);
char *suffix = new char[n];
strcpy(suffix,&arg[1][2]);
char *ptr = strchr(suffix,'[');
if (ptr) {
if (suffix[strlen(suffix)-1] != ']')
error->all(FLERR,"Invalid attribute in dump modify command");
argindex[nfield+nthresh] = atoi(ptr+1);
*ptr = '\0';
} else argindex[nfield+nthresh] = 0;
n = modify->find_compute(suffix);
if (n < 0) error->all(FLERR,"Could not find dump modify compute ID");
if (modify->compute[n]->peratom_flag == 0)
error->all(FLERR,
"Dump modify compute ID does not compute per-atom info");
if (argindex[nfield+nthresh] == 0 &&
modify->compute[n]->size_peratom_cols > 0)
error->all(FLERR,
"Dump modify compute ID does not compute per-atom vector");
if (argindex[nfield+nthresh] > 0 &&
modify->compute[n]->size_peratom_cols == 0)
error->all(FLERR,
"Dump modify compute ID does not compute per-atom array");
if (argindex[nfield+nthresh] > 0 &&
argindex[nfield+nthresh] > modify->compute[n]->size_peratom_cols)
error->all(FLERR,"Dump modify compute ID vector is not large enough");
field2index[nfield+nthresh] = add_compute(suffix);
delete [] suffix;
// fix value = f_ID
// if no trailing [], then arg is set to 0, else arg is between []
// must grow field2index and argindex arrays, since access is beyond nfield
} else if (strncmp(arg[1],"f_",2) == 0) {
thresh_array[nthresh] = FIX;
memory->grow(field2index,nfield+nthresh+1,"dump:field2index");
memory->grow(argindex,nfield+nthresh+1,"dump:argindex");
int n = strlen(arg[1]);
char *suffix = new char[n];
strcpy(suffix,&arg[1][2]);
char *ptr = strchr(suffix,'[');
if (ptr) {
if (suffix[strlen(suffix)-1] != ']')
error->all(FLERR,"Invalid attribute in dump modify command");
argindex[nfield+nthresh] = atoi(ptr+1);
*ptr = '\0';
} else argindex[nfield+nthresh] = 0;
n = modify->find_fix(suffix);
if (n < 0) error->all(FLERR,"Could not find dump modify fix ID");
if (modify->fix[n]->peratom_flag == 0)
error->all(FLERR,"Dump modify fix ID does not compute per-atom info");
if (argindex[nfield+nthresh] == 0 &&
modify->fix[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump modify fix ID does not compute per-atom vector");
if (argindex[nfield+nthresh] > 0 &&
modify->fix[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump modify fix ID does not compute per-atom array");
if (argindex[nfield+nthresh] > 0 &&
argindex[nfield+nthresh] > modify->fix[n]->size_peratom_cols)
error->all(FLERR,"Dump modify fix ID vector is not large enough");
field2index[nfield+nthresh] = add_fix(suffix);
delete [] suffix;
// variable value = v_ID
// must grow field2index and argindex arrays, since access is beyond nfield
} else if (strncmp(arg[1],"v_",2) == 0) {
thresh_array[nthresh] = VARIABLE;
memory->grow(field2index,nfield+nthresh+1,"dump:field2index");
memory->grow(argindex,nfield+nthresh+1,"dump:argindex");
int n = strlen(arg[1]);
char *suffix = new char[n];
strcpy(suffix,&arg[1][2]);
argindex[nfield+nthresh] = 0;
n = input->variable->find(suffix);
if (n < 0) error->all(FLERR,"Could not find dump modify variable name");
if (input->variable->atomstyle(n) == 0)
error->all(FLERR,"Dump modify variable is not atom-style variable");
field2index[nfield+nthresh] = add_variable(suffix);
delete [] suffix;
} else error->all(FLERR,"Invalid dump_modify threshhold operator");
// set operation type of threshhold
if (strcmp(arg[2],"<") == 0) thresh_op[nthresh] = LT;
else if (strcmp(arg[2],"<=") == 0) thresh_op[nthresh] = LE;
else if (strcmp(arg[2],">") == 0) thresh_op[nthresh] = GT;
else if (strcmp(arg[2],">=") == 0) thresh_op[nthresh] = GE;
else if (strcmp(arg[2],"==") == 0) thresh_op[nthresh] = EQ;
else if (strcmp(arg[2],"!=") == 0) thresh_op[nthresh] = NEQ;
else error->all(FLERR,"Invalid dump_modify threshhold operator");
// set threshhold value
thresh_value[nthresh] = force->numeric(FLERR,arg[3]);
nthresh++;
return 4;
}
return 0;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory in buf, choose, variable arrays
------------------------------------------------------------------------- */
bigint DumpCustom::memory_usage()
{
bigint bytes = Dump::memory_usage();
bytes += memory->usage(choose,maxlocal);
bytes += memory->usage(dchoose,maxlocal);
bytes += memory->usage(clist,maxlocal);
bytes += memory->usage(vbuf,nvariable,maxlocal);
return bytes;
}
/* ----------------------------------------------------------------------
extraction of Compute, Fix, Variable results
------------------------------------------------------------------------- */
void DumpCustom::pack_compute(int n)
{
double *vector = compute[field2index[n]]->vector_atom;
double **array = compute[field2index[n]]->array_atom;
int index = argindex[n];
if (index == 0) {
for (int i = 0; i < nchoose; i++) {
buf[n] = vector[clist[i]];
n += size_one;
}
} else {
index--;
for (int i = 0; i < nchoose; i++) {
buf[n] = array[clist[i]][index];
n += size_one;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_fix(int n)
{
double *vector = fix[field2index[n]]->vector_atom;
double **array = fix[field2index[n]]->array_atom;
int index = argindex[n];
if (index == 0) {
for (int i = 0; i < nchoose; i++) {
buf[n] = vector[clist[i]];
n += size_one;
}
} else {
index--;
for (int i = 0; i < nchoose; i++) {
buf[n] = array[clist[i]][index];
n += size_one;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_variable(int n)
{
double *vector = vbuf[field2index[n]];
for (int i = 0; i < nchoose; i++) {
buf[n] = vector[clist[i]];
n += size_one;
}
}
/* ----------------------------------------------------------------------
one method for every attribute dump custom can output
the atom property is packed into buf starting at n with stride size_one
customize a new attribute by adding a method
------------------------------------------------------------------------- */
void DumpCustom::pack_id(int n)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int i = 0; i < nchoose; i++) {
buf[n] = tag[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_molecule(int n)
{
int *molecule = atom->molecule;
for (int i = 0; i < nchoose; i++) {
buf[n] = molecule[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_type(int n)
{
int *type = atom->type;
for (int i = 0; i < nchoose; i++) {
buf[n] = type[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_mass(int n)
{
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
if (rmass) {
for (int i = 0; i < nchoose; i++) {
buf[n] = rmass[clist[i]];
n += size_one;
}
} else {
for (int i = 0; i < nchoose; i++) {
buf[n] = mass[type[clist[i]]];
n += size_one;
}
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_x(int n)
{
double **x = atom->x;
for (int i = 0; i < nchoose; i++) {
buf[n] = x[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_y(int n)
{
double **x = atom->x;
for (int i = 0; i < nchoose; i++) {
buf[n] = x[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_z(int n)
{
double **x = atom->x;
for (int i = 0; i < nchoose; i++) {
buf[n] = x[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xs(int n)
{
double **x = atom->x;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (int i = 0; i < nchoose; i++) {
buf[n] = (x[clist[i]][0] - boxxlo) * invxprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ys(int n)
{
double **x = atom->x;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (int i = 0; i < nchoose; i++) {
buf[n] = (x[clist[i]][1] - boxylo) * invyprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zs(int n)
{
double **x = atom->x;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (int i = 0; i < nchoose; i++) {
buf[n] = (x[clist[i]][2] - boxzlo) * invzprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xs_triclinic(int n)
{
int j;
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = h_inv[0]*(x[j][0]-boxlo[0]) + h_inv[5]*(x[j][1]-boxlo[1]) +
h_inv[4]*(x[j][2]-boxlo[2]);
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ys_triclinic(int n)
{
int j;
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = h_inv[1]*(x[j][1]-boxlo[1]) + h_inv[3]*(x[j][2]-boxlo[2]);
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zs_triclinic(int n)
{
double **x = atom->x;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
buf[n] = h_inv[2]*(x[clist[i]][2]-boxlo[2]);
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double xprd = domain->xprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = x[j][0] + ((image[j] & IMGMASK) - IMGMAX) * xprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_yu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double yprd = domain->yprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = x[j][1] + ((image[j] >> IMGBITS & IMGMASK) - IMGMAX) * yprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double zprd = domain->zprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = x[j][2] + ((image[j] >> IMG2BITS) - IMGMAX) * zprd;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int xbox,ybox,zbox;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
xbox = (image[j] & IMGMASK) - IMGMAX;
ybox = (image[j] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[j] >> IMG2BITS) - IMGMAX;
buf[n] = x[j][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_yu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int ybox,zbox;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
ybox = (image[j] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[j] >> IMG2BITS) - IMGMAX;
buf[n] = x[j][1] + h[1]*ybox + h[3]*zbox;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *h = domain->h;
int zbox;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
zbox = (image[j] >> IMG2BITS) - IMGMAX;
buf[n] = x[j][2] + h[2]*zbox;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xsu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = (x[j][0] - boxxlo) * invxprd + (image[j] & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ysu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = (x[j][1] - boxylo) * invyprd + (image[j] >> IMGBITS & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zsu(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = (x[j][2] - boxzlo) * invzprd + (image[j] >> IMG2BITS) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_xsu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = h_inv[0]*(x[j][0]-boxlo[0]) + h_inv[5]*(x[j][1]-boxlo[1]) +
h_inv[4]*(x[j][2]-boxlo[2]) + (image[j] & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ysu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = h_inv[1]*(x[j][1]-boxlo[1]) + h_inv[3]*(x[j][2]-boxlo[2]) +
(image[j] >> IMGBITS & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_zsu_triclinic(int n)
{
int j;
double **x = atom->x;
imageint *image = atom->image;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nchoose; i++) {
j = clist[i];
buf[n] = h_inv[2]*(x[j][2]-boxlo[2]) + (image[j] >> IMG2BITS) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ix(int n)
{
imageint *image = atom->image;
for (int i = 0; i < nchoose; i++) {
buf[n] = (image[clist[i]] & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_iy(int n)
{
imageint *image = atom->image;
for (int i = 0; i < nchoose; i++) {
buf[n] = (image[clist[i]] >> IMGBITS & IMGMASK) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_iz(int n)
{
imageint *image = atom->image;
for (int i = 0; i < nchoose; i++) {
buf[n] = (image[clist[i]] >> IMG2BITS) - IMGMAX;
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_vx(int n)
{
double **v = atom->v;
for (int i = 0; i < nchoose; i++) {
buf[n] = v[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_vy(int n)
{
double **v = atom->v;
for (int i = 0; i < nchoose; i++) {
buf[n] = v[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_vz(int n)
{
double **v = atom->v;
for (int i = 0; i < nchoose; i++) {
buf[n] = v[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_fx(int n)
{
double **f = atom->f;
for (int i = 0; i < nchoose; i++) {
buf[n] = f[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_fy(int n)
{
double **f = atom->f;
for (int i = 0; i < nchoose; i++) {
buf[n] = f[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_fz(int n)
{
double **f = atom->f;
for (int i = 0; i < nchoose; i++) {
buf[n] = f[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_q(int n)
{
double *q = atom->q;
for (int i = 0; i < nchoose; i++) {
buf[n] = q[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_mux(int n)
{
double **mu = atom->mu;
for (int i = 0; i < nchoose; i++) {
buf[n] = mu[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_muy(int n)
{
double **mu = atom->mu;
for (int i = 0; i < nchoose; i++) {
buf[n] = mu[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_muz(int n)
{
double **mu = atom->mu;
for (int i = 0; i < nchoose; i++) {
buf[n] = mu[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_mu(int n)
{
double **mu = atom->mu;
for (int i = 0; i < nchoose; i++) {
buf[n] = mu[clist[i]][3];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_radius(int n)
{
double *radius = atom->radius;
for (int i = 0; i < nchoose; i++) {
buf[n] = radius[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_diameter(int n)
{
double *radius = atom->radius;
for (int i = 0; i < nchoose; i++) {
buf[n] = 2.0*radius[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_omegax(int n)
{
double **omega = atom->omega;
for (int i = 0; i < nchoose; i++) {
buf[n] = omega[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_omegay(int n)
{
double **omega = atom->omega;
for (int i = 0; i < nchoose; i++) {
buf[n] = omega[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_omegaz(int n)
{
double **omega = atom->omega;
for (int i = 0; i < nchoose; i++) {
buf[n] = omega[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_angmomx(int n)
{
double **angmom = atom->angmom;
for (int i = 0; i < nchoose; i++) {
buf[n] = angmom[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_angmomy(int n)
{
double **angmom = atom->angmom;
for (int i = 0; i < nchoose; i++) {
buf[n] = angmom[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_angmomz(int n)
{
double **angmom = atom->angmom;
for (int i = 0; i < nchoose; i++) {
buf[n] = angmom[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_tqx(int n)
{
double **torque = atom->torque;
for (int i = 0; i < nchoose; i++) {
buf[n] = torque[clist[i]][0];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_tqy(int n)
{
double **torque = atom->torque;
for (int i = 0; i < nchoose; i++) {
buf[n] = torque[clist[i]][1];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_tqz(int n)
{
double **torque = atom->torque;
for (int i = 0; i < nchoose; i++) {
buf[n] = torque[clist[i]][2];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_spin(int n)
{
int *spin = atom->spin;
for (int i = 0; i < nchoose; i++) {
buf[n] = spin[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_eradius(int n)
{
double *eradius = atom->eradius;
for (int i = 0; i < nchoose; i++) {
buf[n] = eradius[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_ervel(int n)
{
double *ervel = atom->ervel;
for (int i = 0; i < nchoose; i++) {
buf[n] = ervel[clist[i]];
n += size_one;
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::pack_erforce(int n)
{
double *erforce = atom->erforce;
for (int i = 0; i < nchoose; i++) {
buf[n] = erforce[clist[i]];
n += size_one;
}
}
diff --git a/src/dump_custom.h b/src/dump_custom.h
index 4480bbc82..687af7bd0 100644
--- a/src/dump_custom.h
+++ b/src/dump_custom.h
@@ -1,342 +1,342 @@
/* -*- 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 DUMP_CLASS
DumpStyle(custom,DumpCustom)
#else
#ifndef LMP_DUMP_CUSTOM_H
#define LMP_DUMP_CUSTOM_H
#include "dump.h"
namespace LAMMPS_NS {
class DumpCustom : public Dump {
public:
DumpCustom(class LAMMPS *, int, char **);
virtual ~DumpCustom();
protected:
int nevery; // dump frequency for output
int iregion; // -1 if no region, else which region
char *idregion; // region ID
int nthresh; // # of defined threshholds
int *thresh_array; // array to threshhhold on for each nthresh
int *thresh_op; // threshhold operation for each nthresh
double *thresh_value; // threshhold value for each nthresh
int *vtype; // type of each vector (INT, DOUBLE)
char **vformat; // format string for each vector element
char *columns; // column labels
int nchoose; // # of selected atoms
int maxlocal; // size of atom selection and variable arrays
int *choose; // local indices of selected atoms
double *dchoose; // value for each atom to threshhold against
int *clist; // compressed list of indices of selected atoms
int nfield; // # of keywords listed by user
int ioptional; // index of start of optional args
int *field2index; // which compute,fix,variable calcs this field
int *argindex; // index into compute,fix scalar_atom,vector_atom
// 0 for scalar_atom, 1-N for vector_atom values
int ncompute; // # of Compute objects used by dump
char **id_compute; // their IDs
class Compute **compute; // list of ptrs to the Compute objects
int nfix; // # of Fix objects used by dump
char **id_fix; // their IDs
class Fix **fix; // list of ptrs to the Fix objects
int nvariable; // # of Variables used by dump
char **id_variable; // their names
int *variable; // list of indices for the Variables
double **vbuf; // local storage for variable evaluation
int ntypes; // # of atom types
char **typenames; // array of element names for each type
// private methods
virtual void init_style();
virtual void write_header(bigint);
int count();
- void pack(int *);
+ void pack(tagint *);
virtual int convert_string(int, double *);
virtual void write_data(int, double *);
bigint memory_usage();
int parse_fields(int, char **);
int add_compute(char *);
int add_fix(char *);
int add_variable(char *);
virtual int modify_param(int, char **);
typedef void (DumpCustom::*FnPtrHeader)(bigint);
FnPtrHeader header_choice; // ptr to write header functions
void header_binary(bigint);
void header_binary_triclinic(bigint);
void header_item(bigint);
void header_item_triclinic(bigint);
typedef int (DumpCustom::*FnPtrConvert)(int, double *);
FnPtrConvert convert_choice; // ptr to convert data functions
int convert_image(int, double *);
int convert_noimage(int, double *);
typedef void (DumpCustom::*FnPtrWrite)(int, double *);
FnPtrWrite write_choice; // ptr to write data functions
void write_binary(int, double *);
void write_string(int, double *);
void write_lines(int, double *);
// customize by adding a method prototype
typedef void (DumpCustom::*FnPtrPack)(int);
FnPtrPack *pack_choice; // ptrs to pack functions
void pack_compute(int);
void pack_fix(int);
void pack_variable(int);
void pack_id(int);
void pack_molecule(int);
void pack_type(int);
void pack_mass(int);
void pack_x(int);
void pack_y(int);
void pack_z(int);
void pack_xs(int);
void pack_ys(int);
void pack_zs(int);
void pack_xs_triclinic(int);
void pack_ys_triclinic(int);
void pack_zs_triclinic(int);
void pack_xu(int);
void pack_yu(int);
void pack_zu(int);
void pack_xu_triclinic(int);
void pack_yu_triclinic(int);
void pack_zu_triclinic(int);
void pack_xsu(int);
void pack_ysu(int);
void pack_zsu(int);
void pack_xsu_triclinic(int);
void pack_ysu_triclinic(int);
void pack_zsu_triclinic(int);
void pack_ix(int);
void pack_iy(int);
void pack_iz(int);
void pack_vx(int);
void pack_vy(int);
void pack_vz(int);
void pack_fx(int);
void pack_fy(int);
void pack_fz(int);
void pack_q(int);
void pack_mux(int);
void pack_muy(int);
void pack_muz(int);
void pack_mu(int);
void pack_radius(int);
void pack_diameter(int);
void pack_omegax(int);
void pack_omegay(int);
void pack_omegaz(int);
void pack_angmomx(int);
void pack_angmomy(int);
void pack_angmomz(int);
void pack_tqx(int);
void pack_tqy(int);
void pack_tqz(int);
void pack_spin(int);
void pack_eradius(int);
void pack_ervel(int);
void pack_erforce(int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: No dump custom arguments specified
The dump custom command requires that atom quantities be specified to
output to dump file.
E: Invalid attribute in dump custom command
Self-explantory.
E: Dump_modify format string is too short
There are more fields to be dumped in a line of output than
your format string specifies.
E: Could not find dump custom compute ID
The compute ID needed by dump custom to compute a per-atom quantity
does not exist.
E: Could not find dump custom fix ID
Self-explanatory.
E: Dump custom and fix not computed at compatible times
The fix must produce per-atom quantities on timesteps that dump custom
needs them.
E: Could not find dump custom variable name
Self-explanatory.
E: Region ID for dump custom does not exist
Self-explanatory.
E: Threshhold for an atom property that isn't allocated
A dump threshhold has been requested on a quantity that is
not defined by the atom style used in this simulation.
E: Dumping an atom property that isn't allocated
The chosen atom style does not define the per-atom quantity being
dumped.
E: Dumping an atom quantity that isn't allocated
Only per-atom quantities that are defined for the atom style being
used are allowed.
E: Dump custom compute does not compute per-atom info
Self-explanatory.
E: Dump custom compute does not calculate per-atom vector
Self-explanatory.
E: Dump custom compute does not calculate per-atom array
Self-explanatory.
E: Dump custom compute vector is accessed out-of-range
Self-explanatory.
E: Dump custom fix does not compute per-atom info
Self-explanatory.
E: Dump custom fix does not compute per-atom vector
Self-explanatory.
E: Dump custom fix does not compute per-atom array
Self-explanatory.
E: Dump custom fix vector is accessed out-of-range
Self-explanatory.
E: Dump custom variable is not atom-style variable
Only atom-style variables generate per-atom quantities, needed for
dump output.
E: Illegal ... command
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.
E: Dump_modify region ID does not exist
Self-explanatory.
E: Dump modify element names do not match atom types
Number of element names must equal number of atom types.
E: Invalid attribute in dump modify command
Self-explantory.
E: Could not find dump modify compute ID
Self-explanatory.
E: Dump modify compute ID does not compute per-atom info
Self-explanatory.
E: Dump modify compute ID does not compute per-atom vector
Self-explanatory.
E: Dump modify compute ID does not compute per-atom array
Self-explanatory.
E: Dump modify compute ID vector is not large enough
Self-explanatory.
E: Could not find dump modify fix ID
Self-explanatory.
E: Dump modify fix ID does not compute per-atom info
Self-explanatory.
E: Dump modify fix ID does not compute per-atom vector
Self-explanatory.
E: Dump modify fix ID does not compute per-atom array
Self-explanatory.
E: Dump modify fix ID vector is not large enough
Self-explanatory.
E: Could not find dump modify variable name
Self-explanatory.
E: Dump modify variable is not atom-style variable
Self-explanatory.
E: Invalid dump_modify threshhold operator
Operator keyword used for threshold specification in not recognized.
*/
diff --git a/src/dump_dcd.cpp b/src/dump_dcd.cpp
index 877d8a3f1..a4a6e4f70 100644
--- a/src/dump_dcd.cpp
+++ b/src/dump_dcd.cpp
@@ -1,356 +1,356 @@
/* ----------------------------------------------------------------------
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: Naveen Michaud-Agrawal (Johns Hopkins U)
Axel Kohlmeyer (Temple U), support for groups
------------------------------------------------------------------------- */
#include "math.h"
#include "inttypes.h"
#include "stdio.h"
#include "time.h"
#include "string.h"
#include "dump_dcd.h"
#include "domain.h"
#include "atom.h"
#include "update.h"
#include "output.h"
#include "group.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define NFILE_POS 8L
#define NSTEP_POS 20L
// necessary to set SEEK params b/c MPI-2 messes with these settings
#ifndef SEEK_SET
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif
/* ---------------------------------------------------------------------- */
static inline void fwrite_int32(FILE* fd, uint32_t i)
{
fwrite(&i,sizeof(uint32_t),1,fd);
}
/* ---------------------------------------------------------------------- */
DumpDCD::DumpDCD(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg)
{
if (narg != 5) error->all(FLERR,"Illegal dump dcd command");
if (binary || compressed || multifile || multiproc)
error->all(FLERR,"Invalid dump dcd filename");
size_one = 3;
sort_flag = 1;
sortcol = 0;
unwrap_flag = 0;
format_default = NULL;
// allocate global array for atom coords
bigint n = group->count(igroup);
if (n > MAXSMALLINT/sizeof(float))
error->all(FLERR,"Too many atoms for dump dcd");
natoms = static_cast<int> (n);
memory->create(coords,3*natoms,"dump:coords");
xf = &coords[0*natoms];
yf = &coords[1*natoms];
zf = &coords[2*natoms];
openfile();
headerflag = 0;
nevery_save = 0;
ntotal = 0;
}
/* ---------------------------------------------------------------------- */
DumpDCD::~DumpDCD()
{
memory->destroy(coords);
}
/* ---------------------------------------------------------------------- */
void DumpDCD::init_style()
{
if (sort_flag == 0 || sortcol != 0)
error->all(FLERR,"Dump dcd requires sorting by atom ID");
// check that dump frequency has not changed and is not a variable
int idump;
for (idump = 0; idump < output->ndump; idump++)
if (strcmp(id,output->dump[idump]->id) == 0) break;
if (output->every_dump[idump] == 0)
error->all(FLERR,"Cannot use variable every setting for dump dcd");
if (nevery_save == 0) nevery_save = output->every_dump[idump];
else if (nevery_save != output->every_dump[idump])
error->all(FLERR,"Cannot change dump_modify every for dump dcd");
}
/* ---------------------------------------------------------------------- */
void DumpDCD::openfile()
{
if (me == 0) {
fp = fopen(filename,"wb");
if (fp == NULL) error->one(FLERR,"Cannot open dump file");
}
}
/* ---------------------------------------------------------------------- */
void DumpDCD::write_header(bigint n)
{
if (n != natoms) error->all(FLERR,"Dump dcd of non-matching # of atoms");
if (update->ntimestep > MAXSMALLINT)
error->all(FLERR,"Too big a timestep for dump dcd");
// first time, write header for entire file
if (headerflag == 0) {
if (me == 0) write_dcd_header("Written by LAMMPS");
headerflag = 1;
nframes = 0;
}
// dim[] = size and angle cosines of orthogonal or triclinic box
// dim[0] = a = length of unit cell vector along x-axis
// dim[1] = gamma = cosine of angle between a and b
// dim[2] = b = length of unit cell vector in xy-plane
// dim[3] = beta = cosine of angle between a and c
// dim[4] = alpha = cosine of angle between b and c
// dim[5] = c = length of final unit cell vector
// 48 = 6 doubles
double dim[6];
if (domain->triclinic) {
double *h = domain->h;
double alen = h[0];
double blen = sqrt(h[5]*h[5] + h[1]*h[1]);
double clen = sqrt(h[4]*h[4] + h[3]*h[3] + h[2]*h[2]);
dim[0] = alen;
dim[2] = blen;
dim[5] = clen;
dim[4] = (h[5]*h[4] + h[1]*h[3]) / blen/clen; // alpha
dim[3] = (h[0]*h[4]) / alen/clen; // beta
dim[1] = (h[0]*h[5]) / alen/blen; // gamma
} else {
dim[0] = domain->xprd;
dim[2] = domain->yprd;
dim[5] = domain->zprd;
dim[1] = dim[3] = dim[4] = 0.0;
}
if (me == 0) {
uint32_t out_integer = 48;
fwrite_int32(fp,out_integer);
fwrite(dim,out_integer,1,fp);
fwrite_int32(fp,out_integer);
if (flush_flag) fflush(fp);
}
}
/* ---------------------------------------------------------------------- */
-void DumpDCD::pack(int *ids)
+void DumpDCD::pack(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
m = n = 0;
if (unwrap_flag) {
double xprd = domain->xprd;
double yprd = domain->yprd;
double zprd = domain->zprd;
double xy = domain->xy;
double xz = domain->xz;
double yz = domain->yz;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
int ix = (image[i] & IMGMASK) - IMGMAX;
int iy = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int iz = (image[i] >> IMG2BITS) - IMGMAX;
if (domain->triclinic) {
buf[m++] = x[i][0] + ix * xprd + iy * xy + iz * xz;
buf[m++] = x[i][1] + iy * yprd + iz * yz;
buf[m++] = x[i][2] + iz * zprd;
} else {
buf[m++] = x[i][0] + ix * xprd;
buf[m++] = x[i][1] + iy * yprd;
buf[m++] = x[i][2] + iz * zprd;
}
ids[n++] = tag[i];
}
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
ids[n++] = tag[i];
}
}
}
/* ---------------------------------------------------------------------- */
void DumpDCD::write_data(int n, double *mybuf)
{
// copy buf atom coords into 3 global arrays
int m = 0;
for (int i = 0; i < n; i++) {
xf[ntotal] = mybuf[m++];
yf[ntotal] = mybuf[m++];
zf[ntotal] = mybuf[m++];
ntotal++;
}
// if last chunk of atoms in this snapshot, write global arrays to file
if (ntotal == natoms) {
write_frame();
ntotal = 0;
}
}
/* ---------------------------------------------------------------------- */
int DumpDCD::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"unwrap") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
if (strcmp(arg[1],"yes") == 0) unwrap_flag = 1;
else if (strcmp(arg[1],"no") == 0) unwrap_flag = 0;
else error->all(FLERR,"Illegal dump_modify command");
return 2;
}
return 0;
}
/* ----------------------------------------------------------------------
return # of bytes of allocated memory in buf and global coords array
------------------------------------------------------------------------- */
bigint DumpDCD::memory_usage()
{
bigint bytes = Dump::memory_usage();
bytes += memory->usage(coords,natoms*3);
return bytes;
}
/* ---------------------------------------------------------------------- */
void DumpDCD::write_frame()
{
// write coords
uint32_t out_integer = natoms*sizeof(float);
fwrite_int32(fp,out_integer);
fwrite(xf,out_integer,1,fp);
fwrite_int32(fp,out_integer);
fwrite_int32(fp,out_integer);
fwrite(yf,out_integer,1,fp);
fwrite_int32(fp,out_integer);
fwrite_int32(fp,out_integer);
fwrite(zf,out_integer,1,fp);
fwrite_int32(fp,out_integer);
// update NFILE and NSTEP fields in DCD header
nframes++;
out_integer = nframes;
fseek(fp,NFILE_POS,SEEK_SET);
fwrite_int32(fp,out_integer);
out_integer = update->ntimestep;
fseek(fp,NSTEP_POS,SEEK_SET);
fwrite_int32(fp,out_integer);
fseek(fp,0,SEEK_END);
}
/* ---------------------------------------------------------------------- */
void DumpDCD::write_dcd_header(const char *remarks)
{
uint32_t out_integer;
float out_float;
char title_string[200];
time_t cur_time;
struct tm *tmbuf;
int ntimestep = update->ntimestep;
out_integer = 84;
fwrite_int32(fp,out_integer);
strcpy(title_string,"CORD");
fwrite(title_string,4,1,fp);
fwrite_int32(fp,0); // NFILE = # of snapshots in file
fwrite_int32(fp,ntimestep); // START = timestep of first snapshot
fwrite_int32(fp,nevery_save); // SKIP = interval between snapshots
fwrite_int32(fp,ntimestep); // NSTEP = timestep of last snapshot
fwrite_int32(fp,0); // NAMD writes NSTEP or ISTART
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
out_float = update->dt;
fwrite(&out_float,sizeof(float),1,fp);
fwrite_int32(fp,1);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,0);
fwrite_int32(fp,24); // pretend to be Charmm version 24
fwrite_int32(fp,84);
fwrite_int32(fp,164);
fwrite_int32(fp,2);
strncpy(title_string,remarks,80);
title_string[79] = '\0';
fwrite(title_string,80,1,fp);
cur_time=time(NULL);
tmbuf=localtime(&cur_time);
memset(title_string,' ',81);
strftime(title_string,80,"REMARKS Created %d %B,%Y at %H:%M",tmbuf);
fwrite(title_string,80,1,fp);
fwrite_int32(fp,164);
fwrite_int32(fp,4);
fwrite_int32(fp,natoms); // number of atoms in each snapshot
fwrite_int32(fp,4);
if (flush_flag) fflush(fp);
}
diff --git a/src/dump_dcd.h b/src/dump_dcd.h
index f96c2cc6f..c04c760a0 100644
--- a/src/dump_dcd.h
+++ b/src/dump_dcd.h
@@ -1,100 +1,100 @@
/* -*- 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 DUMP_CLASS
DumpStyle(dcd,DumpDCD)
#else
#ifndef LMP_DUMP_DCD_H
#define LMP_DUMP_DCD_H
#include "dump.h"
namespace LAMMPS_NS {
class DumpDCD : public Dump {
public:
DumpDCD(LAMMPS *, int, char**);
virtual ~DumpDCD();
private:
int natoms,ntotal;
int headerflag,nevery_save,nframes;
float *coords,*xf,*yf,*zf;
int unwrap_flag; // 1 if atom coords are unwrapped, 0 if no
void init_style();
void openfile();
void write_header(bigint);
- void pack(int *);
+ void pack(tagint *);
void write_data(int, double *);
int modify_param(int, char **);
bigint memory_usage();
void write_frame();
void write_dcd_header(const char *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Invalid dump dcd filename
Filenames used with the dump dcd style cannot be binary or compressed
or cause multiple files to be written.
E: Too many atoms for dump dcd
The system size must fit in a 32-bit integer to use this dump
style.
E: Dump dcd requires sorting by atom ID
Use the dump_modify sort command to enable this.
E: Cannot use variable every setting for dump dcd
The format of DCD dump files requires snapshots be output
at a constant frequency.
E: Cannot change dump_modify every for dump dcd
The frequency of writing dump dcd snapshots cannot be changed.
E: Cannot open dump file
The output file for the dump command cannot be opened. Check that the
path and name are correct.
E: Dump dcd of non-matching # of atoms
Every snapshot written by dump dcd must contain the same # of atoms.
E: Too big a timestep for dump dcd
The timestep must fit in a 32-bit integer to use this dump style.
*/
diff --git a/src/dump_image.cpp b/src/dump_image.cpp
index 05a7486c5..53f09b02a 100644
--- a/src/dump_image.cpp
+++ b/src/dump_image.cpp
@@ -1,1071 +1,1071 @@
/* ----------------------------------------------------------------------
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 "ctype.h"
#include "stdlib.h"
#include "string.h"
#include "dump_image.h"
#include "image.h"
#include "atom.h"
#include "domain.h"
#include "group.h"
#include "force.h"
#include "comm.h"
#include "input.h"
#include "variable.h"
#include "math_const.h"
#include "error.h"
#include "memory.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define BIG 1.0e20
enum{NUMERIC,ATOM,TYPE,ELEMENT,ATTRIBUTE};
enum{STATIC,DYNAMIC};
enum{NO,YES};
/* ---------------------------------------------------------------------- */
DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) :
DumpCustom(lmp, narg, arg)
{
if (binary || multiproc) error->all(FLERR,"Invalid dump image filename");
// force binary flag on to avoid corrupted output on Windows
binary = 1;
multifile_override = 0;
// set filetype based on filename suffix
int n = strlen(filename);
if (strlen(filename) > 4 && strcmp(&filename[n-4],".jpg") == 0)
filetype = JPG;
else if (strlen(filename) > 4 && strcmp(&filename[n-4],".JPG") == 0)
filetype = JPG;
else if (strlen(filename) > 5 && strcmp(&filename[n-5],".jpeg") == 0)
filetype = JPG;
else if (strlen(filename) > 5 && strcmp(&filename[n-5],".JPEG") == 0)
filetype = JPG;
else if (strlen(filename) > 4 && strcmp(&filename[n-4],".png") == 0)
filetype = PNG;
else if (strlen(filename) > 4 && strcmp(&filename[n-4],".PNG") == 0)
filetype = PNG;
else filetype = PPM;
#ifndef LAMMPS_JPEG
if (filetype == JPG)
error->all(FLERR,"Support for writing images in JPEG format not included");
#endif
#ifndef LAMMPS_PNG
if (filetype == PNG)
error->all(FLERR,"Support for writing images in PNG format not included");
#endif
// atom color,diameter settings
if (nfield != 2) error->all(FLERR,"Illegal dump image command");
acolor = ATTRIBUTE;
if (strcmp(arg[5],"type") == 0) acolor = TYPE;
else if (strcmp(arg[5],"element") == 0) acolor = ELEMENT;
adiam = ATTRIBUTE;
if (strcmp(arg[6],"type") == 0) adiam = TYPE;
else if (strcmp(arg[6],"element") == 0) adiam = ELEMENT;
// create Image class with single colormap for atoms
// change defaults for 2d
image = new Image(lmp,1);
if (domain->dimension == 2) {
image->theta = 0.0;
image->phi = 0.0;
image->up[0] = 0.0; image->up[1] = 1.0; image->up[2] = 0.0;
}
// set defaults for optional args
atomflag = YES;
if (atom->nbondtypes == 0) bondflag = NO;
else {
bondflag = YES;
bcolor = ATOM;
bdiam = NUMERIC;
bdiamvalue = 0.5;
}
thetastr = phistr = NULL;
cflag = STATIC;
cx = cy = cz = 0.5;
cxstr = cystr = czstr = NULL;
upxstr = upystr = upzstr = NULL;
zoomstr = NULL;
perspstr = NULL;
boxflag = YES;
boxdiam = 0.02;
axesflag = NO;
// parse optional args
int iarg = ioptional;
while (iarg < narg) {
if (strcmp(arg[iarg],"adiam") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
adiam = NUMERIC;
adiamvalue = force->numeric(FLERR,arg[iarg+1]);
if (adiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command");
iarg += 2;
} else if (strcmp(arg[iarg],"atom") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
if (strcmp(arg[iarg+1],"yes") == 0) atomflag = YES;
else if (strcmp(arg[iarg+1],"no") == 0) atomflag = NO;
else error->all(FLERR,"Illegal dump image command");
iarg += 2;
} else if (strcmp(arg[iarg],"bond") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
if (atom->nbondtypes == 0)
error->all(FLERR,"Dump image bond not allowed with no bond types");
bondflag = YES;
if (strcmp(arg[iarg+1],"none") == 0) bondflag = NO;
else if (strcmp(arg[iarg+1],"atom") == 0) bcolor = ATOM;
else if (strcmp(arg[iarg+1],"type") == 0) bcolor = TYPE;
else error->all(FLERR,"Illegal dump image command");
if (!islower(arg[iarg+2][0])) {
bdiam = NUMERIC;
bdiamvalue = force->numeric(FLERR,arg[iarg+2]);
if (bdiamvalue <= 0.0) error->all(FLERR,"Illegal dump image command");
} else if (strcmp(arg[iarg+2],"atom") == 0) bdiam = ATOM;
else if (strcmp(arg[iarg+2],"type") == 0) bdiam = TYPE;
else if (strcmp(arg[iarg+2],"none") == 0) bondflag = NO;
else error->all(FLERR,"Illegal dump image command");
iarg += 3;
} else if (strcmp(arg[iarg],"size") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
int width = force->inumeric(FLERR,arg[iarg+1]);
int height = force->inumeric(FLERR,arg[iarg+2]);
if (width <= 0 || height <= 0)
error->all(FLERR,"Illegal dump image command");
image->width = width;
image->height = height;
iarg += 3;
} else if (strcmp(arg[iarg],"view") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
int n = strlen(&arg[iarg+1][2]) + 1;
thetastr = new char[n];
strcpy(thetastr,&arg[iarg+1][2]);
} else {
double theta = force->numeric(FLERR,arg[iarg+1]);
if (theta < 0.0 || theta > 180.0)
error->all(FLERR,"Invalid dump image theta value");
theta *= MY_PI/180.0;
image->theta = theta;
}
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) {
int n = strlen(&arg[iarg+2][2]) + 1;
phistr = new char[n];
strcpy(phistr,&arg[iarg+2][2]);
} else {
double phi = force->numeric(FLERR,arg[iarg+2]);
phi *= MY_PI/180.0;
image->phi = phi;
}
iarg += 3;
} else if (strcmp(arg[iarg],"center") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal dump image command");
if (strcmp(arg[iarg+1],"s") == 0) cflag = STATIC;
else if (strcmp(arg[iarg+1],"d") == 0) cflag = DYNAMIC;
else error->all(FLERR,"Illegal dump image command");
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) {
int n = strlen(&arg[iarg+2][2]) + 1;
cxstr = new char[n];
strcpy(cxstr,&arg[iarg+2][2]);
cflag = DYNAMIC;
} else cx = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) {
int n = strlen(&arg[iarg+3][2]) + 1;
cystr = new char[n];
strcpy(cystr,&arg[iarg+3][2]);
cflag = DYNAMIC;
} else cy = force->numeric(FLERR,arg[iarg+3]);
if (strstr(arg[iarg+4],"v_") == arg[iarg+4]) {
int n = strlen(&arg[iarg+4][2]) + 1;
czstr = new char[n];
strcpy(czstr,&arg[iarg+4][2]);
cflag = DYNAMIC;
} else cz = force->numeric(FLERR,arg[iarg+4]);
iarg += 5;
} else if (strcmp(arg[iarg],"up") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
int n = strlen(&arg[iarg+1][2]) + 1;
upxstr = new char[n];
strcpy(upxstr,&arg[iarg+1][2]);
} else image->up[0] = force->numeric(FLERR,arg[iarg+1]);
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) {
int n = strlen(&arg[iarg+2][2]) + 1;
upystr = new char[n];
strcpy(upystr,&arg[iarg+2][2]);
} else image->up[1] = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) {
int n = strlen(&arg[iarg+3][2]) + 1;
upzstr = new char[n];
strcpy(upzstr,&arg[iarg+3][2]);
} else image->up[2] = force->numeric(FLERR,arg[iarg+3]);
iarg += 4;
} else if (strcmp(arg[iarg],"zoom") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
int n = strlen(&arg[iarg+1][2]) + 1;
zoomstr = new char[n];
strcpy(zoomstr,&arg[iarg+1][2]);
} else {
double zoom = force->numeric(FLERR,arg[iarg+1]);
if (zoom <= 0.0) error->all(FLERR,"Illegal dump image command");
image->zoom = zoom;
}
iarg += 2;
} else if (strcmp(arg[iarg],"persp") == 0) {
error->all(FLERR,"Dump image persp option is not yet supported");
if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
int n = strlen(&arg[iarg+1][2]) + 1;
perspstr = new char[n];
strcpy(perspstr,&arg[iarg+1][2]);
} else {
double persp = force->numeric(FLERR,arg[iarg+1]);
if (persp < 0.0) error->all(FLERR,"Illegal dump image command");
image->persp = persp;
}
iarg += 2;
} else if (strcmp(arg[iarg],"box") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
if (strcmp(arg[iarg+1],"yes") == 0) boxflag = YES;
else if (strcmp(arg[iarg+1],"no") == 0) boxflag = NO;
else error->all(FLERR,"Illegal dump image command");
boxdiam = force->numeric(FLERR,arg[iarg+2]);
if (boxdiam < 0.0) error->all(FLERR,"Illegal dump image command");
iarg += 3;
} else if (strcmp(arg[iarg],"axes") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal dump image command");
if (strcmp(arg[iarg+1],"yes") == 0) axesflag = YES;
else if (strcmp(arg[iarg+1],"no") == 0) axesflag = NO;
else error->all(FLERR,"Illegal dump image command");
axeslen = force->numeric(FLERR,arg[iarg+2]);
axesdiam = force->numeric(FLERR,arg[iarg+3]);
if (axeslen < 0.0 || axesdiam < 0.0)
error->all(FLERR,"Illegal dump image command");
iarg += 4;
} else if (strcmp(arg[iarg],"shiny") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump image command");
double shiny = force->numeric(FLERR,arg[iarg+1]);
if (shiny < 0.0 || shiny > 1.0)
error->all(FLERR,"Illegal dump image command");
image->shiny = shiny;
iarg += 2;
} else if (strcmp(arg[iarg],"ssao") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal dump image command");
if (strcmp(arg[iarg+1],"yes") == 0) image->ssao = YES;
else if (strcmp(arg[iarg+1],"no") == 0) image->ssao = NO;
else error->all(FLERR,"Illegal dump image command");
int seed = force->inumeric(FLERR,arg[iarg+2]);
if (seed <= 0) error->all(FLERR,"Illegal dump image command");
image->seed = seed;
double ssaoint = force->numeric(FLERR,arg[iarg+3]);
if (ssaoint < 0.0 || ssaoint > 1.0)
error->all(FLERR,"Illegal dump image command");
image->ssaoint = ssaoint;
iarg += 4;
} else error->all(FLERR,"Illegal dump image command");
}
// allocate image buffer now that image size is known
image->buffers();
// communication neede for bonds colored by atoms
if (bondflag) {
if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3;
else comm_forward = 1;
}
// additional defaults for dump_modify options
diamtype = new double[ntypes+1];
diamelement = new double[ntypes+1];
colortype = new double*[ntypes+1];
colorelement = new double*[ntypes+1];
for (int i = 1; i <= ntypes; i++) {
diamtype[i] = 1.0;
if (i % 6 == 1) colortype[i] = image->color2rgb("red");
else if (i % 6 == 2) colortype[i] = image->color2rgb("green");
else if (i % 6 == 3) colortype[i] = image->color2rgb("blue");
else if (i % 6 == 4) colortype[i] = image->color2rgb("yellow");
else if (i % 6 == 5) colortype[i] = image->color2rgb("aqua");
else if (i % 6 == 0) colortype[i] = image->color2rgb("cyan");
}
if (bondflag) {
bdiamtype = new double[atom->nbondtypes+1];
bcolortype = new double*[atom->nbondtypes+1];
for (int i = 1; i <= atom->nbondtypes; i++) {
bdiamtype[i] = 0.5;
if (i % 6 == 1) bcolortype[i] = image->color2rgb("red");
else if (i % 6 == 2) bcolortype[i] = image->color2rgb("green");
else if (i % 6 == 3) bcolortype[i] = image->color2rgb("blue");
else if (i % 6 == 4) bcolortype[i] = image->color2rgb("yellow");
else if (i % 6 == 5) bcolortype[i] = image->color2rgb("aqua");
else if (i % 6 == 0) bcolortype[i] = image->color2rgb("cyan");
}
} else {
bdiamtype = NULL;
bcolortype = NULL;
}
// viewflag = DYNAMIC if any view parameter is dynamic
viewflag = STATIC;
if (thetastr || phistr || cflag == DYNAMIC ||
upxstr || upystr || upzstr || zoomstr || perspstr) viewflag = DYNAMIC;
box_bounds();
if (cflag == STATIC) box_center();
if (viewflag == STATIC) view_params();
// local data
maxbufcopy = 0;
chooseghost = NULL;
bufcopy = NULL;
}
/* ---------------------------------------------------------------------- */
DumpImage::~DumpImage()
{
delete image;
delete [] diamtype;
delete [] diamelement;
delete [] colortype;
delete [] colorelement;
delete [] bdiamtype;
delete [] bcolortype;
memory->destroy(chooseghost);
memory->destroy(bufcopy);
}
/* ---------------------------------------------------------------------- */
void DumpImage::init_style()
{
if (multifile == 0 && !multifile_override)
error->all(FLERR,"Dump image requires one snapshot per file");
if (sort_flag) error->all(FLERR,"Dump image cannot perform sorting");
DumpCustom::init_style();
// check variables
if (thetastr) {
thetavar = input->variable->find(thetastr);
if (thetavar < 0)
error->all(FLERR,"Variable name for dump image theta does not exist");
if (!input->variable->equalstyle(thetavar))
error->all(FLERR,"Variable for dump image theta is invalid style");
}
if (phistr) {
phivar = input->variable->find(phistr);
if (phivar < 0)
error->all(FLERR,"Variable name for dump image phi does not exist");
if (!input->variable->equalstyle(phivar))
error->all(FLERR,"Variable for dump image phi is invalid style");
}
if (cxstr) {
cxvar = input->variable->find(cxstr);
if (cxvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(cxvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (cystr) {
cyvar = input->variable->find(cystr);
if (cyvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(cyvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (czstr) {
czvar = input->variable->find(czstr);
if (czvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(czvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (upxstr) {
upxvar = input->variable->find(upxstr);
if (upxvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(upxvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (upystr) {
upyvar = input->variable->find(upystr);
if (upyvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(upyvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (upzstr) {
upzvar = input->variable->find(upzstr);
if (upzvar < 0)
error->all(FLERR,"Variable name for dump image center does not exist");
if (!input->variable->equalstyle(upzvar))
error->all(FLERR,"Variable for dump image center is invalid style");
}
if (zoomstr) {
zoomvar = input->variable->find(zoomstr);
if (zoomvar < 0)
error->all(FLERR,"Variable name for dump image zoom does not exist");
if (!input->variable->equalstyle(zoomvar))
error->all(FLERR,"Variable for dump image zoom is invalid style");
}
if (perspstr) {
perspvar = input->variable->find(perspstr);
if (perspvar < 0)
error->all(FLERR,"Variable name for dump image persp does not exist");
if (!input->variable->equalstyle(perspvar))
error->all(FLERR,"Variable for dump image persp is invalid style");
}
// set up type -> element mapping
if (atomflag && acolor == ELEMENT) {
for (int i = 1; i <= ntypes; i++) {
colorelement[i] = image->element2color(typenames[i]);
if (colorelement[i] == NULL)
error->all(FLERR,"Invalid dump image element name");
}
}
if (atomflag && adiam == ELEMENT) {
for (int i = 1; i <= ntypes; i++) {
diamelement[i] = image->element2diam(typenames[i]);
if (diamelement[i] == 0.0)
error->all(FLERR,"Invalid dump image element name");
}
}
}
/* ---------------------------------------------------------------------- */
void DumpImage::write()
{
// open new file
openfile();
// reset box center and view parameters if dynamic
box_bounds();
if (cflag == DYNAMIC) box_center();
if (viewflag == DYNAMIC) view_params();
// nme = # of atoms this proc will contribute to dump
nme = count();
if (nme > maxbuf) {
maxbuf = nme;
memory->destroy(buf);
memory->create(buf,maxbuf*size_one,"dump:buf");
}
// pack buf with color & diameter
pack(NULL);
// set minmax color range if using dynamic atom color map
if (acolor == ATTRIBUTE && image->map_dynamic(0)) {
double two[2],twoall[2];
double lo = BIG;
double hi = -BIG;
int m = 0;
for (int i = 0; i < nchoose; i++) {
lo = MIN(lo,buf[m]);
hi = MAX(hi,buf[m]);
m += size_one;
}
two[0] = -lo;
two[1] = hi;
MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world);
int flag = image->map_minmax(0,-twoall[0],twoall[1]);
if (flag) error->all(FLERR,"Invalid color map min/max values");
}
// create image on each proc, then merge them
image->clear();
create_image();
image->merge();
// write image file
if (me == 0) {
if (filetype == JPG) image->write_JPG(fp);
else if (filetype == PNG) image->write_PNG(fp);
else image->write_PPM(fp);
if (multifile) {
fclose(fp);
fp = NULL;
}
}
}
/* ----------------------------------------------------------------------
simulation box bounds
------------------------------------------------------------------------- */
void DumpImage::box_bounds()
{
if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2];
} else {
boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy;
boxxz = domain->xz;
boxyz = domain->yz;
}
}
/* ----------------------------------------------------------------------
reset view parameters
called once from constructor if view is STATIC
called every snapshot from write() if view is DYNAMIC
------------------------------------------------------------------------- */
void DumpImage::box_center()
{
if (cxstr) cx = input->variable->compute_equal(cxvar);
if (cystr) cy = input->variable->compute_equal(cyvar);
if (czstr) cz = input->variable->compute_equal(czvar);
image->xctr = boxxlo + cx*(boxxhi-boxxlo);
image->yctr = boxylo + cy*(boxyhi-boxylo);
image->zctr = boxzlo + cz*(boxzhi-boxzlo);
}
/* ----------------------------------------------------------------------
reset view parameters in Image class
called once from constructor if view is STATIC
called every snapshot from write() if view is DYNAMIC
------------------------------------------------------------------------- */
void DumpImage::view_params()
{
// view direction theta and phi
if (thetastr) {
double theta = input->variable->compute_equal(thetavar);
if (theta < 0.0 || theta > 180.0)
error->all(FLERR,"Invalid dump image theta value");
theta *= MY_PI/180.0;
image->theta = theta;
}
if (phistr) {
double phi = input->variable->compute_equal(phivar);
phi *= MY_PI/180.0;
image->phi = phi;
}
// up vector
if (upxstr) image->up[0] = input->variable->compute_equal(upxvar);
if (upystr) image->up[1] = input->variable->compute_equal(upyvar);
if (upzstr) image->up[2] = input->variable->compute_equal(upzvar);
// zoom and perspective
if (zoomstr) image->zoom = input->variable->compute_equal(zoomvar);
if (image->zoom <= 0.0) error->all(FLERR,"Invalid dump image zoom value");
if (perspstr) image->persp = input->variable->compute_equal(perspvar);
if (image->persp < 0.0) error->all(FLERR,"Invalid dump image persp value");
// remainder of view setup is internal to Image class
image->view_params(boxxlo,boxxhi,boxylo,boxyhi,boxzlo,boxzhi);
}
/* ----------------------------------------------------------------------
create image for atoms on this proc
every pixel has depth
------------------------------------------------------------------------- */
void DumpImage::create_image()
{
int i,j,m,itype,atom1,atom2;
double diameter,delx,dely,delz;
double *color,*color1,*color2;
double xmid[3];
// render my atoms
if (atomflag) {
double **x = atom->x;
m = 0;
for (i = 0; i < nchoose; i++) {
j = clist[i];
if (acolor == TYPE) {
itype = static_cast<int> (buf[m]);
color = colortype[itype];
} else if (acolor == ELEMENT) {
itype = static_cast<int> (buf[m]);
color = colorelement[itype];
} else if (acolor == ATTRIBUTE) {
color = image->map_value2color(0,buf[m]);
}
if (adiam == NUMERIC) {
diameter = adiamvalue;
} else if (adiam == TYPE) {
itype = static_cast<int> (buf[m+1]);
diameter = diamtype[itype];
} else if (adiam == ELEMENT) {
itype = static_cast<int> (buf[m+1]);
diameter = diamelement[itype];
} else if (adiam == ATTRIBUTE) {
diameter = buf[m+1];
}
image->draw_sphere(x[j],color,diameter);
m += size_one;
}
}
// render bonds for my atoms
// both atoms in bond must be selected for bond to be rendered
// if newton_bond is off, only render bond once
// render bond in 2 pieces if crosses periodic boundary
// if bond is deleted (type = 0), do not render
// if bond is turned off (type < 0), still render
if (bondflag) {
double **x = atom->x;
- int *tag = atom->tag;
- int **bond_atom = atom->bond_atom;
+ tagint *tag = atom->tag;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
int *num_bond = atom->num_bond;
int *type = atom->type;
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
int newton_bond = force->newton_bond;
// communicate choose flag for ghost atoms to know if they are selected
// if bcolor/bdiam = ATOM, setup bufcopy to comm atom color/diam attributes
if (nall > maxbufcopy) {
maxbufcopy = atom->nmax;
memory->destroy(chooseghost);
memory->create(chooseghost,maxbufcopy,"dump:chooseghost");
if (comm_forward == 3) {
memory->destroy(bufcopy);
memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy");
}
}
for (i = 0; i < nlocal; i++) chooseghost[i] = choose[i];
if (comm_forward == 3) {
for (i = 0; i < nlocal; i++) bufcopy[i][0] = bufcopy[i][1] = 0.0;
m = 0;
for (i = 0; i < nchoose; i++) {
j = clist[i];
bufcopy[j][0] = buf[m];
bufcopy[j][1] = buf[m+1];
m += size_one;
}
}
comm->forward_comm_dump(this);
for (i = 0; i < nchoose; i++) {
atom1 = clist[i];
for (m = 0; m < num_bond[atom1]; m++) {
atom2 = atom->map(bond_atom[atom1][m]);
if (atom2 < 0 || !chooseghost[atom2]) continue;
if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue;
if (bond_type[atom1][m] == 0) continue;
if (bcolor == ATOM) {
if (acolor == TYPE) {
color1 = colortype[type[atom1]];
color2 = colortype[type[atom2]];
} else if (acolor == ELEMENT) {
color1 = colorelement[type[atom1]];
color2 = colorelement[type[atom2]];
} else if (acolor == ATTRIBUTE) {
color1 = image->map_value2color(0,bufcopy[atom1][0]);
color2 = image->map_value2color(0,bufcopy[atom2][0]);
}
} else if (bcolor == TYPE) {
itype = bond_type[atom1][m];
if (itype < 0) itype = -itype;
color = bcolortype[itype];
}
if (bdiam == NUMERIC) {
diameter = bdiamvalue;
} else if (bdiam == ATOM) {
if (adiam == NUMERIC) {
diameter = adiamvalue;
} else if (adiam == TYPE) {
diameter = MIN(diamtype[type[atom1]],diamtype[type[atom1]]);
} else if (adiam == ELEMENT) {
diameter = MIN(diamelement[type[atom1]],diamelement[type[atom1]]);
} else if (adiam == ATTRIBUTE) {
diameter = MIN(bufcopy[atom1][1],bufcopy[atom2][1]);
}
} else if (bdiam == TYPE) {
itype = bond_type[atom1][m];
if (itype < 0) itype = -itype;
diameter = bdiamtype[itype];
}
// draw cylinder in 2 pieces if bcolor = ATOM
// or bond crosses periodic boundary
delx = x[atom2][0] - x[atom1][0];
dely = x[atom2][1] - x[atom1][1];
delz = x[atom2][2] - x[atom1][2];
if (bcolor == ATOM || domain->minimum_image_check(delx,dely,delz)) {
domain->minimum_image(delx,dely,delz);
xmid[0] = x[atom1][0] + 0.5*delx;
xmid[1] = x[atom1][1] + 0.5*dely;
xmid[2] = x[atom1][2] + 0.5*delz;
if (bcolor == ATOM)
image->draw_cylinder(x[atom1],xmid,color1,diameter,3);
else image->draw_cylinder(x[atom1],xmid,color,diameter,3);
xmid[0] = x[atom2][0] - 0.5*delx;
xmid[1] = x[atom2][1] - 0.5*dely;
xmid[2] = x[atom2][2] - 0.5*delz;
if (bcolor == ATOM)
image->draw_cylinder(xmid,x[atom2],color2,diameter,3);
else image->draw_cylinder(xmid,x[atom2],color,diameter,3);
} else image->draw_cylinder(x[atom1],x[atom2],color,diameter,3);
}
}
}
// render outline of simulation box, orthogonal or triclinic
if (boxflag) {
double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo);
if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo);
diameter *= boxdiam;
double (*boxcorners)[3];
double box[8][3];
if (domain->triclinic == 0) {
box[0][0] = boxxlo; box[0][1] = boxylo; box[0][2] = boxzlo;
box[1][0] = boxxhi; box[1][1] = boxylo; box[1][2] = boxzlo;
box[2][0] = boxxlo; box[2][1] = boxyhi; box[2][2] = boxzlo;
box[3][0] = boxxhi; box[3][1] = boxyhi; box[3][2] = boxzlo;
box[4][0] = boxxlo; box[4][1] = boxylo; box[4][2] = boxzhi;
box[5][0] = boxxhi; box[5][1] = boxylo; box[5][2] = boxzhi;
box[6][0] = boxxlo; box[6][1] = boxyhi; box[6][2] = boxzhi;
box[7][0] = boxxhi; box[7][1] = boxyhi; box[7][2] = boxzhi;
boxcorners = box;
} else {
domain->box_corners();
boxcorners = domain->corners;
}
image->draw_box(boxcorners,diameter);
}
// render XYZ axes in red/green/blue
// offset by 10% of box size and scale by axeslen
if (axesflag) {
double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo);
if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo);
diameter *= axesdiam;
double (*boxcorners)[3];
double axes[4][3];
if (domain->triclinic == 0) {
axes[0][0] = boxxlo; axes[0][1] = boxylo; axes[0][2] = boxzlo;
axes[1][0] = boxxhi; axes[1][1] = boxylo; axes[1][2] = boxzlo;
axes[2][0] = boxxlo; axes[2][1] = boxyhi; axes[2][2] = boxzlo;
axes[3][0] = boxxlo; axes[3][1] = boxylo; axes[3][2] = boxzhi;
} else {
domain->box_corners();
boxcorners = domain->corners;
axes[0][0] = boxcorners[0][0];
axes[0][1] = boxcorners[0][1];
axes[0][2] = boxcorners[0][2];
axes[1][0] = boxcorners[1][0];
axes[1][1] = boxcorners[1][1];
axes[1][2] = boxcorners[1][2];
axes[2][0] = boxcorners[2][0];
axes[2][1] = boxcorners[2][1];
axes[2][2] = boxcorners[2][2];
axes[3][0] = boxcorners[4][0];
axes[3][1] = boxcorners[4][1];
axes[3][2] = boxcorners[4][2];
}
double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo);
if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo);
offset *= 0.1;
axes[0][0] -= offset; axes[0][1] -= offset; axes[0][2] -= offset;
axes[1][0] -= offset; axes[1][1] -= offset; axes[1][2] -= offset;
axes[2][0] -= offset; axes[2][1] -= offset; axes[2][2] -= offset;
axes[3][0] -= offset; axes[3][1] -= offset; axes[3][2] -= offset;
axes[1][0] = axes[0][0] + axeslen*(axes[1][0]-axes[0][0]);
axes[1][1] = axes[0][1] + axeslen*(axes[1][1]-axes[0][1]);
axes[1][2] = axes[0][2] + axeslen*(axes[1][2]-axes[0][2]);
axes[2][0] = axes[0][0] + axeslen*(axes[2][0]-axes[0][0]);
axes[2][1] = axes[0][1] + axeslen*(axes[2][1]-axes[0][1]);
axes[2][2] = axes[0][2] + axeslen*(axes[2][2]-axes[0][2]);
axes[3][0] = axes[0][0] + axeslen*(axes[3][0]-axes[0][0]);
axes[3][1] = axes[0][1] + axeslen*(axes[3][1]-axes[0][1]);
axes[3][2] = axes[0][2] + axeslen*(axes[3][2]-axes[0][2]);
image->draw_axes(axes,diameter);
}
}
/* ---------------------------------------------------------------------- */
int DumpImage::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
if (comm_forward == 1) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = chooseghost[j];
}
} else {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = chooseghost[j];
buf[m++] = bufcopy[j][0];
buf[m++] = bufcopy[j][1];
}
}
return comm_forward;
}
/* ---------------------------------------------------------------------- */
void DumpImage::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (comm_forward == 1)
for (i = first; i < last; i++) chooseghost[i] = static_cast<int> (buf[m++]);
else {
for (i = first; i < last; i++) {
chooseghost[i] = static_cast<int> (buf[m++]);
bufcopy[i][0] = buf[m++];
bufcopy[i][1] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
int DumpImage::modify_param(int narg, char **arg)
{
int n = DumpCustom::modify_param(narg,arg);
if (n) return n;
if (strcmp(arg[0],"acolor") == 0) {
if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
int nlo,nhi;
force->bounds(arg[1],atom->ntypes,nlo,nhi);
// ptrs = list of ncount colornames separated by '/'
int ncount = 1;
char *nextptr;
char *ptr = arg[2];
while (nextptr = strchr(ptr,'/')) {
ptr = nextptr + 1;
ncount++;
}
char **ptrs = new char*[ncount+1];
ncount = 0;
ptrs[ncount++] = strtok(arg[2],"/");
while (ptrs[ncount++] = strtok(NULL,"/"));
ncount--;
// assign each of ncount colors in round-robin fashion to types
int m = 0;
for (int i = nlo; i <= nhi; i++) {
colortype[i] = image->color2rgb(ptrs[m%ncount]);
if (colortype[i] == NULL)
error->all(FLERR,"Invalid color in dump_modify command");
m++;
}
delete [] ptrs;
return 3;
}
if (strcmp(arg[0],"adiam") == 0) {
if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
int nlo,nhi;
force->bounds(arg[1],atom->ntypes,nlo,nhi);
double diam = force->numeric(FLERR,arg[2]);
if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command");
for (int i = nlo; i <= nhi; i++) diamtype[i] = diam;
return 3;
}
if (strcmp(arg[0],"amap") == 0) {
if (narg < 6) error->all(FLERR,"Illegal dump_modify command");
if (strlen(arg[3]) != 2) error->all(FLERR,"Illegal dump_modify command");
int factor = 2;
if (arg[3][0] == 's') factor = 1;
int nentry = force->inumeric(FLERR,arg[5]);
if (nentry < 1) error->all(FLERR,"Illegal dump_modify command");
int n = 6 + factor*nentry;
if (narg < n) error->all(FLERR,"Illegal dump_modify command");
int flag = image->map_reset(0,n-1,&arg[1]);
if (flag) error->all(FLERR,"Illegal dump_modify command");
return n;
}
if (strcmp(arg[0],"bcolor") == 0) {
if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
if (atom->nbondtypes == 0)
error->all(FLERR,"Dump modify bcolor not allowed with no bond types");
int nlo,nhi;
force->bounds(arg[1],atom->nbondtypes,nlo,nhi);
// ptrs = list of ncount colornames separated by '/'
int ncount = 1;
char *nextptr;
char *ptr = arg[2];
while (nextptr = strchr(ptr,'/')) {
ptr = nextptr + 1;
ncount++;
}
char **ptrs = new char*[ncount+1];
ncount = 0;
ptrs[ncount++] = strtok(arg[2],"/");
while (ptrs[ncount++] = strtok(NULL,"/"));
ncount--;
// assign each of ncount colors in round-robin fashion to types
int m = 0;
for (int i = nlo; i <= nhi; i++) {
bcolortype[i] = image->color2rgb(ptrs[m%ncount]);
if (bcolortype[i] == NULL)
error->all(FLERR,"Invalid color in dump_modify command");
m++;
}
delete [] ptrs;
return 3;
}
if (strcmp(arg[0],"bdiam") == 0) {
if (narg < 3) error->all(FLERR,"Illegal dump_modify command");
if (atom->nbondtypes == 0)
error->all(FLERR,"Dump modify bdiam not allowed with no bond types");
int nlo,nhi;
force->bounds(arg[1],atom->ntypes,nlo,nhi);
double diam = force->numeric(FLERR,arg[2]);
if (diam <= 0.0) error->all(FLERR,"Illegal dump_modify command");
for (int i = nlo; i <= nhi; i++) bdiamtype[i] = diam;
return 3;
}
if (strcmp(arg[0],"backcolor") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
double *color = image->color2rgb(arg[1]);
if (color == NULL) error->all(FLERR,"Invalid color in dump_modify command");
image->background[0] = static_cast<int> (color[0]*255.0);
image->background[1] = static_cast<int> (color[1]*255.0);
image->background[2] = static_cast<int> (color[2]*255.0);
return 2;
}
if (strcmp(arg[0],"boxcolor") == 0) {
if (narg < 2) error->all(FLERR,"Illegal dump_modify command");
image->boxcolor = image->color2rgb(arg[1]);
if (image->boxcolor == NULL)
error->all(FLERR,"Invalid color in dump_modify command");
return 2;
}
if (strcmp(arg[0],"color") == 0) {
if (narg < 5) error->all(FLERR,"Illegal dump_modify command");
int flag = image->addcolor(arg[1],force->numeric(FLERR,arg[2]),force->numeric(FLERR,arg[3]),force->numeric(FLERR,arg[4]));
if (flag) error->all(FLERR,"Illegal dump_modify command");
return 5;
}
return 0;
}
diff --git a/src/dump_local.cpp b/src/dump_local.cpp
index fd914563d..f4d7fb260 100644
--- a/src/dump_local.cpp
+++ b/src/dump_local.cpp
@@ -1,543 +1,543 @@
/* ----------------------------------------------------------------------
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 "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)
{
if (narg == 5) error->all(FLERR,"No dump local arguments specified");
clearstep = 1;
nevery = force->inumeric(FLERR,arg[3]);
size_one = nfield = narg-5;
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(narg,arg);
// 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) format_default = strcat(format_default,"%d ");
else format_default = strcat(format_default,"%g ");
vformat[i] = NULL;
}
// setup column string
int n = 0;
for (int iarg = 5; iarg < narg; iarg++) n += strlen(arg[iarg]) + 2;
columns = new char[n];
columns[0] = '\0';
for (int iarg = 5; iarg < narg; iarg++) {
strcat(columns,arg[iarg]);
strcat(columns," ");
}
// setup default label string
char *str = (char *) "ENTRIES";
n = strlen(str) + 1;
label = new char[n];
strcpy(label,str);
}
/* ---------------------------------------------------------------------- */
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;
delete [] columns;
delete [] label;
}
/* ---------------------------------------------------------------------- */
void DumpLocal::init_style()
{
if (sort_flag && sortcol == 0)
error->all(FLERR,"Dump local cannot sort by atom ID");
delete [] format;
char *str;
if (format_user) str = format_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
char *ptr;
for (int i = 0; i < size_one; i++) {
if (i == 0) ptr = strtok(format," \0");
else ptr = strtok(NULL," \0");
delete [] vformat[i];
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
if (ncompute) {
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(int *dummy)
+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 = 5; iarg < narg; iarg++) {
i = iarg-5;
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/dump_local.h b/src/dump_local.h
index 7cf154d4a..862ddf21a 100644
--- a/src/dump_local.h
+++ b/src/dump_local.h
@@ -1,161 +1,161 @@
/* -*- 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 DUMP_CLASS
DumpStyle(local,DumpLocal)
#else
#ifndef LMP_DUMP_LOCAL_H
#define LMP_DUMP_LOCAL_H
#include "dump.h"
namespace LAMMPS_NS {
class DumpLocal : public Dump {
public:
DumpLocal(LAMMPS *, int, char **);
virtual ~DumpLocal();
private:
int nevery; // dump frequency to check Fix against
char *label; // string for dump file header
int nmine; // # of lines I am dumping
int *vtype; // type of each vector (INT, DOUBLE)
char **vformat; // format string for each vector element
char *columns; // column labels
int nfield; // # of keywords listed by user
int *field2index; // which compute,fix,variable calcs this field
int *argindex; // index into compute,fix scalar_atom,vector_atom
// 0 for scalar_atom, 1-N for vector_atom values
int ncompute; // # of Compute objects used by dump
char **id_compute; // their IDs
class Compute **compute; // list of ptrs to the Compute objects
int nfix; // # of Fix objects used by dump
char **id_fix; // their IDs
class Fix **fix; // list of ptrs to the Fix objects
void init_style();
int modify_param(int, char **);
void write_header(bigint);
int count();
- void pack(int *);
+ void pack(tagint *);
int convert_string(int, double *);
void write_data(int, double *);
void parse_fields(int, char **);
int add_compute(char *);
int add_fix(char *);
typedef void (DumpLocal::*FnPtrWrite)(int, double *);
FnPtrWrite write_choice; // ptr to write data functions
void write_string(int, double *);
void write_lines(int, double *);
// customize by adding a method prototype
typedef void (DumpLocal::*FnPtrPack)(int);
FnPtrPack *pack_choice; // ptrs to pack functions
void pack_index(int);
void pack_compute(int);
void pack_fix(int);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: No dump local arguments specified
Self-explanatory.
E: Dump local cannot sort by atom ID
This is because dump local does not really dump per-atom info.
E: Could not find dump local compute ID
Self-explanatory.
E: Could not find dump local fix ID
Self-explanatory.
E: Dump local and fix not computed at compatible times
The fix must produce per-atom quantities on timesteps that dump local
needs them.
E: Illegal ... command
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.
E: Dump local count is not consistent across input fields
Every column of output must be the same length.
E: Invalid attribute in dump local command
Self-explantory.
E: Dump local compute does not compute local info
Self-explanatory.
E: Dump local compute does not calculate local vector
Self-explanatory.
E: Dump local compute does not calculate local array
Self-explanatory.
E: Dump local compute vector is accessed out-of-range
Self-explanatory.
E: Dump local fix does not compute local info
Self-explanatory.
E: Dump local fix does not compute local vector
Self-explanatory.
E: Dump local fix does not compute local array
Self-explanatory.
E: Dump local fix vector is accessed out-of-range
Self-explanatory.
E: Dump local attributes contain no compute or fix
Self-explanatory.
*/
diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp
index f3ef0178c..273ec06e4 100644
--- a/src/dump_xyz.cpp
+++ b/src/dump_xyz.cpp
@@ -1,216 +1,216 @@
/* ----------------------------------------------------------------------
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 "dump_xyz.h"
#include "atom.h"
#include "group.h"
#include "error.h"
#include "memory.h"
#include "update.h"
using namespace LAMMPS_NS;
#define ONELINE 128
#define DELTA 1048576
/* ---------------------------------------------------------------------- */
DumpXYZ::DumpXYZ(LAMMPS *lmp, int narg, char **arg) : Dump(lmp, narg, arg)
{
if (narg != 5) error->all(FLERR,"Illegal dump xyz command");
if (binary || multiproc) error->all(FLERR,"Invalid dump xyz filename");
size_one = 5;
buffer_allow = 1;
buffer_flag = 1;
sort_flag = 1;
sortcol = 0;
if (format_default) delete [] format_default;
char *str = (char *) "%s %g %g %g";
int n = strlen(str) + 1;
format_default = new char[n];
strcpy(format_default,str);
ntypes = atom->ntypes;
typenames = NULL;
}
/* ---------------------------------------------------------------------- */
DumpXYZ::~DumpXYZ()
{
delete[] format_default;
format_default = NULL;
if (typenames) {
for (int i = 1; i <= ntypes; i++)
delete [] typenames[i];
delete [] typenames;
typenames = NULL;
}
}
/* ---------------------------------------------------------------------- */
void DumpXYZ::init_style()
{
delete [] format;
char *str;
if (format_user) str = format_user;
else str = format_default;
int n = strlen(str) + 2;
format = new char[n];
strcpy(format,str);
strcat(format,"\n");
// initialize typenames array to be backward compatible by default
// a 32-bit int can be maximally 10 digits plus sign
if (typenames == NULL) {
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
typenames[itype] = new char[12];
sprintf(typenames[itype],"%d",itype);
}
}
// setup function ptr
if (buffer_flag == 1) write_choice = &DumpXYZ::write_string;
else write_choice = &DumpXYZ::write_lines;
// open single file, one time only
if (multifile == 0) openfile();
}
/* ---------------------------------------------------------------------- */
int DumpXYZ::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"element") == 0) {
if (narg < ntypes+1)
error->all(FLERR, "Dump modify element names do not match atom types");
if (typenames) {
for (int i = 1; i <= ntypes; i++)
delete [] typenames[i];
delete [] typenames;
typenames = NULL;
}
typenames = new char*[ntypes+1];
for (int itype = 1; itype <= ntypes; itype++) {
int n = strlen(arg[itype]) + 1;
typenames[itype] = new char[n];
strcpy(typenames[itype],arg[itype]);
}
return ntypes+1;
}
return 0;
}
/* ---------------------------------------------------------------------- */
void DumpXYZ::write_header(bigint n)
{
if (me == 0) {
fprintf(fp,BIGINT_FORMAT "\n",n);
fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep);
}
}
/* ---------------------------------------------------------------------- */
-void DumpXYZ::pack(int *ids)
+void DumpXYZ::pack(tagint *ids)
{
int m,n;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
double **x = atom->x;
int nlocal = atom->nlocal;
m = n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
buf[m++] = tag[i];
buf[m++] = type[i];
buf[m++] = x[i][0];
buf[m++] = x[i][1];
buf[m++] = x[i][2];
if (ids) ids[n++] = tag[i];
}
}
/* ----------------------------------------------------------------------
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 DumpXYZ::convert_string(int n, double *mybuf)
{
int offset = 0;
int m = 0;
for (int i = 0; i < n; i++) {
if (offset + ONELINE > maxsbuf) {
if ((bigint) maxsbuf + DELTA > MAXSMALLINT) return -1;
maxsbuf += DELTA;
memory->grow(sbuf,maxsbuf,"dump:sbuf");
}
offset += sprintf(&sbuf[offset],format,
typenames[static_cast<int> (mybuf[m+1])],
mybuf[m+2],mybuf[m+3],mybuf[m+4]);
m += size_one;
}
return offset;
}
/* ---------------------------------------------------------------------- */
void DumpXYZ::write_data(int n, double *mybuf)
{
(this->*write_choice)(n,mybuf);
}
/* ---------------------------------------------------------------------- */
void DumpXYZ::write_string(int n, double *mybuf)
{
fwrite(mybuf,sizeof(char),n,fp);
}
/* ---------------------------------------------------------------------- */
void DumpXYZ::write_lines(int n, double *mybuf)
{
int m = 0;
for (int i = 0; i < n; i++) {
fprintf(fp,format,
typenames[static_cast<int> (mybuf[m+1])],
mybuf[m+2],mybuf[m+3],mybuf[m+4]);
m += size_one;
}
}
diff --git a/src/dump_xyz.h b/src/dump_xyz.h
index f57336daa..80719f6a8 100644
--- a/src/dump_xyz.h
+++ b/src/dump_xyz.h
@@ -1,71 +1,71 @@
/* -*- 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 DUMP_CLASS
DumpStyle(xyz,DumpXYZ)
#else
#ifndef LMP_DUMP_XYZ_H
#define LMP_DUMP_XYZ_H
#include "dump.h"
namespace LAMMPS_NS {
class DumpXYZ : public Dump {
public:
DumpXYZ(class LAMMPS *, int, char**);
virtual ~DumpXYZ();
protected:
int ntypes;
char **typenames;
void init_style();
void write_header(bigint);
- void pack(int *);
+ void pack(tagint *);
int convert_string(int, double *);
void write_data(int, double *);
int modify_param(int, char **);
typedef void (DumpXYZ::*FnPtrWrite)(int, double *);
FnPtrWrite write_choice; // ptr to write data functions
void write_string(int, double *);
void write_lines(int, double *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Invalid dump xyz filename
Filenames used with the dump xyz style cannot be binary or cause files
to be written by each processor.
E: Dump modify element names do not match atom types
Number of element names must equal number of atom types.
*/
diff --git a/src/fix.h b/src/fix.h
index 459479d99..6f11272be 100644
--- a/src/fix.h
+++ b/src/fix.h
@@ -1,244 +1,255 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_FIX_H
#define LMP_FIX_H
#include "pointers.h"
namespace LAMMPS_NS {
class Fix : protected Pointers {
public:
char *id,*style;
int igroup,groupbit;
int restart_global; // 1 if Fix saves global state, 0 if not
int restart_peratom; // 1 if Fix saves peratom state, 0 if not
int restart_file; // 1 if Fix writes own restart file, 0 if not
int force_reneighbor; // 1 if Fix forces reneighboring, 0 if not
int box_change_size; // 1 if Fix changes box size, 0 if not
int box_change_shape; // 1 if Fix changes box shape, 0 if not
int box_change_domain; // 1 if Fix changes proc sub-domains, 0 if not
bigint next_reneighbor; // next timestep to force a reneighboring
int thermo_energy; // 1 if fix_modify enabled ThEng, 0 if not
int nevery; // how often to call an end_of_step fix
int rigid_flag; // 1 if Fix integrates rigid bodies, 0 if not
int virial_flag; // 1 if Fix contributes to virial, 0 if not
int no_change_box; // 1 if cannot swap ortho <-> triclinic
int time_integrate; // 1 if fix performs time integration, 0 if no
int time_depend; // 1 if requires continuous timestepping
int create_attribute; // 1 if fix stores attributes that need
// setting when a new atom is created
int restart_pbc; // 1 if fix moves atoms (except integrate)
// so write_restart must remap to PBC
int wd_header; // # of header values fix writes to data file
int wd_section; // # of sections fix writes to data file
int cudable_comm; // 1 if fix has CUDA-enabled communication
int scalar_flag; // 0/1 if compute_scalar() function exists
int vector_flag; // 0/1 if compute_vector() function exists
int array_flag; // 0/1 if compute_array() function exists
int size_vector; // length of global vector
int size_array_rows; // rows in global array
int size_array_cols; // columns in global array
int global_freq; // frequency s/v data is available at
int peratom_flag; // 0/1 if per-atom data is stored
int size_peratom_cols; // 0 = vector, N = columns in peratom array
int peratom_freq; // frequency per-atom data is available at
int local_flag; // 0/1 if local data is stored
int size_local_rows; // rows in local vector or array
int size_local_cols; // 0 = vector, N = columns in local array
int local_freq; // frequency local data is available at
int extscalar; // 0/1 if global scalar is intensive/extensive
int extvector; // 0/1/-1 if global vector is all int/ext/extlist
int *extlist; // list of 0/1 int/ext for each vec component
int extarray; // 0/1 if global array is intensive/extensive
double *vector_atom; // computed per-atom vector
double **array_atom; // computed per-atom array
double *vector_local; // computed local vector
double **array_local; // computed local array
int comm_forward; // size of forward communication (0 if none)
int comm_reverse; // size of reverse communication (0 if none)
int comm_border; // size of border communication (0 if none)
double virial[6]; // accumlated virial
double **vatom; // accumulated per-atom virial
int restart_reset; // 1 if restart just re-initialized fix
unsigned int datamask;
unsigned int datamask_ext;
Fix(class LAMMPS *, int, char **);
virtual ~Fix();
void modify_params(int, char **);
virtual int setmask() = 0;
virtual void init() {}
virtual void init_list(int, class NeighList *) {}
virtual void setup(int) {}
virtual void setup_pre_exchange() {}
virtual void setup_pre_neighbor() {}
virtual void setup_pre_force(int) {}
virtual void min_setup(int) {}
virtual void initial_integrate(int) {}
virtual void post_integrate() {}
virtual void pre_exchange() {}
virtual void pre_neighbor() {}
virtual void pre_force(int) {}
virtual void post_force(int) {}
virtual void final_integrate() {}
virtual void end_of_step() {}
virtual void post_run() {}
virtual void write_restart(FILE *) {}
virtual void write_restart_file(char *) {}
virtual void restart(char *) {}
virtual void grow_arrays(int) {}
virtual void copy_arrays(int, int, int) {}
virtual void set_arrays(int) {}
virtual void update_arrays(int, int) {}
- virtual void set_molecule(int, int, double *, double *, double *) {}
+ virtual void set_molecule(int, tagint, double *, double *, double *) {}
virtual int pack_border(int, int *, double *) {return 0;}
virtual int unpack_border(int, int, double *) {return 0;}
virtual int pack_exchange(int, double *) {return 0;}
virtual int unpack_exchange(int, double *) {return 0;}
virtual int pack_restart(int, double *) {return 0;}
virtual void unpack_restart(int, int) {}
virtual int size_restart(int) {return 0;}
virtual int maxsize_restart() {return 0;}
virtual void setup_pre_force_respa(int, int) {}
virtual void initial_integrate_respa(int, int, int) {}
virtual void post_integrate_respa(int, int) {}
virtual void pre_force_respa(int, int, int) {}
virtual void post_force_respa(int, int, int) {}
virtual void final_integrate_respa(int, int) {}
virtual void min_setup_pre_exchange() {}
virtual void min_setup_pre_neighbor() {}
virtual void min_setup_pre_force(int) {}
virtual void min_pre_exchange() {}
virtual void min_pre_neighbor() {}
virtual void min_pre_force(int) {}
virtual void min_post_force(int) {}
virtual double min_energy(double *) {return 0.0;}
virtual void min_store() {}
virtual void min_clearstore() {}
virtual void min_pushstore() {}
virtual void min_popstore() {}
virtual int min_reset_ref() {return 0;}
virtual void min_step(double, double *) {}
virtual double max_alpha(double *) {return 0.0;}
virtual int min_dof() {return 0;}
virtual int pack_comm(int, int *, double *, int, int *) {return 0;}
virtual void unpack_comm(int, int, double *) {}
virtual int pack_reverse_comm(int, int, double *) {return 0;}
virtual void unpack_reverse_comm(int, int *, double *) {}
virtual double compute_scalar() {return 0.0;}
virtual double compute_vector(int) {return 0.0;}
virtual double compute_array(int,int) {return 0.0;}
virtual int dof(int) {return 0;}
virtual void deform(int) {}
virtual void reset_target(double) {}
virtual void reset_dt() {}
virtual void reset_timestep(bigint) {}
virtual void read_data_header(char *) {}
virtual void read_data_section(char *, int, char *) {}
virtual bigint read_data_skip_lines(char *) {return 0;}
virtual void write_data_header(FILE *, int) {}
virtual void write_data_section_size(int, int &, int &) {}
virtual void write_data_section_pack(int, double **) {}
virtual void write_data_section_keyword(int, FILE *) {}
virtual void write_data_section(int, FILE *, int, double **, int) {}
virtual void zero_momentum() {}
virtual void zero_rotation() {}
virtual int modify_param(int, char **) {return 0;}
virtual void *extract(const char *, int &) {return NULL;}
virtual double memory_usage() {return 0.0;}
virtual unsigned int data_mask() {return datamask;}
virtual unsigned int data_mask_ext() {return datamask_ext;}
protected:
int evflag;
int vflag_global,vflag_atom;
int maxvatom;
void v_setup(int);
void v_tally(int, int *, double, double *);
+
+ // union data struct for packing 32-bit and 64-bit ints into double bufs
+ // see atom_vec.h for documentation
+
+ union ubuf {
+ double d;
+ int64_t i;
+ ubuf(double arg) : d(arg) {}
+ ubuf(int64_t arg) : i(arg) {}
+ ubuf(int arg) : i(arg) {}
+ };
};
namespace FixConst {
static const int INITIAL_INTEGRATE = 1<<0;
static const int POST_INTEGRATE = 1<<1;
static const int PRE_EXCHANGE = 1<<2;
static const int PRE_NEIGHBOR = 1<<3;
static const int PRE_FORCE = 1<<4;
static const int POST_FORCE = 1<<5;
static const int FINAL_INTEGRATE = 1<<6;
static const int END_OF_STEP = 1<<7;
static const int THERMO_ENERGY = 1<<8;
static const int INITIAL_INTEGRATE_RESPA = 1<<9;
static const int POST_INTEGRATE_RESPA = 1<<10;
static const int PRE_FORCE_RESPA = 1<<11;
static const int POST_FORCE_RESPA = 1<<12;
static const int FINAL_INTEGRATE_RESPA = 1<<13;
static const int MIN_PRE_EXCHANGE = 1<<14;
static const int MIN_PRE_NEIGHBOR = 1<<15;
static const int MIN_PRE_FORCE = 1<<16;
static const int MIN_POST_FORCE = 1<<17;
static const int MIN_ENERGY = 1<<18;
static const int POST_RUN = 1<<19;
static const int FIX_CONST_LAST = 1<<20;
}
}
#endif
/* ERROR/WARNING messages:
E: Fix ID must be alphanumeric or underscore characters
Self-explanatory.
E: Could not find fix group ID
A group ID used in the fix command does not exist.
E: Illegal ... command
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.
*/
diff --git a/src/fix_external.h b/src/fix_external.h
index 437519e54..39faadeff 100644
--- a/src/fix_external.h
+++ b/src/fix_external.h
@@ -1,76 +1,76 @@
/* -*- 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 FIX_CLASS
FixStyle(external,FixExternal)
#else
#ifndef LMP_FIX_EXTERNAL_H
#define LMP_FIX_EXTERNAL_H
#include "fix.h"
namespace LAMMPS_NS {
class FixExternal : public Fix {
public:
double **fexternal;
FixExternal(class LAMMPS *, int, char **);
~FixExternal();
int setmask();
void init();
void setup(int);
void min_setup(int);
void post_force(int);
void min_post_force(int);
double compute_scalar();
void set_energy(double eng);
double memory_usage();
void grow_arrays(int);
void copy_arrays(int, int, int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
- typedef void (*FnPtr)(void *, bigint, int, int *, double **, double **);
+ typedef void (*FnPtr)(void *, bigint, int, tagint *, double **, double **);
void set_callback(FnPtr, void *);
private:
int mode,ncall,napply;
FnPtr callback;
void *ptr_caller;
double user_energy;
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Fix external callback function not set
This must be done by an external program in order to use this fix.
*/
diff --git a/src/fix_property_atom.cpp b/src/fix_property_atom.cpp
index 91f8bce59..a1be2b556 100644
--- a/src/fix_property_atom.cpp
+++ b/src/fix_property_atom.cpp
@@ -1,566 +1,575 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "fix_property_atom.h"
#include "atom.h"
#include "memory.h"
#include "error.h"
#include "update.h"
using namespace LAMMPS_NS;
using namespace FixConst;
enum{MOLECULE,CHARGE,INTEGER,DOUBLE};
/* ---------------------------------------------------------------------- */
FixPropertyAtom::FixPropertyAtom(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal fix property/atom command");
restart_peratom = 1;
wd_section = 1;
int iarg = 3;
nvalue = narg-iarg;
style = new int[nvalue];
index = new int[nvalue];
molecule_flag = 0;
q_flag = 0;
nvalue = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"mol") == 0) {
if (atom->molecule_flag)
error->all(FLERR,"Fix property/atom mol when atom_style "
"already has molecule attribute");
if (molecule_flag)
error->all(FLERR,"Fix property/atom cannot specify mol twice");
style[nvalue] = MOLECULE;
atom->molecule_flag = molecule_flag = 1;
nvalue++;
} else if (strcmp(arg[iarg],"q") == 0) {
if (atom->q_flag)
error->all(FLERR,"Fix property/atom q when atom_style "
"already has charge attribute");
if (q_flag)
error->all(FLERR,"Fix property/atom cannot specify q twice");
style[nvalue] = CHARGE;
atom->q_flag = q_flag = 1;
nvalue++;
} else if (strstr(arg[iarg],"i_") == arg[iarg]) {
style[nvalue] = INTEGER;
int tmp;
index[nvalue] = atom->find_custom(&arg[iarg][2],tmp);
if (index[nvalue] >= 0)
error->all(FLERR,"Fix property/atom vector name already exists");
index[nvalue] = atom->add_custom(&arg[iarg][2],0);
nvalue++;
} else if (strstr(arg[iarg],"d_") == arg[iarg]) {
style[nvalue] = DOUBLE;
int tmp;
index[nvalue] = atom->find_custom(&arg[iarg][2],tmp);
if (index[nvalue] >= 0)
error->all(FLERR,"Fix property/atom vector name already exists");
index[nvalue] = atom->add_custom(&arg[iarg][2],1);
nvalue++;
} else break;
iarg++;
}
// optional args
border = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"ghost") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix property/atom command");
if (strcmp(arg[iarg+1],"no") == 0) border = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) border = 1;
else error->all(FLERR,"Illegal fix property/atom command");
iarg += 2;
} else error->all(FLERR,"Illegal fix property/atom command");
}
if (border) comm_border = nvalue;
// store current atom style
int n = strlen(atom->atom_style) + 1;
astyle = new char[n];
strcpy(astyle,atom->atom_style);
// perform initial allocation of atom-based array
// register with Atom class
nmax_old = 0;
grow_arrays(atom->nmax);
atom->add_callback(0);
atom->add_callback(1);
if (border) atom->add_callback(2);
}
/* ---------------------------------------------------------------------- */
FixPropertyAtom::~FixPropertyAtom()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
atom->delete_callback(id,1);
if (border) atom->delete_callback(id,2);
// deallocate per-atom vectors in Atom class
// set ptrs to NULL, so they no longer exist for Atom class
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE) {
atom->molecule_flag = 0;
memory->destroy(atom->molecule);
atom->molecule = NULL;
} else if (style[m] == CHARGE) {
atom->q_flag = 0;
memory->destroy(atom->q);
atom->q = NULL;
} else if (style[m] == INTEGER) {
atom->remove_custom(0,index[m]);
} else if (style[m] == DOUBLE) {
atom->remove_custom(1,index[m]);
}
}
delete [] style;
delete [] index;
delete [] astyle;
}
/* ---------------------------------------------------------------------- */
int FixPropertyAtom::setmask()
{
int mask = 0;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixPropertyAtom::init()
{
// error if atom style has changed since fix was defined
// don't allow this b/c user could change to style that defines molecule,q
if (strcmp(astyle,atom->atom_style) != 0)
error->all(FLERR,"Atom style was redefined after using fix property/atom");
}
/* ----------------------------------------------------------------------
unpack N lines in buf from section of data file labeled by keyword
------------------------------------------------------------------------- */
void FixPropertyAtom::read_data_section(char *keyword, int n, char *buf)
{
- int j,m,tagdata;
+ int j,m;
+ tagint itag;
char *next;
- if (atom->map_style == 0)
- error->all(FLERR,"Fix property/atom cannot read from data file "
- "unless an atom map is defined");
+ int mapflag = 0;
+ if (atom->map_style == 0) {
+ mapflag = 1;
+ atom->map_init();
+ atom->map_set();
+ }
next = strchr(buf,'\n');
*next = '\0';
int nwords = atom->count_words(buf);
*next = '\n';
if (nwords != nvalue+1) {
char str[128];
sprintf(str,"Incorrect %s format in data file",keyword);
error->all(FLERR,str);
}
char **values = new char*[nwords];
// loop over lines of atom info
// tokenize the line into values
// if I own atom tag, unpack its values
- int map_tag_max = atom->map_tag_max;
+ tagint map_tag_max = atom->map_tag_max;
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
values[0] = strtok(buf," \t\n\r\f");
for (j = 1; j < nwords; j++)
values[j] = strtok(NULL," \t\n\r\f");
- tagdata = atoi(values[0]);
- if (tagdata <= 0 || tagdata > map_tag_max) {
+ itag = ATOTAGINT(values[0]);
+ if (itag <= 0 || itag > map_tag_max) {
char str[128];
sprintf(str,"Invalid atom ID in %s section of data file",keyword);
error->one(FLERR,str);
}
// assign words in line to per-atom vectors
- if ((m = atom->map(tagdata)) >= 0) {
+ if ((m = atom->map(itag)) >= 0) {
for (j = 0; j < nvalue; j++) {
if (style[j] == MOLECULE) atom->molecule[m] = atoi(values[j+1]);
else if (style[j] == CHARGE) atom->q[m] = atof(values[j+1]);
else if (style[j] == INTEGER)
atom->ivector[index[j]][m] = atoi(values[j+1]);
else if (style[j] == DOUBLE)
atom->dvector[index[j]][m] = atof(values[j+1]);
}
}
buf = next + 1;
}
delete [] values;
+
+ if (mapflag) {
+ atom->map_delete();
+ atom->map_style = 0;
+ }
}
/* ----------------------------------------------------------------------
return # of lines in section of data file labeled by keyword
------------------------------------------------------------------------- */
bigint FixPropertyAtom::read_data_skip_lines(char *keyword)
{
return atom->natoms;
}
/* ----------------------------------------------------------------------
return size I own for Mth data section
# of data sections = 1 for this fix
nx = # of local atoms
ny = columns = tag + nvalues
------------------------------------------------------------------------- */
void FixPropertyAtom::write_data_section_size(int mth, int &nx, int &ny)
{
nx = atom->nlocal;
ny = nvalue + 1;
}
/* ----------------------------------------------------------------------
pack values for Mth data section into buf
buf allocated by caller as Nlocal by Nvalues+1
------------------------------------------------------------------------- */
void FixPropertyAtom::write_data_section_pack(int mth, double **buf)
{
int i;
// 1st column = atom tag
// rest of columns = per-atom values
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) buf[i][0] = ubuf(tag[i]).d;
for (int m = 0; m < nvalue; m++) {
int mp1 = m+1;
if (style[m] == MOLECULE) {
int *molecule = atom->molecule;
for (i = 0; i < nlocal; i++) buf[i][mp1] = ubuf(molecule[i]).d;
} else if (style[m] == CHARGE) {
double *q = atom->q;
for (i = 0; i < nlocal; i++) buf[i][mp1] = q[i];
} else if (style[m] == INTEGER) {
int *ivec = atom->ivector[index[m]];
for (i = 0; i < nlocal; i++) buf[i][mp1] = ubuf(ivec[i]).d;
} else if (style[m] == DOUBLE) {
double *dvec = atom->dvector[index[m]];
for (i = 0; i < nlocal; i++) buf[i][mp1] = dvec[i];
}
}
}
/* ----------------------------------------------------------------------
write section keyword for Mth data section to file
use Molecules or Charges if that is only field, else use fix ID
only called by proc 0
------------------------------------------------------------------------- */
void FixPropertyAtom::write_data_section_keyword(int mth, FILE *fp)
{
if (nvalue == 1 && style[0] == MOLECULE) fprintf(fp,"\nMolecules\n\n");
else if (nvalue == 1 && style[0] == CHARGE) fprintf(fp,"\nCharges\n\n");
else fprintf(fp,"\n%s\n\n",id);
}
/* ----------------------------------------------------------------------
write N lines from buf to file
convert buf fields to int or double depending on styles
index can be used to prepend global numbering
only called by proc 0
------------------------------------------------------------------------- */
void FixPropertyAtom::write_data_section(int mth, FILE *fp,
int n, double **buf, int index)
{
int m;
for (int i = 0; i < n; i++) {
- fprintf(fp,"%d",(int) ubuf(buf[i][0]).i);
+ fprintf(fp,TAGINT_FORMAT,(tagint) ubuf(buf[i][0]).i);
for (m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE || style[m] == INTEGER)
fprintf(fp," %d",(int) ubuf(buf[i][m+1]).i);
else fprintf(fp," %g",buf[i][m+1]);
}
fprintf(fp,"\n");
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double FixPropertyAtom::memory_usage()
{
double bytes = 0.0;
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE) bytes = atom->nmax * sizeof(int);
else if (style[m] == CHARGE) bytes = atom->nmax * sizeof(double);
else if (style[m] == INTEGER) bytes = atom->nmax * sizeof(int);
else if (style[m] == DOUBLE) bytes = atom->nmax * sizeof(double);
}
return bytes;
}
/* ----------------------------------------------------------------------
allocate atom-based arrays
initialize new values to 0,
since AtomVec class won't do it as atoms are added,
e.g. in create_atom() or data_atom()
------------------------------------------------------------------------- */
void FixPropertyAtom::grow_arrays(int nmax)
{
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE) {
memory->grow(atom->molecule,nmax,"atom:molecule");
size_t nbytes = (nmax-nmax_old) * sizeof(int);
memset(&atom->molecule[nmax_old],0,nbytes);
} else if (style[m] == CHARGE) {
memory->grow(atom->q,nmax,"atom:q");
size_t nbytes = (nmax-nmax_old) * sizeof(double);
memset(&atom->q[nmax_old],0,nbytes);
} else if (style[m] == INTEGER) {
memory->grow(atom->ivector[index[m]],nmax,"atom:ivector");
size_t nbytes = (nmax-nmax_old) * sizeof(int);
memset(&atom->ivector[index[m]][nmax_old],0,nbytes);
} else if (style[m] == DOUBLE) {
memory->grow(atom->dvector[index[m]],nmax,"atom:dvector");
size_t nbytes = (nmax-nmax_old) * sizeof(double);
memset(&atom->dvector[index[m]][nmax_old],0,nbytes);
}
}
nmax_old = nmax;
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixPropertyAtom::copy_arrays(int i, int j, int delflag)
{
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE)
atom->molecule[j] = atom->molecule[i];
else if (style[m] == CHARGE)
atom->q[j] = atom->q[i];
else if (style[m] == INTEGER)
atom->ivector[index[m]][j] = atom->ivector[index[m]][i];
else if (style[m] == DOUBLE)
atom->dvector[index[m]][j] = atom->dvector[index[m]][i];
}
}
/* ----------------------------------------------------------------------
pack values for border communication at re-neighboring
------------------------------------------------------------------------- */
int FixPropertyAtom::pack_border(int n, int *list, double *buf)
{
int i,j,k;
int m = 0;
for (k = 0; k < nvalue; k++) {
if (style[k] == MOLECULE) {
int *molecule = atom->molecule;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = ubuf(molecule[j]).d;
}
} else if (style[k] == CHARGE) {
double *q = atom->q;
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = q[j];
}
} else if (style[k] == INTEGER) {
int *ivector = atom->ivector[index[k]];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = ubuf(ivector[j]).i;
}
} else if (style[k] == DOUBLE) {
double *dvector = atom->dvector[index[k]];
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = dvector[j];
}
}
}
return m;
}
/* ----------------------------------------------------------------------
unpack values for border communication at re-neighboring
------------------------------------------------------------------------- */
int FixPropertyAtom::unpack_border(int n, int first, double *buf)
{
int i,k,last;
int m = 0;
for (k = 0; k < nvalue; k++) {
if (style[k] == MOLECULE) {
int *molecule = atom->molecule;
last = first + n;
for (i = first; i < last; i++)
molecule[i] = (int) ubuf(buf[m++]).i;
} else if (style[k] == CHARGE) {
double *q = atom->q;
last = first + n;
for (i = first; i < last; i++)
q[i] = buf[m++];
} else if (style[k] == INTEGER) {
int *ivector = atom->ivector[index[k]];
last = first + n;
for (i = first; i < last; i++)
ivector[i] = (int) ubuf(buf[m++]).i;
} else if (style[k] == DOUBLE) {
double *dvector = atom->dvector[index[k]];
last = first + n;
for (i = first; i < last; i++)
dvector[i] = buf[m++];
}
}
return m;
}
/* ----------------------------------------------------------------------
pack values in local atom-based array for exchange with another proc
------------------------------------------------------------------------- */
int FixPropertyAtom::pack_exchange(int i, double *buf)
{
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE) buf[m] = ubuf(atom->molecule[i]).d;
else if (style[m] == CHARGE) buf[m] = atom->q[i];
else if (style[m] == INTEGER) buf[m] = ubuf(atom->ivector[index[m]][i]).d;
else if (style[m] == DOUBLE) buf[m] = atom->dvector[index[m]][i];
}
return nvalue;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based array from exchange with another proc
------------------------------------------------------------------------- */
int FixPropertyAtom::unpack_exchange(int nlocal, double *buf)
{
for (int m = 0; m < nvalue; m++) {
if (style[m] == MOLECULE)
atom->molecule[nlocal] = (int) ubuf(buf[m]).i;
else if (style[m] == CHARGE)
atom->q[nlocal] = buf[m];
else if (style[m] == INTEGER)
atom->ivector[index[m]][nlocal] = (int) ubuf(buf[m]).i;
else if (style[m] == DOUBLE)
atom->dvector[index[m]][nlocal] = buf[m];
}
return nvalue;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixPropertyAtom::pack_restart(int i, double *buf)
{
buf[0] = nvalue+1;
int m = 1;
for (int j = 0; j < nvalue; j++) {
if (style[j] == MOLECULE) buf[m++] = ubuf(atom->molecule[i]).d;
else if (style[j] == CHARGE) buf[m++] = atom->q[i];
else if (style[j] == INTEGER) buf[m++] = ubuf(atom->ivector[index[m]][i]).d;
else if (style[j] == DOUBLE) buf[m++] = atom->dvector[index[m]][i];
}
return nvalue+1;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixPropertyAtom::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++;
for (int i = 0; i < nvalue; i++) {
if (style[i] == MOLECULE)
atom->molecule[nlocal] = (int) ubuf(extra[nlocal][m++]).i;
else if (style[i] == CHARGE)
atom->q[nlocal] = extra[nlocal][m++];
else if (style[i] == INTEGER)
atom->ivector[index[m]][nlocal] = (int) ubuf(extra[nlocal][m++]).i;
else if (style[i] == DOUBLE)
atom->dvector[index[m]][nlocal] = extra[nlocal][m++];
}
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixPropertyAtom::maxsize_restart()
{
return nvalue+1;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixPropertyAtom::size_restart(int nlocal)
{
return nvalue+1;
}
diff --git a/src/fix_property_atom.h b/src/fix_property_atom.h
index 12ecb9694..e8b0d67d7 100644
--- a/src/fix_property_atom.h
+++ b/src/fix_property_atom.h
@@ -1,81 +1,69 @@
/* ----------------------------------------------------------------------
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 FIX_CLASS
FixStyle(property/atom,FixPropertyAtom)
#else
#ifndef LMP_FIX_PROPERTY_ATOM_H
#define LMP_FIX_PROPERTY_ATOM_H
#include "fix.h"
namespace LAMMPS_NS {
class FixPropertyAtom : public Fix {
public:
FixPropertyAtom(class LAMMPS *, int, char **);
~FixPropertyAtom();
int setmask();
void init();
void read_data_section(char *, int, char *);
bigint read_data_skip_lines(char *);
void write_data_section_size(int, int &, int &);
void write_data_section_pack(int, double **);
void write_data_section_keyword(int, FILE *);
void write_data_section(int, FILE *, int, double **, int);
void grow_arrays(int);
void copy_arrays(int, int, int);
int pack_border(int, int *, double *);
int unpack_border(int, int, double *);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
int pack_restart(int, double *);
void unpack_restart(int, int);
int size_restart(int);
int maxsize_restart();
double memory_usage();
private:
int nvalue,border;
int molecule_flag,q_flag;
int *style,*index;
char *astyle;
int nmax_old; // length of peratom arrays the last time they grew
-
- // union data struct for packing 32-bit and 64-bit ints into double bufs
- // see atom_vec.h for documentation
-
- union ubuf {
- double d;
- int64_t i;
- ubuf(double arg) : d(arg) {}
- ubuf(int64_t arg) : i(arg) {}
- ubuf(int arg) : i(arg) {}
- };
-
};
}
#endif
#endif
/* ERROR/WARNING messages:
*/
diff --git a/src/fix_restrain.cpp b/src/fix_restrain.cpp
index 33f717c89..70b0d72d0 100644
--- a/src/fix_restrain.cpp
+++ b/src/fix_restrain.cpp
@@ -1,624 +1,626 @@
/* ----------------------------------------------------------------------
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: Craig Tenney (University of Notre Dame)
support for bond and angle restraints by Andres Jaramillo-Botero (Caltech)
------------------------------------------------------------------------- */
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "fix_restrain.h"
#include "atom.h"
#include "force.h"
#include "update.h"
#include "domain.h"
#include "comm.h"
#include "respa.h"
#include "input.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
enum{BOND,ANGLE,DIHEDRAL};
#define TOLERANCE 0.05
#define SMALL 0.001
#define DELTA 1
/* ---------------------------------------------------------------------- */
FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 4) error->all(FLERR,"Illegal fix restrain command");
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
// parse args
nrestrain = maxrestrain = 0;
rstyle = NULL;
ids = NULL;
kstart = kstop = NULL;
target = cos_target = sin_target = NULL;
int iarg = 3;
while (iarg < narg) {
if (nrestrain == maxrestrain) {
maxrestrain += DELTA;
memory->grow(rstyle,maxrestrain,"restrain:rstyle");
memory->grow(ids,maxrestrain,4,"restrain:ids");
memory->grow(kstart,maxrestrain,"restrain:kstart");
memory->grow(kstop,maxrestrain,"restrain:kstop");
memory->grow(target,maxrestrain,"restrain:target");
memory->grow(cos_target,maxrestrain,"restrain:cos_target");
memory->grow(sin_target,maxrestrain,"restrain:sin_target");
}
if (strcmp(arg[iarg],"bond") == 0) {
if (iarg+6 > narg) error->all(FLERR,"Illegal fix restrain command");
rstyle[nrestrain] = BOND;
ids[nrestrain][0] = force->inumeric(FLERR,arg[iarg+1]);
ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]);
kstart[nrestrain] = force->numeric(FLERR,arg[iarg+3]);
kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]);
target[nrestrain] = force->numeric(FLERR,arg[iarg+5]);
iarg += 6;
} else if (strcmp(arg[iarg],"angle") == 0) {
if (iarg+7 > narg) error->all(FLERR,"Illegal fix restrain command");
rstyle[nrestrain] = ANGLE;
ids[nrestrain][0] = force->inumeric(FLERR,arg[iarg+1]);
ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]);
ids[nrestrain][2] = force->inumeric(FLERR,arg[iarg+3]);
kstart[nrestrain] = force->numeric(FLERR,arg[iarg+4]);
kstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]);
target[nrestrain] = force->numeric(FLERR,arg[iarg+6]);
target[nrestrain] *= MY_PI / 180.0;
iarg += 7;
} else if (strcmp(arg[iarg],"dihedral") == 0) {
if (iarg+8 > narg) error->all(FLERR,"Illegal fix restrain command");
rstyle[nrestrain] = DIHEDRAL;
ids[nrestrain][0] = force->inumeric(FLERR,arg[iarg+1]);
ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]);
ids[nrestrain][2] = force->inumeric(FLERR,arg[iarg+3]);
ids[nrestrain][3] = force->inumeric(FLERR,arg[iarg+4]);
kstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]);
kstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]);
target[nrestrain] = force->numeric(FLERR,arg[iarg+7]);
target[nrestrain] *= MY_PI / 180.0;
cos_target[nrestrain] = cos(target[nrestrain]);
sin_target[nrestrain] = sin(target[nrestrain]);
iarg += 8;
} else error->all(FLERR,"Illegal fix restrain command");
nrestrain++;
}
// require atom map to lookup atom IDs
if (atom->map_style == 0)
error->all(FLERR,"Fix restrain requires an atom map, see atom_modify");
}
/* ---------------------------------------------------------------------- */
FixRestrain::~FixRestrain()
{
memory->destroy(rstyle);
memory->destroy(ids);
memory->destroy(kstart);
memory->destroy(kstop);
memory->destroy(target);
memory->destroy(cos_target);
memory->destroy(sin_target);
}
/* ---------------------------------------------------------------------- */
int FixRestrain::setmask()
{
int mask = 0;
mask |= POST_FORCE;
mask |= THERMO_ENERGY;
mask |= POST_FORCE_RESPA;
mask |= MIN_POST_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixRestrain::init()
{
if (strcmp(update->integrate_style,"respa") == 0)
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixRestrain::setup(int vflag)
{
if (strcmp(update->integrate_style,"verlet") == 0)
post_force(vflag);
else {
((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1);
post_force_respa(vflag,nlevels_respa-1,0);
((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1);
}
}
/* ---------------------------------------------------------------------- */
void FixRestrain::min_setup(int vflag)
{
post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixRestrain::post_force(int vflag)
{
energy = 0.0;
for (int m = 0; m < nrestrain; m++)
if (rstyle[m] == BOND) restrain_bond(m);
else if (rstyle[m] == ANGLE) restrain_angle(m);
else if (rstyle[m] == DIHEDRAL) restrain_dihedral(m);
}
/* ---------------------------------------------------------------------- */
void FixRestrain::post_force_respa(int vflag, int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixRestrain::min_post_force(int vflag)
{
post_force(vflag);
}
/* ----------------------------------------------------------------------
apply harmonic bond restraints
---------------------------------------------------------------------- */
void FixRestrain::restrain_bond(int m)
{
int i1,i2;
double delx,dely,delz,fbond;
double rsq,r,dr,rk;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
double k = kstart[m] + delta * (kstop[m] - kstart[m]);
i1 = atom->map(ids[m][0]);
i2 = atom->map(ids[m][1]);
// newton_bond on: only processor owning i2 computes restraint
// newton_bond off: only processors owning either of i1,i2 computes restraint
if (newton_bond) {
if (i2 == -1 || i2 >= nlocal) return;
if (i1 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT,
ids[m][0],ids[m][1],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
} else {
if ((i1 == -1 || i1 >= nlocal) && (i2 == -1 || i2 >= nlocal)) return;
if (i1 == -1 || i2 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT,
ids[m][0],ids[m][1],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
}
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
r = sqrt(rsq);
dr = r - target[m];
rk = k * dr;
// force & energy
if (r > 0.0) fbond = -2.0*rk/r;
else fbond = 0.0;
energy = rk*dr;
// apply force to each of 2 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += delx*fbond;
f[i1][1] += dely*fbond;
f[i1][2] += delz*fbond;
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= delx*fbond;
f[i2][1] -= dely*fbond;
f[i2][2] -= delz*fbond;
}
}
/* ----------------------------------------------------------------------
apply harmonic angle restraints
---------------------------------------------------------------------- */
void FixRestrain::restrain_angle(int m)
{
int i1,i2,i3;
double delx1,dely1,delz1,delx2,dely2,delz2;
double f1[3],f3[3];
double dtheta,tk;
double rsq1,rsq2,r1,r2,c,s,a,a11,a12,a22;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
double k = kstart[m] + delta * (kstop[m] - kstart[m]);
i1 = atom->map(ids[m][0]);
i2 = atom->map(ids[m][1]);
i3 = atom->map(ids[m][2]);
// newton_bond on: only processor owning i2 computes restraint
// newton_bond off: only processors owning any of i1-i3 computes restraint
if (newton_bond) {
if (i2 == -1 || i2 >= nlocal) return;
if (i1 == -1 || i3 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d %d missing on proc %d at step "
BIGINT_FORMAT,
ids[m][0],ids[m][1],ids[m][2],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
} else {
if ((i1 == -1 || i1 >= nlocal) && (i2 == -1 || i2 >= nlocal) &&
(i3 == -1 || i3 >= nlocal)) return;
if (i1 == -1 || i2 == -1 || i3 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d %d missing on proc %d at step "
BIGINT_FORMAT,
ids[m][0],ids[m][1],ids[m][2],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
}
// 1st bond
delx1 = x[i1][0] - x[i2][0];
dely1 = x[i1][1] - x[i2][1];
delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(delx1,dely1,delz1);
rsq1 = delx1*delx1 + dely1*dely1 + delz1*delz1;
r1 = sqrt(rsq1);
// 2nd bond
delx2 = x[i3][0] - x[i2][0];
dely2 = x[i3][1] - x[i2][1];
delz2 = x[i3][2] - x[i2][2];
domain->minimum_image(delx2,dely2,delz2);
rsq2 = delx2*delx2 + dely2*dely2 + delz2*delz2;
r2 = sqrt(rsq2);
// angle (cos and sin)
c = delx1*delx2 + dely1*dely2 + delz1*delz2;
c /= r1*r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
s = sqrt(1.0 - c*c);
if (s < SMALL) s = SMALL;
s = 1.0/s;
// force & energy
dtheta = acos(c) - target[m];
tk = k * dtheta;
energy = tk*dtheta;
a = -2.0 * tk * s;
a11 = a*c / rsq1;
a12 = -a / (r1*r2);
a22 = a*c / rsq2;
f1[0] = a11*delx1 + a12*delx2;
f1[1] = a11*dely1 + a12*dely2;
f1[2] = a11*delz1 + a12*delz2;
f3[0] = a22*delx2 + a12*delx1;
f3[1] = a22*dely2 + a12*dely1;
f3[2] = a22*delz2 + a12*delz1;
// apply force to each of 3 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= f1[0] + f3[0];
f[i2][1] -= f1[1] + f3[1];
f[i2][2] -= f1[2] + f3[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
}
/* ----------------------------------------------------------------------
apply dihedral restraints
adopted from dihedral_charmm
---------------------------------------------------------------------- */
void FixRestrain::restrain_dihedral(int m)
{
int i1,i2,i3,i4,i,mult;
double vb1x,vb1y,vb1z,vb2x,vb2y,vb2z,vb3x,vb3y,vb3z,vb2xm,vb2ym,vb2zm;
double f1[3],f2[3],f3[3],f4[3];
double ax,ay,az,bx,by,bz,rasq,rbsq,rgsq,rg,rginv,ra2inv,rb2inv,rabinv;
double df,df1,ddf1,fg,hg,fga,hgb,gaa,gbb;
double dtfx,dtfy,dtfz,dtgx,dtgy,dtgz,dthx,dthy,dthz;
double c,s,p,sx2,sy2,sz2;
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
double k = kstart[m] + delta * (kstop[m] - kstart[m]);
i1 = atom->map(ids[m][0]);
i2 = atom->map(ids[m][1]);
i3 = atom->map(ids[m][2]);
i4 = atom->map(ids[m][3]);
// newton_bond on: only processor owning i2 computes restraint
// newton_bond off: only processors owning any of i1-i4 computes restraint
if (newton_bond) {
if (i2 == -1 || i2 >= nlocal) return;
if (i1 == -1 || i3 == -1 || i4 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d %d %d missing on proc %d at step "
BIGINT_FORMAT,
ids[m][0],ids[m][1],ids[m][2],ids[m][3],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
} else {
if ((i1 == -1 || i1 >= nlocal) && (i2 == -1 || i2 >= nlocal) &&
(i3 == -1 || i3 >= nlocal) && (i4 == -1 || i3 >= nlocal)) return;
if (i1 == -1 || i2 == -1 || i3 == -1 || i4 == -1) {
char str[128];
sprintf(str,
"Restrain atoms %d %d %d %d missing on proc %d at step "
BIGINT_FORMAT,
ids[m][0],ids[m][1],ids[m][2],ids[m][3],
comm->me,update->ntimestep);
error->one(FLERR,str);
}
}
// 1st bond
vb1x = x[i1][0] - x[i2][0];
vb1y = x[i1][1] - x[i2][1];
vb1z = x[i1][2] - x[i2][2];
domain->minimum_image(vb1x,vb1y,vb1z);
// 2nd bond
vb2x = x[i3][0] - x[i2][0];
vb2y = x[i3][1] - x[i2][1];
vb2z = x[i3][2] - x[i2][2];
domain->minimum_image(vb2x,vb2y,vb2z);
vb2xm = -vb2x;
vb2ym = -vb2y;
vb2zm = -vb2z;
domain->minimum_image(vb2xm,vb2ym,vb2zm);
// 3rd bond
vb3x = x[i4][0] - x[i3][0];
vb3y = x[i4][1] - x[i3][1];
vb3z = x[i4][2] - x[i3][2];
domain->minimum_image(vb3x,vb3y,vb3z);
ax = vb1y*vb2zm - vb1z*vb2ym;
ay = vb1z*vb2xm - vb1x*vb2zm;
az = vb1x*vb2ym - vb1y*vb2xm;
bx = vb3y*vb2zm - vb3z*vb2ym;
by = vb3z*vb2xm - vb3x*vb2zm;
bz = vb3x*vb2ym - vb3y*vb2xm;
rasq = ax*ax + ay*ay + az*az;
rbsq = bx*bx + by*by + bz*bz;
rgsq = vb2xm*vb2xm + vb2ym*vb2ym + vb2zm*vb2zm;
rg = sqrt(rgsq);
rginv = ra2inv = rb2inv = 0.0;
if (rg > 0) rginv = 1.0/rg;
if (rasq > 0) ra2inv = 1.0/rasq;
if (rbsq > 0) rb2inv = 1.0/rbsq;
rabinv = sqrt(ra2inv*rb2inv);
c = (ax*bx + ay*by + az*bz)*rabinv;
s = rg*rabinv*(ax*vb3x + ay*vb3y + az*vb3z);
// error check
if (c > 1.0 + TOLERANCE || c < (-1.0 - TOLERANCE)) {
int me;
MPI_Comm_rank(world,&me);
if (screen) {
char str[128];
- sprintf(str,"Restrain problem: %d " BIGINT_FORMAT " %d %d %d %d",
+ sprintf(str,"Restrain problem: %d " BIGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT,
me,update->ntimestep,
atom->tag[i1],atom->tag[i2],atom->tag[i3],atom->tag[i4]);
error->warning(FLERR,str);
fprintf(screen," 1st atom: %d %g %g %g\n",
me,x[i1][0],x[i1][1],x[i1][2]);
fprintf(screen," 2nd atom: %d %g %g %g\n",
me,x[i2][0],x[i2][1],x[i2][2]);
fprintf(screen," 3rd atom: %d %g %g %g\n",
me,x[i3][0],x[i3][1],x[i3][2]);
fprintf(screen," 4th atom: %d %g %g %g\n",
me,x[i4][0],x[i4][1],x[i4][2]);
}
}
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
mult = 1; // multiplicity
p = 1.0;
df1 = 0.0;
for (i = 0; i < mult; i++) {
ddf1 = p*c - df1*s;
df1 = p*s + df1*c;
p = ddf1;
}
p = p*cos_target[m] + df1*sin_target[m];
df1 = df1*cos_target[m] - ddf1*sin_target[m];
df1 *= -mult;
p += 1.0;
energy = k * p;
fg = vb1x*vb2xm + vb1y*vb2ym + vb1z*vb2zm;
hg = vb3x*vb2xm + vb3y*vb2ym + vb3z*vb2zm;
fga = fg*ra2inv*rginv;
hgb = hg*rb2inv*rginv;
gaa = -ra2inv*rg;
gbb = rb2inv*rg;
dtfx = gaa*ax;
dtfy = gaa*ay;
dtfz = gaa*az;
dtgx = fga*ax - hgb*bx;
dtgy = fga*ay - hgb*by;
dtgz = fga*az - hgb*bz;
dthx = gbb*bx;
dthy = gbb*by;
dthz = gbb*bz;
df = -k * df1;
sx2 = df*dtgx;
sy2 = df*dtgy;
sz2 = df*dtgz;
f1[0] = df*dtfx;
f1[1] = df*dtfy;
f1[2] = df*dtfz;
f2[0] = sx2 - f1[0];
f2[1] = sy2 - f1[1];
f2[2] = sz2 - f1[2];
f4[0] = df*dthx;
f4[1] = df*dthy;
f4[2] = df*dthz;
f3[0] = -sx2 - f4[0];
f3[1] = -sy2 - f4[1];
f3[2] = -sz2 - f4[2];
// apply force to each of 4 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] += f2[0];
f[i2][1] += f2[1];
f[i2][2] += f2[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (newton_bond || i4 < nlocal) {
f[i4][0] += f4[0];
f[i4][1] += f4[1];
f[i4][2] += f4[2];
}
}
/* ----------------------------------------------------------------------
potential energy of added force
------------------------------------------------------------------------- */
double FixRestrain::compute_scalar()
{
MPI_Allreduce(&energy,&energy_all,1,MPI_DOUBLE,MPI_SUM,world);
return energy_all;
}
diff --git a/src/fix_shear_history.cpp b/src/fix_shear_history.cpp
index bebd23386..96461d293 100644
--- a/src/fix_shear_history.cpp
+++ b/src/fix_shear_history.cpp
@@ -1,451 +1,451 @@
/* ----------------------------------------------------------------------
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 "stdio.h"
#include "fix_shear_history.h"
#include "atom.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "force.h"
#include "pair.h"
#include "update.h"
#include "modify.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
/* ---------------------------------------------------------------------- */
FixShearHistory::FixShearHistory(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
restart_peratom = 1;
create_attribute = 1;
// perform initial allocation of atom-based arrays
// register with atom class
npartner = NULL;
partner = NULL;
shearpartner = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
atom->add_callback(1);
ipage = NULL;
dpage = NULL;
pgsize = oneatom = 0;
// initialize npartner to 0 so neighbor list creation is OK the 1st time
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) npartner[i] = 0;
maxtouch = 0;
}
/* ---------------------------------------------------------------------- */
FixShearHistory::~FixShearHistory()
{
// 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->sfree(partner);
memory->sfree(shearpartner);
delete [] ipage;
delete [] dpage;
}
/* ---------------------------------------------------------------------- */
int FixShearHistory::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
mask |= MIN_PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixShearHistory::init()
{
if (atom->tag_enable == 0)
error->all(FLERR,
"Pair style granular with history requires atoms have IDs");
int dim;
computeflag = (int *) pair->extract("computeflag",dim);
allocate_pages();
}
/* ----------------------------------------------------------------------
create pages if first time or if neighbor pgsize/oneatom has changed
note that latter could cause shear history info to be discarded
------------------------------------------------------------------------- */
void FixShearHistory::allocate_pages()
{
int create = 0;
if (ipage == NULL) create = 1;
if (pgsize != neighbor->pgsize) create = 1;
if (oneatom != neighbor->oneatom) create = 1;
if (create) {
delete [] ipage;
delete [] dpage;
pgsize = neighbor->pgsize;
oneatom = neighbor->oneatom;
int nmypage = comm->nthreads;
- ipage = new MyPage<int>[nmypage];
+ ipage = new MyPage<tagint>[nmypage];
dpage = new MyPage<double[3]>[nmypage];
for (int i = 0; i < nmypage; i++) {
ipage[i].init(oneatom,pgsize);
dpage[i].init(oneatom,pgsize);
}
}
}
/* ----------------------------------------------------------------------
called by setup of run or minimize
called by write_restart as input script command
only invoke pre_exchange() if neigh list stores more current history info
than npartner/partner arrays in this fix
that will only be case if pair->compute() has been invoked since
update of npartner/npartner
this logic avoids 2 problems:
run 100; write_restart; run 100
setup_pre_exchange is called twice (by write_restart and 2nd run setup)
w/out a neighbor list being created in between
read_restart; run 100
setup_pre_exchange called by run setup whacks restart shear history info
------------------------------------------------------------------------- */
void FixShearHistory::setup_pre_exchange()
{
if (*computeflag) pre_exchange();
*computeflag = 0;
}
/* ----------------------------------------------------------------------
copy shear partner info from neighbor lists to atom arrays
so can be migrated or stored with atoms
------------------------------------------------------------------------- */
void FixShearHistory::pre_exchange()
{
int i,j,ii,jj,m,n,inum,jnum;
int *ilist,*jlist,*numneigh,**firstneigh;
int *touch,**firsttouch;
double *shear,*allshear,**firstshear;
// nlocal may include atoms added since last neigh build
int nlocal = atom->nlocal;
// zero npartner for all current atoms
// clear 2 page data structures
for (i = 0; i < nlocal; i++) npartner[i] = 0;
ipage->reset();
dpage->reset();
// 1st loop over neighbor list
// calculate npartner for each owned atom
// nlocal_neigh = nlocal when neigh list was built, may be smaller than nlocal
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
NeighList *list = pair->list;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
firsttouch = list->listgranhistory->firstneigh;
firstshear = list->listgranhistory->firstdouble;
int nlocal_neigh = 0;
if (inum) nlocal_neigh = ilist[inum-1] + 1;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
jlist = firstneigh[i];
jnum = numneigh[i];
touch = firsttouch[i];
for (jj = 0; jj < jnum; jj++) {
if (touch[jj]) {
npartner[i]++;
j = jlist[jj];
j &= NEIGHMASK;
if (j < nlocal_neigh) npartner[j]++;
}
}
}
// get page chunks to store atom IDs and shear history for my atoms
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
n = npartner[i];
partner[i] = ipage->get(n);
shearpartner[i] = dpage->get(n);
if (partner[i] == NULL || shearpartner[i] == NULL)
error->one(FLERR,"Shear history overflow, boost neigh_modify one");
}
// 2nd loop over neighbor list
// store atom IDs and shear history for my atoms
// re-zero npartner to use as counter for all my atoms
for (i = 0; i < nlocal; i++) npartner[i] = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
jlist = firstneigh[i];
allshear = firstshear[i];
jnum = numneigh[i];
touch = firsttouch[i];
for (jj = 0; jj < jnum; jj++) {
if (touch[jj]) {
shear = &allshear[3*jj];
j = jlist[jj];
j &= NEIGHMASK;
m = npartner[i];
partner[i][m] = tag[j];
shearpartner[i][m][0] = shear[0];
shearpartner[i][m][1] = shear[1];
shearpartner[i][m][2] = shear[2];
npartner[i]++;
if (j < nlocal_neigh) {
m = npartner[j];
partner[j][m] = tag[i];
shearpartner[j][m][0] = -shear[0];
shearpartner[j][m][1] = -shear[1];
shearpartner[j][m][2] = -shear[2];
npartner[j]++;
}
}
}
}
// set maxtouch = max # of partners of any owned atom
// bump up comm->maxexchange_fix if necessary
maxtouch = 0;
for (i = 0; i < nlocal; i++) maxtouch = MAX(maxtouch,npartner[i]);
comm->maxexchange_fix = MAX(comm->maxexchange_fix,4*maxtouch+1);
}
/* ---------------------------------------------------------------------- */
void FixShearHistory::min_setup_pre_exchange()
{
if (*computeflag) pre_exchange();
*computeflag = 0;
}
/* ---------------------------------------------------------------------- */
void FixShearHistory::min_pre_exchange()
{
pre_exchange();
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixShearHistory::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax * sizeof(int);
bytes += nmax * sizeof(int *);
bytes += nmax * sizeof(double *);
int nmypage = comm->nthreads;
for (int i = 0; i < nmypage; i++) {
bytes += ipage[i].size();
bytes += dpage[i].size();
}
return bytes;
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixShearHistory::grow_arrays(int nmax)
{
memory->grow(npartner,nmax,"shear_history:npartner");
- partner = (int **) memory->srealloc(partner,nmax*sizeof(int *),
- "shear_history:partner");
+ partner = (tagint **) memory->srealloc(partner,nmax*sizeof(tagint *),
+ "shear_history:partner");
typedef double (*sptype)[3];
shearpartner = (sptype *)
memory->srealloc(shearpartner,nmax*sizeof(sptype),
"shear_history:shearpartner");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixShearHistory::copy_arrays(int i, int j, int delflag)
{
// just copy pointers for partner and shearpartner
// b/c can't overwrite chunk allocation inside ipage,dpage
// incoming atoms in unpack_exchange just grab new chunks
// so are orphaning chunks for migrating atoms
// OK, b/c will reset ipage,dpage on next reneighboring
npartner[j] = npartner[i];
partner[j] = partner[i];
shearpartner[j] = shearpartner[i];
}
/* ----------------------------------------------------------------------
initialize one atom's array values, called when atom is created
------------------------------------------------------------------------- */
void FixShearHistory::set_arrays(int i)
{
npartner[i] = 0;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixShearHistory::pack_exchange(int i, double *buf)
{
// NOTE: how do I know comm buf is big enough if extreme # of touching neighs
// Comm::BUFEXTRA may need to be increased
int m = 0;
buf[m++] = npartner[i];
for (int n = 0; n < npartner[i]; n++) {
buf[m++] = partner[i][n];
buf[m++] = shearpartner[i][n][0];
buf[m++] = shearpartner[i][n][1];
buf[m++] = shearpartner[i][n][2];
}
return m;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixShearHistory::unpack_exchange(int nlocal, double *buf)
{
// allocate new chunks from ipage,dpage for incoming values
int m = 0;
npartner[nlocal] = static_cast<int> (buf[m++]);
maxtouch = MAX(maxtouch,npartner[nlocal]);
partner[nlocal] = ipage->get(npartner[nlocal]);
shearpartner[nlocal] = dpage->get(npartner[nlocal]);
for (int n = 0; n < npartner[nlocal]; n++) {
- partner[nlocal][n] = static_cast<int> (buf[m++]);
+ partner[nlocal][n] = static_cast<tagint> (buf[m++]);
shearpartner[nlocal][n][0] = buf[m++];
shearpartner[nlocal][n][1] = buf[m++];
shearpartner[nlocal][n][2] = buf[m++];
}
return m;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixShearHistory::pack_restart(int i, double *buf)
{
int m = 0;
buf[m++] = 4*npartner[i] + 2;
buf[m++] = npartner[i];
for (int n = 0; n < npartner[i]; n++) {
buf[m++] = partner[i][n];
buf[m++] = shearpartner[i][n][0];
buf[m++] = shearpartner[i][n][1];
buf[m++] = shearpartner[i][n][2];
}
return m;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixShearHistory::unpack_restart(int nlocal, int nth)
{
// ipage = NULL if being called from granular pair style init()
if (ipage == NULL) allocate_pages();
// skip to Nth set of extra values
double **extra = atom->extra;
int m = 0;
for (int i = 0; i < nth; i++) m += static_cast<int> (extra[nlocal][m]);
m++;
// allocate new chunks from ipage,dpage for incoming values
npartner[nlocal] = static_cast<int> (extra[nlocal][m++]);
maxtouch = MAX(maxtouch,npartner[nlocal]);
partner[nlocal] = ipage->get(npartner[nlocal]);
shearpartner[nlocal] = dpage->get(npartner[nlocal]);
for (int n = 0; n < npartner[nlocal]; n++) {
- partner[nlocal][n] = static_cast<int> (extra[nlocal][m++]);
+ partner[nlocal][n] = static_cast<tagint> (extra[nlocal][m++]);
shearpartner[nlocal][n][0] = extra[nlocal][m++];
shearpartner[nlocal][n][1] = extra[nlocal][m++];
shearpartner[nlocal][n][2] = extra[nlocal][m++];
}
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixShearHistory::maxsize_restart()
{
// maxtouch_all = max # of touching partners across all procs
int maxtouch_all;
MPI_Allreduce(&maxtouch,&maxtouch_all,1,MPI_INT,MPI_MAX,world);
return 4*maxtouch_all + 2;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixShearHistory::size_restart(int nlocal)
{
return 4*npartner[nlocal] + 2;
}
diff --git a/src/fix_shear_history.h b/src/fix_shear_history.h
index 498ecb906..f4f6f3625 100644
--- a/src/fix_shear_history.h
+++ b/src/fix_shear_history.h
@@ -1,87 +1,87 @@
/* -*- 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 FIX_CLASS
FixStyle(SHEAR_HISTORY,FixShearHistory)
#else
#ifndef LMP_FIX_SHEAR_HISTORY_H
#define LMP_FIX_SHEAR_HISTORY_H
#include "fix.h"
#include "my_page.h"
namespace LAMMPS_NS {
class FixShearHistory : public Fix {
friend class Neighbor;
friend class PairGranHookeHistory;
public:
FixShearHistory(class LAMMPS *, int, char **);
~FixShearHistory();
int setmask();
void init();
void setup_pre_exchange();
virtual void pre_exchange();
void min_setup_pre_exchange();
void min_pre_exchange();
double memory_usage();
void grow_arrays(int);
void copy_arrays(int, int, int);
void set_arrays(int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
int pack_restart(int, double *);
void unpack_restart(int, int);
int size_restart(int);
int maxsize_restart();
protected:
int *npartner; // # of touching partners of each atom
- int **partner; // tags for the partners
+ tagint **partner; // global atom IDs for the partners
double (**shearpartner)[3]; // 3 shear values with the partner
int maxtouch; // max # of touching partners for my atoms
class Pair *pair;
int *computeflag; // computeflag in PairGranHookeHistory
int pgsize,oneatom; // copy of settings in Neighbor
- MyPage<int> *ipage; // pages of partner atom IDs
+ MyPage<tagint> *ipage; // pages of partner atom IDs
MyPage<double[3]> *dpage; // pages of shear history with partners
void allocate_pages();
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Pair style granular with history requires atoms have IDs
Atoms in the simulation do not have IDs, so history effects
cannot be tracked by the granular pair potential.
E: Too many touching neighbors - boost MAXTOUCH
A granular simulation has too many neighbors touching one atom. The
MAXTOUCH parameter in fix_shear_history.cpp must be set larger and
LAMMPS must be re-built.
*/
diff --git a/src/fix_store_state.cpp b/src/fix_store_state.cpp
index bd95daf7a..addcffcab 100644
--- a/src/fix_store_state.cpp
+++ b/src/fix_store_state.cpp
@@ -1,1286 +1,1286 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "fix_store_state.h"
#include "atom.h"
#include "domain.h"
#include "update.h"
#include "group.h"
#include "modify.h"
#include "compute.h"
#include "fix.h"
#include "input.h"
#include "variable.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
using namespace FixConst;
enum{KEYWORD,COMPUTE,FIX,VARIABLE};
#define INVOKED_PERATOM 8
/* ---------------------------------------------------------------------- */
FixStoreState::FixStoreState(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 5) error->all(FLERR,"Illegal fix store/state command");
restart_peratom = 1;
peratom_freq = 1;
nevery = force->inumeric(FLERR,arg[3]);
if (nevery < 0) error->all(FLERR,"Illegal fix store/state command");
// parse values until one isn't recognized
// customize a new keyword by adding to if statement
pack_choice = new FnPtrPack[narg-4];
which = new int[narg-4];
argindex = new int[narg-4];
ids = new char*[narg-4];
value2index = new int[narg-4];
nvalues = 0;
cfv_any = 0;
int iarg = 4;
while (iarg < narg) {
which[nvalues] = KEYWORD;
ids[nvalues] = NULL;
if (strcmp(arg[iarg],"id") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_id;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (!atom->molecule_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_molecule;
} else if (strcmp(arg[iarg],"type") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_type;
} else if (strcmp(arg[iarg],"mass") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_mass;
} else if (strcmp(arg[iarg],"x") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_x;
} else if (strcmp(arg[iarg],"y") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_y;
} else if (strcmp(arg[iarg],"z") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_z;
} else if (strcmp(arg[iarg],"xs") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_xs_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_xs;
} else if (strcmp(arg[iarg],"ys") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_ys_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_ys;
} else if (strcmp(arg[iarg],"zs") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_zs_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_zs;
} else if (strcmp(arg[iarg],"xu") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_xu_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_xu;
} else if (strcmp(arg[iarg],"yu") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_yu_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_yu;
} else if (strcmp(arg[iarg],"zu") == 0) {
if (domain->triclinic)
pack_choice[nvalues++] = &FixStoreState::pack_zu_triclinic;
else pack_choice[nvalues++] = &FixStoreState::pack_zu;
} else if (strcmp(arg[iarg],"ix") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_ix;
} else if (strcmp(arg[iarg],"iy") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_iy;
} else if (strcmp(arg[iarg],"iz") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_iz;
} else if (strcmp(arg[iarg],"vx") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_vx;
} else if (strcmp(arg[iarg],"vy") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_vy;
} else if (strcmp(arg[iarg],"vz") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_vz;
} else if (strcmp(arg[iarg],"fx") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_fx;
} else if (strcmp(arg[iarg],"fy") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_fy;
} else if (strcmp(arg[iarg],"fz") == 0) {
pack_choice[nvalues++] = &FixStoreState::pack_fz;
} else if (strcmp(arg[iarg],"q") == 0) {
if (!atom->q_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_q;
} else if (strcmp(arg[iarg],"mux") == 0) {
if (!atom->mu_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_mux;
} else if (strcmp(arg[iarg],"muy") == 0) {
if (!atom->mu_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_muy;
} else if (strcmp(arg[iarg],"muz") == 0) {
if (!atom->mu_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_muz;
} else if (strcmp(arg[iarg],"radius") == 0) {
if (!atom->radius_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_radius;
} else if (strcmp(arg[iarg],"omegax") == 0) {
if (!atom->omega_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_omegax;
} else if (strcmp(arg[iarg],"omegay") == 0) {
if (!atom->omega_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_omegay;
} else if (strcmp(arg[iarg],"omegaz") == 0) {
if (!atom->omega_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_omegaz;
} else if (strcmp(arg[iarg],"angmomx") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_angmomx;
} else if (strcmp(arg[iarg],"angmomy") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_angmomy;
} else if (strcmp(arg[iarg],"angmomz") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_angmomz;
} else if (strcmp(arg[iarg],"tqx") == 0) {
if (!atom->torque_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_tqx;
} else if (strcmp(arg[iarg],"tqy") == 0) {
if (!atom->torque_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_tqy;
} else if (strcmp(arg[iarg],"tqz") == 0) {
if (!atom->torque_flag)
error->all(FLERR,
"Fix store/state for atom property that isn't allocated");
pack_choice[nvalues++] = &FixStoreState::pack_tqz;
} else if (strncmp(arg[iarg],"c_",2) == 0 ||
strncmp(arg[iarg],"f_",2) == 0 ||
strncmp(arg[iarg],"v_",2) == 0) {
cfv_any = 1;
if (arg[iarg][0] == 'c') which[nvalues] = COMPUTE;
else if (arg[iarg][0] == 'f') which[nvalues] = FIX;
else if (arg[iarg][0] == 'v') which[nvalues] = VARIABLE;
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,"Illegal fix store/state command");
argindex[nvalues] = atoi(ptr+1);
*ptr = '\0';
} else argindex[nvalues] = 0;
n = strlen(suffix) + 1;
ids[nvalues] = new char[n];
strcpy(ids[nvalues],suffix);
nvalues++;
delete [] suffix;
} else break;
iarg++;
}
// optional args
comflag = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"com") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal fix store/state command");
if (strcmp(arg[iarg+1],"no") == 0) comflag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) comflag = 1;
else error->all(FLERR,"Illegal fix store/state command");
iarg += 2;
} else error->all(FLERR,"Illegal fix store/state command");
}
// error check
for (int i = 0; i < nvalues; i++) {
if (which[i] == COMPUTE) {
int icompute = modify->find_compute(ids[i]);
if (icompute < 0)
error->all(FLERR,"Compute ID for fix store/state does not exist");
if (modify->compute[icompute]->peratom_flag == 0)
error->all(FLERR,"Fix store/state compute "
"does not calculate per-atom values");
if (argindex[i] == 0 &&
modify->compute[icompute]->size_peratom_cols != 0)
error->all(FLERR,"Fix store/state compute does not "
"calculate a per-atom vector");
if (argindex[i] && modify->compute[icompute]->size_peratom_cols == 0)
error->all(FLERR,
"Fix store/state compute does not "
"calculate a per-atom array");
if (argindex[i] &&
argindex[i] > modify->compute[icompute]->size_peratom_cols)
error->all(FLERR,
"Fix store/state compute array is accessed out-of-range");
} else if (which[i] == FIX) {
int ifix = modify->find_fix(ids[i]);
if (ifix < 0)
error->all(FLERR,
"Fix ID for fix store/state does not exist");
if (modify->fix[ifix]->peratom_flag == 0)
error->all(FLERR,
"Fix store/state fix does not calculate per-atom values");
if (argindex[i] == 0 && modify->fix[ifix]->size_peratom_cols != 0)
error->all(FLERR,
"Fix store/state fix does not calculate a per-atom vector");
if (argindex[i] && modify->fix[ifix]->size_peratom_cols == 0)
error->all(FLERR,
"Fix store/state fix does not calculate a per-atom array");
if (argindex[i] && argindex[i] > modify->fix[ifix]->size_peratom_cols)
error->all(FLERR,
"Fix store/state fix array is accessed out-of-range");
if (nevery % modify->fix[ifix]->peratom_freq)
error->all(FLERR,
"Fix for fix store/state not computed at compatible time");
} else if (which[i] == VARIABLE) {
int ivariable = input->variable->find(ids[i]);
if (ivariable < 0)
error->all(FLERR,"Variable name for fix store/state does not exist");
if (input->variable->atomstyle(ivariable) == 0)
error->all(FLERR,"Fix store/state variable is not atom-style variable");
}
}
// this fix produces either a per-atom vector or array
peratom_flag = 1;
if (nvalues == 1) size_peratom_cols = 0;
else size_peratom_cols = nvalues;
// perform initial allocation of atom-based array
// register with Atom class
values = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
atom->add_callback(1);
// zero the array since dump may access it on timestep 0
// zero the array since a variable may access it before first run
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (int m = 0; m < nvalues; m++)
values[i][m] = 0.0;
// store current values for keywords but not for compute, fix, variable
kflag = 1;
cfv_flag = 0;
end_of_step();
firstflag = 1;
}
/* ---------------------------------------------------------------------- */
FixStoreState::~FixStoreState()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
atom->delete_callback(id,1);
delete [] which;
delete [] argindex;
for (int m = 0; m < nvalues; m++) delete [] ids[m];
delete [] ids;
delete [] value2index;
delete [] pack_choice;
memory->destroy(values);
}
/* ---------------------------------------------------------------------- */
int FixStoreState::setmask()
{
int mask = 0;
if (nevery) mask |= END_OF_STEP;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixStoreState::init()
{
// set indices and check validity of all computes,fixes,variables
// no error check if end_of_step() will not be called
if (!firstflag && nevery == 0) return;
for (int m = 0; m < nvalues; m++) {
if (which[m] == COMPUTE) {
int icompute = modify->find_compute(ids[m]);
if (icompute < 0)
error->all(FLERR,"Compute ID for fix store/state does not exist");
value2index[m] = icompute;
} else if (which[m] == FIX) {
int ifix = modify->find_fix(ids[m]);
if (ifix < 0)
error->all(FLERR,"Fix ID for fix store/state does not exist");
value2index[m] = ifix;
} else if (which[m] == VARIABLE) {
int ivariable = input->variable->find(ids[m]);
if (ivariable < 0)
error->all(FLERR,"Variable name for fix store/state does not exist");
value2index[m] = ivariable;
}
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::setup(int vflag)
{
// if first invocation, store current values for compute, fix, variable
if (firstflag) {
kflag = 0;
cfv_flag = 1;
end_of_step();
firstflag = 0;
kflag = cfv_flag = 1;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::end_of_step()
{
int i,j,n;
// compute com if comflag set
if (comflag) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,cm);
}
// if any compute/fix/variable and nevery, wrap with clear/add
if (cfv_any && nevery) modify->clearstep_compute();
// fill vector or array with per-atom values
if (values) vbuf = &values[0][0];
else vbuf = NULL;
for (int m = 0; m < nvalues; m++) {
if (which[m] == KEYWORD && kflag) (this->*pack_choice[m])(m);
else if (cfv_flag) {
n = value2index[m];
j = argindex[m];
int *mask = atom->mask;
int nlocal = atom->nlocal;
// invoke compute if not previously invoked
if (which[m] == COMPUTE) {
Compute *compute = modify->compute[n];
if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
if (j == 0) {
double *compute_vector = compute->vector_atom;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) values[i][m] = compute_vector[i];
} else {
int jm1 = j - 1;
double **compute_array = compute->array_atom;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) values[i][m] = compute_array[i][jm1];
}
// access fix fields, guaranteed to be ready
} else if (which[m] == FIX) {
if (j == 0) {
double *fix_vector = modify->fix[n]->vector_atom;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) values[i][m] = fix_vector[i];
} else {
int jm1 = j - 1;
double **fix_array = modify->fix[n]->array_atom;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) values[i][m] = fix_array[i][jm1];
}
// evaluate atom-style variable
} else if (which[m] == VARIABLE)
input->variable->compute_atom(n,igroup,&values[0][m],nvalues,0);
}
}
// if any compute/fix/variable and nevery, wrap with clear/add
if (cfv_any && nevery) {
int nextstep = (update->ntimestep/nevery)*nevery + nevery;
modify->addstep_compute(nextstep);
}
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double FixStoreState::memory_usage()
{
double bytes = atom->nmax*nvalues * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
allocate atom-based array
------------------------------------------------------------------------- */
void FixStoreState::grow_arrays(int nmax)
{
memory->grow(values,nmax,nvalues,"store/state:values");
if (nvalues == 1) {
if (nmax) vector_atom = &values[0][0];
else vector_atom = NULL;
} else array_atom = values;
}
/* ----------------------------------------------------------------------
copy values within local atom-based array
------------------------------------------------------------------------- */
void FixStoreState::copy_arrays(int i, int j, int delflag)
{
for (int m = 0; m < nvalues; m++) values[j][m] = values[i][m];
}
/* ----------------------------------------------------------------------
pack values in local atom-based array for exchange with another proc
------------------------------------------------------------------------- */
int FixStoreState::pack_exchange(int i, double *buf)
{
for (int m = 0; m < nvalues; m++) buf[m] = values[i][m];
return nvalues;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based array from exchange with another proc
------------------------------------------------------------------------- */
int FixStoreState::unpack_exchange(int nlocal, double *buf)
{
for (int m = 0; m < nvalues; m++) values[nlocal][m] = buf[m];
return nvalues;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixStoreState::pack_restart(int i, double *buf)
{
buf[0] = nvalues+1;
for (int m = 0; m < nvalues; m++) buf[m+1] = values[i][m];
return nvalues+1;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixStoreState::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++;
for (int i = 0; i < nvalues; i++) values[nlocal][i] = extra[nlocal][m++];
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixStoreState::maxsize_restart()
{
return nvalues+1;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixStoreState::size_restart(int nlocal)
{
return nvalues+1;
}
/* ----------------------------------------------------------------------
one method for every keyword fix store/state can archive
the atom property is packed into buf starting at n with stride nvalues
customize a new keyword by adding a method
------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_id(int n)
{
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = tag[i];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_molecule(int n)
{
int *molecule = atom->molecule;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = molecule[i];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_type(int n)
{
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = type[i];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_mass(int n)
{
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (rmass) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = rmass[i];
else vbuf[n] = 0.0;
n += nvalues;
}
} else {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = mass[type[i]];
else vbuf[n] = 0.0;
n += nvalues;
}
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_x(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = x[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_y(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = x[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_z(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = x[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_xs(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxxlo = domain->boxlo[0];
double invxprd = 1.0/domain->xprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (x[i][0] - boxxlo) * invxprd;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_ys(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxylo = domain->boxlo[1];
double invyprd = 1.0/domain->yprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (x[i][1] - boxylo) * invyprd;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_zs(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double boxzlo = domain->boxlo[2];
double invzprd = 1.0/domain->zprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (x[i][2] - boxzlo) * invzprd;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_xs_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
vbuf[n] = h_inv[0]*(x[i][0]-boxlo[0]) +
h_inv[5]*(x[i][1]-boxlo[1]) + h_inv[4]*(x[i][2]-boxlo[2]);
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_ys_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
vbuf[n] = h_inv[1]*(x[i][1]-boxlo[1]) + h_inv[3]*(x[i][2]-boxlo[2]);
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_zs_triclinic(int n)
{
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *boxlo = domain->boxlo;
double *h_inv = domain->h_inv;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
vbuf[n] = h_inv[2]*(x[i][2]-boxlo[2]);
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_xu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double xprd = domain->xprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
vbuf[n] = x[i][0] + ((image[i] & IMGMASK) - IMGMAX) * xprd;
if (comflag) vbuf[n] -= cm[0];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_yu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double yprd = domain->yprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
vbuf[n] = x[i][1] + ((image[i] >> IMGBITS & IMGMASK) - IMGMAX) * yprd;
if (comflag) vbuf[n] -= cm[1];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_zu(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double zprd = domain->zprd;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
vbuf[n] = x[i][2] + ((image[i] >> IMG2BITS) - IMGMAX) * zprd;
if (comflag) vbuf[n] -= cm[2];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_xu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int xbox,ybox,zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xbox = (image[i] & IMGMASK) - IMGMAX;
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
vbuf[n] = x[i][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
if (comflag) vbuf[n] -= cm[0];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_yu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int ybox,zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
ybox = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[i] >> IMG2BITS) - IMGMAX;
vbuf[n] = x[i][1] + h[1]*ybox + h[3]*zbox;
if (comflag) vbuf[n] -= cm[1];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_zu_triclinic(int n)
{
double **x = atom->x;
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double *h = domain->h;
int zbox;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
zbox = (image[i] >> IMG2BITS) - IMGMAX;
vbuf[n] = x[i][2] + h[2]*zbox;
if (comflag) vbuf[n] -= cm[2];
} else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_ix(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (image[i] & IMGMASK) - IMGMAX;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_iy(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_iz(int n)
{
imageint *image = atom->image;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = (image[i] >> IMG2BITS) - IMGMAX;
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_vx(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = v[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_vy(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = v[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_vz(int n)
{
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = v[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_fx(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = f[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_fy(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = f[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_fz(int n)
{
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = f[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_q(int n)
{
double *q = atom->q;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = q[i];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_mux(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = mu[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_muy(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = mu[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_muz(int n)
{
double **mu = atom->mu;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = mu[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_radius(int n)
{
double *radius = atom->radius;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = radius[i];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_omegax(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = omega[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_omegay(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = omega[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_omegaz(int n)
{
double **omega = atom->omega;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = omega[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_angmomx(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = angmom[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_angmomy(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = angmom[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_angmomz(int n)
{
double **angmom = atom->angmom;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = angmom[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_tqx(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = torque[i][0];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_tqy(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = torque[i][1];
else vbuf[n] = 0.0;
n += nvalues;
}
}
/* ---------------------------------------------------------------------- */
void FixStoreState::pack_tqz(int n)
{
double **torque = atom->torque;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) vbuf[n] = torque[i][2];
else vbuf[n] = 0.0;
n += nvalues;
}
}
diff --git a/src/fix_tmd.cpp b/src/fix_tmd.cpp
index 1a1059447..8ac0533ff 100644
--- a/src/fix_tmd.cpp
+++ b/src/fix_tmd.cpp
@@ -1,547 +1,549 @@
/* ----------------------------------------------------------------------
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)
Christian Burisch (Bochum Univeristy, Germany)
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "fix_tmd.h"
#include "atom.h"
#include "update.h"
#include "modify.h"
#include "domain.h"
#include "group.h"
#include "respa.h"
#include "force.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace FixConst;
#define CHUNK 1000
#define MAXLINE 256
/* ---------------------------------------------------------------------- */
FixTMD::FixTMD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg)
{
if (narg < 6) error->all(FLERR,"Illegal fix tmd command");
rho_stop = force->numeric(FLERR,arg[3]);
nfileevery = force->inumeric(FLERR,arg[5]);
if (rho_stop < 0 || nfileevery < 0)
error->all(FLERR,"Illegal fix tmd command");
if (nfileevery && narg != 7) error->all(FLERR,"Illegal fix tmd command");
MPI_Comm_rank(world,&me);
// perform initial allocation of atom-based arrays
// register with Atom class
xf = NULL;
xold = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
// make sure an atom map exists before reading in target coordinates
if (atom->map_style == 0)
error->all(FLERR,"Cannot use fix TMD unless atom map exists");
// read from arg[4] and store coordinates of final target in xf
readfile(arg[4]);
// open arg[6] statistics file and write header
if (nfileevery) {
if (narg != 7) error->all(FLERR,"Illegal fix tmd command");
if (me == 0) {
fp = fopen(arg[6],"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open fix tmd file %s",arg[6]);
error->one(FLERR,str);
}
fprintf(fp,"%s %s\n","# Step rho_target rho_old gamma_back",
"gamma_forward lambda work_lambda work_analytical");
}
}
masstotal = group->mass(igroup);
// rho_start = initial rho
// xold = initial x or 0.0 if not in group
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double **x = atom->x;
double *mass = atom->mass;
int nlocal = atom->nlocal;
double dx,dy,dz;
rho_start = 0.0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],xold[i]);
dx = xold[i][0] - xf[i][0];
dy = xold[i][1] - xf[i][1];
dz = xold[i][2] - xf[i][2];
rho_start += mass[type[i]]*(dx*dx + dy*dy + dz*dz);
} else xold[i][0] = xold[i][1] = xold[i][2] = 0.0;
}
double rho_start_total;
MPI_Allreduce(&rho_start,&rho_start_total,1,MPI_DOUBLE,MPI_SUM,world);
rho_start = sqrt(rho_start_total/masstotal);
rho_old = rho_start;
work_lambda = 0.0;
work_analytical = 0.0;
previous_stat = 0;
}
/* ---------------------------------------------------------------------- */
FixTMD::~FixTMD()
{
if (nfileevery && me == 0) fclose(fp);
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
// delete locally stored arrays
memory->destroy(xf);
memory->destroy(xold);
}
/* ---------------------------------------------------------------------- */
int FixTMD::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= INITIAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixTMD::init()
{
// check that no integrator fix comes after a TMD fix
int flag = 0;
for (int i = 0; i < modify->nfix; i++) {
if (strcmp(modify->fix[i]->style,"tmd") == 0) flag = 1;
if (flag && strcmp(modify->fix[i]->style,"nve") == 0) flag = 2;
if (flag && strcmp(modify->fix[i]->style,"nvt") == 0) flag = 2;
if (flag && strcmp(modify->fix[i]->style,"npt") == 0) flag = 2;
if (flag && strcmp(modify->fix[i]->style,"nph") == 0) flag = 2;
}
if (flag == 2) error->all(FLERR,"Fix tmd must come after integration fixes");
// timesteps
dtv = update->dt;
dtf = update->dt * force->ftm2v;
if (strstr(update->integrate_style,"respa"))
step_respa = ((Respa *) update->integrate)->step;
}
/* ---------------------------------------------------------------------- */
void FixTMD::initial_integrate(int vflag)
{
double a,b,c,d,e;
double dx,dy,dz,dxkt,dykt,dzkt;
double dxold,dyold,dzold,xback,yback,zback;
double gamma_forward,gamma_back,gamma_max,lambda;
double kt,fr,kttotal,frtotal,dtfm;
double unwrap[3];
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double *mass = atom->mass;
imageint *image = atom->image;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
double rho_target = rho_start + delta * (rho_stop - rho_start);
// compute the Lagrange multiplier
a = b = e = 0.0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dxold = xold[i][0] - xf[i][0];
dyold = xold[i][1] - xf[i][1];
dzold = xold[i][2] - xf[i][2];
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - xf[i][0];
dy = unwrap[1] - xf[i][1];
dz = unwrap[2] - xf[i][2];
a += mass[type[i]]*(dxold*dxold + dyold*dyold + dzold*dzold);
b += mass[type[i]]*(dx *dxold + dy *dyold + dz *dzold);
e += mass[type[i]]*(dx *dx + dy *dy + dz *dz);
}
}
double abe[3],abetotal[3];
abe[0] = a; abe[1] = b; abe[2] = e;
MPI_Allreduce(abe,abetotal,3,MPI_DOUBLE,MPI_SUM,world);
a = abetotal[0]/masstotal;
b = 2.0*abetotal[1]/masstotal;
e = abetotal[2]/masstotal;
c = e - rho_old*rho_old;
d = b*b - 4*a*c;
if (d < 0) d = 0;
if (b >= 0) gamma_max = (-b - sqrt(d))/(2*a);
else gamma_max = (-b + sqrt(d))/(2*a);
gamma_back = c/(a*gamma_max);
if (a == 0.0) gamma_back = 0;
c = e - rho_target*rho_target;
d = b*b - 4*a*c;
if (d < 0) d = 0;
if (b >= 0) gamma_max = (-b - sqrt(d))/(2*a);
else gamma_max = (-b + sqrt(d))/(2*a);
gamma_forward = c/(a*gamma_max);
if (a == 0.0) gamma_forward = 0;
fr = kt = 0.0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dxold = xold[i][0] - xf[i][0];
dyold = xold[i][1] - xf[i][1];
dzold = xold[i][2] - xf[i][2];
domain->unmap(x[i],image[i],unwrap);
xback = unwrap[0] + gamma_back*dxold;
yback = unwrap[1] + gamma_back*dyold;
zback = unwrap[2] + gamma_back*dzold;
dxkt = xback - xold[i][0];
dykt = yback - xold[i][1];
dzkt = zback - xold[i][2];
kt += mass[type[i]]*(dxkt*dxkt + dykt*dykt + dzkt*dzkt);
fr += f[i][0]*dxold + f[i][1]*dyold + f[i][2]*dzold;
}
}
double r[2],rtotal[2];
r[0] = fr; r[1] = kt;
MPI_Allreduce(r,rtotal,2,MPI_DOUBLE,MPI_SUM,world);
frtotal = rtotal[0];
kttotal = rtotal[1];
// stat write of mean constraint force based on previous time step constraint
if (nfileevery && me == 0) {
work_analytical +=
(-frtotal - kttotal/dtv/dtf)*(rho_target - rho_old)/rho_old;
lambda = gamma_back*rho_old*masstotal/dtv/dtf;
work_lambda += lambda*(rho_target - rho_old);
if (!(update->ntimestep % nfileevery) &&
(previous_stat != update->ntimestep)) {
fprintf(fp,
BIGINT_FORMAT " %g %g %g %g %g %g %g\n",
update->ntimestep,rho_target,rho_old,
gamma_back,gamma_forward,lambda,work_lambda,work_analytical);
fflush(fp);
previous_stat = update->ntimestep;
}
}
rho_old = rho_target;
// apply the constraint and save constrained positions for next step
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
dtfm = dtf / mass[type[i]];
dxold = xold[i][0] - xf[i][0];
x[i][0] += gamma_forward*dxold;
v[i][0] += gamma_forward*dxold/dtv;
f[i][0] += gamma_forward*dxold/dtv/dtfm;
dyold = xold[i][1] - xf[i][1];
x[i][1] += gamma_forward*dyold;
v[i][1] += gamma_forward*dyold/dtv;
f[i][1] += gamma_forward*dyold/dtv/dtfm;
dzold = xold[i][2] - xf[i][2];
x[i][2] += gamma_forward*dzold;
v[i][2] += gamma_forward*dzold/dtv;
f[i][2] += gamma_forward*dzold/dtv/dtfm;
domain->unmap(x[i],image[i],xold[i]);
}
}
}
/* ---------------------------------------------------------------------- */
void FixTMD::initial_integrate_respa(int vflag, int ilevel, int flag)
{
if (flag) return; // only used by NPT,NPH
dtv = step_respa[ilevel];
dtf = step_respa[ilevel] * force->ftm2v;
if (ilevel == 0) initial_integrate(vflag);
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixTMD::memory_usage()
{
double bytes = 2*atom->nmax*3 * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
allocate atom-based arrays
------------------------------------------------------------------------- */
void FixTMD::grow_arrays(int nmax)
{
memory->grow(xf,nmax,3,"fix_tmd:xf");
memory->grow(xold,nmax,3,"fix_tmd:xold");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixTMD::copy_arrays(int i, int j, int delflag)
{
xf[j][0] = xf[i][0];
xf[j][1] = xf[i][1];
xf[j][2] = xf[i][2];
xold[j][0] = xold[i][0];
xold[j][1] = xold[i][1];
xold[j][2] = xold[i][2];
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixTMD::pack_exchange(int i, double *buf)
{
buf[0] = xf[i][0];
buf[1] = xf[i][1];
buf[2] = xf[i][2];
buf[3] = xold[i][0];
buf[4] = xold[i][1];
buf[5] = xold[i][2];
return 6;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixTMD::unpack_exchange(int nlocal, double *buf)
{
xf[nlocal][0] = buf[0];
xf[nlocal][1] = buf[1];
xf[nlocal][2] = buf[2];
xold[nlocal][0] = buf[3];
xold[nlocal][1] = buf[4];
xold[nlocal][2] = buf[5];
return 6;
}
/* ----------------------------------------------------------------------
read target coordinates from file, store with appropriate atom
------------------------------------------------------------------------- */
void FixTMD::readfile(char *file)
{
if (me == 0) {
if (screen) fprintf(screen,"Reading TMD target file %s ...\n",file);
open(file);
}
int *mask = atom->mask;
int nlocal = atom->nlocal;
char *buffer = new char[CHUNK*MAXLINE];
char *next,*bufptr;
- int i,m,nlines,tag,imageflag,ix,iy,iz;
+ int i,m,nlines,imageflag,ix,iy,iz;
+ tagint itag;
double x,y,z,xprd,yprd,zprd;
int firstline = 1;
int ncount = 0;
char *eof = NULL;
xprd = yprd = zprd = -1.0;
while (!eof) {
if (me == 0) {
m = 0;
for (nlines = 0; nlines < CHUNK; nlines++) {
eof = fgets(&buffer[m],MAXLINE,fp);
if (eof == NULL) break;
m += strlen(&buffer[m]);
}
if (buffer[m-1] != '\n') strcpy(&buffer[m++],"\n");
m++;
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
MPI_Bcast(&nlines,1,MPI_INT,0,world);
MPI_Bcast(&m,1,MPI_INT,0,world);
MPI_Bcast(buffer,m,MPI_CHAR,0,world);
bufptr = buffer;
for (i = 0; i < nlines; i++) {
next = strchr(bufptr,'\n');
*next = '\0';
if (firstline) {
if (strstr(bufptr,"xlo xhi")) {
double lo,hi;
sscanf(bufptr,"%lg %lg",&lo,&hi);
xprd = hi - lo;
bufptr = next + 1;
continue;
} else if (strstr(bufptr,"ylo yhi")) {
double lo,hi;
sscanf(bufptr,"%lg %lg",&lo,&hi);
yprd = hi - lo;
bufptr = next + 1;
continue;
} else if (strstr(bufptr,"zlo zhi")) {
double lo,hi;
sscanf(bufptr,"%lg %lg",&lo,&hi);
zprd = hi - lo;
bufptr = next + 1;
continue;
} else if (atom->count_words(bufptr) == 4) {
if (xprd >= 0.0 || yprd >= 0.0 || zprd >= 0.0)
error->all(FLERR,"Incorrect format in TMD target file");
imageflag = 0;
firstline = 0;
} else if (atom->count_words(bufptr) == 7) {
if (xprd < 0.0 || yprd < 0.0 || zprd < 0.0)
error->all(FLERR,"Incorrect format in TMD target file");
imageflag = 1;
firstline = 0;
} else error->all(FLERR,"Incorrect format in TMD target file");
}
if (imageflag)
- sscanf(bufptr,"%d %lg %lg %lg %d %d %d",&tag,&x,&y,&z,&ix,&iy,&iz);
+ sscanf(bufptr,TAGINT_FORMAT " %lg %lg %lg %d %d %d",
+ &itag,&x,&y,&z,&ix,&iy,&iz);
else
- sscanf(bufptr,"%d %lg %lg %lg",&tag,&x,&y,&z);
+ sscanf(bufptr,TAGINT_FORMAT " %lg %lg %lg",&itag,&x,&y,&z);
- m = atom->map(tag);
+ m = atom->map(itag);
if (m >= 0 && m < nlocal && mask[m] & groupbit) {
if (imageflag) {
xf[m][0] = x + ix*xprd;
xf[m][1] = y + iy*yprd;
xf[m][2] = z + iz*zprd;
} else {
xf[m][0] = x;
xf[m][1] = y;
xf[m][2] = z;
}
ncount++;
}
bufptr = next + 1;
}
}
// clean up
delete [] buffer;
if (me == 0) {
if (compressed) pclose(fp);
else fclose(fp);
}
// check that all atoms in group were listed in target file
// set xf = 0.0 for atoms not in group
int gcount = 0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) gcount++;
else xf[i][0] = xf[i][1] = xf[i][2] = 0.0;
int flag = 0;
if (gcount != ncount) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall) error->all(FLERR,"TMD target file did not list all group atoms");
}
/* ----------------------------------------------------------------------
proc 0 opens TMD data file
test if gzipped
------------------------------------------------------------------------- */
void FixTMD::open(char *file)
{
compressed = 0;
char *suffix = file + strlen(file) - 3;
if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
if (!compressed) fp = fopen(file,"r");
else {
#ifdef LAMMPS_GZIP
char gunzip[128];
sprintf(gunzip,"gzip -c -d %s",file);
#ifdef _WIN32
fp = _popen(gunzip,"rb");
#else
fp = popen(gunzip,"r");
#endif
#else
error->one(FLERR,"Cannot open gzipped file");
#endif
}
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open file %s",file);
error->one(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void FixTMD::reset_dt()
{
dtv = update->dt;
dtf = update->dt * force->ftm2v;
}
diff --git a/src/force.cpp b/src/force.cpp
index 23699fdb2..d486493c9 100644
--- a/src/force.cpp
+++ b/src/force.cpp
@@ -1,745 +1,797 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "ctype.h"
#include "force.h"
#include "style_bond.h"
#include "style_angle.h"
#include "style_dihedral.h"
#include "style_improper.h"
#include "style_pair.h"
#include "style_kspace.h"
#include "atom.h"
#include "comm.h"
#include "pair.h"
#include "pair_hybrid.h"
#include "pair_hybrid_overlay.h"
#include "bond.h"
#include "bond_hybrid.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "kspace.h"
#include "group.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
Force::Force(LAMMPS *lmp) : Pointers(lmp)
{
newton = newton_pair = newton_bond = 1;
special_lj[0] = special_coul[0] = 1.0;
special_lj[1] = special_lj[2] = special_lj[3] = 0.0;
special_coul[1] = special_coul[2] = special_coul[3] = 0.0;
special_angle = special_dihedral = 0;
special_extra = 0;
dielectric = 1.0;
pair = NULL;
bond = NULL;
angle = NULL;
dihedral = NULL;
improper = NULL;
kspace = NULL;
char *str = (char *) "none";
int n = strlen(str) + 1;
pair_style = new char[n];
strcpy(pair_style,str);
bond_style = new char[n];
strcpy(bond_style,str);
angle_style = new char[n];
strcpy(angle_style,str);
dihedral_style = new char[n];
strcpy(dihedral_style,str);
improper_style = new char[n];
strcpy(improper_style,str);
kspace_style = new char[n];
strcpy(kspace_style,str);
// fill pair map with pair styles listed in style_pair.h
pair_map = new std::map<std::string,PairCreator>();
#define PAIR_CLASS
#define PairStyle(key,Class) \
(*pair_map)[#key] = &pair_creator<Class>;
#include "style_pair.h"
#undef PairStyle
#undef PAIR_CLASS
}
/* ---------------------------------------------------------------------- */
Force::~Force()
{
delete [] pair_style;
delete [] bond_style;
delete [] angle_style;
delete [] dihedral_style;
delete [] improper_style;
delete [] kspace_style;
if (pair) delete pair;
if (bond) delete bond;
if (angle) delete angle;
if (dihedral) delete dihedral;
if (improper) delete improper;
if (kspace) delete kspace;
delete pair_map;
}
/* ---------------------------------------------------------------------- */
void Force::init()
{
qqrd2e = qqr2e/dielectric;
if (kspace) kspace->init(); // kspace must come before pair
if (pair) pair->init(); // so g_ewald is defined
if (bond) bond->init();
if (angle) angle->init();
if (dihedral) dihedral->init();
if (improper) improper->init();
}
/* ----------------------------------------------------------------------
create a pair style, called from input script or restart file
------------------------------------------------------------------------- */
void Force::create_pair(const char *style, const char *suffix)
{
delete [] pair_style;
if (pair) delete pair;
int sflag;
pair = new_pair(style,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
pair_style = new char[n];
strcpy(pair_style,estyle);
} else {
int n = strlen(style) + 1;
pair_style = new char[n];
strcpy(pair_style,style);
}
}
/* ----------------------------------------------------------------------
generate a pair class
try first with suffix appended
------------------------------------------------------------------------- */
Pair *Force::new_pair(const char *style, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (pair_map->find(estyle) != pair_map->end()) {
PairCreator pair_creator = (*pair_map)[estyle];
return pair_creator(lmp);
}
}
sflag = 0;
if (strcmp(style,"none") == 0) return NULL;
if (pair_map->find(style) != pair_map->end()) {
PairCreator pair_creator = (*pair_map)[style];
return pair_creator(lmp);
}
error->all(FLERR,"Invalid pair style");
return NULL;
}
/* ----------------------------------------------------------------------
one instance per pair style in style_pair.h
------------------------------------------------------------------------- */
template <typename T>
Pair *Force::pair_creator(LAMMPS *lmp)
{
return new T(lmp);
}
/* ----------------------------------------------------------------------
return ptr to Pair class if matches word or matches hybrid sub-style
if exact, then style name must be exact match to word
if not exact, style name must contain word
return NULL if no match or multiple sub-styles match
------------------------------------------------------------------------- */
Pair *Force::pair_match(const char *word, int exact)
{
int iwhich,count;
if (exact && strcmp(pair_style,word) == 0) return pair;
else if (!exact && strstr(pair_style,word)) return pair;
else if (strstr(pair_style,"hybrid/overlay")) {
PairHybridOverlay *hybrid = (PairHybridOverlay *) pair;
count = 0;
for (int i = 0; i < hybrid->nstyles; i++)
if ((exact && strcmp(hybrid->keywords[i],word) == 0) ||
(!exact && strstr(hybrid->keywords[i],word))) {
iwhich = i;
count++;
}
if (count == 1) return hybrid->styles[iwhich];
} else if (strstr(pair_style,"hybrid")) {
PairHybrid *hybrid = (PairHybrid *) pair;
count = 0;
for (int i = 0; i < hybrid->nstyles; i++)
if ((exact && strcmp(hybrid->keywords[i],word) == 0) ||
(!exact && strstr(hybrid->keywords[i],word))) {
iwhich = i;
count++;
}
if (count == 1) return hybrid->styles[iwhich];
}
return NULL;
}
/* ----------------------------------------------------------------------
create a bond style, called from input script or restart file
------------------------------------------------------------------------- */
void Force::create_bond(const char *style, const char *suffix)
{
delete [] bond_style;
if (bond) delete bond;
int sflag;
bond = new_bond(style,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
bond_style = new char[n];
strcpy(bond_style,estyle);
} else {
int n = strlen(style) + 1;
bond_style = new char[n];
strcpy(bond_style,style);
}
}
/* ----------------------------------------------------------------------
generate a bond class, fist with suffix appended
------------------------------------------------------------------------- */
Bond *Force::new_bond(const char *style, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (0) return NULL;
#define BOND_CLASS
#define BondStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp);
#include "style_bond.h"
#undef BondStyle
#undef BOND_CLASS
}
sflag = 0;
if (strcmp(style,"none") == 0) return NULL;
#define BOND_CLASS
#define BondStyle(key,Class) \
else if (strcmp(style,#key) == 0) return new Class(lmp);
#include "style_bond.h"
#undef BOND_CLASS
else error->all(FLERR,"Invalid bond style");
return NULL;
}
/* ----------------------------------------------------------------------
return ptr to current bond class or hybrid sub-class if matches style
------------------------------------------------------------------------- */
Bond *Force::bond_match(const char *style)
{
if (strcmp(bond_style,style) == 0) return bond;
else if (strcmp(bond_style,"hybrid") == 0) {
BondHybrid *hybrid = (BondHybrid *) bond;
for (int i = 0; i < hybrid->nstyles; i++)
if (strcmp(hybrid->keywords[i],style) == 0) return hybrid->styles[i];
}
return NULL;
}
/* ----------------------------------------------------------------------
create an angle style, called from input script or restart file
------------------------------------------------------------------------- */
void Force::create_angle(const char *style, const char *suffix)
{
delete [] angle_style;
if (angle) delete angle;
int sflag;
angle = new_angle(style,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
angle_style = new char[n];
strcpy(angle_style,estyle);
} else {
int n = strlen(style) + 1;
angle_style = new char[n];
strcpy(angle_style,style);
}
}
/* ----------------------------------------------------------------------
generate an angle class
------------------------------------------------------------------------- */
Angle *Force::new_angle(const char *style, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (0) return NULL;
#define ANGLE_CLASS
#define AngleStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp);
#include "style_angle.h"
#undef AngleStyle
#undef ANGLE_CLASS
}
sflag = 0;
if (strcmp(style,"none") == 0) return NULL;
#define ANGLE_CLASS
#define AngleStyle(key,Class) \
else if (strcmp(style,#key) == 0) return new Class(lmp);
#include "style_angle.h"
#undef ANGLE_CLASS
else error->all(FLERR,"Invalid angle style");
return NULL;
}
/* ----------------------------------------------------------------------
create a dihedral style, called from input script or restart file
------------------------------------------------------------------------- */
void Force::create_dihedral(const char *style, const char *suffix)
{
delete [] dihedral_style;
if (dihedral) delete dihedral;
int sflag;
dihedral = new_dihedral(style,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
dihedral_style = new char[n];
strcpy(dihedral_style,estyle);
} else {
int n = strlen(style) + 1;
dihedral_style = new char[n];
strcpy(dihedral_style,style);
}
}
/* ----------------------------------------------------------------------
generate a dihedral class
------------------------------------------------------------------------- */
Dihedral *Force::new_dihedral(const char *style, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (0) return NULL;
#define DIHEDRAL_CLASS
#define DihedralStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp);
#include "style_dihedral.h"
#undef DihedralStyle
#undef DIHEDRAL_CLASS
}
sflag = 0;
if (strcmp(style,"none") == 0) return NULL;
#define DIHEDRAL_CLASS
#define DihedralStyle(key,Class) \
else if (strcmp(style,#key) == 0) return new Class(lmp);
#include "style_dihedral.h"
#undef DihedralStyle
#undef DIHEDRAL_CLASS
else error->all(FLERR,"Invalid dihedral style");
return NULL;
}
/* ----------------------------------------------------------------------
create an improper style, called from input script or restart file
------------------------------------------------------------------------- */
void Force::create_improper(const char *style, const char *suffix)
{
delete [] improper_style;
if (improper) delete improper;
int sflag;
improper = new_improper(style,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
int n = strlen(estyle) + 1;
improper_style = new char[n];
strcpy(improper_style,estyle);
} else {
int n = strlen(style) + 1;
improper_style = new char[n];
strcpy(improper_style,style);
}
}
/* ----------------------------------------------------------------------
generate a improper class
------------------------------------------------------------------------- */
Improper *Force::new_improper(const char *style, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",style,suffix);
if (0) return NULL;
#define IMPROPER_CLASS
#define ImproperStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp);
#include "style_improper.h"
#undef ImproperStyle
#undef IMPROPER_CLASS
}
sflag = 0;
if (strcmp(style,"none") == 0) return NULL;
#define IMPROPER_CLASS
#define ImproperStyle(key,Class) \
else if (strcmp(style,#key) == 0) return new Class(lmp);
#include "style_improper.h"
#undef IMPROPER_CLASS
else error->all(FLERR,"Invalid improper style");
return NULL;
}
/* ----------------------------------------------------------------------
new kspace style
------------------------------------------------------------------------- */
void Force::create_kspace(int narg, char **arg, const char *suffix)
{
delete [] kspace_style;
if (kspace) delete kspace;
int sflag;
kspace = new_kspace(narg,arg,suffix,sflag);
if (sflag) {
char estyle[256];
sprintf(estyle,"%s/%s",arg[0],suffix);
int n = strlen(estyle) + 1;
kspace_style = new char[n];
strcpy(kspace_style,estyle);
} else {
int n = strlen(arg[0]) + 1;
kspace_style = new char[n];
strcpy(kspace_style,arg[0]);
}
}
/* ----------------------------------------------------------------------
generate a kspace class
------------------------------------------------------------------------- */
KSpace *Force::new_kspace(int narg, char **arg, const char *suffix, int &sflag)
{
if (suffix && lmp->suffix_enable) {
sflag = 1;
char estyle[256];
sprintf(estyle,"%s/%s",arg[0],suffix);
if (0) return NULL;
#define KSPACE_CLASS
#define KSpaceStyle(key,Class) \
else if (strcmp(estyle,#key) == 0) return new Class(lmp,narg-1,&arg[1]);
#include "style_kspace.h"
#undef KSpaceStyle
#undef KSPACE_CLASS
}
sflag = 0;
if (strcmp(arg[0],"none") == 0) return NULL;
#define KSPACE_CLASS
#define KSpaceStyle(key,Class) \
else if (strcmp(arg[0],#key) == 0) return new Class(lmp,narg-1,&arg[1]);
#include "style_kspace.h"
#undef KSPACE_CLASS
else error->all(FLERR,"Invalid kspace style");
return NULL;
}
/* ----------------------------------------------------------------------
return ptr to Kspace class if matches word
if exact, then style name must be exact match to word
if not exact, style name must contain word
return NULL if no match
------------------------------------------------------------------------- */
KSpace *Force::kspace_match(const char *word, int exact)
{
if (exact && strcmp(kspace_style,word) == 0) return kspace;
else if (!exact && strstr(kspace_style,word)) return kspace;
return NULL;
}
/* ----------------------------------------------------------------------
set special bond values
------------------------------------------------------------------------- */
void Force::set_special(int narg, char **arg)
{
if (narg == 0) error->all(FLERR,"Illegal special_bonds command");
// defaults
special_lj[1] = special_lj[2] = special_lj[3] = 0.0;
special_coul[1] = special_coul[2] = special_coul[3] = 0.0;
special_angle = special_dihedral = special_extra = 0;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"amber") == 0) {
if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = 0.0;
special_lj[2] = 0.0;
special_lj[3] = 0.5;
special_coul[1] = 0.0;
special_coul[2] = 0.0;
special_coul[3] = 5.0/6.0;
iarg += 1;
} else if (strcmp(arg[iarg],"charmm") == 0) {
if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = 0.0;
special_lj[2] = 0.0;
special_lj[3] = 0.0;
special_coul[1] = 0.0;
special_coul[2] = 0.0;
special_coul[3] = 0.0;
iarg += 1;
} else if (strcmp(arg[iarg],"dreiding") == 0) {
if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = 0.0;
special_lj[2] = 0.0;
special_lj[3] = 1.0;
special_coul[1] = 0.0;
special_coul[2] = 0.0;
special_coul[3] = 1.0;
iarg += 1;
} else if (strcmp(arg[iarg],"fene") == 0) {
if (iarg+1 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = 0.0;
special_lj[2] = 1.0;
special_lj[3] = 1.0;
special_coul[1] = 0.0;
special_coul[2] = 1.0;
special_coul[3] = 1.0;
iarg += 1;
} else if (strcmp(arg[iarg],"lj/coul") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = special_coul[1] = atof(arg[iarg+1]);
special_lj[2] = special_coul[2] = atof(arg[iarg+2]);
special_lj[3] = special_coul[3] = atof(arg[iarg+3]);
iarg += 4;
} else if (strcmp(arg[iarg],"lj") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command");
special_lj[1] = atof(arg[iarg+1]);
special_lj[2] = atof(arg[iarg+2]);
special_lj[3] = atof(arg[iarg+3]);
iarg += 4;
} else if (strcmp(arg[iarg],"coul") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal special_bonds command");
special_coul[1] = atof(arg[iarg+1]);
special_coul[2] = atof(arg[iarg+2]);
special_coul[3] = atof(arg[iarg+3]);
iarg += 4;
} else if (strcmp(arg[iarg],"angle") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command");
if (strcmp(arg[iarg+1],"no") == 0) special_angle = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) special_angle = 1;
else error->all(FLERR,"Illegal special_bonds command");
iarg += 2;
} else if (strcmp(arg[iarg],"dihedral") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command");
if (strcmp(arg[iarg+1],"no") == 0) special_dihedral = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) special_dihedral = 1;
else error->all(FLERR,"Illegal special_bonds command");
iarg += 2;
} else if (strcmp(arg[iarg],"extra") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal special_bonds command");
special_extra = atoi(arg[iarg+1]);
iarg += 2;
} else error->all(FLERR,"Illegal special_bonds command");
}
for (int i = 1; i <= 3; i++)
if (special_lj[i] < 0.0 || special_lj[i] > 1.0 ||
special_coul[i] < 0.0 || special_coul[i] > 1.0)
error->all(FLERR,"Illegal special_bonds command");
if (special_extra < 0) error->all(FLERR,"Illegal special_bonds command");
}
/* ----------------------------------------------------------------------
compute bounds implied by numeric str with a possible wildcard asterik
1 = lower bound, nmax = upper bound
5 possibilities:
(1) i = i to i, (2) * = nmin to nmax,
(3) i* = i to nmax, (4) *j = nmin to j, (5) i*j = i to j
return nlo,nhi
------------------------------------------------------------------------- */
void Force::bounds(char *str, int nmax, int &nlo, int &nhi, int nmin)
{
char *ptr = strchr(str,'*');
if (ptr == NULL) {
nlo = nhi = atoi(str);
} else if (strlen(str) == 1) {
nlo = nmin;
nhi = nmax;
} else if (ptr == str) {
nlo = nmin;
nhi = atoi(ptr+1);
} else if (strlen(ptr+1) == 0) {
nlo = atoi(str);
nhi = nmax;
} else {
nlo = atoi(str);
nhi = atoi(ptr+1);
}
if (nlo < nmin || nhi > nmax)
error->all(FLERR,"Numeric index is out of bounds");
}
+/* ----------------------------------------------------------------------
+ compute bounds implied by numeric str with a possible wildcard asterik
+ 1 = lower bound, nmax = upper bound
+ 5 possibilities:
+ (1) i = i to i, (2) * = nmin to nmax,
+ (3) i* = i to nmax, (4) *j = nmin to j, (5) i*j = i to j
+ return nlo,nhi
+------------------------------------------------------------------------- */
+
+void Force::boundsbig(char *str, bigint nmax, bigint &nlo, bigint &nhi,
+ bigint nmin)
+{
+ char *ptr = strchr(str,'*');
+
+ if (ptr == NULL) {
+ nlo = nhi = ATOBIGINT(str);
+ } else if (strlen(str) == 1) {
+ nlo = nmin;
+ nhi = nmax;
+ } else if (ptr == str) {
+ nlo = nmin;
+ nhi = ATOBIGINT(ptr+1);
+ } else if (strlen(ptr+1) == 0) {
+ nlo = ATOBIGINT(str);
+ nhi = nmax;
+ } else {
+ nlo = ATOBIGINT(str);
+ nhi = ATOBIGINT(ptr+1);
+ }
+
+ if (nlo < nmin || nhi > nmax)
+ error->all(FLERR,"Numeric index is out of bounds");
+}
+
/* ----------------------------------------------------------------------
read a floating point value from a string
generate an error if not a legitimate floating point value
called by various commands to check validity of their arguments
------------------------------------------------------------------------- */
double Force::numeric(const char *file, int line, char *str)
{
int n = strlen(str);
for (int i = 0; i < n; i++) {
if (isdigit(str[i])) continue;
if (str[i] == '-' || str[i] == '+' || str[i] == '.') continue;
if (str[i] == 'e' || str[i] == 'E') continue;
error->all(file,line,"Expected floating point parameter "
"in input script or data file");
}
return atof(str);
}
/* ----------------------------------------------------------------------
read an integer value from a string
generate an error if not a legitimate integer value
called by various commands to check validity of their arguments
------------------------------------------------------------------------- */
int Force::inumeric(const char *file, int line, char *str)
{
int n = strlen(str);
for (int i = 0; i < n; i++) {
if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue;
error->all(file,line,
"Expected integer parameter in input script or data file");
}
return atoi(str);
}
+/* ----------------------------------------------------------------------
+ read a big integer value from a string
+ generate an error if not a legitimate integer value
+ called by various commands to check validity of their arguments
+------------------------------------------------------------------------- */
+
+bigint Force::bnumeric(const char *file, int line, char *str)
+{
+ int n = strlen(str);
+ for (int i = 0; i < n; i++) {
+ if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue;
+ error->all(file,line,
+ "Expected integer parameter in input script or data file");
+ }
+
+ return ATOLL(str);
+}
+
/* ----------------------------------------------------------------------
memory usage of force classes
------------------------------------------------------------------------- */
bigint Force::memory_usage()
{
bigint bytes = 0;
if (pair) bytes += static_cast<bigint> (pair->memory_usage());
if (bond) bytes += static_cast<bigint> (bond->memory_usage());
if (angle) bytes += static_cast<bigint> (angle->memory_usage());
if (dihedral) bytes += static_cast<bigint> (dihedral->memory_usage());
if (improper) bytes += static_cast<bigint> (improper->memory_usage());
if (kspace) bytes += static_cast<bigint> (kspace->memory_usage());
return bytes;
}
diff --git a/src/force.h b/src/force.h
index c866656de..c2109d089 100644
--- a/src/force.h
+++ b/src/force.h
@@ -1,161 +1,163 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_FORCE_H
#define LMP_FORCE_H
#include "pointers.h"
#include <map>
#include <string>
namespace LAMMPS_NS {
class Force : protected Pointers {
public:
double boltz; // Boltzmann constant (eng/degree-K)
double hplanck; // Planck's constant (energy-time)
double mvv2e; // conversion of mv^2 to energy
double ftm2v; // conversion of ft/m to velocity
double mv2d; // conversion of mass/volume to density
double nktv2p; // conversion of NkT/V to pressure
double qqr2e; // conversion of q^2/r to energy
double qe2f; // conversion of qE to force
double vxmu2f; // conversion of vx dynamic-visc to force
double xxt2kmu; // conversion of xx/t to kinematic-visc
double dielectric; // dielectric constant
double qqrd2e; // q^2/r to energy w/ dielectric constant
double e_mass; // electron mass
double hhmrr2e; // conversion of (hbar)^2/(mr^2) to energy
double mvh2r; // conversion of mv/hbar to distance
// hbar = h/(2*pi)
double angstrom; // 1 angstrom in native units
double femtosecond; // 1 femtosecond in native units
double qelectron; // 1 electron charge abs() in native units
int newton,newton_pair,newton_bond; // Newton's 3rd law settings
class Pair *pair;
char *pair_style;
typedef Pair *(*PairCreator)(LAMMPS *);
std::map<std::string,PairCreator> *pair_map;
class Bond *bond;
char *bond_style;
class Angle *angle;
char *angle_style;
class Dihedral *dihedral;
char *dihedral_style;
class Improper *improper;
char *improper_style;
class KSpace *kspace;
char *kspace_style;
// index [0] is not used in these arrays
double special_lj[4]; // 1-2, 1-3, 1-4 prefactors for LJ
double special_coul[4]; // 1-2, 1-3, 1-4 prefactors for Coulombics
int special_angle; // 0 if defined angles are ignored
// 1 if only weight 1,3 atoms if in an angle
int special_dihedral; // 0 if defined dihedrals are ignored
// 1 if only weight 1,4 atoms if in a dihedral
int special_extra; // extra space for added bonds
Force(class LAMMPS *);
~Force();
void init();
void create_pair(const char *, const char *suffix = NULL);
class Pair *new_pair(const char *, const char *, int &);
class Pair *pair_match(const char *, int);
void create_bond(const char *, const char *suffix = NULL);
class Bond *new_bond(const char *, const char *, int &);
class Bond *bond_match(const char *);
void create_angle(const char *, const char *suffix = NULL);
class Angle *new_angle(const char *, const char *, int &);
void create_dihedral(const char *, const char *suffix = NULL);
class Dihedral *new_dihedral(const char *, const char *, int &);
void create_improper(const char *, const char *suffix = NULL);
class Improper *new_improper(const char *, const char *, int &);
void create_kspace(int, char **, const char *suffix = NULL);
class KSpace *new_kspace(int, char **, const char *, int &);
class KSpace *kspace_match(const char *, int);
void set_special(int, char **);
void bounds(char *, int, int &, int &, int nmin=1);
+ void boundsbig(char *, bigint, bigint &, bigint &, bigint nmin=1);
double numeric(const char *, int, char *);
int inumeric(const char *, int, char *);
+ bigint bnumeric(const char *, int, char *);
bigint memory_usage();
private:
template <typename T> static Pair *pair_creator(LAMMPS *);
};
}
#endif
/* ERROR/WARNING messages:
E: Invalid pair style
The choice of pair style is unknown.
E: Invalid bond style
The choice of bond style is unknown.
E: Invalid angle style
The choice of angle style is unknown.
E: Invalid dihedral style
The choice of dihedral style is unknown.
E: Invalid improper style
The choice of improper style is unknown.
E: Invalid kspace style
The choice of kspace style is unknown.
E: Illegal ... command
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.
E: Numeric index is out of bounds
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.
U: Expected floating point parameter in input script or data file
The quantity being read is an integer on non-numeric value.
U: Expected integer parameter in input script or data file
The quantity being read is a floating point or non-numeric value.
*/
diff --git a/src/group.cpp b/src/group.cpp
index d525c7928..22b9035cc 100644
--- a/src/group.cpp
+++ b/src/group.cpp
@@ -1,1449 +1,1510 @@
/* ----------------------------------------------------------------------
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 "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "group.h"
#include "domain.h"
#include "atom.h"
#include "force.h"
#include "region.h"
#include "modify.h"
#include "fix.h"
#include "compute.h"
#include "output.h"
#include "input.h"
#include "variable.h"
#include "dump.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MAX_GROUP 32
enum{TYPE,MOLECULE,ID};
enum{LT,LE,GT,GE,EQ,NEQ,BETWEEN};
#define BIG 1.0e20
/* ----------------------------------------------------------------------
initialize group memory
------------------------------------------------------------------------- */
Group::Group(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
names = new char*[MAX_GROUP];
bitmask = new int[MAX_GROUP];
inversemask = new int[MAX_GROUP];
for (int i = 0; i < MAX_GROUP; i++) names[i] = NULL;
for (int i = 0; i < MAX_GROUP; i++) bitmask[i] = 1 << i;
for (int i = 0; i < MAX_GROUP; i++) inversemask[i] = bitmask[i] ^ ~0;
// create "all" group
char *str = (char *) "all";
int n = strlen(str) + 1;
names[0] = new char[n];
strcpy(names[0],str);
ngroup = 1;
}
/* ----------------------------------------------------------------------
free all memory
------------------------------------------------------------------------- */
Group::~Group()
{
for (int i = 0; i < MAX_GROUP; i++) delete [] names[i];
delete [] names;
delete [] bitmask;
delete [] inversemask;
}
/* ----------------------------------------------------------------------
assign atoms to a new or existing group
------------------------------------------------------------------------- */
void Group::assign(int narg, char **arg)
{
int i;
if (domain->box_exist == 0)
error->all(FLERR,"Group command before simulation box is defined");
if (narg < 2) error->all(FLERR,"Illegal group command");
// delete the group if not being used elsewhere
// clear mask of each atom assigned to this group
if (strcmp(arg[1],"delete") == 0) {
int igroup = find(arg[0]);
if (igroup == -1) error->all(FLERR,"Could not find group delete group ID");
if (igroup == 0) error->all(FLERR,"Cannot delete group all");
for (i = 0; i < modify->nfix; i++)
if (modify->fix[i]->igroup == igroup)
error->all(FLERR,"Cannot delete group currently used by a fix");
for (i = 0; i < modify->ncompute; i++)
if (modify->compute[i]->igroup == igroup)
error->all(FLERR,"Cannot delete group currently used by a compute");
for (i = 0; i < output->ndump; i++)
if (output->dump[i]->igroup == igroup)
error->all(FLERR,"Cannot delete group currently used by a dump");
if (atom->firstgroupname && strcmp(arg[0],atom->firstgroupname) == 0)
error->all(FLERR,
"Cannot delete group currently used by atom_modify first");
int *mask = atom->mask;
int nlocal = atom->nlocal;
int bits = inversemask[igroup];
for (i = 0; i < nlocal; i++) mask[i] &= bits;
delete [] names[igroup];
names[igroup] = NULL;
ngroup--;
return;
}
// find group in existing list
// add a new group if igroup = -1
int igroup = find(arg[0]);
if (igroup == -1) {
if (ngroup == MAX_GROUP) error->all(FLERR,"Too many groups");
igroup = find_unused();
int n = strlen(arg[0]) + 1;
names[igroup] = new char[n];
strcpy(names[igroup],arg[0]);
ngroup++;
}
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int bit = bitmask[igroup];
// style = region
// add to group if atom is in region
if (strcmp(arg[1],"region") == 0) {
if (narg != 3) error->all(FLERR,"Illegal group command");
int iregion = domain->find_region(arg[2]);
if (iregion == -1) error->all(FLERR,"Group region ID does not exist");
domain->regions[iregion]->init();
for (i = 0; i < nlocal; i++)
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
mask[i] |= bit;
// style = type, molecule, id
} else if (strcmp(arg[1],"type") == 0 || strcmp(arg[1],"molecule") == 0 ||
strcmp(arg[1],"id") == 0) {
if (narg < 3) error->all(FLERR,"Illegal group command");
int category;
if (strcmp(arg[1],"type") == 0) category = TYPE;
else if (strcmp(arg[1],"molecule") == 0) category = MOLECULE;
else if (strcmp(arg[1],"id") == 0) category = ID;
// args = logical condition
if (narg > 3 &&
(strcmp(arg[2],"<") == 0 || strcmp(arg[2],">") == 0 ||
strcmp(arg[2],"<=") == 0 || strcmp(arg[2],">=") == 0 ||
strcmp(arg[2],"<>") == 0)) {
- int condition,bound1,bound2;
+ int condition;
if (strcmp(arg[2],"<") == 0) condition = LT;
else if (strcmp(arg[2],"<=") == 0) condition = LE;
else if (strcmp(arg[2],">") == 0) condition = GT;
else if (strcmp(arg[2],">=") == 0) condition = GE;
else if (strcmp(arg[2],"==") == 0) condition = EQ;
else if (strcmp(arg[2],"!=") == 0) condition = NEQ;
else if (strcmp(arg[2],"<>") == 0) condition = BETWEEN;
else error->all(FLERR,"Illegal group command");
- bound1 = force->inumeric(FLERR,arg[3]);
+ tagint bound1,bound2;
+ if (sizeof(tagint) == sizeof(smallint))
+ bound1 = force->inumeric(FLERR,arg[3]);
+ else
+ bound1 = force->bnumeric(FLERR,arg[3]);
bound2 = -1;
if (condition == BETWEEN) {
if (narg != 5) error->all(FLERR,"Illegal group command");
- bound2 = force->inumeric(FLERR,arg[4]);
+ if (sizeof(tagint) == sizeof(smallint))
+ bound2 = force->inumeric(FLERR,arg[4]);
+ else
+ bound2 = force->bnumeric(FLERR,arg[4]);
} else if (narg != 4) error->all(FLERR,"Illegal group command");
+ tagint *tag = atom->tag;
int *attribute;
if (category == TYPE) attribute = atom->type;
else if (category == MOLECULE) attribute = atom->molecule;
- else if (category == ID) attribute = atom->tag;
+ else if (category == ID) attribute = NULL;
// add to group if meets condition
- if (condition == LT) {
- for (i = 0; i < nlocal; i++) if (attribute[i] < bound1) mask[i] |= bit;
- } else if (condition == LE) {
- for (i = 0; i < nlocal; i++) if (attribute[i] <= bound1) mask[i] |= bit;
- } else if (condition == GT) {
- for (i = 0; i < nlocal; i++) if (attribute[i] > bound1) mask[i] |= bit;
- } else if (condition == GE) {
- for (i = 0; i < nlocal; i++) if (attribute[i] >= bound1) mask[i] |= bit;
- } else if (condition == EQ) {
- for (i = 0; i < nlocal; i++) if (attribute[i] == bound1) mask[i] |= bit;
- } else if (condition == NEQ) {
- for (i = 0; i < nlocal; i++) if (attribute[i] != bound1) mask[i] |= bit;
- } else if (condition == BETWEEN) {
- for (i = 0; i < nlocal; i++)
- if (attribute[i] >= bound1 && attribute[i] <= bound2) mask[i] |= bit;
+ if (attribute) {
+ if (condition == LT) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] < bound1) mask[i] |= bit;
+ } else if (condition == LE) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] <= bound1) mask[i] |= bit;
+ } else if (condition == GT) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] > bound1) mask[i] |= bit;
+ } else if (condition == GE) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] >= bound1) mask[i] |= bit;
+ } else if (condition == EQ) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] == bound1) mask[i] |= bit;
+ } else if (condition == NEQ) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] != bound1) mask[i] |= bit;
+ } else if (condition == BETWEEN) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] >= bound1 && attribute[i] <= bound2)
+ mask[i] |= bit;
+ }
+ } else {
+ if (condition == LT) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] < bound1) mask[i] |= bit;
+ } else if (condition == LE) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] <= bound1) mask[i] |= bit;
+ } else if (condition == GT) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] > bound1) mask[i] |= bit;
+ } else if (condition == GE) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] >= bound1) mask[i] |= bit;
+ } else if (condition == EQ) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] == bound1) mask[i] |= bit;
+ } else if (condition == NEQ) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] != bound1) mask[i] |= bit;
+ } else if (condition == BETWEEN) {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] >= bound1 && tag[i] <= bound2)
+ mask[i] |= bit;
+ }
}
-
+
// args = list of values
} else {
+ tagint *tag = atom->tag;
int *attribute;
if (category == TYPE) attribute = atom->type;
else if (category == MOLECULE) attribute = atom->molecule;
- else if (category == ID) attribute = atom->tag;
-
+ else if (category == ID) attribute = NULL;
+
char *ptr;
- int start,stop,delta;
+ tagint start,stop,delta;
for (int iarg = 2; iarg < narg; iarg++) {
- if (strchr(arg[iarg],':')) {
- start = atoi(strtok(arg[iarg],":"));
- stop = atoi(strtok(NULL,":"));
- ptr = strtok(NULL,":");
- if (ptr) delta = atoi(ptr);
- else delta = 1;
+ if (attribute) {
+ if (strchr(arg[iarg],':')) {
+ start = atoi(strtok(arg[iarg],":"));
+ stop = atoi(strtok(NULL,":"));
+ ptr = strtok(NULL,":");
+ if (ptr) delta = atoi(ptr);
+ else delta = 1;
+ } else {
+ start = stop = atoi(arg[iarg]);
+ delta = 1;
+ }
} else {
- start = stop = atoi(arg[iarg]);
- delta = 1;
+ if (strchr(arg[iarg],':')) {
+ start = ATOTAGINT(strtok(arg[iarg],":"));
+ stop = ATOTAGINT(strtok(NULL,":"));
+ ptr = strtok(NULL,":");
+ if (ptr) delta = ATOTAGINT(ptr);
+ else delta = 1;
+ } else {
+ start = stop = ATOTAGINT(arg[iarg]);
+ delta = 1;
+ }
}
// add to group if attribute matches value or sequence
- for (i = 0; i < nlocal; i++)
- if (attribute[i] >= start && attribute[i] <= stop &&
- (attribute[i]-start) % delta == 0) mask[i] |= bit;
+ if (attribute) {
+ for (i = 0; i < nlocal; i++)
+ if (attribute[i] >= start && attribute[i] <= stop &&
+ (attribute[i]-start) % delta == 0) mask[i] |= bit;
+ } else {
+ for (i = 0; i < nlocal; i++)
+ if (tag[i] >= start && tag[i] <= stop &&
+ (tag[i]-start) % delta == 0) mask[i] |= bit;
+ }
}
}
// style = variable
} else if (strcmp(arg[1],"variable") == 0) {
int ivar = input->variable->find(arg[2]);
if (ivar < 0) error->all(FLERR,"Variable name for group does not exist");
if (!input->variable->atomstyle(ivar))
error->all(FLERR,"Variable for group is invalid style");
double *aflag;
// aflag = evaluation of per-atom variable
memory->create(aflag,nlocal,"group:aflag");
input->variable->compute_atom(ivar,0,aflag,1,0);
// add to group if per-atom variable evaluated to non-zero
for (i = 0; i < nlocal; i++)
if (aflag[i] != 0.0) mask[i] |= bit;
memory->destroy(aflag);
// style = subtract
} else if (strcmp(arg[1],"subtract") == 0) {
if (narg < 4) error->all(FLERR,"Illegal group command");
int length = narg-2;
int *list = new int[length];
int jgroup;
for (int iarg = 2; iarg < narg; iarg++) {
jgroup = find(arg[iarg]);
if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
list[iarg-2] = jgroup;
}
// add to group if in 1st group in list
int otherbit = bitmask[list[0]];
for (i = 0; i < nlocal; i++)
if (mask[i] & otherbit) mask[i] |= bit;
// remove atoms if they are in any of the other groups
// AND with inverse mask removes the atom from group
int inverse = inversemask[igroup];
for (int ilist = 1; ilist < length; ilist++) {
otherbit = bitmask[list[ilist]];
for (i = 0; i < nlocal; i++)
if (mask[i] & otherbit) mask[i] &= inverse;
}
delete [] list;
// style = union
} else if (strcmp(arg[1],"union") == 0) {
if (narg < 3) error->all(FLERR,"Illegal group command");
int length = narg-2;
int *list = new int[length];
int jgroup;
for (int iarg = 2; iarg < narg; iarg++) {
jgroup = find(arg[iarg]);
if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
list[iarg-2] = jgroup;
}
// add to group if in any other group in list
int otherbit;
for (int ilist = 0; ilist < length; ilist++) {
otherbit = bitmask[list[ilist]];
for (i = 0; i < nlocal; i++)
if (mask[i] & otherbit) mask[i] |= bit;
}
delete [] list;
// style = intersect
} else if (strcmp(arg[1],"intersect") == 0) {
if (narg < 4) error->all(FLERR,"Illegal group command");
int length = narg-2;
int *list = new int[length];
int jgroup;
for (int iarg = 2; iarg < narg; iarg++) {
jgroup = find(arg[iarg]);
if (jgroup == -1) error->all(FLERR,"Group ID does not exist");
list[iarg-2] = jgroup;
}
// add to group if in all groups in list
int otherbit,ok,ilist;
for (i = 0; i < nlocal; i++) {
ok = 1;
for (ilist = 0; ilist < length; ilist++) {
otherbit = bitmask[list[ilist]];
if ((mask[i] & otherbit) == 0) ok = 0;
}
if (ok) mask[i] |= bit;
}
delete [] list;
// not a valid group style
} else error->all(FLERR,"Illegal group command");
// print stats for changed group
int n;
n = 0;
for (i = 0; i < nlocal; i++) if (mask[i] & bit) n++;
double rlocal = n;
double all;
MPI_Allreduce(&rlocal,&all,1,MPI_DOUBLE,MPI_SUM,world);
if (me == 0) {
if (screen) fprintf(screen,"%.15g atoms in group %s\n",all,names[igroup]);
if (logfile)
fprintf(logfile,"%.15g atoms in group %s\n",all,names[igroup]);
}
}
/* ----------------------------------------------------------------------
add flagged atoms to a new or existing group
------------------------------------------------------------------------- */
void Group::create(char *name, int *flag)
{
int i;
// find group in existing list
// add a new group if igroup = -1
int igroup = find(name);
if (igroup == -1) {
if (ngroup == MAX_GROUP) error->all(FLERR,"Too many groups");
igroup = find_unused();
int n = strlen(name) + 1;
names[igroup] = new char[n];
strcpy(names[igroup],name);
ngroup++;
}
// add atoms to group whose flags are set
int *mask = atom->mask;
int nlocal = atom->nlocal;
int bit = bitmask[igroup];
for (i = 0; i < nlocal; i++)
if (flag[i]) mask[i] |= bit;
}
/* ----------------------------------------------------------------------
return group index if name matches existing group, -1 if no such group
------------------------------------------------------------------------- */
int Group::find(const char *name)
{
for (int igroup = 0; igroup < MAX_GROUP; igroup++)
if (names[igroup] && strcmp(name,names[igroup]) == 0) return igroup;
return -1;
}
/* ----------------------------------------------------------------------
return index of first available group
should never be called when group limit has been reached
------------------------------------------------------------------------- */
int Group::find_unused()
{
for (int igroup = 0; igroup < MAX_GROUP; igroup++)
if (names[igroup] == NULL) return igroup;
return -1;
}
/* ----------------------------------------------------------------------
write group info to a restart file
only called by proc 0
------------------------------------------------------------------------- */
void Group::write_restart(FILE *fp)
{
fwrite(&ngroup,sizeof(int),1,fp);
// use count to not change restart format with deleted groups
// remove this on next major release
int n;
int count = 0;
for (int i = 0; i < MAX_GROUP; i++) {
if (names[i]) n = strlen(names[i]) + 1;
else n = 0;
fwrite(&n,sizeof(int),1,fp);
if (n) {
fwrite(names[i],sizeof(char),n,fp);
count++;
}
if (count == ngroup) break;
}
}
/* ----------------------------------------------------------------------
read group info from a restart file
proc 0 reads, bcast to all procs
------------------------------------------------------------------------- */
void Group::read_restart(FILE *fp)
{
int i,n;
// delete existing group names
// atom masks will be overwritten by reading of restart file
for (i = 0; i < MAX_GROUP; i++) delete [] names[i];
if (me == 0) fread(&ngroup,sizeof(int),1,fp);
MPI_Bcast(&ngroup,1,MPI_INT,0,world);
// use count to not change restart format with deleted groups
// remove this on next major release
int count = 0;
for (i = 0; i < MAX_GROUP; i++) {
if (count == ngroup) {
names[i] = NULL;
continue;
}
if (me == 0) fread(&n,sizeof(int),1,fp);
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n) {
names[i] = new char[n];
if (me == 0) fread(names[i],sizeof(char),n,fp);
MPI_Bcast(names[i],n,MPI_CHAR,0,world);
count++;
} else names[i] = NULL;
}
}
// ----------------------------------------------------------------------
// computations on a group of atoms
// ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
count atoms in group
------------------------------------------------------------------------- */
bigint Group::count(int igroup)
{
int groupbit = bitmask[igroup];
int *mask = atom->mask;
int nlocal = atom->nlocal;
int n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) n++;
bigint nsingle = n;
bigint nall;
MPI_Allreduce(&nsingle,&nall,1,MPI_LMP_BIGINT,MPI_SUM,world);
return nall;
}
/* ----------------------------------------------------------------------
count atoms in group and region
------------------------------------------------------------------------- */
bigint Group::count(int igroup, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int n = 0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) n++;
bigint nsingle = n;
bigint nall;
MPI_Allreduce(&nsingle,&nall,1,MPI_LMP_BIGINT,MPI_SUM,world);
return nall;
}
/* ----------------------------------------------------------------------
compute the total mass of group of atoms
use either per-type mass or per-atom rmass
------------------------------------------------------------------------- */
double Group::mass(int igroup)
{
int groupbit = bitmask[igroup];
double *mass = atom->mass;
double *rmass = atom->rmass;
int *mask = atom->mask;
int *type = atom->type;
int nlocal = atom->nlocal;
double one = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) one += rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) one += mass[type[i]];
}
double all;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
return all;
}
/* ----------------------------------------------------------------------
compute the total mass of group of atoms in region
use either per-type mass or per-atom rmass
------------------------------------------------------------------------- */
double Group::mass(int igroup, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double *mass = atom->mass;
double *rmass = atom->rmass;
int *mask = atom->mask;
int *type = atom->type;
int nlocal = atom->nlocal;
double one = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += mass[type[i]];
}
double all;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
return all;
}
/* ----------------------------------------------------------------------
compute the total charge of group of atoms
------------------------------------------------------------------------- */
double Group::charge(int igroup)
{
int groupbit = bitmask[igroup];
double *q = atom->q;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double qone = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) qone += q[i];
double qall;
MPI_Allreduce(&qone,&qall,1,MPI_DOUBLE,MPI_SUM,world);
return qall;
}
/* ----------------------------------------------------------------------
compute the total charge of group of atoms in region
------------------------------------------------------------------------- */
double Group::charge(int igroup, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double *q = atom->q;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double qone = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
qone += q[i];
double qall;
MPI_Allreduce(&qone,&qall,1,MPI_DOUBLE,MPI_SUM,world);
return qall;
}
/* ----------------------------------------------------------------------
compute the coordinate bounds of the group of atoms
periodic images are not considered, so atoms are NOT unwrapped
------------------------------------------------------------------------- */
void Group::bounds(int igroup, double *minmax)
{
int groupbit = bitmask[igroup];
double extent[6];
extent[0] = extent[2] = extent[4] = BIG;
extent[1] = extent[3] = extent[5] = -BIG;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
extent[0] = MIN(extent[0],x[i][0]);
extent[1] = MAX(extent[1],x[i][0]);
extent[2] = MIN(extent[2],x[i][1]);
extent[3] = MAX(extent[3],x[i][1]);
extent[4] = MIN(extent[4],x[i][2]);
extent[5] = MAX(extent[5],x[i][2]);
}
}
// compute extent across all procs
// flip sign of MIN to do it in one Allreduce MAX
// set box by extent in shrink-wrapped dims
extent[0] = -extent[0];
extent[2] = -extent[2];
extent[4] = -extent[4];
MPI_Allreduce(extent,minmax,6,MPI_DOUBLE,MPI_MAX,world);
minmax[0] = -minmax[0];
minmax[2] = -minmax[2];
minmax[4] = -minmax[4];
}
/* ----------------------------------------------------------------------
compute the coordinate bounds of the group of atoms in region
periodic images are not considered, so atoms are NOT unwrapped
------------------------------------------------------------------------- */
void Group::bounds(int igroup, double *minmax, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double extent[6];
extent[0] = extent[2] = extent[4] = BIG;
extent[1] = extent[3] = extent[5] = -BIG;
double **x = atom->x;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
extent[0] = MIN(extent[0],x[i][0]);
extent[1] = MAX(extent[1],x[i][0]);
extent[2] = MIN(extent[2],x[i][1]);
extent[3] = MAX(extent[3],x[i][1]);
extent[4] = MIN(extent[4],x[i][2]);
extent[5] = MAX(extent[5],x[i][2]);
}
}
// compute extent across all procs
// flip sign of MIN to do it in one Allreduce MAX
// set box by extent in shrink-wrapped dims
extent[0] = -extent[0];
extent[2] = -extent[2];
extent[4] = -extent[4];
MPI_Allreduce(extent,minmax,6,MPI_DOUBLE,MPI_MAX,world);
minmax[0] = -minmax[0];
minmax[2] = -minmax[2];
minmax[4] = -minmax[4];
}
/* ----------------------------------------------------------------------
compute the center-of-mass coords of group of atoms
masstotal = total mass
return center-of-mass coords in cm[]
must unwrap atoms to compute center-of-mass correctly
------------------------------------------------------------------------- */
void Group::xcm(int igroup, double masstotal, double *cm)
{
int groupbit = bitmask[igroup];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double cmone[3];
cmone[0] = cmone[1] = cmone[2] = 0.0;
double massone;
double unwrap[3];
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
massone = rmass[i];
domain->unmap(x[i],image[i],unwrap);
cmone[0] += unwrap[0] * massone;
cmone[1] += unwrap[1] * massone;
cmone[2] += unwrap[2] * massone;
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
massone = mass[type[i]];
domain->unmap(x[i],image[i],unwrap);
cmone[0] += unwrap[0] * massone;
cmone[1] += unwrap[1] * massone;
cmone[2] += unwrap[2] * massone;
}
}
MPI_Allreduce(cmone,cm,3,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) {
cm[0] /= masstotal;
cm[1] /= masstotal;
cm[2] /= masstotal;
}
}
/* ----------------------------------------------------------------------
compute the center-of-mass coords of group of atoms in region
mastotal = total mass
return center-of-mass coords in cm[]
must unwrap atoms to compute center-of-mass correctly
------------------------------------------------------------------------- */
void Group::xcm(int igroup, double masstotal, double *cm, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double cmone[3];
cmone[0] = cmone[1] = cmone[2] = 0.0;
double massone;
double unwrap[3];
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
massone = rmass[i];
domain->unmap(x[i],image[i],unwrap);
cmone[0] += unwrap[0] * massone;
cmone[1] += unwrap[1] * massone;
cmone[2] += unwrap[2] * massone;
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
massone = mass[type[i]];
domain->unmap(x[i],image[i],unwrap);
cmone[0] += unwrap[0] * massone;
cmone[1] += unwrap[1] * massone;
cmone[2] += unwrap[2] * massone;
}
}
MPI_Allreduce(cmone,cm,3,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) {
cm[0] /= masstotal;
cm[1] /= masstotal;
cm[2] /= masstotal;
}
}
/* ----------------------------------------------------------------------
compute the center-of-mass velocity of group of atoms
masstotal = total mass
return center-of-mass velocity in cm[]
------------------------------------------------------------------------- */
void Group::vcm(int igroup, double masstotal, double *cm)
{
int groupbit = bitmask[igroup];
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double p[3],massone;
p[0] = p[1] = p[2] = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
massone = rmass[i];
p[0] += v[i][0]*massone;
p[1] += v[i][1]*massone;
p[2] += v[i][2]*massone;
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
massone = mass[type[i]];
p[0] += v[i][0]*massone;
p[1] += v[i][1]*massone;
p[2] += v[i][2]*massone;
}
}
MPI_Allreduce(p,cm,3,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) {
cm[0] /= masstotal;
cm[1] /= masstotal;
cm[2] /= masstotal;
}
}
/* ----------------------------------------------------------------------
compute the center-of-mass velocity of group of atoms in region
masstotal = total mass
return center-of-mass velocity in cm[]
------------------------------------------------------------------------- */
void Group::vcm(int igroup, double masstotal, double *cm, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double p[3],massone;
p[0] = p[1] = p[2] = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
massone = rmass[i];
p[0] += v[i][0]*massone;
p[1] += v[i][1]*massone;
p[2] += v[i][2]*massone;
}
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
massone = mass[type[i]];
p[0] += v[i][0]*massone;
p[1] += v[i][1]*massone;
p[2] += v[i][2]*massone;
}
}
MPI_Allreduce(p,cm,3,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) {
cm[0] /= masstotal;
cm[1] /= masstotal;
cm[2] /= masstotal;
}
}
/* ----------------------------------------------------------------------
compute the total force on group of atoms
------------------------------------------------------------------------- */
void Group::fcm(int igroup, double *cm)
{
int groupbit = bitmask[igroup];
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double flocal[3];
flocal[0] = flocal[1] = flocal[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
flocal[0] += f[i][0];
flocal[1] += f[i][1];
flocal[2] += f[i][2];
}
MPI_Allreduce(flocal,cm,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute the total force on group of atoms in region
------------------------------------------------------------------------- */
void Group::fcm(int igroup, double *cm, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double **f = atom->f;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double flocal[3];
flocal[0] = flocal[1] = flocal[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
flocal[0] += f[i][0];
flocal[1] += f[i][1];
flocal[2] += f[i][2];
}
MPI_Allreduce(flocal,cm,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute the total kinetic energy of group of atoms and return it
------------------------------------------------------------------------- */
double Group::ke(int igroup)
{
int groupbit = bitmask[igroup];
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double one = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
mass[type[i]];
}
double all;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
all *= 0.5 * force->mvv2e;
return all;
}
/* ----------------------------------------------------------------------
compute the total kinetic energy of group of atoms in region and return it
------------------------------------------------------------------------- */
double Group::ke(int igroup, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double one = 0.0;
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
mass[type[i]];
}
double all;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
all *= 0.5 * force->mvv2e;
return all;
}
/* ----------------------------------------------------------------------
compute the radius-of-gyration of group of atoms
around center-of-mass cm
must unwrap atoms to compute Rg correctly
------------------------------------------------------------------------- */
double Group::gyration(int igroup, double masstotal, double *cm)
{
int groupbit = bitmask[igroup];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double rg = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
rg += (dx*dx + dy*dy + dz*dz) * massone;
}
double rg_all;
MPI_Allreduce(&rg,&rg_all,1,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) return sqrt(rg_all/masstotal);
return 0.0;
}
/* ----------------------------------------------------------------------
compute the radius-of-gyration of group of atoms in region
around center-of-mass cm
must unwrap atoms to compute Rg correctly
------------------------------------------------------------------------- */
double Group::gyration(int igroup, double masstotal, double *cm, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double rg = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
rg += (dx*dx + dy*dy + dz*dz) * massone;
}
double rg_all;
MPI_Allreduce(&rg,&rg_all,1,MPI_DOUBLE,MPI_SUM,world);
if (masstotal > 0.0) return sqrt(rg_all/masstotal);
return 0.0;
}
/* ----------------------------------------------------------------------
compute the angular momentum L (lmom) of group
around center-of-mass cm
must unwrap atoms to compute L correctly
------------------------------------------------------------------------- */
void Group::angmom(int igroup, double *cm, double *lmom)
{
int groupbit = bitmask[igroup];
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double p[3];
p[0] = p[1] = p[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
p[0] += massone * (dy*v[i][2] - dz*v[i][1]);
p[1] += massone * (dz*v[i][0] - dx*v[i][2]);
p[2] += massone * (dx*v[i][1] - dy*v[i][0]);
}
MPI_Allreduce(p,lmom,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute the angular momentum L (lmom) of group of atoms in region
around center-of-mass cm
must unwrap atoms to compute L correctly
------------------------------------------------------------------------- */
void Group::angmom(int igroup, double *cm, double *lmom, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double p[3];
p[0] = p[1] = p[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
p[0] += massone * (dy*v[i][2] - dz*v[i][1]);
p[1] += massone * (dz*v[i][0] - dx*v[i][2]);
p[2] += massone * (dx*v[i][1] - dy*v[i][0]);
}
MPI_Allreduce(p,lmom,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute the torque T (tq) on group
around center-of-mass cm
must unwrap atoms to compute T correctly
------------------------------------------------------------------------- */
void Group::torque(int igroup, double *cm, double *tq)
{
int groupbit = bitmask[igroup];
double **x = atom->x;
double **f = atom->f;
int *mask = atom->mask;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double dx,dy,dz;
double unwrap[3];
double tlocal[3];
tlocal[0] = tlocal[1] = tlocal[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
tlocal[0] += dy*f[i][2] - dz*f[i][1];
tlocal[1] += dz*f[i][0] - dx*f[i][2];
tlocal[2] += dx*f[i][1] - dy*f[i][0];
}
MPI_Allreduce(tlocal,tq,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute the torque T (tq) on group of atoms in region
around center-of-mass cm
must unwrap atoms to compute T correctly
------------------------------------------------------------------------- */
void Group::torque(int igroup, double *cm, double *tq, int iregion)
{
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
double **f = atom->f;
int *mask = atom->mask;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double dx,dy,dz;
double unwrap[3];
double tlocal[3];
tlocal[0] = tlocal[1] = tlocal[2] = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
tlocal[0] += dy*f[i][2] - dz*f[i][1];
tlocal[1] += dz*f[i][0] - dx*f[i][2];
tlocal[2] += dx*f[i][1] - dy*f[i][0];
}
MPI_Allreduce(tlocal,tq,3,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute moment of inertia tensor around center-of-mass cm of group
must unwrap atoms to compute itensor correctly
------------------------------------------------------------------------- */
void Group::inertia(int igroup, double *cm, double itensor[3][3])
{
int i,j;
int groupbit = bitmask[igroup];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double ione[3][3];
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
ione[i][j] = 0.0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
ione[0][0] += massone * (dy*dy + dz*dz);
ione[1][1] += massone * (dx*dx + dz*dz);
ione[2][2] += massone * (dx*dx + dy*dy);
ione[0][1] -= massone * dx*dy;
ione[1][2] -= massone * dy*dz;
ione[0][2] -= massone * dx*dz;
}
ione[1][0] = ione[0][1];
ione[2][1] = ione[1][2];
ione[2][0] = ione[0][2];
MPI_Allreduce(&ione[0][0],&itensor[0][0],9,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute moment of inertia tensor around cm of group of atoms in region
must unwrap atoms to compute itensor correctly
------------------------------------------------------------------------- */
void Group::inertia(int igroup, double *cm, double itensor[3][3], int iregion)
{
int i,j;
int groupbit = bitmask[igroup];
Region *region = domain->regions[iregion];
double **x = atom->x;
int *mask = atom->mask;
int *type = atom->type;
imageint *image = atom->image;
double *mass = atom->mass;
double *rmass = atom->rmass;
int nlocal = atom->nlocal;
double dx,dy,dz,massone;
double unwrap[3];
double ione[3][3];
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
ione[i][j] = 0.0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2])) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
ione[0][0] += massone * (dy*dy + dz*dz);
ione[1][1] += massone * (dx*dx + dz*dz);
ione[2][2] += massone * (dx*dx + dy*dy);
ione[0][1] -= massone * dx*dy;
ione[1][2] -= massone * dy*dz;
ione[0][2] -= massone * dx*dz;
}
ione[1][0] = ione[0][1];
ione[2][1] = ione[1][2];
ione[2][0] = ione[0][2];
MPI_Allreduce(&ione[0][0],&itensor[0][0],9,MPI_DOUBLE,MPI_SUM,world);
}
/* ----------------------------------------------------------------------
compute angular velocity omega from L = Iw, inverting I to solve for w
really not a group operation, but L and I were computed for a group
------------------------------------------------------------------------- */
void Group::omega(double *angmom, double inertia[3][3], double *w)
{
double inverse[3][3];
inverse[0][0] = inertia[1][1]*inertia[2][2] - inertia[1][2]*inertia[2][1];
inverse[0][1] = -(inertia[0][1]*inertia[2][2] - inertia[0][2]*inertia[2][1]);
inverse[0][2] = inertia[0][1]*inertia[1][2] - inertia[0][2]*inertia[1][1];
inverse[1][0] = -(inertia[1][0]*inertia[2][2] - inertia[1][2]*inertia[2][0]);
inverse[1][1] = inertia[0][0]*inertia[2][2] - inertia[0][2]*inertia[2][0];
inverse[1][2] = -(inertia[0][0]*inertia[1][2] - inertia[0][2]*inertia[1][0]);
inverse[2][0] = inertia[1][0]*inertia[2][1] - inertia[1][1]*inertia[2][0];
inverse[2][1] = -(inertia[0][0]*inertia[2][1] - inertia[0][1]*inertia[2][0]);
inverse[2][2] = inertia[0][0]*inertia[1][1] - inertia[0][1]*inertia[1][0];
double determinant = inertia[0][0]*inertia[1][1]*inertia[2][2] +
inertia[0][1]*inertia[1][2]*inertia[2][0] +
inertia[0][2]*inertia[1][0]*inertia[2][1] -
inertia[0][0]*inertia[1][2]*inertia[2][1] -
inertia[0][1]*inertia[1][0]*inertia[2][2] -
inertia[2][0]*inertia[1][1]*inertia[0][2];
if (determinant > 0.0)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
inverse[i][j] /= determinant;
w[0] = inverse[0][0]*angmom[0] + inverse[0][1]*angmom[1] +
inverse[0][2]*angmom[2];
w[1] = inverse[1][0]*angmom[0] + inverse[1][1]*angmom[1] +
inverse[1][2]*angmom[2];
w[2] = inverse[2][0]*angmom[0] + inverse[2][1]*angmom[1] +
inverse[2][2]*angmom[2];
}
diff --git a/src/lammps.cpp b/src/lammps.cpp
index 69034f97b..ae44e92f1 100644
--- a/src/lammps.cpp
+++ b/src/lammps.cpp
@@ -1,852 +1,852 @@
/* ----------------------------------------------------------------------
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 "lammps.h"
#include "style_angle.h"
#include "style_atom.h"
#include "style_bond.h"
#include "style_command.h"
#include "style_compute.h"
#include "style_dihedral.h"
#include "style_dump.h"
#include "style_fix.h"
#include "style_improper.h"
#include "style_integrate.h"
#include "style_kspace.h"
#include "style_minimize.h"
#include "style_pair.h"
#include "style_region.h"
#include "universe.h"
#include "input.h"
#include "atom.h"
#include "update.h"
#include "neighbor.h"
#include "comm.h"
#include "domain.h"
#include "force.h"
#include "modify.h"
#include "group.h"
#include "output.h"
#include "citeme.h"
#include "accelerator_cuda.h"
#include "accelerator_omp.h"
#include "timer.h"
#include "memory.h"
#include "error.h"
#include "version.h"
#include <stdlib.h>
using namespace LAMMPS_NS;
// for help flag output
static void help_message(FILE *);
static void print_columns(const char **, const int, FILE *);
/* ----------------------------------------------------------------------
start up LAMMPS
allocate fundamental classes (memory, error, universe, input)
parse input switches
initialize communicators, screen & logfile output
input is allocated at end after MPI info is setup
------------------------------------------------------------------------- */
LAMMPS::LAMMPS(int narg, char **arg, MPI_Comm communicator)
{
memory = new Memory(this);
error = new Error(this);
universe = new Universe(this,communicator);
output = NULL;
screen = NULL;
logfile = NULL;
infile = NULL;
// parse input switches
int inflag = 0;
int screenflag = 0;
int logflag = 0;
int partscreenflag = 0;
int partlogflag = 0;
int cudaflag = -1;
int restartflag = 0;
int citeflag = 1;
int helpflag = 0;
suffix = NULL;
suffix_enable = 0;
char *rfile = NULL;
char *dfile = NULL;
int wdfirst,wdlast;
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"-partition") == 0 ||
strcmp(arg[iarg],"-p") == 0) {
universe->existflag = 1;
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
iarg++;
while (iarg < narg && arg[iarg][0] != '-') {
universe->add_world(arg[iarg]);
iarg++;
}
} else if (strcmp(arg[iarg],"-in") == 0 ||
strcmp(arg[iarg],"-i") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
inflag = iarg + 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-screen") == 0 ||
strcmp(arg[iarg],"-sc") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
screenflag = iarg + 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-log") == 0 ||
strcmp(arg[iarg],"-l") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
logflag = iarg + 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-var") == 0 ||
strcmp(arg[iarg],"-v") == 0) {
if (iarg+3 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
iarg += 3;
while (iarg < narg && arg[iarg][0] != '-') iarg++;
} else if (strcmp(arg[iarg],"-echo") == 0 ||
strcmp(arg[iarg],"-e") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
iarg += 2;
} else if (strcmp(arg[iarg],"-pscreen") == 0 ||
strcmp(arg[iarg],"-ps") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
partscreenflag = iarg + 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-plog") == 0 ||
strcmp(arg[iarg],"-pl") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
partlogflag = iarg + 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-cuda") == 0 ||
strcmp(arg[iarg],"-c") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
if (strcmp(arg[iarg+1],"on") == 0) cudaflag = 1;
else if (strcmp(arg[iarg+1],"off") == 0) cudaflag = 0;
else error->universe_all(FLERR,"Invalid command-line argument");
iarg += 2;
} else if (strcmp(arg[iarg],"-suffix") == 0 ||
strcmp(arg[iarg],"-sf") == 0) {
if (iarg+2 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
delete [] suffix;
int n = strlen(arg[iarg+1]) + 1;
suffix = new char[n];
strcpy(suffix,arg[iarg+1]);
suffix_enable = 1;
iarg += 2;
} else if (strcmp(arg[iarg],"-reorder") == 0 ||
strcmp(arg[iarg],"-ro") == 0) {
if (iarg+3 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
if (universe->existflag)
error->universe_all(FLERR,"Cannot use -reorder after -partition");
universe->reorder(arg[iarg+1],arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"-restart") == 0 ||
strcmp(arg[iarg],"-r") == 0) {
if (iarg+3 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
restartflag = 1;
rfile = arg[iarg+1];
dfile = arg[iarg+2];
iarg += 3;
// delimit any extra args for the write_data command
wdfirst = iarg;
while (iarg < narg && arg[iarg][0] != '-') iarg++;
wdlast = iarg;
} else if (strcmp(arg[iarg],"-nocite") == 0 ||
strcmp(arg[iarg],"-nc") == 0) {
citeflag = 0;
iarg++;
} else if (strcmp(arg[iarg],"-help") == 0 ||
strcmp(arg[iarg],"-h") == 0) {
if (iarg+1 > narg)
error->universe_all(FLERR,"Invalid command-line argument");
helpflag = 1;
citeflag = 0;
iarg += 1;
} else error->universe_all(FLERR,"Invalid command-line argument");
}
// if no partition command-line switch, universe is one world with all procs
if (universe->existflag == 0) universe->add_world(NULL);
// sum of procs in all worlds must equal total # of procs
if (!universe->consistent())
error->universe_all(FLERR,"Processor partitions are inconsistent");
// universe cannot use stdin for input file
if (universe->existflag && inflag == 0)
error->universe_all(FLERR,"Must use -in switch with multiple partitions");
// if no partition command-line switch, cannot use -pscreen option
if (universe->existflag == 0 && partscreenflag)
error->universe_all(FLERR,"Can only use -pscreen with multiple partitions");
// if no partition command-line switch, cannot use -plog option
if (universe->existflag == 0 && partlogflag)
error->universe_all(FLERR,"Can only use -plog with multiple partitions");
// set universe screen and logfile
if (universe->me == 0) {
if (screenflag == 0)
universe->uscreen = stdout;
else if (strcmp(arg[screenflag],"none") == 0)
universe->uscreen = NULL;
else {
universe->uscreen = fopen(arg[screenflag],"w");
if (universe->uscreen == NULL)
error->universe_one(FLERR,"Cannot open universe screen file");
}
if (logflag == 0) {
if (helpflag == 0) {
universe->ulogfile = fopen("log.lammps","w");
if (universe->ulogfile == NULL)
error->universe_warn(FLERR,"Cannot open log.lammps for writing");
}
} else if (strcmp(arg[logflag],"none") == 0)
universe->ulogfile = NULL;
else {
universe->ulogfile = fopen(arg[logflag],"w");
if (universe->ulogfile == NULL)
error->universe_one(FLERR,"Cannot open universe log file");
}
}
if (universe->me > 0) {
if (screenflag == 0) universe->uscreen = stdout;
else universe->uscreen = NULL;
universe->ulogfile = NULL;
}
// make universe and single world the same, since no partition switch
// world inherits settings from universe
// set world screen, logfile, communicator, infile
// open input script if from file
if (universe->existflag == 0) {
screen = universe->uscreen;
logfile = universe->ulogfile;
world = universe->uworld;
if (universe->me == 0) {
if (inflag == 0) infile = stdin;
else infile = fopen(arg[inflag],"r");
if (infile == NULL) {
char str[128];
sprintf(str,"Cannot open input script %s",arg[inflag]);
error->one(FLERR,str);
}
}
if (universe->me == 0) {
if (screen) fprintf(screen,"LAMMPS (%s)\n",universe->version);
if (logfile) fprintf(logfile,"LAMMPS (%s)\n",universe->version);
}
// universe is one or more worlds, as setup by partition switch
// split universe communicator into separate world communicators
// set world screen, logfile, communicator, infile
// open input script
} else {
int me;
MPI_Comm_split(universe->uworld,universe->iworld,0,&world);
MPI_Comm_rank(world,&me);
if (me == 0)
if (partscreenflag == 0)
if (screenflag == 0) {
char str[32];
sprintf(str,"screen.%d",universe->iworld);
screen = fopen(str,"w");
if (screen == NULL) error->one(FLERR,"Cannot open screen file");
} else if (strcmp(arg[screenflag],"none") == 0)
screen = NULL;
else {
char str[128];
sprintf(str,"%s.%d",arg[screenflag],universe->iworld);
screen = fopen(str,"w");
if (screen == NULL) error->one(FLERR,"Cannot open screen file");
}
else if (strcmp(arg[partscreenflag],"none") == 0)
screen = NULL;
else {
char str[128];
sprintf(str,"%s.%d",arg[partscreenflag],universe->iworld);
screen = fopen(str,"w");
if (screen == NULL) error->one(FLERR,"Cannot open screen file");
} else screen = NULL;
if (me == 0)
if (partlogflag == 0)
if (logflag == 0) {
char str[32];
sprintf(str,"log.lammps.%d",universe->iworld);
logfile = fopen(str,"w");
if (logfile == NULL) error->one(FLERR,"Cannot open logfile");
} else if (strcmp(arg[logflag],"none") == 0)
logfile = NULL;
else {
char str[128];
sprintf(str,"%s.%d",arg[logflag],universe->iworld);
logfile = fopen(str,"w");
if (logfile == NULL) error->one(FLERR,"Cannot open logfile");
}
else if (strcmp(arg[partlogflag],"none") == 0)
logfile = NULL;
else {
char str[128];
sprintf(str,"%s.%d",arg[partlogflag],universe->iworld);
logfile = fopen(str,"w");
if (logfile == NULL) error->one(FLERR,"Cannot open logfile");
} else logfile = NULL;
if (me == 0) {
infile = fopen(arg[inflag],"r");
if (infile == NULL) {
char str[128];
sprintf(str,"Cannot open input script %s",arg[inflag]);
error->one(FLERR,str);
}
} else infile = NULL;
// screen and logfile messages for universe and world
if (universe->me == 0) {
if (universe->uscreen) {
fprintf(universe->uscreen,"LAMMPS (%s)\n",universe->version);
fprintf(universe->uscreen,"Running on %d partitions of processors\n",
universe->nworlds);
}
if (universe->ulogfile) {
fprintf(universe->ulogfile,"LAMMPS (%s)\n",universe->version);
fprintf(universe->ulogfile,"Running on %d partitions of processors\n",
universe->nworlds);
}
}
if (me == 0) {
if (screen) {
fprintf(screen,"LAMMPS (%s)\n",universe->version);
fprintf(screen,"Processor partition = %d\n",universe->iworld);
}
if (logfile) {
fprintf(logfile,"LAMMPS (%s)\n",universe->version);
fprintf(logfile,"Processor partition = %d\n",universe->iworld);
}
}
}
// check datatype settings in lmptype.h
if (sizeof(smallint) != sizeof(int))
error->all(FLERR,"Smallint setting in lmptype.h is invalid");
if (sizeof(imageint) < sizeof(smallint))
error->all(FLERR,"Imageint setting in lmptype.h is invalid");
if (sizeof(tagint) < sizeof(smallint))
error->all(FLERR,"Tagint setting in lmptype.h is invalid");
- if (sizeof(bigint) < sizeof(tagint))
+ if (sizeof(bigint) < sizeof(imageint) || sizeof(bigint) < sizeof(tagint))
error->all(FLERR,"Bigint setting in lmptype.h is invalid");
int mpisize;
MPI_Type_size(MPI_LMP_BIGINT,&mpisize);
if (mpisize != sizeof(bigint))
error->all(FLERR,"MPI_LMP_BIGINT and bigint in "
"lmptype.h are not compatible");
#ifdef LAMMPS_SMALLBIG
if (sizeof(smallint) != 4 || sizeof(imageint) != 4 ||
sizeof(tagint) != 4 || sizeof(bigint) != 8)
- error->all(FLERR,"Small, tag, big integers are not sized correctly");
+ error->all(FLERR,"Small to big integers are not sized correctly");
#endif
#ifdef LAMMPS_BIGBIG
if (sizeof(smallint) != 4 || sizeof(imageint) != 8 ||
sizeof(tagint) != 8 || sizeof(bigint) != 8)
- error->all(FLERR,"Small, tag, big integers are not sized correctly");
+ error->all(FLERR,"Small to big integers are not sized correctly");
#endif
#ifdef LAMMPS_SMALLSMALL
if (sizeof(smallint) != 4 || sizeof(imageint) != 4 ||
sizeof(tagint) != 4 || sizeof(bigint) != 4)
- error->all(FLERR,"Small, tag, big integers are not sized correctly");
+ error->all(FLERR,"Small to big integers are not sized correctly");
#endif
// create CUDA class if USER-CUDA installed, unless explicitly switched off
// instantiation creates dummy CUDA class if USER-CUDA is not installed
if (cudaflag == 0) {
cuda = NULL;
} else if (cudaflag == 1) {
cuda = new Cuda(this);
if (!cuda->cuda_exists)
error->all(FLERR,"Cannot use -cuda on without USER-CUDA installed");
} else {
cuda = new Cuda(this);
if (!cuda->cuda_exists) {
delete cuda;
cuda = NULL;
}
}
int me;
MPI_Comm_rank(world,&me);
if (cuda && me == 0) error->message(FLERR,"USER-CUDA mode is enabled");
// allocate CiteMe class if enabled
if (citeflag) citeme = new CiteMe(this);
else citeme = NULL;
// allocate input class now that MPI is fully setup
input = new Input(this,narg,arg);
// allocate top-level classes
create();
post_create();
// if helpflag set, print help and quit
if (helpflag) {
if (universe->me == 0) help_message(screen);
error->done();
}
// if restartflag set, process 2 command and quit
// add args between wdfirst and wdlast to write_data
// also add "noinit" to prevent write_data from doing system init
if (restartflag) {
char cmd[128];
sprintf(cmd,"read_restart %s\n",rfile);
input->one(cmd);
sprintf(cmd,"write_data %s",dfile);
for (iarg = wdfirst; iarg < wdlast; iarg++)
sprintf(&cmd[strlen(cmd)]," %s",arg[iarg]);
strcat(cmd," noinit\n");
input->one(cmd);
error->done();
}
}
/* ----------------------------------------------------------------------
shutdown LAMMPS
delete top-level classes
close screen and log files in world and universe
output files were already closed in destroy()
delete fundamental classes
------------------------------------------------------------------------- */
LAMMPS::~LAMMPS()
{
destroy();
delete citeme;
if (universe->nworlds == 1) {
if (screen && screen != stdout) fclose(screen);
if (logfile) fclose(logfile);
logfile = NULL;
if (screen != stdout) screen = NULL;
} else {
if (screen && screen != stdout) fclose(screen);
if (logfile) fclose(logfile);
if (universe->ulogfile) fclose(universe->ulogfile);
logfile = NULL;
if (screen != stdout) screen = NULL;
}
if (infile && infile != stdin) fclose(infile);
if (world != universe->uworld) MPI_Comm_free(&world);
delete cuda;
delete [] suffix;
delete input;
delete universe;
delete error;
delete memory;
}
/* ----------------------------------------------------------------------
allocate single instance of top-level classes
fundamental classes are allocated in constructor
some classes have package variants
------------------------------------------------------------------------- */
void LAMMPS::create()
{
// Comm class must be created before Atom class
// so that nthreads is defined when create_avec invokes grow()
if (cuda) comm = new CommCuda(this);
else comm = new Comm(this);
if (cuda) neighbor = new NeighborCuda(this);
else neighbor = new Neighbor(this);
if (cuda) domain = new DomainCuda(this);
#ifdef LMP_USER_OMP
else domain = new DomainOMP(this);
#else
else domain = new Domain(this);
#endif
atom = new Atom(this);
atom->create_avec("atomic",0,NULL,suffix);
group = new Group(this);
force = new Force(this); // must be after group, to create temperature
if (cuda) modify = new ModifyCuda(this);
else modify = new Modify(this);
output = new Output(this); // must be after group, so "all" exists
// must be after modify so can create Computes
update = new Update(this); // must be after output, force, neighbor
timer = new Timer(this);
}
/* ----------------------------------------------------------------------
invoke package-specific setup commands
called from LAMMPS constructor and after clear() command
only invoke if suffix is set and enabled
------------------------------------------------------------------------- */
void LAMMPS::post_create()
{
if (suffix && suffix_enable) {
if (strcmp(suffix,"gpu") == 0) input->one("package gpu force/neigh 0 0 1");
if (strcmp(suffix,"omp") == 0) input->one("package omp *");
}
}
/* ----------------------------------------------------------------------
initialize top-level classes
do not initialize Timer class, other classes like Run() do that explicitly
------------------------------------------------------------------------- */
void LAMMPS::init()
{
if (cuda) cuda->accelerator(0,NULL);
update->init();
force->init(); // pair must come after update due to minimizer
domain->init();
atom->init(); // atom must come after force and domain
// atom deletes extra array
// used by fix shear_history::unpack_restart()
// when force->pair->gran_history creates fix ??
// atom_vec init uses deform_vremap
modify->init(); // modify must come after update, force, atom, domain
neighbor->init(); // neighbor must come after force, modify
comm->init(); // comm must come after force, modify, neighbor, atom
output->init(); // output must come after domain, force, modify
}
/* ----------------------------------------------------------------------
delete single instance of top-level classes
fundamental classes are deleted in destructor
------------------------------------------------------------------------- */
void LAMMPS::destroy()
{
delete update;
delete neighbor;
delete comm;
delete force;
delete group;
delete output;
delete modify; // modify must come after output, force, update
// since they delete fixes
delete domain; // domain must come after modify
// since fix destructors access domain
delete atom; // atom must come after modify, neighbor
// since fixes delete callbacks in atom
delete timer;
modify = NULL; // necessary since input->variable->varreader
// will be destructed later
}
/* ----------------------------------------------------------------------
for each style, print name of all child classes built into executable
------------------------------------------------------------------------- */
void help_message(FILE *fp)
{
const int nmax = 500;
const char *pager = NULL;
const char **styles = new const char *[nmax];
if (fp == NULL) return;
// if output is stdout, use pipe to pager
if (fp == stdout) {
pager = getenv("PAGER");
if (pager == NULL) pager = "more";
#if defined(_WIN32)
fp = _popen(pager,"w");
#else
fp = popen(pager,"w");
#endif
// reset to original state, if pipe command fails
if (fp == NULL) {
fp = stdout;
pager = NULL;
}
}
// general help message about command line and flags
fputs("\nLarge-scale Atomic/Molecular Massively Parallel Simulator - "
LAMMPS_VERSION "-ICMS\n\n"
"Usage example: lmp_g++ -v t 300 -log none -nc "
"-echo screen -in in.alloy\n\n",fp);
fputs("List of command line options supported by this LAMMPS executable:\n"
" -cuda on/off : turn CUDA mode on or off (-c)\n"
" -echo none/screen/log/both : select how to echo input (-e)\n"
" -in <filename> : read input from file not stdin (-i)\n"
" -help : print this help message (-h)\n"
" -log none/<filename> : where to send log output (-l)\n"
" -nocite : disable writing log.cite file (-nc)\n"
" -partition <partition size> : assign partition sizes (-p)\n"
" -plog <basename> : basename for partition logs (-pl)\n"
" -pscreen <basename> : basename for partition screens (-ps)\n"
" -restart <restart> <datafile>: convert restart to data file (-r)\n"
" -reorder <topology specs> : processor reordering (-ro)\n"
" -screen none/<filename> : where to send screen output (-sc)\n"
" -suffix cuda/gpu/opt/omp : style suffix to apply (-sf)\n"
" -var <varname> <value> : set index style variable (-v)\n",fp);
fputs("\nList of style options included in this LAMMPS executable:\n\n",fp);
fputs("* Atom styles:",fp);
int n=0;
#define ATOM_CLASS
#define AtomStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_atom.h"
#undef ATOM_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Integrate styles:",fp);
n=0;
#define INTEGRATE_CLASS
#define IntegrateStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_integrate.h"
#undef INTEGRATE_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Minimize styles:",fp);
n=0;
#define MINIMIZE_CLASS
#define MinimizeStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_minimize.h"
#undef MINIMIZE_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Pair styles:",fp);
n=0;
#define PAIR_CLASS
#define PairStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_pair.h"
#undef PAIR_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Bond styles:",fp);
n=0;
#define BOND_CLASS
#define BondStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_bond.h"
#undef BOND_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Angle styles:",fp);
n=0;
#define ANGLE_CLASS
#define AngleStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_angle.h"
#undef ANGLE_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Dihedral styles:",fp);
n=0;
#define DIHEDRAL_CLASS
#define DihedralStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_dihedral.h"
#undef DIHEDRAL_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Improper styles:",fp);
n=0;
#define IMPROPER_CLASS
#define ImproperStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_improper.h"
#undef IMPROPER_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* KSpace styles:",fp);
n=0;
#define KSPACE_CLASS
#define KSpaceStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_kspace.h"
#undef KSPACE_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Fix styles:",fp);
n=0;
#define FIX_CLASS
#define FixStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_fix.h"
#undef FIX_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Compute styles:",fp);
n=0;
#define COMPUTE_CLASS
#define ComputeStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_compute.h"
#undef COMPUTE_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Region styles:",fp);
n=0;
#define REGION_CLASS
#define RegionStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_region.h"
#undef REGION_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Dump styles:",fp);
n=0;
#define DUMP_CLASS
#define DumpStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_dump.h"
#undef DUMP_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
fputs("* Command styles (add-on input script commands):",fp);
n=0;
#define COMMAND_CLASS
#define CommandStyle(key,Class) if (n<nmax) {styles[n]=#key; ++n;}
#include "style_command.h"
#undef COMMAND_CLASS
print_columns(styles,n,fp);
if (n==nmax) fputs("\nWARNING: not showing all styles. Increase nmax.",fp);
fputs("\n\n",fp);
delete[] styles;
// wait for pager, if active
if (pager != NULL) pclose(fp);
}
/* ----------------------------------------------------------------------
sort and format the -h style name output
------------------------------------------------------------------------- */
static int cmpstringp(const void *p1, const void *p2)
{
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
static void print_columns(const char **styles, const int num, FILE *fp)
{
int len,i;
qsort(styles,num,sizeof(const char *),&cmpstringp);
int pos = 80;
for (i = 0; i < num; ++i) {
// skip "secret" styles
if (isupper(styles[i][0])) continue;
len = strlen(styles[i]);
if (pos + len > 80) {
fprintf(fp,"\n");
pos = 0;
}
if (len < 16) {
fprintf(fp,"%-16s",styles[i]);
pos += 16;
} else if (len < 32) {
fprintf(fp,"%-32s",styles[i]);
pos += 32;
} else if (len < 48) {
fprintf(fp,"%-48s",styles[i]);
pos += 48;
} else if (len < 64) {
fprintf(fp,"%-64s",styles[i]);
pos += 64;
} else {
fprintf(fp,"%-80s",styles[i]);
pos += 80;
}
}
}
diff --git a/src/library.cpp b/src/library.cpp
index 2e2823244..60b07548d 100644
--- a/src/library.cpp
+++ b/src/library.cpp
@@ -1,534 +1,534 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
// C or Fortran style library interface to LAMMPS
// customize by adding new LAMMPS-specific functions
#include "lmptype.h"
#include "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "library.h"
#include "lammps.h"
#include "input.h"
#include "atom.h"
#include "domain.h"
#include "update.h"
#include "group.h"
#include "input.h"
#include "variable.h"
#include "modify.h"
#include "compute.h"
#include "fix.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
create an instance of LAMMPS and return pointer to it
pass in command-line args and MPI communicator to run on
------------------------------------------------------------------------- */
void lammps_open(int argc, char **argv, MPI_Comm communicator, void **ptr)
{
LAMMPS *lmp = new LAMMPS(argc,argv,communicator);
*ptr = (void *) lmp;
}
/* ----------------------------------------------------------------------
create an instance of LAMMPS and return pointer to it
caller doesn't know MPI communicator, so use MPI_COMM_WORLD
intialize MPI if needed
------------------------------------------------------------------------- */
void lammps_open_no_mpi(int argc, char **argv, void **ptr)
{
int flag;
MPI_Initialized(&flag);
if (!flag) {
int argc = 0;
char **argv = NULL;
MPI_Init(&argc,&argv);
}
MPI_Comm communicator = MPI_COMM_WORLD;
LAMMPS *lmp = new LAMMPS(argc,argv,communicator);
*ptr = (void *) lmp;
}
/* ----------------------------------------------------------------------
destruct an instance of LAMMPS
------------------------------------------------------------------------- */
void lammps_close(void *ptr)
{
LAMMPS *lmp = (LAMMPS *) ptr;
delete lmp;
}
/* ----------------------------------------------------------------------
process an input script in filename str
------------------------------------------------------------------------- */
void lammps_file(void *ptr, char *str)
{
LAMMPS *lmp = (LAMMPS *) ptr;
lmp->input->file(str);
}
/* ----------------------------------------------------------------------
process a single input command in str
------------------------------------------------------------------------- */
char *lammps_command(void *ptr, char *str)
{
LAMMPS *lmp = (LAMMPS *) ptr;
return lmp->input->one(str);
}
/* ----------------------------------------------------------------------
clean-up function to free memory allocated by lib and returned to caller
------------------------------------------------------------------------- */
void lammps_free(void *ptr)
{
free(ptr);
}
/* ----------------------------------------------------------------------
add LAMMPS-specific library functions
all must receive LAMMPS pointer as argument
customize by adding a function here and in library.h header file
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
extract a pointer to an internal LAMMPS global entity
name = desired quantity, e.g. dt or boxyhi or natoms
returns a void pointer to the entity
which the caller can cast to the proper data type
returns a NULL if name not listed below
customize by adding names
------------------------------------------------------------------------- */
void *lammps_extract_global(void *ptr, char *name)
{
LAMMPS *lmp = (LAMMPS *) ptr;
if (strcmp(name,"dt") == 0) return (void *) &lmp->update->dt;
if (strcmp(name,"boxxlo") == 0) return (void *) &lmp->domain->boxlo[0];
if (strcmp(name,"boxxhi") == 0) return (void *) &lmp->domain->boxhi[0];
if (strcmp(name,"boxylo") == 0) return (void *) &lmp->domain->boxlo[1];
if (strcmp(name,"boxyhi") == 0) return (void *) &lmp->domain->boxhi[1];
if (strcmp(name,"boxzlo") == 0) return (void *) &lmp->domain->boxlo[2];
if (strcmp(name,"boxzhi") == 0) return (void *) &lmp->domain->boxhi[2];
if (strcmp(name,"natoms") == 0) return (void *) &lmp->atom->natoms;
if (strcmp(name,"nlocal") == 0) return (void *) &lmp->atom->nlocal;
return NULL;
}
/* ----------------------------------------------------------------------
extract a pointer to an internal LAMMPS atom-based entity
name = desired quantity, e.g. x or mass
returns a void pointer to the entity
which the caller can cast to the proper data type
returns a NULL if Atom::extract() does not recognize the name
customize by adding names to Atom::extract()
------------------------------------------------------------------------- */
void *lammps_extract_atom(void *ptr, char *name)
{
LAMMPS *lmp = (LAMMPS *) ptr;
return lmp->atom->extract(name);
}
/* ----------------------------------------------------------------------
extract a pointer to an internal LAMMPS compute-based entity
id = compute ID
style = 0 for global data, 1 for per-atom data, 2 for local data
type = 0 for scalar, 1 for vector, 2 for array
for global data, returns a pointer to the
compute's internal data structure for the entity
caller should cast it to (double *) for a scalar or vector
caller should cast it to (double **) for an array
for per-atom or local data, returns a pointer to the
compute's internal data structure for the entity
caller should cast it to (double *) for a vector
caller should cast it to (double **) for an array
returns a void pointer to the compute's internal data structure
for the entity which the caller can cast to the proper data type
returns a NULL if id is not recognized or style/type not supported
IMPORTANT: if the compute is not current it will be invoked
LAMMPS cannot easily check here if it is valid to invoke the compute,
so caller must insure that it is OK
------------------------------------------------------------------------- */
void *lammps_extract_compute(void *ptr, char *id, int style, int type)
{
LAMMPS *lmp = (LAMMPS *) ptr;
int icompute = lmp->modify->find_compute(id);
if (icompute < 0) return NULL;
Compute *compute = lmp->modify->compute[icompute];
if (style == 0) {
if (type == 0) {
if (!compute->scalar_flag) return NULL;
if (compute->invoked_scalar != lmp->update->ntimestep)
compute->compute_scalar();
return (void *) &compute->scalar;
}
if (type == 1) {
if (!compute->vector_flag) return NULL;
if (compute->invoked_vector != lmp->update->ntimestep)
compute->compute_vector();
return (void *) compute->vector;
}
if (type == 2) {
if (!compute->array_flag) return NULL;
if (compute->invoked_array != lmp->update->ntimestep)
compute->compute_array();
return (void *) compute->array;
}
}
if (style == 1) {
if (!compute->peratom_flag) return NULL;
if (type == 1) {
if (compute->invoked_peratom != lmp->update->ntimestep)
compute->compute_peratom();
return (void *) compute->vector_atom;
}
if (type == 2) {
if (compute->invoked_peratom != lmp->update->ntimestep)
compute->compute_peratom();
return (void *) compute->array_atom;
}
}
if (style == 2) {
if (!compute->local_flag) return NULL;
if (type == 1) {
if (compute->invoked_local != lmp->update->ntimestep)
compute->compute_local();
return (void *) compute->vector_local;
}
if (type == 2) {
if (compute->invoked_local != lmp->update->ntimestep)
compute->compute_local();
return (void *) compute->array_local;
}
}
return NULL;
}
/* ----------------------------------------------------------------------
extract a pointer to an internal LAMMPS fix-based entity
id = fix ID
style = 0 for global data, 1 for per-atom data, 2 for local data
type = 0 for scalar, 1 for vector, 2 for array
i,j = indices needed only to specify which global vector or array value
for global data, returns a pointer to a memory location
which is allocated by this function
which the caller can cast to a (double *) which points to the value
for per-atom or local data, returns a pointer to the
fix's internal data structure for the entity
caller should cast it to (double *) for a vector
caller should cast it to (double **) for an array
returns a NULL if id is not recognized or style/type not supported
IMPORTANT: for global data,
this function allocates a double to store the value in,
so the caller must free this memory to avoid a leak, e.g.
double *dptr = (double *) lammps_extract_fix();
double value = *dptr;
free(dptr);
IMPORTANT: LAMMPS cannot easily check here when info extracted from
the fix is valid, so caller must insure that it is OK
------------------------------------------------------------------------- */
void *lammps_extract_fix(void *ptr, char *id, int style, int type,
int i, int j)
{
LAMMPS *lmp = (LAMMPS *) ptr;
int ifix = lmp->modify->find_fix(id);
if (ifix < 0) return NULL;
Fix *fix = lmp->modify->fix[ifix];
if (style == 0) {
double *dptr = (double *) malloc(sizeof(double));
if (type == 0) {
if (!fix->scalar_flag) return NULL;
*dptr = fix->compute_scalar();
return (void *) dptr;
}
if (type == 1) {
if (!fix->vector_flag) return NULL;
*dptr = fix->compute_vector(i);
return (void *) dptr;
}
if (type == 2) {
if (!fix->array_flag) return NULL;
*dptr = fix->compute_array(i,j);
return (void *) dptr;
}
}
if (style == 1) {
if (!fix->peratom_flag) return NULL;
if (type == 1) return (void *) fix->vector_atom;
if (type == 2) return (void *) fix->array_atom;
}
if (style == 2) {
if (!fix->local_flag) return NULL;
if (type == 1) return (void *) fix->vector_local;
if (type == 2) return (void *) fix->array_local;
}
return NULL;
}
/* ----------------------------------------------------------------------
extract a pointer to an internal LAMMPS evaluated variable
name = variable name, must be equal-style or atom-style variable
group = group ID for evaluating an atom-style variable, else NULL
for equal-style variable, returns a pointer to a memory location
which is allocated by this function
which the caller can cast to a (double *) which points to the value
for atom-style variable, returns a pointer to the
vector of per-atom values on each processor,
which the caller can cast to a (double *) which points to the values
returns a NULL if name is not recognized or not equal-style or atom-style
IMPORTANT: for both equal-style and atom-style variables,
this function allocates memory to store the variable data in
so the caller must free this memory to avoid a leak
e.g. for equal-style variables
double *dptr = (double *) lammps_extract_variable();
double value = *dptr;
free(dptr);
e.g. for atom-style variables
double *vector = (double *) lammps_extract_variable();
use the vector values
free(vector);
IMPORTANT: LAMMPS cannot easily check here when it is valid to evaluate
the variable or any fixes or computes or thermodynamic info it references,
so caller must insure that it is OK
------------------------------------------------------------------------- */
void *lammps_extract_variable(void *ptr, char *name, char *group)
{
LAMMPS *lmp = (LAMMPS *) ptr;
int ivar = lmp->input->variable->find(name);
if (ivar < 0) return NULL;
if (lmp->input->variable->equalstyle(ivar)) {
double *dptr = (double *) malloc(sizeof(double));
*dptr = lmp->input->variable->compute_equal(ivar);
return (void *) dptr;
}
if (lmp->input->variable->atomstyle(ivar)) {
int igroup = lmp->group->find(group);
if (igroup < 0) return NULL;
int nlocal = lmp->atom->nlocal;
double *vector = (double *) malloc(nlocal*sizeof(double));
lmp->input->variable->compute_atom(ivar,igroup,vector,1,0);
return (void *) vector;
}
return NULL;
}
/* ----------------------------------------------------------------------
return the total number of atoms in the system
useful before call to lammps_get_atoms() so can pre-allocate vector
------------------------------------------------------------------------- */
int lammps_get_natoms(void *ptr)
{
LAMMPS *lmp = (LAMMPS *) ptr;
if (lmp->atom->natoms > MAXSMALLINT) return 0;
int natoms = static_cast<int> (lmp->atom->natoms);
return natoms;
}
/* ----------------------------------------------------------------------
gather the named atom-based entity across all processors
name = desired quantity, e.g. x or charge
type = 0 for integer values, 1 for double values
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
return atom-based values in data, ordered by count, then by atom ID
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
data must be pre-allocated by caller to correct length
------------------------------------------------------------------------- */
void lammps_gather_atoms(void *ptr, char *name,
int type, int count, void *data)
{
LAMMPS *lmp = (LAMMPS *) ptr;
// error if tags are not defined or not consecutive
int flag = 0;
if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0) flag = 1;
if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
if (flag && lmp->comm->me == 0) {
lmp->error->warning(FLERR,"Library error in lammps_gather_atoms");
return;
}
int natoms = static_cast<int> (lmp->atom->natoms);
int i,j,offset;
void *vptr = lmp->atom->extract(name);
// copy = Natom length vector of per-atom values
// use atom ID to insert each atom's values into copy
// MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
if (type == 0) {
int *vector = NULL;
int **array = NULL;
if (count == 1) vector = (int *) vptr;
else array = (int **) vptr;
int *copy;
lmp->memory->create(copy,count*natoms,"lib/gather:copy");
for (i = 0; i < count*natoms; i++) copy[i] = 0;
- int *tag = lmp->atom->tag;
+ tagint *tag = lmp->atom->tag;
int nlocal = lmp->atom->nlocal;
if (count == 1)
for (i = 0; i < nlocal; i++)
copy[tag[i]-1] = vector[i];
else
for (i = 0; i < nlocal; i++) {
offset = count*(tag[i]-1);
for (j = 0; j < count; j++)
copy[offset++] = array[i][0];
}
MPI_Allreduce(copy,data,count*natoms,MPI_INT,MPI_SUM,lmp->world);
lmp->memory->destroy(copy);
} else {
double *vector = NULL;
double **array = NULL;
if (count == 1) vector = (double *) vptr;
else array = (double **) vptr;
double *copy;
lmp->memory->create(copy,count*natoms,"lib/gather:copy");
for (i = 0; i < count*natoms; i++) copy[i] = 0.0;
- int *tag = lmp->atom->tag;
+ tagint *tag = lmp->atom->tag;
int nlocal = lmp->atom->nlocal;
if (count == 1) {
for (i = 0; i < nlocal; i++)
copy[tag[i]-1] = vector[i];
} else {
for (i = 0; i < nlocal; i++) {
offset = count*(tag[i]-1);
for (j = 0; j < count; j++)
copy[offset++] = array[i][j];
}
}
MPI_Allreduce(copy,data,count*natoms,MPI_DOUBLE,MPI_SUM,lmp->world);
lmp->memory->destroy(copy);
}
}
/* ----------------------------------------------------------------------
scatter the named atom-based entity across all processors
name = desired quantity, e.g. x or charge
type = 0 for integer values, 1 for double values
count = # of per-atom values, e.g. 1 for type or charge, 3 for x or f
data = atom-based values in data, ordered by count, then by atom ID
e.g. x[0][0],x[0][1],x[0][2],x[1][0],x[1][1],x[1][2],x[2][0],...
------------------------------------------------------------------------- */
void lammps_scatter_atoms(void *ptr, char *name,
int type, int count, void *data)
{
LAMMPS *lmp = (LAMMPS *) ptr;
// error if tags are not defined or not consecutive or no atom map
int flag = 0;
if (lmp->atom->tag_enable == 0 || lmp->atom->tag_consecutive() == 0) flag = 1;
if (lmp->atom->natoms > MAXSMALLINT) flag = 1;
if (lmp->atom->map_style == 0) flag = 1;
if (flag && lmp->comm->me == 0) {
lmp->error->warning(FLERR,"Library error in lammps_scatter_atoms");
return;
}
int natoms = static_cast<int> (lmp->atom->natoms);
int i,j,m,offset;
void *vptr = lmp->atom->extract(name);
// copy = Natom length vector of per-atom values
// use atom ID to insert each atom's values into copy
// MPI_Allreduce with MPI_SUM to merge into data, ordered by atom ID
if (type == 0) {
int *vector = NULL;
int **array = NULL;
if (count == 1) vector = (int *) vptr;
else array = (int **) vptr;
int *dptr = (int *) data;
if (count == 1) {
for (i = 0; i < natoms; i++)
if ((m = lmp->atom->map(i+1)) >= 0)
vector[m] = dptr[i];
} else {
for (i = 0; i < natoms; i++)
if ((m = lmp->atom->map(i+1)) >= 0) {
offset = count*i;
for (j = 0; j < count; j++)
array[m][j] = dptr[offset++];
}
}
} else {
double *vector = NULL;
double **array = NULL;
if (count == 1) vector = (double *) vptr;
else array = (double **) vptr;
double *dptr = (double *) data;
if (count == 1) {
for (i = 0; i < natoms; i++)
if ((m = lmp->atom->map(i+1)) >= 0)
vector[m] = dptr[i];
} else {
for (i = 0; i < natoms; i++) {
if ((m = lmp->atom->map(i+1)) >= 0) {
offset = count*i;
for (j = 0; j < count; j++)
array[m][j] = dptr[offset++];
}
}
}
}
}
diff --git a/src/lmptype.h b/src/lmptype.h
index 1c3b783e2..a23aa9113 100644
--- a/src/lmptype.h
+++ b/src/lmptype.h
@@ -1,169 +1,172 @@
/* -*- 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.
------------------------------------------------------------------------- */
// define integer data types used by LAMMPS and associated size limits
// smallint = variables for on-procesor system (nlocal, nmax, etc)
// imageint = variables for atom image flags (image)
// tagint = variables for atom IDs (tag)
// bigint = variables for total system (natoms, ntimestep, etc)
// smallint must be an int, as defined by C compiler
// imageint can be 32-bit or 64-bit int, must be >= smallint
// tagint can be 32-bit or 64-bit int, must be >= smallint
// bigint can be 32-bit or 64-bit int, must be >= tagint
// MPI_LMP_BIGINT = MPI data type corresponding to a bigint
#ifndef LMP_LMPTYPE_H
#define LMP_LMPTYPE_H
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include "limits.h"
#include "stdint.h"
#include "inttypes.h"
// grrr - IBM Power6 does not provide this def in their system header files
#ifndef PRId64
#define PRId64 "ld"
#endif
namespace LAMMPS_NS {
// reserve 2 hi bits in molecular system neigh list for special bonds flag
// max local + ghost atoms per processor = 2^30 - 1
#define SBBITS 30
#define NEIGHMASK 0x3FFFFFFF
-// default to 32-bit smallint and tagint, 64-bit bigint
+// default to 32-bit smallint and other ints, 64-bit bigint
#if !defined(LAMMPS_SMALLSMALL) && !defined(LAMMPS_BIGBIG) && !defined(LAMMPS_SMALLBIG)
#define LAMMPS_SMALLBIG
#endif
// allow user override of LONGLONG to LONG, necessary for some machines/MPI
#ifdef LAMMPS_LONGLONG_TO_LONG
#define MPI_LL MPI_LONG
#define ATOLL atoll
#else
#define MPI_LL MPI_LONG_LONG
#define ATOLL atol
#endif
// for atomic problems that exceed 2 billion (2^31) atoms
-// 32-bit smallint and imageint and tagint, 64-bit bigint
+// 32-bit smallint/imageint/tagint, 64-bit bigint
#ifdef LAMMPS_SMALLBIG
typedef int smallint;
typedef int imageint;
typedef int tagint;
typedef int64_t bigint;
#define MAXSMALLINT INT_MAX
#define MAXTAGINT INT_MAX
#define MAXBIGINT INT64_MAX
+#define MPI_LMP_TAGINT MPI_INT
#define MPI_LMP_BIGINT MPI_LL
#define TAGINT_FORMAT "%d"
#define BIGINT_FORMAT "%" PRId64
#define ATOTAGINT atoi
#define ATOBIGINT ATOLL
#define IMGMASK 1023
#define IMGMAX 512
#define IMGBITS 10
#define IMG2BITS 20
#endif
// for molecular problems that exceed 2 billion (2^31) atoms
// or problems where atoms wrap around the periodic box more than 512 times
-// 32-bit smallint, 64-bit imageint and tagint and bigint
+// 32-bit smallint, 64-bit imageint/tagint/bigint
#ifdef LAMMPS_BIGBIG
typedef int smallint;
typedef int64_t imageint;
typedef int64_t tagint;
typedef int64_t bigint;
#define MAXSMALLINT INT_MAX
#define MAXTAGINT INT64_MAX
#define MAXBIGINT INT64_MAX
+#define MPI_LMP_TAGINT MPI_LL
#define MPI_LMP_BIGINT MPI_LL
#define TAGINT_FORMAT "%" PRId64
#define BIGINT_FORMAT "%" PRId64
#define ATOTAGINT ATOLL
#define ATOBIGINT ATOLL
#define IMGMASK 2097151
#define IMGMAX 1048576
#define IMGBITS 21
#define IMG2BITS 42
#endif
// for machines that do not support 64-bit ints
-// 32-bit smallint and imageint and tagint and bigint
+// 32-bit smallint/imageint/tagint/bigint
#ifdef LAMMPS_SMALLSMALL
typedef int smallint;
typedef int imageint;
typedef int tagint;
typedef int bigint;
#define MAXSMALLINT INT_MAX
#define MAXTAGINT INT_MAX
#define MAXBIGINT INT_MAX
+#define MPI_LMP_TAGINT MPI_INT
#define MPI_LMP_BIGINT MPI_INT
#define TAGINT_FORMAT "%d"
#define BIGINT_FORMAT "%d"
#define ATOTAGINT atoi
#define ATOBIGINT atoi
#define IMGMASK 1023
#define IMGMAX 512
#define IMGBITS 10
#define IMG2BITS 20
#endif
}
// settings to enable LAMMPS to build under Windows
#ifdef _WIN32
#include "lmpwindows.h"
#endif
#endif
diff --git a/src/molecule.cpp b/src/molecule.cpp
index 669a34ce1..389a9cf79 100644
--- a/src/molecule.cpp
+++ b/src/molecule.cpp
@@ -1,1368 +1,1369 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "molecule.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "comm.h"
#include "domain.h"
#include "math_extra.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define MAXLINE 256
#define EPSILON 1.0e-7
#define BIG 1.0e20
/* ---------------------------------------------------------------------- */
Molecule::Molecule(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
{
me = comm->me;
if (narg != 2) error->all(FLERR,"Illegal molecule command");
int n = strlen(arg[0]) + 1;
id = new char[n];
strcpy(id,arg[0]);
for (int i = 0; i < n-1; i++)
if (!isalnum(id[i]) && id[i] != '_')
error->all(FLERR,
"Molecule ID must be alphanumeric or underscore characters");
char *file = arg[1];
// initialize all fields to empty
initialize();
// scan file for sizes of all fields and allocate them
if (me == 0) open(file);
read(0);
if (me == 0) fclose(fp);
allocate();
// read file again to populate all fields
if (me == 0) open(file);
read(1);
if (me == 0) fclose(fp);
}
/* ---------------------------------------------------------------------- */
Molecule::~Molecule()
{
delete [] id;
deallocate();
}
/* ----------------------------------------------------------------------
compute center = geometric center of molecule
also compute:
dx = displacement of each atom from center
molradius = radius of molecule from center including finite-size particles
------------------------------------------------------------------------- */
void Molecule::compute_center()
{
if (centerflag) return;
centerflag = 1;
center[0] = center[1] = center[2] = 0.0;
for (int i = 0; i < natoms; i++) {
center[0] += x[i][0];
center[1] += x[i][1];
center[2] += x[i][2];
}
center[0] /= natoms;
center[1] /= natoms;
center[2] /= natoms;
memory->destroy(dx);
memory->create(dx,natoms,3,"molecule:dx");
for (int i = 0; i < natoms; i++) {
dx[i][0] = x[i][0] - center[0];
dx[i][1] = x[i][1] - center[1];
dx[i][2] = x[i][2] - center[2];
}
molradius = 0.0;
for (int i = 0; i < natoms; i++) {
double rad = MathExtra::len3(dx[i]);
if (radiusflag) rad += radius[i];
molradius = MAX(molradius,rad);
}
}
/* ----------------------------------------------------------------------
compute masstotal = total mass of molecule
could have been set by user, otherwise calculate it
------------------------------------------------------------------------- */
void Molecule::compute_mass()
{
if (massflag) return;
massflag = 1;
if (!rmassflag) atom->check_mass();
masstotal = 0.0;
for (int i = 0; i < natoms; i++) {
if (rmassflag) masstotal += rmass[i];
else masstotal += atom->type[type[i]];
}
}
/* ----------------------------------------------------------------------
compute com = center of mass of molecule
could have been set by user, otherwise calculate it
NOTE: account for finite size particles?
also compute:
dxcom = displacement of each atom from COM
comatom = which atom (1-Natom) is nearest the COM
maxextent = furthest any atom in molecule is from comatom (not COM)
------------------------------------------------------------------------- */
void Molecule::compute_com()
{
if (!comflag) {
comflag = 1;
if (!rmassflag) atom->check_mass();
double onemass;
com[0] = com[1] = com[2] = 0.0;
for (int i = 0; i < natoms; i++) {
if (rmassflag) onemass = rmass[i];
else onemass = atom->type[type[i]];
com[0] += x[i][0]*onemass;
com[1] += x[i][1]*onemass;
com[2] += x[i][2]*onemass;
}
com[0] /= masstotal;
com[1] /= masstotal;
com[2] /= masstotal;
}
memory->destroy(dxcom);
memory->create(dxcom,natoms,3,"molecule:dxcom");
for (int i = 0; i < natoms; i++) {
dxcom[i][0] = x[i][0] - com[0];
dxcom[i][1] = x[i][1] - com[1];
dxcom[i][2] = x[i][2] - com[2];
}
double rsqmin = BIG;
for (int i = 0; i < natoms; i++) {
double rsq = MathExtra::lensq3(dxcom[i]);
if (rsq < rsqmin) {
comatom = i;
rsqmin = rsq;
}
}
double rsqmax = 0.0;
for (int i = 0; i < natoms; i++) {
double dx = x[comatom][0] - x[i][0];
double dy = x[comatom][1] - x[i][1];
double dz = x[comatom][2] - x[i][2];
double rsq = dx*dx + dy*dy + dz*dz;
rsqmax = MAX(rsqmax,rsq);
}
comatom++;
maxextent = sqrt(rsqmax);
}
/* ----------------------------------------------------------------------
compute itensor = 6 moments of inertia of molecule around xyz axes
could have been set by user, otherwise calculate it
NOTE: account for finite size particles?
also compute:
inertia = 3 principal components of inertia
ex,ey,ez = principal axes in space coords
quat = quaternion for orientation of molecule
dxbody = displacement of each atom from COM in body frame
------------------------------------------------------------------------- */
void Molecule::compute_inertia()
{
if (!inertiaflag) {
inertiaflag = 1;
if (!rmassflag) atom->check_mass();
double onemass,dx,dy,dz;
for (int i = 0; i < 6; i++) itensor[i] = 0.0;
for (int i = 0; i < natoms; i++) {
if (rmassflag) onemass = rmass[i];
else onemass = atom->type[type[i]];
dx = dxcom[i][0];
dy = dxcom[i][1];
dz = dxcom[i][2];
itensor[0] += onemass * (dy*dy + dz*dz);
itensor[1] += onemass * (dx*dx + dz*dz);
itensor[2] += onemass * (dx*dx + dy*dy);
itensor[3] -= onemass * dy*dz;
itensor[4] -= onemass * dx*dz;
itensor[5] -= onemass * dx*dy;
}
}
// diagonalize inertia tensor for each body via Jacobi rotations
// inertia = 3 eigenvalues = principal moments of inertia
// evectors and exzy = 3 evectors = principal axes of rigid body
int ierror;
double cross[3];
double tensor[3][3],evectors[3][3];
tensor[0][0] = itensor[0];
tensor[1][1] = itensor[1];
tensor[2][2] = itensor[2];
tensor[1][2] = tensor[2][1] = itensor[3];
tensor[0][2] = tensor[2][0] = itensor[4];
tensor[0][1] = tensor[1][0] = itensor[5];
if (MathExtra::jacobi(tensor,inertia,evectors))
error->all(FLERR,"Insufficient Jacobi rotations for rigid molecule");
ex[0] = evectors[0][0];
ex[1] = evectors[1][0];
ex[2] = evectors[2][0];
ey[0] = evectors[0][1];
ey[1] = evectors[1][1];
ey[2] = evectors[2][1];
ez[0] = evectors[0][2];
ez[1] = evectors[1][2];
ez[2] = evectors[2][2];
// if any principal moment < scaled EPSILON, set to 0.0
double max;
max = MAX(inertia[0],inertia[1]);
max = MAX(max,inertia[2]);
if (inertia[0] < EPSILON*max) inertia[0] = 0.0;
if (inertia[1] < EPSILON*max) inertia[1] = 0.0;
if (inertia[2] < EPSILON*max) inertia[2] = 0.0;
// enforce 3 evectors as a right-handed coordinate system
// flip 3rd vector if needed
MathExtra::cross3(ex,ey,cross);
if (MathExtra::dot3(cross,ez) < 0.0) MathExtra::negate3(ez);
// create quaternion
MathExtra::exyz_to_q(ex,ey,ez,quat);
// compute displacements in body frame defined by quat
memory->destroy(dxbody);
memory->create(dxbody,natoms,3,"molecule:dxbody");
for (int i = 0; i < natoms; i++)
MathExtra::transpose_matvec(ex,ey,ez,dxcom[i],dxbody[i]);
}
/* ----------------------------------------------------------------------
read molecule info from file
flag = 0, just scan for sizes of fields
flag = 1, read and store fields
------------------------------------------------------------------------- */
void Molecule::read(int flag)
{
char line[MAXLINE],keyword[MAXLINE];
char *eof,*ptr;
// skip 1st line of file
if (me == 0) {
eof = fgets(line,MAXLINE,fp);
if (eof == NULL) error->one(FLERR,"Unexpected end of molecule file");
}
// read header lines
// skip blank lines or lines that start with "#"
// stop when read an unrecognized line
while (1) {
readline(line);
// trim anything from '#' onward
// if line is blank, continue
if (ptr = strchr(line,'#')) *ptr = '\0';
if (strspn(line," \t\n\r") == strlen(line)) continue;
// search line for header keywords and set corresponding variable
if (strstr(line,"atoms")) sscanf(line,"%d",&natoms);
else if (strstr(line,"bonds")) sscanf(line,"%d",&nbonds);
else if (strstr(line,"angles")) sscanf(line,"%d",&nangles);
else if (strstr(line,"dihedrals")) sscanf(line,"%d",&ndihedrals);
else if (strstr(line,"impropers")) sscanf(line,"%d",&nimpropers);
else if (strstr(line,"mass")) {
massflag = 1;
sscanf(line,"%lg",&masstotal);
}
else if (strstr(line,"com")) {
comflag = 1;
sscanf(line,"%lg %lg %lg",&com[0],&com[1],&com[2]);
if (domain->dimension == 2 && com[2] != 0.0)
error->all(FLERR,"Molecule file z center-of-mass must be 0.0 for 2d");
}
else if (strstr(line,"inertia")) {
inertiaflag = 1;
sscanf(line,"%lg %lg %lg %lg %lg %lg",
&itensor[0],&itensor[1],&itensor[2],
&itensor[3],&itensor[4],&itensor[5]);
}
else break;
}
// error check
if (flag == 0) {
if (natoms == 0) error->all(FLERR,"No atom count in molecule file");
if (nbonds && !atom->avec->bonds_allow)
error->all(FLERR,"Bonds in molecule file not supported by atom style");
if (nangles && !atom->avec->angles_allow)
error->all(FLERR,"Angles in molecule file not supported by atom style");
if (ndihedrals && !atom->avec->dihedrals_allow)
error->all(FLERR,
"Dihedrals in molecule file not supported by atom style");
if (nimpropers && !atom->avec->impropers_allow)
error->all(FLERR,
"Impropers in molecule file not supported by atom style");
}
// count = vector for tallying bonds,angles,etc per atom
if (flag == 0) memory->create(count,natoms,"molecule:count");
else count = NULL;
// grab keyword and skip next line
parse_keyword(0,line,keyword);
readline(line);
// loop over sections of molecule file
while (strlen(keyword)) {
if (strcmp(keyword,"Coords") == 0) {
xflag = 1;
if (flag) coords(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Types") == 0) {
typeflag = 1;
if (flag) types(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Charges") == 0) {
qflag = 1;
if (flag) charges(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Diameters") == 0) {
radiusflag = 1;
if (flag) diameters(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Masses") == 0) {
rmassflag = 1;
if (flag) masses(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Bonds") == 0) {
if (nbonds == 0)
error->all(FLERR,"Molecule file has bonds but no nbonds setting");
- bondflag = 1;
+ bondflag = tag_require = 1;
bonds(flag,line);
} else if (strcmp(keyword,"Angles") == 0) {
if (nangles == 0)
error->all(FLERR,"Molecule file has angles but no nangles setting");
- angleflag = 1;
+ angleflag = tag_require = 1;
angles(flag,line);
} else if (strcmp(keyword,"Dihedrals") == 0) {
if (ndihedrals == 0) error->all(FLERR,"Molecule file has dihedrals "
"but no ndihedrals setting");
- dihedralflag = 1;
+ dihedralflag = tag_require = 1;
dihedrals(flag,line);
} else if (strcmp(keyword,"Impropers") == 0) {
if (nimpropers == 0) error->all(FLERR,"Molecule file has impropers "
"but no nimpropers setting");
- improperflag = 1;
+ improperflag = tag_require = 1;
impropers(flag,line);
} else if (strcmp(keyword,"Special Bond Counts") == 0) {
nspecialflag = 1;
nspecial_read(flag,line);
} else if (strcmp(keyword,"Special Bonds") == 0) {
- specialflag = 1;
+ specialflag = tag_require = 1;
if (flag) special_read(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Shake Flags") == 0) {
shakeflagflag = 1;
if (flag) shakeflag_read(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Shake Atoms") == 0) {
- shakeatomflag = 1;
+ shakeatomflag = tag_require = 1;
if (shaketypeflag) shakeflag = 1;
if (!shakeflagflag)
error->all(FLERR,"Molecule file shake flags not before shake atoms");
if (flag) shakeatom_read(line);
else skip_lines(natoms,line);
} else if (strcmp(keyword,"Shake Bond Types") == 0) {
shaketypeflag = 1;
if (shakeatomflag) shakeflag = 1;
if (!shakeflagflag)
error->all(FLERR,"Molecule file shake flags not before shake bonds");
if (flag) shaketype_read(line);
else skip_lines(natoms,line);
} else error->one(FLERR,"Unknown section in molecule file");
parse_keyword(1,line,keyword);
}
// clean up
memory->destroy(count);
// error check
if (flag == 0) {
if (qflag && !atom->q_flag)
error->all(FLERR,"Molecule file has undefined atom property");
if (radiusflag && !atom->radius_flag)
error->all(FLERR,"Molecule file has undefined atom property");
if (rmassflag && !atom->rmass_flag)
error->all(FLERR,"Molecule file has undefined atom property");
if (bondflag && !atom->avec->bonds_allow)
error->all(FLERR,"Invalid molecule file section: Bonds");
if (angleflag && !atom->avec->angles_allow)
error->all(FLERR,"Invalid molecule file section: Angles");
if (dihedralflag && !atom->avec->dihedrals_allow)
error->all(FLERR,"Invalid molecule file section: Dihedrals");
if (improperflag && !atom->avec->impropers_allow)
error->all(FLERR,"Invalid molecule file section: Impropers");
if (bond_per_atom > atom->bond_per_atom ||
angle_per_atom > atom->angle_per_atom ||
dihedral_per_atom > atom->dihedral_per_atom ||
improper_per_atom > atom->improper_per_atom)
error->all(FLERR,"Molecule file bond/angle/etc counts "
"per atom are too large");
// test for maxspecial > atom->maxspecial is done when molecules added
// in Atom::add_molecule_atom()
if ((nspecialflag && !specialflag) || (!nspecialflag && specialflag))
error->all(FLERR,"Molecule file needs both Special Bond sections");
if (specialflag && !bondflag)
error->all(FLERR,"Molecule file has special flags but no bonds");
if ((shakeflagflag || shakeatomflag || shaketypeflag) && !shakeflag)
error->all(FLERR,"Molecule file shake info is incomplete");
}
}
/* ----------------------------------------------------------------------
read coords from file
------------------------------------------------------------------------- */
void Molecule::coords(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %lg %lg %lg",&tmp,&x[i][0],&x[i][1],&x[i][2]);
}
if (domain->dimension == 2) {
for (int i = 0; i < natoms; i++)
if (x[i][2] != 0.0)
error->all(FLERR,"Molecule file z coord must be 0.0 for 2d");
}
}
/* ----------------------------------------------------------------------
read types from file
set maxtype = max of any atom type
------------------------------------------------------------------------- */
void Molecule::types(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %d",&tmp,&type[i]);
}
for (int i = 0; i < natoms; i++)
if (type[i] <= 0 || type[i] > atom->ntypes)
error->all(FLERR,"Invalid atom type in molecule file");
for (int i = 0; i < natoms; i++)
maxtype = MAX(maxtype,type[i]);
}
/* ----------------------------------------------------------------------
read charges from file
------------------------------------------------------------------------- */
void Molecule::charges(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %lg",&tmp,&q[i]);
}
}
/* ----------------------------------------------------------------------
read diameters from file and set radii
------------------------------------------------------------------------- */
void Molecule::diameters(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %lg",&tmp,&radius[i]);
radius[i] *= 0.5;
}
for (int i = 0; i < natoms; i++)
if (radius[i] < 0.0)
error->all(FLERR,"Invalid atom diameter in molecule file");
}
/* ----------------------------------------------------------------------
read masses from file
------------------------------------------------------------------------- */
void Molecule::masses(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %lg",&tmp,&rmass[i]);
}
for (int i = 0; i < natoms; i++)
if (rmass[i] <= 0.0) error->all(FLERR,"Invalid atom mass in molecule file");
}
/* ----------------------------------------------------------------------
read bonds from file
store each with both atoms if newton_bond = 0
if flag = 0, just count bonds/atom
if flag = 1, store them with atoms
------------------------------------------------------------------------- */
void Molecule::bonds(int flag, char *line)
{
int m,tmp,itype,atom1,atom2;
int newton_bond = force->newton_bond;
if (flag == 0)
for (int i = 0; i < natoms; i++) count[i] = 0;
else
for (int i = 0; i < natoms; i++) num_bond[i] = 0;
for (int i = 0; i < nbonds; i++) {
readline(line);
sscanf(line,"%d %d %d %d",&tmp,&itype,&atom1,&atom2);
if (atom1 <= 0 || atom1 > natoms ||
atom2 <= 0 || atom2 > natoms)
error->one(FLERR,"Invalid atom ID in Bonds section of molecule file");
if (itype <= 0 || itype > atom->nbondtypes)
error->one(FLERR,"Invalid bond type in Bonds section of molecule file");
if (flag) {
m = atom1-1;
bond_type[m][num_bond[m]] = itype;
bond_atom[m][num_bond[m]] = atom2;
num_bond[m]++;
if (newton_bond == 0) {
m = atom2-1;
bond_type[m][num_bond[m]] = itype;
bond_atom[m][num_bond[m]] = atom1;
num_bond[m]++;
}
} else {
count[atom1-1]++;
if (newton_bond == 0) count[atom2-1]++;
}
}
// bond_per_atom = max of count vector
if (flag == 0) {
bond_per_atom = 0;
for (int i = 0; i < natoms; i++)
bond_per_atom = MAX(bond_per_atom,count[i]);
}
}
/* ----------------------------------------------------------------------
read angles from file
store each with all 3 atoms if newton_bond = 0
if flag = 0, just count angles/atom
if flag = 1, store them with atoms
------------------------------------------------------------------------- */
void Molecule::angles(int flag, char *line)
{
int m,tmp,itype,atom1,atom2,atom3;
int newton_bond = force->newton_bond;
if (flag == 0)
for (int i = 0; i < natoms; i++) count[i] = 0;
else
for (int i = 0; i < natoms; i++) num_angle[i] = 0;
for (int i = 0; i < nangles; i++) {
readline(line);
sscanf(line,"%d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3);
if (atom1 <= 0 || atom1 > natoms ||
atom2 <= 0 || atom2 > natoms ||
atom3 <= 0 || atom3 > natoms)
error->one(FLERR,"Invalid atom ID in Angles section of molecule file");
if (itype <= 0 || itype > atom->nangletypes)
error->one(FLERR,"Invalid angle type in Angles section of molecule file");
if (flag) {
m = atom2-1;
angle_type[m][num_angle[m]] = itype;
angle_atom1[m][num_angle[m]] = atom1;
angle_atom2[m][num_angle[m]] = atom2;
angle_atom3[m][num_angle[m]] = atom3;
num_angle[m]++;
if (newton_bond == 0) {
m = atom1-1;
angle_type[m][num_angle[m]] = itype;
angle_atom1[m][num_angle[m]] = atom1;
angle_atom2[m][num_angle[m]] = atom2;
angle_atom3[m][num_angle[m]] = atom3;
num_angle[m]++;
m = atom3-1;
angle_type[m][num_angle[m]] = itype;
angle_atom1[m][num_angle[m]] = atom1;
angle_atom2[m][num_angle[m]] = atom2;
angle_atom3[m][num_angle[m]] = atom3;
num_angle[m]++;
}
} else {
count[atom2-1]++;
if (newton_bond == 0) {
count[atom1-1]++;
count[atom3-1]++;
}
}
}
// angle_per_atom = max of count vector
if (flag == 0) {
angle_per_atom = 0;
for (int i = 0; i < natoms; i++)
angle_per_atom = MAX(angle_per_atom,count[i]);
}
}
/* ----------------------------------------------------------------------
read dihedrals from file
store each with all 4 atoms if newton_bond = 0
if flag = 0, just count dihedrals/atom
if flag = 1, store them with atoms
------------------------------------------------------------------------- */
void Molecule::dihedrals(int flag, char *line)
{
int m,tmp,itype,atom1,atom2,atom3,atom4;
int newton_bond = force->newton_bond;
if (flag == 0)
for (int i = 0; i < natoms; i++) count[i] = 0;
else
for (int i = 0; i < natoms; i++) num_dihedral[i] = 0;
for (int i = 0; i < ndihedrals; i++) {
readline(line);
sscanf(line,"%d %d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3,&atom4);
if (atom1 <= 0 || atom1 > natoms ||
atom2 <= 0 || atom2 > natoms ||
atom3 <= 0 || atom3 > natoms ||
atom4 <= 0 || atom4 > natoms)
error->one(FLERR,
"Invalid atom ID in dihedrals section of molecule file");
if (itype <= 0 || itype > atom->ndihedraltypes)
error->one(FLERR,
"Invalid dihedral type in dihedrals section of molecule file");
if (flag) {
m = atom2-1;
dihedral_type[m][num_dihedral[m]] = itype;
dihedral_atom1[m][num_dihedral[m]] = atom1;
dihedral_atom2[m][num_dihedral[m]] = atom2;
dihedral_atom3[m][num_dihedral[m]] = atom3;
num_dihedral[m]++;
if (newton_bond == 0) {
m = atom1-1;
dihedral_type[m][num_dihedral[m]] = itype;
dihedral_atom1[m][num_dihedral[m]] = atom1;
dihedral_atom2[m][num_dihedral[m]] = atom2;
dihedral_atom3[m][num_dihedral[m]] = atom3;
num_dihedral[m]++;
m = atom3-1;
dihedral_type[m][num_dihedral[m]] = itype;
dihedral_atom1[m][num_dihedral[m]] = atom1;
dihedral_atom2[m][num_dihedral[m]] = atom2;
dihedral_atom3[m][num_dihedral[m]] = atom3;
num_dihedral[m]++;
m = atom4-1;
dihedral_type[m][num_dihedral[m]] = itype;
dihedral_atom1[m][num_dihedral[m]] = atom1;
dihedral_atom2[m][num_dihedral[m]] = atom2;
dihedral_atom3[m][num_dihedral[m]] = atom3;
num_dihedral[m]++;
}
} else {
count[atom2-1]++;
if (newton_bond == 0) {
count[atom1-1]++;
count[atom3-1]++;
count[atom4-1]++;
}
}
}
// dihedral_per_atom = max of count vector
if (flag == 0) {
dihedral_per_atom = 0;
for (int i = 0; i < natoms; i++)
dihedral_per_atom = MAX(dihedral_per_atom,count[i]);
}
}
/* ----------------------------------------------------------------------
read impropers from file
store each with all 4 atoms if newton_bond = 0
if flag = 0, just count impropers/atom
if flag = 1, store them with atoms
------------------------------------------------------------------------- */
void Molecule::impropers(int flag, char *line)
{
int m,tmp,itype,atom1,atom2,atom3,atom4;
int newton_bond = force->newton_bond;
if (flag == 0)
for (int i = 0; i < natoms; i++) count[i] = 0;
else
for (int i = 0; i < natoms; i++) num_improper[i] = 0;
for (int i = 0; i < nimpropers; i++) {
readline(line);
sscanf(line,"%d %d %d %d %d %d",&tmp,&itype,&atom1,&atom2,&atom3,&atom4);
if (atom1 <= 0 || atom1 > natoms ||
atom2 <= 0 || atom2 > natoms ||
atom3 <= 0 || atom3 > natoms ||
atom4 <= 0 || atom4 > natoms)
error->one(FLERR,
"Invalid atom ID in impropers section of molecule file");
if (itype <= 0 || itype > atom->nimpropertypes)
error->one(FLERR,
"Invalid improper type in impropers section of molecule file");
if (flag) {
m = atom2-1;
improper_type[m][num_improper[m]] = itype;
improper_atom1[m][num_improper[m]] = atom1;
improper_atom2[m][num_improper[m]] = atom2;
improper_atom3[m][num_improper[m]] = atom3;
num_improper[m]++;
if (newton_bond == 0) {
m = atom1-1;
improper_type[m][num_improper[m]] = itype;
improper_atom1[m][num_improper[m]] = atom1;
improper_atom2[m][num_improper[m]] = atom2;
improper_atom3[m][num_improper[m]] = atom3;
num_improper[m]++;
m = atom3-1;
improper_type[m][num_improper[m]] = itype;
improper_atom1[m][num_improper[m]] = atom1;
improper_atom2[m][num_improper[m]] = atom2;
improper_atom3[m][num_improper[m]] = atom3;
num_improper[m]++;
m = atom4-1;
improper_type[m][num_improper[m]] = itype;
improper_atom1[m][num_improper[m]] = atom1;
improper_atom2[m][num_improper[m]] = atom2;
improper_atom3[m][num_improper[m]] = atom3;
num_improper[m]++;
}
} else {
count[atom2-1]++;
if (newton_bond == 0) {
count[atom1-1]++;
count[atom3-1]++;
count[atom4-1]++;
}
}
}
// improper_per_atom = max of count vector
if (flag == 0) {
improper_per_atom = 0;
for (int i = 0; i < natoms; i++)
improper_per_atom = MAX(improper_per_atom,count[i]);
}
}
/* ----------------------------------------------------------------------
read 3 special bonds counts from file
if flag = 0, just tally maxspecial
if flag = 1, store them with atoms
------------------------------------------------------------------------- */
void Molecule::nspecial_read(int flag, char *line)
{
int tmp,c1,c2,c3;
if (flag == 0) maxspecial = 0;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %d %d %d",&tmp,&c1,&c2,&c3);
if (flag) {
nspecial[i][0] = c1;
nspecial[i][1] = c1+c2;
nspecial[i][2] = c1+c2+c3;
} else maxspecial = MAX(maxspecial,c1+c2+c3);
}
}
/* ----------------------------------------------------------------------
read special bond indices from file
------------------------------------------------------------------------- */
void Molecule::special_read(char *line)
{
int m,nwords;
char **words = new char*[maxspecial+1];
for (int i = 0; i < natoms; i++) {
readline(line);
nwords = parse(line,words,maxspecial+1);
if (nwords != nspecial[i][2]+1)
error->all(FLERR,"Molecule file special list "
"does not match special count");
for (m = 1; m < nwords; m++) {
special[i][m-1] = atoi(words[m]);
if (special[i][m-1] <= 0 || special[i][m-1] > natoms ||
special[i][m-1] == i+1)
error->all(FLERR,"Invalid special atom index in molecule file");
}
}
delete [] words;
}
/* ----------------------------------------------------------------------
read SHAKE flags from file
------------------------------------------------------------------------- */
void Molecule::shakeflag_read(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
sscanf(line,"%d %d",&tmp,&shake_flag[i]);
}
for (int i = 0; i < natoms; i++)
if (shake_flag[i] < 0 || shake_flag[i] > 4)
error->all(FLERR,"Invalid shake flag in molecule file");
}
/* ----------------------------------------------------------------------
read SHAKE atom info from file
------------------------------------------------------------------------- */
void Molecule::shakeatom_read(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (shake_flag[i] == 1)
sscanf(line,"%d %d %d %d",&tmp,
&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]);
else if (shake_flag[i] == 2)
sscanf(line,"%d %d %d",&tmp,&shake_atom[i][0],&shake_atom[i][1]);
else if (shake_flag[i] == 3)
sscanf(line,"%d %d %d %d",&tmp,
&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]);
else if (shake_flag[i] == 4)
sscanf(line,"%d %d %d %d %d",&tmp,
&shake_atom[i][0],&shake_atom[i][1],
&shake_atom[i][2],&shake_atom[i][3]);
}
for (int i = 0; i < natoms; i++) {
int m = shake_flag[i];
if (m == 1) m = 3;
for (int j = 0; j < m; j++)
if (shake_atom[i][j] <= 0 || shake_atom[i][j] > natoms)
error->all(FLERR,"Invalid shake atom in molecule file");
}
}
/* ----------------------------------------------------------------------
read SHAKE bond type info from file
------------------------------------------------------------------------- */
void Molecule::shaketype_read(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (shake_flag[i] == 1)
sscanf(line,"%d %d %d %d",&tmp,
&shake_type[i][0],&shake_type[i][1],&shake_type[i][2]);
else if (shake_flag[i] == 2)
sscanf(line,"%d %d",&tmp,&shake_type[i][0]);
else if (shake_flag[i] == 3)
sscanf(line,"%d %d %d",&tmp,&shake_type[i][0],&shake_type[i][1]);
else if (shake_flag[i] == 4)
sscanf(line,"%d %d %d %d",&tmp,
&shake_type[i][0],&shake_type[i][1],&shake_type[i][2]);
}
for (int i = 0; i < natoms; i++) {
int m = shake_flag[i];
if (m == 1) m = 3;
for (int j = 0; j < m-1; j++)
if (shake_type[i][j] <= 0 || shake_type[i][j] > atom->nbondtypes)
error->all(FLERR,"Invalid shake bond type in molecule file");
if (shake_flag[i] == 1)
if (shake_type[i][2] <= 0 || shake_type[i][2] > atom->nangletypes)
error->all(FLERR,"Invalid shake angle type in molecule file");
}
}
/* ----------------------------------------------------------------------
init all data structures to empty
------------------------------------------------------------------------- */
void Molecule::initialize()
{
natoms = 0;
nbonds = nangles = ndihedrals = nimpropers = 0;
maxtype = 0;
bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0;
maxspecial = 0;
xflag = typeflag = qflag = radiusflag = rmassflag = 0;
bondflag = angleflag = dihedralflag = improperflag = 0;
nspecialflag = specialflag = 0;
shakeflag = shakeflagflag = shakeatomflag = shaketypeflag = 0;
centerflag = massflag = comflag = inertiaflag = 0;
+ tag_require = 0;
x = NULL;
type = NULL;
q = NULL;
radius = NULL;
rmass = NULL;
num_bond = NULL;
bond_type = NULL;
bond_atom = NULL;
num_angle = NULL;
angle_type = NULL;
angle_atom1 = angle_atom2 = angle_atom3 = NULL;
num_dihedral = NULL;
dihedral_type = NULL;
dihedral_atom1 = dihedral_atom2 = dihedral_atom3 = dihedral_atom4 = NULL;
num_improper = NULL;
improper_type = NULL;
improper_atom1 = improper_atom2 = improper_atom3 = improper_atom4 = NULL;
nspecial = NULL;
special = NULL;
shake_flag = NULL;
shake_atom = shake_type = NULL;
dx = NULL;
dxcom = NULL;
dxbody = NULL;
}
/* ----------------------------------------------------------------------
allocate all data structures
------------------------------------------------------------------------- */
void Molecule::allocate()
{
if (xflag) memory->create(x,natoms,3,"molecule:x");
if (typeflag) memory->create(type,natoms,"molecule:type");
if (qflag) memory->create(q,natoms,"molecule:q");
if (radiusflag) memory->create(radius,natoms,"molecule:radius");
if (rmassflag) memory->create(rmass,natoms,"molecule:rmass");
if (bondflag) {
memory->create(num_bond,natoms,"molecule:num_bond");
memory->create(bond_type,natoms,bond_per_atom,
"molecule:bond_type");
memory->create(bond_atom,natoms,bond_per_atom,
"molecule:bond_atom");
}
if (angleflag) {
memory->create(num_angle,natoms,"molecule:num_angle");
memory->create(angle_type,natoms,angle_per_atom,
"molecule:angle_type");
memory->create(angle_atom1,natoms,angle_per_atom,
"molecule:angle_atom1");
memory->create(angle_atom2,natoms,angle_per_atom,
"molecule:angle_atom2");
memory->create(angle_atom3,natoms,angle_per_atom,
"molecule:angle_atom3");
}
if (dihedralflag) {
memory->create(num_dihedral,natoms,"molecule:num_dihedral");
memory->create(dihedral_type,natoms,dihedral_per_atom,
"molecule:dihedral_type");
memory->create(dihedral_atom1,natoms,dihedral_per_atom,
"molecule:dihedral_atom1");
memory->create(dihedral_atom2,natoms,dihedral_per_atom,
"molecule:dihedral_atom2");
memory->create(dihedral_atom3,natoms,dihedral_per_atom,
"molecule:dihedral_atom3");
memory->create(dihedral_atom4,natoms,dihedral_per_atom,
"molecule:dihedral_atom4");
}
if (improperflag) {
memory->create(num_improper,natoms,"molecule:num_improper");
memory->create(improper_type,natoms,improper_per_atom,
"molecule:improper_type");
memory->create(improper_atom1,natoms,improper_per_atom,
"molecule:improper_atom1");
memory->create(improper_atom2,natoms,improper_per_atom,
"molecule:improper_atom2");
memory->create(improper_atom3,natoms,improper_per_atom,
"molecule:improper_atom3");
memory->create(improper_atom4,natoms,improper_per_atom,
"molecule:improper_atom4");
}
if (nspecialflag)
memory->create(nspecial,natoms,3,"molecule:nspecial");
if (specialflag)
memory->create(special,natoms,maxspecial,"molecule:special");
if (shakeflag) {
memory->create(shake_flag,natoms,"molecule:shake_flag");
memory->create(shake_atom,natoms,4,"molecule:shake_flag");
memory->create(shake_type,natoms,3,"molecule:shake_flag");
}
}
/* ----------------------------------------------------------------------
deallocate all data structures
------------------------------------------------------------------------- */
void Molecule::deallocate()
{
memory->destroy(x);
memory->destroy(type);
memory->destroy(q);
memory->destroy(radius);
memory->destroy(rmass);
memory->destroy(num_bond);
memory->destroy(bond_type);
memory->destroy(bond_atom);
memory->destroy(num_angle);
memory->destroy(angle_type);
memory->destroy(angle_atom1);
memory->destroy(angle_atom2);
memory->destroy(angle_atom3);
memory->destroy(num_dihedral);
memory->destroy(dihedral_type);
memory->destroy(dihedral_atom1);
memory->destroy(dihedral_atom2);
memory->destroy(dihedral_atom3);
memory->destroy(dihedral_atom4);
memory->destroy(num_improper);
memory->destroy(improper_type);
memory->destroy(improper_atom1);
memory->destroy(improper_atom2);
memory->destroy(improper_atom3);
memory->destroy(improper_atom4);
memory->destroy(nspecial);
memory->destroy(special);
memory->destroy(shake_flag);
memory->destroy(shake_atom);
memory->destroy(shake_type);
memory->destroy(dx);
memory->destroy(dxcom);
memory->destroy(dxbody);
}
/* ----------------------------------------------------------------------
open molecule file
------------------------------------------------------------------------- */
void Molecule::open(char *file)
{
fp = fopen(file,"r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open molecule file %s",file);
error->one(FLERR,str);
}
}
/* ----------------------------------------------------------------------
read and bcast a line
------------------------------------------------------------------------- */
void Molecule::readline(char *line)
{
int n;
if (me == 0) {
if (fgets(line,MAXLINE,fp) == NULL) n = 0;
else n = strlen(line) + 1;
}
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) error->all(FLERR,"Unexpected end of molecule file");
MPI_Bcast(line,n,MPI_CHAR,0,world);
}
/* ----------------------------------------------------------------------
extract keyword from line
flag = 0, read and bcast line
flag = 1, line has already been read
------------------------------------------------------------------------- */
void Molecule::parse_keyword(int flag, char *line, char *keyword)
{
if (flag) {
// read upto non-blank line plus 1 following line
// eof is set to 1 if any read hits end-of-file
int eof = 0;
if (me == 0) {
if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) {
if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
}
if (fgets(keyword,MAXLINE,fp) == NULL) eof = 1;
}
// if eof, set keyword empty and return
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) {
keyword[0] = '\0';
return;
}
// bcast keyword line to all procs
int n;
if (me == 0) n = strlen(line) + 1;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
}
// copy non-whitespace portion of line into keyword
int start = strspn(line," \t\n\r");
int stop = strlen(line) - 1;
while (line[stop] == ' ' || line[stop] == '\t'
|| line[stop] == '\n' || line[stop] == '\r') stop--;
line[stop+1] = '\0';
strcpy(keyword,&line[start]);
}
/* ----------------------------------------------------------------------
skip N lines of file
------------------------------------------------------------------------- */
void Molecule::skip_lines(int n, char *line)
{
for (int i = 0; i < n; i++) readline(line);
}
/* ----------------------------------------------------------------------
parse line into words separated by whitespace
return # of words
max = max pointers storable in words
------------------------------------------------------------------------- */
int Molecule::parse(char *line, char **words, int max)
{
char *ptr;
int nwords = 0;
words[nwords++] = strtok(line," \t\n\r\f");
while (ptr = strtok(NULL," \t\n\r\f")) {
if (nwords < max) words[nwords] = ptr;
nwords++;
}
return nwords;
}
/* ----------------------------------------------------------------------
proc 0 prints molecule params
------------------------------------------------------------------------- */
/*
void Molecule::print()
{
printf("MOLECULE %s\n",id);
printf(" %d natoms\n",natoms);
if (nbonds) printf(" %d nbonds\n",nbonds);
if (nangles) printf(" %d nangles\n",nangles);
if (ndihedrals) printf(" %d ndihedrals\n",ndihedrals);
if (nimpropers) printf(" %d nimpropers\n",nimpropers);
if (xflag) {
printf( "Coords:\n");
for (int i = 0; i < natoms; i++)
printf(" %d %g %g %g\n",i+1,x[i][0],x[i][1],x[i][2]);
}
if (typeflag) {
printf( "Types:\n");
for (int i = 0; i < natoms; i++)
printf(" %d %d\n",i+1,type[i]);
}
if (qflag) {
printf( "Charges:\n");
for (int i = 0; i < natoms; i++)
printf(" %d %g\n",i+1,q[i]);
}
if (radiusflag) {
printf( "Radii:\n");
for (int i = 0; i < natoms; i++)
printf(" %d %g\n",i+1,radius[i]);
}
if (rmassflag) {
printf( "Masses:\n");
for (int i = 0; i < natoms; i++)
printf(" %d %g\n",i+1,rmass[i]);
}
if (bondflag) {
printf( "Bonds:\n");
for (int i = 0; i < natoms; i++) {
printf(" %d %d\n",i+1,num_bond[i]);
for (int j = 0; j < num_bond[i]; j++)
printf(" %d %d %d %d\n",j+1,bond_type[i][j],i+1,bond_atom[i][j]);
}
}
if (angleflag) {
printf( "Angles:\n");
for (int i = 0; i < natoms; i++) {
printf(" %d %d\n",i+1,num_angle[i]);
for (int j = 0; j < num_angle[i]; j++)
printf(" %d %d %d %d %d\n",
j+1,angle_type[i][j],
angle_atom1[i][j],angle_atom2[i][j],angle_atom3[i][j]);
}
}
if (dihedralflag) {
printf( "Dihedrals:\n");
for (int i = 0; i < natoms; i++) {
printf(" %d %d\n",i+1,num_dihedral[i]);
for (int j = 0; j < num_dihedral[i]; j++)
printf(" %d %d %d %d %d %d\n",
j+1,dihedral_type[i][j],
dihedral_atom1[i][j],dihedral_atom2[i][j],
dihedral_atom3[i][j],dihedral_atom4[i][j]);
}
}
if (improperflag) {
printf( "Impropers:\n");
for (int i = 0; i < natoms; i++) {
printf(" %d %d\n",i+1,num_improper[i]);
for (int j = 0; j < num_improper[i]; j++)
printf(" %d %d %d %d %d %d\n",
j+1,improper_type[i][j],
improper_atom1[i][j],improper_atom2[i][j],
improper_atom3[i][j],improper_atom4[i][j]);
}
}
if (specialflag) {
printf( "Special neighs:\n");
for (int i = 0; i < natoms; i++) {
printf(" %d %d %d %d\n",i+1,
nspecial[i][0],nspecial[i][1]-nspecial[i][0],
nspecial[i][2]-nspecial[i][1]);
printf(" ");
for (int j = 0; j < nspecial[i][2]; j++)
printf(" %d",special[i][j]);
printf("\n");
}
}
}
*/
diff --git a/src/molecule.h b/src/molecule.h
index 11a9c9a22..7b35f77d1 100644
--- a/src/molecule.h
+++ b/src/molecule.h
@@ -1,139 +1,143 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef LMP_ONE_MOLECULE_H
#define LMP_ONE_MOLEUCULE_H
#include "pointers.h"
namespace LAMMPS_NS {
class Molecule : protected Pointers {
public:
char *id;
// number of atoms,bonds,etc in molecule
int natoms;
int nbonds,nangles,ndihedrals,nimpropers;
// max bond,angle,etc per atom
int maxtype;
int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom;
int maxspecial;
// 1 if attribute defined in file, 0 if not
int xflag,typeflag,qflag,radiusflag,rmassflag;
int bondflag,angleflag,dihedralflag,improperflag;
int nspecialflag,specialflag;
int shakeflag,shakeflagflag,shakeatomflag,shaketypeflag;
// 1 if attribute defined or computed, 0 if not
int centerflag,massflag,comflag,inertiaflag;
+ // 1 if molecule fields require atom IDs
+
+ int tag_require;
+
// attributes
double **x; // displacement of each atom from origin
int *type; // type of each atom
double *q; // charge on each atom
double *radius; // radius of each atom
double *rmass; // mass of each atom
int *num_bond; // bonds, angles, dihedrals, impropers for each atom
int **bond_type;
int **bond_atom;
int *num_angle;
int **angle_type;
int **angle_atom1,**angle_atom2,**angle_atom3;
int *num_dihedral;
int **dihedral_type;
int **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4;
int *num_improper;
int **improper_type;
int **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4;
int **nspecial;
int **special;
int *shake_flag;
int **shake_atom;
int **shake_type;
double center[3]; // geometric center of molecule
double masstotal; // total mass of molecule
double com[3]; // center of mass of molecule
double itensor[6]; // moments of inertia of molecule
double inertia[3]; // principal moments of inertia of molecule
double ex[3],ey[3],ez[3]; // principal axes of molecule in space coords
double quat[4]; // quaternion for orientation of molecule
double molradius; // radius of molecule from COM,
// including finite-size particle radii
int comatom; // index (1-Natom) of atom closest to COM
double maxextent; // furthest any atom in molecule is from comatom
double **dx; // displacement of each atom relative to center
double **dxcom; // displacement of each atom relative to COM
double **dxbody; // displacement of each atom relative to COM
// in body frame (diagonalized interia tensor)
Molecule(class LAMMPS *, int, char **);
~Molecule();
void compute_center();
void compute_mass();
void compute_com();
void compute_inertia();
private:
int me;
FILE *fp;
int *count;
void read(int);
void coords(char *);
void types(char *);
void charges(char *);
void diameters(char *);
void masses(char *);
void bonds(int, char *);
void angles(int, char *);
void dihedrals(int, char *);
void impropers(int, char *);
void nspecial_read(int, char *);
void special_read(char *);
void shakeflag_read(char *);
void shakeatom_read(char *);
void shaketype_read(char *);
void initialize();
void allocate();
void deallocate();
void open(char *);
void readline(char *);
void parse_keyword(int, char *, char *);
void skip_lines(int, char *);
int parse(char *, char **, int);
// void print();
};
}
#endif
diff --git a/src/neigh_bond.cpp b/src/neigh_bond.cpp
index a73ed41b4..17a6e55fd 100644
--- a/src/neigh_bond.cpp
+++ b/src/neigh_bond.cpp
@@ -1,686 +1,690 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "atom.h"
#include "force.h"
#include "update.h"
#include "domain.h"
#include "output.h"
#include "thermo.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define BONDDELTA 10000
enum{IGNORE,WARN,ERROR}; // same as thermo.cpp
// bondlist, anglelist, dihedrallist, improperlist
// no longer store atom->map() of the bond partners
// instead store domain->closest_image() of the bond partners of atom I
// this enables distances between list atoms to be calculated
// w/out invoking domain->minimium_image(), e.g. in bond->compute()
/* ---------------------------------------------------------------------- */
void Neighbor::bond_all()
{
int i,m,atom1;
int nlocal = atom->nlocal;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nbondlist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_bond[i]; m++) {
atom1 = atom->map(bond_atom[i][m]);
if (atom1 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Bond atoms %d %d missing on proc %d at step " BIGINT_FORMAT,
+ sprintf(str,"Bond atoms " TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
tag[i],bond_atom[i][m],me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
if (newton_bond || i < atom1) {
if (nbondlist == maxbond) {
maxbond += BONDDELTA;
memory->grow(bondlist,maxbond,3,"neighbor:bondlist");
}
bondlist[nbondlist][0] = i;
bondlist[nbondlist][1] = atom1;
bondlist[nbondlist][2] = bond_type[i][m];
nbondlist++;
}
}
if (cluster_check) bond_check();
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Bond atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::bond_partial()
{
int i,m,atom1;
int nlocal = atom->nlocal;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nbondlist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_bond[i]; m++) {
if (bond_type[i][m] <= 0) continue;
atom1 = atom->map(bond_atom[i][m]);
if (atom1 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Bond atoms %d %d missing on proc %d at step " BIGINT_FORMAT,
+ sprintf(str,"Bond atoms " TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
tag[i],bond_atom[i][m],me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
if (newton_bond || i < atom1) {
if (nbondlist == maxbond) {
maxbond += BONDDELTA;
memory->grow(bondlist,maxbond,3,"neighbor:bondlist");
}
bondlist[nbondlist][0] = i;
bondlist[nbondlist][1] = atom1;
bondlist[nbondlist][2] = bond_type[i][m];
nbondlist++;
}
}
if (cluster_check) bond_check();
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Bond atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::bond_check()
{
int i,j;
double dx,dy,dz,dxstart,dystart,dzstart;
double **x = atom->x;
int flag = 0;
for (int m = 0; m < nbondlist; m++) {
i = bondlist[m][0];
j = bondlist[m][1];
dxstart = dx = x[i][0] - x[j][0];
dystart = dy = x[i][1] - x[j][1];
dzstart = dz = x[i][2] - x[j][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Bond extent > half of periodic box length");
}
/* ---------------------------------------------------------------------- */
void Neighbor::angle_all()
{
int i,m,atom1,atom2,atom3;
int nlocal = atom->nlocal;
int *num_angle = atom->num_angle;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nanglelist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_angle[i]; m++) {
atom1 = atom->map(angle_atom1[i][m]);
atom2 = atom->map(angle_atom2[i][m]);
atom3 = atom->map(angle_atom3[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Angle atoms %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Angle atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
angle_atom1[i][m],angle_atom2[i][m],angle_atom3[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3)) {
if (nanglelist == maxangle) {
maxangle += BONDDELTA;
memory->grow(anglelist,maxangle,4,"neighbor:anglelist");
}
anglelist[nanglelist][0] = atom1;
anglelist[nanglelist][1] = atom2;
anglelist[nanglelist][2] = atom3;
anglelist[nanglelist][3] = angle_type[i][m];
nanglelist++;
}
}
if (cluster_check) angle_check();
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Angle atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::angle_partial()
{
int i,m,atom1,atom2,atom3;
int nlocal = atom->nlocal;
int *num_angle = atom->num_angle;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom2 = atom->angle_atom2;
- int **angle_atom3 = atom->angle_atom3;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom2 = atom->angle_atom2;
+ tagint **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nanglelist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_angle[i]; m++) {
if (angle_type[i][m] <= 0) continue;
atom1 = atom->map(angle_atom1[i][m]);
atom2 = atom->map(angle_atom2[i][m]);
atom3 = atom->map(angle_atom3[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Angle atoms %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Angle atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
angle_atom1[i][m],angle_atom2[i][m],angle_atom3[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
if (newton_bond || (i <= atom1 && i <= atom2 && i <= atom3)) {
if (nanglelist == maxangle) {
maxangle += BONDDELTA;
memory->grow(anglelist,maxangle,4,"neighbor:anglelist");
}
anglelist[nanglelist][0] = atom1;
anglelist[nanglelist][1] = atom2;
anglelist[nanglelist][2] = atom3;
anglelist[nanglelist][3] = angle_type[i][m];
nanglelist++;
}
}
if (cluster_check) angle_check();
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Angle atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::angle_check()
{
int i,j,k;
double dx,dy,dz,dxstart,dystart,dzstart;
double **x = atom->x;
int flag = 0;
// check all 3 distances
// in case angle potential computes any of them
for (int m = 0; m < nanglelist; m++) {
i = anglelist[m][0];
j = anglelist[m][1];
k = anglelist[m][2];
dxstart = dx = x[i][0] - x[j][0];
dystart = dy = x[i][1] - x[j][1];
dzstart = dz = x[i][2] - x[j][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[i][0] - x[k][0];
dystart = dy = x[i][1] - x[k][1];
dzstart = dz = x[i][2] - x[k][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[j][0] - x[k][0];
dystart = dy = x[j][1] - x[k][1];
dzstart = dz = x[j][2] - x[k][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all) error->all(FLERR,"Angle extent > half of periodic box length");
}
/* ---------------------------------------------------------------------- */
void Neighbor::dihedral_all()
{
int i,m,atom1,atom2,atom3,atom4;
int nlocal = atom->nlocal;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
int **dihedral_type = atom->dihedral_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
ndihedrallist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_dihedral[i]; m++) {
atom1 = atom->map(dihedral_atom1[i][m]);
atom2 = atom->map(dihedral_atom2[i][m]);
atom3 = atom->map(dihedral_atom3[i][m]);
atom4 = atom->map(dihedral_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Dihedral atoms %d %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Dihedral atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
dihedral_atom1[i][m],dihedral_atom2[i][m],
dihedral_atom3[i][m],dihedral_atom4[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
atom4 = domain->closest_image(i,atom4);
if (newton_bond ||
(i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) {
if (ndihedrallist == maxdihedral) {
maxdihedral += BONDDELTA;
memory->grow(dihedrallist,maxdihedral,5,"neighbor:dihedrallist");
}
dihedrallist[ndihedrallist][0] = atom1;
dihedrallist[ndihedrallist][1] = atom2;
dihedrallist[ndihedrallist][2] = atom3;
dihedrallist[ndihedrallist][3] = atom4;
dihedrallist[ndihedrallist][4] = dihedral_type[i][m];
ndihedrallist++;
}
}
if (cluster_check) dihedral_check(ndihedrallist,dihedrallist);
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Dihedral atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::dihedral_partial()
{
int i,m,atom1,atom2,atom3,atom4;
int nlocal = atom->nlocal;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
int **dihedral_type = atom->dihedral_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
ndihedrallist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_dihedral[i]; m++) {
if (dihedral_type[i][m] <= 0) continue;
atom1 = atom->map(dihedral_atom1[i][m]);
atom2 = atom->map(dihedral_atom2[i][m]);
atom3 = atom->map(dihedral_atom3[i][m]);
atom4 = atom->map(dihedral_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Dihedral atoms %d %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Dihedral atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
dihedral_atom1[i][m],dihedral_atom2[i][m],
dihedral_atom3[i][m],dihedral_atom4[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
atom4 = domain->closest_image(i,atom4);
if (newton_bond ||
(i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) {
if (ndihedrallist == maxdihedral) {
maxdihedral += BONDDELTA;
memory->grow(dihedrallist,maxdihedral,5,"neighbor:dihedrallist");
}
dihedrallist[ndihedrallist][0] = atom1;
dihedrallist[ndihedrallist][1] = atom2;
dihedrallist[ndihedrallist][2] = atom3;
dihedrallist[ndihedrallist][3] = atom4;
dihedrallist[ndihedrallist][4] = dihedral_type[i][m];
ndihedrallist++;
}
}
if (cluster_check) dihedral_check(ndihedrallist,dihedrallist);
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Dihedral atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::dihedral_check(int nlist, int **list)
{
int i,j,k,l;
double dx,dy,dz,dxstart,dystart,dzstart;
double **x = atom->x;
int flag = 0;
// check all 6 distances
// in case dihedral/improper potential computes any of them
for (int m = 0; m < nlist; m++) {
i = list[m][0];
j = list[m][1];
k = list[m][2];
l = list[m][3];
dxstart = dx = x[i][0] - x[j][0];
dystart = dy = x[i][1] - x[j][1];
dzstart = dz = x[i][2] - x[j][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[i][0] - x[k][0];
dystart = dy = x[i][1] - x[k][1];
dzstart = dz = x[i][2] - x[k][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[i][0] - x[l][0];
dystart = dy = x[i][1] - x[l][1];
dzstart = dz = x[i][2] - x[l][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[j][0] - x[k][0];
dystart = dy = x[j][1] - x[k][1];
dzstart = dz = x[j][2] - x[k][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[j][0] - x[l][0];
dystart = dy = x[j][1] - x[l][1];
dzstart = dz = x[j][2] - x[l][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
dxstart = dx = x[k][0] - x[l][0];
dystart = dy = x[k][1] - x[l][1];
dzstart = dz = x[k][2] - x[l][2];
domain->minimum_image(dx,dy,dz);
if (dx != dxstart || dy != dystart || dz != dzstart) flag = 1;
}
int flag_all;
MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
if (flag_all)
error->all(FLERR,"Dihedral/improper extent > half of periodic box length");
}
/* ---------------------------------------------------------------------- */
void Neighbor::improper_all()
{
int i,m,atom1,atom2,atom3,atom4;
int nlocal = atom->nlocal;
int *num_improper = atom->num_improper;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
int **improper_type = atom->improper_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nimproperlist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_improper[i]; m++) {
atom1 = atom->map(improper_atom1[i][m]);
atom2 = atom->map(improper_atom2[i][m]);
atom3 = atom->map(improper_atom3[i][m]);
atom4 = atom->map(improper_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Improper atoms %d %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Improper atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
improper_atom1[i][m],improper_atom2[i][m],
improper_atom3[i][m],improper_atom4[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
atom4 = domain-> closest_image(i,atom4);
if (newton_bond ||
(i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) {
if (nimproperlist == maximproper) {
maximproper += BONDDELTA;
memory->grow(improperlist,maximproper,5,"neighbor:improperlist");
}
improperlist[nimproperlist][0] = atom1;
improperlist[nimproperlist][1] = atom2;
improperlist[nimproperlist][2] = atom3;
improperlist[nimproperlist][3] = atom4;
improperlist[nimproperlist][4] = improper_type[i][m];
nimproperlist++;
}
}
if (cluster_check) dihedral_check(nimproperlist,improperlist);
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Improper atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
/* ---------------------------------------------------------------------- */
void Neighbor::improper_partial()
{
int i,m,atom1,atom2,atom3,atom4;
int nlocal = atom->nlocal;
int *num_improper = atom->num_improper;
- int **improper_atom1 = atom->improper_atom1;
- int **improper_atom2 = atom->improper_atom2;
- int **improper_atom3 = atom->improper_atom3;
- int **improper_atom4 = atom->improper_atom4;
+ tagint **improper_atom1 = atom->improper_atom1;
+ tagint **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom3 = atom->improper_atom3;
+ tagint **improper_atom4 = atom->improper_atom4;
int **improper_type = atom->improper_type;
int newton_bond = force->newton_bond;
int lostbond = output->thermo->lostbond;
int nmissing = 0;
nimproperlist = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_improper[i]; m++) {
if (improper_type[i][m] <= 0) continue;
atom1 = atom->map(improper_atom1[i][m]);
atom2 = atom->map(improper_atom2[i][m]);
atom3 = atom->map(improper_atom3[i][m]);
atom4 = atom->map(improper_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) {
nmissing++;
if (lostbond == ERROR) {
char str[128];
- sprintf(str,
- "Improper atoms %d %d %d %d missing on proc %d at step "
- BIGINT_FORMAT,
+ sprintf(str,"Improper atoms "
+ TAGINT_FORMAT " " TAGINT_FORMAT " "
+ TAGINT_FORMAT " " TAGINT_FORMAT
+ " missing on proc %d at step " BIGINT_FORMAT,
improper_atom1[i][m],improper_atom2[i][m],
improper_atom3[i][m],improper_atom4[i][m],
me,update->ntimestep);
error->one(FLERR,str);
}
continue;
}
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
atom4 = domain->closest_image(i,atom4);
if (newton_bond ||
(i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4)) {
if (nimproperlist == maximproper) {
maximproper += BONDDELTA;
memory->grow(improperlist,maximproper,5,"neighbor:improperlist");
}
improperlist[nimproperlist][0] = atom1;
improperlist[nimproperlist][1] = atom2;
improperlist[nimproperlist][2] = atom3;
improperlist[nimproperlist][3] = atom4;
improperlist[nimproperlist][4] = improper_type[i][m];
nimproperlist++;
}
}
if (cluster_check) dihedral_check(nimproperlist,improperlist);
if (lostbond == IGNORE) return;
int all;
MPI_Allreduce(&nmissing,&all,1,MPI_INT,MPI_SUM,world);
if (all) {
char str[128];
sprintf(str,
"Improper atoms missing at step " BIGINT_FORMAT,update->ntimestep);
if (me == 0) error->warning(FLERR,str);
}
}
diff --git a/src/neigh_full.cpp b/src/neigh_full.cpp
index 0c830b372..7b536f469 100644
--- a/src/neigh_full.cpp
+++ b/src/neigh_full.cpp
@@ -1,503 +1,503 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "domain.h"
#include "my_page.h"
#include "group.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
N^2 search for all neighbors
every neighbor pair appears in list of both atoms i and j
------------------------------------------------------------------------- */
void Neighbor::full_nsq(NeighList *list)
{
int i,j,n,itype,jtype,which,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned atoms, storing neighbors
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms, owned and ghost
// skip i = j
for (j = 0; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
list->gnum = 0;
}
/* ----------------------------------------------------------------------
N^2 search for all neighbors
include neighbors of ghost atoms, but no "special neighbors" for ghosts
every neighbor pair appears in list of both atoms i and j
------------------------------------------------------------------------- */
void Neighbor::full_nsq_ghost(NeighList *list)
{
int i,j,n,itype,jtype,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned & ghost atoms, storing neighbors
for (i = 0; i < nall; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms, owned and ghost
// skip i = j
// no molecular test when i = ghost atom
if (i < nlocal) {
for (j = 0; j < nall; j++) {
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
} else {
for (j = 0; j < nall; j++) {
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = atom->nlocal;
list->gnum = inum - atom->nlocal;
}
/* ----------------------------------------------------------------------
binned neighbor list construction for all neighbors
every neighbor pair appears in list of both atoms i and j
------------------------------------------------------------------------- */
void Neighbor::full_bin(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
// bin owned & ghost atoms
bin_atoms();
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned atoms, storing neighbors
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in surrounding bins in stencil including self
// skip i = j
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
list->gnum = 0;
}
/* ----------------------------------------------------------------------
binned neighbor list construction for all neighbors
include neighbors of ghost atoms, but no "special neighbors" for ghosts
every neighbor pair appears in list of both atoms i and j
------------------------------------------------------------------------- */
void Neighbor::full_bin_ghost(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int xbin,ybin,zbin,xbin2,ybin2,zbin2;
int *neighptr;
// bin owned & ghost atoms
bin_atoms();
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
int **stencilxyz = list->stencilxyz;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned & ghost atoms, storing neighbors
for (i = 0; i < nall; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in surrounding bins in stencil including self
// when i is a ghost atom, must check if stencil bin is out of bounds
// skip i = j
// no molecular test when i = ghost atom
if (i < nlocal) {
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
} else {
ibin = coord2bin(x[i],xbin,ybin,zbin);
for (k = 0; k < nstencil; k++) {
xbin2 = xbin + stencilxyz[k][0];
ybin2 = ybin + stencilxyz[k][1];
zbin2 = zbin + stencilxyz[k][2];
if (xbin2 < 0 || xbin2 >= mbinx ||
ybin2 < 0 || ybin2 >= mbiny ||
zbin2 < 0 || zbin2 >= mbinz) continue;
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (i == j) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = atom->nlocal;
list->gnum = inum - atom->nlocal;
}
/* ----------------------------------------------------------------------
binned neighbor list construction for all neighbors
multi-type stencil is itype dependent and is distance checked
every neighbor pair appears in list of both atoms i and j
------------------------------------------------------------------------- */
void Neighbor::full_multi(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which,ns;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*s;
double *cutsq,*distsq;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int *nstencil_multi = list->nstencil_multi;
int **stencil_multi = list->stencil_multi;
double **distsq_multi = list->distsq_multi;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in other bins in stencil, including self
// skip if i,j neighbor cutoff is less than bin distance
// skip i = j
ibin = coord2bin(x[i]);
s = stencil_multi[itype];
distsq = distsq_multi[itype];
cutsq = cutneighsq[itype];
ns = nstencil_multi[itype];
for (k = 0; k < ns; k++) {
for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
jtype = type[j];
if (cutsq[jtype] < distsq[k]) continue;
if (i == j) continue;
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
list->gnum = 0;
}
diff --git a/src/neigh_gran.cpp b/src/neigh_gran.cpp
index 204988e23..465e6af86 100644
--- a/src/neigh_gran.cpp
+++ b/src/neigh_gran.cpp
@@ -1,586 +1,588 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "group.h"
#include "fix_shear_history.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
granular particles
N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
shear history must be accounted for when a neighbor pair is added
pair added to list if atoms i and j are both owned and i < j
pair added if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::granular_nsq_no_newton(NeighList *list)
{
int i,j,m,n,nn,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
double radi,radsum,cutsq;
int *neighptr,*touchptr;
double *shearptr;
NeighList *listgranhistory;
- int *npartner,**partner;
+ int *npartner;
+ tagint **partner;
double (**shearpartner)[3];
int **firsttouch;
double **firstshear;
MyPage<int> *ipage_touch;
MyPage<double> *dpage_shear;
double **x = atom->x;
double *radius = atom->radius;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
FixShearHistory *fix_history = list->fix_history;
if (fix_history) {
npartner = fix_history->npartner;
partner = fix_history->partner;
shearpartner = fix_history->shearpartner;
listgranhistory = list->listgranhistory;
firsttouch = listgranhistory->firstneigh;
firstshear = listgranhistory->firstdouble;
ipage_touch = listgranhistory->ipage;
dpage_shear = listgranhistory->dpage;
}
int inum = 0;
ipage->reset();
if (fix_history) {
ipage_touch->reset();
dpage_shear->reset();
}
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
if (fix_history) {
nn = 0;
touchptr = ipage_touch->vget();
shearptr = dpage_shear->vget();
}
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
radi = radius[i];
// loop over remaining atoms, owned and ghost
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) {
neighptr[n] = j;
if (fix_history) {
if (rsq < radsum*radsum) {
for (m = 0; m < npartner[i]; m++)
if (partner[i][m] == tag[j]) break;
if (m < npartner[i]) {
touchptr[n] = 1;
shearptr[nn++] = shearpartner[i][m][0];
shearptr[nn++] = shearpartner[i][m][1];
shearptr[nn++] = shearpartner[i][m][2];
} else {
touchptr[n] = 0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
}
} else {
touchptr[n] = 0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
}
}
n++;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (fix_history) {
firsttouch[i] = touchptr;
firstshear[i] = shearptr;
ipage_touch->vgot(n);
dpage_shear->vgot(nn);
}
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
granular particles
N^2 / 2 search for neighbor pairs with full Newton's 3rd law
no shear history is allowed for this option
pair added to list if atoms i and j are both owned and i < j
if j is ghost only me or other proc adds pair
decision based on itag,jtag tests
------------------------------------------------------------------------- */
void Neighbor::granular_nsq_newton(NeighList *list)
{
int i,j,n,itag,jtag,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
double radi,radsum,cutsq;
int *neighptr;
double **x = atom->x;
double *radius = atom->radius;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itag = tag[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
radi = radius[i];
// loop over remaining atoms, owned and ghost
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
if (j >= nlocal) {
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) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
}
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) neighptr[n++] = j;
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
granular particles
binned neighbor list construction with partial Newton's 3rd law
shear history must be accounted for when a neighbor pair is added
each owned atom i checks own bin and surrounding bins in non-Newton stencil
pair stored once if i,j are both owned and i < j
pair stored by me if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::granular_bin_no_newton(NeighList *list)
{
int i,j,k,m,n,nn,ibin;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
double radi,radsum,cutsq;
int *neighptr,*touchptr;
double *shearptr;
NeighList *listgranhistory;
- int *npartner,**partner;
+ int *npartner;
+ tagint **partner;
double (**shearpartner)[3];
int **firsttouch;
double **firstshear;
MyPage<int> *ipage_touch;
MyPage<double> *dpage_shear;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
double **x = atom->x;
double *radius = atom->radius;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
FixShearHistory *fix_history = list->fix_history;
if (fix_history) {
npartner = fix_history->npartner;
partner = fix_history->partner;
shearpartner = fix_history->shearpartner;
listgranhistory = list->listgranhistory;
firsttouch = listgranhistory->firstneigh;
firstshear = listgranhistory->firstdouble;
ipage_touch = listgranhistory->ipage;
dpage_shear = listgranhistory->dpage;
}
int inum = 0;
ipage->reset();
if (fix_history) {
ipage_touch->reset();
dpage_shear->reset();
}
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
if (fix_history) {
nn = 0;
touchptr = ipage_touch->vget();
shearptr = dpage_shear->vget();
}
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
radi = radius[i];
ibin = coord2bin(x[i]);
// loop over all atoms in surrounding bins in stencil including self
// only store pair if i < j
// stores own/own pairs only once
// stores own/ghost pairs on both procs
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) {
neighptr[n] = j;
if (fix_history) {
if (rsq < radsum*radsum) {
for (m = 0; m < npartner[i]; m++)
if (partner[i][m] == tag[j]) break;
if (m < npartner[i]) {
touchptr[n] = 1;
shearptr[nn++] = shearpartner[i][m][0];
shearptr[nn++] = shearpartner[i][m][1];
shearptr[nn++] = shearpartner[i][m][2];
} else {
touchptr[n] = 0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
}
} else {
touchptr[n] = 0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
shearptr[nn++] = 0.0;
}
}
n++;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (fix_history) {
firsttouch[i] = touchptr;
firstshear[i] = shearptr;
ipage_touch->vgot(n);
dpage_shear->vgot(nn);
}
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
granular particles
binned neighbor list construction with full Newton's 3rd law
no shear history is allowed for this option
each owned atom i checks its own bin and other bins in Newton stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::granular_bin_newton(NeighList *list)
{
int i,j,k,n,ibin;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
double radi,radsum,cutsq;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
double **x = atom->x;
double *radius = atom->radius;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
radi = radius[i];
// loop over rest of atoms in i's bin, ghosts are at end of linked list
// if j is owned atom, store it, since j is beyond i in linked list
// if j is ghost, only store if j coords are "above and to the right" of i
for (j = bins[i]; j >= 0; j = bins[j]) {
if (j >= nlocal) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) neighptr[n++] = j;
}
// loop over all atoms in other bins in stencil, store every pair
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
granular particles
binned neighbor list construction with Newton's 3rd law for triclinic
no shear history is allowed for this option
each owned atom i checks its own bin and other bins in triclinic stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::granular_bin_newton_tri(NeighList *list)
{
int i,j,k,n,ibin;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
double radi,radsum,cutsq;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
double **x = atom->x;
double *radius = atom->radius;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
radi = radius[i];
// loop over all atoms in bins in stencil
// pairs for atoms j "below" i are excluded
// below = lower z or (equal z and lower y) or (equal zy and lower x)
// (equal zyx and j <= i)
// latter excludes self-self interaction but allows superposed atoms
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp) {
if (x[j][0] < xtmp) continue;
if (x[j][0] == xtmp && j <= i) continue;
}
}
if (exclude && exclusion(i,j,type[i],type[j],mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
radsum = radi + radius[j];
cutsq = (radsum+skin) * (radsum+skin);
if (rsq <= cutsq) neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
diff --git a/src/neigh_half_bin.cpp b/src/neigh_half_bin.cpp
index ef55cb5ba..75736e97d 100644
--- a/src/neigh_half_bin.cpp
+++ b/src/neigh_half_bin.cpp
@@ -1,456 +1,456 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "domain.h"
#include "my_page.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
binned neighbor list construction with partial Newton's 3rd law
each owned atom i checks own bin and other bins in stencil
pair stored once if i,j are both owned and i < j
pair stored by me if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::half_bin_no_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in other bins in stencil including self
// only store pair if i < j
// stores own/own pairs only once
// stores own/ghost pairs on both procs
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
binned neighbor list construction with partial Newton's 3rd law
include neighbors of ghost atoms, but no "special neighbors" for ghosts
owned and ghost atoms check own bin and other bins in stencil
pair stored once if i,j are both owned and i < j
pair stored by me if i owned and j ghost (also stored by proc owning j)
pair stored once if i,j are both ghost and i < j
------------------------------------------------------------------------- */
void Neighbor::half_bin_no_newton_ghost(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int xbin,ybin,zbin,xbin2,ybin2,zbin2;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
int **stencilxyz = list->stencilxyz;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nall; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in other bins in stencil including self
// when i is a ghost atom, must check if stencil bin is out of bounds
// only store pair if i < j
// stores own/own pairs only once
// stores own/ghost pairs with owned atom only, on both procs
// stores ghost/ghost pairs only once
// no molecular test when i = ghost atom
if (i < nlocal) {
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
} else {
ibin = coord2bin(x[i],xbin,ybin,zbin);
for (k = 0; k < nstencil; k++) {
xbin2 = xbin + stencilxyz[k][0];
ybin2 = ybin + stencilxyz[k][1];
zbin2 = zbin + stencilxyz[k][2];
if (xbin2 < 0 || xbin2 >= mbinx ||
ybin2 < 0 || ybin2 >= mbiny ||
zbin2 < 0 || zbin2 >= mbinz) continue;
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighghostsq[itype][jtype]) neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = atom->nlocal;
list->gnum = inum - atom->nlocal;
}
/* ----------------------------------------------------------------------
binned neighbor list construction with full Newton's 3rd law
each owned atom i checks its own bin and other bins in Newton stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::half_bin_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over rest of atoms in i's bin, ghosts are at end of linked list
// if j is owned atom, store it, since j is beyond i in linked list
// if j is ghost, only store if j coords are "above and to the right" of i
for (j = bins[i]; j >= 0; j = bins[j]) {
if (j >= nlocal) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
// OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
// loop over all atoms in other bins in stencil, store every pair
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
// OLD: if (which >= 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
binned neighbor list construction with Newton's 3rd law for triclinic
each owned atom i checks its own bin and other bins in triclinic stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::half_bin_newton_tri(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
if (includegroup) nlocal = atom->nfirst;
int molecular = atom->molecular;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in bins in stencil
// pairs for atoms j "below" i are excluded
// below = lower z or (equal z and lower y) or (equal zy and lower x)
// (equal zyx and j <= i)
// latter excludes self-self interaction but allows superposed atoms
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp) {
if (x[j][0] < xtmp) continue;
if (x[j][0] == xtmp && j <= i) continue;
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
diff --git a/src/neigh_half_multi.cpp b/src/neigh_half_multi.cpp
index 46a76be6d..fddc683fb 100644
--- a/src/neigh_half_multi.cpp
+++ b/src/neigh_half_multi.cpp
@@ -1,356 +1,356 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "domain.h"
#include "my_page.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
binned neighbor list construction with partial Newton's 3rd law
each owned atom i checks own bin and other bins in stencil
multi-type stencil is itype dependent and is distance checked
pair stored once if i,j are both owned and i < j
pair stored by me if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::half_multi_no_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which,ns;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*s;
double *cutsq,*distsq;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int *nstencil_multi = list->nstencil_multi;
int **stencil_multi = list->stencil_multi;
double **distsq_multi = list->distsq_multi;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in other bins in stencil including self
// only store pair if i < j
// skip if i,j neighbor cutoff is less than bin distance
// stores own/own pairs only once
// stores own/ghost pairs on both procs
ibin = coord2bin(x[i]);
s = stencil_multi[itype];
distsq = distsq_multi[itype];
cutsq = cutneighsq[itype];
ns = nstencil_multi[itype];
for (k = 0; k < ns; k++) {
for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
jtype = type[j];
if (cutsq[jtype] < distsq[k]) continue;
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
binned neighbor list construction with full Newton's 3rd law
each owned atom i checks its own bin and other bins in Newton stencil
multi-type stencil is itype dependent and is distance checked
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::half_multi_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which,ns;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*s;
double *cutsq,*distsq;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int *nstencil_multi = list->nstencil_multi;
int **stencil_multi = list->stencil_multi;
double **distsq_multi = list->distsq_multi;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over rest of atoms in i's bin, ghosts are at end of linked list
// if j is owned atom, store it, since j is beyond i in linked list
// if j is ghost, only store if j coords are "above and to the right" of i
for (j = bins[i]; j >= 0; j = bins[j]) {
if (j >= nlocal) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
// loop over all atoms in other bins in stencil, store every pair
// skip if i,j neighbor cutoff is less than bin distance
ibin = coord2bin(x[i]);
s = stencil_multi[itype];
distsq = distsq_multi[itype];
cutsq = cutneighsq[itype];
ns = nstencil_multi[itype];
for (k = 0; k < ns; k++) {
for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
jtype = type[j];
if (cutsq[jtype] < distsq[k]) continue;
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
binned neighbor list construction with Newton's 3rd law for triclinic
each owned atom i checks its own bin and other bins in triclinic stencil
multi-type stencil is itype dependent and is distance checked
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::half_multi_newton_tri(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,which,ns;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*s;
double *cutsq,*distsq;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int *nstencil_multi = list->nstencil_multi;
int **stencil_multi = list->stencil_multi;
double **distsq_multi = list->distsq_multi;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in bins, including self, in stencil
// skip if i,j neighbor cutoff is less than bin distance
// bins below self are excluded from stencil
// pairs for atoms j "below" i are excluded
// below = lower z or (equal z and lower y) or (equal zy and lower x)
// (equal zyx and j <= i)
// latter excludes self-self interaction but allows superposed atoms
ibin = coord2bin(x[i]);
s = stencil_multi[itype];
distsq = distsq_multi[itype];
cutsq = cutneighsq[itype];
ns = nstencil_multi[itype];
for (k = 0; k < ns; k++) {
for (j = binhead[ibin+s[k]]; j >= 0; j = bins[j]) {
jtype = type[j];
if (cutsq[jtype] < distsq[k]) continue;
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp) {
if (x[j][0] < xtmp) continue;
if (x[j][0] == xtmp && j <= i) continue;
}
}
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
diff --git a/src/neigh_half_nsq.cpp b/src/neigh_half_nsq.cpp
index 8446c9d98..f8fad972b 100644
--- a/src/neigh_half_nsq.cpp
+++ b/src/neigh_half_nsq.cpp
@@ -1,307 +1,307 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "domain.h"
#include "group.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
pair stored once if i,j are both owned and i < j
pair stored by me if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::half_nsq_no_newton(NeighList *list)
{
int i,j,n,itype,jtype,which,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned atoms, storing neighbors
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over remaining atoms, owned and ghost
// only store pair if i < j
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
/* ----------------------------------------------------------------------
N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
include neighbors of ghost atoms, but no "special neighbors" for ghosts
pair stored once if i,j are both owned and i < j
pair stored by me if i owned and j ghost (also stored by proc owning j)
pair stored once if i,j are both ghost and i < j
------------------------------------------------------------------------- */
void Neighbor::half_nsq_no_newton_ghost(NeighList *list)
{
int i,j,n,itype,jtype,which,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
// loop over owned & ghost atoms, storing neighbors
for (i = 0; i < nall; i++) {
n = 0;
neighptr = ipage->vget();
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over remaining atoms, owned and ghost
// only store pair if i < j
// stores own/own pairs only once
// stores own/ghost pairs with owned atom only, on both procs
// stores ghost/ghost pairs only once
// no molecular test when i = ghost atom
if (i < nlocal) {
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
} else {
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = atom->nlocal;
list->gnum = inum - atom->nlocal;
}
/* ----------------------------------------------------------------------
N^2 / 2 search for neighbor pairs with full Newton's 3rd law
every pair stored exactly once by some processor
decision on ghost atoms based on itag,jtag tests
------------------------------------------------------------------------- */
void Neighbor::half_nsq_newton(NeighList *list)
{
int i,j,n,itype,jtype,itag,jtag,which,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr;
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
int inum = 0;
ipage->reset();
for (i = 0; i < nlocal; i++) {
n = 0;
neighptr = ipage->vget();
itag = tag[i];
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over remaining atoms, owned and ghost
// itag = jtag is possible for long cutoffs that include images of self
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
if (j >= nlocal) {
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) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if (domain->minimum_image_check(delx,dely,delz))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
}
}
ilist[inum++] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
list->inum = inum;
}
diff --git a/src/neigh_respa.cpp b/src/neigh_respa.cpp
index 41ee06c9e..346a893af 100644
--- a/src/neigh_respa.cpp
+++ b/src/neigh_respa.cpp
@@ -1,834 +1,834 @@
/* ----------------------------------------------------------------------
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 "neighbor.h"
#include "neigh_list.h"
#include "atom.h"
#include "domain.h"
#include "group.h"
#include "my_page.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ----------------------------------------------------------------------
multiple respa lists
N^2 / 2 search for neighbor pairs with partial Newton's 3rd law
pair added to list if atoms i and j are both owned and i < j
pair added if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::respa_nsq_no_newton(NeighList *list)
{
int i,j,n,itype,jtype,n_inner,n_middle,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*neighptr_inner,*neighptr_middle;
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
NeighList *listinner = list->listinner;
int *ilist_inner = listinner->ilist;
int *numneigh_inner = listinner->numneigh;
int **firstneigh_inner = listinner->firstneigh;
MyPage<int> *ipage_inner = listinner->ipage;
NeighList *listmiddle;
int *ilist_middle,*numneigh_middle,**firstneigh_middle;
MyPage<int> *ipage_middle;
int respamiddle = list->respamiddle;
if (respamiddle) {
listmiddle = list->listmiddle;
ilist_middle = listmiddle->ilist;
numneigh_middle = listmiddle->numneigh;
firstneigh_middle = listmiddle->firstneigh;
ipage_middle = listmiddle->ipage;
}
int inum = 0;
int which = 0;
int minchange = 0;
ipage->reset();
ipage_inner->reset();
if (respamiddle) ipage_middle->reset();
for (i = 0; i < nlocal; i++) {
n = n_inner = 0;
neighptr = ipage->vget();
neighptr_inner = ipage_inner->vget();
if (respamiddle) {
n_middle = 0;
neighptr_middle = ipage_middle->vget();
}
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over remaining atoms, owned and ghost
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle && rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
ilist[inum] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
ilist_inner[inum] = i;
firstneigh_inner[i] = neighptr_inner;
numneigh_inner[i] = n_inner;
ipage_inner->vgot(n_inner);
if (ipage_inner->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (respamiddle) {
ilist_middle[inum] = i;
firstneigh_middle[i] = neighptr_middle;
numneigh_middle[i] = n_middle;
ipage_middle->vgot(n_middle);
if (ipage_middle->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
inum++;
}
list->inum = inum;
listinner->inum = inum;
if (respamiddle) listmiddle->inum = inum;
}
/* ----------------------------------------------------------------------
multiple respa lists
N^2 / 2 search for neighbor pairs with full Newton's 3rd law
pair added to list if atoms i and j are both owned and i < j
if j is ghost only me or other proc adds pair
decision based on itag,jtag tests
------------------------------------------------------------------------- */
void Neighbor::respa_nsq_newton(NeighList *list)
{
int i,j,n,itype,jtype,itag,jtag,n_inner,n_middle,bitmask;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*neighptr_inner,*neighptr_middle;
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int nall = nlocal + atom->nghost;
int molecular = atom->molecular;
if (includegroup) {
nlocal = atom->nfirst;
bitmask = group->bitmask[includegroup];
}
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
MyPage<int> *ipage = list->ipage;
NeighList *listinner = list->listinner;
int *ilist_inner = listinner->ilist;
int *numneigh_inner = listinner->numneigh;
int **firstneigh_inner = listinner->firstneigh;
MyPage<int> *ipage_inner = listinner->ipage;
NeighList *listmiddle;
int *ilist_middle,*numneigh_middle,**firstneigh_middle;
MyPage<int> *ipage_middle;
int respamiddle = list->respamiddle;
if (respamiddle) {
listmiddle = list->listmiddle;
ilist_middle = listmiddle->ilist;
numneigh_middle = listmiddle->numneigh;
firstneigh_middle = listmiddle->firstneigh;
ipage_middle = listmiddle->ipage;
}
int inum = 0;
int which = 0;
int minchange = 0;
ipage->reset();
ipage_inner->reset();
if (respamiddle) ipage_middle->reset();
for (i = 0; i < nlocal; i++) {
n = n_inner = 0;
neighptr = ipage->vget();
neighptr_inner = ipage_inner->vget();
if (respamiddle) {
n_middle = 0;
neighptr_middle = ipage_middle->vget();
}
itag = tag[i];
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over remaining atoms, owned and ghost
for (j = i+1; j < nall; j++) {
if (includegroup && !(mask[j] & bitmask)) continue;
if (j >= nlocal) {
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) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle &&
rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
ilist[inum] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
ilist_inner[inum] = i;
firstneigh_inner[i] = neighptr_inner;
numneigh_inner[i] = n_inner;
ipage_inner->vgot(n_inner);
if (ipage_inner->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (respamiddle) {
ilist_middle[inum] = i;
firstneigh_middle[i] = neighptr_middle;
numneigh_middle[i] = n_middle;
ipage_middle->vgot(n_middle);
if (ipage_middle->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
inum++;
}
list->inum = inum;
listinner->inum = inum;
if (respamiddle) listmiddle->inum = inum;
}
/* ----------------------------------------------------------------------
multiple respa lists
binned neighbor list construction with partial Newton's 3rd law
each owned atom i checks own bin and surrounding bins in non-Newton stencil
pair stored once if i,j are both owned and i < j
pair stored by me if j is ghost (also stored by proc owning j)
------------------------------------------------------------------------- */
void Neighbor::respa_bin_no_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*neighptr_inner,*neighptr_middle;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
NeighList *listinner = list->listinner;
int *ilist_inner = listinner->ilist;
int *numneigh_inner = listinner->numneigh;
int **firstneigh_inner = listinner->firstneigh;
MyPage<int> *ipage_inner = listinner->ipage;
NeighList *listmiddle;
int *ilist_middle,*numneigh_middle,**firstneigh_middle;
MyPage<int> *ipage_middle;
int respamiddle = list->respamiddle;
if (respamiddle) {
listmiddle = list->listmiddle;
ilist_middle = listmiddle->ilist;
numneigh_middle = listmiddle->numneigh;
firstneigh_middle = listmiddle->firstneigh;
ipage_middle = listmiddle->ipage;
}
int inum = 0;
int which = 0;
int minchange = 0;
ipage->reset();
ipage_inner->reset();
if (respamiddle) ipage_middle->reset();
for (i = 0; i < nlocal; i++) {
n = n_inner = 0;
neighptr = ipage->vget();
neighptr_inner = ipage_inner->vget();
if (respamiddle) {
n_middle = 0;
neighptr_middle = ipage_middle->vget();
}
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
ibin = coord2bin(x[i]);
// loop over all atoms in surrounding bins in stencil including self
// only store pair if i < j
// stores own/own pairs only once
// stores own/ghost pairs on both procs
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (j <= i) continue;
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0)
neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle &&
rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
}
ilist[inum] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
ilist_inner[inum] = i;
firstneigh_inner[i] = neighptr_inner;
numneigh_inner[i] = n_inner;
ipage_inner->vgot(n_inner);
if (ipage_inner->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (respamiddle) {
ilist_middle[inum] = i;
firstneigh_middle[i] = neighptr_middle;
numneigh_middle[i] = n_middle;
ipage_middle->vgot(n_middle);
if (ipage_middle->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
inum++;
}
list->inum = inum;
listinner->inum = inum;
if (respamiddle) listmiddle->inum = inum;
}
/* ----------------------------------------------------------------------
multiple respa lists
binned neighbor list construction with full Newton's 3rd law
each owned atom i checks its own bin and other bins in Newton stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::respa_bin_newton(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*neighptr_inner,*neighptr_middle;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
NeighList *listinner = list->listinner;
int *ilist_inner = listinner->ilist;
int *numneigh_inner = listinner->numneigh;
int **firstneigh_inner = listinner->firstneigh;
MyPage<int> *ipage_inner = listinner->ipage;
NeighList *listmiddle;
int *ilist_middle,*numneigh_middle,**firstneigh_middle;
MyPage<int> *ipage_middle;
int respamiddle = list->respamiddle;
if (respamiddle) {
listmiddle = list->listmiddle;
ilist_middle = listmiddle->ilist;
numneigh_middle = listmiddle->numneigh;
firstneigh_middle = listmiddle->firstneigh;
ipage_middle = listmiddle->ipage;
}
int inum = 0;
int which = 0;
int minchange = 0;
ipage->reset();
ipage_inner->reset();
if (respamiddle) ipage_middle->reset();
for (i = 0; i < nlocal; i++) {
n = n_inner = 0;
neighptr = ipage->vget();
neighptr_inner = ipage_inner->vget();
if (respamiddle) {
n_middle = 0;
neighptr_middle = ipage_middle->vget();
}
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over rest of atoms in i's bin, ghosts are at end of linked list
// if j is owned atom, store it, since j is beyond i in linked list
// if j is ghost, only store if j coords are "above and to the right" of i
for (j = bins[i]; j >= 0; j = bins[j]) {
if (j >= nlocal) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp && x[j][0] < xtmp) continue;
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0) neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle &&
rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
// loop over all atoms in other bins in stencil, store every pair
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0)
neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle &&
rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
}
ilist[inum] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
ilist_inner[inum] = i;
firstneigh_inner[i] = neighptr_inner;
numneigh_inner[i] = n_inner;
ipage_inner->vgot(n_inner);
if (ipage_inner->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (respamiddle) {
ilist_middle[inum] = i;
firstneigh_middle[i] = neighptr_middle;
numneigh_middle[i] = n_middle;
ipage_middle->vgot(n_middle);
if (ipage_middle->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
inum++;
}
list->inum = inum;
listinner->inum = inum;
if (respamiddle) listmiddle->inum = inum;
}
/* ----------------------------------------------------------------------
multiple respa lists
binned neighbor list construction with Newton's 3rd law for triclinic
each owned atom i checks its own bin and other bins in triclinic stencil
every pair stored exactly once by some processor
------------------------------------------------------------------------- */
void Neighbor::respa_bin_newton_tri(NeighList *list)
{
int i,j,k,n,itype,jtype,ibin,n_inner,n_middle;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
int *neighptr,*neighptr_inner,*neighptr_middle;
// bin local & ghost atoms
bin_atoms();
// loop over each atom, storing neighbors
- int **special = atom->special;
+ tagint **special = atom->special;
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
double **x = atom->x;
int *type = atom->type;
int *mask = atom->mask;
int *molecule = atom->molecule;
int nlocal = atom->nlocal;
int molecular = atom->molecular;
if (includegroup) nlocal = atom->nfirst;
int *ilist = list->ilist;
int *numneigh = list->numneigh;
int **firstneigh = list->firstneigh;
int nstencil = list->nstencil;
int *stencil = list->stencil;
MyPage<int> *ipage = list->ipage;
NeighList *listinner = list->listinner;
int *ilist_inner = listinner->ilist;
int *numneigh_inner = listinner->numneigh;
int **firstneigh_inner = listinner->firstneigh;
MyPage<int> *ipage_inner = listinner->ipage;
NeighList *listmiddle;
int *ilist_middle,*numneigh_middle,**firstneigh_middle;
MyPage<int> *ipage_middle;
int respamiddle = list->respamiddle;
if (respamiddle) {
listmiddle = list->listmiddle;
ilist_middle = listmiddle->ilist;
numneigh_middle = listmiddle->numneigh;
firstneigh_middle = listmiddle->firstneigh;
ipage_middle = listmiddle->ipage;
}
int inum = 0;
int which = 0;
int minchange = 0;
ipage->reset();
ipage_inner->reset();
if (respamiddle) ipage_middle->reset();
for (i = 0; i < nlocal; i++) {
n = n_inner = 0;
neighptr = ipage->vget();
neighptr_inner = ipage_inner->vget();
if (respamiddle) {
n_middle = 0;
neighptr_middle = ipage_middle->vget();
}
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
// loop over all atoms in bins in stencil
// pairs for atoms j "below" i are excluded
// below = lower z or (equal z and lower y) or (equal zy and lower x)
// (equal zyx and j <= i)
// latter excludes self-self interaction but allows superposed atoms
ibin = coord2bin(x[i]);
for (k = 0; k < nstencil; k++) {
for (j = binhead[ibin+stencil[k]]; j >= 0; j = bins[j]) {
if (x[j][2] < ztmp) continue;
if (x[j][2] == ztmp) {
if (x[j][1] < ytmp) continue;
if (x[j][1] == ytmp) {
if (x[j][0] < xtmp) continue;
if (x[j][0] == xtmp && j <= i) continue;
}
}
jtype = type[j];
if (exclude && exclusion(i,j,itype,jtype,mask,molecule)) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutneighsq[itype][jtype]) {
if (molecular) {
which = find_special(special[i],nspecial[i],tag[j]);
if (which == 0) neighptr[n++] = j;
else if ((minchange = domain->minimum_image_check(delx,dely,delz)))
neighptr[n++] = j;
else if (which > 0) neighptr[n++] = j ^ (which << SBBITS);
} else neighptr[n++] = j;
if (rsq < cut_inner_sq) {
if (which == 0) neighptr_inner[n_inner++] = j;
else if (minchange) neighptr_inner[n_inner++] = j;
else if (which > 0)
neighptr_inner[n_inner++] = j ^ (which << SBBITS);
}
if (respamiddle &&
rsq < cut_middle_sq && rsq > cut_middle_inside_sq) {
if (which == 0) neighptr_middle[n_middle++] = j;
else if (minchange) neighptr_middle[n_middle++] = j;
else if (which > 0)
neighptr_middle[n_middle++] = j ^ (which << SBBITS);
}
}
}
}
ilist[inum] = i;
firstneigh[i] = neighptr;
numneigh[i] = n;
ipage->vgot(n);
if (ipage->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
ilist_inner[inum] = i;
firstneigh_inner[i] = neighptr_inner;
numneigh_inner[i] = n_inner;
ipage_inner->vgot(n_inner);
if (ipage_inner->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
if (respamiddle) {
ilist_middle[inum] = i;
firstneigh_middle[i] = neighptr_middle;
numneigh_middle[i] = n_middle;
ipage_middle->vgot(n_middle);
if (ipage_middle->status())
error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
}
inum++;
}
list->inum = inum;
listinner->inum = inum;
if (respamiddle) listmiddle->inum = inum;
}
diff --git a/src/neighbor.h b/src/neighbor.h
index 13590dd47..751e15523 100644
--- a/src/neighbor.h
+++ b/src/neighbor.h
@@ -1,407 +1,407 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_NEIGHBOR_H
#define LMP_NEIGHBOR_H
#include "pointers.h"
namespace LAMMPS_NS {
class Neighbor : protected Pointers {
friend class Cuda;
public:
int style; // 0,1,2 = nsq, bin, multi
int every; // build every this many steps
int delay; // delay build for this many steps
int dist_check; // 0 = always build, 1 = only if 1/2 dist
int ago; // how many steps ago neighboring occurred
int pgsize; // size of neighbor page
int oneatom; // max # of neighbors for one atom
int includegroup; // only build pairwise lists for this group
int build_once; // 1 if only build lists once per run
int cudable; // GPU <-> CPU communication flag for CUDA
double skin; // skin distance
double cutneighmin; // min neighbor cutoff for all type pairs
double cutneighmax; // max neighbor cutoff for all type pairs
double *cuttype; // for each type, max neigh cut w/ others
bigint ncalls; // # of times build has been called
bigint ndanger; // # of dangerous builds
bigint lastcall; // timestep of last neighbor::build() call
int nrequest; // requests for pairwise neighbor lists
class NeighRequest **requests; // from Pair, Fix, Compute, Command classes
int maxrequest;
int old_style; // previous run info to avoid
int old_nrequest; // re-creation of pairwise neighbor lists
int old_triclinic;
int old_pgsize;
int old_oneatom;
class NeighRequest **old_requests;
int nlist; // pairwise neighbor lists
class NeighList **lists;
int nbondlist; // list of bonds to compute
int **bondlist;
int nanglelist; // list of angles to compute
int **anglelist;
int ndihedrallist; // list of dihedrals to compute
int **dihedrallist;
int nimproperlist; // list of impropers to compute
int **improperlist;
Neighbor(class LAMMPS *);
virtual ~Neighbor();
virtual void init();
int request(void *); // another class requests a neighbor list
void print_lists_of_lists(); // debug print out
int decide(); // decide whether to build or not
virtual int check_distance(); // check max distance moved since last build
void setup_bins(); // setup bins based on box and cutoff
virtual void build(int topoflag=1); // create all neighbor lists (pair,bond)
virtual void build_topology(); // create all topology neighbor lists
void build_one(int); // create a single neighbor list
void set(int, char **); // set neighbor style and skin distance
void modify_params(int, char**); // modify parameters that control builds
bigint memory_usage();
int exclude_setting();
protected:
int me,nprocs;
int maxatom; // size of atom-based NeighList arrays
int maxbond,maxangle,maxdihedral,maximproper; // size of bond lists
int maxwt; // max weighting factor applied + 1
int must_check; // 1 if must check other classes to reneigh
int restart_check; // 1 if restart enabled, 0 if no
int fix_check; // # of fixes that induce reneigh
int *fixchecklist; // which fixes to check
double **cutneighsq; // neighbor cutneigh sq for each type pair
double **cutneighghostsq; // neighbor cutnsq for each ghost type pair
double cutneighmaxsq; // cutneighmax squared
double *cuttypesq; // cuttype squared
double triggersq; // trigger = build when atom moves this dist
int cluster_check; // 1 if check bond/angle/etc satisfies minimg
double **xhold; // atom coords at last neighbor build
int maxhold; // size of xhold array
int boxcheck; // 1 if need to store box size
double boxlo_hold[3],boxhi_hold[3]; // box size at last neighbor build
double corners_hold[8][3]; // box corners at last neighbor build
int nbinx,nbiny,nbinz; // # of global bins
int *bins; // ptr to next atom in each bin
int maxbin; // size of bins array
int *binhead; // ptr to 1st atom in each bin
int maxhead; // size of binhead array
int mbins; // # of local bins and offset
int mbinx,mbiny,mbinz;
int mbinxlo,mbinylo,mbinzlo;
int binsizeflag; // user-chosen bin size
double binsize_user;
double binsizex,binsizey,binsizez; // actual bin sizes and inverse sizes
double bininvx,bininvy,bininvz;
int sx,sy,sz,smax; // bin stencil extents
int dimension; // 2/3 for 2d/3d
int triclinic; // 0 if domain is orthog, 1 if triclinic
int newton_pair; // 0 if newton off, 1 if on for pairwise
double *bboxlo,*bboxhi; // ptrs to full domain bounding box
double (*corners)[3]; // ptr to 8 corners of triclinic box
double inner[2],middle[2]; // rRESPA cutoffs for extra lists
double cut_inner_sq; // outer cutoff for inner neighbor list
double cut_middle_sq; // outer cutoff for middle neighbor list
double cut_middle_inside_sq; // inner cutoff for middle neighbor list
int special_flag[4]; // flags for 1-2, 1-3, 1-4 neighbors
int anyghostlist; // 1 if any non-occasional list
// stores neighbors of ghosts
int exclude; // 0 if no type/group exclusions, 1 if yes
int nex_type; // # of entries in type exclusion list
int maxex_type; // max # in type list
int *ex1_type,*ex2_type; // pairs of types to exclude
int **ex_type; // 2d array of excluded type pairs
int nex_group; // # of entries in group exclusion list
int maxex_group; // max # in group list
int *ex1_group,*ex2_group; // pairs of group #'s to exclude
int *ex1_bit,*ex2_bit; // pairs of group bits to exclude
int nex_mol; // # of entries in molecule exclusion list
int maxex_mol; // max # in molecule list
int *ex_mol_group; // molecule group #'s to exclude
int *ex_mol_bit; // molecule group bits to exclude
int nblist,nglist,nslist; // # of pairwise neigh lists of various kinds
int *blist; // lists to build every reneighboring
int *glist; // lists to grow atom arrays every reneigh
int *slist; // lists to grow stencil arrays every reneigh
void bin_atoms(); // bin all atoms
double bin_distance(int, int, int); // distance between binx
int coord2bin(double *); // mapping atom coord to a bin
int coord2bin(double *, int &, int &, int&); // ditto
int exclusion(int, int, int,
int, int *, int *) const; // test for pair exclusion
virtual void choose_build(int, class NeighRequest *);
void choose_stencil(int, class NeighRequest *);
// pairwise build functions
typedef void (Neighbor::*PairPtr)(class NeighList *);
PairPtr *pair_build;
void half_nsq_no_newton(class NeighList *);
void half_nsq_no_newton_ghost(class NeighList *);
void half_nsq_newton(class NeighList *);
void half_bin_no_newton(class NeighList *);
void half_bin_no_newton_ghost(class NeighList *);
void half_bin_newton(class NeighList *);
void half_bin_newton_tri(class NeighList *);
void half_multi_no_newton(class NeighList *);
void half_multi_newton(class NeighList *);
void half_multi_newton_tri(class NeighList *);
void full_nsq(class NeighList *);
void full_nsq_ghost(class NeighList *);
void full_bin(class NeighList *);
void full_bin_ghost(class NeighList *);
void full_multi(class NeighList *);
void half_from_full_no_newton(class NeighList *);
void half_from_full_newton(class NeighList *);
void skip_from(class NeighList *);
void skip_from_granular(class NeighList *);
void skip_from_respa(class NeighList *);
void copy_from(class NeighList *);
void granular_nsq_no_newton(class NeighList *);
void granular_nsq_newton(class NeighList *);
void granular_bin_no_newton(class NeighList *);
void granular_bin_newton(class NeighList *);
void granular_bin_newton_tri(class NeighList *);
void respa_nsq_no_newton(class NeighList *);
void respa_nsq_newton(class NeighList *);
void respa_bin_no_newton(class NeighList *);
void respa_bin_newton(class NeighList *);
void respa_bin_newton_tri(class NeighList *);
// include prototypes for multi-threaded neighbor lists
// builds or their corresponding dummy versions
#define LMP_INSIDE_NEIGHBOR_H
#include "accelerator_omp.h"
#undef LMP_INSIDE_NEIGHBOR_H
// pairwise stencil creation functions
typedef void (Neighbor::*StencilPtr)(class NeighList *, int, int, int);
StencilPtr *stencil_create;
void stencil_half_bin_2d_no_newton(class NeighList *, int, int, int);
void stencil_half_ghost_bin_2d_no_newton(class NeighList *, int, int, int);
void stencil_half_bin_3d_no_newton(class NeighList *, int, int, int);
void stencil_half_ghost_bin_3d_no_newton(class NeighList *, int, int, int);
void stencil_half_bin_2d_newton(class NeighList *, int, int, int);
void stencil_half_bin_3d_newton(class NeighList *, int, int, int);
void stencil_half_bin_2d_newton_tri(class NeighList *, int, int, int);
void stencil_half_bin_3d_newton_tri(class NeighList *, int, int, int);
void stencil_half_multi_2d_no_newton(class NeighList *, int, int, int);
void stencil_half_multi_3d_no_newton(class NeighList *, int, int, int);
void stencil_half_multi_2d_newton(class NeighList *, int, int, int);
void stencil_half_multi_3d_newton(class NeighList *, int, int, int);
void stencil_half_multi_2d_newton_tri(class NeighList *, int, int, int);
void stencil_half_multi_3d_newton_tri(class NeighList *, int, int, int);
void stencil_full_bin_2d(class NeighList *, int, int, int);
void stencil_full_ghost_bin_2d(class NeighList *, int, int, int);
void stencil_full_bin_3d(class NeighList *, int, int, int);
void stencil_full_ghost_bin_3d(class NeighList *, int, int, int);
void stencil_full_multi_2d(class NeighList *, int, int, int);
void stencil_full_multi_3d(class NeighList *, int, int, int);
// topology build functions
typedef void (Neighbor::*BondPtr)(); // ptrs to topology build functions
BondPtr bond_build; // ptr to bond list functions
void bond_all(); // bond list with all bonds
void bond_partial(); // exclude certain bonds
void bond_check();
BondPtr angle_build; // ptr to angle list functions
void angle_all(); // angle list with all angles
void angle_partial(); // exclude certain angles
void angle_check();
BondPtr dihedral_build; // ptr to dihedral list functions
void dihedral_all(); // dihedral list with all dihedrals
void dihedral_partial(); // exclude certain dihedrals
void dihedral_check(int, int **);
BondPtr improper_build; // ptr to improper list functions
void improper_all(); // improper list with all impropers
void improper_partial(); // exclude certain impropers
// find_special: determine if atom j is in special list of atom i
// if it is not, return 0
// if it is and special flag is 0 (both coeffs are 0.0), return -1
// if it is and special flag is 1 (both coeffs are 1.0), return 0
// if it is and special flag is 2 (otherwise), return 1,2,3
// for which level of neighbor it is (and which coeff it maps to)
- inline int find_special(const int *list, const int *nspecial,
- const int tag) const {
+ inline int find_special(const tagint *list, const int *nspecial,
+ const tagint tag) const {
const int n1 = nspecial[0];
const int n2 = nspecial[1];
const int n3 = nspecial[2];
for (int i = 0; i < n3; i++) {
if (list[i] == tag) {
if (i < n1) {
if (special_flag[1] == 0) return -1;
else if (special_flag[1] == 1) return 0;
else return 1;
} else if (i < n2) {
if (special_flag[2] == 0) return -1;
else if (special_flag[2] == 1) return 0;
else return 2;
} else {
if (special_flag[3] == 0) return -1;
else if (special_flag[3] == 1) return 0;
else return 3;
}
}
}
return 0;
};
};
}
#endif
/* ERROR/WARNING messages:
E: Neighbor delay must be 0 or multiple of every setting
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.
E: Neighbor page size must be >= 10x the one atom setting
This is required to prevent wasting too much memory.
E: Invalid atom type in neighbor exclusion list
Atom types must range from 1 to Ntypes inclusive.
W: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies
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.
E: Neighbor include group not allowed with ghost neighbors
This is a current restriction within LAMMPS.
E: Neighbor multi not yet enabled for ghost neighbors
This is a current restriction within LAMMPS.
E: Neighbor multi not yet enabled for granular
Self-explanatory.
E: Neighbor multi not yet enabled for rRESPA
Self-explanatory.
E: Too many local+ghost atoms for neighbor list
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.
W: Building an occasional neighobr list when atoms may have moved too far
This can cause LAMMPS to crash when the neighbor list is built.
The solution is to check for building the regular neighbor lists
more frequently.
E: Domain too large for neighbor bins
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.
E: Cannot use neighbor bins - box size << cutoff
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.
E: Too many neighbor bins
This is likely due to an immense simulation box that has blown up
to a large size.
E: Illegal ... command
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.
E: Invalid group ID in neigh_modify command
A group ID used in the neigh_modify command does not exist.
E: Neigh_modify include group != atom_modify first group
Self-explanatory.
E: Neigh_modify exclude molecule requires atom attribute molecule
Self-explanatory.
*/
diff --git a/src/read_data.cpp b/src/read_data.cpp
index 67bebe6fb..2a512350f 100644
--- a/src/read_data.cpp
+++ b/src/read_data.cpp
@@ -1,1649 +1,1573 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
#include "read_data.h"
#include "atom.h"
#include "atom_vec.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "comm.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "force.h"
#include "pair.h"
#include "domain.h"
#include "bond.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "special.h"
#include "error.h"
#include "memory.h"
using namespace LAMMPS_NS;
#define MAXLINE 256
#define LB_FACTOR 1.1
#define CHUNK 1024
#define DELTA 4 // must be 2 or larger
#define MAXBODY 20 // max # of lines in one body, also in Atom class
// customize for new sections
#define NSECTIONS 25 // change when add to header::section_keywords
+/* ---------------------------------------------------------------------- */
+
// compare two style strings and compare under consideration of possibly
// having suffixes which should be ignored (like /cuda, /gpu, /omp, /opt)
// we also need to strip off all coulomb related parts, since they do not
// affect the choice of coefficients (with very few execptions).
static const char *suffixes[] = {"/cuda","/gpu","/opt","/omp","/coul/cut",
"/coul/long","/coul/msm","/coul/dsf","/coul/debye","/coul/charmm",NULL};
static int style_match(const char *one, const char *two)
{
int i, delta, len, len1, len2;
// cannot compare empty styles
if ((one == NULL) || (two == NULL)) return 1;
len1 = strlen(one);
len2 = strlen(two);
for (i=0; suffixes[i] != NULL; ++i) {
len = strlen(suffixes[i]);
if ((delta = len1 - len) > 0)
if (strcmp(one+delta,suffixes[i]) == 0)
len1 = delta;
if ((delta = len2 - len) > 0)
if (strcmp(two+delta,suffixes[i]) == 0)
len2 = delta;
}
// after trimming off the suffix, the length has to match
if (len1 != len2)
return 0;
if (strncmp(one,two,len1) == 0)
return 1;
return 0;
}
-
/* ---------------------------------------------------------------------- */
ReadData::ReadData(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
line = new char[MAXLINE];
keyword = new char[MAXLINE];
style = new char[MAXLINE];
buffer = new char[CHUNK*MAXLINE];
narg = maxarg = 0;
arg = NULL;
// customize for new sections
// pointers to atom styles that store extra info
nellipsoids = 0;
avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid");
nlines = 0;
avec_line = (AtomVecLine *) atom->style_match("line");
ntris = 0;
avec_tri = (AtomVecTri *) atom->style_match("tri");
nbodies = 0;
avec_body = (AtomVecBody *) atom->style_match("body");
}
/* ---------------------------------------------------------------------- */
ReadData::~ReadData()
{
delete [] line;
delete [] keyword;
delete [] style;
delete [] buffer;
memory->sfree(arg);
for (int i = 0; i < nfix; i++) {
delete [] fix_header[i];
delete [] fix_section[i];
}
memory->destroy(fix_index);
memory->sfree(fix_header);
memory->sfree(fix_section);
}
/* ---------------------------------------------------------------------- */
void ReadData::command(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal read_data command");
if (domain->box_exist)
error->all(FLERR,"Cannot read_data after simulation box is defined");
if (domain->dimension == 2 && domain->zperiodic == 0)
error->all(FLERR,"Cannot run 2d simulation with nonperiodic Z dimension");
// fixes that process data file info
nfix = 0;
fix_index = NULL;
fix_header = NULL;
fix_section = NULL;
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"fix") == 0) {
if (iarg+4 > narg)
error->all(FLERR,"Illegal read_data command");
memory->grow(fix_index,nfix+1,"read_data:fix_index");
fix_header = (char **)
memory->srealloc(fix_header,(nfix+1)*sizeof(char *),
"read_data:fix_header");
fix_section = (char **)
memory->srealloc(fix_section,(nfix+1)*sizeof(char *),
"read_data:fix_section");
fix_index[nfix] = modify->find_fix(arg[iarg+1]);
if (fix_index[nfix] < 0)
error->all(FLERR,"Fix ID for read_data does not exist");
if (strcmp(arg[iarg+2],"NULL") == 0) fix_header[nfix] = NULL;
else {
int n = strlen(arg[iarg+2]) + 1;
fix_header[nfix] = new char[n];
strcpy(fix_header[nfix],arg[iarg+2]);
}
int n = strlen(arg[iarg+3]) + 1;
fix_section[nfix] = new char[n];
strcpy(fix_section[nfix],arg[iarg+3]);
nfix++;
iarg += 4;
} else error->all(FLERR,"Illegal read_data command");
}
- // scan data file to determine max topology needed per atom
- // allocate initial topology arrays
- if (atom->molecular) {
- if (me == 0) {
- if (screen) fprintf(screen,"Scanning data file ...\n");
- open(arg[0]);
- header(0);
- scan(atom->bond_per_atom,atom->angle_per_atom,
- atom->dihedral_per_atom,atom->improper_per_atom);
- if (compressed) pclose(fp);
- else fclose(fp);
- atom->bond_per_atom += atom->extra_bond_per_atom;
- atom->angle_per_atom += atom->extra_angle_per_atom;
- atom->dihedral_per_atom += atom->extra_dihedral_per_atom;
- atom->improper_per_atom += atom->extra_improper_per_atom;
- }
-
- MPI_Bcast(&atom->bond_per_atom,1,MPI_INT,0,world);
- MPI_Bcast(&atom->angle_per_atom,1,MPI_INT,0,world);
- MPI_Bcast(&atom->dihedral_per_atom,1,MPI_INT,0,world);
- MPI_Bcast(&atom->improper_per_atom,1,MPI_INT,0,world);
+ // perform 1-pass read if no molecular topoogy in file
+ // perform 2-pass read if molecular topology
+ // 1st pass calculates max topology/atom
- } else
- atom->bond_per_atom = atom->angle_per_atom =
- atom->dihedral_per_atom = atom->improper_per_atom = 0;
+ int atomflag,topoflag;
+ int bondflag,angleflag,dihedralflag,improperflag;
+ int ellipsoidflag,lineflag,triflag,bodyflag;
- // read header info
+ atomflag = topoflag = 0;
+ bondflag = angleflag = dihedralflag = improperflag = 0;
+ ellipsoidflag = lineflag = triflag = bodyflag = 0;
- if (me == 0) {
- if (screen) fprintf(screen,"Reading data file ...\n");
- open(arg[0]);
- } else fp = NULL;
- header(1);
- domain->box_exist = 1;
+ int firstpass = 1;
- // problem setup using info from header
+ while (1) {
- update->ntimestep = 0;
+ // open file on proc 0
- int n;
- if (comm->nprocs == 1) n = static_cast<int> (atom->natoms);
- else n = static_cast<int> (LB_FACTOR * atom->natoms / comm->nprocs);
+ if (me == 0) {
+ if (firstpass && screen) fprintf(screen,"Reading data file ...\n");
+ open(arg[0]);
+ } else fp = NULL;
+
+ // read header info
+
+ header();
+
+ // problem setup using info from header
+ // 1st pass only
+
+ if (firstpass) {
+ domain->box_exist = 1;
+ update->ntimestep = 0;
+
+ int n;
+ if (comm->nprocs == 1) n = static_cast<int> (atom->natoms);
+ else n = static_cast<int> (LB_FACTOR * atom->natoms / comm->nprocs);
+
+ atom->allocate_type_arrays();
+ atom->avec->grow(n);
+ n = atom->nmax;
+
+ domain->print_box(" ");
+ domain->set_initial_box();
+ domain->set_global_box();
+ comm->set_proc_grid();
+ domain->set_local_box();
+ }
- atom->allocate_type_arrays();
- atom->avec->grow(n);
- n = atom->nmax;
+ // customize for new sections
+ // read rest of file in free format
- domain->print_box(" ");
- domain->set_initial_box();
- domain->set_global_box();
- comm->set_proc_grid();
- domain->set_local_box();
+ while (strlen(keyword)) {
- // customize for new sections
- // read rest of file in free format
+ // if special fix matches, it processes section
- int atomflag = 0;
+ if (nfix) {
+ int i;
+ for (i = 0; i < nfix; i++)
+ if (strcmp(keyword,fix_section[i]) == 0) {
+ if (firstpass) fix(i,keyword);
+ else skip_lines(modify->fix[fix_index[i]]->
+ read_data_skip_lines(keyword));
+ parse_keyword(0);
+ break;
+ }
+ if (i < nfix) continue;
+ }
- while (strlen(keyword)) {
+ if (strcmp(keyword,"Atoms") == 0) {
+ atomflag = 1;
+ if (firstpass) {
+ if (me == 0 && !style_match(style,atom->atom_style))
+ error->warning(FLERR,"Recommended atom style in data file differs");
+ atoms();
+ } else skip_lines(atom->natoms);
+ } else if (strcmp(keyword,"Velocities") == 0) {
+ if (atomflag == 0)
+ error->all(FLERR,"Must read Atoms before Velocities");
+ if (firstpass) velocities();
+ else skip_lines(atom->natoms);
+
+ } else if (strcmp(keyword,"Bonds") == 0) {
+ topoflag = bondflag = 1;
+ if (atom->avec->bonds_allow == 0)
+ error->all(FLERR,"Invalid data file section: Bonds");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bonds");
+ bonds(firstpass);
+ } else if (strcmp(keyword,"Angles") == 0) {
+ topoflag = angleflag = 1;
+ if (atom->avec->angles_allow == 0)
+ error->all(FLERR,"Invalid data file section: Angles");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Angles");
+ angles(firstpass);
+ } else if (strcmp(keyword,"Dihedrals") == 0) {
+ topoflag = dihedralflag = 1;
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,"Invalid data file section: Dihedrals");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Dihedrals");
+ dihedrals(firstpass);
+ } else if (strcmp(keyword,"Impropers") == 0) {
+ topoflag = improperflag = 1;
+ if (atom->avec->impropers_allow == 0)
+ error->all(FLERR,"Invalid data file section: Impropers");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Impropers");
+ impropers(firstpass);
+
+ } else if (strcmp(keyword,"Ellipsoids") == 0) {
+ ellipsoidflag = 1;
+ if (!avec_ellipsoid)
+ error->all(FLERR,"Invalid data file section: Ellipsoids");
+ if (atomflag == 0)
+ error->all(FLERR,"Must read Atoms before Ellipsoids");
+ if (firstpass)
+ bonus(nellipsoids,(AtomVec *) avec_ellipsoid,"ellipsoids");
+ else skip_lines(nellipsoids);
+ } else if (strcmp(keyword,"Lines") == 0) {
+ lineflag = 1;
+ if (!avec_line)
+ error->all(FLERR,"Invalid data file section: Lines");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Lines");
+ if (firstpass) bonus(nlines,(AtomVec *) avec_line,"lines");
+ else skip_lines(nlines);
+ } else if (strcmp(keyword,"Triangles") == 0) {
+ triflag = 1;
+ if (!avec_tri)
+ error->all(FLERR,"Invalid data file section: Triangles");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Triangles");
+ if (firstpass) bonus(ntris,(AtomVec *) avec_tri,"triangles");
+ else skip_lines(ntris);
+ } else if (strcmp(keyword,"Bodies") == 0) {
+ bodyflag = 1;
+ if (!avec_body)
+ error->all(FLERR,"Invalid data file section: Bodies");
+ if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bodies");
+ bodies(firstpass);
+
+ } else if (strcmp(keyword,"Masses") == 0) {
+ if (firstpass) mass();
+ else skip_lines(atom->ntypes);
+ } else if (strcmp(keyword,"Pair Coeffs") == 0) {
+ if (force->pair == NULL)
+ error->all(FLERR,"Must define pair_style before Pair Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->pair_style))
+ error->warning(FLERR,"Recommended pair style in data file differs");
+ paircoeffs();
+ } else skip_lines(atom->ntypes);
+ } else if (strcmp(keyword,"PairIJ Coeffs") == 0) {
+ if (force->pair == NULL)
+ error->all(FLERR,"Must define pair_style before PairIJ Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->pair_style))
+ error->warning(FLERR,"Recommended pair style in data file differs");
+ pairIJcoeffs();
+ } else skip_lines(atom->ntypes*(atom->ntypes+1)/2);
+ } else if (strcmp(keyword,"Bond Coeffs") == 0) {
+ if (atom->avec->bonds_allow == 0)
+ error->all(FLERR,"Invalid data file section: Bond Coeffs");
+ if (force->bond == NULL)
+ error->all(FLERR,"Must define bond_style before Bond Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->bond_style))
+ error->warning(FLERR,"Recommended bond style in data file differs");
+ bondcoeffs();
+ } else skip_lines(atom->nbondtypes);
+ } else if (strcmp(keyword,"Angle Coeffs") == 0) {
+ if (atom->avec->angles_allow == 0)
+ error->all(FLERR,"Invalid data file section: Angle Coeffs");
+ if (force->angle == NULL)
+ error->all(FLERR,"Must define angle_style before Angle Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->angle_style))
+ error->warning(FLERR,"Recommended angle style in data file differs");
+ anglecoeffs(0);
+ } else skip_lines(atom->nangletypes);
+ } else if (strcmp(keyword,"Dihedral Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,"Invalid data file section: Dihedral Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->dihedral_style))
+ error->warning(FLERR,"Recommended dihedral style in data file differs");
+ dihedralcoeffs(0);
+ } else skip_lines(atom->ndihedraltypes);
+ } else if (strcmp(keyword,"Improper Coeffs") == 0) {
+ if (atom->avec->impropers_allow == 0)
+ error->all(FLERR,"Invalid data file section: Improper Coeffs");
+ if (force->improper == NULL)
+ error->all(FLERR,"Must define improper_style before Improper Coeffs");
+ if (firstpass) {
+ if (me == 0 && !style_match(style,force->improper_style))
+ error->warning(FLERR,"Recommended improper style in data file differs");
+ impropercoeffs(0);
+ } else skip_lines(atom->nimpropertypes);
+
+ } else if (strcmp(keyword,"BondBond Coeffs") == 0) {
+ if (atom->avec->angles_allow == 0)
+ error->all(FLERR,"Invalid data file section: BondBond Coeffs");
+ if (force->angle == NULL)
+ error->all(FLERR,"Must define angle_style before BondBond Coeffs");
+ if (firstpass) anglecoeffs(1);
+ else skip_lines(atom->nangletypes);
+ } else if (strcmp(keyword,"BondAngle Coeffs") == 0) {
+ if (atom->avec->angles_allow == 0)
+ error->all(FLERR,"Invalid data file section: BondAngle Coeffs");
+ if (force->angle == NULL)
+ error->all(FLERR,"Must define angle_style before BondAngle Coeffs");
+ if (firstpass) anglecoeffs(2);
+ else skip_lines(atom->nangletypes);
+
+ } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,
+ "Invalid data file section: MiddleBondTorsion Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,
+ "Must define dihedral_style before "
+ "MiddleBondTorsion Coeffs");
+ if (firstpass) dihedralcoeffs(1);
+ else skip_lines(atom->ndihedraltypes);
+ } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,
+ "Must define dihedral_style before EndBondTorsion Coeffs");
+ if (firstpass) dihedralcoeffs(2);
+ else skip_lines(atom->ndihedraltypes);
+ } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,
+ "Must define dihedral_style before AngleTorsion Coeffs");
+ if (firstpass) dihedralcoeffs(3);
+ else skip_lines(atom->ndihedraltypes);
+ } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,
+ "Invalid data file section: AngleAngleTorsion Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,
+ "Must define dihedral_style before "
+ "AngleAngleTorsion Coeffs");
+ if (firstpass) dihedralcoeffs(4);
+ else skip_lines(atom->ndihedraltypes);
+ } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) {
+ if (atom->avec->dihedrals_allow == 0)
+ error->all(FLERR,"Invalid data file section: BondBond13 Coeffs");
+ if (force->dihedral == NULL)
+ error->all(FLERR,
+ "Must define dihedral_style before BondBond13 Coeffs");
+ if (firstpass) dihedralcoeffs(5);
+ else skip_lines(atom->ndihedraltypes);
+
+ } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) {
+ if (atom->avec->impropers_allow == 0)
+ error->all(FLERR,"Invalid data file section: AngleAngle Coeffs");
+ if (force->improper == NULL)
+ error->all(FLERR,
+ "Must define improper_style before AngleAngle Coeffs");
+ if (firstpass) impropercoeffs(1);
+ else skip_lines(atom->nimpropertypes);
+
+ } else {
+ char str[128];
+ sprintf(str,"Unknown identifier in data file: %s",keyword);
+ error->all(FLERR,str);
+ }
+
+ parse_keyword(0);
+ }
- // allow special fixes first chance to match and process the section
- // if fix matches, continue to next section
+ // error if natoms > 0 yet no atoms were read
- if (nfix) {
- for (n = 0; n < nfix; n++)
- if (strcmp(keyword,fix_section[n]) == 0) {
- fix(n,keyword);
- parse_keyword(0,1);
- break;
- }
- if (n < nfix) continue;
+ if (atom->natoms > 0 && atomflag == 0)
+ error->all(FLERR,"No atoms in data file");
+
+ // close file
+
+ if (me == 0) {
+ if (compressed) pclose(fp);
+ else fclose(fp);
}
- if (strcmp(keyword,"Atoms") == 0) {
- if (me == 0 && !style_match(style,atom->atom_style))
- error->warning(FLERR,"Recommended atom style in data file differs");
- atoms();
- atomflag = 1;
- } else if (strcmp(keyword,"Velocities") == 0) {
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Velocities");
- velocities();
-
- } else if (strcmp(keyword,"Ellipsoids") == 0) {
- if (!avec_ellipsoid)
- error->all(FLERR,"Invalid data file section: Ellipsoids");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Ellipsoids");
- bonus(nellipsoids,(AtomVec *) avec_ellipsoid,"ellipsoids");
- } else if (strcmp(keyword,"Lines") == 0) {
- if (!avec_line)
- error->all(FLERR,"Invalid data file section: Lines");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Lines");
- bonus(nlines,(AtomVec *) avec_line,"lines");
- } else if (strcmp(keyword,"Triangles") == 0) {
- if (!avec_tri)
- error->all(FLERR,"Invalid data file section: Triangles");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Triangles");
- bonus(ntris,(AtomVec *) avec_tri,"triangles");
- } else if (strcmp(keyword,"Bodies") == 0) {
- if (!avec_body)
- error->all(FLERR,"Invalid data file section: Bodies");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bodies");
- bodies();
-
- } else if (strcmp(keyword,"Bonds") == 0) {
- if (atom->avec->bonds_allow == 0)
- error->all(FLERR,"Invalid data file section: Bonds");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bonds");
- bonds();
- } else if (strcmp(keyword,"Angles") == 0) {
- if (atom->avec->angles_allow == 0)
- error->all(FLERR,"Invalid data file section: Angles");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Angles");
- angles();
- } else if (strcmp(keyword,"Dihedrals") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: Dihedrals");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Dihedrals");
- dihedrals();
- } else if (strcmp(keyword,"Impropers") == 0) {
- if (atom->avec->impropers_allow == 0)
- error->all(FLERR,"Invalid data file section: Impropers");
- if (atomflag == 0) error->all(FLERR,"Must read Atoms before Impropers");
- impropers();
-
- } else if (strcmp(keyword,"Masses") == 0) {
- mass();
- } else if (strcmp(keyword,"Pair Coeffs") == 0) {
- if (force->pair == NULL)
- error->all(FLERR,"Must define pair_style before Pair Coeffs");
- if (me == 0 && !style_match(style,force->pair_style))
- error->warning(FLERR,"Recommended pair style in data file differs");
- paircoeffs();
- } else if (strcmp(keyword,"PairIJ Coeffs") == 0) {
- if (force->pair == NULL)
- error->all(FLERR,"Must define pair_style before PairIJ Coeffs");
- if (me == 0 && !style_match(style,force->pair_style))
- error->warning(FLERR,"Recommended pair style in data file differs");
- pairIJcoeffs();
- } else if (strcmp(keyword,"Bond Coeffs") == 0) {
- if (atom->avec->bonds_allow == 0)
- error->all(FLERR,"Invalid data file section: Bond Coeffs");
- if (force->bond == NULL)
- error->all(FLERR,"Must define bond_style before Bond Coeffs");
- if (me == 0 && !style_match(style,force->bond_style))
- error->warning(FLERR,"Recommended bond style in data file differs");
- bondcoeffs();
- } else if (strcmp(keyword,"Angle Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->all(FLERR,"Invalid data file section: Angle Coeffs");
- if (force->angle == NULL)
- error->all(FLERR,"Must define angle_style before Angle Coeffs");
- if (me == 0 && !style_match(style,force->angle_style))
- error->warning(FLERR,"Recommended angle style in data file differs");
- anglecoeffs(0);
- } else if (strcmp(keyword,"Dihedral Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: Dihedral Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs");
- if (me == 0 && !style_match(style,force->dihedral_style))
- error->warning(FLERR,"Recommended dihedral style in data file differs");
- dihedralcoeffs(0);
- } else if (strcmp(keyword,"Improper Coeffs") == 0) {
- if (atom->avec->impropers_allow == 0)
- error->all(FLERR,"Invalid data file section: Improper Coeffs");
- if (force->improper == NULL)
- error->all(FLERR,"Must define improper_style before Improper Coeffs");
- if (me == 0 && !style_match(style,force->improper_style))
- error->warning(FLERR,"Recommended improper style in data file differs");
- impropercoeffs(0);
-
- } else if (strcmp(keyword,"BondBond Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->all(FLERR,"Invalid data file section: BondBond Coeffs");
- if (force->angle == NULL)
- error->all(FLERR,"Must define angle_style before BondBond Coeffs");
- anglecoeffs(1);
- } else if (strcmp(keyword,"BondAngle Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->all(FLERR,"Invalid data file section: BondAngle Coeffs");
- if (force->angle == NULL)
- error->all(FLERR,"Must define angle_style before BondAngle Coeffs");
- anglecoeffs(2);
-
- } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: MiddleBondTorsion Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,
- "Must define dihedral_style before "
- "MiddleBondTorsion Coeffs");
- dihedralcoeffs(1);
- } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,
- "Must define dihedral_style before EndBondTorsion Coeffs");
- dihedralcoeffs(2);
- } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,
- "Must define dihedral_style before AngleTorsion Coeffs");
- dihedralcoeffs(3);
- } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: AngleAngleTorsion Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,
- "Must define dihedral_style before "
- "AngleAngleTorsion Coeffs");
- dihedralcoeffs(4);
- } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->all(FLERR,"Invalid data file section: BondBond13 Coeffs");
- if (force->dihedral == NULL)
- error->all(FLERR,"Must define dihedral_style before BondBond13 Coeffs");
- dihedralcoeffs(5);
-
- } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) {
- if (atom->avec->impropers_allow == 0)
- error->all(FLERR,"Invalid data file section: AngleAngle Coeffs");
- if (force->improper == NULL)
- error->all(FLERR,"Must define improper_style before AngleAngle Coeffs");
- impropercoeffs(1);
+ // done if this was 2nd pass
- } else {
- char str[128];
- sprintf(str,"Unknown identifier in data file: %s",keyword);
- error->all(FLERR,str);
- }
+ if (!firstpass) break;
- parse_keyword(0,1);
- }
+ // at end of 1st pass, error check for required sections
+ // customize for new sections
- // close file
+ if ((atom->nbonds && !bondflag) || (atom->nangles && !angleflag) ||
+ (atom->ndihedrals && !dihedralflag) ||
+ (atom->nimpropers && !improperflag))
+ error->one(FLERR,"Needed molecular topology not in data file");
- if (me == 0) {
- if (compressed) pclose(fp);
- else fclose(fp);
- }
+ if ((nellipsoids && !ellipsoidflag) || (nlines && !lineflag) ||
+ (ntris && !triflag) || (nbodies && !bodyflag))
+ error->one(FLERR,"Needed bonus data not in data file");
+
+ // break out of loop if no molecular topology in file
+ // else make 2nd pass
+
+ if (!topoflag) break;
+ firstpass = 0;
- // error if natoms > 0 yet no atoms were read
+ // reallocate bond,angle,diehdral,improper arrays via grow(),
+ // using new bond,angle,dihedral,improper per-atom values from 1st pass
+ // should leave other atom arrays unchanged, since already nmax in length
- if (atom->natoms > 0 && atomflag == 0)
- error->all(FLERR,"No atoms in data file");
+ if (bondflag) {
+ memory->destroy(atom->bond_type);
+ memory->destroy(atom->bond_atom);
+ atom->bond_type = NULL;
+ atom->bond_atom = NULL;
+ }
+ if (angleflag) {
+ memory->destroy(atom->angle_type);
+ memory->destroy(atom->angle_atom1);
+ memory->destroy(atom->angle_atom2);
+ memory->destroy(atom->angle_atom3);
+ atom->angle_type = NULL;
+ atom->angle_atom1 = atom->angle_atom2 = atom->angle_atom3 = NULL;
+ }
+ if (dihedralflag) {
+ memory->destroy(atom->dihedral_type);
+ memory->destroy(atom->dihedral_atom1);
+ memory->destroy(atom->dihedral_atom2);
+ memory->destroy(atom->dihedral_atom3);
+ memory->destroy(atom->dihedral_atom4);
+ atom->dihedral_type = NULL;
+ atom->dihedral_atom1 = atom->dihedral_atom2 =
+ atom->dihedral_atom3 = atom->dihedral_atom4 = NULL;
+ }
+ if (improperflag) {
+ memory->destroy(atom->improper_type);
+ memory->destroy(atom->improper_atom1);
+ memory->destroy(atom->improper_atom2);
+ memory->destroy(atom->improper_atom3);
+ memory->destroy(atom->improper_atom4);
+ atom->improper_type = NULL;
+ atom->improper_atom1 = atom->improper_atom2 =
+ atom->improper_atom3 = atom->improper_atom4 = NULL;
+ }
+
+ atom->avec->grow(atom->nmax);
+ }
- // create bond topology now that system is defined
+ // create special bond lists for molecular systems
if (atom->molecular) {
Special special(lmp);
special.build();
}
}
/* ----------------------------------------------------------------------
read free-format header of data file
- if flag = 0, only called by proc 0
- if flag = 1, called by all procs so bcast lines as read them
1st line and blank lines are skipped
non-blank lines are checked for header keywords and leading value is read
header ends with EOF or non-blank line containing no header keyword
if EOF, line is set to blank line
else line has first keyword line for rest of file
------------------------------------------------------------------------- */
-void ReadData::header(int flag)
+void ReadData::header()
{
int n;
char *ptr;
// customize for new sections
const char *section_keywords[NSECTIONS] =
{"Atoms","Velocities","Ellipsoids","Lines","Triangles","Bodies",
"Bonds","Angles","Dihedrals","Impropers",
"Masses","Pair Coeffs","PairIJ Coeffs","Bond Coeffs","Angle Coeffs",
"Dihedral Coeffs","Improper Coeffs",
"BondBond Coeffs","BondAngle Coeffs","MiddleBondTorsion Coeffs",
"EndBondTorsion Coeffs","AngleTorsion Coeffs",
"AngleAngleTorsion Coeffs","BondBond13 Coeffs","AngleAngle Coeffs"};
// skip 1st line of file
if (me == 0) {
char *eof = fgets(line,MAXLINE,fp);
if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
}
// customize for new header lines
while (1) {
// read a line and bcast length if flag is set
if (me == 0) {
if (fgets(line,MAXLINE,fp) == NULL) n = 0;
else n = strlen(line) + 1;
}
- if (flag) MPI_Bcast(&n,1,MPI_INT,0,world);
+ MPI_Bcast(&n,1,MPI_INT,0,world);
// if n = 0 then end-of-file so return with blank line
if (n == 0) {
line[0] = '\0';
return;
}
- // bcast line if flag is set
-
- if (flag) MPI_Bcast(line,n,MPI_CHAR,0,world);
+ MPI_Bcast(line,n,MPI_CHAR,0,world);
// trim anything from '#' onward
// if line is blank, continue
if ((ptr = strchr(line,'#'))) *ptr = '\0';
if (strspn(line," \t\n\r") == strlen(line)) continue;
// allow special fixes first chance to match and process the line
// if fix matches, continue to next header line
if (nfix) {
for (n = 0; n < nfix; n++) {
if (!fix_header[n]) continue;
if (strstr(line,fix_header[n])) {
modify->fix[fix_index[n]]->read_data_header(line);
break;
}
}
if (n < nfix) continue;
}
// search line for header keyword and set corresponding variable
if (strstr(line,"atoms")) {
sscanf(line,BIGINT_FORMAT,&atom->natoms);
// check for these first
// otherwise "triangles" will be matched as "angles"
} else if (strstr(line,"ellipsoids")) {
if (!avec_ellipsoid && me == 0)
error->one(FLERR,"No ellipsoids allowed with this atom style");
sscanf(line,BIGINT_FORMAT,&nellipsoids);
} else if (strstr(line,"lines")) {
if (!avec_line && me == 0)
error->one(FLERR,"No lines allowed with this atom style");
sscanf(line,BIGINT_FORMAT,&nlines);
} else if (strstr(line,"triangles")) {
if (!avec_tri && me == 0)
error->one(FLERR,"No triangles allowed with this atom style");
sscanf(line,BIGINT_FORMAT,&ntris);
} else if (strstr(line,"bodies")) {
if (!avec_body && me == 0)
error->one(FLERR,"No bodies allowed with this atom style");
sscanf(line,BIGINT_FORMAT,&nbodies);
}
else if (strstr(line,"bonds")) sscanf(line,BIGINT_FORMAT,&atom->nbonds);
else if (strstr(line,"angles")) sscanf(line,BIGINT_FORMAT,&atom->nangles);
else if (strstr(line,"dihedrals")) sscanf(line,BIGINT_FORMAT,
&atom->ndihedrals);
else if (strstr(line,"impropers")) sscanf(line,BIGINT_FORMAT,
&atom->nimpropers);
else if (strstr(line,"atom types")) sscanf(line,"%d",&atom->ntypes);
else if (strstr(line,"bond types")) sscanf(line,"%d",&atom->nbondtypes);
else if (strstr(line,"angle types")) sscanf(line,"%d",&atom->nangletypes);
else if (strstr(line,"dihedral types"))
sscanf(line,"%d",&atom->ndihedraltypes);
else if (strstr(line,"improper types"))
sscanf(line,"%d",&atom->nimpropertypes);
else if (strstr(line,"extra bond per atom"))
sscanf(line,"%d",&atom->extra_bond_per_atom);
else if (strstr(line,"extra angle per atom"))
sscanf(line,"%d",&atom->extra_angle_per_atom);
else if (strstr(line,"extra dihedral per atom"))
sscanf(line,"%d",&atom->extra_dihedral_per_atom);
else if (strstr(line,"extra improper per atom"))
sscanf(line,"%d",&atom->extra_improper_per_atom);
else if (strstr(line,"extra special per atom"))
sscanf(line,"%d",&force->special_extra);
else if (strstr(line,"xlo xhi"))
sscanf(line,"%lg %lg",&domain->boxlo[0],&domain->boxhi[0]);
else if (strstr(line,"ylo yhi"))
sscanf(line,"%lg %lg",&domain->boxlo[1],&domain->boxhi[1]);
else if (strstr(line,"zlo zhi"))
sscanf(line,"%lg %lg",&domain->boxlo[2],&domain->boxhi[2]);
else if (strstr(line,"xy xz yz")) {
domain->triclinic = 1;
sscanf(line,"%lg %lg %lg",&domain->xy,&domain->xz,&domain->yz);
} else break;
}
// error check on total system size
- if (atom->natoms < 0 || atom->natoms > MAXBIGINT ||
- atom->nbonds < 0 || atom->nbonds > MAXBIGINT ||
- atom->nangles < 0 || atom->nangles > MAXBIGINT ||
- atom->ndihedrals < 0 || atom->ndihedrals > MAXBIGINT ||
- atom->nimpropers < 0 || atom->nimpropers > MAXBIGINT) {
+ if (atom->natoms < 0 || atom->natoms >= MAXBIGINT ||
+ atom->nbonds < 0 || atom->nbonds >= MAXBIGINT ||
+ atom->nangles < 0 || atom->nangles >= MAXBIGINT ||
+ atom->ndihedrals < 0 || atom->ndihedrals >= MAXBIGINT ||
+ atom->nimpropers < 0 || atom->nimpropers >= MAXBIGINT) {
if (me == 0) error->one(FLERR,"System in data file is too big");
}
// check that exiting string is a valid section keyword
- parse_keyword(1,flag);
+ parse_keyword(1);
for (n = 0; n < NSECTIONS; n++)
if (strcmp(keyword,section_keywords[n]) == 0) break;
if (n == NSECTIONS && me == 0) {
char str[128];
sprintf(str,"Unknown identifier in data file: %s",keyword);
error->one(FLERR,str);
}
// error check on consistency of header values
if ((atom->nbonds || atom->nbondtypes) &&
atom->avec->bonds_allow == 0 && me == 0)
error->one(FLERR,"No bonds allowed with this atom style");
if ((atom->nangles || atom->nangletypes) &&
atom->avec->angles_allow == 0 && me == 0)
error->one(FLERR,"No angles allowed with this atom style");
if ((atom->ndihedrals || atom->ndihedraltypes) &&
atom->avec->dihedrals_allow == 0 && me == 0)
error->one(FLERR,"No dihedrals allowed with this atom style");
if ((atom->nimpropers || atom->nimpropertypes) &&
atom->avec->impropers_allow == 0 && me == 0)
error->one(FLERR,"No impropers allowed with this atom style");
if (atom->nbonds > 0 && atom->nbondtypes <= 0 && me == 0)
error->one(FLERR,"Bonds defined but no bond types");
if (atom->nangles > 0 && atom->nangletypes <= 0 && me == 0)
error->one(FLERR,"Angles defined but no angle types");
if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0 && me == 0)
error->one(FLERR,"Dihedrals defined but no dihedral types");
if (atom->nimpropers > 0 && atom->nimpropertypes <= 0 && me == 0)
error->one(FLERR,"Impropers defined but no improper types");
}
/* ----------------------------------------------------------------------
read all atoms
------------------------------------------------------------------------- */
void ReadData::atoms()
{
int nchunk,eof;
+ if (me == 0) {
+ if (screen) fprintf(screen," reading atoms ...\n");
+ if (logfile) fprintf(logfile," reading atoms ...\n");
+ }
+
bigint nread = 0;
bigint natoms = atom->natoms;
while (nread < natoms) {
nchunk = MIN(natoms-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
atom->data_atoms(nchunk,buffer);
nread += nchunk;
}
// check that all atoms were assigned correctly
bigint tmp = atom->nlocal;
MPI_Allreduce(&tmp,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " atoms\n",natoms);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " atoms\n",natoms);
}
if (natoms != atom->natoms)
error->all(FLERR,"Did not assign all atoms correctly");
+
+ // check that atom IDs are valid
- // if any atom ID < 0, error
- // if all atom IDs = 0, tag_enable = 0
- // if any atom ID > 0, error if any atom ID == 0
- // not checking if atom IDs > natoms or are unique
-
- int nlocal = atom->nlocal;
- int *tag = atom->tag;
-
- int flag = 0;
- for (int i = 0; i < nlocal; i++)
- if (tag[i] < 0) flag = 1;
- int flag_all;
- MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
- if (flag_all)
- error->all(FLERR,"Invalid atom ID in Atoms section of data file");
-
- flag = 0;
- for (int i = 0; i < nlocal; i++)
- if (tag[i] > 0) flag = 1;
- MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world);
- if (flag_all == 0) atom->tag_enable = 0;
-
- if (atom->tag_enable) {
- flag = 0;
- for (int i = 0; i < nlocal; i++)
- if (tag[i] == 0) flag = 1;
- MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world);
- if (flag_all)
- error->all(FLERR,"Invalid atom ID in Atoms section of data file");
- }
+ atom->tag_check();
- // create global mapping
+ // if molecular system or user-requested, create global mapping of atoms
- if (atom->map_style) {
+ if (atom->molecular || atom->map_user) {
atom->map_init();
atom->map_set();
}
}
/* ----------------------------------------------------------------------
read all velocities
to find atoms, must build atom map if not a molecular system
------------------------------------------------------------------------- */
void ReadData::velocities()
{
int nchunk,eof;
+ if (me == 0) {
+ if (screen) fprintf(screen," reading velocities ...\n");
+ if (logfile) fprintf(logfile," reading velocities ...\n");
+ }
+
int mapflag = 0;
if (atom->map_style == 0) {
mapflag = 1;
- atom->map_style = 1;
atom->map_init();
atom->map_set();
}
bigint nread = 0;
bigint natoms = atom->natoms;
while (nread < natoms) {
nchunk = MIN(natoms-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
atom->data_vels(nchunk,buffer);
nread += nchunk;
}
if (mapflag) {
atom->map_delete();
atom->map_style = 0;
}
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " velocities\n",natoms);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " velocities\n",natoms);
}
}
/* ----------------------------------------------------------------------
- read all bonus data
- to find atoms, must build atom map if not a molecular system
+ scan or read all bonds
------------------------------------------------------------------------- */
-void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type)
+void ReadData::bonds(int firstpass)
{
- int nchunk,eof;
-
- int mapflag = 0;
- if (atom->map_style == 0) {
- mapflag = 1;
- atom->map_style = 1;
- atom->map_init();
- atom->map_set();
- }
-
- bigint nread = 0;
- bigint natoms = nbonus;
-
- while (nread < natoms) {
- nchunk = MIN(natoms-nread,CHUNK);
- eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
- if (eof) error->all(FLERR,"Unexpected end of data file");
- atom->data_bonus(nchunk,buffer,ptr);
- nread += nchunk;
- }
-
- if (mapflag) {
- atom->map_delete();
- atom->map_style = 0;
- }
-
if (me == 0) {
- if (screen) fprintf(screen," " BIGINT_FORMAT " %s\n",natoms,type);
- if (logfile) fprintf(logfile," " BIGINT_FORMAT " %s\n",natoms,type);
- }
-}
-
-/* ----------------------------------------------------------------------
- read all body data
- variable amount of info per body, described by ninteger and ndouble
- to find atoms, must build atom map if not a molecular system
-------------------------------------------------------------------------- */
-
-void ReadData::bodies()
-{
- int i,m,nchunk,nmax,ninteger,ndouble,tmp,onebody;
- char *eof;
-
- int mapflag = 0;
- if (atom->map_style == 0) {
- mapflag = 1;
- atom->map_style = 1;
- atom->map_init();
- atom->map_set();
- }
-
- // nmax = max # of bodies to read in this chunk
- // nchunk = actual # read
-
- bigint nread = 0;
- bigint natoms = nbodies;
-
- while (nread < natoms) {
- if (natoms-nread > CHUNK) nmax = CHUNK;
- else nmax = natoms-nread;
-
- if (me == 0) {
- nchunk = 0;
- nlines = 0;
- m = 0;
-
- while (nchunk < nmax && nlines <= CHUNK-MAXBODY) {
- eof = fgets(&buffer[m],MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble);
- m += strlen(&buffer[m]);
-
- onebody = 0;
- if (ninteger) onebody += (ninteger-1)/10 + 1;
- if (ndouble) onebody += (ndouble-1)/10 + 1;
- if (onebody+1 > MAXBODY)
- error->one(FLERR,
- "Too many lines in one body in data file - boost MAXBODY");
-
- for (i = 0; i < onebody; i++) {
- eof = fgets(&buffer[m],MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- m += strlen(&buffer[m]);
- }
-
- nchunk++;
- nlines += onebody+1;
- }
-
- if (buffer[m-1] != '\n') strcpy(&buffer[m++],"\n");
- m++;
+ if (firstpass) {
+ if (screen) fprintf(screen," scanning bonds ...\n");
+ if (logfile) fprintf(logfile," scanning bonds ...\n");
+ } else {
+ if (screen) fprintf(screen," reading bonds ...\n");
+ if (logfile) fprintf(logfile," reading bonds ...\n");
}
-
- MPI_Bcast(&nchunk,1,MPI_INT,0,world);
- MPI_Bcast(&m,1,MPI_INT,0,world);
- MPI_Bcast(buffer,m,MPI_CHAR,0,world);
-
- atom->data_bodies(nchunk,buffer,avec_body);
- nread += nchunk;
}
- if (mapflag) {
- atom->map_delete();
- atom->map_style = 0;
- }
+ // allocate count if firstpass
- if (me == 0) {
- if (screen) fprintf(screen," " BIGINT_FORMAT " bodies\n",natoms);
- if (logfile) fprintf(logfile," " BIGINT_FORMAT " bodies\n",natoms);
+ int nlocal = atom->nlocal;
+ int *count = NULL;
+ if (firstpass) {
+ memory->create(count,nlocal,"read_data:count");
+ for (int i = 0; i < nlocal; i++) count[i] = 0;
}
-}
-/* ---------------------------------------------------------------------- */
-
-void ReadData::bonds()
-{
- int i,nchunk,eof;
+ // read and process bonds
+ int nchunk,eof;
bigint nread = 0;
bigint nbonds = atom->nbonds;
while (nread < nbonds) {
nchunk = MIN(nbonds-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
- atom->data_bonds(nchunk,buffer);
+ atom->data_bonds(nchunk,buffer,count);
nread += nchunk;
}
- // check that bonds were assigned correctly
+ // if firstpass: tally max bond/atom and return
+
+ if (firstpass) {
+ int max = 0;
+ for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
+ int maxall;
+ MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
+
+ if (me == 0) {
+ if (screen) fprintf(screen," %d = max bonds/atom\n",maxall);
+ if (logfile) fprintf(logfile," %d = max bonds/atom\n",maxall);
+ }
+ atom->bond_per_atom = maxall;
+ memory->destroy(count);
+ return;
+ }
+
+ // if 2nd pass: check that bonds were assigned correctly
- int nlocal = atom->nlocal;
- bigint sum;
bigint n = 0;
- for (i = 0; i < nlocal; i++) n += atom->num_bond[i];
+ for (int i = 0; i < nlocal; i++) n += atom->num_bond[i];
+ bigint sum;
MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
int factor = 1;
if (!force->newton_bond) factor = 2;
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " bonds\n",sum/factor);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " bonds\n",sum/factor);
}
+
if (sum != factor*atom->nbonds)
error->all(FLERR,"Bonds assigned incorrectly");
}
-/* ---------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------
+ scan or read all angles
+------------------------------------------------------------------------- */
-void ReadData::angles()
+void ReadData::angles(int firstpass)
{
- int i,nchunk,eof;
+ if (me == 0) {
+ if (firstpass) {
+ if (screen) fprintf(screen," scanning angles ...\n");
+ if (logfile) fprintf(logfile," scanning angles ...\n");
+ } else {
+ if (screen) fprintf(screen," reading angles ...\n");
+ if (logfile) fprintf(logfile," reading angles ...\n");
+ }
+ }
+
+ // allocate count if firstpass
+ int nlocal = atom->nlocal;
+ int *count = NULL;
+ if (firstpass) {
+ memory->create(count,nlocal,"read_data:count");
+ for (int i = 0; i < nlocal; i++) count[i] = 0;
+ }
+
+ // read and process angles
+
+ int nchunk,eof;
bigint nread = 0;
bigint nangles = atom->nangles;
while (nread < nangles) {
nchunk = MIN(nangles-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
- atom->data_angles(nchunk,buffer);
+ atom->data_angles(nchunk,buffer,count);
nread += nchunk;
}
- // check that ang
+ // if firstpass: tally max angle/atom and return
+
+ if (firstpass) {
+ int max = 0;
+ for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
+ int maxall;
+ MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
+
+ if (me == 0) {
+ if (screen) fprintf(screen," %d = max angles/atom\n",maxall);
+ if (logfile) fprintf(logfile," %d = max angles/atom\n",maxall);
+ }
+ atom->angle_per_atom = maxall;
+ memory->destroy(count);
+ return;
+ }
+
+ // if 2nd pass: check that angles were assigned correctly
- int nlocal = atom->nlocal;
- bigint sum;
bigint n = 0;
- for (i = 0; i < nlocal; i++) n += atom->num_angle[i];
+ for (int i = 0; i < nlocal; i++) n += atom->num_angle[i];
+ bigint sum;
MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
int factor = 1;
if (!force->newton_bond) factor = 3;
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " angles\n",sum/factor);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " angles\n",sum/factor);
}
+
if (sum != factor*atom->nangles)
error->all(FLERR,"Angles assigned incorrectly");
}
-/* ---------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------
+ scan or read all dihedrals
+------------------------------------------------------------------------- */
-void ReadData::dihedrals()
+void ReadData::dihedrals(int firstpass)
{
- int i,nchunk,eof;
+ if (me == 0) {
+ if (firstpass) {
+ if (screen) fprintf(screen," scanning dihedrals ...\n");
+ if (logfile) fprintf(logfile," scanning dihedrals ...\n");
+ } else {
+ if (screen) fprintf(screen," reading dihedrals ...\n");
+ if (logfile) fprintf(logfile," reading dihedrals ...\n");
+ }
+ }
+
+ // allocate count if firstpass
+ int nlocal = atom->nlocal;
+ int *count = NULL;
+ if (firstpass) {
+ memory->create(count,nlocal,"read_data:count");
+ for (int i = 0; i < nlocal; i++) count[i] = 0;
+ }
+
+ // read and process dihedrals
+
+ int nchunk,eof;
bigint nread = 0;
bigint ndihedrals = atom->ndihedrals;
while (nread < ndihedrals) {
nchunk = MIN(ndihedrals-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
- atom->data_dihedrals(nchunk,buffer);
+ atom->data_dihedrals(nchunk,buffer,count);
nread += nchunk;
}
- // check that dihedrals were assigned correctly
+ // if firstpass: tally max dihedral/atom and return
+
+ if (firstpass) {
+ int max = 0;
+ for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
+ int maxall;
+ MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
+
+ if (me == 0) {
+ if (screen) fprintf(screen," %d = max dihedrals/atom\n",maxall);
+ if (logfile) fprintf(logfile," %d = max dihedrals/atom\n",maxall);
+ }
+ atom->dihedral_per_atom = maxall;
+ memory->destroy(count);
+ return;
+ }
+
+ // if 2nd pass: check that dihedrals were assigned correctly
- int nlocal = atom->nlocal;
- bigint sum;
bigint n = 0;
- for (i = 0; i < nlocal; i++) n += atom->num_dihedral[i];
+ for (int i = 0; i < nlocal; i++) n += atom->num_dihedral[i];
+ bigint sum;
MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
int factor = 1;
if (!force->newton_bond) factor = 4;
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " dihedrals\n",sum/factor);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " dihedrals\n",sum/factor);
}
+
if (sum != factor*atom->ndihedrals)
error->all(FLERR,"Dihedrals assigned incorrectly");
}
-/* ---------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------
+ scan or read all impropers
+------------------------------------------------------------------------- */
-void ReadData::impropers()
+void ReadData::impropers(int firstpass)
{
- int i,nchunk,eof;
+ if (me == 0) {
+ if (firstpass) {
+ if (screen) fprintf(screen," scanning impropers ...\n");
+ if (logfile) fprintf(logfile," scanning impropers ...\n");
+ } else {
+ if (screen) fprintf(screen," reading impropers ...\n");
+ if (logfile) fprintf(logfile," reading impropers ...\n");
+ }
+ }
+
+ // allocate count if firstpass
+
+ int nlocal = atom->nlocal;
+ int *count = NULL;
+ if (firstpass) {
+ memory->create(count,nlocal,"read_data:count");
+ for (int i = 0; i < nlocal; i++) count[i] = 0;
+ }
+ // read and process impropers
+
+ int nchunk,eof;
bigint nread = 0;
bigint nimpropers = atom->nimpropers;
while (nread < nimpropers) {
nchunk = MIN(nimpropers-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
- atom->data_impropers(nchunk,buffer);
+ atom->data_impropers(nchunk,buffer,count);
nread += nchunk;
}
- // check that impropers were assigned correctly
+ // if firstpass: tally max improper/atom and return
+
+ if (firstpass) {
+ int max = 0;
+ for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]);
+ int maxall;
+ MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
+
+ if (me == 0) {
+ if (screen) fprintf(screen," %d = max impropers/atom\n",maxall);
+ if (logfile) fprintf(logfile," %d = max impropers/atom\n",maxall);
+ }
+ atom->improper_per_atom = maxall;
+ memory->destroy(count);
+ return;
+ }
+
+ // if 2nd pass: check that impropers were assigned correctly
- int nlocal = atom->nlocal;
- bigint sum;
bigint n = 0;
- for (i = 0; i < nlocal; i++) n += atom->num_improper[i];
+ for (int i = 0; i < nlocal; i++) n += atom->num_improper[i];
+ bigint sum;
MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world);
int factor = 1;
if (!force->newton_bond) factor = 4;
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " impropers\n",sum/factor);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " impropers\n",sum/factor);
}
+
if (sum != factor*atom->nimpropers)
error->all(FLERR,"Impropers assigned incorrectly");
}
+/* ----------------------------------------------------------------------
+ read all bonus data
+ to find atoms, must build atom map if not a molecular system
+------------------------------------------------------------------------- */
+
+void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type)
+{
+ int nchunk,eof;
+
+ int mapflag = 0;
+ if (atom->map_style == 0) {
+ mapflag = 1;
+ atom->map_init();
+ atom->map_set();
+ }
+
+ bigint nread = 0;
+ bigint natoms = nbonus;
+
+ while (nread < natoms) {
+ nchunk = MIN(natoms-nread,CHUNK);
+ eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
+ if (eof) error->all(FLERR,"Unexpected end of data file");
+ atom->data_bonus(nchunk,buffer,ptr);
+ nread += nchunk;
+ }
+
+ if (mapflag) {
+ atom->map_delete();
+ atom->map_style = 0;
+ }
+
+ if (me == 0) {
+ if (screen) fprintf(screen," " BIGINT_FORMAT " %s\n",natoms,type);
+ if (logfile) fprintf(logfile," " BIGINT_FORMAT " %s\n",natoms,type);
+ }
+}
+
+/* ----------------------------------------------------------------------
+ read all body data
+ variable amount of info per body, described by ninteger and ndouble
+ to find atoms, must build atom map if not a molecular system
+ if not firstpass, just read but no processing of data
+------------------------------------------------------------------------- */
+
+void ReadData::bodies(int firstpass)
+{
+ int i,m,nchunk,nmax,ninteger,ndouble,tmp,onebody;
+ char *eof;
+
+ int mapflag = 0;
+ if (atom->map_style == 0 && firstpass) {
+ mapflag = 1;
+ atom->map_init();
+ atom->map_set();
+ }
+
+ // nmax = max # of bodies to read in this chunk
+ // nchunk = actual # read
+
+ bigint nread = 0;
+ bigint natoms = nbodies;
+
+ while (nread < natoms) {
+ if (natoms-nread > CHUNK) nmax = CHUNK;
+ else nmax = natoms-nread;
+
+ if (me == 0) {
+ nchunk = 0;
+ nlines = 0;
+ m = 0;
+
+ while (nchunk < nmax && nlines <= CHUNK-MAXBODY) {
+ eof = fgets(&buffer[m],MAXLINE,fp);
+ if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
+ sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble);
+ m += strlen(&buffer[m]);
+
+ onebody = 0;
+ if (ninteger) onebody += (ninteger-1)/10 + 1;
+ if (ndouble) onebody += (ndouble-1)/10 + 1;
+ if (onebody+1 > MAXBODY)
+ error->one(FLERR,
+ "Too many lines in one body in data file - boost MAXBODY");
+
+ for (i = 0; i < onebody; i++) {
+ eof = fgets(&buffer[m],MAXLINE,fp);
+ if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
+ m += strlen(&buffer[m]);
+ }
+
+ nchunk++;
+ nlines += onebody+1;
+ }
+
+ if (buffer[m-1] != '\n') strcpy(&buffer[m++],"\n");
+ m++;
+ }
+
+ MPI_Bcast(&nchunk,1,MPI_INT,0,world);
+ MPI_Bcast(&m,1,MPI_INT,0,world);
+ MPI_Bcast(buffer,m,MPI_CHAR,0,world);
+
+ if (firstpass) atom->data_bodies(nchunk,buffer,avec_body);
+ nread += nchunk;
+ }
+
+ if (mapflag && firstpass) {
+ atom->map_delete();
+ atom->map_style = 0;
+ }
+
+ if (me == 0 && firstpass) {
+ if (screen) fprintf(screen," " BIGINT_FORMAT " bodies\n",natoms);
+ if (logfile) fprintf(logfile," " BIGINT_FORMAT " bodies\n",natoms);
+ }
+}
+
/* ---------------------------------------------------------------------- */
void ReadData::mass()
{
- int i;
+ int i,m;
char *next;
char *buf = new char[atom->ntypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->ntypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (i = 0; i < atom->ntypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
atom->set_mass(buf);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::paircoeffs()
{
char *next;
char *buf = new char[atom->ntypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->ntypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (int i = 0; i < atom->ntypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
parse_coeffs(buf,NULL,1);
force->pair->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::pairIJcoeffs()
{
int i,j;
char *next;
int nsq = atom->ntypes* (atom->ntypes+1) / 2;
char *buf = new char[nsq * MAXLINE];
int eof = comm->read_lines_from_file(fp,nsq,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (i = 0; i < atom->ntypes; i++)
for (j = i; j < atom->ntypes; j++) {
next = strchr(buf,'\n');
*next = '\0';
parse_coeffs(buf,NULL,0);
force->pair->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::bondcoeffs()
{
char *next;
char *buf = new char[atom->nbondtypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->nbondtypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (int i = 0; i < atom->nbondtypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
parse_coeffs(buf,NULL,0);
force->bond->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::anglecoeffs(int which)
{
char *next;
char *buf = new char[atom->nangletypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->nangletypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (int i = 0; i < atom->nangletypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
if (which == 0) parse_coeffs(buf,NULL,0);
else if (which == 1) parse_coeffs(buf,"bb",0);
else if (which == 2) parse_coeffs(buf,"ba",0);
force->angle->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::dihedralcoeffs(int which)
{
char *next;
char *buf = new char[atom->ndihedraltypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->ndihedraltypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (int i = 0; i < atom->ndihedraltypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
if (which == 0) parse_coeffs(buf,NULL,0);
else if (which == 1) parse_coeffs(buf,"mbt",0);
else if (which == 2) parse_coeffs(buf,"ebt",0);
else if (which == 3) parse_coeffs(buf,"at",0);
else if (which == 4) parse_coeffs(buf,"aat",0);
else if (which == 5) parse_coeffs(buf,"bb13",0);
force->dihedral->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ---------------------------------------------------------------------- */
void ReadData::impropercoeffs(int which)
{
char *next;
char *buf = new char[atom->nimpropertypes*MAXLINE];
int eof = comm->read_lines_from_file(fp,atom->nimpropertypes,MAXLINE,buf);
if (eof) error->all(FLERR,"Unexpected end of data file");
char *original = buf;
for (int i = 0; i < atom->nimpropertypes; i++) {
next = strchr(buf,'\n');
*next = '\0';
if (which == 0) parse_coeffs(buf,NULL,0);
else if (which == 1) parse_coeffs(buf,"aa",0);
force->improper->coeff(narg,arg);
buf = next + 1;
}
delete [] original;
}
/* ----------------------------------------------------------------------
read fix section, pass lines to fix to process
n = index of fix
------------------------------------------------------------------------- */
void ReadData::fix(int ifix, char *keyword)
{
int nchunk,eof;
bigint nlines = modify->fix[ifix]->read_data_skip_lines(keyword);
bigint nread = 0;
while (nread < nlines) {
nchunk = MIN(nlines-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) error->all(FLERR,"Unexpected end of data file");
modify->fix[ifix]->read_data_section(keyword,nchunk,buffer);
nread += nchunk;
}
}
-/* ----------------------------------------------------------------------
- proc 0 scans the data file for topology maximums
-------------------------------------------------------------------------- */
-
-void ReadData::scan(int &bond_per_atom, int &angle_per_atom,
- int &dihedral_per_atom, int &improper_per_atom)
-{
- int i,tmp1,tmp2,atom1,atom2,atom3,atom4;
- char *eof;
-
- if (atom->natoms > MAXSMALLINT)
- error->one(FLERR,"Molecular data file has too many atoms");
-
- // customize for new sections
-
- int natoms = static_cast<int> (atom->natoms);
- bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0;
- int ellipsoid_flag = 0;
- int line_flag = 0;
- int tri_flag = 0;
- int body_flag = 0;
-
- // customize for new sections
- // allocate topology counting vector
- // initially, array length = 1 to natoms
- // will grow via reallocate() if atom IDs > natoms
-
- int cmax = natoms + 1;
- int *count;
- memory->create(count,cmax,"read_data:count");
-
- while (strlen(keyword)) {
-
- // allow special fixes first chance to match and process the section
- // if fix matches, continue to next section
-
- if (nfix) {
- for (i = 0; i < nfix; i++) {
- if (strcmp(keyword,fix_section[i]) == 0) {
- int n = modify->fix[fix_index[i]]->read_data_skip_lines(keyword);
- skip_lines(n);
- parse_keyword(0,0);
- break;
- }
- }
- if (i < nfix) continue;
- }
-
- if (strcmp(keyword,"Masses") == 0) skip_lines(atom->ntypes);
- else if (strcmp(keyword,"Atoms") == 0) skip_lines(natoms);
- else if (strcmp(keyword,"Velocities") == 0) skip_lines(natoms);
-
- else if (strcmp(keyword,"Ellipsoids") == 0) {
- if (!avec_ellipsoid)
- error->one(FLERR,"Invalid data file section: Ellipsoids");
- ellipsoid_flag = 1;
- skip_lines(nellipsoids);
- } else if (strcmp(keyword,"Lines") == 0) {
- if (!avec_line) error->one(FLERR,"Invalid data file section: Lines");
- line_flag = 1;
- skip_lines(nlines);
- } else if (strcmp(keyword,"Triangles") == 0) {
- if (!avec_tri) error->one(FLERR,"Invalid data file section: Triangles");
- tri_flag = 1;
- skip_lines(ntris);
- } else if (strcmp(keyword,"Bodies") == 0) {
- if (!avec_body) error->one(FLERR,"Invalid data file section: Bodies");
- body_flag = 1;
- skip_lines(nbodies);
-
- } else if (strcmp(keyword,"Pair Coeffs") == 0) {
- if (force->pair == NULL)
- error->one(FLERR,"Must define pair_style before Pair Coeffs");
- skip_lines(atom->ntypes);
- } else if (strcmp(keyword,"PairIJ Coeffs") == 0) {
- if (force->pair == NULL)
- error->one(FLERR,"Must define pair_style before Pair Coeffs");
- skip_lines(atom->ntypes*(atom->ntypes+1)/2);
- } else if (strcmp(keyword,"Bond Coeffs") == 0) {
- if (atom->avec->bonds_allow == 0)
- error->one(FLERR,"Invalid data file section: Bond Coeffs");
- if (force->bond == NULL)
- error->one(FLERR,"Must define bond_style before Bond Coeffs");
- skip_lines(atom->nbondtypes);
- } else if (strcmp(keyword,"Angle Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->one(FLERR,"Invalid data file section: Angle Coeffs");
- if (force->angle == NULL)
- error->one(FLERR,"Must define angle_style before Angle Coeffs");
- skip_lines(atom->nangletypes);
- } else if (strcmp(keyword,"Dihedral Coeffs") == 0) {
- skip_lines(atom->ndihedraltypes);
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: Dihedral Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,"Must define dihedral_style before Dihedral Coeffs");
- } else if (strcmp(keyword,"Improper Coeffs") == 0) {
- if (atom->avec->impropers_allow == 0)
- error->one(FLERR,"Invalid data file section: Improper Coeffs");
- if (force->improper == NULL)
- error->one(FLERR,"Must define improper_style before Improper Coeffs");
- skip_lines(atom->nimpropertypes);
-
- } else if (strcmp(keyword,"BondBond Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->one(FLERR,"Invalid data file section: BondBond Coeffs");
- if (force->angle == NULL)
- error->one(FLERR,"Must define angle_style before BondBond Coeffs");
- skip_lines(atom->nangletypes);
- } else if (strcmp(keyword,"BondAngle Coeffs") == 0) {
- if (atom->avec->angles_allow == 0)
- error->one(FLERR,"Invalid data file section: BondAngle Coeffs");
- if (force->angle == NULL)
- error->one(FLERR,"Must define angle_style before BondAngle Coeffs");
- skip_lines(atom->nangletypes);
- } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: MiddleBondTorsion Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,
- "Must define dihedral_style before "
- "MiddleBondTorsion Coeffs");
- skip_lines(atom->ndihedraltypes);
- } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: EndBondTorsion Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,
- "Must define dihedral_style before EndBondTorsion Coeffs");
- skip_lines(atom->ndihedraltypes);
- } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: AngleTorsion Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,
- "Must define dihedral_style before AngleTorsion Coeffs");
- skip_lines(atom->ndihedraltypes);
- } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: AngleAngleTorsion Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,
- "Must define dihedral_style before "
- "AngleAngleTorsion Coeffs");
- skip_lines(atom->ndihedraltypes);
- } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) {
- if (atom->avec->dihedrals_allow == 0)
- error->one(FLERR,"Invalid data file section: BondBond13 Coeffs");
- if (force->dihedral == NULL)
- error->one(FLERR,"Must define dihedral_style before BondBond13 Coeffs");
- skip_lines(atom->ndihedraltypes);
- } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) {
- if (atom->avec->impropers_allow == 0)
- error->one(FLERR,"Invalid data file section: AngleAngle Coeffs");
- if (force->improper == NULL)
- error->one(FLERR,"Must define improper_style before AngleAngle Coeffs");
- skip_lines(atom->nimpropertypes);
-
- } else if (strcmp(keyword,"Bonds") == 0) {
- for (i = 1; i < cmax; i++) count[i] = 0;
- if (force->newton_bond)
- for (i = 0; i < atom->nbonds; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2);
- if (atom1 >= cmax) cmax = reallocate(&count,cmax,atom1);
- count[atom1]++;
- }
- else
- for (i = 0; i < atom->nbonds; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d",&tmp1,&tmp2,&atom1,&atom2);
- int amax = MAX(atom1,atom2);
- if (amax >= cmax) cmax = reallocate(&count,cmax,amax);
- count[atom1]++;
- count[atom2]++;
- }
- for (i = 1; i < cmax; i++) bond_per_atom = MAX(bond_per_atom,count[i]);
- if (screen) fprintf(screen," %d = max bonds/atom\n",bond_per_atom);
- if (logfile) fprintf(logfile," %d = max bonds/atom\n",bond_per_atom);
-
- } else if (strcmp(keyword,"Angles") == 0) {
- for (i = 1; i < cmax; i++) count[i] = 0;
- if (force->newton_bond)
- for (i = 0; i < atom->nangles; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3);
- if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2);
- count[atom2]++;
- }
- else
- for (i = 0; i < atom->nangles; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d",&tmp1,&tmp2,&atom1,&atom2,&atom3);
- int amax = MAX(atom1,atom2);
- amax = MAX(amax,atom3);
- if (amax >= cmax) cmax = reallocate(&count,cmax,amax);
- count[atom1]++;
- count[atom2]++;
- count[atom3]++;
- }
- for (i = 1; i < cmax; i++) angle_per_atom = MAX(angle_per_atom,count[i]);
- if (screen) fprintf(screen," %d = max angles/atom\n",angle_per_atom);
- if (logfile) fprintf(logfile," %d = max angles/atom\n",angle_per_atom);
-
- } else if (strcmp(keyword,"Dihedrals") == 0) {
- for (i = 1; i < cmax; i++) count[i] = 0;
- if (force->newton_bond)
- for (i = 0; i < atom->ndihedrals; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d %d",
- &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4);
- if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2);
- count[atom2]++;
- }
- else
- for (i = 0; i < atom->ndihedrals; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d %d",
- &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4);
- int amax = MAX(atom1,atom2);
- amax = MAX(amax,atom3);
- amax = MAX(amax,atom4);
- if (amax >= cmax) cmax = reallocate(&count,cmax,amax);
- count[atom1]++;
- count[atom2]++;
- count[atom3]++;
- count[atom4]++;
- }
- for (i = 1; i < cmax; i++)
- dihedral_per_atom = MAX(dihedral_per_atom,count[i]);
- if (screen)
- fprintf(screen," %d = max dihedrals/atom\n",dihedral_per_atom);
- if (logfile)
- fprintf(logfile," %d = max dihedrals/atom\n",dihedral_per_atom);
-
- } else if (strcmp(keyword,"Impropers") == 0) {
- for (i = 1; i < cmax; i++) count[i] = 0;
- if (force->newton_bond)
- for (i = 0; i < atom->nimpropers; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d %d",
- &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4);
- if (atom2 >= cmax) cmax = reallocate(&count,cmax,atom2);
- count[atom2]++;
- }
- else
- for (i = 0; i < atom->nimpropers; i++) {
- eof = fgets(line,MAXLINE,fp);
- if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
- sscanf(line,"%d %d %d %d %d %d",
- &tmp1,&tmp2,&atom1,&atom2,&atom3,&atom4);
- int amax = MAX(atom1,atom2);
- amax = MAX(amax,atom3);
- amax = MAX(amax,atom4);
- if (amax >= cmax) cmax = reallocate(&count,cmax,amax);
- count[atom1]++;
- count[atom2]++;
- count[atom3]++;
- count[atom4]++;
- }
- for (i = 1; i < cmax; i++)
- improper_per_atom = MAX(improper_per_atom,count[i]);
- if (screen)
- fprintf(screen," %d = max impropers/atom\n",improper_per_atom);
- if (logfile)
- fprintf(logfile," %d = max impropers/atom\n",improper_per_atom);
-
- } else {
- char str[128];
- sprintf(str,"Unknown identifier in data file: %s",keyword);
- error->one(FLERR,str);
- }
-
- parse_keyword(0,0);
- }
-
- // free topology counting vector
-
- memory->destroy(count);
-
- // error check that topology was specified in file
-
- if ((atom->nbonds && !bond_per_atom) ||
- (atom->nangles && !angle_per_atom) ||
- (atom->ndihedrals && !dihedral_per_atom) ||
- (atom->nimpropers && !improper_per_atom))
- error->one(FLERR,"Needed topology not in data file");
-
- // customize for new sections
- // error check that Bonus sections were speficied in file
-
- if (nellipsoids && !ellipsoid_flag)
- error->one(FLERR,"Needed bonus data not in data file");
- if (nlines && !line_flag)
- error->one(FLERR,"Needed bonus data not in data file");
- if (ntris && !tri_flag)
- error->one(FLERR,"Needed bonus data not in data file");
- if (nbodies && !body_flag)
- error->one(FLERR,"Needed bonus data not in data file");
-}
-
/* ----------------------------------------------------------------------
reallocate the count vector from cmax to amax+1 and return new length
zero new locations
------------------------------------------------------------------------- */
int ReadData::reallocate(int **pcount, int cmax, int amax)
{
int *count = *pcount;
memory->grow(count,amax+1,"read_data:count");
for (int i = cmax; i <= amax; i++) count[i] = 0;
*pcount = count;
return amax+1;
}
/* ----------------------------------------------------------------------
proc 0 opens data file
test if gzipped
------------------------------------------------------------------------- */
void ReadData::open(char *file)
{
compressed = 0;
char *suffix = file + strlen(file) - 3;
if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1;
if (!compressed) fp = fopen(file,"r");
else {
#ifdef LAMMPS_GZIP
char gunzip[128];
sprintf(gunzip,"gzip -c -d %s",file);
#ifdef _WIN32
fp = _popen(gunzip,"rb");
#else
fp = popen(gunzip,"r");
#endif
#else
error->one(FLERR,"Cannot open gzipped file");
#endif
}
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open file %s",file);
error->one(FLERR,str);
}
}
/* ----------------------------------------------------------------------
grab next keyword
read lines until one is non-blank
keyword is all text on line w/out leading & trailing white space
read one additional line (assumed blank)
if any read hits EOF, set keyword to empty
if first = 1, line variable holds non-blank line that ended header
- if flag = 0, only proc 0 is calling so no bcast
- else flag = 1, bcast keyword line to all procs
------------------------------------------------------------------------- */
-void ReadData::parse_keyword(int first, int flag)
+void ReadData::parse_keyword(int first)
{
int eof = 0;
// proc 0 reads upto non-blank line plus 1 following line
// eof is set to 1 if any read hits end-of-file
if (me == 0) {
if (!first) {
if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
}
while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) {
if (fgets(line,MAXLINE,fp) == NULL) eof = 1;
}
if (fgets(buffer,MAXLINE,fp) == NULL) eof = 1;
}
// if eof, set keyword empty and return
- if (flag) MPI_Bcast(&eof,1,MPI_INT,0,world);
+ MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) {
keyword[0] = '\0';
return;
}
// bcast keyword line to all procs
- if (flag) {
- int n;
- if (me == 0) n = strlen(line) + 1;
- MPI_Bcast(&n,1,MPI_INT,0,world);
- MPI_Bcast(line,n,MPI_CHAR,0,world);
- }
+ int n;
+ if (me == 0) n = strlen(line) + 1;
+ MPI_Bcast(&n,1,MPI_INT,0,world);
+ MPI_Bcast(line,n,MPI_CHAR,0,world);
// handle comments following the keyword
// truncate string and increment pointer over whitespace
char *ptr;
if ((ptr = strrchr(line,'#'))) {
*ptr++ = '\0';
while (*ptr == ' ' || *ptr == '\t') ++ptr;
int stop = strlen(ptr) - 1;
while (ptr[stop] == ' ' || ptr[stop] == '\t'
|| ptr[stop] == '\n' || ptr[stop] == '\r') stop--;
ptr[stop+1] = '\0';
strcpy(style,ptr);
} else style[0] = '\0';
// copy non-whitespace portion of line into keyword
int start = strspn(line," \t\n\r");
int stop = strlen(line) - 1;
while (line[stop] == ' ' || line[stop] == '\t'
|| line[stop] == '\n' || line[stop] == '\r') stop--;
line[stop+1] = '\0';
strcpy(keyword,&line[start]);
}
/* ----------------------------------------------------------------------
proc 0 reads N lines from file
- NOTE: needs to be called with bigint in some cases
- if called with int, will it be promoted to bigint?
+ could be skipping Natoms lines, so use bigints
------------------------------------------------------------------------- */
-void ReadData::skip_lines(int n)
+void ReadData::skip_lines(bigint n)
{
+ if (me) return;
char *eof;
- for (int i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp);
+ for (bigint i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp);
if (eof == NULL) error->one(FLERR,"Unexpected end of data file");
}
/* ----------------------------------------------------------------------
parse a line of coeffs into words, storing them in narg,arg
trim anything from '#' onward
word strings remain in line, are not copied
if addstr != NULL, add addstr as extra arg for class2 angle/dihedral/improper
if 2nd word starts with letter, then is hybrid style, add addstr after it
else add addstr before 2nd word
if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2"
------------------------------------------------------------------------- */
void ReadData::parse_coeffs(char *line, const char *addstr, int dupflag)
{
char *ptr;
if ((ptr = strchr(line,'#'))) *ptr = '\0';
narg = 0;
char *word = strtok(line," \t\n\r\f");
while (word) {
if (narg == maxarg) {
maxarg += DELTA;
arg = (char **)
memory->srealloc(arg,maxarg*sizeof(char *),"read_data:arg");
}
if (addstr && narg == 1 && !islower(word[0])) arg[narg++] = (char *) addstr;
arg[narg++] = word;
if (addstr && narg == 2 && islower(word[0])) arg[narg++] = (char *) addstr;
if (dupflag && narg == 1) arg[narg++] = word;
word = strtok(NULL," \t\n\r\f");
}
}
diff --git a/src/read_data.h b/src/read_data.h
index 6169532aa..e9100105a 100644
--- a/src/read_data.h
+++ b/src/read_data.h
@@ -1,428 +1,430 @@
/* -*- 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 COMMAND_CLASS
CommandStyle(read_data,ReadData)
#else
#ifndef LMP_READ_DATA_H
#define LMP_READ_DATA_H
#include "stdio.h"
#include "pointers.h"
namespace LAMMPS_NS {
class ReadData : protected Pointers {
public:
ReadData(class LAMMPS *);
~ReadData();
void command(int, char **);
private:
char *line,*keyword,*buffer,*style;
FILE *fp;
char **arg;
int me,narg,maxarg,compressed;
- int nfix; // # of extra fixes that process/store info in data file
+ int nfix; // # of extra fixes that process/store info in data file
int *fix_index;
char **fix_header;
char **fix_section;
bigint nellipsoids;
class AtomVecEllipsoid *avec_ellipsoid;
bigint nlines;
class AtomVecLine *avec_line;
bigint ntris;
class AtomVecTri *avec_tri;
bigint nbodies;
class AtomVecBody *avec_body;
void open(char *);
void scan(int &, int &, int &, int &);
int reallocate(int **, int, int);
- void header(int);
- void parse_keyword(int, int);
- void skip_lines(int);
+ void header();
+ void parse_keyword(int);
+ void skip_lines(bigint);
void parse_coeffs(char *, const char *, int);
void atoms();
void velocities();
- void bonus(bigint, class AtomVec *, const char *);
- void bodies();
- void bonds();
- void angles();
- void dihedrals();
- void impropers();
+ void bonds(int);
+ void bond_scan(int, char *, int *);
+ void angles(int);
+ void dihedrals(int);
+ void impropers(int);
+
+ void bonus(bigint, class AtomVec *, const char *);
+ void bodies(int);
void mass();
void paircoeffs();
void pairIJcoeffs();
void bondcoeffs();
void anglecoeffs(int);
void dihedralcoeffs(int);
void impropercoeffs(int);
void fix(int, char *);
};
}
#endif
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: Cannot read_data after simulation box is defined
The read_data command cannot be used after a read_data,
read_restart, or create_box command.
E: Cannot run 2d simulation with nonperiodic Z dimension
Use the boundary command to make the z dimension periodic in order to
run a 2d simulation.
E: Fix ID for read_data does not exist
Self-explanatory.
E: Must read Atoms before Velocities
The Atoms section of a data file must come before a Velocities
section.
E: Invalid data file section: Ellipsoids
Atom style does not allow ellipsoids.
E: Must read Atoms before Ellipsoids
The Atoms section of a data file must come before a Ellipsoids
section.
E: Invalid data file section: Lines
Atom style does not allow lines.
E: Must read Atoms before Lines
The Atoms section of a data file must come before a Lines section.
E: Invalid data file section: Triangles
Atom style does not allow triangles.
E: Must read Atoms before Triangles
The Atoms section of a data file must come before a Triangles section.
E: Invalid data file section: Bodies
Atom style does not allow bodies.
E: Must read Atoms before Bodies
The Atoms section of a data file must come before a Bodies section.
E: Invalid data file section: Bonds
Atom style does not allow bonds.
E: Must read Atoms before Bonds
The Atoms section of a data file must come before a Bonds section.
E: Invalid data file section: Angles
Atom style does not allow angles.
E: Must read Atoms before Angles
The Atoms section of a data file must come before an Angles section.
E: Invalid data file section: Dihedrals
Atom style does not allow dihedrals.
E: Must read Atoms before Dihedrals
The Atoms section of a data file must come before a Dihedrals section.
E: Invalid data file section: Impropers
Atom style does not allow impropers.
E: Must read Atoms before Impropers
The Atoms section of a data file must come before an Impropers
section.
E: Must define pair_style before Pair Coeffs
Must use a pair_style command before reading a data file that defines
Pair Coeffs.
E: Must define pair_style before PairIJ Coeffs
UNDOCUMENTED
E: Invalid data file section: Bond Coeffs
Atom style does not allow bonds.
E: Must define bond_style before Bond Coeffs
Must use a bond_style command before reading a data file that
defines Bond Coeffs.
E: Invalid data file section: Angle Coeffs
Atom style does not allow angles.
E: Must define angle_style before Angle Coeffs
Must use an angle_style command before reading a data file that
defines Angle Coeffs.
E: Invalid data file section: Dihedral Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before Dihedral Coeffs
Must use a dihedral_style command before reading a data file that
defines Dihedral Coeffs.
E: Invalid data file section: Improper Coeffs
Atom style does not allow impropers.
E: Must define improper_style before Improper Coeffs
Must use an improper_style command before reading a data file that
defines Improper Coeffs.
E: Invalid data file section: BondBond Coeffs
Atom style does not allow angles.
E: Must define angle_style before BondBond Coeffs
Must use an angle_style command before reading a data file that
defines Angle Coeffs.
E: Invalid data file section: BondAngle Coeffs
Atom style does not allow angles.
E: Must define angle_style before BondAngle Coeffs
Must use an angle_style command before reading a data file that
defines Angle Coeffs.
E: Invalid data file section: MiddleBondTorsion Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before MiddleBondTorsion Coeffs
Must use a dihedral_style command before reading a data file that
defines MiddleBondTorsion Coeffs.
E: Invalid data file section: EndBondTorsion Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before EndBondTorsion Coeffs
Must use a dihedral_style command before reading a data file that
defines EndBondTorsion Coeffs.
E: Invalid data file section: AngleTorsion Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before AngleTorsion Coeffs
Must use a dihedral_style command before reading a data file that
defines AngleTorsion Coeffs.
E: Invalid data file section: AngleAngleTorsion Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before AngleAngleTorsion Coeffs
Must use a dihedral_style command before reading a data file that
defines AngleAngleTorsion Coeffs.
E: Invalid data file section: BondBond13 Coeffs
Atom style does not allow dihedrals.
E: Must define dihedral_style before BondBond13 Coeffs
Must use a dihedral_style command before reading a data file that
defines BondBond13 Coeffs.
E: Invalid data file section: AngleAngle Coeffs
Atom style does not allow impropers.
E: Must define improper_style before AngleAngle Coeffs
Must use an improper_style command before reading a data file that
defines AngleAngle Coeffs.
E: Unknown identifier in data file: %s
A section of the data file cannot be read by LAMMPS.
E: No atoms in data file
The header of the data file indicated that atoms would be included,
but they were not present.
E: Unexpected end of data file
LAMMPS hit the end of the data file while attempting to read a
section. Something is wrong with the format of the data file.
E: No ellipsoids allowed with this atom style
Self-explanatory. Check data file.
E: No lines allowed with this atom style
Self-explanatory. Check data file.
E: No triangles allowed with this atom style
Self-explanatory. Check data file.
E: No bodies allowed with this atom style
Self-explanatory. Check data file.
E: System in data file is too big
See the setting for bigint in the src/lmptype.h file.
E: No bonds allowed with this atom style
Self-explanatory. Check data file.
E: No angles allowed with this atom style
Self-explanatory. Check data file.
E: No dihedrals allowed with this atom style
Self-explanatory. Check data file.
E: No impropers allowed with this atom style
Self-explanatory. Check data file.
E: Bonds defined but no bond types
The data file header lists bonds but no bond types.
E: Angles defined but no angle types
The data file header lists angles but no angle types.
E: Dihedrals defined but no dihedral types
The data file header lists dihedrals but no dihedral types.
E: Impropers defined but no improper types
The data file header lists improper but no improper types.
E: Did not assign all atoms correctly
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.
E: Invalid atom ID in Atoms section of data file
Atom IDs must be positive integers.
E: Too many lines in one body in data file - boost MAXBODY
MAXBODY is a setting at the top of the src/read_data.cpp file.
Set it larger and re-compile the code.
E: Bonds assigned incorrectly
Bonds read in from the data file were not assigned correctly to atoms.
This means there is something invalid about the topology definitions.
E: Angles assigned incorrectly
Angles read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions.
E: Dihedrals assigned incorrectly
Dihedrals read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions.
E: Impropers assigned incorrectly
Impropers read in from the data file were not assigned correctly to
atoms. This means there is something invalid about the topology
definitions.
E: Molecular data file has too many atoms
These kids of data files are currently limited to a number
of atoms that fits in a 32-bit integer.
E: Needed topology not in data file
The header of the data file indicated that bonds or angles or
dihedrals or impropers would be included, but they were not present.
E: Needed bonus data not in data file
Some atom styles require bonus data. See the read_data doc page for
details.
E: Cannot open gzipped file
LAMMPS was compiled without support for reading and writing gzipped
files through a pipeline to the gzip program with -DLAMMPS_GZIP.
E: Cannot open file %s
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.
*/
diff --git a/src/read_dump.cpp b/src/read_dump.cpp
index 6196f876c..3256d28a4 100644
--- a/src/read_dump.cpp
+++ b/src/read_dump.cpp
@@ -1,944 +1,948 @@
/* ----------------------------------------------------------------------
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: Timothy Sirk (ARL)
------------------------------------------------------------------------- */
#include "lmptype.h"
#include "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "read_dump.h"
#include "reader.h"
#include "style_reader.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "domain.h"
#include "comm.h"
#include "irregular.h"
#include "error.h"
#include "memory.h"
using namespace LAMMPS_NS;
#define CHUNK 1024
#define EPSILON 1.0e-6
// also in reader_native.cpp
enum{ID,TYPE,X,Y,Z,VX,VY,VZ,Q,IX,IY,IZ};
enum{UNSET,NOSCALE_NOWRAP,NOSCALE_WRAP,SCALE_NOWRAP,SCALE_WRAP};
/* ---------------------------------------------------------------------- */
ReadDump::ReadDump(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
dimension = domain->dimension;
triclinic = domain->triclinic;
nfile = 0;
files = NULL;
nfield = 0;
fieldtype = NULL;
fieldlabel = NULL;
fields = NULL;
int n = strlen("native") + 1;
readerstyle = new char[n];
strcpy(readerstyle,"native");
reader = NULL;
fp = NULL;
}
/* ---------------------------------------------------------------------- */
ReadDump::~ReadDump()
{
for (int i = 0; i < nfile; i++) delete [] files[i];
delete [] files;
for (int i = 0; i < nfield; i++) delete [] fieldlabel[i];
delete [] fieldlabel;
delete [] fieldtype;
delete [] readerstyle;
memory->destroy(fields);
delete reader;
}
/* ---------------------------------------------------------------------- */
void ReadDump::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"Read_dump command before simulation box is defined");
if (narg < 2) error->all(FLERR,"Illegal read_dump command");
store_files(1,&arg[0]);
bigint nstep = ATOBIGINT(arg[1]);
int nremain = narg - 2;
if (nremain) nremain = fields_and_keywords(nremain,&arg[narg-nremain]);
else nremain = fields_and_keywords(0,NULL);
if (nremain) setup_reader(nremain,&arg[narg-nremain]);
else setup_reader(0,NULL);
// find the snapshot and read/bcast/process header info
if (me == 0 && screen) fprintf(screen,"Scanning dump file ...\n");
bigint ntimestep = seek(nstep,1);
if (ntimestep < 0)
error->all(FLERR,"Dump file does not contain requested snapshot");
header(1);
// reset timestep to nstep
update->reset_timestep(nstep);
// counters
// read in the snapshot and reset system
if (me == 0 && screen)
fprintf(screen,"Reading snapshot from dump file ...\n");
bigint natoms_prev = atom->natoms;
atoms();
if (me == 0) reader->close_file();
// print out stats
bigint npurge_all,nreplace_all,ntrim_all,nadd_all;
bigint tmp;
tmp = npurge;
MPI_Allreduce(&tmp,&npurge_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
tmp = nreplace;
MPI_Allreduce(&tmp,&nreplace_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
tmp = ntrim;
MPI_Allreduce(&tmp,&ntrim_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
tmp = nadd;
MPI_Allreduce(&tmp,&nadd_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
domain->print_box(" ");
if (me == 0) {
if (screen) {
fprintf(screen," " BIGINT_FORMAT " atoms before read\n",natoms_prev);
fprintf(screen," " BIGINT_FORMAT " atoms in snapshot\n",nsnapatoms);
fprintf(screen," " BIGINT_FORMAT " atoms purged\n",npurge_all);
fprintf(screen," " BIGINT_FORMAT " atoms replaced\n",nreplace_all);
fprintf(screen," " BIGINT_FORMAT " atoms trimmed\n",ntrim_all);
fprintf(screen," " BIGINT_FORMAT " atoms added\n",nadd_all);
fprintf(screen," " BIGINT_FORMAT " atoms after read\n",atom->natoms);
}
if (logfile) {
fprintf(logfile," " BIGINT_FORMAT " atoms before read\n",natoms_prev);
fprintf(logfile," " BIGINT_FORMAT " atoms in snapshot\n",nsnapatoms);
fprintf(logfile," " BIGINT_FORMAT " atoms purged\n",npurge_all);
fprintf(logfile," " BIGINT_FORMAT " atoms replaced\n",nreplace_all);
fprintf(logfile," " BIGINT_FORMAT " atoms trimmed\n",ntrim_all);
fprintf(logfile," " BIGINT_FORMAT " atoms added\n",nadd_all);
fprintf(logfile," " BIGINT_FORMAT " atoms after read\n",atom->natoms);
}
}
}
/* ---------------------------------------------------------------------- */
void ReadDump::store_files(int nstr, char **str)
{
nfile = nstr;
files = new char*[nfile];
for (int i = 0; i < nfile; i++) {
int n = strlen(str[i]) + 1;
files[i] = new char[n];
strcpy(files[i],str[i]);
}
}
/* ---------------------------------------------------------------------- */
void ReadDump::setup_reader(int narg, char **arg)
{
// allocate snapshot field buffer
memory->create(fields,CHUNK,nfield,"read_dump:fields");
// create reader class
// match readerstyle to options in style_reader.h
if (0) return; // dummy line to enable else-if macro expansion
#define READER_CLASS
#define ReaderStyle(key,Class) \
else if (strcmp(readerstyle,#key) == 0) reader = new Class(lmp);
#include "style_reader.h"
#undef READER_CLASS
// unrecognized style
else error->all(FLERR,"Invalid dump reader style");
// pass any arguments to reader
if (narg > 0) reader->settings(narg,arg);
}
/* ----------------------------------------------------------------------
seek Nrequest timestep in one or more dump files
if exact = 1, must find exactly Nrequest
if exact = 0, find first step >= Nrequest
return matching ntimestep or -1 if did not find a match
------------------------------------------------------------------------- */
bigint ReadDump::seek(bigint nrequest, int exact)
{
int ifile,eofflag;
bigint ntimestep;
if (me == 0) {
// exit file loop when dump timestep >= nrequest
// or files exhausted
for (ifile = 0; ifile < nfile; ifile++) {
ntimestep = -1;
reader->open_file(files[ifile]);
while (1) {
eofflag = reader->read_time(ntimestep);
if (eofflag) break;
if (ntimestep >= nrequest) break;
reader->skip();
}
if (ntimestep >= nrequest) break;
reader->close_file();
}
currentfile = ifile;
if (ntimestep < nrequest) ntimestep = -1;
if (exact && ntimestep != nrequest) ntimestep = -1;
if (ntimestep < 0) reader->close_file();
}
MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
return ntimestep;
}
/* ----------------------------------------------------------------------
find next matching snapshot in one or more dump files
Ncurrent = current timestep from last snapshot
Nlast = match no timestep bigger than Nlast
Nevery = only match timesteps that are a multiple of Nevery
Nskip = skip every this many timesteps
return matching ntimestep or -1 if did not find a match
------------------------------------------------------------------------- */
bigint ReadDump::next(bigint ncurrent, bigint nlast, int nevery, int nskip)
{
int ifile,eofflag;
bigint ntimestep;
if (me == 0) {
// exit file loop when dump timestep matches all criteria
// or files exhausted
int iskip = 0;
for (ifile = currentfile; ifile < nfile; ifile++) {
ntimestep = -1;
if (ifile != currentfile) reader->open_file(files[ifile]);
while (1) {
eofflag = reader->read_time(ntimestep);
if (iskip == nskip) iskip = 0;
iskip++;
if (eofflag) break;
if (ntimestep <= ncurrent) break;
if (ntimestep > nlast) break;
if (nevery && ntimestep % nevery) reader->skip();
else if (iskip < nskip) reader->skip();
else break;
}
if (eofflag) reader->close_file();
else break;
}
currentfile = ifile;
if (eofflag) ntimestep = -1;
if (ntimestep <= ncurrent) ntimestep = -1;
if (ntimestep > nlast) ntimestep = -1;
if (ntimestep < 0) reader->close_file();
}
MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
return ntimestep;
}
/* ----------------------------------------------------------------------
read and broadcast and store snapshot header info
set nsnapatoms = # of atoms in snapshot
------------------------------------------------------------------------- */
void ReadDump::header(int fieldinfo)
{
int triclinic_snap;
int fieldflag,xflag,yflag,zflag;
if (me == 0)
nsnapatoms = reader->read_header(box,triclinic_snap,
fieldinfo,nfield,fieldtype,fieldlabel,
scaleflag,wrapflag,fieldflag,
xflag,yflag,zflag);
MPI_Bcast(&nsnapatoms,1,MPI_LMP_BIGINT,0,world);
MPI_Bcast(&triclinic_snap,1,MPI_INT,0,world);
MPI_Bcast(&box[0][0],9,MPI_DOUBLE,0,world);
// local copy of snapshot box parameters
// used in xfield,yfield,zfield when converting dump atom to absolute coords
xlo = box[0][0];
xhi = box[0][1];
ylo = box[1][0];
yhi = box[1][1];
zlo = box[2][0];
zhi = box[2][1];
if (triclinic_snap) {
xy = box[0][2];
xz = box[1][2];
yz = box[2][2];
double xdelta = MIN(0.0,xy);
xdelta = MIN(xdelta,xz);
xdelta = MIN(xdelta,xy+xz);
xlo = xlo - xdelta;
xdelta = MAX(0.0,xy);
xdelta = MAX(xdelta,xz);
xdelta = MAX(xdelta,xy+xz);
xhi = xhi - xdelta;
ylo = ylo - MIN(0.0,yz);
yhi = yhi - MAX(0.0,yz);
}
xprd = xhi - xlo;
yprd = yhi - ylo;
zprd = zhi - zlo;
// done if not checking fields
if (!fieldinfo) return;
MPI_Bcast(&fieldflag,1,MPI_INT,0,world);
MPI_Bcast(&xflag,1,MPI_INT,0,world);
MPI_Bcast(&yflag,1,MPI_INT,0,world);
MPI_Bcast(&zflag,1,MPI_INT,0,world);
// error check on current vs new box and fields
// triclinic_snap < 0 means no box info in file
if (triclinic_snap < 0 && boxflag > 0)
error->all(FLERR,"No box information in dump. You have to use 'box no'");
if (triclinic_snap >= 0) {
if ((triclinic_snap && !triclinic) ||
(!triclinic_snap && triclinic))
error->one(FLERR,"Read_dump triclinic status does not match simulation");
}
// error check on requested fields exisiting in dump file
if (fieldflag < 0)
error->one(FLERR,"Read_dump field not found in dump file");
// all explicitly requested x,y,z must have consistent scaling & wrapping
int value = MAX(xflag,yflag);
value = MAX(zflag,value);
if ((xflag != UNSET && xflag != value) ||
(yflag != UNSET && yflag != value) ||
(zflag != UNSET && zflag != value))
error->one(FLERR,
"Read_dump xyz fields do not have consistent scaling/wrapping");
// set scaled/wrapped based on xyz flags
value = UNSET;
if (xflag != UNSET) value = xflag;
if (yflag != UNSET) value = yflag;
if (zflag != UNSET) value = zflag;
if (value == UNSET) {
scaled = wrapped = 0;
} else if (value == NOSCALE_NOWRAP) {
scaled = wrapped = 0;
} else if (value == NOSCALE_WRAP) {
scaled = 0;
wrapped = 1;
} else if (value == SCALE_NOWRAP) {
scaled = 1;
wrapped = 0;
} else if (value == SCALE_WRAP) {
scaled = wrapped = 1;
}
// scaled, triclinic coords require all 3 x,y,z fields, to perform unscaling
// set yindex,zindex = column index of Y and Z fields in fields array
// needed for unscaling to absolute coords in xfield(), yfield(), zfield()
if (scaled && triclinic == 1) {
int flag = 0;
if (xflag == UNSET) flag = 1;
if (yflag == UNSET) flag = 1;
if (dimension == 3 && zflag == UNSET) flag = 1;
if (flag)
error->one(FLERR,"All read_dump x,y,z fields must be specified for "
"scaled, triclinic coords");
for (int i = 0; i < nfield; i++) {
if (fieldtype[i] == Y) yindex = i;
if (fieldtype[i] == Z) zindex = i;
}
}
}
/* ---------------------------------------------------------------------- */
void ReadDump::atoms()
{
// initialize counters
npurge = nreplace = ntrim = nadd = 0;
// if purgeflag set, delete all current atoms
if (purgeflag) {
if (atom->map_style) atom->map_clear();
npurge = atom->nlocal;
atom->nlocal = atom->nghost = 0;
atom->natoms = 0;
}
// to match existing atoms to dump atoms:
// must build map if not a molecular system
int mapflag = 0;
if (atom->map_style == 0) {
mapflag = 1;
- atom->map_style = 1;
atom->map_init();
atom->map_set();
}
// uflag[i] = 1 for each owned atom appearing in dump
// ucflag = similar flag for each chunk atom, used in process_atoms()
int nlocal = atom->nlocal;
memory->create(uflag,nlocal,"read_dump:uflag");
for (int i = 0; i < nlocal; i++) uflag[i] = 0;
memory->create(ucflag,CHUNK,"read_dump:ucflag");
memory->create(ucflag_all,CHUNK,"read_dump:ucflag");
// read, broadcast, and process atoms from snapshot in chunks
addproc = -1;
int nchunk;
bigint nread = 0;
while (nread < nsnapatoms) {
nchunk = MIN(nsnapatoms-nread,CHUNK);
if (me == 0) reader->read_atoms(nchunk,nfield,fields);
MPI_Bcast(&fields[0][0],nchunk*nfield,MPI_DOUBLE,0,world);
process_atoms(nchunk);
nread += nchunk;
}
// if addflag set, add tags to new atoms if possible
if (addflag) {
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
- if (atom->natoms < 0 || atom->natoms > MAXBIGINT)
+ if (atom->natoms < 0 || atom->natoms >= MAXBIGINT)
error->all(FLERR,"Too many total atoms");
- // change these to MAXTAGINT when allow tagint = bigint
- if (atom->natoms > MAXSMALLINT) atom->tag_enable = 0;
- if (atom->natoms <= MAXSMALLINT) atom->tag_extend();
+ if (atom->tag_enable) atom->tag_extend();
}
// if trimflag set, delete atoms not replaced by snapshot atoms
if (trimflag) {
delete_atoms();
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
}
// can now delete uflag arrays
memory->destroy(uflag);
memory->destroy(ucflag);
memory->destroy(ucflag_all);
// delete atom map if created it above
// else reinitialize map for current atoms
// do this before migrating atoms to new procs via Irregular
if (mapflag) {
atom->map_delete();
atom->map_style = 0;
} else {
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
// overwrite simulation box with dump snapshot box if requested
// reallocate processors to box
if (boxflag) {
domain->boxlo[0] = xlo;
domain->boxhi[0] = xhi;
domain->boxlo[1] = ylo;
domain->boxhi[1] = yhi;
if (dimension == 3) {
domain->boxlo[2] = zlo;
domain->boxhi[2] = zhi;
}
if (triclinic) {
domain->xy = xy;
if (dimension == 3) {
domain->xz = xz;
domain->yz = yz;
}
}
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid(0);
domain->set_local_box();
}
// move atoms back inside simulation box and to new processors
// use remap() instead of pbc() in case atoms moved a long distance
// adjust image flags of all atoms (old and new) based on current box
// use irregular() in case atoms moved a long distance
double **x = atom->x;
imageint *image = atom->image;
nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);
if (triclinic) domain->x2lamda(atom->nlocal);
domain->reset_box();
Irregular *irregular = new Irregular(lmp);
irregular->migrate_atoms();
delete irregular;
if (triclinic) domain->lamda2x(atom->nlocal);
+
+ // check that atom IDs are valid
+
+ atom->tag_check();
}
/* ----------------------------------------------------------------------
process arg list for dump file fields and optional keywords
------------------------------------------------------------------------- */
int ReadDump::fields_and_keywords(int narg, char **arg)
{
// per-field vectors, leave space for ID and TYPE
fieldtype = new int[narg+2];
fieldlabel = new char*[narg+2];
// add id and type fields as needed
// scan ahead to see if "add yes" keyword/value is used
// requires extra "type" field from from dump file
int iarg;
for (iarg = 0; iarg < narg; iarg++)
if (strcmp(arg[iarg],"add") == 0)
if (iarg < narg-1 && strcmp(arg[iarg+1],"yes") == 0) break;
nfield = 0;
fieldtype[nfield++] = ID;
if (iarg < narg) fieldtype[nfield++] = TYPE;
// parse fields
iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"x") == 0) fieldtype[nfield++] = X;
else if (strcmp(arg[iarg],"y") == 0) fieldtype[nfield++] = Y;
else if (strcmp(arg[iarg],"z") == 0) fieldtype[nfield++] = Z;
else if (strcmp(arg[iarg],"vx") == 0) fieldtype[nfield++] = VX;
else if (strcmp(arg[iarg],"vy") == 0) fieldtype[nfield++] = VY;
else if (strcmp(arg[iarg],"vz") == 0) fieldtype[nfield++] = VZ;
else if (strcmp(arg[iarg],"q") == 0) {
if (!atom->q_flag)
error->all(FLERR,"Read dump of atom property that isn't allocated");
fieldtype[nfield++] = Q;
}
else if (strcmp(arg[iarg],"ix") == 0) fieldtype[nfield++] = IX;
else if (strcmp(arg[iarg],"iy") == 0) fieldtype[nfield++] = IY;
else if (strcmp(arg[iarg],"iz") == 0) fieldtype[nfield++] = IZ;
else break;
iarg++;
}
// check for no fields
if (fieldtype[nfield-1] == ID || fieldtype[nfield-1] == TYPE)
error->all(FLERR,"Illegal read_dump command");
if (dimension == 2) {
for (int i = 0; i < nfield; i++)
if (fieldtype[i] == Z || fieldtype[i] == VZ || fieldtype[i] == IZ)
error->all(FLERR,"Illegal read_dump command");
}
for (int i = 0; i < nfield; i++)
for (int j = i+1; j < nfield; j++)
if (fieldtype[i] == fieldtype[j])
error->all(FLERR,"Duplicate fields in read_dump command");
// parse optional args
boxflag = 1;
replaceflag = 1;
purgeflag = 0;
trimflag = 0;
addflag = 0;
for (int i = 0; i < nfield; i++) fieldlabel[i] = NULL;
scaleflag = 0;
wrapflag = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"box") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) boxflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) boxflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"replace") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) replaceflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) replaceflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"purge") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) purgeflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) purgeflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"trim") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) trimflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) trimflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"add") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) addflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) addflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"label") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal read_dump command");
int i;
for (i = 0; i < nfield; i++)
if (fieldlabel[i] && strcmp(arg[iarg+1],fieldlabel[i]) == 0) break;
if (i == nfield) error->all(FLERR,"Illegal read_dump command");
int n = strlen(arg[iarg+2]) + 1;
fieldlabel[i] = new char[n];
strcpy(fieldlabel[i],arg[iarg+2]);
iarg += 3;
} else if (strcmp(arg[iarg],"scaled") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) scaleflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) scaleflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"wrapped") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
if (strcmp(arg[iarg+1],"yes") == 0) wrapflag = 1;
else if (strcmp(arg[iarg+1],"no") == 0) wrapflag = 0;
else error->all(FLERR,"Illegal read_dump command");
iarg += 2;
} else if (strcmp(arg[iarg],"format") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
delete [] readerstyle;
int n = strlen(arg[iarg+1]) + 1;
readerstyle = new char[n];
strcpy(readerstyle,arg[iarg+1]);
iarg += 2;
break;
} else error->all(FLERR,"Illegal read_dump command");
}
if (purgeflag && (replaceflag || trimflag))
error->all(FLERR,"If read_dump purges it cannot replace or trim");
return narg-iarg;
}
/* ----------------------------------------------------------------------
process each of N atoms in chunk read from dump file
if in replace mode and atom ID matches current atom,
overwrite atom info with fields from dump file
if in add mode and atom ID does not match any current atom,
create new atom with dump file field values,
and assign to a proc in round-robin manner
use round-robin method, b/c atom coords may not be inside simulation box
------------------------------------------------------------------------- */
void ReadDump::process_atoms(int n)
{
- int i,m,ifield,itype,itag;;
+ int i,m,ifield,itype;
int xbox,ybox,zbox;
+ tagint tag;
double **x = atom->x;
double **v = atom->v;
double *q = atom->q;
imageint *image = atom->image;
int nlocal = atom->nlocal;
- int map_tag_max = atom->map_tag_max;
+ tagint map_tag_max = atom->map_tag_max;
for (i = 0; i < n; i++) {
ucflag[i] = 0;
// check if new atom matches one I own
// setting m = -1 forces new atom not to match
+ // NOTE: atom ID in fields is stored as double, not as ubuf
+ // so can only cast it to tagint, thus cannot be full 64-bit ID
- itag = static_cast<int> (fields[i][0]);
- if (itag <= map_tag_max) m = atom->map(static_cast<int> (fields[i][0]));
+ tag = static_cast<tagint> (fields[i][0]);
+ if (tag <= map_tag_max) m = atom->map(tag);
else m = -1;
if (m < 0 || m >= nlocal) continue;
ucflag[i] = 1;
uflag[m] = 1;
if (replaceflag) {
nreplace++;
// current image flags
xbox = (image[m] & IMGMASK) - IMGMAX;
ybox = (image[m] >> IMGBITS & IMGMASK) - IMGMAX;
zbox = (image[m] >> IMG2BITS) - IMGMAX;
// overwrite atom attributes with field info
// start from field 1 since 0 = id, 1 will be skipped if type
for (ifield = 1; ifield < nfield; ifield++) {
switch (fieldtype[ifield]) {
case X:
x[m][0] = xfield(i,ifield);
break;
case Y:
x[m][1] = yfield(i,ifield);
break;
case Z:
x[m][2] = zfield(i,ifield);
break;
case VX:
v[m][0] = fields[i][ifield];
break;
case Q:
q[m] = fields[i][ifield];
break;
case VY:
v[m][1] = fields[i][ifield];
break;
case VZ:
v[m][2] = fields[i][ifield];
break;
case IX:
xbox = static_cast<int> (fields[i][ifield]);
break;
case IY:
ybox = static_cast<int> (fields[i][ifield]);
break;
case IZ:
zbox = static_cast<int> (fields[i][ifield]);
break;
}
}
// replace image flag in case changed by ix,iy,iz fields or unwrapping
if (!wrapped) xbox = ybox = zbox = 0;
image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
}
}
// create any atoms in chunk that no processor owned
// add atoms in round-robin sequence on processors
// cannot do it geometrically b/c dump coords may not be in simulation box
if (!addflag) return;
MPI_Allreduce(ucflag,ucflag_all,n,MPI_INT,MPI_SUM,world);
int nlocal_previous = atom->nlocal;
double one[3];
for (i = 0; i < n; i++) {
if (ucflag_all[i]) continue;
// each processor adds every Pth atom
addproc++;
if (addproc == nprocs) addproc = 0;
if (addproc != me) continue;
// create type and coord fields from dump file
// coord = 0.0 unless corresponding dump file field was specified
one[0] = one[1] = one[2] = 0.0;
for (ifield = 1; ifield < nfield; ifield++) {
switch (fieldtype[ifield]) {
case TYPE:
itype = static_cast<int> (fields[i][ifield]);
break;
case X:
one[0] = xfield(i,ifield);
break;
case Y:
one[1] = yfield(i,ifield);
break;
case Z:
one[2] = zfield(i,ifield);
break;
}
}
// create the atom on proc that owns it
// reset v,image ptrs in case they are reallocated
m = atom->nlocal;
atom->avec->create_atom(itype,one);
nadd++;
v = atom->v;
q = atom->q;
image = atom->image;
// set atom attributes from other dump file fields
xbox = ybox = zbox = 0;
for (ifield = 1; ifield < nfield; ifield++) {
switch (fieldtype[ifield]) {
case VX:
v[m][0] = fields[i][ifield];
break;
case VY:
v[m][1] = fields[i][ifield];
break;
case VZ:
v[m][2] = fields[i][ifield];
break;
case Q:
q[m] = fields[i][ifield];
break;
case IX:
xbox = static_cast<int> (fields[i][ifield]);
break;
case IY:
ybox = static_cast<int> (fields[i][ifield]);
break;
case IZ:
zbox = static_cast<int> (fields[i][ifield]);
break;
}
// replace image flag in case changed by ix,iy,iz fields
image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
}
}
// invoke set_arrays() for fixes that need initialization of new atoms
// same as in CreateAtoms
nlocal = atom->nlocal;
for (m = 0; m < modify->nfix; m++) {
Fix *fix = modify->fix[m];
if (fix->create_attribute)
for (i = nlocal_previous; i < nlocal; i++)
fix->set_arrays(i);
}
}
/* ----------------------------------------------------------------------
delete atoms not flagged as replaced by dump atoms
------------------------------------------------------------------------- */
void ReadDump::delete_atoms()
{
AtomVec *avec = atom->avec;
int nlocal = atom->nlocal;
int i = 0;
while (i < nlocal) {
if (uflag[i] == 0) {
avec->copy(nlocal-1,i,1);
uflag[i] = uflag[nlocal-1];
nlocal--;
ntrim++;
} else i++;
}
atom->nlocal = nlocal;
}
/* ----------------------------------------------------------------------
convert XYZ fields in dump file into absolute, unscaled coordinates
depends on scaled vs unscaled and triclinic vs orthogonal
does not depend on wrapped vs unwrapped
------------------------------------------------------------------------- */
double ReadDump::xfield(int i, int j)
{
if (!scaled) return fields[i][j];
else if (!triclinic) return fields[i][j]*xprd + xlo;
else if (dimension == 2)
return xprd*fields[i][j] + xy*fields[i][yindex] + xlo;
return xprd*fields[i][j] + xy*fields[i][yindex] + xz*fields[i][zindex] + xlo;
}
double ReadDump::yfield(int i, int j)
{
if (!scaled) return fields[i][j];
else if (!triclinic) return fields[i][j]*yprd + ylo;
else if (dimension == 2) return yprd*fields[i][j] + ylo;
return yprd*fields[i][j] + yz*fields[i][zindex] + ylo;
}
double ReadDump::zfield(int i, int j)
{
if (!scaled) return fields[i][j];
return fields[i][j]*zprd + zlo;
}
diff --git a/src/read_restart.cpp b/src/read_restart.cpp
index 937b10548..31549b69d 100644
--- a/src/read_restart.cpp
+++ b/src/read_restart.cpp
@@ -1,1073 +1,1072 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "dirent.h"
#include "read_restart.h"
#include "atom.h"
#include "atom_vec.h"
#include "domain.h"
#include "comm.h"
#include "irregular.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "fix_read_restart.h"
#include "group.h"
#include "force.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "special.h"
#include "universe.h"
#include "mpiio.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
// same as write_restart.cpp
#define MAGIC_STRING "LammpS RestartT"
#define ENDIAN 0x0001
#define ENDIANSWAP 0x1000
#define VERSION_NUMERIC 0
enum{VERSION,SMALLINT,TAGINT,BIGINT,
UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID,
NEWTON_PAIR,NEWTON_BOND,
XPERIODIC,YPERIODIC,ZPERIODIC,BOUNDARY,
ATOM_STYLE,NATOMS,NTYPES,
NBONDS,NBONDTYPES,BOND_PER_ATOM,
NANGLES,NANGLETYPES,ANGLE_PER_ATOM,
NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM,
NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM,
TRICLINIC,BOXLO,BOXHI,XY,XZ,YZ,
SPECIAL_LJ,SPECIAL_COUL,
MASS,PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER,
MULTIPROC,MPIIO,PROCSPERFILE,PERPROC,
IMAGEINT};
#define LB_FACTOR 1.1
/* ---------------------------------------------------------------------- */
ReadRestart::ReadRestart(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void ReadRestart::command(int narg, char **arg)
{
if (narg != 1) error->all(FLERR,"Illegal read_restart command");
if (domain->box_exist)
error->all(FLERR,"Cannot read_restart after simulation box is defined");
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
// if filename contains "*", search dir for latest restart file
char *file = new char[strlen(arg[0]) + 16];
if (strchr(arg[0],'*')) {
int n;
if (me == 0) {
file_search(arg[0],file);
n = strlen(file) + 1;
}
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(file,n,MPI_CHAR,0,world);
} else strcpy(file,arg[0]);
// check for multiproc files and an MPI-IO filename
if (strchr(arg[0],'%')) multiproc = 1;
else multiproc = 0;
if (strstr(arg[0],".mpi")) mpiioflag = 1;
else mpiioflag = 0;
if (multiproc && mpiioflag)
error->all(FLERR,
"Read restart MPI-IO output not allowed with '%' in filename");
if (mpiioflag) {
mpiio = new RestartMPIIO(lmp);
if (!mpiio->mpiio_exists)
error->all(FLERR,"Reading from MPI-IO filename when "
"MPIIO package is not installed");
}
// open single restart file or base file for multiproc case
if (me == 0) {
if (screen) fprintf(screen,"Reading restart file ...\n");
char *hfile;
if (multiproc) {
hfile = new char[strlen(file) + 16];
char *ptr = strchr(file,'%');
*ptr = '\0';
sprintf(hfile,"%s%s%s",file,"base",ptr+1);
*ptr = '%';
} else hfile = file;
fp = fopen(hfile,"rb");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open restart file %s",hfile);
error->one(FLERR,str);
}
if (multiproc) delete [] hfile;
}
// read magic string, endian flag, numeric version
magic_string();
endian();
int incompatible = version_numeric();
// read header info which creates simulation box
header(incompatible);
domain->box_exist = 1;
// problem setup using info from header
int n;
if (nprocs == 1) n = static_cast<int> (atom->natoms);
else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs);
atom->allocate_type_arrays();
atom->avec->grow(n);
n = atom->nmax;
domain->print_box(" ");
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid();
domain->set_local_box();
// read groups, ntype-length arrays, force field, fix info from file
// nextra = max # of extra quantities stored with each atom
group->read_restart(fp);
type_arrays();
force_fields();
int nextra = modify->read_restart(fp);
atom->nextra_store = nextra;
memory->create(atom->extra,n,nextra,"atom:extra");
// read file layout info
file_layout();
// close header file if in multiproc mode
if (multiproc && me == 0) fclose(fp);
// read per-proc info
AtomVec *avec = atom->avec;
int maxbuf = 0;
double *buf = NULL;
int m,flag;
// MPI-IO input from single file
if (mpiioflag) {
// add calls to RestartMPIIO class
// reopen header file
// perform reads
// allow for different # of procs reading than wrote the file
// mpiio->open(file);
// mpiio->read();
// mpiio->close();
// then process atom info as
//m = 0;
//while (m < n) m += avec->unpack_restart(&buf[m]);
}
// input of single native file
// nprocs_file = # of chunks in file
// proc 0 reads a chunk and bcasts it to other procs
// each proc unpacks the atoms, saving ones in it's sub-domain
// check for atom in sub-domain differs for orthogonal vs triclinic box
else if (multiproc == 0) {
int triclinic = domain->triclinic;
double *x,lamda[3];
double *coord,*sublo,*subhi;
if (triclinic == 0) {
sublo = domain->sublo;
subhi = domain->subhi;
} else {
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
for (int iproc = 0; iproc < nprocs_file; iproc++) {
if (read_int() != PERPROC)
error->all(FLERR,"Invalid flag in peratom section of restart file");
n = read_int();
if (n > maxbuf) {
maxbuf = n;
memory->destroy(buf);
memory->create(buf,maxbuf,"read_restart:buf");
}
read_double_vec(n,buf);
m = 0;
while (m < n) {
x = &buf[m+1];
if (triclinic) {
domain->x2lamda(x,lamda);
coord = lamda;
} else coord = x;
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2]) {
m += avec->unpack_restart(&buf[m]);
}
else m += static_cast<int> (buf[m]);
}
}
if (me == 0) fclose(fp);
}
// input of multiple native files with procs <= files
// # of files = multiproc_file
// each proc reads a subset of files, striding by nprocs
// each proc keeps all atoms in all perproc chunks in its files
else if (nprocs <= multiproc_file) {
char *procfile = new char[strlen(file) + 16];
char *ptr = strchr(file,'%');
for (int iproc = me; iproc < multiproc_file; iproc += nprocs) {
*ptr = '\0';
sprintf(procfile,"%s%d%s",file,iproc,ptr+1);
*ptr = '%';
fp = fopen(procfile,"rb");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open restart file %s",procfile);
error->one(FLERR,str);
}
fread(&flag,sizeof(int),1,fp);
if (flag != PROCSPERFILE)
error->one(FLERR,"Invalid flag in peratom section of restart file");
int procsperfile;
fread(&procsperfile,sizeof(int),1,fp);
for (int i = 0; i < procsperfile; i++) {
fread(&flag,sizeof(int),1,fp);
if (flag != PERPROC)
error->one(FLERR,"Invalid flag in peratom section of restart file");
fread(&n,sizeof(int),1,fp);
if (n > maxbuf) {
maxbuf = n;
memory->destroy(buf);
memory->create(buf,maxbuf,"read_restart:buf");
}
fread(buf,sizeof(double),n,fp);
m = 0;
while (m < n) m += avec->unpack_restart(&buf[m]);
}
fclose(fp);
}
delete [] procfile;
}
// input of multiple native files with procs > files
// # of files = multiproc_file
// cluster procs based on # of files
// 1st proc in each cluster reads per-proc chunks from file
// sends chunks round-robin to other procs in its cluster
// each proc keeps all atoms in its perproc chunks in file
else {
// nclusterprocs = # of procs in my cluster that read from one file
// filewriter = 1 if this proc reads file, else 0
// fileproc = ID of proc in my cluster who reads from file
// clustercomm = MPI communicator within my cluster of procs
int nfile = multiproc_file;
int icluster = static_cast<int> ((bigint) me * nfile/nprocs);
int fileproc = static_cast<int> ((bigint) icluster * nprocs/nfile);
int fcluster = static_cast<int> ((bigint) fileproc * nfile/nprocs);
if (fcluster < icluster) fileproc++;
int fileprocnext =
static_cast<int> ((bigint) (icluster+1) * nprocs/nfile);
fcluster = static_cast<int> ((bigint) fileprocnext * nfile/nprocs);
if (fcluster < icluster+1) fileprocnext++;
int nclusterprocs = fileprocnext - fileproc;
int filereader = 0;
if (me == fileproc) filereader = 1;
MPI_Comm clustercomm;
MPI_Comm_split(world,icluster,0,&clustercomm);
if (filereader) {
char *procfile = new char[strlen(file) + 16];
char *ptr = strchr(file,'%');
*ptr = '\0';
sprintf(procfile,"%s%d%s",file,icluster,ptr+1);
*ptr = '%';
fp = fopen(procfile,"rb");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open restart file %s",procfile);
error->one(FLERR,str);
}
delete [] procfile;
}
int flag,procsperfile;
if (filereader) {
fread(&flag,sizeof(int),1,fp);
if (flag != PROCSPERFILE)
error->one(FLERR,"Invalid flag in peratom section of restart file");
fread(&procsperfile,sizeof(int),1,fp);
}
MPI_Bcast(&procsperfile,1,MPI_INT,0,clustercomm);
int tmp,iproc;
MPI_Status status;
MPI_Request request;
for (int i = 0; i < procsperfile; i++) {
if (filereader) {
fread(&flag,sizeof(int),1,fp);
if (flag != PERPROC)
error->one(FLERR,"Invalid flag in peratom section of restart file");
fread(&n,sizeof(int),1,fp);
if (n > maxbuf) {
maxbuf = n;
memory->destroy(buf);
memory->create(buf,maxbuf,"read_restart:buf");
}
fread(buf,sizeof(double),n,fp);
if (i % nclusterprocs) {
iproc = me + (i % nclusterprocs);
MPI_Send(&n,1,MPI_INT,iproc,0,world);
MPI_Recv(&tmp,0,MPI_INT,iproc,0,world,&status);
MPI_Rsend(buf,n,MPI_DOUBLE,iproc,0,world);
}
} else if (i % nclusterprocs == me - fileproc) {
MPI_Recv(&n,1,MPI_INT,fileproc,0,world,&status);
if (n > maxbuf) {
maxbuf = n;
memory->destroy(buf);
memory->create(buf,maxbuf,"read_restart:buf");
}
MPI_Irecv(buf,n,MPI_DOUBLE,fileproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,fileproc,0,world);
MPI_Wait(&request,&status);
}
if (i % nclusterprocs == me - fileproc) {
m = 0;
while (m < n) m += avec->unpack_restart(&buf[m]);
}
}
if (filereader) fclose(fp);
MPI_Comm_free(&clustercomm);
}
// clean-up memory
delete [] file;
memory->destroy(buf);
// for multiproc or MPI-IO files:
// perform irregular comm to migrate atoms to correct procs
if (multiproc || mpiioflag) {
// create a temporary fix to hold and migrate extra atom info
// necessary b/c irregular will migrate atoms
if (nextra) {
char cextra[8],fixextra[8];
sprintf(cextra,"%d",nextra);
sprintf(fixextra,"%d",modify->nfix_restart_peratom);
char **newarg = new char*[5];
newarg[0] = (char *) "_read_restart";
newarg[1] = (char *) "all";
newarg[2] = (char *) "READ_RESTART";
newarg[3] = cextra;
newarg[4] = fixextra;
modify->add_fix(5,newarg);
delete [] newarg;
}
// move atoms to new processors via irregular()
// in case read by different proc than wrote restart file
// first do map_init() since irregular->migrate_atoms() will do map_clear()
if (atom->map_style) atom->map_init();
if (domain->triclinic) domain->x2lamda(atom->nlocal);
Irregular *irregular = new Irregular(lmp);
irregular->migrate_atoms();
delete irregular;
if (domain->triclinic) domain->lamda2x(atom->nlocal);
// put extra atom info held by fix back into atom->extra
// destroy temporary fix
if (nextra) {
memory->destroy(atom->extra);
memory->create(atom->extra,atom->nmax,nextra,"atom:extra");
int ifix = modify->find_fix("_read_restart");
FixReadRestart *fix = (FixReadRestart *) modify->fix[ifix];
int *count = fix->count;
double **extra = fix->extra;
double **atom_extra = atom->extra;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (int j = 0; j < count[i]; j++)
atom_extra[i][j] = extra[i][j];
modify->delete_fix("_read_restart");
}
}
// check that all atoms were assigned to procs
bigint natoms;
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " atoms\n",natoms);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " atoms\n",natoms);
}
if (natoms != atom->natoms)
error->all(FLERR,"Did not assign all atoms correctly");
if (me == 0) {
if (atom->nbonds) {
if (screen) fprintf(screen," " BIGINT_FORMAT " bonds\n",atom->nbonds);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " bonds\n",atom->nbonds);
}
if (atom->nangles) {
if (screen) fprintf(screen," " BIGINT_FORMAT " angles\n",
atom->nangles);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " angles\n",
atom->nangles);
}
if (atom->ndihedrals) {
if (screen) fprintf(screen," " BIGINT_FORMAT " dihedrals\n",
atom->ndihedrals);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " dihedrals\n",
atom->ndihedrals);
}
if (atom->nimpropers) {
if (screen) fprintf(screen," " BIGINT_FORMAT " impropers\n",
atom->nimpropers);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " impropers\n",
atom->nimpropers);
}
}
- // check if tags are being used
- // create global mapping and bond topology now that system is defined
+ // check that atom IDs are valid
- flag = 0;
- for (int i = 0; i < atom->nlocal; i++)
- if (atom->tag[i] > 0) flag = 1;
- int flag_all;
- MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_MAX,world);
- if (flag_all == 0) atom->tag_enable = 0;
+ atom->tag_check();
- if (atom->map_style) {
+ // if molecular system or user-requested, create global mapping of atoms
+
+ if (atom->molecular || atom->map_user) {
atom->map_init();
atom->map_set();
}
+
+ // create special bond lists for molecular systems
+
if (atom->molecular) {
Special special(lmp);
special.build();
}
}
/* ----------------------------------------------------------------------
infile contains a "*"
search for all files which match the infile pattern
replace "*" with latest timestep value to create outfile name
search dir referenced by initial pathname of file
if infile also contains "%", use "base" when searching directory
only called by proc 0
------------------------------------------------------------------------- */
void ReadRestart::file_search(char *infile, char *outfile)
{
char *ptr;
// separate infile into dir + filename
char *dirname = new char[strlen(infile) + 1];
char *filename = new char[strlen(infile) + 1];
if (strchr(infile,'/')) {
ptr = strrchr(infile,'/');
*ptr = '\0';
strcpy(dirname,infile);
strcpy(filename,ptr+1);
*ptr = '/';
} else {
strcpy(dirname,"./");
strcpy(filename,infile);
}
// if filename contains "%" replace "%" with "base"
char *pattern = new char[strlen(filename) + 16];
if (ptr = strchr(filename,'%')) {
*ptr = '\0';
sprintf(pattern,"%s%s%s",filename,"base",ptr+1);
*ptr = '%';
} else strcpy(pattern,filename);
// scan all files in directory, searching for files that match pattern
// maxnum = largest int that matches "*"
int n = strlen(pattern) + 16;
char *begin = new char[n];
char *middle = new char[n];
char *end = new char[n];
ptr = strchr(pattern,'*');
*ptr = '\0';
strcpy(begin,pattern);
strcpy(end,ptr+1);
int nbegin = strlen(begin);
bigint maxnum = -1;
struct dirent *ep;
DIR *dp = opendir(dirname);
if (dp == NULL)
error->one(FLERR,"Cannot open dir to search for restart file");
while (ep = readdir(dp)) {
if (strstr(ep->d_name,begin) != ep->d_name) continue;
if ((ptr = strstr(&ep->d_name[nbegin],end)) == NULL) continue;
if (strlen(end) == 0) ptr = ep->d_name + strlen(ep->d_name);
*ptr = '\0';
if (strlen(&ep->d_name[nbegin]) < n) {
strcpy(middle,&ep->d_name[nbegin]);
if (ATOBIGINT(middle) > maxnum) maxnum = ATOBIGINT(middle);
}
}
closedir(dp);
if (maxnum < 0) error->one(FLERR,"Found no restart file matching pattern");
// create outfile with maxint substituted for "*"
// use original infile, not pattern, since need to retain "%" in filename
ptr = strchr(infile,'*');
*ptr = '\0';
sprintf(outfile,"%s" BIGINT_FORMAT "%s",infile,maxnum,ptr+1);
*ptr = '*';
// clean up
delete [] dirname;
delete [] filename;
delete [] pattern;
delete [] begin;
delete [] middle;
delete [] end;
}
/* ----------------------------------------------------------------------
read header of restart file
------------------------------------------------------------------------- */
void ReadRestart::header(int incompatible)
{
int px,py,pz;
int xperiodic,yperiodic,zperiodic;
int boundary[3][2];
// read flags and fields until flag = -1
int flag = read_int();
while (flag >= 0) {
// check restart file version, warn if different
if (flag == VERSION) {
char *version = read_string();
if (me == 0) {
if (screen) fprintf(screen," restart file = %s, LAMMPS = %s\n",
version,universe->version);
}
if (incompatible)
error->all(FLERR,"Restart file incompatible with current version");
delete [] version;
// check lmptype.h sizes, error if different
} else if (flag == SMALLINT) {
int size = read_int();
if (size != sizeof(smallint))
error->all(FLERR,"Smallint setting in lmptype.h is not compatible");
} else if (flag == IMAGEINT) {
int size = read_int();
if (size != sizeof(imageint))
error->all(FLERR,"Imageint setting in lmptype.h is not compatible");
} else if (flag == TAGINT) {
int size = read_int();
if (size != sizeof(tagint))
error->all(FLERR,"Tagint setting in lmptype.h is not compatible");
} else if (flag == BIGINT) {
int size = read_int();
if (size != sizeof(bigint))
error->all(FLERR,"Bigint setting in lmptype.h is not compatible");
// reset unit_style only if different
// so that timestep,neighbor-skin are not changed
} else if (flag == UNITS) {
char *style = read_string();
if (strcmp(style,update->unit_style) != 0) update->set_units(style);
delete [] style;
} else if (flag == NTIMESTEP) {
update->ntimestep = read_bigint();
// set dimension from restart file
} else if (flag == DIMENSION) {
int dimension = read_int();
domain->dimension = dimension;
if (domain->dimension == 2 && domain->zperiodic == 0)
error->all(FLERR,
"Cannot run 2d simulation with nonperiodic Z dimension");
// read nprocs from restart file, warn if different
} else if (flag == NPROCS) {
nprocs_file = read_int();
if (nprocs_file != comm->nprocs && me == 0)
error->warning(FLERR,"Restart file used different # of processors");
// don't set procgrid, warn if different
} else if (flag == PROCGRID) {
int procgrid[3];
read_int();
read_int_vec(3,procgrid);
if (comm->user_procgrid[0] != 0 &&
(procgrid[0] != comm->user_procgrid[0] ||
procgrid[1] != comm->user_procgrid[1] ||
procgrid[2] != comm->user_procgrid[2]) && me == 0)
error->warning(FLERR,"Restart file used different 3d processor grid");
// don't set newton_pair, leave input script value unchanged
// set newton_bond from restart file
// warn if different and input script settings are not default
} else if (flag == NEWTON_PAIR) {
int newton_pair_file = read_int();
if (force->newton_pair != 1) {
if (newton_pair_file != force->newton_pair && me == 0)
error->warning(FLERR,
"Restart file used different newton pair setting, "
"using input script value");
}
} else if (flag == NEWTON_BOND) {
int newton_bond_file = read_int();
if (force->newton_bond != 1) {
if (newton_bond_file != force->newton_bond && me == 0)
error->warning(FLERR,
"Restart file used different newton bond setting, "
"using restart file value");
}
force->newton_bond = newton_bond_file;
if (force->newton_pair || force->newton_bond) force->newton = 1;
else force->newton = 0;
// set boundary settings from restart file
// warn if different and input script settings are not default
} else if (flag == XPERIODIC) {
xperiodic = read_int();
} else if (flag == YPERIODIC) {
yperiodic = read_int();
} else if (flag == ZPERIODIC) {
zperiodic = read_int();
} else if (flag == BOUNDARY) {
int boundary[3][2];
read_int();
read_int_vec(6,&boundary[0][0]);
if (domain->boundary[0][0] || domain->boundary[0][1] ||
domain->boundary[1][0] || domain->boundary[1][1] ||
domain->boundary[2][0] || domain->boundary[2][1]) {
if (boundary[0][0] != domain->boundary[0][0] ||
boundary[0][1] != domain->boundary[0][1] ||
boundary[1][0] != domain->boundary[1][0] ||
boundary[1][1] != domain->boundary[1][1] ||
boundary[2][0] != domain->boundary[2][0] ||
boundary[2][1] != domain->boundary[2][1]) {
if (me == 0)
error->warning(FLERR,
"Restart file used different boundary settings, "
"using restart file values");
}
}
domain->boundary[0][0] = boundary[0][0];
domain->boundary[0][1] = boundary[0][1];
domain->boundary[1][0] = boundary[1][0];
domain->boundary[1][1] = boundary[1][1];
domain->boundary[2][0] = boundary[2][0];
domain->boundary[2][1] = boundary[2][1];
domain->periodicity[0] = domain->xperiodic = xperiodic;
domain->periodicity[1] = domain->yperiodic = yperiodic;
domain->periodicity[2] = domain->zperiodic = zperiodic;
domain->nonperiodic = 0;
if (xperiodic == 0 || yperiodic == 0 || zperiodic == 0) {
domain->nonperiodic = 1;
if (boundary[0][0] >= 2 || boundary[0][1] >= 2 ||
boundary[1][0] >= 2 || boundary[1][1] >= 2 ||
boundary[2][0] >= 2 || boundary[2][1] >= 2)
domain->nonperiodic = 2;
}
// create new AtomVec class
// if style = hybrid, read additional sub-class arguments
} else if (flag == ATOM_STYLE) {
char *style = read_string();
int nwords = 0;
char **words = NULL;
if (strcmp(style,"hybrid") == 0) {
nwords = read_int();
words = new char*[nwords];
for (int i = 0; i < nwords; i++) words[i] = read_string();
}
atom->create_avec(style,nwords,words);
atom->avec->read_restart_settings(fp);
for (int i = 0; i < nwords; i++) delete [] words[i];
delete [] words;
delete [] style;
} else if (flag == NATOMS) {
atom->natoms = read_bigint();
} else if (flag == NTYPES) {
atom->ntypes = read_int();
} else if (flag == NBONDS) {
atom->nbonds = read_bigint();
} else if (flag == NBONDTYPES) {
atom->nbondtypes = read_int();
} else if (flag == BOND_PER_ATOM) {
atom->bond_per_atom = read_int();
} else if (flag == NANGLES) {
atom->nangles = read_bigint();
} else if (flag == NANGLETYPES) {
atom->nangletypes = read_int();
} else if (flag == ANGLE_PER_ATOM) {
atom->angle_per_atom = read_int();
} else if (flag == NDIHEDRALS) {
atom->ndihedrals = read_bigint();
} else if (flag == NDIHEDRALTYPES) {
atom->ndihedraltypes = read_int();
} else if (flag == DIHEDRAL_PER_ATOM) {
atom->dihedral_per_atom = read_int();
} else if (flag == NIMPROPERS) {
atom->nimpropers = read_bigint();
} else if (flag == NIMPROPERTYPES) {
atom->nimpropertypes = read_int();
} else if (flag == IMPROPER_PER_ATOM) {
atom->improper_per_atom = read_int();
} else if (flag == TRICLINIC) {
domain->triclinic = read_int();
} else if (flag == BOXLO) {
read_int();
read_double_vec(3,domain->boxlo);
} else if (flag == BOXHI) {
read_int();
read_double_vec(3,domain->boxhi);
} else if (flag == XY) {
domain->xy = read_double();
} else if (flag == XZ) {
domain->xz = read_double();
} else if (flag == YZ) {
domain->yz = read_double();
} else if (flag == SPECIAL_LJ) {
read_int();
read_double_vec(3,&force->special_lj[1]);
} else if (flag == SPECIAL_COUL) {
read_int();
read_double_vec(3,&force->special_coul[1]);
} else error->all(FLERR,"Invalid flag in header section of restart file");
flag = read_int();
}
}
/* ---------------------------------------------------------------------- */
void ReadRestart::type_arrays()
{
int flag = read_int();
while (flag >= 0) {
if (flag == MASS) {
read_int();
double *mass = new double[atom->ntypes+1];
read_double_vec(atom->ntypes,&mass[1]);
atom->set_mass(mass);
delete [] mass;
} else error->all(FLERR,
"Invalid flag in type arrays section of restart file");
flag = read_int();
}
}
/* ---------------------------------------------------------------------- */
void ReadRestart::force_fields()
{
int n;
char *style;
int flag = read_int();
while (flag >= 0) {
if (flag == PAIR) {
style = read_string();
force->create_pair(style);
delete [] style;
force->pair->read_restart(fp);
} else if (flag == BOND) {
style = read_string();
force->create_bond(style);
delete [] style;
force->bond->read_restart(fp);
} else if (flag == ANGLE) {
style = read_string();
force->create_angle(style);
delete [] style;
force->angle->read_restart(fp);
} else if (flag == DIHEDRAL) {
style = read_string();
force->create_dihedral(style);
delete [] style;
force->dihedral->read_restart(fp);
} else if (flag == IMPROPER) {
style = read_string();
force->create_improper(style);
delete [] style;
force->improper->read_restart(fp);
} else error->all(FLERR,
"Invalid flag in force field section of restart file");
flag = read_int();
}
}
/* ---------------------------------------------------------------------- */
void ReadRestart::file_layout()
{
int flag = read_int();
while (flag >= 0) {
if (flag == MULTIPROC) {
multiproc_file = read_int();
if (multiproc == 0 && multiproc_file)
error->all(FLERR,"Restart file is not a multi-proc file");
if (multiproc && multiproc_file == 0)
error->all(FLERR,"Restart file is a multi-proc file");
} else if (flag == MPIIO) {
int mpiioflag_file = read_int();
if (mpiioflag == 0 && mpiioflag_file)
error->all(FLERR,"Restart file is a MPI-IO file");
if (mpiioflag && mpiioflag_file == 0)
error->all(FLERR,"Restart file is not a MPI-IO file");
}
// NOTE: could add reading of MPI-IO specific fields to header here
// e.g. read vector of PERPROCSIZE values
flag = read_int();
}
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// low-level fread methods
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void ReadRestart::magic_string()
{
int n = strlen(MAGIC_STRING) + 1;
char *str = new char[n];
int count;
if (me == 0) count = fread(str,sizeof(char),n,fp);
MPI_Bcast(&count,1,MPI_INT,0,world);
if (count < n)
error->all(FLERR,"Invalid LAMMPS restart file");
MPI_Bcast(str,n,MPI_CHAR,0,world);
if (strcmp(str,MAGIC_STRING) != 0)
error->all(FLERR,"Invalid LAMMPS restart file");
delete [] str;
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
void ReadRestart::endian()
{
int endian;
if (me == 0) fread(&endian,sizeof(int),1,fp);
MPI_Bcast(&endian,1,MPI_INT,0,world);
if (endian == ENDIAN) return;
if (endian == ENDIANSWAP)
error->all(FLERR,"Restart file byte ordering is swapped");
else error->all(FLERR,"Restart file byte ordering is not recognized");
}
/* ----------------------------------------------------------------------
------------------------------------------------------------------------- */
int ReadRestart::version_numeric()
{
int vn;
if (me == 0) fread(&vn,sizeof(int),1,fp);
MPI_Bcast(&vn,1,MPI_INT,0,world);
if (vn != VERSION_NUMERIC) return 1;
return 0;
}
/* ----------------------------------------------------------------------
read an int from restart file and bcast it
------------------------------------------------------------------------- */
int ReadRestart::read_int()
{
int value;
if (me == 0) fread(&value,sizeof(int),1,fp);
MPI_Bcast(&value,1,MPI_INT,0,world);
return value;
}
/* ----------------------------------------------------------------------
read a bigint from restart file and bcast it
------------------------------------------------------------------------- */
bigint ReadRestart::read_bigint()
{
bigint value;
if (me == 0) fread(&value,sizeof(bigint),1,fp);
MPI_Bcast(&value,1,MPI_LMP_BIGINT,0,world);
return value;
}
/* ----------------------------------------------------------------------
read a double from restart file and bcast it
------------------------------------------------------------------------- */
double ReadRestart::read_double()
{
double value;
if (me == 0) fread(&value,sizeof(double),1,fp);
MPI_Bcast(&value,1,MPI_DOUBLE,0,world);
return value;
}
/* ----------------------------------------------------------------------
read a char string (including NULL) and bcast it
str is allocated here, ptr is returned, caller must deallocate
------------------------------------------------------------------------- */
char *ReadRestart::read_string()
{
int n;
if (me == 0) fread(&n,sizeof(int),1,fp);
MPI_Bcast(&n,1,MPI_INT,0,world);
char *value = new char[n];
if (me == 0) fread(value,sizeof(char),n,fp);
MPI_Bcast(value,n,MPI_CHAR,0,world);
return value;
}
/* ----------------------------------------------------------------------
read vector of N ints from restart file and bcast them
do not bcast them, caller does that if required
------------------------------------------------------------------------- */
void ReadRestart::read_int_vec(int n, int *vec)
{
if (me == 0) fread(vec,sizeof(int),n,fp);
MPI_Bcast(vec,n,MPI_INT,0,world);
}
/* ----------------------------------------------------------------------
read vector of N doubles from restart file and bcast them
do not bcast them, caller does that if required
------------------------------------------------------------------------- */
void ReadRestart::read_double_vec(int n, double *vec)
{
if (me == 0) fread(vec,sizeof(double),n,fp);
MPI_Bcast(vec,n,MPI_DOUBLE,0,world);
}
diff --git a/src/replicate.cpp b/src/replicate.cpp
index d0b3b71ab..9b4e9bcf4 100644
--- a/src/replicate.cpp
+++ b/src/replicate.cpp
@@ -1,407 +1,411 @@
/* ----------------------------------------------------------------------
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 "stdlib.h"
#include "string.h"
#include "replicate.h"
#include "atom.h"
#include "atom_vec.h"
#include "atom_vec_hybrid.h"
#include "force.h"
#include "domain.h"
#include "comm.h"
#include "special.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define LB_FACTOR 1.1
#define EPSILON 1.0e-6
/* ---------------------------------------------------------------------- */
Replicate::Replicate(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void Replicate::command(int narg, char **arg)
{
int i,j,m,n;
if (domain->box_exist == 0)
error->all(FLERR,"Replicate command before simulation box is defined");
if (narg != 3) error->all(FLERR,"Illegal replicate command");
int me = comm->me;
int nprocs = comm->nprocs;
if (me == 0 && screen) fprintf(screen,"Replicating atoms ...\n");
// nrep = total # of replications
int nx = force->inumeric(FLERR,arg[0]);
int ny = force->inumeric(FLERR,arg[1]);
int nz = force->inumeric(FLERR,arg[2]);
int nrep = nx*ny*nz;
// error and warning checks
if (nx <= 0 || ny <= 0 || nz <= 0)
error->all(FLERR,"Illegal replicate command");
if (domain->dimension == 2 && nz != 1)
error->all(FLERR,"Cannot replicate 2d simulation in z dimension");
if ((nx > 1 && domain->xperiodic == 0) ||
(ny > 1 && domain->yperiodic == 0) ||
(nz > 1 && domain->zperiodic == 0)) {
if (comm->me == 0)
error->warning(FLERR,"Replicating in a non-periodic dimension");
}
if (atom->nextra_grow || atom->nextra_restart || atom->nextra_store)
error->all(FLERR,"Cannot replicate with fixes that store atom quantities");
// maxtag = largest atom tag across all existing atoms
- int maxtag = 0;
- for (i = 0; i < atom->nlocal; i++) maxtag = MAX(atom->tag[i],maxtag);
- int maxtag_all;
- MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_INT,MPI_MAX,world);
- maxtag = maxtag_all;
+ tagint maxtag = 0;
+ if (atom->tag_enable) {
+ for (i = 0; i < atom->nlocal; i++) maxtag = MAX(atom->tag[i],maxtag);
+ tagint maxtag_all;
+ MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world);
+ maxtag = maxtag_all;
+ }
// maxmol = largest molecule tag across all existing atoms
int maxmol = 0;
if (atom->molecule_flag) {
for (i = 0; i < atom->nlocal; i++) maxmol = MAX(atom->molecule[i],maxmol);
int maxmol_all;
MPI_Allreduce(&maxmol,&maxmol_all,1,MPI_INT,MPI_MAX,world);
maxmol = maxmol_all;
}
// unmap existing atoms via image flags
for (i = 0; i < atom->nlocal; i++)
domain->unmap(atom->x[i],atom->image[i]);
// communication buffer for all my atom's info
// max_size = largest buffer needed by any proc
// must do before new Atom class created,
// since size_restart() uses atom->nlocal
int max_size;
int send_size = atom->avec->size_restart();
MPI_Allreduce(&send_size,&max_size,1,MPI_INT,MPI_MAX,world);
double *buf;
memory->create(buf,max_size,"replicate:buf");
// old = original atom class
// atom = new replicated atom class
// if old atom style was hybrid, pass sub-style names to create_avec
Atom *old = atom;
atom = new Atom(lmp);
atom->settings(old);
int nstyles = 0;
char **keywords = NULL;
if (strcmp(old->atom_style,"hybrid") == 0) {
AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) old->avec;
nstyles = avec_hybrid->nstyles;
keywords = avec_hybrid->keywords;
}
atom->create_avec(old->atom_style,nstyles,keywords);
// check that new system will not be too large
- // if molecular and N > MAXTAGINT, error
- // if atomic and new N > MAXTAGINT, turn off tags for existing and new atoms
- // new system cannot exceed MAXBIGINT
- // NOTE: change these 2 to MAXTAGINT when allow tagint = bigint
-
- if (atom->molecular &&
- (nrep*old->natoms < 0 || nrep*old->natoms > MAXSMALLINT))
- error->all(FLERR,"Replicated molecular system atom IDs are too big");
- if (nrep*old->natoms < 0 || nrep*old->natoms > MAXSMALLINT)
- atom->tag_enable = 0;
- if (atom->tag_enable == 0)
- for (int i = 0; i < atom->nlocal; i++)
- atom->tag[i] = 0;
-
- if (nrep*old->natoms < 0 || nrep*old->natoms > MAXBIGINT ||
- nrep*old->nbonds < 0 || nrep*old->nbonds > MAXBIGINT ||
- nrep*old->nangles < 0 || nrep*old->nangles > MAXBIGINT ||
- nrep*old->ndihedrals < 0 || nrep*old->ndihedrals > MAXBIGINT ||
- nrep*old->nimpropers < 0 || nrep*old->nimpropers > MAXBIGINT)
+ // new tags cannot exceed MAXTAGINT
+ // new system sizes cannot exceed MAXBIGINT
+
+ if (atom->tag_enable) {
+ bigint maxnewtag = maxtag + (nrep-1)*old->natoms;
+ if (maxnewtag < 0 || maxnewtag >= MAXTAGINT)
+ error->all(FLERR,"Replicated system atom IDs are too big");
+ }
+
+ if (nrep*old->natoms < 0 || nrep*old->natoms >= MAXBIGINT ||
+ nrep*old->nbonds < 0 || nrep*old->nbonds >= MAXBIGINT ||
+ nrep*old->nangles < 0 || nrep*old->nangles >= MAXBIGINT ||
+ nrep*old->ndihedrals < 0 || nrep*old->ndihedrals >= MAXBIGINT ||
+ nrep*old->nimpropers < 0 || nrep*old->nimpropers >= MAXBIGINT)
error->all(FLERR,"Replicated system is too big");
// assign atom and topology counts in new class from old one
atom->natoms = old->natoms * nrep;
atom->nbonds = old->nbonds * nrep;
atom->nangles = old->nangles * nrep;
atom->ndihedrals = old->ndihedrals * nrep;
atom->nimpropers = old->nimpropers * nrep;
atom->ntypes = old->ntypes;
atom->nbondtypes = old->nbondtypes;
atom->nangletypes = old->nangletypes;
atom->ndihedraltypes = old->ndihedraltypes;
atom->nimpropertypes = old->nimpropertypes;
atom->bond_per_atom = old->bond_per_atom;
atom->angle_per_atom = old->angle_per_atom;
atom->dihedral_per_atom = old->dihedral_per_atom;
atom->improper_per_atom = old->improper_per_atom;
// store old simulation box
int triclinic = domain->triclinic;
double old_xprd = domain->xprd;
double old_yprd = domain->yprd;
double old_zprd = domain->zprd;
double old_xy = domain->xy;
double old_xz = domain->xz;
double old_yz = domain->yz;
// setup new simulation box
domain->boxhi[0] = domain->boxlo[0] + nx*old_xprd;
domain->boxhi[1] = domain->boxlo[1] + ny*old_yprd;
domain->boxhi[2] = domain->boxlo[2] + nz*old_zprd;
if (triclinic) {
domain->xy *= ny;
domain->xz *= nz;
domain->yz *= nz;
}
// new problem setup using new box boundaries
if (nprocs == 1) n = static_cast<int> (atom->natoms);
else n = static_cast<int> (LB_FACTOR * atom->natoms / nprocs);
atom->allocate_type_arrays();
atom->avec->grow(n);
n = atom->nmax;
domain->print_box(" ");
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid();
domain->set_local_box();
// copy type arrays to new atom class
if (atom->mass) {
for (int itype = 1; itype <= atom->ntypes; itype++) {
atom->mass_setflag[itype] = old->mass_setflag[itype];
if (atom->mass_setflag[itype]) atom->mass[itype] = old->mass[itype];
}
}
// set bounds for my proc
// if periodic and I am lo/hi proc, adjust bounds by EPSILON
// insures all replicated atoms will be owned even with round-off
double epsilon[3];
if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON;
else {
epsilon[0] = domain->prd[0] * EPSILON;
epsilon[1] = domain->prd[1] * EPSILON;
epsilon[2] = domain->prd[2] * EPSILON;
}
double sublo[3],subhi[3];
if (triclinic == 0) {
sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0];
sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1];
sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2];
} else {
sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0];
sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1];
sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2];
}
if (domain->xperiodic) {
if (comm->myloc[0] == 0) sublo[0] -= epsilon[0];
if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] += epsilon[0];
}
if (domain->yperiodic) {
if (comm->myloc[1] == 0) sublo[1] -= epsilon[1];
if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] += epsilon[1];
}
if (domain->zperiodic) {
if (comm->myloc[2] == 0) sublo[2] -= epsilon[2];
if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] += epsilon[2];
}
// loop over all procs
// if this iteration of loop is me:
// pack my unmapped atom data into buf
// bcast it to all other procs
// performs 3d replicate loop with while loop over atoms in buf
// x = new replicated position, remapped into simulation box
// unpack atom into new atom class from buf if I own it
// adjust tag, mol #, coord, topology info as needed
AtomVec *old_avec = old->avec;
AtomVec *avec = atom->avec;
- int ix,iy,iz,atom_offset,mol_offset;
+ int ix,iy,iz,mol_offset;
+ tagint atom_offset;
imageint image;
double x[3],lamda[3];
double *coord;
int tag_enable = atom->tag_enable;
for (int iproc = 0; iproc < nprocs; iproc++) {
if (me == iproc) {
n = 0;
for (i = 0; i < old->nlocal; i++) n += old_avec->pack_restart(i,&buf[n]);
}
MPI_Bcast(&n,1,MPI_INT,iproc,world);
MPI_Bcast(buf,n,MPI_DOUBLE,iproc,world);
for (ix = 0; ix < nx; ix++) {
for (iy = 0; iy < ny; iy++) {
for (iz = 0; iz < nz; iz++) {
// while loop over one proc's atom list
m = 0;
while (m < n) {
image = ((imageint) IMGMAX << IMG2BITS) |
((imageint) IMGMAX << IMGBITS) | IMGMAX;
if (triclinic == 0) {
x[0] = buf[m+1] + ix*old_xprd;
x[1] = buf[m+2] + iy*old_yprd;
x[2] = buf[m+3] + iz*old_zprd;
} else {
x[0] = buf[m+1] + ix*old_xprd + iy*old_xy + iz*old_xz;
x[1] = buf[m+2] + iy*old_yprd + iz*old_yz;
x[2] = buf[m+3] + iz*old_zprd;
}
domain->remap(x,image);
if (triclinic) {
domain->x2lamda(x,lamda);
coord = lamda;
} else coord = x;
if (coord[0] >= sublo[0] && coord[0] < subhi[0] &&
coord[1] >= sublo[1] && coord[1] < subhi[1] &&
coord[2] >= sublo[2] && coord[2] < subhi[2]) {
m += avec->unpack_restart(&buf[m]);
i = atom->nlocal - 1;
if (tag_enable)
atom_offset = iz*ny*nx*maxtag + iy*nx*maxtag + ix*maxtag;
else atom_offset = 0;
mol_offset = iz*ny*nx*maxmol + iy*nx*maxmol + ix*maxmol;
atom->x[i][0] = x[0];
atom->x[i][1] = x[1];
atom->x[i][2] = x[2];
atom->tag[i] += atom_offset;
atom->image[i] = image;
if (atom->molecule_flag) {
if (atom->molecule[i] > 0)
atom->molecule[i] += mol_offset;
if (atom->avec->bonds_allow)
for (j = 0; j < atom->num_bond[i]; j++)
atom->bond_atom[i][j] += atom_offset;
if (atom->avec->angles_allow)
for (j = 0; j < atom->num_angle[i]; j++) {
atom->angle_atom1[i][j] += atom_offset;
atom->angle_atom2[i][j] += atom_offset;
atom->angle_atom3[i][j] += atom_offset;
}
if (atom->avec->dihedrals_allow)
for (j = 0; j < atom->num_dihedral[i]; j++) {
atom->dihedral_atom1[i][j] += atom_offset;
atom->dihedral_atom2[i][j] += atom_offset;
atom->dihedral_atom3[i][j] += atom_offset;
atom->dihedral_atom4[i][j] += atom_offset;
}
if (atom->avec->impropers_allow)
for (j = 0; j < atom->num_improper[i]; j++) {
atom->improper_atom1[i][j] += atom_offset;
atom->improper_atom2[i][j] += atom_offset;
atom->improper_atom3[i][j] += atom_offset;
atom->improper_atom4[i][j] += atom_offset;
}
}
} else m += static_cast<int> (buf[m]);
}
}
}
}
}
// free communication buffer and old atom class
memory->destroy(buf);
delete old;
// check that all atoms were assigned to procs
bigint natoms;
bigint nblocal = atom->nlocal;
MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (me == 0) {
if (screen) fprintf(screen," " BIGINT_FORMAT " atoms\n",natoms);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " atoms\n",natoms);
}
if (natoms != atom->natoms)
error->all(FLERR,"Replicate did not assign all atoms correctly");
if (me == 0) {
if (atom->nbonds) {
if (screen) fprintf(screen," " BIGINT_FORMAT " bonds\n",atom->nbonds);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " bonds\n",atom->nbonds);
}
if (atom->nangles) {
if (screen) fprintf(screen," " BIGINT_FORMAT " angles\n",
atom->nangles);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " angles\n",
atom->nangles);
}
if (atom->ndihedrals) {
if (screen) fprintf(screen," " BIGINT_FORMAT " dihedrals\n",
atom->ndihedrals);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " dihedrals\n",
atom->ndihedrals);
}
if (atom->nimpropers) {
if (screen) fprintf(screen," " BIGINT_FORMAT " impropers\n",
atom->nimpropers);
if (logfile) fprintf(logfile," " BIGINT_FORMAT " impropers\n",
atom->nimpropers);
}
}
- // create global mapping and bond topology now that system is defined
+ // check that atom IDs are valid
- if (atom->map_style) {
- atom->nghost = 0;
+ atom->tag_check();
+
+ // if molecular system or user-requested, create global mapping of atoms
+
+ if (atom->molecular || atom->map_user) {
atom->map_init();
atom->map_set();
}
+
+ // create special bond lists for molecular systems
+
if (atom->molecular) {
Special special(lmp);
special.build();
}
}
diff --git a/src/set.cpp b/src/set.cpp
index 046dc67f4..562b8f94c 100644
--- a/src/set.cpp
+++ b/src/set.cpp
@@ -1,966 +1,967 @@
/* ----------------------------------------------------------------------
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 "set.h"
#include "atom.h"
#include "atom_vec.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "domain.h"
#include "region.h"
#include "group.h"
#include "comm.h"
#include "neighbor.h"
#include "force.h"
#include "pair.h"
#include "input.h"
#include "variable.h"
#include "random_park.h"
#include "math_extra.h"
#include "math_const.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
using namespace MathConst;
enum{ATOM_SELECT,MOL_SELECT,TYPE_SELECT,GROUP_SELECT,REGION_SELECT};
enum{TYPE,TYPE_FRACTION,MOLECULE,X,Y,Z,CHARGE,MASS,SHAPE,LENGTH,TRI,
DIPOLE,DIPOLE_RANDOM,QUAT,QUAT_RANDOM,THETA,ANGMOM,
DIAMETER,DENSITY,VOLUME,IMAGE,BOND,ANGLE,DIHEDRAL,IMPROPER,
MESO_E,MESO_CV,MESO_RHO,INAME,DNAME};
#define BIG INT_MAX
/* ---------------------------------------------------------------------- */
void Set::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"Set command before simulation box is defined");
if (atom->natoms == 0)
error->all(FLERR,"Set command with no atoms existing");
if (narg < 3) error->all(FLERR,"Illegal set command");
// style and ID info
if (strcmp(arg[0],"atom") == 0) style = ATOM_SELECT;
else if (strcmp(arg[0],"mol") == 0) style = MOL_SELECT;
else if (strcmp(arg[0],"type") == 0) style = TYPE_SELECT;
else if (strcmp(arg[0],"group") == 0) style = GROUP_SELECT;
else if (strcmp(arg[0],"region") == 0) style = REGION_SELECT;
else error->all(FLERR,"Illegal set command");
int n = strlen(arg[1]) + 1;
id = new char[n];
strcpy(id,arg[1]);
select = NULL;
selection(atom->nlocal);
// loop over keyword/value pairs
// call appropriate routine to reset attributes
if (comm->me == 0 && screen) fprintf(screen,"Setting atom values ...\n");
int allcount,origarg;
int iarg = 2;
while (iarg < narg) {
varflag = varflag1 = varflag2 = varflag3 = varflag4 = 0;
count = 0;
origarg = iarg;
if (strcmp(arg[iarg],"type") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else ivalue = force->inumeric(FLERR,arg[iarg+1]);
set(TYPE);
iarg += 2;
} else if (strcmp(arg[iarg],"type/fraction") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal set command");
newtype = force->inumeric(FLERR,arg[iarg+1]);
fraction = force->numeric(FLERR,arg[iarg+2]);
ivalue = force->inumeric(FLERR,arg[iarg+3]);
if (newtype <= 0 || newtype > atom->ntypes)
error->all(FLERR,"Invalid value in set command");
if (fraction < 0.0 || fraction > 1.0)
error->all(FLERR,"Invalid value in set command");
if (ivalue <= 0)
error->all(FLERR,"Invalid random number seed in set command");
setrandom(TYPE_FRACTION);
iarg += 4;
} else if (strcmp(arg[iarg],"mol") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (!atom->molecule_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(MOLECULE);
iarg += 2;
} else if (strcmp(arg[iarg],"x") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
set(X);
iarg += 2;
} else if (strcmp(arg[iarg],"y") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
set(Y);
iarg += 2;
} else if (strcmp(arg[iarg],"z") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
set(Z);
iarg += 2;
} else if (strcmp(arg[iarg],"charge") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->q_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(CHARGE);
iarg += 2;
} else if (strcmp(arg[iarg],"mass") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->rmass_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(MASS);
iarg += 2;
} else if (strcmp(arg[iarg],"shape") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else xvalue = force->numeric(FLERR,arg[iarg+1]);
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2);
else yvalue = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3);
else zvalue = force->numeric(FLERR,arg[iarg+3]);
if (!atom->ellipsoid_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(SHAPE);
iarg += 4;
} else if (strcmp(arg[iarg],"length") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->line_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(LENGTH);
iarg += 2;
} else if (strcmp(arg[iarg],"tri") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->tri_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(TRI);
iarg += 2;
} else if (strcmp(arg[iarg],"dipole") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else xvalue = force->numeric(FLERR,arg[iarg+1]);
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2);
else yvalue = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3);
else zvalue = force->numeric(FLERR,arg[iarg+3]);
if (!atom->mu_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(DIPOLE);
iarg += 4;
} else if (strcmp(arg[iarg],"dipole/random") == 0) {
if (iarg+3 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
dvalue = force->numeric(FLERR,arg[iarg+2]);
if (!atom->mu_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0)
error->all(FLERR,"Invalid random number seed in set command");
if (dvalue <= 0.0)
error->all(FLERR,"Invalid dipole length in set command");
setrandom(DIPOLE_RANDOM);
iarg += 3;
} else if (strcmp(arg[iarg],"quat") == 0) {
if (iarg+5 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else xvalue = force->numeric(FLERR,arg[iarg+1]);
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2);
else yvalue = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3);
else zvalue = force->numeric(FLERR,arg[iarg+3]);
if (strstr(arg[iarg+4],"v_") == arg[iarg+4]) varparse(arg[iarg+4],4);
else wvalue = force->numeric(FLERR,arg[iarg+4]);
if (!atom->ellipsoid_flag && !atom->tri_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(QUAT);
iarg += 5;
} else if (strcmp(arg[iarg],"quat/random") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (!atom->ellipsoid_flag && !atom->tri_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0)
error->all(FLERR,"Invalid random number seed in set command");
setrandom(QUAT_RANDOM);
iarg += 2;
} else if (strcmp(arg[iarg],"theta") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else {
dvalue = force->numeric(FLERR,arg[iarg+1]);
dvalue *= MY_PI/180.0;
}
if (!atom->line_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(THETA);
iarg += 2;
} else if (strcmp(arg[iarg],"angmom") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else xvalue = force->numeric(FLERR,arg[iarg+1]);
if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) varparse(arg[iarg+2],2);
else yvalue = force->numeric(FLERR,arg[iarg+2]);
if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) varparse(arg[iarg+3],3);
else zvalue = force->numeric(FLERR,arg[iarg+3]);
if (!atom->ellipsoid_flag && !atom->tri_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(ANGMOM);
iarg += 4;
} else if (strcmp(arg[iarg],"diameter") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->radius_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(DIAMETER);
iarg += 2;
} else if (strcmp(arg[iarg],"density") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->rmass_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (dvalue <= 0.0) error->all(FLERR,"Invalid density in set command");
set(DENSITY);
iarg += 2;
} else if (strcmp(arg[iarg],"volume") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->vfrac_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (dvalue <= 0.0) error->all(FLERR,"Invalid volume in set command");
set(VOLUME);
iarg += 2;
} else if (strcmp(arg[iarg],"image") == 0) {
if (iarg+4 > narg) error->all(FLERR,"Illegal set command");
ximageflag = yimageflag = zimageflag = 0;
if (strcmp(arg[iarg+1],"NULL") != 0) {
ximageflag = 1;
ximage = force->inumeric(FLERR,arg[iarg+1]);
}
if (strcmp(arg[iarg+2],"NULL") != 0) {
yimageflag = 1;
yimage = force->inumeric(FLERR,arg[iarg+2]);
}
if (strcmp(arg[iarg+3],"NULL") != 0) {
zimageflag = 1;
zimage = force->inumeric(FLERR,arg[iarg+3]);
}
if (ximageflag && ximage && !domain->xperiodic)
error->all(FLERR,
"Cannot set non-zero image flag for non-periodic dimension");
if (yimageflag && yimage && !domain->yperiodic)
error->all(FLERR,
"Cannot set non-zero image flag for non-periodic dimension");
if (zimageflag && zimage && !domain->zperiodic)
error->all(FLERR,
"Cannot set non-zero image flag for non-periodic dimension");
set(IMAGE);
iarg += 4;
} else if (strcmp(arg[iarg],"bond") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (atom->avec->bonds_allow == 0)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0 || ivalue > atom->nbondtypes)
error->all(FLERR,"Invalid value in set command");
topology(BOND);
iarg += 2;
} else if (strcmp(arg[iarg],"angle") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (atom->avec->angles_allow == 0)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0 || ivalue > atom->nangletypes)
error->all(FLERR,"Invalid value in set command");
topology(ANGLE);
iarg += 2;
} else if (strcmp(arg[iarg],"dihedral") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (atom->avec->dihedrals_allow == 0)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0 || ivalue > atom->ndihedraltypes)
error->all(FLERR,"Invalid value in set command");
topology(DIHEDRAL);
iarg += 2;
} else if (strcmp(arg[iarg],"improper") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
ivalue = force->inumeric(FLERR,arg[iarg+1]);
if (atom->avec->impropers_allow == 0)
error->all(FLERR,"Cannot set this attribute for this atom style");
if (ivalue <= 0 || ivalue > atom->nimpropertypes)
error->all(FLERR,"Invalid value in set command");
topology(IMPROPER);
iarg += 2;
} else if (strcmp(arg[iarg],"meso_e") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->e_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(MESO_E);
iarg += 2;
} else if (strcmp(arg[iarg],"meso_cv") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->cv_flag)
error->all(FLERR,"Cannot set this attribute for this atom style");
set(MESO_CV);
iarg += 2;
} else if (strcmp(arg[iarg],"meso_rho") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
if (!atom->rho_flag)
error->all(FLERR,"Cannot set meso_rho for this atom style");
set(MESO_RHO);
iarg += 2;
} else if (strstr(arg[iarg],"i_") == arg[iarg]) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else ivalue = force->inumeric(FLERR,arg[iarg+1]);
int flag;
index_custom = atom->find_custom(&arg[iarg][2],flag);
if (index_custom < 0 || flag != 0)
error->all(FLERR,"Set command integer vector does not exist");
set(INAME);
iarg += 2;
} else if (strstr(arg[iarg],"d_") == arg[iarg]) {
if (iarg+2 > narg) error->all(FLERR,"Illegal set command");
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) varparse(arg[iarg+1],1);
else dvalue = force->numeric(FLERR,arg[iarg+1]);
int flag;
index_custom = atom->find_custom(&arg[iarg][2],flag);
if (index_custom < 0 || flag != 1)
error->all(FLERR,"Set command floating point vector does not exist");
set(DNAME);
iarg += 2;
} else error->all(FLERR,"Illegal set command");
// statistics
MPI_Allreduce(&count,&allcount,1,MPI_INT,MPI_SUM,world);
if (comm->me == 0) {
if (screen) fprintf(screen," %d settings made for %s\n",
allcount,arg[origarg]);
if (logfile) fprintf(logfile," %d settings made for %s\n",
allcount,arg[origarg]);
}
}
// free local memory
delete [] id;
delete [] select;
}
/* ----------------------------------------------------------------------
select atoms according to ATOM, MOLECULE, TYPE, GROUP, REGION style
n = nlocal or nlocal+nghost depending on keyword
------------------------------------------------------------------------- */
void Set::selection(int n)
{
delete [] select;
select = new int[n];
int nlo,nhi;
if (style == ATOM_SELECT) {
if (atom->tag_enable == 0)
error->all(FLERR,"Cannot use set atom with no atom IDs defined");
- force->bounds(id,BIG,nlo,nhi);
+ bigint nlobig,nhibig;
+ force->boundsbig(id,MAXTAGINT,nlobig,nhibig);
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
for (int i = 0; i < n; i++)
- if (tag[i] >= nlo && tag[i] <= nhi) select[i] = 1;
+ if (tag[i] >= nlobig && tag[i] <= nhibig) select[i] = 1;
else select[i] = 0;
} else if (style == MOL_SELECT) {
if (atom->molecule_flag == 0)
error->all(FLERR,"Cannot use set mol with no molecule IDs defined");
else force->bounds(id,BIG,nlo,nhi,0);
int *molecule = atom->molecule;
for (int i = 0; i < n; i++)
if (molecule[i] >= nlo && molecule[i] <= nhi) select[i] = 1;
else select[i] = 0;
} else if (style == TYPE_SELECT) {
force->bounds(id,atom->ntypes,nlo,nhi);
int *type = atom->type;
for (int i = 0; i < n; i++)
if (type[i] >= nlo && type[i] <= nhi) select[i] = 1;
else select[i] = 0;
} else if (style == GROUP_SELECT) {
int igroup = group->find(id);
if (igroup == -1) error->all(FLERR,"Could not find set group ID");
int groupbit = group->bitmask[igroup];
int *mask = atom->mask;
for (int i = 0; i < n; i++)
if (mask[i] & groupbit) select[i] = 1;
else select[i] = 0;
} else if (style == REGION_SELECT) {
int iregion = domain->find_region(id);
if (iregion == -1) error->all(FLERR,"Set region ID does not exist");
double **x = atom->x;
for (int i = 0; i < n; i++)
if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2]))
select[i] = 1;
else select[i] = 0;
}
}
/* ----------------------------------------------------------------------
set owned atom properties directly
either scalar or per-atom values from atom-style variable(s)
------------------------------------------------------------------------- */
void Set::set(int keyword)
{
// evaluate atom-style variable(s) if necessary
vec1 = vec2 = vec3 = vec4 = NULL;
if (varflag) {
int nlocal = atom->nlocal;
if (varflag1) {
memory->create(vec1,nlocal,"set:vec1");
input->variable->compute_atom(ivar1,0,vec1,1,0);
}
if (varflag2) {
memory->create(vec2,nlocal,"set:vec2");
input->variable->compute_atom(ivar2,0,vec2,1,0);
}
if (varflag3) {
memory->create(vec3,nlocal,"set:vec3");
input->variable->compute_atom(ivar3,0,vec3,1,0);
}
if (varflag4) {
memory->create(vec4,nlocal,"set:vec4");
input->variable->compute_atom(ivar4,0,vec4,1,0);
}
}
// loop over selected atoms
AtomVecEllipsoid *avec_ellipsoid =
(AtomVecEllipsoid *) atom->style_match("ellipsoid");
AtomVecLine *avec_line = (AtomVecLine *) atom->style_match("line");
AtomVecTri *avec_tri = (AtomVecTri *) atom->style_match("tri");
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (!select[i]) continue;
// overwrite dvalue, ivalue, xyzw value if variables defined
// else the input script scalar value remains in place
if (varflag1) {
dvalue = xvalue = vec1[i];
ivalue = static_cast<int> (dvalue);
}
if (varflag2) yvalue = vec2[i];
if (varflag3) zvalue = vec3[i];
if (varflag4) wvalue = vec4[i];
// set values in per-atom arrays
// error check here in case atom-style variables generated bogus value
if (keyword == TYPE) {
if (ivalue <= 0 || ivalue > atom->ntypes)
error->one(FLERR,"Invalid value in set command");
atom->type[i] = ivalue;
}
else if (keyword == MOLECULE) atom->molecule[i] = ivalue;
else if (keyword == X) atom->x[i][0] = dvalue;
else if (keyword == Y) atom->x[i][1] = dvalue;
else if (keyword == Z) atom->x[i][2] = dvalue;
else if (keyword == CHARGE) atom->q[i] = dvalue;
else if (keyword == MASS) {
if (dvalue <= 0.0) error->one(FLERR,"Invalid mass in set command");
atom->rmass[i] = dvalue;
}
else if (keyword == DIAMETER) {
if (dvalue < 0.0) error->one(FLERR,"Invalid diameter in set command");
atom->radius[i] = 0.5 * dvalue;
}
else if (keyword == VOLUME) {
if (dvalue <= 0.0) error->one(FLERR,"Invalid volume in set command");
atom->vfrac[i] = dvalue;
}
else if (keyword == MESO_E) atom->e[i] = dvalue;
else if (keyword == MESO_CV) atom->cv[i] = dvalue;
else if (keyword == MESO_RHO) atom->rho[i] = dvalue;
// set shape of ellipsoidal particle
else if (keyword == SHAPE) {
if (xvalue < 0.0 || yvalue < 0.0 || zvalue < 0.0)
error->one(FLERR,"Invalid shape in set command");
if (xvalue > 0.0 || yvalue > 0.0 || zvalue > 0.0) {
if (xvalue == 0.0 || yvalue == 0.0 || zvalue == 0.0)
error->one(FLERR,"Invalid shape in set command");
}
avec_ellipsoid->set_shape(i,0.5*xvalue,0.5*yvalue,0.5*zvalue);
}
// set length of line particle
else if (keyword == LENGTH) {
if (dvalue < 0.0) error->one(FLERR,"Invalid length in set command");
avec_line->set_length(i,dvalue);
}
// set corners of tri particle
else if (keyword == TRI) {
if (dvalue < 0.0) error->one(FLERR,"Invalid length in set command");
avec_tri->set_equilateral(i,dvalue);
}
// set rmass via density
// if radius > 0.0, treat as sphere
// if shape > 0.0, treat as ellipsoid
// if length > 0.0, treat as line
// if area > 0.0, treat as tri
// else set rmass to density directly
else if (keyword == DENSITY) {
if (dvalue <= 0.0) error->one(FLERR,"Invalid density in set command");
if (atom->radius_flag && atom->radius[i] > 0.0)
atom->rmass[i] = 4.0*MY_PI/3.0 *
atom->radius[i]*atom->radius[i]*atom->radius[i] * dvalue;
else if (atom->ellipsoid_flag && atom->ellipsoid[i] >= 0) {
double *shape = avec_ellipsoid->bonus[atom->ellipsoid[i]].shape;
atom->rmass[i] = 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2] * dvalue;
} else if (atom->line_flag && atom->line[i] >= 0) {
double length = avec_line->bonus[atom->line[i]].length;
atom->rmass[i] = length * dvalue;
} else if (atom->tri_flag && atom->tri[i] >= 0) {
double *c1 = avec_tri->bonus[atom->tri[i]].c1;
double *c2 = avec_tri->bonus[atom->tri[i]].c2;
double *c3 = avec_tri->bonus[atom->tri[i]].c3;
double c2mc1[2],c3mc1[3];
MathExtra::sub3(c2,c1,c2mc1);
MathExtra::sub3(c3,c1,c3mc1);
double norm[3];
MathExtra::cross3(c2mc1,c3mc1,norm);
double area = 0.5 * MathExtra::len3(norm);
atom->rmass[i] = area * dvalue;
} else atom->rmass[i] = dvalue;
}
// set dipole moment
else if (keyword == DIPOLE) {
double **mu = atom->mu;
mu[i][0] = xvalue;
mu[i][1] = yvalue;
mu[i][2] = zvalue;
mu[i][3] = sqrt(mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] +
mu[i][2]*mu[i][2]);
}
// set quaternion orientation of ellipsoid or tri particle
else if (keyword == QUAT) {
double *quat;
if (avec_ellipsoid && atom->ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat;
else if (avec_tri && atom->tri[i] >= 0)
quat = avec_tri->bonus[atom->tri[i]].quat;
else
error->one(FLERR,"Cannot set quaternion for atom that has none");
double theta2 = MY_PI2 * wvalue/180.0;
double sintheta2 = sin(theta2);
quat[0] = cos(theta2);
quat[1] = xvalue * sintheta2;
quat[2] = yvalue * sintheta2;
quat[3] = zvalue * sintheta2;
MathExtra::qnormalize(quat);
}
// set theta of line particle
else if (keyword == THETA) {
if (atom->line[i] < 0)
error->one(FLERR,"Cannot set theta for atom that is not a line");
avec_line->bonus[atom->line[i]].theta = dvalue;
}
// set angmom of ellipsoidal or tri particle
else if (keyword == ANGMOM) {
atom->angmom[i][0] = xvalue;
atom->angmom[i][1] = yvalue;
atom->angmom[i][2] = zvalue;
}
// reset any or all of 3 image flags
else if (keyword == IMAGE) {
int xbox = (atom->image[i] & IMGMASK) - IMGMAX;
int ybox = (atom->image[i] >> IMGBITS & IMGMASK) - IMGMAX;
int zbox = (atom->image[i] >> IMG2BITS) - IMGMAX;
if (ximageflag) xbox = ximage;
if (yimageflag) ybox = yimage;
if (zimageflag) zbox = zimage;
atom->image[i] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
}
// set value for custom integer or double vector
else if (keyword == INAME) {
atom->ivector[index_custom][i] = ivalue;
}
else if (keyword == DNAME) {
atom->dvector[index_custom][i] = dvalue;
}
count++;
}
// clear up per-atom memory if allocated
memory->destroy(vec1);
memory->destroy(vec2);
memory->destroy(vec3);
memory->destroy(vec4);
}
/* ----------------------------------------------------------------------
set an owned atom property randomly
- set seed based on atom tag
+ set seed based on atom coordinates
make atom result independent of what proc owns it
------------------------------------------------------------------------- */
void Set::setrandom(int keyword)
{
int i;
AtomVecEllipsoid *avec_ellipsoid =
(AtomVecEllipsoid *) atom->style_match("ellipsoid");
AtomVecLine *avec_line = (AtomVecLine *) atom->style_match("line");
AtomVecTri *avec_tri = (AtomVecTri *) atom->style_match("tri");
RanPark *random = new RanPark(lmp,1);
double **x = atom->x;
int seed = ivalue;
// set fraction of atom types to newtype
if (keyword == TYPE_FRACTION) {
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++)
if (select[i]) {
random->reset(seed,x[i]);
if (random->uniform() > fraction) continue;
atom->type[i] = newtype;
count++;
}
// set dipole moments to random orientations in 3d or 2d
// dipole length is determined by dipole type array
} else if (keyword == DIPOLE_RANDOM) {
double **mu = atom->mu;
int nlocal = atom->nlocal;
double msq,scale;
if (domain->dimension == 3) {
for (i = 0; i < nlocal; i++)
if (select[i]) {
random->reset(seed,x[i]);
mu[i][0] = random->uniform() - 0.5;
mu[i][1] = random->uniform() - 0.5;
mu[i][2] = random->uniform() - 0.5;
msq = mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1] + mu[i][2]*mu[i][2];
scale = dvalue/sqrt(msq);
mu[i][0] *= scale;
mu[i][1] *= scale;
mu[i][2] *= scale;
mu[i][3] = dvalue;
count++;
}
} else {
for (i = 0; i < nlocal; i++)
if (select[i]) {
random->reset(seed,x[i]);
mu[i][0] = random->uniform() - 0.5;
mu[i][1] = random->uniform() - 0.5;
mu[i][2] = 0.0;
msq = mu[i][0]*mu[i][0] + mu[i][1]*mu[i][1];
scale = dvalue/sqrt(msq);
mu[i][0] *= scale;
mu[i][1] *= scale;
mu[i][3] = dvalue;
count++;
}
}
// set quaternions to random orientations in 3d or 2d
} else if (keyword == QUAT_RANDOM) {
int *ellipsoid = atom->ellipsoid;
int *tri = atom->tri;
int nlocal = atom->nlocal;
double *quat;
if (domain->dimension == 3) {
double s,t1,t2,theta1,theta2;
for (i = 0; i < nlocal; i++)
if (select[i]) {
if (avec_ellipsoid && atom->ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat;
else if (avec_tri && atom->tri[i] >= 0)
quat = avec_tri->bonus[atom->tri[i]].quat;
else
error->one(FLERR,"Cannot set quaternion for atom that has none");
random->reset(seed,x[i]);
s = random->uniform();
t1 = sqrt(1.0-s);
t2 = sqrt(s);
theta1 = 2.0*MY_PI*random->uniform();
theta2 = 2.0*MY_PI*random->uniform();
quat[0] = cos(theta2)*t2;
quat[1] = sin(theta1)*t1;
quat[2] = cos(theta1)*t1;
quat[3] = sin(theta2)*t2;
count++;
}
} else {
double theta2;
for (i = 0; i < nlocal; i++)
if (select[i]) {
if (avec_ellipsoid && atom->ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[atom->ellipsoid[i]].quat;
else
error->one(FLERR,"Cannot set quaternion for atom that has none");
random->reset(seed,x[i]);
theta2 = MY_PI*random->uniform();
quat[0] = cos(theta2);
quat[1] = 0.0;
quat[2] = 0.0;
quat[3] = sin(theta2);
count++;
}
}
}
delete random;
}
/* ---------------------------------------------------------------------- */
void Set::topology(int keyword)
{
int m,atom1,atom2,atom3,atom4;
// border swap to acquire ghost atom info
// enforce PBC before in case atoms are outside box
// init entire system since comm->exchange is done
// comm::init needs neighbor::init needs pair::init needs kspace::init, etc
if (comm->me == 0 && screen) fprintf(screen," system init for set ...\n");
lmp->init();
if (domain->triclinic) domain->x2lamda(atom->nlocal);
domain->pbc();
domain->reset_box();
comm->setup();
comm->exchange();
comm->borders();
if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
// select both owned and ghost atoms
selection(atom->nlocal + atom->nghost);
// for BOND, each of 2 atoms must be in group
if (keyword == BOND) {
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (m = 0; m < atom->num_bond[i]; m++) {
atom1 = atom->map(atom->bond_atom[i][m]);
if (atom1 == -1) error->one(FLERR,"Bond atom missing in set command");
if (select[i] && select[atom1]) {
atom->bond_type[i][m] = ivalue;
count++;
}
}
}
// for ANGLE, each of 3 atoms must be in group
if (keyword == ANGLE) {
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (m = 0; m < atom->num_angle[i]; m++) {
atom1 = atom->map(atom->angle_atom1[i][m]);
atom2 = atom->map(atom->angle_atom2[i][m]);
atom3 = atom->map(atom->angle_atom3[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1)
error->one(FLERR,"Angle atom missing in set command");
if (select[atom1] && select[atom2] && select[atom3]) {
atom->angle_type[i][m] = ivalue;
count++;
}
}
}
// for DIHEDRAL, each of 4 atoms must be in group
if (keyword == DIHEDRAL) {
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (m = 0; m < atom->num_dihedral[i]; m++) {
atom1 = atom->map(atom->dihedral_atom1[i][m]);
atom2 = atom->map(atom->dihedral_atom2[i][m]);
atom3 = atom->map(atom->dihedral_atom3[i][m]);
atom4 = atom->map(atom->dihedral_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1)
error->one(FLERR,"Dihedral atom missing in set command");
if (select[atom1] && select[atom2] && select[atom3] && select[atom4]) {
atom->dihedral_type[i][m] = ivalue;
count++;
}
}
}
// for IMPROPER, each of 4 atoms must be in group
if (keyword == IMPROPER) {
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
for (m = 0; m < atom->num_improper[i]; m++) {
atom1 = atom->map(atom->improper_atom1[i][m]);
atom2 = atom->map(atom->improper_atom2[i][m]);
atom3 = atom->map(atom->improper_atom3[i][m]);
atom4 = atom->map(atom->improper_atom4[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1)
error->one(FLERR,"Improper atom missing in set command");
if (select[atom1] && select[atom2] && select[atom3] && select[atom4]) {
atom->improper_type[i][m] = ivalue;
count++;
}
}
}
}
/* ---------------------------------------------------------------------- */
void Set::varparse(char *name, int m)
{
varflag = 1;
name = &name[2];
int n = strlen(name) + 1;
char *str = new char[n];
strcpy(str,name);
int ivar = input->variable->find(str);
delete [] str;
if (ivar < 0)
error->all(FLERR,"Variable name for set command does not exist");
if (!input->variable->atomstyle(ivar))
error->all(FLERR,"Variable for set command is invalid style");
if (m == 1) {
varflag1 = 1; ivar1 = ivar;
} else if (m == 2) {
varflag2 = 1; ivar2 = ivar;
} else if (m == 3) {
varflag3 = 1; ivar3 = ivar;
} else if (m == 4) {
varflag4 = 1; ivar4 = ivar;
}
}
diff --git a/src/special.cpp b/src/special.cpp
index 170115521..d081a82ab 100644
--- a/src/special.cpp
+++ b/src/special.cpp
@@ -1,1109 +1,1114 @@
/* ----------------------------------------------------------------------
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 "stdio.h"
#include "special.h"
#include "atom.h"
#include "atom_vec.h"
#include "force.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
// allocate space for static class variable
Special *Special::sptr;
/* ---------------------------------------------------------------------- */
Special::Special(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
onetwo = onethree = onefour = NULL;
}
/* ---------------------------------------------------------------------- */
Special::~Special()
{
memory->destroy(onetwo);
memory->destroy(onethree);
memory->destroy(onefour);
}
/* ----------------------------------------------------------------------
create 1-2, 1-3, 1-4 lists of topology neighbors
store in onetwo, onethree, onefour for each atom
store 3 counters in nspecial[i]
------------------------------------------------------------------------- */
void Special::build()
{
int i,j,k,size;
int max,maxall,nbuf;
- int *buf;
+ tagint *buf;
MPI_Barrier(world);
int nlocal = atom->nlocal;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_bond = atom->num_bond;
- int **bond_atom = atom->bond_atom;
+ tagint **bond_atom = atom->bond_atom;
int **nspecial = atom->nspecial;
if (me == 0 && screen) fprintf(screen,"Finding 1-2 1-3 1-4 neighbors ...\n");
// initialize nspecial counters to 0
for (i = 0; i < nlocal; i++) {
nspecial[i][0] = 0;
nspecial[i][1] = 0;
nspecial[i][2] = 0;
}
// -----------------------------------------------------
// compute nspecial[i][0] = # of 1-2 neighbors of atom i
// -----------------------------------------------------
// bond partners stored by atom itself
for (i = 0; i < nlocal; i++) nspecial[i][0] = num_bond[i];
// if newton_bond off, then done
// else only counted 1/2 of all bonds, so count other half
if (force->newton_bond) {
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = global tag of 2nd atom in each bond
nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += num_bond[i];
memory->create(buf,nbuf,"special:buf");
// fill buffer with global tags of bond partners of my atoms
size = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++)
buf[size++] = bond_atom[i][j];
// cycle buffer around ring of procs back to self
// when receive buffer, scan tags for atoms I own
// when find one, increment nspecial count for that atom
sptr = this;
- comm->ring(size,sizeof(int),buf,1,ring_one,NULL);
+ comm->ring(size,sizeof(tagint),buf,1,ring_one,NULL);
memory->destroy(buf);
}
// ----------------------------------------------------
// create onetwo[i] = list of 1-2 neighbors for atom i
// ----------------------------------------------------
max = 0;
for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
if (me == 0) {
if (screen) fprintf(screen," %d = max # of 1-2 neighbors\n",maxall);
if (logfile) fprintf(logfile," %d = max # of 1-2 neighbors\n",maxall);
}
memory->create(onetwo,nlocal,maxall,"special:onetwo");
// count = accumulating counter
memory->create(count,nlocal,"special:count");
for (i = 0; i < nlocal; i++) count[i] = 0;
// add bond partners stored by atom to onetwo list
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++)
onetwo[i][count[i]++] = bond_atom[i][j];
// if newton_bond off, then done
// else only stored 1/2 of all bonds, so store other half
if (force->newton_bond) {
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = 2 global tags in each bond
nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += 2*num_bond[i];
memory->create(buf,nbuf,"special:buf");
// fill buffer with global tags of both atoms in bond
size = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
buf[size++] = tag[i];
buf[size++] = bond_atom[i][j];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan 2nd-atom tags for atoms I own
// when find one, add 1st-atom tag to onetwo list for 2nd atom
sptr = this;
- comm->ring(size,sizeof(int),buf,2,ring_two,NULL);
+ comm->ring(size,sizeof(tagint),buf,2,ring_two,NULL);
memory->destroy(buf);
}
memory->destroy(count);
// -----------------------------------------------------
// done if special_bonds for 1-3, 1-4 are set to 1.0
// -----------------------------------------------------
if (force->special_lj[2] == 1.0 && force->special_coul[2] == 1.0 &&
force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0) {
dedup();
combine();
return;
}
// -----------------------------------------------------
// compute nspecial[i][1] = # of 1-3 neighbors of atom i
// -----------------------------------------------------
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = 2 scalars + list of 1-2 neighbors
nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += 2 + nspecial[i][0];
memory->create(buf,nbuf,"special:buf");
// fill buffer with:
// (1) = counter for 1-3 neighbors, initialized to 0
// (2) = # of 1-2 neighbors
// (3:N) = list of 1-2 neighbors
size = 0;
for (i = 0; i < nlocal; i++) {
buf[size++] = 0;
buf[size++] = nspecial[i][0];
for (j = 0; j < nspecial[i][0]; j++) buf[size++] = onetwo[i][j];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1-2 neighbors for atoms I own
// when find one, increment 1-3 count by # of 1-2 neighbors of my atom,
// subtracting one since my list will contain original atom
sptr = this;
- comm->ring(size,sizeof(int),buf,3,ring_three,buf);
+ comm->ring(size,sizeof(tagint),buf,3,ring_three,buf);
// extract count from buffer that has cycled back to me
// nspecial[i][1] = # of 1-3 neighbors of atom i
j = 0;
for (i = 0; i < nlocal; i++) {
nspecial[i][1] = buf[j];
j += 2 + nspecial[i][0];
}
memory->destroy(buf);
// ----------------------------------------------------
// create onethree[i] = list of 1-3 neighbors for atom i
// ----------------------------------------------------
max = 0;
for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][1]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
if (me == 0) {
if (screen) fprintf(screen," %d = max # of 1-3 neighbors\n",maxall);
if (logfile) fprintf(logfile," %d = max # of 1-3 neighbors\n",maxall);
}
memory->create(onethree,nlocal,maxall,"special:onethree");
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = 4 scalars + list of 1-2 neighs + list of 1-3 neighs
nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += 4 + nspecial[i][0] + nspecial[i][1];
memory->create(buf,nbuf,"special:buf");
// fill buffer with:
// (1) = global tag of original atom
// (2) = # of 1-2 neighbors
// (3) = # of 1-3 neighbors
// (4) = counter for 1-3 neighbors, initialized to 0
// (5:N) = list of 1-2 neighbors
// (N+1:2N) space for list of 1-3 neighbors
size = 0;
for (i = 0; i < nlocal; i++) {
buf[size++] = tag[i];
buf[size++] = nspecial[i][0];
buf[size++] = nspecial[i][1];
buf[size++] = 0;
for (j = 0; j < nspecial[i][0]; j++) buf[size++] = onetwo[i][j];
size += nspecial[i][1];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1-2 neighbors for atoms I own
// when find one, add its neighbors to 1-3 list
// increment the count in buf(i+4)
// exclude the atom whose tag = original
// this process may include duplicates but they will be culled later
sptr = this;
- comm->ring(size,sizeof(int),buf,4,ring_four,buf);
+ comm->ring(size,sizeof(tagint),buf,4,ring_four,buf);
// fill onethree with buffer values that have been returned to me
// sanity check: accumulated buf[i+3] count should equal
// nspecial[i][1] for each atom
j = 0;
for (i = 0; i < nlocal; i++) {
if (buf[j+3] != nspecial[i][1])
error->one(FLERR,"1-3 bond count is inconsistent");
j += 4 + nspecial[i][0];
for (k = 0; k < nspecial[i][1]; k++)
onethree[i][k] = buf[j++];
}
memory->destroy(buf);
// done if special_bonds for 1-4 are set to 1.0
if (force->special_lj[3] == 1.0 && force->special_coul[3] == 1.0) {
dedup();
if (force->special_angle) angle_trim();
combine();
return;
}
// -----------------------------------------------------
// compute nspecial[i][2] = # of 1-4 neighbors of atom i
// -----------------------------------------------------
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = 2 scalars + list of 1-3 neighbors
nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += 2 + nspecial[i][1];
memory->create(buf,nbuf,"special:buf");
// fill buffer with:
// (1) = counter for 1-4 neighbors, initialized to 0
// (2) = # of 1-3 neighbors
// (3:N) = list of 1-3 neighbors
size = 0;
for (i = 0; i < nlocal; i++) {
buf[size++] = 0;
buf[size++] = nspecial[i][1];
for (j = 0; j < nspecial[i][1]; j++) buf[size++] = onethree[i][j];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1-3 neighbors for atoms I own
// when find one, increment 1-4 count by # of 1-2 neighbors of my atom
// may include duplicates and original atom but they will be culled later
sptr = this;
- comm->ring(size,sizeof(int),buf,5,ring_five,buf);
+ comm->ring(size,sizeof(tagint),buf,5,ring_five,buf);
// extract count from buffer that has cycled back to me
// nspecial[i][2] = # of 1-4 neighbors of atom i
j = 0;
for (i = 0; i < nlocal; i++) {
nspecial[i][2] = buf[j];
j += 2 + nspecial[i][1];
}
memory->destroy(buf);
// ----------------------------------------------------
// create onefour[i] = list of 1-4 neighbors for atom i
// ----------------------------------------------------
max = 0;
for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][2]);
MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world);
if (me == 0) {
if (screen) fprintf(screen," %d = max # of 1-4 neighbors\n",maxall);
if (logfile) fprintf(logfile," %d = max # of 1-4 neighbors\n",maxall);
}
memory->create(onefour,nlocal,maxall,"special:onefour");
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = 3 scalars + list of 1-3 neighs + list of 1-4 neighs
nbuf = 0;
for (i = 0; i < nlocal; i++)
nbuf += 3 + nspecial[i][1] + nspecial[i][2];
memory->create(buf,nbuf,"special:buf");
// fill buffer with:
// (1) = # of 1-3 neighbors
// (2) = # of 1-4 neighbors
// (3) = counter for 1-4 neighbors, initialized to 0
// (4:N) = list of 1-3 neighbors
// (N+1:2N) space for list of 1-4 neighbors
size = 0;
for (i = 0; i < nlocal; i++) {
buf[size++] = nspecial[i][1];
buf[size++] = nspecial[i][2];
buf[size++] = 0;
for (j = 0; j < nspecial[i][1]; j++) buf[size++] = onethree[i][j];
size += nspecial[i][2];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1-3 neighbors for atoms I own
// when find one, add its neighbors to 1-4 list
// incrementing the count in buf(i+4)
// this process may include duplicates but they will be culled later
sptr = this;
- comm->ring(size,sizeof(int),buf,6,ring_six,buf);
+ comm->ring(size,sizeof(tagint),buf,6,ring_six,buf);
// fill onefour with buffer values that have been returned to me
// sanity check: accumulated buf[i+2] count should equal
// nspecial[i][2] for each atom
j = 0;
for (i = 0; i < nlocal; i++) {
if (buf[j+2] != nspecial[i][2])
error->one(FLERR,"1-4 bond count is inconsistent");
j += 3 + nspecial[i][1];
for (k = 0; k < nspecial[i][2]; k++)
onefour[i][k] = buf[j++];
}
memory->destroy(buf);
dedup();
if (force->special_angle) angle_trim();
if (force->special_dihedral) dihedral_trim();
combine();
}
/* ----------------------------------------------------------------------
remove duplicates within each of onetwo, onethree, onefour individually
------------------------------------------------------------------------- */
void Special::dedup()
{
- int i,j,m;
+ int i,j;
+ tagint m;
// clear map so it can be used as scratch space
atom->map_clear();
// use map to cull duplicates
// exclude original atom explicitly
// adjust onetwo, onethree, onefour values to reflect removed duplicates
// must unset map for each atom
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int unique;
for (i = 0; i < nlocal; i++) {
unique = 0;
atom->map_one(tag[i],0);
for (j = 0; j < nspecial[i][0]; j++) {
m = onetwo[i][j];
if (atom->map(m) < 0) {
onetwo[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][0] = unique;
atom->map_one(tag[i],-1);
for (j = 0; j < unique; j++) atom->map_one(onetwo[i][j],-1);
}
for (i = 0; i < nlocal; i++) {
unique = 0;
atom->map_one(tag[i],0);
for (j = 0; j < nspecial[i][1]; j++) {
m = onethree[i][j];
if (atom->map(m) < 0) {
onethree[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][1] = unique;
atom->map_one(tag[i],-1);
for (j = 0; j < unique; j++) atom->map_one(onethree[i][j],-1);
}
for (i = 0; i < nlocal; i++) {
unique = 0;
atom->map_one(tag[i],0);
for (j = 0; j < nspecial[i][2]; j++) {
m = onefour[i][j];
if (atom->map(m) < 0) {
onefour[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][2] = unique;
atom->map_one(tag[i],-1);
for (j = 0; j < unique; j++) atom->map_one(onefour[i][j],-1);
}
// re-create map
atom->nghost = 0;
atom->map_set();
}
/* ----------------------------------------------------------------------
concatenate onetwo, onethree, onefour into master atom->special list
remove duplicates between 3 lists, leave dup in first list it appears in
convert nspecial[0], nspecial[1], nspecial[2] into cumulative counters
------------------------------------------------------------------------- */
void Special::combine()
{
- int i,j,m;
+ int i,j;
+ tagint m;
int me;
MPI_Comm_rank(world,&me);
int **nspecial = atom->nspecial;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int nlocal = atom->nlocal;
// ----------------------------------------------------
// compute culled maxspecial = max # of special neighs of any atom
// ----------------------------------------------------
// clear map so it can be used as scratch space
atom->map_clear();
// unique = # of unique nspecial neighbors of one atom
// cull duplicates using map to check for them
// exclude original atom explicitly
// must unset map for each atom
int unique;
int maxspecial = 0;
for (i = 0; i < nlocal; i++) {
unique = 0;
atom->map_one(tag[i],0);
for (j = 0; j < nspecial[i][0]; j++) {
m = onetwo[i][j];
if (atom->map(m) < 0) {
unique++;
atom->map_one(m,0);
}
}
for (j = 0; j < nspecial[i][1]; j++) {
m = onethree[i][j];
if (atom->map(m) < 0) {
unique++;
atom->map_one(m,0);
}
}
for (j = 0; j < nspecial[i][2]; j++) {
m = onefour[i][j];
if (atom->map(m) < 0) {
unique++;
atom->map_one(m,0);
}
}
maxspecial = MAX(maxspecial,unique);
atom->map_one(tag[i],-1);
for (j = 0; j < nspecial[i][0]; j++) atom->map_one(onetwo[i][j],-1);
for (j = 0; j < nspecial[i][1]; j++) atom->map_one(onethree[i][j],-1);
for (j = 0; j < nspecial[i][2]; j++) atom->map_one(onefour[i][j],-1);
}
// compute global maxspecial, must be at least 1
// add in extra factor from special_bonds command
// allocate correct special array with same nmax, new maxspecial
// previously allocated one must be destroyed
// must make AtomVec class update its ptr to special
MPI_Allreduce(&maxspecial,&atom->maxspecial,1,MPI_INT,MPI_MAX,world);
atom->maxspecial += force->special_extra;
atom->maxspecial = MAX(atom->maxspecial,1);
if (me == 0) {
if (screen)
fprintf(screen," %d = max # of special neighbors\n",atom->maxspecial);
if (logfile)
fprintf(logfile," %d = max # of special neighbors\n",atom->maxspecial);
}
memory->destroy(atom->special);
memory->create(atom->special,atom->nmax,atom->maxspecial,"atom:special");
atom->avec->grow_reset();
- int **special = atom->special;
+ tagint **special = atom->special;
// ----------------------------------------------------
// fill special array with 1-2, 1-3, 1-4 neighs for each atom
// ----------------------------------------------------
// again use map to cull duplicates
// exclude original atom explicitly
// adjust nspecial[i] values to reflect removed duplicates
// nspecial[i][1] and nspecial[i][2] now become cumulative counters
for (i = 0; i < nlocal; i++) {
unique = 0;
atom->map_one(tag[i],0);
for (j = 0; j < nspecial[i][0]; j++) {
m = onetwo[i][j];
if (atom->map(m) < 0) {
special[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][0] = unique;
for (j = 0; j < nspecial[i][1]; j++) {
m = onethree[i][j];
if (atom->map(m) < 0) {
special[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][1] = unique;
for (j = 0; j < nspecial[i][2]; j++) {
m = onefour[i][j];
if (atom->map(m) < 0) {
special[i][unique++] = m;
atom->map_one(m,0);
}
}
nspecial[i][2] = unique;
atom->map_one(tag[i],-1);
for (j = 0; j < nspecial[i][2]; j++) atom->map_one(special[i][j],-1);
}
// re-create map
atom->nghost = 0;
atom->map_set();
}
/* ----------------------------------------------------------------------
trim list of 1-3 neighbors by checking defined angles
delete a 1-3 neigh if they are not end atoms of a defined angle
and if they are not 1,3 or 2,4 atoms of a defined dihedral
------------------------------------------------------------------------- */
void Special::angle_trim()
{
int i,j,m,n;
int *num_angle = atom->num_angle;
int *num_dihedral = atom->num_dihedral;
- int **angle_atom1 = atom->angle_atom1;
- int **angle_atom3 = atom->angle_atom3;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom2 = atom->dihedral_atom2;
- int **dihedral_atom3 = atom->dihedral_atom3;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **angle_atom1 = atom->angle_atom1;
+ tagint **angle_atom3 = atom->angle_atom3;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom3 = atom->dihedral_atom3;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
// stats on old 1-3 neighbor counts
double onethreecount = 0.0;
for (i = 0; i < nlocal; i++) onethreecount += nspecial[i][1];
double allcount;
MPI_Allreduce(&onethreecount,&allcount,1,MPI_DOUBLE,MPI_SUM,world);
if (me == 0) {
if (screen)
fprintf(screen,
" %g = # of 1-3 neighbors before angle trim\n",allcount);
if (logfile)
fprintf(logfile,
" %g = # of 1-3 neighbors before angle trim\n",allcount);
}
// if angles or dihedrals are defined,
// flag each 1-3 neigh if it appears in an angle or dihedral
if ((num_angle && atom->nangles) || (num_dihedral && atom->ndihedrals)) {
// dflag = flag for 1-3 neighs of all owned atoms
int maxcount = 0;
for (i = 0; i < nlocal; i++) maxcount = MAX(maxcount,nspecial[i][1]);
memory->create(dflag,nlocal,maxcount,"special::dflag");
for (i = 0; i < nlocal; i++) {
n = nspecial[i][1];
for (j = 0; j < n; j++) dflag[i][j] = 0;
}
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = list of 1,3 atoms in each angle stored by atom
// and list of 1,3 and 2,4 atoms in each dihedral stored by atom
int nbuf = 0;
for (i = 0; i < nlocal; i++) {
if (num_angle && atom->nangles) nbuf += 2*num_angle[i];
if (num_dihedral && atom->ndihedrals) nbuf += 2*2*num_dihedral[i];
}
int *buf;
memory->create(buf,nbuf,"special:buf");
// fill buffer with list of 1,3 atoms in each angle
// and with list of 1,3 and 2,4 atoms in each dihedral
int size = 0;
if (num_angle && atom->nangles)
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_angle[i]; j++) {
buf[size++] = angle_atom1[i][j];
buf[size++] = angle_atom3[i][j];
}
if (num_dihedral && atom->ndihedrals)
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_dihedral[i]; j++) {
buf[size++] = dihedral_atom1[i][j];
buf[size++] = dihedral_atom3[i][j];
buf[size++] = dihedral_atom2[i][j];
buf[size++] = dihedral_atom4[i][j];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1,3 atoms looking for atoms I own
// when find one, scan its 1-3 neigh list and mark I,J as in an angle
sptr = this;
- comm->ring(size,sizeof(int),buf,7,ring_seven,NULL);
+ comm->ring(size,sizeof(tagint),buf,7,ring_seven,NULL);
// delete 1-3 neighbors if they are not flagged in dflag
for (i = 0; i < nlocal; i++) {
m = 0;
for (j = 0; j < nspecial[i][1]; j++)
if (dflag[i][j]) onethree[i][m++] = onethree[i][j];
nspecial[i][1] = m;
}
// clean up
memory->destroy(dflag);
memory->destroy(buf);
// if no angles or dihedrals are defined, delete all 1-3 neighs
} else {
for (i = 0; i < nlocal; i++) nspecial[i][1] = 0;
}
// stats on new 1-3 neighbor counts
onethreecount = 0.0;
for (i = 0; i < nlocal; i++) onethreecount += nspecial[i][1];
MPI_Allreduce(&onethreecount,&allcount,1,MPI_DOUBLE,MPI_SUM,world);
if (me == 0) {
if (screen)
fprintf(screen,
" %g = # of 1-3 neighbors after angle trim\n",allcount);
if (logfile)
fprintf(logfile,
" %g = # of 1-3 neighbors after angle trim\n",allcount);
}
}
/* ----------------------------------------------------------------------
trim list of 1-4 neighbors by checking defined dihedrals
delete a 1-4 neigh if they are not end atoms of a defined dihedral
------------------------------------------------------------------------- */
void Special::dihedral_trim()
{
int i,j,m,n;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom1 = atom->dihedral_atom1;
- int **dihedral_atom4 = atom->dihedral_atom4;
+ tagint **dihedral_atom1 = atom->dihedral_atom1;
+ tagint **dihedral_atom4 = atom->dihedral_atom4;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
// stats on old 1-4 neighbor counts
double onefourcount = 0.0;
for (i = 0; i < nlocal; i++) onefourcount += nspecial[i][2];
double allcount;
MPI_Allreduce(&onefourcount,&allcount,1,MPI_DOUBLE,MPI_SUM,world);
if (me == 0) {
if (screen)
fprintf(screen,
" %g = # of 1-4 neighbors before dihedral trim\n",allcount);
if (logfile)
fprintf(logfile,
" %g = # of 1-4 neighbors before dihedral trim\n",allcount);
}
// if dihedrals are defined, flag each 1-4 neigh if it appears in a dihedral
if (num_dihedral && atom->ndihedrals) {
// dflag = flag for 1-4 neighs of all owned atoms
int maxcount = 0;
for (i = 0; i < nlocal; i++) maxcount = MAX(maxcount,nspecial[i][2]);
memory->create(dflag,nlocal,maxcount,"special::dflag");
for (i = 0; i < nlocal; i++) {
n = nspecial[i][2];
for (j = 0; j < n; j++) dflag[i][j] = 0;
}
// nbufmax = largest buffer needed to hold info from any proc
// info for each atom = list of 1,4 atoms in each dihedral stored by atom
int nbuf = 0;
for (i = 0; i < nlocal; i++) nbuf += 2*num_dihedral[i];
int *buf;
memory->create(buf,nbuf,"special:buf");
// fill buffer with list of 1,4 atoms in each dihedral
int size = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_dihedral[i]; j++) {
buf[size++] = dihedral_atom1[i][j];
buf[size++] = dihedral_atom4[i][j];
}
// cycle buffer around ring of procs back to self
// when receive buffer, scan list of 1,4 atoms looking for atoms I own
// when find one, scan its 1-4 neigh list and mark I,J as in a dihedral
sptr = this;
- comm->ring(size,sizeof(int),buf,8,ring_eight,NULL);
+ comm->ring(size,sizeof(tagint),buf,8,ring_eight,NULL);
// delete 1-4 neighbors if they are not flagged in dflag
for (i = 0; i < nlocal; i++) {
m = 0;
for (j = 0; j < nspecial[i][2]; j++)
if (dflag[i][j]) onefour[i][m++] = onefour[i][j];
nspecial[i][2] = m;
}
// clean up
memory->destroy(dflag);
memory->destroy(buf);
// if no dihedrals are defined, delete all 1-4 neighs
} else {
for (i = 0; i < nlocal; i++) nspecial[i][2] = 0;
}
// stats on new 1-4 neighbor counts
onefourcount = 0.0;
for (i = 0; i < nlocal; i++) onefourcount += nspecial[i][2];
MPI_Allreduce(&onefourcount,&allcount,1,MPI_DOUBLE,MPI_SUM,world);
if (me == 0) {
if (screen)
fprintf(screen,
" %g = # of 1-4 neighbors after dihedral trim\n",allcount);
if (logfile)
fprintf(logfile,
" %g = # of 1-4 neighbors after dihedral trim\n",allcount);
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan tags for atoms I own
when find one, increment nspecial count for that atom
------------------------------------------------------------------------- */
void Special::ring_one(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int *buf = (int *) cbuf;
+ tagint *buf = (tagint *) cbuf;
int m;
for (int i = 0; i < ndatum; i++) {
m = atom->map(buf[i]);
if (m >= 0 && m < nlocal) nspecial[m][0]++;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan 2nd-atom tags for atoms I own
when find one, add 1st-atom tag to onetwo list for 2nd atom
------------------------------------------------------------------------- */
void Special::ring_two(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int nlocal = atom->nlocal;
- int **onetwo = sptr->onetwo;
+ tagint **onetwo = sptr->onetwo;
int *count = sptr->count;
- int *buf = (int *) cbuf;
+ tagint *buf = (tagint *) cbuf;
int m;
for (int i = 1; i < ndatum; i += 2) {
m = atom->map(buf[i]);
if (m >= 0 && m < nlocal) onetwo[m][count[m]++] = buf[i-1];
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1-2 neighbors for atoms I own
when find one, increment 1-3 count by # of 1-2 neighbors of my atom,
subtracting one since my list will contain original atom
------------------------------------------------------------------------- */
void Special::ring_three(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int *buf = (int *) cbuf;
+ tagint *buf = (tagint *) cbuf;
int i,j,m,n,num12;
i = 0;
while (i < ndatum) {
n = buf[i];
num12 = buf[i+1];
for (j = 0; j < num12; j++) {
m = atom->map(buf[i+2+j]);
if (m >= 0 && m < nlocal)
n += nspecial[m][0] - 1;
}
buf[i] = n;
i += 2 + num12;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1-2 neighbors for atoms I own
when find one, add its neighbors to 1-3 list
increment the count in buf(i+4)
exclude the atom whose tag = original
this process may include duplicates but they will be culled later
------------------------------------------------------------------------- */
void Special::ring_four(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int **onetwo = sptr->onetwo;
+ tagint **onetwo = sptr->onetwo;
- int *buf = (int *) cbuf;
- int i,j,k,m,n,original,num12,num13;
+ tagint *buf = (tagint *) cbuf;
+ tagint original;
+ int i,j,k,m,n,num12,num13;
i = 0;
while (i < ndatum) {
original = buf[i];
num12 = buf[i+1];
num13 = buf[i+2];
n = buf[i+3];
for (j = 0; j < num12; j++) {
m = atom->map(buf[i+4+j]);
if (m >= 0 && m < nlocal)
for (k = 0; k < nspecial[m][0]; k++)
if (onetwo[m][k] != original)
buf[i+4+num12+(n++)] = onetwo[m][k];
}
buf[i+3] = n;
i += 4 + num12 + num13;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1-3 neighbors for atoms I own
when find one, increment 1-4 count by # of 1-2 neighbors of my atom
may include duplicates and original atom but they will be culled later
------------------------------------------------------------------------- */
void Special::ring_five(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int *buf = (int *) cbuf;
+ tagint *buf = (tagint *) cbuf;
int i,j,m,n,num13;
i = 0;
while (i < ndatum) {
n = buf[i];
num13 = buf[i+1];
for (j = 0; j < num13; j++) {
m = atom->map(buf[i+2+j]);
if (m >= 0 && m < nlocal) n += nspecial[m][0];
}
buf[i] = n;
i += 2 + num13;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1-3 neighbors for atoms I own
when find one, add its neighbors to 1-4 list
incrementing the count in buf(i+4)
this process may include duplicates but they will be culled later
------------------------------------------------------------------------- */
void Special::ring_six(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int **onetwo = sptr->onetwo;
+ tagint **onetwo = sptr->onetwo;
- int *buf = (int *) cbuf;
+ tagint *buf = (tagint *) cbuf;
int i,j,k,m,n,num13,num14;
i = 0;
while (i < ndatum) {
num13 = buf[i];
num14 = buf[i+1];
n = buf[i+2];
for (j = 0; j < num13; j++) {
m = atom->map(buf[i+3+j]);
if (m >= 0 && m < nlocal)
for (k = 0; k < nspecial[m][0]; k++)
buf[i+3+num13+(n++)] = onetwo[m][k];
}
buf[i+2] = n;
i += 3 + num13 + num14;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1,3 atoms looking for atoms I own
when find one, scan its 1-3 neigh list and mark I,J as in an angle
------------------------------------------------------------------------- */
void Special::ring_seven(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int **onethree = sptr->onethree;
+ tagint **onethree = sptr->onethree;
int **dflag = sptr->dflag;
- int *buf = (int *) cbuf;
- int i,m,iglobal,jglobal,ilocal,jlocal;
+ tagint *buf = (tagint *) cbuf;
+ tagint iglobal,jglobal;
+ int i,m,ilocal,jlocal;
i = 0;
while (i < ndatum) {
iglobal = buf[i];
jglobal = buf[i+1];
ilocal = atom->map(iglobal);
jlocal = atom->map(jglobal);
if (ilocal >= 0 && ilocal < nlocal)
for (m = 0; m < nspecial[ilocal][1]; m++)
if (jglobal == onethree[ilocal][m]) {
dflag[ilocal][m] = 1;
break;
}
if (jlocal >= 0 && jlocal < nlocal)
for (m = 0; m < nspecial[jlocal][1]; m++)
if (iglobal == onethree[jlocal][m]) {
dflag[jlocal][m] = 1;
break;
}
i += 2;
}
}
/* ----------------------------------------------------------------------
when receive buffer, scan list of 1,4 atoms looking for atoms I own
when find one, scan its 1-4 neigh list and mark I,J as in a dihedral
------------------------------------------------------------------------- */
void Special::ring_eight(int ndatum, char *cbuf)
{
Atom *atom = sptr->atom;
int **nspecial = atom->nspecial;
int nlocal = atom->nlocal;
- int **onefour = sptr->onefour;
+ tagint **onefour = sptr->onefour;
int **dflag = sptr->dflag;
- int *buf = (int *) cbuf;
- int i,m,iglobal,jglobal,ilocal,jlocal;
+ tagint *buf = (tagint *) cbuf;
+ tagint iglobal,jglobal;
+ int i,m,ilocal,jlocal;
i = 0;
while (i < ndatum) {
iglobal = buf[i];
jglobal = buf[i+1];
ilocal = atom->map(iglobal);
jlocal = atom->map(jglobal);
if (ilocal >= 0 && ilocal < nlocal)
for (m = 0; m < nspecial[ilocal][2]; m++)
if (jglobal == onefour[ilocal][m]) {
dflag[ilocal][m] = 1;
break;
}
if (jlocal >= 0 && jlocal < nlocal)
for (m = 0; m < nspecial[jlocal][2]; m++)
if (iglobal == onefour[jlocal][m]) {
dflag[jlocal][m] = 1;
break;
}
i += 2;
}
}
diff --git a/src/special.h b/src/special.h
index b44de6b6e..987ca490e 100644
--- a/src/special.h
+++ b/src/special.h
@@ -1,73 +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.
------------------------------------------------------------------------- */
#ifndef LMP_SPECIAL_H
#define LMP_SPECIAL_H
#include "pointers.h"
namespace LAMMPS_NS {
class Special : protected Pointers {
public:
Special(class LAMMPS *);
~Special();
void build();
private:
int me,nprocs;
- int **onetwo,**onethree,**onefour;
+ tagint **onetwo,**onethree,**onefour;
// data used by ring callback methods
int *count;
int **dflag;
void dedup();
void angle_trim();
void dihedral_trim();
void combine();
// static variable for ring communication callback to access class data
// callback functions for ring communication
static Special *sptr;
static void ring_one(int, char *);
static void ring_two(int, char *);
static void ring_three(int, char *);
static void ring_four(int, char *);
static void ring_five(int, char *);
static void ring_six(int, char *);
static void ring_seven(int, char *);
static void ring_eight(int, char *);
};
}
#endif
/* ERROR/WARNING messages:
E: 1-3 bond count is inconsistent
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.
E: 1-4 bond count is inconsistent
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.
*/
diff --git a/src/variable.cpp b/src/variable.cpp
index 3ccf70560..6ace068ba 100644
--- a/src/variable.cpp
+++ b/src/variable.cpp
@@ -1,4070 +1,4079 @@
/* ----------------------------------------------------------------------
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 "string.h"
#include "ctype.h"
#include "unistd.h"
#include "variable.h"
#include "universe.h"
#include "atom.h"
#include "update.h"
#include "group.h"
#include "domain.h"
#include "comm.h"
#include "region.h"
#include "modify.h"
#include "compute.h"
#include "fix.h"
#include "fix_store.h"
#include "output.h"
#include "thermo.h"
#include "random_mars.h"
#include "math_const.h"
#include "atom_masks.h"
#include "memory.h"
#include "error.h"
#include "force.h"
using namespace LAMMPS_NS;
using namespace MathConst;
#define VARDELTA 4
#define MAXLEVEL 4
#define MAXLINE 256
#define CHUNK 1024
#define MYROUND(a) (( a-floor(a) ) >= .5) ? ceil(a) : floor(a)
enum{INDEX,LOOP,WORLD,UNIVERSE,ULOOP,STRING,GETENV,
SCALARFILE,ATOMFILE,FORMAT,EQUAL,ATOM};
enum{ARG,OP};
// customize by adding a function
// if add before OR,
// also set precedence level in constructor and precedence length in *.h
enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,MODULO,UNARY,
NOT,EQ,NE,LT,LE,GT,GE,AND,OR,
SQRT,EXP,LN,LOG,ABS,SIN,COS,TAN,ASIN,ACOS,ATAN,ATAN2,
RANDOM,NORMAL,CEIL,FLOOR,ROUND,RAMP,STAGGER,LOGFREQ,STRIDE,
VDISPLACE,SWIGGLE,CWIGGLE,GMASK,RMASK,GRMASK,
- VALUE,ATOMARRAY,TYPEARRAY,INTARRAY};
+ VALUE,ATOMARRAY,TYPEARRAY,INTARRAY,BIGINTARRAY};
// customize by adding a special function
enum{SUM,XMIN,XMAX,AVE,TRAP,NEXT,ISDEF};
#define INVOKED_SCALAR 1
#define INVOKED_VECTOR 2
#define INVOKED_ARRAY 4
#define INVOKED_PERATOM 8
#define BIG 1.0e20
/* ---------------------------------------------------------------------- */
Variable::Variable(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
nvar = maxvar = 0;
names = NULL;
style = NULL;
num = NULL;
which = NULL;
pad = NULL;
reader = NULL;
data = NULL;
eval_in_progress = NULL;
randomequal = NULL;
randomatom = NULL;
// customize by assigning a precedence level
precedence[DONE] = 0;
precedence[OR] = 1;
precedence[AND] = 2;
precedence[EQ] = precedence[NE] = 3;
precedence[LT] = precedence[LE] = precedence[GT] = precedence[GE] = 4;
precedence[ADD] = precedence[SUBTRACT] = 5;
precedence[MULTIPLY] = precedence[DIVIDE] = precedence[MODULO] = 6;
precedence[CARAT] = 7;
precedence[UNARY] = precedence[NOT] = 8;
}
/* ---------------------------------------------------------------------- */
Variable::~Variable()
{
for (int i = 0; i < nvar; i++) {
delete [] names[i];
delete reader[i];
if (style[i] == LOOP || style[i] == ULOOP) delete [] data[i][0];
else for (int j = 0; j < num[i]; j++) delete [] data[i][j];
delete [] data[i];
}
memory->sfree(names);
memory->destroy(style);
memory->destroy(num);
memory->destroy(which);
memory->destroy(pad);
memory->sfree(reader);
memory->sfree(data);
memory->destroy(eval_in_progress);
delete randomequal;
delete randomatom;
}
/* ----------------------------------------------------------------------
called by variable command in input script
------------------------------------------------------------------------- */
void Variable::set(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal variable command");
// DELETE
// doesn't matter if variable no longer exists
if (strcmp(arg[1],"delete") == 0) {
if (narg != 2) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) remove(find(arg[0]));
return;
// INDEX
// num = listed args, which = 1st value, data = copied args
} else if (strcmp(arg[1],"index") == 0) {
if (narg < 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = INDEX;
num[nvar] = narg - 2;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(num[nvar],&arg[2],data[nvar]);
// LOOP
// 1 arg + pad: num = N, which = 1st value, data = single string
// 2 args + pad: num = N2, which = N1, data = single string
} else if (strcmp(arg[1],"loop") == 0) {
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = LOOP;
int nfirst,nlast;
if (narg == 3 || (narg == 4 && strcmp(arg[3],"pad") == 0)) {
nfirst = 1;
nlast = force->inumeric(FLERR,arg[2]);
if (nlast <= 0) error->all(FLERR,"Illegal variable command");
if (narg == 4 && strcmp(arg[3],"pad") == 0) {
char digits[12];
sprintf(digits,"%d",nlast);
pad[nvar] = strlen(digits);
} else pad[nvar] = 0;
} else if (narg == 4 || (narg == 5 && strcmp(arg[4],"pad") == 0)) {
nfirst = force->inumeric(FLERR,arg[2]);
nlast = force->inumeric(FLERR,arg[3]);
if (nfirst > nlast || nlast < 0)
error->all(FLERR,"Illegal variable command");
if (narg == 5 && strcmp(arg[4],"pad") == 0) {
char digits[12];
sprintf(digits,"%d",nlast);
pad[nvar] = strlen(digits);
} else pad[nvar] = 0;
} else error->all(FLERR,"Illegal variable command");
num[nvar] = nlast;
which[nvar] = nfirst-1;
data[nvar] = new char*[1];
data[nvar][0] = NULL;
// WORLD
// num = listed args, which = partition this proc is in, data = copied args
// error check that num = # of worlds in universe
} else if (strcmp(arg[1],"world") == 0) {
if (narg < 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = WORLD;
num[nvar] = narg - 2;
if (num[nvar] != universe->nworlds)
error->all(FLERR,"World variable count doesn't match # of partitions");
which[nvar] = universe->iworld;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(num[nvar],&arg[2],data[nvar]);
// UNIVERSE and ULOOP
// for UNIVERSE: num = listed args, data = copied args
// for ULOOP: num = N, data = single string
// which = partition this proc is in
// universe proc 0 creates lock file
// error check that all other universe/uloop variables are same length
} else if (strcmp(arg[1],"universe") == 0 || strcmp(arg[1],"uloop") == 0) {
if (strcmp(arg[1],"universe") == 0) {
if (narg < 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = UNIVERSE;
num[nvar] = narg - 2;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(num[nvar],&arg[2],data[nvar]);
} else if (strcmp(arg[1],"uloop") == 0) {
if (narg < 3 || narg > 4 || (narg == 4 && strcmp(arg[3],"pad") != 0))
error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = ULOOP;
num[nvar] = force->inumeric(FLERR,arg[2]);
data[nvar] = new char*[1];
data[nvar][0] = NULL;
if (narg == 4) {
char digits[12];
sprintf(digits,"%d",num[nvar]);
pad[nvar] = strlen(digits);
} else pad[nvar] = 0;
}
if (num[nvar] < universe->nworlds)
error->all(FLERR,"Universe/uloop variable count < # of partitions");
which[nvar] = universe->iworld;
if (universe->me == 0) {
FILE *fp = fopen("tmp.lammps.variable","w");
fprintf(fp,"%d\n",universe->nworlds);
fclose(fp);
}
for (int jvar = 0; jvar < nvar; jvar++)
if (num[jvar] && (style[jvar] == UNIVERSE || style[jvar] == ULOOP) &&
num[nvar] != num[jvar])
error->all(FLERR,
"All universe/uloop variables must have same # of values");
// STRING
// remove pre-existing var if also style STRING (allows it to be reset)
// num = 1, which = 1st value
// data = 1 value, string to eval
} else if (strcmp(arg[1],"string") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) {
if (style[find(arg[0])] != STRING)
error->all(FLERR,"Cannot redefine variable as a different style");
remove(find(arg[0]));
}
if (nvar == maxvar) grow();
style[nvar] = STRING;
num[nvar] = 1;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(1,&arg[2],data[nvar]);
// GETENV
// remove pre-existing var if also style GETENV (allows it to be reset)
// num = 1, which = 1st value
// data = 1 value, string to eval
} else if (strcmp(arg[1],"getenv") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) {
if (style[find(arg[0])] != GETENV)
error->all(FLERR,"Cannot redefine variable as a different style");
remove(find(arg[0]));
}
if (nvar == maxvar) grow();
style[nvar] = GETENV;
num[nvar] = 1;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(1,&arg[2],data[nvar]);
data[nvar][1] = NULL;
// SCALARFILE for strings or numbers
// which = 1st value
// data = 1 value, string to eval
} else if (strcmp(arg[1],"file") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = SCALARFILE;
num[nvar] = 1;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
data[nvar][0] = new char[MAXLINE];
reader[nvar] = new VarReader(lmp,arg[0],arg[2],SCALARFILE);
int flag = reader[nvar]->read_scalar(data[nvar][0]);
if (flag) error->all(FLERR,"File variable could not read value");
// ATOMFILE for numbers
// which = 1st value
// data = NULL
} else if (strcmp(arg[1],"atomfile") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = ATOMFILE;
num[nvar] = 1;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
data[nvar][0] = NULL;
reader[nvar] = new VarReader(lmp,arg[0],arg[2],ATOMFILE);
int flag = reader[nvar]->read_peratom();
if (flag) error->all(FLERR,"Atomfile variable could not read values");
// FORMAT
// num = 3, which = 1st value
// data = 3 values
// 1st is name of variable to eval, 2nd is format string,
// 3rd is filled on retrieval
} else if (strcmp(arg[1],"format") == 0) {
if (narg != 4) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) return;
if (nvar == maxvar) grow();
style[nvar] = FORMAT;
num[nvar] = 3;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(2,&arg[2],data[nvar]);
data[nvar][2] = NULL;
// EQUAL
// remove pre-existing var if also style EQUAL (allows it to be reset)
// num = 2, which = 1st value
// data = 2 values, 1st is string to eval, 2nd is filled on retrieval
} else if (strcmp(arg[1],"equal") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) {
if (style[find(arg[0])] != EQUAL)
error->all(FLERR,"Cannot redefine variable as a different style");
remove(find(arg[0]));
}
if (nvar == maxvar) grow();
style[nvar] = EQUAL;
num[nvar] = 2;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(1,&arg[2],data[nvar]);
data[nvar][1] = NULL;
// ATOM
// remove pre-existing var if also style ATOM (allows it to be reset)
// num = 1, which = 1st value
// data = 1 value, string to eval
} else if (strcmp(arg[1],"atom") == 0) {
if (narg != 3) error->all(FLERR,"Illegal variable command");
if (find(arg[0]) >= 0) {
if (style[find(arg[0])] != ATOM)
error->all(FLERR,"Cannot redefine variable as a different style");
remove(find(arg[0]));
}
if (nvar == maxvar) grow();
style[nvar] = ATOM;
num[nvar] = 1;
which[nvar] = 0;
pad[nvar] = 0;
data[nvar] = new char*[num[nvar]];
copy(1,&arg[2],data[nvar]);
} else error->all(FLERR,"Illegal variable command");
// set name of variable
// must come at end, since STRING/EQUAL/ATOM reset may have removed name
// name must be all alphanumeric chars or underscores
int n = strlen(arg[0]) + 1;
names[nvar] = new char[n];
strcpy(names[nvar],arg[0]);
for (int i = 0; i < n-1; i++)
if (!isalnum(names[nvar][i]) && names[nvar][i] != '_')
error->all(FLERR,"Variable name must be alphanumeric or "
"underscore characters");
nvar++;
}
/* ----------------------------------------------------------------------
INDEX variable created by command-line argument
make it INDEX rather than STRING so cannot be re-defined in input script
------------------------------------------------------------------------- */
void Variable::set(char *name, int narg, char **arg)
{
char **newarg = new char*[2+narg];
newarg[0] = name;
newarg[1] = (char *) "index";
for (int i = 0; i < narg; i++) newarg[2+i] = arg[i];
set(2+narg,newarg);
delete [] newarg;
}
/* ----------------------------------------------------------------------
increment variable(s)
return 0 if OK if successfully incremented
return 1 if any variable is exhausted, free the variable to allow re-use
------------------------------------------------------------------------- */
int Variable::next(int narg, char **arg)
{
int ivar;
if (narg == 0) error->all(FLERR,"Illegal next command");
// check that variables exist and are all the same style
// exception: UNIVERSE and ULOOP variables can be mixed in same next command
for (int iarg = 0; iarg < narg; iarg++) {
ivar = find(arg[iarg]);
if (ivar == -1) error->all(FLERR,"Invalid variable in next command");
if (style[ivar] == ULOOP && style[find(arg[0])] == UNIVERSE) continue;
else if (style[ivar] == UNIVERSE && style[find(arg[0])] == ULOOP) continue;
else if (style[ivar] != style[find(arg[0])])
error->all(FLERR,"All variables in next command must be same style");
}
// invalid styles STRING or EQUAL or WORLD or ATOM or GETENV or FORMAT
int istyle = style[find(arg[0])];
if (istyle == STRING || istyle == EQUAL || istyle == WORLD
|| istyle == GETENV || istyle == ATOM || istyle == FORMAT)
error->all(FLERR,"Invalid variable style with next command");
// if istyle = UNIVERSE or ULOOP, insure all such variables are incremented
if (istyle == UNIVERSE || istyle == ULOOP)
for (int i = 0; i < nvar; i++) {
if (style[i] != UNIVERSE && style[i] != ULOOP) continue;
int iarg = 0;
for (iarg = 0; iarg < narg; iarg++)
if (strcmp(arg[iarg],names[i]) == 0) break;
if (iarg == narg)
error->universe_one(FLERR,"Next command must list all "
"universe and uloop variables");
}
// increment all variables in list
// if any variable is exhausted, set flag = 1 and remove var to allow re-use
int flag = 0;
if (istyle == INDEX || istyle == LOOP) {
for (int iarg = 0; iarg < narg; iarg++) {
ivar = find(arg[iarg]);
which[ivar]++;
if (which[ivar] >= num[ivar]) {
flag = 1;
remove(ivar);
}
}
} else if (istyle == SCALARFILE) {
for (int iarg = 0; iarg < narg; iarg++) {
ivar = find(arg[iarg]);
int done = reader[ivar]->read_scalar(data[ivar][0]);
if (done) {
flag = 1;
remove(ivar);
}
}
} else if (istyle == ATOMFILE) {
for (int iarg = 0; iarg < narg; iarg++) {
ivar = find(arg[iarg]);
int done = reader[ivar]->read_peratom();
if (done) {
flag = 1;
remove(ivar);
}
}
} else if (istyle == UNIVERSE || istyle == ULOOP) {
// wait until lock file can be created and owned by proc 0 of this world
// rename() is not atomic in practice, but no known simple fix
// means multiple procs can read/write file at the same time (bad!)
// random delays help
// delay for random fraction of 1 second before first rename() call
// delay for random fraction of 1 second before subsequent tries
// when successful, read next available index and Bcast it within my world
int nextindex;
if (me == 0) {
int seed = 12345 + universe->me + which[find(arg[0])];
RanMars *random = new RanMars(lmp,seed);
int delay = (int) (1000000*random->uniform());
usleep(delay);
while (1) {
if (!rename("tmp.lammps.variable","tmp.lammps.variable.lock")) break;
delay = (int) (1000000*random->uniform());
usleep(delay);
}
delete random;
FILE *fp = fopen("tmp.lammps.variable.lock","r");
fscanf(fp,"%d",&nextindex);
//printf("READ %d %d\n",universe->me,nextindex);
fclose(fp);
fp = fopen("tmp.lammps.variable.lock","w");
fprintf(fp,"%d\n",nextindex+1);
//printf("WRITE %d %d\n",universe->me,nextindex+1);
fclose(fp);
rename("tmp.lammps.variable.lock","tmp.lammps.variable");
if (universe->uscreen)
fprintf(universe->uscreen,
"Increment via next: value %d on partition %d\n",
nextindex+1,universe->iworld);
if (universe->ulogfile)
fprintf(universe->ulogfile,
"Increment via next: value %d on partition %d\n",
nextindex+1,universe->iworld);
}
MPI_Bcast(&nextindex,1,MPI_INT,0,world);
// set all variables in list to nextindex
// must increment all UNIVERSE and ULOOP variables here
// error check above tested for this
for (int iarg = 0; iarg < narg; iarg++) {
ivar = find(arg[iarg]);
which[ivar] = nextindex;
if (which[ivar] >= num[ivar]) {
flag = 1;
remove(ivar);
}
}
}
return flag;
}
/* ----------------------------------------------------------------------
return ptr to the data text associated with a variable
if INDEX or WORLD or UNIVERSE or STRING or SCALARFILE var,
return ptr to stored string
if LOOP or ULOOP var, write int to data[0] and return ptr to string
if EQUAL var, evaluate variable and put result in str
if FORMAT var, evaluate its variable and put formatted result in str
if GETENV var, query environment and put result in str
if ATOM or ATOMFILE var, return NULL
return NULL if no variable with name or which value is bad,
caller must respond
------------------------------------------------------------------------- */
char *Variable::retrieve(char *name)
{
int ivar = find(name);
if (ivar == -1) return NULL;
if (which[ivar] >= num[ivar]) return NULL;
char *str;
if (style[ivar] == INDEX || style[ivar] == WORLD ||
style[ivar] == UNIVERSE || style[ivar] == STRING ||
style[ivar] == SCALARFILE) {
str = data[ivar][which[ivar]];
} else if (style[ivar] == LOOP || style[ivar] == ULOOP) {
char result[16];
if (pad[ivar] == 0) sprintf(result,"%d",which[ivar]+1);
else {
char padstr[16];
sprintf(padstr,"%%0%dd",pad[ivar]);
sprintf(result,padstr,which[ivar]+1);
}
int n = strlen(result) + 1;
delete [] data[ivar][0];
data[ivar][0] = new char[n];
strcpy(data[ivar][0],result);
str = data[ivar][0];
} else if (style[ivar] == EQUAL) {
char result[64];
double answer = evaluate(data[ivar][0],NULL);
sprintf(result,"%.15g",answer);
int n = strlen(result) + 1;
if (data[ivar][1]) delete [] data[ivar][1];
data[ivar][1] = new char[n];
strcpy(data[ivar][1],result);
str = data[ivar][1];
} else if (style[ivar] == FORMAT) {
char result[64];
int jvar = find(data[ivar][0]);
if (jvar == -1) return NULL;
if (!equalstyle(jvar)) return NULL;
double answer = evaluate(data[jvar][0],NULL);
sprintf(result,data[ivar][1],answer);
int n = strlen(result) + 1;
if (data[ivar][2]) delete [] data[ivar][2];
data[ivar][2] = new char[n];
strcpy(data[ivar][2],result);
str = data[ivar][2];
} else if (style[ivar] == GETENV) {
const char *result = getenv(data[ivar][0]);
if (data[ivar][1]) delete [] data[ivar][1];
if (result == NULL) result = (const char *)"";
int n = strlen(result) + 1;
data[ivar][1] = new char[n];
strcpy(data[ivar][1],result);
str = data[ivar][1];
} else if (style[ivar] == ATOM || style[ivar] == ATOMFILE) return NULL;
return str;
}
/* ----------------------------------------------------------------------
return result of equal-style variable evaluation
------------------------------------------------------------------------- */
double Variable::compute_equal(int ivar)
{
// eval_in_progress used to detect circle dependencies
// could extend this later to check v_a = c_b + v_a constructs?
eval_in_progress[ivar] = 1;
double value = evaluate(data[ivar][0],NULL);
eval_in_progress[ivar] = 0;
return value;
}
/* ----------------------------------------------------------------------
return result of immediate equal-style variable evaluation
called from Input::substitute()
------------------------------------------------------------------------- */
double Variable::compute_equal(char *str)
{
return evaluate(str,NULL);
}
/* ----------------------------------------------------------------------
compute result of atom-style and atomfile-style variable evaluation
only computed for atoms in igroup, else result is 0.0
answers are placed every stride locations into result
if sumflag, add variable values to existing result
------------------------------------------------------------------------- */
void Variable::compute_atom(int ivar, int igroup,
double *result, int stride, int sumflag)
{
Tree *tree;
double *vstore;
if (style[ivar] == ATOM) {
double tmp = evaluate(data[ivar][0],&tree);
tmp = collapse_tree(tree);
} else vstore = reader[ivar]->fix->vstore;
int groupbit = group->bitmask[igroup];
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (style[ivar] == ATOM) {
if (sumflag == 0) {
int m = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) result[m] = eval_tree(tree,i);
else result[m] = 0.0;
m += stride;
}
} else {
int m = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) result[m] += eval_tree(tree,i);
m += stride;
}
}
} else {
if (sumflag == 0) {
int m = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) result[m] = vstore[i];
else result[m] = 0.0;
m += stride;
}
} else {
int m = 0;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) result[m] += vstore[i];
m += stride;
}
}
}
if (style[ivar] == ATOM) free_tree(tree);
}
/* ----------------------------------------------------------------------
search for name in list of variables names
return index or -1 if not found
------------------------------------------------------------------------- */
int Variable::find(char *name)
{
for (int i = 0; i < nvar; i++)
if (strcmp(name,names[i]) == 0) return i;
return -1;
}
/* ----------------------------------------------------------------------
return 1 if variable is EQUAL style, 0 if not
------------------------------------------------------------------------- */
int Variable::equalstyle(int ivar)
{
if (style[ivar] == EQUAL) return 1;
return 0;
}
/* ----------------------------------------------------------------------
return 1 if variable is ATOM or ATOMFILE style, 0 if not
------------------------------------------------------------------------- */
int Variable::atomstyle(int ivar)
{
if (style[ivar] == ATOM || style[ivar] == ATOMFILE) return 1;
return 0;
}
/* ----------------------------------------------------------------------
remove Nth variable from list and compact list
delete reader explicitly if it exists
------------------------------------------------------------------------- */
void Variable::remove(int n)
{
delete [] names[n];
if (style[n] == LOOP || style[n] == ULOOP) delete [] data[n][0];
else for (int i = 0; i < num[n]; i++) delete [] data[n][i];
delete [] data[n];
delete reader[n];
for (int i = n+1; i < nvar; i++) {
names[i-1] = names[i];
style[i-1] = style[i];
num[i-1] = num[i];
which[i-1] = which[i];
pad[i-1] = pad[i];
reader[i-1] = reader[i];
data[i-1] = data[i];
}
nvar--;
}
/* ----------------------------------------------------------------------
make space in arrays for new variable
------------------------------------------------------------------------- */
void Variable::grow()
{
int old = maxvar;
maxvar += VARDELTA;
names = (char **) memory->srealloc(names,maxvar*sizeof(char *),"var:names");
memory->grow(style,maxvar,"var:style");
memory->grow(num,maxvar,"var:num");
memory->grow(which,maxvar,"var:which");
memory->grow(pad,maxvar,"var:pad");
reader = (VarReader **)
memory->srealloc(reader,maxvar*sizeof(VarReader *),"var:reader");
for (int i = old; i < maxvar; i++) reader[i] = NULL;
data = (char ***) memory->srealloc(data,maxvar*sizeof(char **),"var:data");
memory->grow(eval_in_progress,maxvar,"var:eval_in_progress");
for (int i = 0; i < maxvar; i++) eval_in_progress[i] = 0;
}
/* ----------------------------------------------------------------------
copy narg strings from **from to **to, and allocate space for them
------------------------------------------------------------------------- */
void Variable::copy(int narg, char **from, char **to)
{
int n;
for (int i = 0; i < narg; i++) {
n = strlen(from[i]) + 1;
to[i] = new char[n];
strcpy(to[i],from[i]);
}
}
/* ----------------------------------------------------------------------
recursive evaluation of a string str
str is an equal-style or atom-style formula containing one or more items:
number = 0.0, -5.45, 2.8e-4, ...
constant = PI
thermo keyword = ke, vol, atoms, ...
math operation = (),-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,
sqrt(x),exp(x),ln(x),log(x),abs(x),
sin(x),cos(x),tan(x),asin(x),atan2(y,x),...
group function = count(group), mass(group), xcm(group,x), ...
special function = sum(x),min(x), ...
atom value = x[i], y[i], vx[i], ...
atom vector = x, y, vx, ...
compute = c_ID, c_ID[i], c_ID[i][j]
fix = f_ID, f_ID[i], f_ID[i][j]
variable = v_name, v_name[i]
equal-style variables passes in tree = NULL:
evaluate the formula, return result as a double
atom-style variable passes in tree = non-NULL:
parse the formula but do not evaluate it
create a parse tree and return it
------------------------------------------------------------------------- */
double Variable::evaluate(char *str, Tree **tree)
{
int op,opprevious;
double value1,value2;
char onechar;
char *ptr;
double argstack[MAXLEVEL];
Tree *treestack[MAXLEVEL];
int opstack[MAXLEVEL];
int nargstack = 0;
int ntreestack = 0;
int nopstack = 0;
int i = 0;
int expect = ARG;
while (1) {
onechar = str[i];
// whitespace: just skip
if (isspace(onechar)) i++;
// ----------------
// parentheses: recursively evaluate contents of parens
// ----------------
else if (onechar == '(') {
if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula");
expect = OP;
char *contents;
i = find_matching_paren(str,i,contents);
i++;
// evaluate contents and push on stack
if (tree) {
Tree *newtree;
evaluate(contents,&newtree);
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = evaluate(contents,NULL);
delete [] contents;
// ----------------
// number: push value onto stack
// ----------------
} else if (isdigit(onechar) || onechar == '.') {
if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula");
expect = OP;
// istop = end of number, including scientific notation
int istart = i;
while (isdigit(str[i]) || str[i] == '.') i++;
if (str[i] == 'e' || str[i] == 'E') {
i++;
if (str[i] == '+' || str[i] == '-') i++;
while (isdigit(str[i])) i++;
}
int istop = i - 1;
int n = istop - istart + 1;
char *number = new char[n+1];
strncpy(number,&str[istart],n);
number[n] = '\0';
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = atof(number);
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = atof(number);
delete [] number;
// ----------------
// letter: c_ID, c_ID[], c_ID[][], f_ID, f_ID[], f_ID[][],
// v_name, v_name[], exp(), xcm(,), x, x[], PI, vol
// ----------------
} else if (isalpha(onechar)) {
if (expect == OP) error->all(FLERR,"Invalid syntax in variable formula");
expect = OP;
// istop = end of word
// word = all alphanumeric or underscore
int istart = i;
while (isalnum(str[i]) || str[i] == '_') i++;
int istop = i-1;
int n = istop - istart + 1;
char *word = new char[n+1];
strncpy(word,&str[istart],n);
word[n] = '\0';
// ----------------
// compute
// ----------------
if (strncmp(word,"c_",2) == 0) {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
n = strlen(word) - 2 + 1;
char *id = new char[n];
strcpy(id,&word[2]);
int icompute = modify->find_compute(id);
if (icompute < 0)
error->all(FLERR,"Invalid compute ID in variable formula");
Compute *compute = modify->compute[icompute];
delete [] id;
// parse zero or one or two trailing brackets
// point i beyond last bracket
// nbracket = # of bracket pairs
// index1,index2 = int inside each bracket pair
int nbracket,index1,index2;
if (str[i] != '[') nbracket = 0;
else {
nbracket = 1;
ptr = &str[i];
index1 = int_between_brackets(ptr);
i = ptr-str+1;
if (str[i] == '[') {
nbracket = 2;
ptr = &str[i];
index2 = int_between_brackets(ptr);
i = ptr-str+1;
}
}
// c_ID = scalar from global scalar
if (nbracket == 0 && compute->scalar_flag) {
if (update->whichflag == 0) {
if (compute->invoked_scalar != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_SCALAR)) {
compute->compute_scalar();
compute->invoked_flag |= INVOKED_SCALAR;
}
value1 = compute->scalar;
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// c_ID[i] = scalar from global vector
} else if (nbracket == 1 && compute->vector_flag) {
if (index1 > compute->size_vector)
error->all(FLERR,"Variable formula compute vector "
"is accessed out-of-range");
if (update->whichflag == 0) {
if (compute->invoked_vector != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_VECTOR)) {
compute->compute_vector();
compute->invoked_flag |= INVOKED_VECTOR;
}
value1 = compute->vector[index1-1];
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// c_ID[i][j] = scalar from global array
} else if (nbracket == 2 && compute->array_flag) {
if (index1 > compute->size_array_rows)
error->all(FLERR,"Variable formula compute array "
"is accessed out-of-range");
if (index2 > compute->size_array_cols)
error->all(FLERR,"Variable formula compute array "
"is accessed out-of-range");
if (update->whichflag == 0) {
if (compute->invoked_array != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_ARRAY)) {
compute->compute_array();
compute->invoked_flag |= INVOKED_ARRAY;
}
value1 = compute->array[index1-1][index2-1];
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// c_ID[i] = scalar from per-atom vector
} else if (nbracket == 1 && compute->peratom_flag &&
compute->size_peratom_cols == 0) {
if (update->whichflag == 0) {
if (compute->invoked_peratom != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
peratom2global(1,NULL,compute->vector_atom,1,index1,
tree,treestack,ntreestack,argstack,nargstack);
// c_ID[i][j] = scalar from per-atom array
} else if (nbracket == 2 && compute->peratom_flag &&
compute->size_peratom_cols > 0) {
if (index2 > compute->size_peratom_cols)
error->all(FLERR,"Variable formula compute array "
"is accessed out-of-range");
if (update->whichflag == 0) {
if (compute->invoked_peratom != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
if (compute->array_atom)
peratom2global(1,NULL,&compute->array_atom[0][index2-1],
compute->size_peratom_cols,index1,
tree,treestack,ntreestack,argstack,nargstack);
else
peratom2global(1,NULL,NULL,
compute->size_peratom_cols,index1,
tree,treestack,ntreestack,argstack,nargstack);
// c_ID = vector from per-atom vector
} else if (nbracket == 0 && compute->peratom_flag &&
compute->size_peratom_cols == 0) {
if (tree == NULL)
error->all(FLERR,
"Per-atom compute in equal-style variable formula");
if (update->whichflag == 0) {
if (compute->invoked_peratom != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
newtree->array = compute->vector_atom;
newtree->nstride = 1;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
// c_ID[i] = vector from per-atom array
} else if (nbracket == 1 && compute->peratom_flag &&
compute->size_peratom_cols > 0) {
if (tree == NULL)
error->all(FLERR,
"Per-atom compute in equal-style variable formula");
if (index1 > compute->size_peratom_cols)
error->all(FLERR,"Variable formula compute array "
"is accessed out-of-range");
if (update->whichflag == 0) {
if (compute->invoked_peratom != update->ntimestep)
error->all(FLERR,"Compute used in variable between runs "
"is not current");
} else if (!(compute->invoked_flag & INVOKED_PERATOM)) {
compute->compute_peratom();
compute->invoked_flag |= INVOKED_PERATOM;
}
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
if (compute->array_atom)
newtree->array = &compute->array_atom[0][index1-1];
else
newtree->array = NULL;
newtree->nstride = compute->size_peratom_cols;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else error->all(FLERR,"Mismatched compute in variable formula");
// ----------------
// fix
// ----------------
} else if (strncmp(word,"f_",2) == 0) {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
n = strlen(word) - 2 + 1;
char *id = new char[n];
strcpy(id,&word[2]);
int ifix = modify->find_fix(id);
if (ifix < 0) error->all(FLERR,"Invalid fix ID in variable formula");
Fix *fix = modify->fix[ifix];
delete [] id;
// parse zero or one or two trailing brackets
// point i beyond last bracket
// nbracket = # of bracket pairs
// index1,index2 = int inside each bracket pair
int nbracket,index1,index2;
if (str[i] != '[') nbracket = 0;
else {
nbracket = 1;
ptr = &str[i];
index1 = int_between_brackets(ptr);
i = ptr-str+1;
if (str[i] == '[') {
nbracket = 2;
ptr = &str[i];
index2 = int_between_brackets(ptr);
i = ptr-str+1;
}
}
// f_ID = scalar from global scalar
if (nbracket == 0 && fix->scalar_flag) {
if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
value1 = fix->compute_scalar();
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// f_ID[i] = scalar from global vector
} else if (nbracket == 1 && fix->vector_flag) {
if (index1 > fix->size_vector)
error->all(FLERR,
"Variable formula fix vector is accessed out-of-range");
if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
value1 = fix->compute_vector(index1-1);
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// f_ID[i][j] = scalar from global array
} else if (nbracket == 2 && fix->array_flag) {
if (index1 > fix->size_array_rows)
error->all(FLERR,
"Variable formula fix array is accessed out-of-range");
if (index2 > fix->size_array_cols)
error->all(FLERR,
"Variable formula fix array is accessed out-of-range");
if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
value1 = fix->compute_array(index1-1,index2-1);
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// f_ID[i] = scalar from per-atom vector
} else if (nbracket == 1 && fix->peratom_flag &&
fix->size_peratom_cols == 0) {
if (update->whichflag > 0 &&
update->ntimestep % fix->peratom_freq)
error->all(FLERR,
"Fix in variable not computed at compatible time");
peratom2global(1,NULL,fix->vector_atom,1,index1,
tree,treestack,ntreestack,argstack,nargstack);
// f_ID[i][j] = scalar from per-atom array
} else if (nbracket == 2 && fix->peratom_flag &&
fix->size_peratom_cols > 0) {
if (index2 > fix->size_peratom_cols)
error->all(FLERR,
"Variable formula fix array is accessed out-of-range");
if (update->whichflag > 0 &&
update->ntimestep % fix->peratom_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
if (fix->array_atom)
peratom2global(1,NULL,&fix->array_atom[0][index2-1],
fix->size_peratom_cols,index1,
tree,treestack,ntreestack,argstack,nargstack);
else
peratom2global(1,NULL,NULL,
fix->size_peratom_cols,index1,
tree,treestack,ntreestack,argstack,nargstack);
// f_ID = vector from per-atom vector
} else if (nbracket == 0 && fix->peratom_flag &&
fix->size_peratom_cols == 0) {
if (tree == NULL)
error->all(FLERR,"Per-atom fix in equal-style variable formula");
if (update->whichflag > 0 &&
update->ntimestep % fix->peratom_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
newtree->array = fix->vector_atom;
newtree->nstride = 1;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
// f_ID[i] = vector from per-atom array
} else if (nbracket == 1 && fix->peratom_flag &&
fix->size_peratom_cols > 0) {
if (tree == NULL)
error->all(FLERR,"Per-atom fix in equal-style variable formula");
if (index1 > fix->size_peratom_cols)
error->all(FLERR,
"Variable formula fix array is accessed out-of-range");
if (update->whichflag > 0 &&
update->ntimestep % fix->peratom_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
if (fix->array_atom)
newtree->array = &fix->array_atom[0][index1-1];
else
newtree->array = NULL;
newtree->nstride = fix->size_peratom_cols;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else error->all(FLERR,"Mismatched fix in variable formula");
// ----------------
// variable
// ----------------
} else if (strncmp(word,"v_",2) == 0) {
n = strlen(word) - 2 + 1;
char *id = new char[n];
strcpy(id,&word[2]);
int ivar = find(id);
if (ivar < 0)
error->all(FLERR,"Invalid variable name in variable formula");
if (eval_in_progress[ivar])
error->all(FLERR,"Variable has circular dependency");
// parse zero or one trailing brackets
// point i beyond last bracket
// nbracket = # of bracket pairs
// index = int inside bracket
int nbracket,index;
if (str[i] != '[') nbracket = 0;
else {
nbracket = 1;
ptr = &str[i];
index = int_between_brackets(ptr);
i = ptr-str+1;
}
// v_name = scalar from non atom/atomfile variable
if (nbracket == 0 && style[ivar] != ATOM && style[ivar] != ATOMFILE) {
char *var = retrieve(id);
if (var == NULL)
error->all(FLERR,"Invalid variable evaluation in variable formula");
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = atof(var);
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = atof(var);
// v_name = per-atom vector from atom-style variable
// evaluate the atom-style variable as newtree
} else if (nbracket == 0 && style[ivar] == ATOM) {
if (tree == NULL)
error->all(FLERR,
"Atom-style variable in equal-style variable formula");
Tree *newtree;
evaluate(data[ivar][0],&newtree);
treestack[ntreestack++] = newtree;
// v_name = per-atom vector from atomfile-style variable
} else if (nbracket == 0 && style[ivar] == ATOMFILE) {
if (tree == NULL)
error->all(FLERR,"Atomfile-style variable in "
"equal-style variable formula");
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
newtree->array = reader[ivar]->fix->vstore;
newtree->nstride = 1;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
// v_name[N] = scalar from atom-style variable
// compute the per-atom variable in result
// use peratom2global to extract single value from result
} else if (nbracket && style[ivar] == ATOM) {
double *result;
memory->create(result,atom->nlocal,"variable:result");
compute_atom(ivar,0,result,1,0);
peratom2global(1,NULL,result,1,index,
tree,treestack,ntreestack,argstack,nargstack);
memory->destroy(result);
// v_name[N] = scalar from atomfile-style variable
} else if (nbracket && style[ivar] == ATOMFILE) {
peratom2global(1,NULL,reader[ivar]->fix->vstore,1,index,
tree,treestack,ntreestack,argstack,nargstack);
} else error->all(FLERR,"Mismatched variable in variable formula");
delete [] id;
// ----------------
// math/group/special function or atom value/vector or
// constant or thermo keyword
// ----------------
} else {
// ----------------
// math or group or special function
// ----------------
if (str[i] == '(') {
char *contents;
i = find_matching_paren(str,i,contents);
i++;
if (math_function(word,contents,tree,
treestack,ntreestack,argstack,nargstack));
else if (group_function(word,contents,tree,
treestack,ntreestack,argstack,nargstack));
else if (special_function(word,contents,tree,
treestack,ntreestack,argstack,nargstack));
else error->all(FLERR,"Invalid math/group/special function "
"in variable formula");
delete [] contents;
// ----------------
// atom value
// ----------------
} else if (str[i] == '[') {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
ptr = &str[i];
int id = int_between_brackets(ptr);
i = ptr-str+1;
peratom2global(0,word,NULL,0,id,
tree,treestack,ntreestack,argstack,nargstack);
// ----------------
// atom vector
// ----------------
} else if (is_atom_vector(word)) {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
atom_vector(word,tree,treestack,ntreestack);
// ----------------
// constant
// ----------------
} else if (is_constant(word)) {
value1 = constant(word);
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
// ----------------
// thermo keyword
// ----------------
} else {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
int flag = output->thermo->evaluate_keyword(word,&value1);
if (flag)
error->all(FLERR,"Invalid thermo keyword in variable formula");
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value1;
}
}
delete [] word;
// ----------------
// math operator, including end-of-string
// ----------------
} else if (strchr("+-*/^<>=!&|%\0",onechar)) {
if (onechar == '+') op = ADD;
else if (onechar == '-') op = SUBTRACT;
else if (onechar == '*') op = MULTIPLY;
else if (onechar == '/') op = DIVIDE;
else if (onechar == '%') op = MODULO;
else if (onechar == '^') op = CARAT;
else if (onechar == '=') {
if (str[i+1] != '=')
error->all(FLERR,"Invalid syntax in variable formula");
op = EQ;
i++;
} else if (onechar == '!') {
if (str[i+1] == '=') {
op = NE;
i++;
} else op = NOT;
} else if (onechar == '<') {
if (str[i+1] != '=') op = LT;
else {
op = LE;
i++;
}
} else if (onechar == '>') {
if (str[i+1] != '=') op = GT;
else {
op = GE;
i++;
}
} else if (onechar == '&') {
if (str[i+1] != '&')
error->all(FLERR,"Invalid syntax in variable formula");
op = AND;
i++;
} else if (onechar == '|') {
if (str[i+1] != '|')
error->all(FLERR,"Invalid syntax in variable formula");
op = OR;
i++;
} else op = DONE;
i++;
if (op == SUBTRACT && expect == ARG) {
opstack[nopstack++] = UNARY;
continue;
}
if (op == NOT && expect == ARG) {
opstack[nopstack++] = op;
continue;
}
if (expect == ARG) error->all(FLERR,"Invalid syntax in variable formula");
expect = ARG;
// evaluate stack as deep as possible while respecting precedence
// before pushing current op onto stack
while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) {
opprevious = opstack[--nopstack];
if (tree) {
Tree *newtree = new Tree();
newtree->type = opprevious;
if (opprevious == UNARY) {
newtree->left = treestack[--ntreestack];
newtree->middle = newtree->right = NULL;
} else {
newtree->right = treestack[--ntreestack];
newtree->middle = NULL;
newtree->left = treestack[--ntreestack];
}
treestack[ntreestack++] = newtree;
} else {
value2 = argstack[--nargstack];
if (opprevious != UNARY && opprevious != NOT)
value1 = argstack[--nargstack];
if (opprevious == ADD)
argstack[nargstack++] = value1 + value2;
else if (opprevious == SUBTRACT)
argstack[nargstack++] = value1 - value2;
else if (opprevious == MULTIPLY)
argstack[nargstack++] = value1 * value2;
else if (opprevious == DIVIDE) {
if (value2 == 0.0)
error->all(FLERR,"Divide by 0 in variable formula");
argstack[nargstack++] = value1 / value2;
} else if (opprevious == MODULO) {
if (value2 == 0.0)
error->all(FLERR,"Modulo 0 in variable formula");
argstack[nargstack++] = fmod(value1,value2);
} else if (opprevious == CARAT) {
if (value2 == 0.0)
error->all(FLERR,"Power by 0 in variable formula");
argstack[nargstack++] = pow(value1,value2);
} else if (opprevious == UNARY) {
argstack[nargstack++] = -value2;
} else if (opprevious == NOT) {
if (value2 == 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == EQ) {
if (value1 == value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == NE) {
if (value1 != value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LT) {
if (value1 < value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LE) {
if (value1 <= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GT) {
if (value1 > value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GE) {
if (value1 >= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == AND) {
if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == OR) {
if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
}
}
}
// if end-of-string, break out of entire formula evaluation loop
if (op == DONE) break;
// push current operation onto stack
opstack[nopstack++] = op;
} else error->all(FLERR,"Invalid syntax in variable formula");
}
if (nopstack) error->all(FLERR,"Invalid syntax in variable formula");
// for atom-style variable, return remaining tree
// for equal-style variable, return remaining arg
if (tree) {
if (ntreestack != 1) error->all(FLERR,"Invalid syntax in variable formula");
*tree = treestack[0];
return 0.0;
} else {
if (nargstack != 1) error->all(FLERR,"Invalid syntax in variable formula");
return argstack[0];
}
}
/* ----------------------------------------------------------------------
one-time collapse of an atom-style variable parse tree
tree was created by one-time parsing of formula string via evaulate()
- only keep tree nodes that depend on ATOMARRAY, TYPEARRAY, INTARRAY
+ only keep tree nodes that depend on
+ ATOMARRAY, TYPEARRAY, INTARRAY, BIGINTARRAY
remainder is converted to single VALUE
this enables optimal eval_tree loop over atoms
customize by adding a function:
sqrt(),exp(),ln(),log(),abs(),sin(),cos(),tan(),asin(),acos(),atan(),
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
ramp(x,y),stagger(x,y),logfreq(x,y,z),stride(x,y,z),
vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z),
gmask(x),rmask(x),grmask(x,y)
---------------------------------------------------------------------- */
double Variable::collapse_tree(Tree *tree)
{
double arg1,arg2;
if (tree->type == VALUE) return tree->value;
if (tree->type == ATOMARRAY) return 0.0;
if (tree->type == TYPEARRAY) return 0.0;
if (tree->type == INTARRAY) return 0.0;
+ if (tree->type == BIGINTARRAY) return 0.0;
if (tree->type == ADD) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = arg1 + arg2;
return tree->value;
}
if (tree->type == SUBTRACT) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = arg1 - arg2;
return tree->value;
}
if (tree->type == MULTIPLY) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = arg1 * arg2;
return tree->value;
}
if (tree->type == DIVIDE) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg2 == 0.0) error->one(FLERR,"Divide by 0 in variable formula");
tree->value = arg1 / arg2;
return tree->value;
}
if (tree->type == MODULO) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg2 == 0.0) error->one(FLERR,"Modulo 0 in variable formula");
tree->value = fmod(arg1,arg2);
return tree->value;
}
if (tree->type == CARAT) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg2 == 0.0) error->one(FLERR,"Power by 0 in variable formula");
tree->value = pow(arg1,arg2);
return tree->value;
}
if (tree->type == UNARY) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = -arg1;
return tree->value;
}
if (tree->type == NOT) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 == 0.0) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == EQ) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 == arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == NE) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 != arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == LT) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 < arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == LE) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 <= arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == GT) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 > arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == GE) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 >= arg2) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == AND) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 != 0.0 && arg2 != 0.0) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == OR) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 != 0.0 || arg2 != 0.0) tree->value = 1.0;
else tree->value = 0.0;
return tree->value;
}
if (tree->type == SQRT) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 < 0.0)
error->one(FLERR,"Sqrt of negative value in variable formula");
tree->value = sqrt(arg1);
return tree->value;
}
if (tree->type == EXP) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = exp(arg1);
return tree->value;
}
if (tree->type == LN) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 <= 0.0)
error->one(FLERR,"Log of zero/negative value in variable formula");
tree->value = log(arg1);
return tree->value;
}
if (tree->type == LOG) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 <= 0.0)
error->one(FLERR,"Log of zero/negative value in variable formula");
tree->value = log10(arg1);
return tree->value;
}
if (tree->type == ABS) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = fabs(arg1);
return tree->value;
}
if (tree->type == SIN) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = sin(arg1);
return tree->value;
}
if (tree->type == COS) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = cos(arg1);
return tree->value;
}
if (tree->type == TAN) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = tan(arg1);
return tree->value;
}
if (tree->type == ASIN) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 < -1.0 || arg1 > 1.0)
error->one(FLERR,"Arcsin of invalid value in variable formula");
tree->value = asin(arg1);
return tree->value;
}
if (tree->type == ACOS) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg1 < -1.0 || arg1 > 1.0)
error->one(FLERR,"Arccos of invalid value in variable formula");
tree->value = acos(arg1);
return tree->value;
}
if (tree->type == ATAN) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = atan(arg1);
return tree->value;
}
if (tree->type == ATAN2) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = atan2(arg1,arg2);
return tree->value;
}
// random() or normal() do not become a single collapsed value
if (tree->type == RANDOM) {
collapse_tree(tree->left);
collapse_tree(tree->middle);
if (randomatom == NULL) {
int seed = static_cast<int> (collapse_tree(tree->right));
if (seed <= 0)
error->one(FLERR,"Invalid math function in variable formula");
randomatom = new RanMars(lmp,seed+me);
}
return 0.0;
}
if (tree->type == NORMAL) {
collapse_tree(tree->left);
double sigma = collapse_tree(tree->middle);
if (sigma < 0.0)
error->one(FLERR,"Invalid math function in variable formula");
if (randomatom == NULL) {
int seed = static_cast<int> (collapse_tree(tree->right));
if (seed <= 0)
error->one(FLERR,"Invalid math function in variable formula");
randomatom = new RanMars(lmp,seed+me);
}
return 0.0;
}
if (tree->type == CEIL) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = ceil(arg1);
return tree->value;
}
if (tree->type == FLOOR) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = floor(arg1);
return tree->value;
}
if (tree->type == ROUND) {
arg1 = collapse_tree(tree->left);
if (tree->left->type != VALUE) return 0.0;
tree->type = VALUE;
tree->value = MYROUND(arg1);
return tree->value;
}
if (tree->type == RAMP) {
arg1 = collapse_tree(tree->left);
arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
tree->value = arg1 + delta*(arg2-arg1);
return tree->value;
}
if (tree->type == STAGGER) {
int ivalue1 = static_cast<int> (collapse_tree(tree->left));
int ivalue2 = static_cast<int> (collapse_tree(tree->right));
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
int lower = update->ntimestep/ivalue1 * ivalue1;
int delta = update->ntimestep - lower;
if (delta < ivalue2) tree->value = lower+ivalue2;
else tree->value = lower+ivalue1;
return tree->value;
}
if (tree->type == LOGFREQ) {
int ivalue1 = static_cast<int> (collapse_tree(tree->left));
int ivalue2 = static_cast<int> (collapse_tree(tree->middle));
int ivalue3 = static_cast<int> (collapse_tree(tree->right));
if (tree->left->type != VALUE || tree->middle->type != VALUE ||
tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) tree->value = ivalue1;
else {
int lower = ivalue1;
while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
int multiple = update->ntimestep/lower;
if (multiple < ivalue2) tree->value = (multiple+1)*lower;
else tree->value = lower*ivalue3;
}
return tree->value;
}
if (tree->type == STRIDE) {
int ivalue1 = static_cast<int> (collapse_tree(tree->left));
int ivalue2 = static_cast<int> (collapse_tree(tree->middle));
int ivalue3 = static_cast<int> (collapse_tree(tree->right));
if (tree->left->type != VALUE || tree->middle->type != VALUE ||
tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) tree->value = ivalue1;
else if (update->ntimestep < ivalue2) {
int offset = update->ntimestep - ivalue1;
tree->value = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (tree->value > ivalue2) tree->value = 9.0e18;
} else tree->value = 9.0e18;
return tree->value;
}
if (tree->type == VDISPLACE) {
double arg1 = collapse_tree(tree->left);
double arg2 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
double delta = update->ntimestep - update->beginstep;
tree->value = arg1 + arg2*delta*update->dt;
return tree->value;
}
if (tree->type == SWIGGLE) {
double arg1 = collapse_tree(tree->left);
double arg2 = collapse_tree(tree->middle);
double arg3 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->middle->type != VALUE ||
tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg3 == 0.0)
error->one(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/arg3;
tree->value = arg1 + arg2*sin(omega*delta*update->dt);
return tree->value;
}
if (tree->type == CWIGGLE) {
double arg1 = collapse_tree(tree->left);
double arg2 = collapse_tree(tree->middle);
double arg3 = collapse_tree(tree->right);
if (tree->left->type != VALUE || tree->middle->type != VALUE ||
tree->right->type != VALUE) return 0.0;
tree->type = VALUE;
if (arg3 == 0.0)
error->one(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/arg3;
tree->value = arg1 + arg2*(1.0-cos(omega*delta*update->dt));
return tree->value;
}
// mask functions do not become a single collapsed value
if (tree->type == GMASK) return 0.0;
if (tree->type == RMASK) return 0.0;
if (tree->type == GRMASK) return 0.0;
return 0.0;
}
/* ----------------------------------------------------------------------
evaluate an atom-style variable parse tree for atom I
tree was created by one-time parsing of formula string via evaulate()
customize by adding a function:
sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(),
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
ramp(x,y),stagger(x,y),logfreq(x,y,z),stride(x,y,z),
vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z),
gmask(x),rmask(x),grmask(x,y)
---------------------------------------------------------------------- */
double Variable::eval_tree(Tree *tree, int i)
{
double arg,arg1,arg2,arg3;
if (tree->type == VALUE) return tree->value;
if (tree->type == ATOMARRAY) return tree->array[i*tree->nstride];
if (tree->type == TYPEARRAY) return tree->array[atom->type[i]];
if (tree->type == INTARRAY) return (double) tree->iarray[i*tree->nstride];
+ if (tree->type == BIGINTARRAY) return (double) tree->barray[i*tree->nstride];
if (tree->type == ADD)
return eval_tree(tree->left,i) + eval_tree(tree->right,i);
if (tree->type == SUBTRACT)
return eval_tree(tree->left,i) - eval_tree(tree->right,i);
if (tree->type == MULTIPLY)
return eval_tree(tree->left,i) * eval_tree(tree->right,i);
if (tree->type == DIVIDE) {
double denom = eval_tree(tree->right,i);
if (denom == 0.0) error->one(FLERR,"Divide by 0 in variable formula");
return eval_tree(tree->left,i) / denom;
}
if (tree->type == MODULO) {
double denom = eval_tree(tree->right,i);
if (denom == 0.0) error->one(FLERR,"Modulo 0 in variable formula");
return fmod(eval_tree(tree->left,i),denom);
}
if (tree->type == CARAT) {
double exponent = eval_tree(tree->right,i);
if (exponent == 0.0) error->one(FLERR,"Power by 0 in variable formula");
return pow(eval_tree(tree->left,i),exponent);
}
if (tree->type == UNARY) return -eval_tree(tree->left,i);
if (tree->type == NOT) {
if (eval_tree(tree->left,i) == 0.0) return 1.0;
else return 0.0;
}
if (tree->type == EQ) {
if (eval_tree(tree->left,i) == eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == NE) {
if (eval_tree(tree->left,i) != eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == LT) {
if (eval_tree(tree->left,i) < eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == LE) {
if (eval_tree(tree->left,i) <= eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == GT) {
if (eval_tree(tree->left,i) > eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == GE) {
if (eval_tree(tree->left,i) >= eval_tree(tree->right,i)) return 1.0;
else return 0.0;
}
if (tree->type == AND) {
if (eval_tree(tree->left,i) != 0.0 && eval_tree(tree->right,i) != 0.0)
return 1.0;
else return 0.0;
}
if (tree->type == OR) {
if (eval_tree(tree->left,i) != 0.0 || eval_tree(tree->right,i) != 0.0)
return 1.0;
else return 0.0;
}
if (tree->type == SQRT) {
arg1 = eval_tree(tree->left,i);
if (arg1 < 0.0)
error->one(FLERR,"Sqrt of negative value in variable formula");
return sqrt(arg1);
}
if (tree->type == EXP)
return exp(eval_tree(tree->left,i));
if (tree->type == LN) {
arg1 = eval_tree(tree->left,i);
if (arg1 <= 0.0)
error->one(FLERR,"Log of zero/negative value in variable formula");
return log(arg1);
}
if (tree->type == LOG) {
arg1 = eval_tree(tree->left,i);
if (arg1 <= 0.0)
error->one(FLERR,"Log of zero/negative value in variable formula");
return log10(arg1);
}
if (tree->type == ABS)
return fabs(eval_tree(tree->left,i));
if (tree->type == SIN)
return sin(eval_tree(tree->left,i));
if (tree->type == COS)
return cos(eval_tree(tree->left,i));
if (tree->type == TAN)
return tan(eval_tree(tree->left,i));
if (tree->type == ASIN) {
arg1 = eval_tree(tree->left,i);
if (arg1 < -1.0 || arg1 > 1.0)
error->one(FLERR,"Arcsin of invalid value in variable formula");
return asin(arg1);
}
if (tree->type == ACOS) {
arg1 = eval_tree(tree->left,i);
if (arg1 < -1.0 || arg1 > 1.0)
error->one(FLERR,"Arccos of invalid value in variable formula");
return acos(arg1);
}
if (tree->type == ATAN)
return atan(eval_tree(tree->left,i));
if (tree->type == ATAN2)
return atan2(eval_tree(tree->left,i),eval_tree(tree->right,i));
if (tree->type == RANDOM) {
double lower = eval_tree(tree->left,i);
double upper = eval_tree(tree->middle,i);
if (randomatom == NULL) {
int seed = static_cast<int> (eval_tree(tree->right,i));
if (seed <= 0)
error->one(FLERR,"Invalid math function in variable formula");
randomatom = new RanMars(lmp,seed+me);
}
return randomatom->uniform()*(upper-lower)+lower;
}
if (tree->type == NORMAL) {
double mu = eval_tree(tree->left,i);
double sigma = eval_tree(tree->middle,i);
if (sigma < 0.0)
error->one(FLERR,"Invalid math function in variable formula");
if (randomatom == NULL) {
int seed = static_cast<int> (eval_tree(tree->right,i));
if (seed <= 0)
error->one(FLERR,"Invalid math function in variable formula");
randomatom = new RanMars(lmp,seed+me);
}
return mu + sigma*randomatom->gaussian();
}
if (tree->type == CEIL)
return ceil(eval_tree(tree->left,i));
if (tree->type == FLOOR)
return floor(eval_tree(tree->left,i));
if (tree->type == ROUND)
return MYROUND(eval_tree(tree->left,i));
if (tree->type == RAMP) {
arg1 = eval_tree(tree->left,i);
arg2 = eval_tree(tree->right,i);
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
arg = arg1 + delta*(arg2-arg1);
return arg;
}
if (tree->type == STAGGER) {
int ivalue1 = static_cast<int> (eval_tree(tree->left,i));
int ivalue2 = static_cast<int> (eval_tree(tree->right,i));
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
int lower = update->ntimestep/ivalue1 * ivalue1;
int delta = update->ntimestep - lower;
if (delta < ivalue2) arg = lower+ivalue2;
else arg = lower+ivalue1;
return arg;
}
if (tree->type == LOGFREQ) {
int ivalue1 = static_cast<int> (eval_tree(tree->left,i));
int ivalue2 = static_cast<int> (eval_tree(tree->middle,i));
int ivalue3 = static_cast<int> (eval_tree(tree->right,i));
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) arg = ivalue1;
else {
int lower = ivalue1;
while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
int multiple = update->ntimestep/lower;
if (multiple < ivalue2) arg = (multiple+1)*lower;
else arg = lower*ivalue3;
}
return arg;
}
if (tree->type == STRIDE) {
int ivalue1 = static_cast<int> (eval_tree(tree->left,i));
int ivalue2 = static_cast<int> (eval_tree(tree->middle,i));
int ivalue3 = static_cast<int> (eval_tree(tree->right,i));
if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) arg = ivalue1;
else if (update->ntimestep < ivalue2) {
int offset = update->ntimestep - ivalue1;
arg = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (arg > ivalue2) arg = 9.0e18;
} else arg = 9.0e18;
return arg;
}
if (tree->type == VDISPLACE) {
arg1 = eval_tree(tree->left,i);
arg2 = eval_tree(tree->right,i);
double delta = update->ntimestep - update->beginstep;
arg = arg1 + arg2*delta*update->dt;
return arg;
}
if (tree->type == SWIGGLE) {
arg1 = eval_tree(tree->left,i);
arg2 = eval_tree(tree->middle,i);
arg3 = eval_tree(tree->right,i);
if (arg3 == 0.0)
error->one(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/arg3;
arg = arg1 + arg2*sin(omega*delta*update->dt);
return arg;
}
if (tree->type == CWIGGLE) {
arg1 = eval_tree(tree->left,i);
arg2 = eval_tree(tree->middle,i);
arg3 = eval_tree(tree->right,i);
if (arg3 == 0.0)
error->one(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/arg3;
arg = arg1 + arg2*(1.0-cos(omega*delta*update->dt));
return arg;
}
if (tree->type == GMASK) {
if (atom->mask[i] & tree->ivalue1) return 1.0;
else return 0.0;
}
if (tree->type == RMASK) {
if (domain->regions[tree->ivalue1]->match(atom->x[i][0],
atom->x[i][1],
atom->x[i][2])) return 1.0;
else return 0.0;
}
if (tree->type == GRMASK) {
if ((atom->mask[i] & tree->ivalue1) &&
(domain->regions[tree->ivalue2]->match(atom->x[i][0],
atom->x[i][1],
atom->x[i][2]))) return 1.0;
else return 0.0;
}
return 0.0;
}
/* ---------------------------------------------------------------------- */
void Variable::free_tree(Tree *tree)
{
if (tree->left) free_tree(tree->left);
if (tree->middle) free_tree(tree->middle);
if (tree->right) free_tree(tree->right);
if (tree->type == ATOMARRAY && tree->selfalloc)
memory->destroy(tree->array);
delete tree;
}
/* ----------------------------------------------------------------------
find matching parenthesis in str, allocate contents = str between parens
i = left paren
return loc or right paren
------------------------------------------------------------------------- */
int Variable::find_matching_paren(char *str, int i,char *&contents)
{
// istop = matching ')' at same level, allowing for nested parens
int istart = i;
int ilevel = 0;
while (1) {
i++;
if (!str[i]) break;
if (str[i] == '(') ilevel++;
else if (str[i] == ')' && ilevel) ilevel--;
else if (str[i] == ')') break;
}
if (!str[i]) error->all(FLERR,"Invalid syntax in variable formula");
int istop = i;
int n = istop - istart - 1;
contents = new char[n+1];
strncpy(contents,&str[istart+1],n);
contents[n] = '\0';
return istop;
}
/* ----------------------------------------------------------------------
find int between brackets and return it
ptr initially points to left bracket
return it pointing to right bracket
error if no right bracket or brackets are empty
error if any between-bracket chars are non-digits or value == 0
------------------------------------------------------------------------- */
int Variable::int_between_brackets(char *&ptr)
{
char *start = ++ptr;
while (*ptr && *ptr != ']') {
if (!isdigit(*ptr))
error->all(FLERR,"Non digit character between brackets in variable");
ptr++;
}
if (*ptr != ']') error->all(FLERR,"Mismatched brackets in variable");
if (ptr == start) error->all(FLERR,"Empty brackets in variable");
*ptr = '\0';
int index = atoi(start);
*ptr = ']';
if (index == 0)
error->all(FLERR,"Index between variable brackets must be positive");
return index;
}
/* ----------------------------------------------------------------------
process a math function in formula
push result onto tree or arg stack
word = math function
contents = str between parentheses with one,two,three args
return 0 if not a match, 1 if successfully processed
customize by adding a math function:
sqrt(),exp(),ln(),log(),abs(),sin(),cos(),tan(),asin(),acos(),atan(),
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),
ramp(x,y),stagger(x,y),logfreq(x,y,z),stride(x,y,z),
vdisplace(x,y),swiggle(x,y,z),cwiggle(x,y,z)
------------------------------------------------------------------------- */
int Variable::math_function(char *word, char *contents, Tree **tree,
Tree **treestack, int &ntreestack,
double *argstack, int &nargstack)
{
// word not a match to any math function
if (strcmp(word,"sqrt") && strcmp(word,"exp") &&
strcmp(word,"ln") && strcmp(word,"log") &&
strcmp(word,"abs") &&
strcmp(word,"sin") && strcmp(word,"cos") &&
strcmp(word,"tan") && strcmp(word,"asin") &&
strcmp(word,"acos") && strcmp(word,"atan") &&
strcmp(word,"atan2") && strcmp(word,"random") &&
strcmp(word,"normal") && strcmp(word,"ceil") &&
strcmp(word,"floor") && strcmp(word,"round") &&
strcmp(word,"ramp") && strcmp(word,"stagger") &&
strcmp(word,"logfreq") && strcmp(word,"stride") &&
strcmp(word,"vdisplace") &&
strcmp(word,"swiggle") && strcmp(word,"cwiggle"))
return 0;
// parse contents for arg1,arg2,arg3 separated by commas
// ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
char *arg1,*arg2,*arg3;
char *ptr1,*ptr2;
ptr1 = find_next_comma(contents);
if (ptr1) {
*ptr1 = '\0';
ptr2 = find_next_comma(ptr1+1);
if (ptr2) *ptr2 = '\0';
} else ptr2 = NULL;
int n = strlen(contents) + 1;
arg1 = new char[n];
strcpy(arg1,contents);
int narg = 1;
if (ptr1) {
n = strlen(ptr1+1) + 1;
arg2 = new char[n];
strcpy(arg2,ptr1+1);
narg = 2;
} else arg2 = NULL;
if (ptr2) {
n = strlen(ptr2+1) + 1;
arg3 = new char[n];
strcpy(arg3,ptr2+1);
narg = 3;
} else arg3 = NULL;
// evaluate args
Tree *newtree;
double tmp,value1,value2,value3;
if (tree) {
newtree = new Tree();
Tree *argtree;
if (narg == 1) {
tmp = evaluate(arg1,&argtree);
newtree->left = argtree;
newtree->middle = newtree->right = NULL;
} else if (narg == 2) {
tmp = evaluate(arg1,&argtree);
newtree->left = argtree;
newtree->middle = NULL;
tmp = evaluate(arg2,&argtree);
newtree->right = argtree;
} else if (narg == 3) {
tmp = evaluate(arg1,&argtree);
newtree->left = argtree;
tmp = evaluate(arg2,&argtree);
newtree->middle = argtree;
tmp = evaluate(arg3,&argtree);
newtree->right = argtree;
}
treestack[ntreestack++] = newtree;
} else {
if (narg == 1) {
value1 = evaluate(arg1,NULL);
} else if (narg == 2) {
value1 = evaluate(arg1,NULL);
value2 = evaluate(arg2,NULL);
} else if (narg == 3) {
value1 = evaluate(arg1,NULL);
value2 = evaluate(arg2,NULL);
value3 = evaluate(arg3,NULL);
}
}
if (strcmp(word,"sqrt") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = SQRT;
else {
if (value1 < 0.0)
error->all(FLERR,"Sqrt of negative value in variable formula");
argstack[nargstack++] = sqrt(value1);
}
} else if (strcmp(word,"exp") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = EXP;
else argstack[nargstack++] = exp(value1);
} else if (strcmp(word,"ln") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = LN;
else {
if (value1 <= 0.0)
error->all(FLERR,"Log of zero/negative value in variable formula");
argstack[nargstack++] = log(value1);
}
} else if (strcmp(word,"log") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = LOG;
else {
if (value1 <= 0.0)
error->all(FLERR,"Log of zero/negative value in variable formula");
argstack[nargstack++] = log10(value1);
}
} else if (strcmp(word,"abs") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ABS;
else argstack[nargstack++] = fabs(value1);
} else if (strcmp(word,"sin") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = SIN;
else argstack[nargstack++] = sin(value1);
} else if (strcmp(word,"cos") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = COS;
else argstack[nargstack++] = cos(value1);
} else if (strcmp(word,"tan") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = TAN;
else argstack[nargstack++] = tan(value1);
} else if (strcmp(word,"asin") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ASIN;
else {
if (value1 < -1.0 || value1 > 1.0)
error->all(FLERR,"Arcsin of invalid value in variable formula");
argstack[nargstack++] = asin(value1);
}
} else if (strcmp(word,"acos") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ACOS;
else {
if (value1 < -1.0 || value1 > 1.0)
error->all(FLERR,"Arccos of invalid value in variable formula");
argstack[nargstack++] = acos(value1);
}
} else if (strcmp(word,"atan") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ATAN;
else argstack[nargstack++] = atan(value1);
} else if (strcmp(word,"atan2") == 0) {
if (narg != 2)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ATAN2;
else argstack[nargstack++] = atan2(value1,value2);
} else if (strcmp(word,"random") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = RANDOM;
else {
if (randomequal == NULL) {
int seed = static_cast<int> (value3);
if (seed <= 0)
error->all(FLERR,"Invalid math function in variable formula");
randomequal = new RanMars(lmp,seed);
}
argstack[nargstack++] = randomequal->uniform()*(value2-value1) + value1;
}
} else if (strcmp(word,"normal") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = NORMAL;
else {
if (value2 < 0.0)
error->all(FLERR,"Invalid math function in variable formula");
if (randomequal == NULL) {
int seed = static_cast<int> (value3);
if (seed <= 0)
error->all(FLERR,"Invalid math function in variable formula");
randomequal = new RanMars(lmp,seed);
}
argstack[nargstack++] = value1 + value2*randomequal->gaussian();
}
} else if (strcmp(word,"ceil") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = CEIL;
else argstack[nargstack++] = ceil(value1);
} else if (strcmp(word,"floor") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = FLOOR;
else argstack[nargstack++] = floor(value1);
} else if (strcmp(word,"round") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = ROUND;
else argstack[nargstack++] = MYROUND(value1);
} else if (strcmp(word,"ramp") == 0) {
if (narg != 2)
error->all(FLERR,"Invalid math function in variable formula");
if (update->whichflag == 0)
error->all(FLERR,"Cannot use ramp in variable formula between runs");
if (tree) newtree->type = RAMP;
else {
double delta = update->ntimestep - update->beginstep;
if (delta != 0.0) delta /= update->endstep - update->beginstep;
double value = value1 + delta*(value2-value1);
argstack[nargstack++] = value;
}
} else if (strcmp(word,"stagger") == 0) {
if (narg != 2)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = STAGGER;
else {
int ivalue1 = static_cast<int> (value1);
int ivalue2 = static_cast<int> (value2);
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
error->all(FLERR,"Invalid math function in variable formula");
int lower = update->ntimestep/ivalue1 * ivalue1;
int delta = update->ntimestep - lower;
double value;
if (delta < ivalue2) value = lower+ivalue2;
else value = lower+ivalue1;
argstack[nargstack++] = value;
}
} else if (strcmp(word,"logfreq") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = LOGFREQ;
else {
int ivalue1 = static_cast<int> (value1);
int ivalue2 = static_cast<int> (value2);
int ivalue3 = static_cast<int> (value3);
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue3 <= 0 || ivalue2 >= ivalue3)
error->all(FLERR,"Invalid math function in variable formula");
double value;
if (update->ntimestep < ivalue1) value = ivalue1;
else {
int lower = ivalue1;
while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
int multiple = update->ntimestep/lower;
if (multiple < ivalue2) value = (multiple+1)*lower;
else value = lower*ivalue3;
}
argstack[nargstack++] = value;
}
} else if (strcmp(word,"stride") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (tree) newtree->type = STRIDE;
else {
int ivalue1 = static_cast<int> (value1);
int ivalue2 = static_cast<int> (value2);
int ivalue3 = static_cast<int> (value3);
if (ivalue1 < 0 || ivalue2 < 0 || ivalue3 <= 0 || ivalue1 > ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
double value;
if (update->ntimestep < ivalue1) value = ivalue1;
else if (update->ntimestep < ivalue2) {
int offset = update->ntimestep - ivalue1;
value = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (value > ivalue2) value = 9.0e18;
} else value = 9.0e18;
argstack[nargstack++] = value;
}
} else if (strcmp(word,"vdisplace") == 0) {
if (narg != 2)
error->all(FLERR,"Invalid math function in variable formula");
if (update->whichflag == 0)
error->all(FLERR,"Cannot use vdisplace in variable formula between runs");
if (tree) newtree->type = VDISPLACE;
else {
double delta = update->ntimestep - update->beginstep;
double value = value1 + value2*delta*update->dt;
argstack[nargstack++] = value;
}
} else if (strcmp(word,"swiggle") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (update->whichflag == 0)
error->all(FLERR,"Cannot use swiggle in variable formula between runs");
if (tree) newtree->type = CWIGGLE;
else {
if (value3 == 0.0)
error->all(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/value3;
double value = value1 + value2*sin(omega*delta*update->dt);
argstack[nargstack++] = value;
}
} else if (strcmp(word,"cwiggle") == 0) {
if (narg != 3)
error->all(FLERR,"Invalid math function in variable formula");
if (update->whichflag == 0)
error->all(FLERR,"Cannot use cwiggle in variable formula between runs");
if (tree) newtree->type = CWIGGLE;
else {
if (value3 == 0.0)
error->all(FLERR,"Invalid math function in variable formula");
double delta = update->ntimestep - update->beginstep;
double omega = 2.0*MY_PI/value3;
double value = value1 + value2*(1.0-cos(omega*delta*update->dt));
argstack[nargstack++] = value;
}
}
delete [] arg1;
delete [] arg2;
delete [] arg3;
return 1;
}
/* ----------------------------------------------------------------------
process a group function in formula with optional region arg
push result onto tree or arg stack
word = group function
contents = str between parentheses with one,two,three args
return 0 if not a match, 1 if successfully processed
customize by adding a group function with optional region arg:
count(group),mass(group),charge(group),
xcm(group,dim),vcm(group,dim),fcm(group,dim),
bound(group,xmin),gyration(group),ke(group),angmom(group,dim),
torque(group,dim),inertia(group,dim),omega(group,dim)
------------------------------------------------------------------------- */
int Variable::group_function(char *word, char *contents, Tree **tree,
Tree **treestack, int &ntreestack,
double *argstack, int &nargstack)
{
// word not a match to any group function
if (strcmp(word,"count") && strcmp(word,"mass") &&
strcmp(word,"charge") && strcmp(word,"xcm") &&
strcmp(word,"vcm") && strcmp(word,"fcm") &&
strcmp(word,"bound") && strcmp(word,"gyration") &&
strcmp(word,"ke") && strcmp(word,"angmom") &&
strcmp(word,"torque") && strcmp(word,"inertia") &&
strcmp(word,"omega"))
return 0;
// parse contents for arg1,arg2,arg3 separated by commas
// ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
char *arg1,*arg2,*arg3;
char *ptr1,*ptr2;
ptr1 = find_next_comma(contents);
if (ptr1) {
*ptr1 = '\0';
ptr2 = find_next_comma(ptr1+1);
if (ptr2) *ptr2 = '\0';
} else ptr2 = NULL;
int n = strlen(contents) + 1;
arg1 = new char[n];
strcpy(arg1,contents);
int narg = 1;
if (ptr1) {
n = strlen(ptr1+1) + 1;
arg2 = new char[n];
strcpy(arg2,ptr1+1);
narg = 2;
} else arg2 = NULL;
if (ptr2) {
n = strlen(ptr2+1) + 1;
arg3 = new char[n];
strcpy(arg3,ptr2+1);
narg = 3;
} else arg3 = NULL;
// group to operate on
int igroup = group->find(arg1);
if (igroup == -1)
error->all(FLERR,"Group ID in variable formula does not exist");
// match word to group function
double value;
if (strcmp(word,"count") == 0) {
if (narg == 1) value = group->count(igroup);
else if (narg == 2) value = group->count(igroup,region_function(arg2));
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"mass") == 0) {
if (narg == 1) value = group->mass(igroup);
else if (narg == 2) value = group->mass(igroup,region_function(arg2));
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"charge") == 0) {
if (narg == 1) value = group->charge(igroup);
else if (narg == 2) value = group->charge(igroup,region_function(arg2));
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"xcm") == 0) {
atom->check_mass();
double xcm[3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = xcm[0];
else if (strcmp(arg2,"y") == 0) value = xcm[1];
else if (strcmp(arg2,"z") == 0) value = xcm[2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"vcm") == 0) {
atom->check_mass();
double vcm[3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->vcm(igroup,masstotal,vcm);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->vcm(igroup,masstotal,vcm,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = vcm[0];
else if (strcmp(arg2,"y") == 0) value = vcm[1];
else if (strcmp(arg2,"z") == 0) value = vcm[2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"fcm") == 0) {
double fcm[3];
if (narg == 2) group->fcm(igroup,fcm);
else if (narg == 3) group->fcm(igroup,fcm,region_function(arg3));
else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = fcm[0];
else if (strcmp(arg2,"y") == 0) value = fcm[1];
else if (strcmp(arg2,"z") == 0) value = fcm[2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"bound") == 0) {
double minmax[6];
if (narg == 2) group->bounds(igroup,minmax);
else if (narg == 3) group->bounds(igroup,minmax,region_function(arg3));
else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"xmin") == 0) value = minmax[0];
else if (strcmp(arg2,"xmax") == 0) value = minmax[1];
else if (strcmp(arg2,"ymin") == 0) value = minmax[2];
else if (strcmp(arg2,"ymax") == 0) value = minmax[3];
else if (strcmp(arg2,"zmin") == 0) value = minmax[4];
else if (strcmp(arg2,"zmax") == 0) value = minmax[5];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"gyration") == 0) {
atom->check_mass();
double xcm[3];
if (narg == 1) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
value = group->gyration(igroup,masstotal,xcm);
} else if (narg == 2) {
int iregion = region_function(arg2);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
value = group->gyration(igroup,masstotal,xcm,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"ke") == 0) {
if (narg == 1) value = group->ke(igroup);
else if (narg == 2) value = group->ke(igroup,region_function(arg2));
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"angmom") == 0) {
atom->check_mass();
double xcm[3],lmom[3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
group->angmom(igroup,xcm,lmom);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
group->angmom(igroup,xcm,lmom,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = lmom[0];
else if (strcmp(arg2,"y") == 0) value = lmom[1];
else if (strcmp(arg2,"z") == 0) value = lmom[2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"torque") == 0) {
atom->check_mass();
double xcm[3],tq[3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
group->torque(igroup,xcm,tq);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
group->torque(igroup,xcm,tq,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = tq[0];
else if (strcmp(arg2,"y") == 0) value = tq[1];
else if (strcmp(arg2,"z") == 0) value = tq[2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"inertia") == 0) {
atom->check_mass();
double xcm[3],inertia[3][3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
group->inertia(igroup,xcm,inertia);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
group->inertia(igroup,xcm,inertia,iregion);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"xx") == 0) value = inertia[0][0];
else if (strcmp(arg2,"yy") == 0) value = inertia[1][1];
else if (strcmp(arg2,"zz") == 0) value = inertia[2][2];
else if (strcmp(arg2,"xy") == 0) value = inertia[0][1];
else if (strcmp(arg2,"yz") == 0) value = inertia[1][2];
else if (strcmp(arg2,"xz") == 0) value = inertia[0][2];
else error->all(FLERR,"Invalid group function in variable formula");
} else if (strcmp(word,"omega") == 0) {
atom->check_mass();
double xcm[3],angmom[3],inertia[3][3],omega[3];
if (narg == 2) {
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
group->angmom(igroup,xcm,angmom);
group->inertia(igroup,xcm,inertia);
group->omega(angmom,inertia,omega);
} else if (narg == 3) {
int iregion = region_function(arg3);
double masstotal = group->mass(igroup,iregion);
group->xcm(igroup,masstotal,xcm,iregion);
group->angmom(igroup,xcm,angmom,iregion);
group->inertia(igroup,xcm,inertia,iregion);
group->omega(angmom,inertia,omega);
} else error->all(FLERR,"Invalid group function in variable formula");
if (strcmp(arg2,"x") == 0) value = omega[0];
else if (strcmp(arg2,"y") == 0) value = omega[1];
else if (strcmp(arg2,"z") == 0) value = omega[2];
else error->all(FLERR,"Invalid group function in variable formula");
}
delete [] arg1;
delete [] arg2;
delete [] arg3;
// save value in tree or on argstack
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value;
return 1;
}
/* ---------------------------------------------------------------------- */
int Variable::region_function(char *id)
{
int iregion = domain->find_region(id);
if (iregion == -1)
error->all(FLERR,"Region ID in variable formula does not exist");
// init region in case sub-regions have been deleted
domain->regions[iregion]->init();
return iregion;
}
/* ----------------------------------------------------------------------
process a special function in formula
push result onto tree or arg stack
word = special function
contents = str between parentheses with one,two,three args
return 0 if not a match, 1 if successfully processed
customize by adding a special function:
sum(x),min(x),max(x),ave(x),trap(x),gmask(x),rmask(x),grmask(x,y),next(x)
------------------------------------------------------------------------- */
int Variable::special_function(char *word, char *contents, Tree **tree,
Tree **treestack, int &ntreestack,
double *argstack, int &nargstack)
{
// word not a match to any special function
if (strcmp(word,"sum") && strcmp(word,"min") && strcmp(word,"max") &&
strcmp(word,"ave") && strcmp(word,"trap") && strcmp(word,"gmask") &&
strcmp(word,"isdef") &&
strcmp(word,"rmask") && strcmp(word,"grmask") && strcmp(word,"next"))
return 0;
// parse contents for arg1,arg2,arg3 separated by commas
// ptr1,ptr2 = location of 1st and 2nd comma, NULL if none
char *arg1,*arg2,*arg3;
char *ptr1,*ptr2;
ptr1 = find_next_comma(contents);
if (ptr1) {
*ptr1 = '\0';
ptr2 = find_next_comma(ptr1+1);
if (ptr2) *ptr2 = '\0';
} else ptr2 = NULL;
int n = strlen(contents) + 1;
arg1 = new char[n];
strcpy(arg1,contents);
int narg = 1;
if (ptr1) {
n = strlen(ptr1+1) + 1;
arg2 = new char[n];
strcpy(arg2,ptr1+1);
narg = 2;
} else arg2 = NULL;
if (ptr2) {
n = strlen(ptr2+1) + 1;
arg3 = new char[n];
strcpy(arg3,ptr2+1);
narg = 3;
} else arg3 = NULL;
// special functions that operate on global vectors
if (strcmp(word,"sum") == 0 || strcmp(word,"min") == 0 ||
strcmp(word,"max") == 0 || strcmp(word,"ave") == 0 ||
strcmp(word,"trap") == 0) {
int method;
if (strcmp(word,"sum") == 0) method = SUM;
else if (strcmp(word,"min") == 0) method = XMIN;
else if (strcmp(word,"max") == 0) method = XMAX;
else if (strcmp(word,"ave") == 0) method = AVE;
else if (strcmp(word,"trap") == 0) method = TRAP;
if (narg != 1)
error->all(FLERR,"Invalid special function in variable formula");
Compute *compute = NULL;
Fix *fix = NULL;
int index,nvec,nstride;
if (strstr(arg1,"c_") == arg1) {
ptr1 = strchr(arg1,'[');
if (ptr1) {
ptr2 = ptr1;
index = int_between_brackets(ptr2);
*ptr1 = '\0';
} else index = 0;
int icompute = modify->find_compute(&arg1[2]);
if (icompute < 0)
error->all(FLERR,"Invalid compute ID in variable formula");
compute = modify->compute[icompute];
if (index == 0 && compute->vector_flag) {
if (update->whichflag == 0) {
if (compute->invoked_vector != update->ntimestep)
error->all(FLERR,
"Compute used in variable between runs is not current");
} else if (!(compute->invoked_flag & INVOKED_VECTOR)) {
compute->compute_vector();
compute->invoked_flag |= INVOKED_VECTOR;
}
nvec = compute->size_vector;
nstride = 1;
} else if (index && compute->array_flag) {
if (index > compute->size_array_cols)
error->all(FLERR,"Variable formula compute array "
"is accessed out-of-range");
if (update->whichflag == 0) {
if (compute->invoked_array != update->ntimestep)
error->all(FLERR,
"Compute used in variable between runs is not current");
} else if (!(compute->invoked_flag & INVOKED_ARRAY)) {
compute->compute_array();
compute->invoked_flag |= INVOKED_ARRAY;
}
nvec = compute->size_array_rows;
nstride = compute->size_array_cols;
} else error->all(FLERR,"Mismatched compute in variable formula");
} else if (strstr(arg1,"f_") == arg1) {
ptr1 = strchr(arg1,'[');
if (ptr1) {
ptr2 = ptr1;
index = int_between_brackets(ptr2);
*ptr1 = '\0';
} else index = 0;
int ifix = modify->find_fix(&arg1[2]);
if (ifix < 0) error->all(FLERR,"Invalid fix ID in variable formula");
fix = modify->fix[ifix];
if (index == 0 && fix->vector_flag) {
if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
nvec = fix->size_vector;
nstride = 1;
} else if (index && fix->array_flag) {
if (index > fix->size_array_cols)
error->all(FLERR,
"Variable formula fix array is accessed out-of-range");
if (update->whichflag > 0 && update->ntimestep % fix->global_freq)
error->all(FLERR,"Fix in variable not computed at compatible time");
nvec = fix->size_array_rows;
nstride = fix->size_array_cols;
} else error->all(FLERR,"Mismatched fix in variable formula");
} else error->all(FLERR,"Invalid special function in variable formula");
double value = 0.0;
if (method == XMIN) value = BIG;
if (method == XMAX) value = -BIG;
if (compute) {
double *vec;
if (index) {
if (compute->array) vec = &compute->array[0][index-1];
else vec = NULL;
} else vec = compute->vector;
int j = 0;
for (int i = 0; i < nvec; i++) {
if (method == SUM) value += vec[j];
else if (method == XMIN) value = MIN(value,vec[j]);
else if (method == XMAX) value = MAX(value,vec[j]);
else if (method == AVE) value += vec[j];
else if (method == TRAP) {
if (i > 0 && i < nvec-1) value += vec[j];
else value += 0.5*vec[j];
}
j += nstride;
}
}
if (fix) {
double one;
for (int i = 0; i < nvec; i++) {
if (index) one = fix->compute_array(i,index-1);
else one = fix->compute_vector(i);
if (method == SUM) value += one;
else if (method == XMIN) value = MIN(value,one);
else if (method == XMAX) value = MAX(value,one);
else if (method == AVE) value += one;
else if (method == TRAP) {
if (i > 0 && i < nvec-1) value += one;
else value += 0.5*one;
}
}
}
if (method == AVE) value /= nvec;
// save value in tree or on argstack
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value;
// mask special functions
} else if (strcmp(word,"gmask") == 0) {
if (tree == NULL)
error->all(FLERR,"Gmask function in equal-style variable formula");
if (narg != 1)
error->all(FLERR,"Invalid special function in variable formula");
int igroup = group->find(arg1);
if (igroup == -1)
error->all(FLERR,"Group ID in variable formula does not exist");
Tree *newtree = new Tree();
newtree->type = GMASK;
newtree->ivalue1 = group->bitmask[igroup];
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else if (strcmp(word,"rmask") == 0) {
if (tree == NULL)
error->all(FLERR,"Rmask function in equal-style variable formula");
if (narg != 1)
error->all(FLERR,"Invalid special function in variable formula");
int iregion = region_function(arg1);
Tree *newtree = new Tree();
newtree->type = RMASK;
newtree->ivalue1 = iregion;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else if (strcmp(word,"grmask") == 0) {
if (tree == NULL)
error->all(FLERR,"Grmask function in equal-style variable formula");
if (narg != 2)
error->all(FLERR,"Invalid special function in variable formula");
int igroup = group->find(arg1);
if (igroup == -1)
error->all(FLERR,"Group ID in variable formula does not exist");
int iregion = region_function(arg2);
Tree *newtree = new Tree();
newtree->type = GRMASK;
newtree->ivalue1 = group->bitmask[igroup];
newtree->ivalue2 = iregion;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
// check if a variable is defined
} else if (strcmp(word,"isdef") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid special function isdef in variable formula");
if (find(arg1) == -1)
argstack[nargstack++] = 0.0;
else
argstack[nargstack++] = 1.0;
// special function for file-style or atomfile-style variables
} else if (strcmp(word,"next") == 0) {
if (narg != 1)
error->all(FLERR,"Invalid special function in variable formula");
int ivar = find(arg1);
if (ivar == -1)
error->all(FLERR,"Variable ID in variable formula does not exist");
// SCALARFILE has single current value, read next one
// save value in tree or on argstack
if (style[ivar] == SCALARFILE) {
double value = atof(data[ivar][0]);
int done = reader[ivar]->read_scalar(data[ivar][0]);
if (done) remove(ivar);
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value;
// ATOMFILE has per-atom values, save values in tree
// copy current per-atom values into result so can read next ones
// set selfalloc = 1 so result will be deleted by free_tree() after eval
} else if (style[ivar] == ATOMFILE) {
if (tree == NULL)
error->all(FLERR,"Atomfile variable in equal-style variable formula");
double *result;
memory->create(result,atom->nlocal,"variable:result");
memcpy(result,reader[ivar]->fix->vstore,atom->nlocal*sizeof(double));
int done = reader[ivar]->read_peratom();
if (done) remove(ivar);
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
newtree->array = result;
newtree->nstride = 1;
newtree->selfalloc = 1;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else error->all(FLERR,"Invalid variable style in special function next");
}
delete [] arg1;
delete [] arg2;
delete [] arg3;
return 1;
}
/* ----------------------------------------------------------------------
extract a global value from a per-atom quantity in a formula
flag = 0 -> word is an atom vector
flag = 1 -> vector is a per-atom compute or fix quantity with nstride
id = positive global ID of atom, converted to local index
push result onto tree or arg stack
customize by adding an atom vector:
id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz
------------------------------------------------------------------------- */
void Variable::peratom2global(int flag, char *word,
double *vector, int nstride, int id,
Tree **tree, Tree **treestack, int &ntreestack,
double *argstack, int &nargstack)
{
if (atom->map_style == 0)
error->all(FLERR,
"Indexed per-atom vector in variable formula without atom map");
int index = atom->map(id);
double mine;
if (index >= 0 && index < atom->nlocal) {
if (flag == 0) {
if (strcmp(word,"id") == 0) mine = atom->tag[index];
else if (strcmp(word,"mass") == 0) {
if (atom->rmass) mine = atom->rmass[index];
else mine = atom->mass[atom->type[index]];
}
else if (strcmp(word,"type") == 0) mine = atom->type[index];
else if (strcmp(word,"mol") == 0) {
if (!atom->molecule_flag)
error->one(FLERR,"Variable uses atom property that isn't allocated");
mine = atom->molecule[index];
}
else if (strcmp(word,"x") == 0) mine = atom->x[index][0];
else if (strcmp(word,"y") == 0) mine = atom->x[index][1];
else if (strcmp(word,"z") == 0) mine = atom->x[index][2];
else if (strcmp(word,"vx") == 0) mine = atom->v[index][0];
else if (strcmp(word,"vy") == 0) mine = atom->v[index][1];
else if (strcmp(word,"vz") == 0) mine = atom->v[index][2];
else if (strcmp(word,"fx") == 0) mine = atom->f[index][0];
else if (strcmp(word,"fy") == 0) mine = atom->f[index][1];
else if (strcmp(word,"fz") == 0) mine = atom->f[index][2];
else error->one(FLERR,"Invalid atom vector in variable formula");
} else mine = vector[index*nstride];
} else mine = 0.0;
double value;
MPI_Allreduce(&mine,&value,1,MPI_DOUBLE,MPI_SUM,world);
if (tree) {
Tree *newtree = new Tree();
newtree->type = VALUE;
newtree->value = value;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
} else argstack[nargstack++] = value;
}
/* ----------------------------------------------------------------------
check if word matches an atom vector
return 1 if yes, else 0
customize by adding an atom vector:
id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz
------------------------------------------------------------------------- */
int Variable::is_atom_vector(char *word)
{
if (strcmp(word,"id") == 0) return 1;
if (strcmp(word,"mass") == 0) return 1;
if (strcmp(word,"type") == 0) return 1;
if (strcmp(word,"mol") == 0) return 1;
if (strcmp(word,"x") == 0) return 1;
if (strcmp(word,"y") == 0) return 1;
if (strcmp(word,"z") == 0) return 1;
if (strcmp(word,"vx") == 0) return 1;
if (strcmp(word,"vy") == 0) return 1;
if (strcmp(word,"vz") == 0) return 1;
if (strcmp(word,"fx") == 0) return 1;
if (strcmp(word,"fy") == 0) return 1;
if (strcmp(word,"fz") == 0) return 1;
return 0;
}
/* ----------------------------------------------------------------------
process an atom vector in formula
push result onto tree
word = atom vector
customize by adding an atom vector:
id,mass,type,mol,x,y,z,vx,vy,vz,fx,fy,fz
------------------------------------------------------------------------- */
void Variable::atom_vector(char *word, Tree **tree,
Tree **treestack, int &ntreestack)
{
if (tree == NULL)
error->all(FLERR,"Atom vector in equal-style variable formula");
Tree *newtree = new Tree();
newtree->type = ATOMARRAY;
newtree->nstride = 3;
newtree->selfalloc = 0;
newtree->left = newtree->middle = newtree->right = NULL;
treestack[ntreestack++] = newtree;
if (strcmp(word,"id") == 0) {
- newtree->type = INTARRAY;
+ if (sizeof(tagint) == sizeof(smallint)) {
+ newtree->type = INTARRAY;
+ newtree->iarray = (int *) atom->tag;
+ } else {
+ newtree->type = BIGINTARRAY;
+ newtree->barray = (bigint *) atom->tag;
+ }
newtree->nstride = 1;
- newtree->iarray = atom->tag;
} else if (strcmp(word,"mass") == 0) {
if (atom->rmass) {
newtree->nstride = 1;
newtree->array = atom->rmass;
} else {
newtree->type = TYPEARRAY;
newtree->array = atom->mass;
}
} else if (strcmp(word,"type") == 0) {
newtree->type = INTARRAY;
newtree->nstride = 1;
newtree->iarray = atom->type;
} else if (strcmp(word,"mol") == 0) {
if (!atom->molecule_flag)
error->one(FLERR,"Variable uses atom property that isn't allocated");
newtree->type = INTARRAY;
newtree->nstride = 1;
newtree->iarray = atom->molecule;
}
else if (strcmp(word,"x") == 0) newtree->array = &atom->x[0][0];
else if (strcmp(word,"y") == 0) newtree->array = &atom->x[0][1];
else if (strcmp(word,"z") == 0) newtree->array = &atom->x[0][2];
else if (strcmp(word,"vx") == 0) newtree->array = &atom->v[0][0];
else if (strcmp(word,"vy") == 0) newtree->array = &atom->v[0][1];
else if (strcmp(word,"vz") == 0) newtree->array = &atom->v[0][2];
else if (strcmp(word,"fx") == 0) newtree->array = &atom->f[0][0];
else if (strcmp(word,"fy") == 0) newtree->array = &atom->f[0][1];
else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2];
}
/* ----------------------------------------------------------------------
check if word matches a constant
return 1 if yes, else 0
customize by adding a constant: PI
------------------------------------------------------------------------- */
int Variable::is_constant(char *word)
{
if (strcmp(word,"PI") == 0) return 1;
return 0;
}
/* ----------------------------------------------------------------------
process a constant in formula
customize by adding a constant: PI
------------------------------------------------------------------------- */
double Variable::constant(char *word)
{
if (strcmp(word,"PI") == 0) return MY_PI;
return 0.0;
}
/* ----------------------------------------------------------------------
read a floating point value from a string
generate an error if not a legitimate floating point value
------------------------------------------------------------------------- */
double Variable::numeric(char *str)
{
int n = strlen(str);
for (int i = 0; i < n; i++) {
if (isdigit(str[i])) continue;
if (str[i] == '-' || str[i] == '+' || str[i] == '.') continue;
if (str[i] == 'e' || str[i] == 'E') continue;
error->all(FLERR,
"Expected floating point parameter in variable definition");
}
return atof(str);
}
/* ----------------------------------------------------------------------
read an integer value from a string
generate an error if not a legitimate integer value
------------------------------------------------------------------------- */
int Variable::inumeric(char *str)
{
int n = strlen(str);
for (int i = 0; i < n; i++) {
if (isdigit(str[i]) || str[i] == '-' || str[i] == '+') continue;
error->all(FLERR,"Expected integer parameter in variable definition");
}
return atoi(str);
}
/* ----------------------------------------------------------------------
find next comma in str
skip commas inside one or more nested parenthesis
only return ptr to comma at level 0, else NULL if not found
------------------------------------------------------------------------- */
char *Variable::find_next_comma(char *str)
{
int level = 0;
for (char *p = str; *p; ++p) {
if ('(' == *p) level++;
else if (')' == *p) level--;
else if (',' == *p && !level) return p;
}
return NULL;
}
/* ----------------------------------------------------------------------
debug routine for printing formula tree recursively
------------------------------------------------------------------------- */
void Variable::print_tree(Tree *tree, int level)
{
printf("TREE %d: %d %g\n",level,tree->type,tree->value);
if (tree->left) print_tree(tree->left,level+1);
if (tree->middle) print_tree(tree->middle,level+1);
if (tree->right) print_tree(tree->right,level+1);
return;
}
/* ----------------------------------------------------------------------
recursive evaluation of string str
called from "if" command in input script
str is a boolean expression containing one or more items:
number = 0.0, -5.45, 2.8e-4, ...
math operation = (),x==y,x!=y,x<y,x<=y,x>y,x>=y,x&&y,x||y
------------------------------------------------------------------------- */
double Variable::evaluate_boolean(char *str)
{
int op,opprevious;
double value1,value2;
char onechar;
double argstack[MAXLEVEL];
int opstack[MAXLEVEL];
int nargstack = 0;
int nopstack = 0;
int i = 0;
int expect = ARG;
while (1) {
onechar = str[i];
// whitespace: just skip
if (isspace(onechar)) i++;
// ----------------
// parentheses: recursively evaluate contents of parens
// ----------------
else if (onechar == '(') {
if (expect == OP)
error->all(FLERR,"Invalid Boolean syntax in if command");
expect = OP;
char *contents;
i = find_matching_paren(str,i,contents);
i++;
// evaluate contents and push on stack
argstack[nargstack++] = evaluate_boolean(contents);
delete [] contents;
// ----------------
// number: push value onto stack
// ----------------
} else if (isdigit(onechar) || onechar == '.' || onechar == '-') {
if (expect == OP)
error->all(FLERR,"Invalid Boolean syntax in if command");
expect = OP;
// istop = end of number, including scientific notation
int istart = i++;
while (isdigit(str[i]) || str[i] == '.') i++;
if (str[i] == 'e' || str[i] == 'E') {
i++;
if (str[i] == '+' || str[i] == '-') i++;
while (isdigit(str[i])) i++;
}
int istop = i - 1;
int n = istop - istart + 1;
char *number = new char[n+1];
strncpy(number,&str[istart],n);
number[n] = '\0';
argstack[nargstack++] = atof(number);
delete [] number;
// ----------------
// Boolean operator, including end-of-string
// ----------------
} else if (strchr("<>=!&|\0",onechar)) {
if (onechar == '=') {
if (str[i+1] != '=')
error->all(FLERR,"Invalid Boolean syntax in if command");
op = EQ;
i++;
} else if (onechar == '!') {
if (str[i+1] == '=') {
op = NE;
i++;
} else op = NOT;
} else if (onechar == '<') {
if (str[i+1] != '=') op = LT;
else {
op = LE;
i++;
}
} else if (onechar == '>') {
if (str[i+1] != '=') op = GT;
else {
op = GE;
i++;
}
} else if (onechar == '&') {
if (str[i+1] != '&')
error->all(FLERR,"Invalid Boolean syntax in if command");
op = AND;
i++;
} else if (onechar == '|') {
if (str[i+1] != '|')
error->all(FLERR,"Invalid Boolean syntax in if command");
op = OR;
i++;
} else op = DONE;
i++;
if (op == NOT && expect == ARG) {
opstack[nopstack++] = op;
continue;
}
if (expect == ARG)
error->all(FLERR,"Invalid Boolean syntax in if command");
expect = ARG;
// evaluate stack as deep as possible while respecting precedence
// before pushing current op onto stack
while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) {
opprevious = opstack[--nopstack];
value2 = argstack[--nargstack];
if (opprevious != NOT) value1 = argstack[--nargstack];
if (opprevious == NOT) {
if (value2 == 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == EQ) {
if (value1 == value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == NE) {
if (value1 != value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LT) {
if (value1 < value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LE) {
if (value1 <= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GT) {
if (value1 > value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GE) {
if (value1 >= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == AND) {
if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == OR) {
if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
}
}
// if end-of-string, break out of entire formula evaluation loop
if (op == DONE) break;
// push current operation onto stack
opstack[nopstack++] = op;
} else error->all(FLERR,"Invalid Boolean syntax in if command");
}
if (nopstack) error->all(FLERR,"Invalid Boolean syntax in if command");
if (nargstack != 1) error->all(FLERR,"Invalid Boolean syntax in if command");
return argstack[0];
}
/* ---------------------------------------------------------------------- */
unsigned int Variable::data_mask(int ivar)
{
if (eval_in_progress[ivar]) return EMPTY_MASK;
eval_in_progress[ivar] = 1;
unsigned int datamask = data_mask(data[ivar][0]);
eval_in_progress[ivar] = 0;
return datamask;
}
/* ---------------------------------------------------------------------- */
unsigned int Variable::data_mask(char *str)
{
unsigned int datamask = EMPTY_MASK;
for (unsigned int i=0; i < strlen(str)-2; i++) {
int istart = i;
while (isalnum(str[i]) || str[i] == '_') i++;
int istop = i-1;
int n = istop - istart + 1;
char *word = new char[n+1];
strncpy(word,&str[istart],n);
word[n] = '\0';
// ----------------
// compute
// ----------------
if ((strncmp(word,"c_",2) == 0) && (i>0) && (!isalnum(str[i-1]))) {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
n = strlen(word) - 2 + 1;
char *id = new char[n];
strcpy(id,&word[2]);
int icompute = modify->find_compute(id);
if (icompute < 0)
error->all(FLERR,"Invalid compute ID in variable formula");
datamask &= modify->compute[icompute]->data_mask();
delete [] id;
}
if ((strncmp(word,"f_",2) == 0) && (i>0) && (!isalnum(str[i-1]))) {
if (domain->box_exist == 0)
error->all(FLERR,
"Variable evaluation before simulation box is defined");
n = strlen(word) - 2 + 1;
char *id = new char[n];
strcpy(id,&word[2]);
int ifix = modify->find_fix(id);
if (ifix < 0) error->all(FLERR,"Invalid fix ID in variable formula");
datamask &= modify->fix[ifix]->data_mask();
delete [] id;
}
if ((strncmp(word,"v_",2) == 0) && (i>0) && (!isalnum(str[i-1]))) {
int ivar = find(word);
datamask &= data_mask(ivar);
}
delete [] word;
}
return datamask;
}
/* ----------------------------------------------------------------------
class to read variable values from a file
for flag = SCALARFILE, reads one value per line
for flag = ATOMFILE, reads set of one value per atom
------------------------------------------------------------------------- */
VarReader::VarReader(LAMMPS *lmp, char *name, char *file, int flag) :
Pointers(lmp)
{
me = comm->me;
style = flag;
if (me == 0) {
fp = fopen(file,"r");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open file variable file %s",file);
error->one(FLERR,str);
}
} else fp = NULL;
// if atomfile-style variable, must store per-atom values read from file
// allocate a new fix STORE, so they persist
// id = variable-ID + VARIABLE_STORE, fix group = all
fix = NULL;
id_fix = NULL;
buffer = NULL;
if (style == ATOMFILE) {
if (atom->map_style == 0)
error->all(FLERR,
"Cannot use atomfile-style variable unless atom map exists");
int n = strlen(name) + strlen("_VARIABLE_STORE") + 1;
id_fix = new char[n];
strcpy(id_fix,name);
strcat(id_fix,"_VARIABLE_STORE");
char **newarg = new char*[5];
newarg[0] = id_fix;
newarg[1] = (char *) "all";
newarg[2] = (char *) "STORE";
newarg[3] = (char *) "0";
newarg[4] = (char *) "1";
modify->add_fix(5,newarg);
fix = (FixStore *) modify->fix[modify->nfix-1];
delete [] newarg;
buffer = new char[CHUNK*MAXLINE];
}
}
/* ---------------------------------------------------------------------- */
VarReader::~VarReader()
{
if (me == 0) fclose(fp);
// check modify in case all fixes have already been deleted
if (fix) {
if (modify) modify->delete_fix(id_fix);
delete [] id_fix;
delete [] buffer;
}
}
/* ----------------------------------------------------------------------
read for SCALARFILE style
read next value from file into str for file-style variable
strip comments, skip blank lines
return 0 if successful, 1 if end-of-file
------------------------------------------------------------------------- */
int VarReader::read_scalar(char *str)
{
int n;
char *ptr;
// read one string from file
if (me == 0) {
while (1) {
if (fgets(str,MAXLINE,fp) == NULL) n = 0;
else n = strlen(str);
if (n == 0) break; // end of file
str[n-1] = '\0'; // strip newline
if (ptr = strchr(str,'#')) *ptr = '\0'; // strip comment
if (strtok(str," \t\n\r\f") == NULL) continue; // skip if blank
n = strlen(str) + 1;
break;
}
}
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) return 1;
MPI_Bcast(str,n,MPI_CHAR,0,world);
return 0;
}
/* ----------------------------------------------------------------------
read snapshot of per-atom values from file
into str for atomfile-style variable
return 0 if successful, 1 if end-of-file
------------------------------------------------------------------------- */
int VarReader::read_peratom()
{
- int i,m,n,tagdata,nchunk,eof;
+ int i,m,n,nchunk,eof;
+ tagint tag;
char *ptr,*next;
double value;
// set all per-atom values to 0.0
// values that appear in file will overwrite this
double *vstore = fix->vstore;
int nlocal = atom->nlocal;
for (i = 0; i < nlocal; i++) vstore[i] = 0.0;
// read one string from file, convert to Nlines
char str[MAXLINE];
if (me == 0) {
while (1) {
if (fgets(str,MAXLINE,fp) == NULL) n = 0;
else n = strlen(str);
if (n == 0) break; // end of file
str[n-1] = '\0'; // strip newline
if (ptr = strchr(str,'#')) *ptr = '\0'; // strip comment
if (strtok(str," \t\n\r\f") == NULL) continue; // skip if blank
n = strlen(str) + 1;
break;
}
}
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n == 0) return 1;
MPI_Bcast(str,n,MPI_CHAR,0,world);
bigint nlines = ATOBIGINT(str);
- int map_tag_max = atom->map_tag_max;
+ tagint map_tag_max = atom->map_tag_max;
bigint nread = 0;
while (nread < nlines) {
nchunk = MIN(nlines-nread,CHUNK);
eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer);
if (eof) return 1;
char *buf = buffer;
for (i = 0; i < nchunk; i++) {
next = strchr(buf,'\n');
*next = '\0';
- sscanf(buf,"%d %lg",&tagdata,&value);
- if (tagdata <= 0 || tagdata > map_tag_max)
+ sscanf(buf,TAGINT_FORMAT " %lg",&tag,&value);
+ if (tag <= 0 || tag > map_tag_max)
error->one(FLERR,"Invalid atom ID in variable file");
- if ((m = atom->map(tagdata)) >= 0) vstore[m] = value;
+ if ((m = atom->map(tag)) >= 0) vstore[m] = value;
buf = next + 1;
}
nread += nchunk;
}
return 0;
}
diff --git a/src/variable.h b/src/variable.h
index 6b13bbdc9..83bac4828 100644
--- a/src/variable.h
+++ b/src/variable.h
@@ -1,400 +1,401 @@
/* -*- 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.
------------------------------------------------------------------------- */
#ifndef LMP_VARIABLE_H
#define LMP_VARIABLE_H
#include "stdlib.h"
#include "pointers.h"
namespace LAMMPS_NS {
class Variable : protected Pointers {
public:
Variable(class LAMMPS *);
~Variable();
void set(int, char **);
void set(char *, int, char **);
int next(int, char **);
int find(char *);
int equalstyle(int);
int atomstyle(int);
char *retrieve(char *);
double compute_equal(int);
double compute_equal(char *);
void compute_atom(int, int, double *, int, int);
int int_between_brackets(char *&);
double evaluate_boolean(char *);
unsigned int data_mask(int ivar);
unsigned int data_mask(char *str);
private:
int nvar; // # of defined variables
int maxvar; // max # of variables following lists can hold
char **names; // name of each variable
int *style; // style of each variable
int *num; // # of values for each variable
int *which; // next available value for each variable
int *pad; // 1 = pad loop/uloop variables with 0s, 0 = no pad
class VarReader **reader; // variable that reads from file
char ***data; // str value of each variable's values
int *eval_in_progress; // flag if evaluation of variable is in progress
class RanMars *randomequal; // random number generator for equal-style vars
class RanMars *randomatom; // random number generator for atom-style vars
int precedence[17]; // precedence level of math operators
// set length to include up to OR in enum
int me;
struct Tree { // parse tree for atom-style variables
double value; // single scalar
double *array; // per-atom or per-type list of doubles
int *iarray; // per-atom list of ints
+ bigint *barray; // per-atom list of bigints
int type; // operation, see enum{} in variable.cpp
int nstride; // stride between atoms if array is a 2d array
int selfalloc; // 1 if array is allocated here, else 0
int ivalue1,ivalue2; // extra values for needed for gmask,rmask,grmask
Tree *left,*middle,*right; // ptrs further down tree
};
void remove(int);
void grow();
void copy(int, char **, char **);
double evaluate(char *, Tree **);
double collapse_tree(Tree *);
double eval_tree(Tree *, int);
void free_tree(Tree *);
int find_matching_paren(char *, int, char *&);
int math_function(char *, char *, Tree **, Tree **, int &, double *, int &);
int group_function(char *, char *, Tree **, Tree **, int &, double *, int &);
int region_function(char *);
int special_function(char *, char *, Tree **, Tree **,
int &, double *, int &);
void peratom2global(int, char *, double *, int, int,
Tree **, Tree **, int &, double *, int &);
int is_atom_vector(char *);
void atom_vector(char *, Tree **, Tree **, int &);
int is_constant(char *);
double constant(char *);
double numeric(char *);
int inumeric(char *);
char *find_next_comma(char *);
void print_tree(Tree *, int);
};
class VarReader : protected Pointers {
public:
class FixStore *fix;
char *id_fix;
VarReader(class LAMMPS *, char *, char *, int);
~VarReader();
int read_scalar(char *);
int read_peratom();
private:
int me,style;
FILE *fp;
char *buffer;
};
}
#endif
/* ERROR/WARNING messages:
E: Illegal ... command
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.
E: World variable count doesn't match # of partitions
A world-style variable must specify a number of values equal to the
number of processor partitions.
E: Universe/uloop variable count < # of partitions
A universe or uloop style variable must specify a number of values >= to the
number of processor partitions.
E: All universe/uloop variables must have same # of values
Self-explanatory.
E: Cannot redefine variable as a different style
An equal-style variable can be re-defined but only if it was
originally an equal-style variable.
E: File variable could not read value
Check the file assigned to the variable.
E: Afile variable could not read values
UNDOCUMENTED
E: Variable name must be alphanumeric or underscore characters
Self-explanatory.
E: Invalid variable in next command
Self-explanatory.
E: All variables in next command must be same style
Self-explanatory.
E: Invalid variable style with next command
Variable styles {equal} and {world} cannot be used in a next
command.
E: Invalid syntax in variable formula
Self-explanatory.
E: Variable evaluation before simulation box is defined
Cannot evaluate a compute or fix or atom-based value in a variable
before the simulation has been setup.
E: Invalid compute ID in variable formula
The compute is not recognized.
E: Compute used in variable between runs is not current
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.
E: Variable formula compute vector is accessed out-of-range
Self-explanatory.
E: Variable formula compute array is accessed out-of-range
Self-explanatory.
E: Per-atom compute in equal-style variable formula
Equal-style variables cannot use per-atom quantities.
E: Mismatched compute in variable formula
A compute is referenced incorrectly or a compute that produces per-atom
values is used in an equal-style variable formula.
E: Invalid fix ID in variable formula
The fix is not recognized.
E: Fix in variable not computed at compatible time
Fixes generate their values on specific timesteps. The variable is
requesting the values on a non-allowed timestep.
E: Variable formula fix vector is accessed out-of-range
Self-explanatory.
E: Variable formula fix array is accessed out-of-range
Self-explanatory.
E: Per-atom fix in equal-style variable formula
Equal-style variables cannot use per-atom quantities.
E: Mismatched fix in variable formula
A fix is referenced incorrectly or a fix that produces per-atom
values is used in an equal-style variable formula.
E: Invalid variable name in variable formula
Variable name is not recognized.
E: Variable has circular dependency
A circular dependency is when variable "a" in used by variable "b" and
variable "b" is also used by varaible "a". Circular dependencies with
longer chains of dependence are also not allowed.
E: Invalid variable evaluation in variable formula
A variable used in a formula could not be evaluated.
E: Atom-style variable in equal-style variable formula
Atom-style variables generate one value per atom which is not allowed
in an equal-style variable.
E: Mismatched variable in variable formula
A variable is referenced incorrectly or an atom-style variable that
produces per-atom values is used in an equal-style variable
formula.
E: Invalid math/group/special function in variable formula
Self-explanatory.
E: Invalid thermo keyword in variable formula
The keyword is not recognized.
E: Divide by 0 in variable formula
Self-explanatory.
E: Modulo 0 in variable formula
Self-explanatory.
E: Power by 0 in variable formula
Self-explanatory.
E: Sqrt of negative value in variable formula
Self-explanatory.
E: Log of zero/negative value in variable formula
Self-explanatory.
E: Arcsin of invalid value in variable formula
Argument of arcsin() must be between -1 and 1.
E: Arccos of invalid value in variable formula
Argument of arccos() must be between -1 and 1.
E: Invalid math function in variable formula
Self-explanatory.
E: Non digit character between brackets in variable
Self-explantory.
E: Mismatched brackets in variable
Self-explanatory.
E: Empty brackets in variable
There is no variable syntax that uses empty brackets. Check
the variable doc page.
E: Index between variable brackets must be positive
Self-explanatory.
E: Cannot use ramp in variable formula between runs
This is because the ramp() function is time dependent.
E: Cannot use vdisplace in variable formula between runs
This is a function of elapsed time.
E: Cannot use swiggle in variable formula between runs
This is a function of elapsed time.
E: Cannot use cwiggle in variable formula between runs
This is a function of elapsed time.
E: Group ID in variable formula does not exist
Self-explanatory.
E: Invalid group function in variable formula
Group function is not recognized.
E: Region ID in variable formula does not exist
Self-explanatory.
E: Invalid special function in variable formula
Self-explanatory.
E: Gmask function in equal-style variable formula
Gmask is per-atom operation.
E: Rmask function in equal-style variable formula
Rmask is per-atom operation.
E: Grmask function in equal-style variable formula
Grmask is per-atom operation.
E: Variable ID in variable formula does not exist
Self-explanatory.
E: Invalid variable in special function next
Only file-style variables can be used with the next() function.
E: Indexed per-atom vector in variable formula without atom map
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.
E: Invalid atom vector in variable formula
The atom vector is not recognized.
E: Atom vector in equal-style variable formula
Atom vectors generate one value per atom which is not allowed
in an equal-style variable.
E: Expected floating point parameter in variable definition
The quantity being read is a non-numeric value.
E: Expected integer parameter in variable definition
The quantity being read is a floating point or non-numeric value.
E: Invalid Boolean syntax in if command
Self-explanatory.
E: Cannot open file variable file %s
The specified file cannot be opened. Check that the path and name are
correct.
*/
diff --git a/src/velocity.cpp b/src/velocity.cpp
index 1d44bcaf5..f27aa5705 100644
--- a/src/velocity.cpp
+++ b/src/velocity.cpp
@@ -1,823 +1,822 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "velocity.h"
#include "atom.h"
#include "update.h"
#include "domain.h"
#include "lattice.h"
#include "input.h"
#include "variable.h"
#include "force.h"
#include "modify.h"
#include "fix.h"
#include "compute.h"
#include "compute_temp.h"
#include "random_park.h"
#include "group.h"
#include "comm.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{CREATE,SET,SCALE,RAMP,ZERO};
enum{ALL,LOCAL,GEOM};
enum{NONE,CONSTANT,EQUAL,ATOM};
#define WARMUP 100
#define SMALL 0.001
/* ---------------------------------------------------------------------- */
Velocity::Velocity(LAMMPS *lmp) : Pointers(lmp) {}
/* ---------------------------------------------------------------------- */
void Velocity::command(int narg, char **arg)
{
if (narg < 2) error->all(FLERR,"Illegal velocity command");
if (domain->box_exist == 0)
error->all(FLERR,"Velocity command before simulation box is defined");
if (atom->natoms == 0)
error->all(FLERR,"Velocity command with no atoms existing");
// atom masses must all be set
atom->check_mass();
// identify group
igroup = group->find(arg[0]);
if (igroup == -1) error->all(FLERR,"Could not find velocity group ID");
groupbit = group->bitmask[igroup];
// identify style
if (strcmp(arg[1],"create") == 0) style = CREATE;
else if (strcmp(arg[1],"set") == 0) style = SET;
else if (strcmp(arg[1],"scale") == 0) style = SCALE;
else if (strcmp(arg[1],"ramp") == 0) style = RAMP;
else if (strcmp(arg[1],"zero") == 0) style = ZERO;
else error->all(FLERR,"Illegal velocity command");
// set defaults
temperature = NULL;
dist_flag = 0;
sum_flag = 0;
momentum_flag = 1;
rotation_flag = 0;
loop_flag = ALL;
scale_flag = 1;
rfix = -1;
// read options from end of input line
// change defaults as options specify
if (style == CREATE) options(narg-4,&arg[4]);
else if (style == SET) options(narg-5,&arg[5]);
else if (style == SCALE) options(narg-3,&arg[3]);
else if (style == RAMP) options(narg-8,&arg[8]);
else if (style == ZERO) options(narg-3,&arg[3]);
// initialize velocities based on style
// create() invoked differently, so can be called externally
if (style == CREATE) {
double t_desired = force->numeric(FLERR,arg[2]);
int seed = force->inumeric(FLERR,arg[3]);
create(t_desired,seed);
}
else if (style == SET) set(narg-2,&arg[2]);
else if (style == SCALE) scale(narg-2,&arg[2]);
else if (style == RAMP) ramp(narg-2,&arg[2]);
else if (style == ZERO) zero(narg-2,&arg[2]);
}
/* ----------------------------------------------------------------------
initialization of defaults before calling velocity methods externaly
------------------------------------------------------------------------- */
void Velocity::init_external(const char *extgroup)
{
igroup = group->find(extgroup);
if (igroup == -1) error->all(FLERR,"Could not find velocity group ID");
groupbit = group->bitmask[igroup];
temperature = NULL;
dist_flag = 0;
sum_flag = 0;
momentum_flag = 1;
rotation_flag = 0;
loop_flag = ALL;
scale_flag = 1;
}
/* ---------------------------------------------------------------------- */
void Velocity::create(double t_desired, int seed)
{
int i;
if (seed <= 0) error->all(FLERR,"Illegal velocity create command");
// if temperature = NULL, create a new ComputeTemp with the velocity group
int tflag = 0;
if (temperature == NULL) {
char **arg = new char*[3];
arg[0] = (char *) "velocity_temp";
arg[1] = group->names[igroup];
arg[2] = (char *) "temp";
temperature = new ComputeTemp(lmp,3,arg);
tflag = 1;
delete [] arg;
}
// initialize temperature computation
// warn if groups don't match
if (igroup != temperature->igroup && comm->me == 0)
error->warning(FLERR,"Mismatch between velocity and compute groups");
temperature->init();
temperature->setup();
// store a copy of current velocities
double **v = atom->v;
int nlocal = atom->nlocal;
double **vhold;
memory->create(vhold,nlocal,3,"velocity:vnew");
for (i = 0; i < nlocal; i++) {
vhold[i][0] = v[i][0];
vhold[i][1] = v[i][1];
vhold[i][2] = v[i][2];
}
// create new velocities, in uniform or gaussian distribution
// loop option determines looping style, ALL is default
// ALL = loop over all natoms, only set those I own via atom->map
// cannot do this if atom IDs do not span 1-Natoms (some were deleted)
// will produce same V, independent of P, if atoms were read-in
// will NOT produce same V, independent of P, if used create_atoms
// LOCAL = only loop over my atoms, adjust RNG to be proc-specific
// will never produce same V, independent of P
// GEOM = only loop over my atoms
// choose RNG for each atom based on its xyz coord (geometry)
// via random->reset()
// will always produce same V, independent of P
// adjust by factor for atom mass
// for 2d, set Vz to 0.0
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int dimension = domain->dimension;
int m;
double vx,vy,vz,factor;
RanPark *random;
if (loop_flag == ALL) {
// create an atom map if one doesn't exist already
int mapflag = 0;
if (atom->map_style == 0) {
mapflag = 1;
- atom->map_style = 1;
atom->nghost = 0;
atom->map_init();
atom->map_set();
}
// error check
if (atom->natoms > MAXSMALLINT)
error->all(FLERR,"Too big a problem to use velocity create loop all");
if (atom->tag_enable == 0)
error->all(FLERR,
"Cannot use velocity create loop all unless atoms have IDs");
if (atom->tag_consecutive() == 0)
error->all(FLERR,
"Atom IDs must be consecutive for velocity create loop all");
// loop over all atoms in system
// generate RNGs for all atoms, only assign to ones I own
// use either per-type mass or per-atom rmass
random = new RanPark(lmp,seed);
int natoms = static_cast<int> (atom->natoms);
for (i = 1; i <= natoms; i++) {
if (dist_flag == 0) {
vx = random->uniform();
vy = random->uniform();
vz = random->uniform();
} else {
vx = random->gaussian();
vy = random->gaussian();
vz = random->gaussian();
}
m = atom->map(i);
if (m >= 0 && m < nlocal) {
if (mask[m] & groupbit) {
if (rmass) factor = 1.0/sqrt(rmass[m]);
else factor = 1.0/sqrt(mass[type[m]]);
v[m][0] = vx * factor;
v[m][1] = vy * factor;
if (dimension == 3) v[m][2] = vz * factor;
else v[m][2] = 0.0;
}
}
}
// delete temporary atom map
if (mapflag) {
atom->map_delete();
atom->map_style = 0;
}
} else if (loop_flag == LOCAL) {
random = new RanPark(lmp,seed + comm->me);
for (i = 0; i < WARMUP; i++) random->uniform();
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
if (dist_flag == 0) {
vx = random->uniform();
vy = random->uniform();
vz = random->uniform();
} else {
vx = random->gaussian();
vy = random->gaussian();
vz = random->gaussian();
}
if (rmass) factor = 1.0/sqrt(rmass[i]);
else factor = 1.0/sqrt(mass[type[i]]);
v[i][0] = vx * factor;
v[i][1] = vy * factor;
if (dimension == 3) v[i][2] = vz * factor;
else v[i][2] = 0.0;
}
}
} else if (loop_flag == GEOM) {
random = new RanPark(lmp,1);
double **x = atom->x;
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
random->reset(seed,x[i]);
if (dist_flag == 0) {
vx = random->uniform();
vy = random->uniform();
vz = random->uniform();
} else {
vx = random->gaussian();
vy = random->gaussian();
vz = random->gaussian();
}
if (rmass) factor = 1.0/sqrt(rmass[i]);
else factor = 1.0/sqrt(mass[type[i]]);
v[i][0] = vx * factor;
v[i][1] = vy * factor;
if (dimension == 3) v[i][2] = vz * factor;
else v[i][2] = 0.0;
}
}
}
// apply momentum and rotation zeroing
if (momentum_flag) zero_momentum();
if (rotation_flag) zero_rotation();
// scale temp to desired value
double t = temperature->compute_scalar();
rescale(t,t_desired);
// if sum_flag set, add back in previous velocities
if (sum_flag) {
for (i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
v[i][0] += vhold[i][0];
v[i][1] += vhold[i][1];
v[i][2] += vhold[i][2];
}
}
}
// free local memory
// if temperature was created, delete it
memory->destroy(vhold);
delete random;
if (tflag) delete temperature;
}
/* ---------------------------------------------------------------------- */
void Velocity::set(int narg, char **arg)
{
int xstyle,ystyle,zstyle,varflag;
double vx,vy,vz;
char *xstr,*ystr,*zstr;
int xvar,yvar,zvar;
// parse 3 args
xstyle = ystyle = zstyle = CONSTANT;
xstr = ystr = zstr = NULL;
if (strstr(arg[0],"v_") == arg[0]) {
int n = strlen(&arg[0][2]) + 1;
xstr = new char[n];
strcpy(xstr,&arg[0][2]);
} else if (strcmp(arg[0],"NULL") == 0) xstyle = NONE;
else vx = force->numeric(FLERR,arg[0]);
if (strstr(arg[1],"v_") == arg[1]) {
int n = strlen(&arg[1][2]) + 1;
ystr = new char[n];
strcpy(ystr,&arg[1][2]);
} else if (strcmp(arg[1],"NULL") == 0) ystyle = NONE;
else vy = force->numeric(FLERR,arg[1]);
if (strstr(arg[2],"v_") == arg[2]) {
int n = strlen(&arg[2][2]) + 1;
zstr = new char[n];
strcpy(zstr,&arg[2][2]);
} else if (strcmp(arg[2],"NULL") == 0) zstyle = NONE;
else vz = force->numeric(FLERR,arg[2]);
// set and apply scale factors
xscale = yscale = zscale = 1.0;
if (xstyle && !xstr) {
if (scale_flag) xscale = domain->lattice->xlattice;
vx *= xscale;
}
if (ystyle && !ystr) {
if (scale_flag) yscale = domain->lattice->ylattice;
vy *= yscale;
}
if (zstyle && !zstr) {
if (scale_flag) zscale = domain->lattice->zlattice;
vz *= zscale;
}
// check variables
if (xstr) {
xvar = input->variable->find(xstr);
if (xvar < 0)
error->all(FLERR,"Variable name for velocity set does not exist");
if (input->variable->equalstyle(xvar)) xstyle = EQUAL;
else if (input->variable->atomstyle(xvar)) xstyle = ATOM;
else error->all(FLERR,"Variable for velocity set is invalid style");
}
if (ystr) {
yvar = input->variable->find(ystr);
if (yvar < 0)
error->all(FLERR,"Variable name for velocity set does not exist");
if (input->variable->equalstyle(yvar)) ystyle = EQUAL;
else if (input->variable->atomstyle(yvar)) ystyle = ATOM;
else error->all(FLERR,"Variable for velocity set is invalid style");
}
if (zstr) {
zvar = input->variable->find(zstr);
if (zvar < 0)
error->all(FLERR,"Variable name for velocity set does not exist");
if (input->variable->equalstyle(zvar)) zstyle = EQUAL;
else if (input->variable->atomstyle(zvar)) zstyle = ATOM;
else error->all(FLERR,"Variable for velocity set is invalid style");
}
if (xstyle == ATOM || ystyle == ATOM || zstyle == ATOM)
varflag = ATOM;
else if (xstyle == EQUAL || ystyle == EQUAL || zstyle == EQUAL)
varflag = EQUAL;
else varflag = CONSTANT;
// error check for 2d models
if (domain->dimension == 2) {
if (zstyle == CONSTANT && vz != 0.0)
error->all(FLERR,"Cannot set non-zero z velocity for 2d simulation");
if (zstyle == EQUAL || zstyle == ATOM)
error->all(FLERR,"Cannot set variable z velocity for 2d simulation");
}
// allocate vfield array if necessary
double **vfield = NULL;
if (varflag == ATOM) memory->create(vfield,atom->nlocal,3,"velocity:vfield");
// set velocities via constants
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
if (varflag == CONSTANT) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
if (sum_flag == 0) {
if (xstyle) v[i][0] = vx;
if (ystyle) v[i][1] = vy;
if (zstyle) v[i][2] = vz;
} else {
if (xstyle) v[i][0] += vx;
if (ystyle) v[i][1] += vy;
if (zstyle) v[i][2] += vz;
}
}
}
// set velocities via variables
} else {
if (xstyle == EQUAL) vx = input->variable->compute_equal(xvar);
else if (xstyle == ATOM && vfield)
input->variable->compute_atom(xvar,igroup,&vfield[0][0],3,0);
if (ystyle == EQUAL) vy = input->variable->compute_equal(yvar);
else if (ystyle == ATOM && vfield)
input->variable->compute_atom(yvar,igroup,&vfield[0][1],3,0);
if (zstyle == EQUAL) vz = input->variable->compute_equal(zvar);
else if (zstyle == ATOM && vfield)
input->variable->compute_atom(zvar,igroup,&vfield[0][2],3,0);
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
if (sum_flag == 0) {
if (xstyle == ATOM) v[i][0] = vfield[i][0];
else if (xstyle) v[i][0] = vx;
if (ystyle == ATOM) v[i][1] = vfield[i][1];
else if (ystyle) v[i][1] = vy;
if (zstyle == ATOM) v[i][2] = vfield[i][2];
else if (zstyle) v[i][2] = vz;
} else {
if (xstyle == ATOM) v[i][0] += vfield[i][0];
else if (xstyle) v[i][0] += vx;
if (ystyle == ATOM) v[i][1] += vfield[i][1];
else if (ystyle) v[i][1] += vy;
if (zstyle == ATOM) v[i][2] += vfield[i][2];
else if (zstyle) v[i][2] += vz;
}
}
}
// clean up
delete [] xstr;
delete [] ystr;
delete [] zstr;
memory->destroy(vfield);
}
/* ----------------------------------------------------------------------
rescale velocities of a group after computing its temperature
------------------------------------------------------------------------- */
void Velocity::scale(int narg, char **arg)
{
double t_desired = force->numeric(FLERR,arg[0]);
// if temperature = NULL, create a new ComputeTemp with the velocity group
int tflag = 0;
if (temperature == NULL) {
char **arg = new char*[3];
arg[0] = (char *) "velocity_temp";
arg[1] = group->names[igroup];
arg[2] = (char *) "temp";
temperature = new ComputeTemp(lmp,3,arg);
tflag = 1;
delete [] arg;
}
// initialize temperature computation
// warn if groups don't match
if (igroup != temperature->igroup && comm->me == 0)
error->warning(FLERR,"Mismatch between velocity and compute groups");
temperature->init();
temperature->setup();
// scale temp to desired value
double t = temperature->compute_scalar();
rescale(t,t_desired);
// if temperature was created, delete it
if (tflag) delete temperature;
}
/* ----------------------------------------------------------------------
apply a ramped set of velocities
------------------------------------------------------------------------- */
void Velocity::ramp(int narg, char **arg)
{
// set scale factors
if (scale_flag) {
xscale = domain->lattice->xlattice;
yscale = domain->lattice->ylattice;
zscale = domain->lattice->zlattice;
}
else xscale = yscale = zscale = 1.0;
// parse args
int v_dim;
if (strcmp(arg[0],"vx") == 0) v_dim = 0;
else if (strcmp(arg[0],"vy") == 0) v_dim = 1;
else if (strcmp(arg[0],"vz") == 0) v_dim = 2;
else error->all(FLERR,"Illegal velocity command");
if (v_dim == 2 && domain->dimension == 2)
error->all(FLERR,"Velocity ramp in z for a 2d problem");
double v_lo,v_hi;
if (v_dim == 0) {
v_lo = xscale*force->numeric(FLERR,arg[1]);
v_hi = xscale*force->numeric(FLERR,arg[2]);
} else if (v_dim == 1) {
v_lo = yscale*force->numeric(FLERR,arg[1]);
v_hi = yscale*force->numeric(FLERR,arg[2]);
} else if (v_dim == 2) {
v_lo = zscale*force->numeric(FLERR,arg[1]);
v_hi = zscale*force->numeric(FLERR,arg[2]);
}
int coord_dim;
if (strcmp(arg[3],"x") == 0) coord_dim = 0;
else if (strcmp(arg[3],"y") == 0) coord_dim = 1;
else if (strcmp(arg[3],"z") == 0) coord_dim = 2;
else error->all(FLERR,"Illegal velocity command");
double coord_lo,coord_hi;
if (coord_dim == 0) {
coord_lo = xscale*force->numeric(FLERR,arg[4]);
coord_hi = xscale*force->numeric(FLERR,arg[5]);
} else if (coord_dim == 1) {
coord_lo = yscale*force->numeric(FLERR,arg[4]);
coord_hi = yscale*force->numeric(FLERR,arg[5]);
} else if (coord_dim == 2) {
coord_lo = zscale*force->numeric(FLERR,arg[4]);
coord_hi = zscale*force->numeric(FLERR,arg[5]);
}
// vramp = ramped velocity component for v_dim
// add or set based on sum_flag
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
double fraction,vramp;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
fraction = (x[i][coord_dim] - coord_lo) / (coord_hi - coord_lo);
fraction = MAX(fraction,0.0);
fraction = MIN(fraction,1.0);
vramp = v_lo + fraction*(v_hi - v_lo);
if (sum_flag) v[i][v_dim] += vramp;
else v[i][v_dim] = vramp;
}
}
/* ----------------------------------------------------------------------
zero linear or angular momentum of a group
if using rigid/small requires init of entire system since
its methods perform forward/reverse comm,
comm::init needs neighbor::init needs pair::init needs kspace::init, etc
also requires setup_pre_neighbor call to setup bodies
------------------------------------------------------------------------- */
void Velocity::zero(int narg, char **arg)
{
if (strcmp(arg[0],"linear") == 0) {
if (rfix < 0) zero_momentum();
else {
if (strcmp(modify->fix[rfix]->style,"rigid/small") == 0) {
lmp->init();
modify->fix[rfix]->setup_pre_neighbor();
modify->fix[rfix]->zero_momentum();
} else if (strstr(modify->fix[rfix]->style,"rigid")) {
modify->fix[rfix]->zero_momentum();
} else error->all(FLERR,"Velocity rigid used with non-rigid fix-ID");
}
} else if (strcmp(arg[0],"angular") == 0) {
if (rfix < 0) zero_rotation();
else {
if (strcmp(modify->fix[rfix]->style,"rigid/small") == 0) {
lmp->init();
modify->fix[rfix]->setup_pre_neighbor();
modify->fix[rfix]->zero_rotation();
} else if (strstr(modify->fix[rfix]->style,"rigid")) {
modify->fix[rfix]->zero_rotation();
} else error->all(FLERR,"Velocity rigid used with non-rigid fix-ID");
}
} else error->all(FLERR,"Illegal velocity command");
}
/* ----------------------------------------------------------------------
rescale velocities of group atoms to t_new from t_old
------------------------------------------------------------------------- */
void Velocity::rescale(double t_old, double t_new)
{
if (t_old == 0.0) error->all(FLERR,"Attempting to rescale a 0.0 temperature");
double factor = sqrt(t_new/t_old);
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
v[i][0] *= factor;
v[i][1] *= factor;
v[i][2] *= factor;
}
}
/* ----------------------------------------------------------------------
zero the linear momentum of a group of atoms by adjusting v by -Vcm
------------------------------------------------------------------------- */
void Velocity::zero_momentum()
{
// cannot have no atoms in group
if (group->count(igroup) == 0)
error->all(FLERR,"Cannot zero momentum of no atoms");
// compute velocity of center-of-mass of group
double masstotal = group->mass(igroup);
double vcm[3];
group->vcm(igroup,masstotal,vcm);
// adjust velocities by vcm to zero linear momentum
double **v = atom->v;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
v[i][0] -= vcm[0];
v[i][1] -= vcm[1];
v[i][2] -= vcm[2];
}
}
/* ----------------------------------------------------------------------
zero the angular momentum of a group of atoms by adjusting v by -(w x r)
------------------------------------------------------------------------- */
void Velocity::zero_rotation()
{
int i;
// cannot have no atoms in group
if (group->count(igroup) == 0)
error->all(FLERR,"Cannot zero momentum of no atoms");
// compute omega (angular velocity) of group around center-of-mass
double xcm[3],angmom[3],inertia[3][3],omega[3];
double masstotal = group->mass(igroup);
group->xcm(igroup,masstotal,xcm);
group->angmom(igroup,xcm,angmom);
group->inertia(igroup,xcm,inertia);
group->omega(angmom,inertia,omega);
// adjust velocities to zero omega
// vnew_i = v_i - w x r_i
// must use unwrapped coords to compute r_i correctly
double **x = atom->x;
double **v = atom->v;
int *mask = atom->mask;
imageint *image = atom->image;
int nlocal = atom->nlocal;
double dx,dy,dz;
double unwrap[3];
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
domain->unmap(x[i],image[i],unwrap);
dx = unwrap[0] - xcm[0];
dy = unwrap[1] - xcm[1];
dz = unwrap[2] - xcm[2];
v[i][0] -= omega[1]*dz - omega[2]*dy;
v[i][1] -= omega[2]*dx - omega[0]*dz;
v[i][2] -= omega[0]*dy - omega[1]*dx;
}
}
/* ----------------------------------------------------------------------
parse optional parameters at end of velocity input line
------------------------------------------------------------------------- */
void Velocity::options(int narg, char **arg)
{
if (narg < 0) error->all(FLERR,"Illegal velocity command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"dist") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"uniform") == 0) dist_flag = 0;
else if (strcmp(arg[iarg+1],"gaussian") == 0) dist_flag = 1;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else if (strcmp(arg[iarg],"sum") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"no") == 0) sum_flag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) sum_flag = 1;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else if (strcmp(arg[iarg],"mom") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"no") == 0) momentum_flag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) momentum_flag = 1;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else if (strcmp(arg[iarg],"rot") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"no") == 0) rotation_flag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) rotation_flag = 1;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else if (strcmp(arg[iarg],"temp") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
int icompute;
for (icompute = 0; icompute < modify->ncompute; icompute++)
if (strcmp(arg[iarg+1],modify->compute[icompute]->id) == 0) break;
if (icompute == modify->ncompute)
error->all(FLERR,"Could not find velocity temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all(FLERR,
"Velocity temperature ID does not compute temperature");
iarg += 2;
} else if (strcmp(arg[iarg],"loop") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"all") == 0) loop_flag = ALL;
else if (strcmp(arg[iarg+1],"local") == 0) loop_flag = LOCAL;
else if (strcmp(arg[iarg+1],"geom") == 0) loop_flag = GEOM;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else if (strcmp(arg[iarg],"rigid") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
rfix = modify->find_fix(arg[iarg+1]);
if (rfix < 0) error->all(FLERR,"Fix ID for velocity does not exist");
iarg += 2;
} else if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal velocity command");
if (strcmp(arg[iarg+1],"box") == 0) scale_flag = 0;
else if (strcmp(arg[iarg+1],"lattice") == 0) scale_flag = 1;
else error->all(FLERR,"Illegal velocity command");
iarg += 2;
} else error->all(FLERR,"Illegal velocity command");
}
}
diff --git a/src/version.h b/src/version.h
index 41e89ad5f..adf240332 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define LAMMPS_VERSION "13 Jan 2014"
+#define LAMMPS_VERSION "17 Jan 2014"
diff --git a/src/write_data.cpp b/src/write_data.cpp
index 994a78c53..a07c280e4 100644
--- a/src/write_data.cpp
+++ b/src/write_data.cpp
@@ -1,704 +1,704 @@
/* ----------------------------------------------------------------------
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 "lmptype.h"
#include "mpi.h"
#include "string.h"
#include "write_data.h"
#include "atom.h"
#include "atom_vec.h"
#include "group.h"
#include "force.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "dihedral.h"
#include "improper.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "domain.h"
#include "universe.h"
#include "comm.h"
#include "output.h"
#include "thermo.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{IGNORE,WARN,ERROR}; // same as thermo.cpp
enum{II,IJ};
/* ---------------------------------------------------------------------- */
WriteData::WriteData(LAMMPS *lmp) : Pointers(lmp)
{
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
}
/* ----------------------------------------------------------------------
called as write_data command in input script
------------------------------------------------------------------------- */
void WriteData::command(int narg, char **arg)
{
if (domain->box_exist == 0)
error->all(FLERR,"Write_data command before simulation box is defined");
if (narg < 1) error->all(FLERR,"Illegal write_data command");
// if filename contains a "*", replace with current timestep
char *ptr;
int n = strlen(arg[0]) + 16;
char *file = new char[n];
if (ptr = strchr(arg[0],'*')) {
*ptr = '\0';
sprintf(file,"%s" BIGINT_FORMAT "%s",arg[0],update->ntimestep,ptr+1);
} else strcpy(file,arg[0]);
// read optional args
// noinit is a hidden arg, only used by -r command-line switch
pairflag = II;
int noinit = 0;
int iarg = 1;
while (iarg < narg) {
if (strcmp(arg[iarg],"pair") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal write_data command");
if (strcmp(arg[iarg+1],"ii") == 0) pairflag = II;
else if (strcmp(arg[iarg+1],"ij") == 0) pairflag = IJ;
else error->all(FLERR,"Illegal write_data command");
iarg += 2;
} else if (strcmp(arg[iarg],"noinit") == 0) {
noinit = 1;
iarg++;
} else error->all(FLERR,"Illegal write_data command");
}
// init entire system since comm->exchange is done
// comm::init needs neighbor::init needs pair::init needs kspace::init, etc
// exception is when called by -r command-line switch
// then write_data immediately follows reading of restart file
// assume that read_restart initialized necessary values
// if don't make exception:
// pair->init() can fail due to various unset values:
// e.g. pair hybrid coeffs, dpd ghost-atom velocity setting
if (noinit == 0) {
if (comm->me == 0 && screen)
fprintf(screen,"System init for write_data ...\n");
lmp->init();
// move atoms to new processors before writing file
// do setup_pre_exchange to force update of per-atom info if needed
// enforce PBC in case atoms are outside box
// call borders() to rebuild atom map since exchange() destroys map
modify->setup_pre_exchange();
if (domain->triclinic) domain->x2lamda(atom->nlocal);
domain->pbc();
domain->reset_box();
comm->setup();
comm->exchange();
comm->borders();
if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
}
write(file);
delete [] file;
}
/* ----------------------------------------------------------------------
called from command()
might later let it be directly called within run/minimize loop
------------------------------------------------------------------------- */
void WriteData::write(char *file)
{
// special case where reneighboring is not done in integrator
// on timestep data file is written (due to build_once being set)
// if box is changing, must be reset, else data file will have
// wrong box size and atoms will be lost when data file is read
// other calls to pbc and domain and comm are not made,
// b/c they only make sense if reneighboring is actually performed
//if (neighbor->build_once) domain->reset_box();
// natoms = sum of nlocal = value to write into data file
// if unequal and thermo lostflag is "error", don't write data file
bigint nblocal = atom->nlocal;
bigint natoms;
MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
if (natoms != atom->natoms && output->thermo->lostflag == ERROR)
error->all(FLERR,"Atom count is inconsistent, cannot write data file");
// sum up bond,angle counts
// may be different than atom->nbonds,nangles if broken/turned-off
if (atom->nbonds || atom->nbondtypes) {
nbonds_local = atom->avec->pack_bond(NULL);
MPI_Allreduce(&nbonds_local,&nbonds,1,MPI_LMP_BIGINT,MPI_SUM,world);
}
if (atom->nangles || atom->nangletypes) {
nangles_local = atom->avec->pack_angle(NULL);
MPI_Allreduce(&nangles_local,&nangles,1,MPI_LMP_BIGINT,MPI_SUM,world);
}
// open data file
if (me == 0) {
fp = fopen(file,"w");
if (fp == NULL) {
char str[128];
sprintf(str,"Cannot open data file %s",file);
error->one(FLERR,str);
}
}
// proc 0 writes header, ntype-length arrays, force fields
if (me == 0) {
header();
type_arrays();
force_fields();
}
// per atom info
if (natoms) atoms();
if (natoms) velocities();
if (atom->nbonds && nbonds) bonds();
if (atom->nangles && nangles) angles();
if (atom->ndihedrals) dihedrals();
if (atom->nimpropers) impropers();
// extra sections managed by fixes
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->wd_section)
for (int m = 0; m < modify->fix[i]->wd_section; m++) fix(i,m);
// close data file
if (me == 0) fclose(fp);
}
/* ----------------------------------------------------------------------
proc 0 writes out data file header
------------------------------------------------------------------------- */
void WriteData::header()
{
fprintf(fp,"LAMMPS data file via write_data, version %s, "
"timestep = " BIGINT_FORMAT "\n",
universe->version,update->ntimestep);
fprintf(fp,"\n");
fprintf(fp,BIGINT_FORMAT " atoms\n",atom->natoms);
fprintf(fp,"%d atom types\n",atom->ntypes);
if (atom->nbonds || atom->nbondtypes) {
fprintf(fp,BIGINT_FORMAT " bonds\n",nbonds);
fprintf(fp,"%d bond types\n",atom->nbondtypes);
}
if (atom->nangles || atom->nangletypes) {
fprintf(fp,BIGINT_FORMAT " angles\n",nangles);
fprintf(fp,"%d angle types\n",atom->nangletypes);
}
if (atom->ndihedrals || atom->ndihedraltypes) {
fprintf(fp,BIGINT_FORMAT " dihedrals\n",atom->ndihedrals);
fprintf(fp,"%d dihedral types\n",atom->ndihedraltypes);
}
if (atom->nimpropers || atom->nimpropertypes) {
fprintf(fp,BIGINT_FORMAT " impropers\n",atom->nimpropers);
fprintf(fp,"%d improper types\n",atom->nimpropertypes);
}
for (int i = 0; i < modify->nfix; i++)
if (modify->fix[i]->wd_header)
for (int m = 0; m < modify->fix[i]->wd_header; m++)
modify->fix[i]->write_data_header(fp,m);
fprintf(fp,"\n");
fprintf(fp,"%-1.16e %-1.16e xlo xhi\n",domain->boxlo[0],domain->boxhi[0]);
fprintf(fp,"%-1.16e %-1.16e ylo yhi\n",domain->boxlo[1],domain->boxhi[1]);
fprintf(fp,"%-1.16e %-1.16e zlo zhi\n",domain->boxlo[2],domain->boxhi[2]);
if (domain->triclinic)
fprintf(fp,"%-1.16e %-1.16e %-1.16e xy xz yz\n",
domain->xy,domain->xz,domain->yz);
}
/* ----------------------------------------------------------------------
proc 0 writes out any type-based arrays that are defined
------------------------------------------------------------------------- */
void WriteData::type_arrays()
{
if (atom->mass) {
double *mass = atom->mass;
fprintf(fp,"\nMasses\n\n");
for (int i = 1; i <= atom->ntypes; i++) fprintf(fp,"%d %g\n",i,mass[i]);
}
}
/* ----------------------------------------------------------------------
proc 0 writes out force field info
------------------------------------------------------------------------- */
void WriteData::force_fields()
{
if (force->pair && force->pair->writedata) {
if (pairflag == II) {
fprintf(fp,"\nPair Coeffs # %s\n\n", force->pair_style);
force->pair->write_data(fp);
} else if (pairflag == IJ) {
fprintf(fp,"\nPairIJ Coeffs # %s\n\n", force->pair_style);
force->pair->write_data_all(fp);
}
}
if (atom->avec->bonds_allow && force->bond && force->bond->writedata) {
fprintf(fp,"\nBond Coeffs # %s\n\n", force->bond_style);
force->bond->write_data(fp);
}
if (atom->avec->angles_allow && force->angle && force->angle->writedata) {
fprintf(fp,"\nAngle Coeffs # %s\n\n", force->angle_style);
force->angle->write_data(fp);
}
if (atom->avec->dihedrals_allow && force->dihedral &&
force->dihedral->writedata) {
fprintf(fp,"\nDihedral Coeffs # %s\n\n", force->dihedral_style);
force->dihedral->write_data(fp);
}
if (atom->avec->impropers_allow && force->improper &&
force->improper->writedata) {
fprintf(fp,"\nImproper Coeffs # %s\n\n", force->improper_style);
force->improper->write_data(fp);
}
}
/* ----------------------------------------------------------------------
write out Atoms section of data file
------------------------------------------------------------------------- */
void WriteData::atoms()
{
// communication buffer for all my Atom info
// max_size = largest buffer needed by any proc
int ncol = atom->avec->size_data_atom + 3;
int sendrow = atom->nlocal;
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
double **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my atom data into buf
atom->avec->pack_data(buf);
// write one chunk of atoms per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
if (me == 0) {
fprintf(fp,"\nAtoms # %s\n\n",atom->atom_style);
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_data(fp,recvrow,buf);
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_DOUBLE,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Velocities section of data file
------------------------------------------------------------------------- */
void WriteData::velocities()
{
// communication buffer for all my Atom info
// max_size = largest buffer needed by any proc
int ncol = atom->avec->size_velocity + 1;
int sendrow = atom->nlocal;
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
double **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my velocity data into buf
atom->avec->pack_vel(buf);
// write one chunk of velocities per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
if (me == 0) {
fprintf(fp,"\nVelocities\n\n");
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_vel(fp,recvrow,buf);
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_DOUBLE,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Bonds section of data file
------------------------------------------------------------------------- */
void WriteData::bonds()
{
// communication buffer for all my Bond info
int ncol = 3;
int sendrow = static_cast<int> (nbonds_local);
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
- int **buf;
+ tagint **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my bond data into buf
int foo = atom->avec->pack_bond(buf);
// write one chunk of info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
int index = 1;
if (me == 0) {
fprintf(fp,"\nBonds\n\n");
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
- MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_INT,iproc,0,world,&request);
+ MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_LMP_TAGINT,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
- MPI_Get_count(&status,MPI_INT,&recvrow);
+ MPI_Get_count(&status,MPI_LMP_TAGINT,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_bond(fp,recvrow,buf,index);
index += recvrow;
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
- MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_INT,0,0,world);
+ MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_LMP_TAGINT,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Angles section of data file
------------------------------------------------------------------------- */
void WriteData::angles()
{
// communication buffer for all my Angle info
int ncol = 4;
int sendrow = static_cast<int> (nangles_local);
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
- int **buf;
+ tagint **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my angle data into buf
atom->avec->pack_angle(buf);
// write one chunk of info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
int index = 1;
if (me == 0) {
fprintf(fp,"\nAngles\n\n");
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
- MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_INT,iproc,0,world,&request);
+ MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_LMP_TAGINT,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
- MPI_Get_count(&status,MPI_INT,&recvrow);
+ MPI_Get_count(&status,MPI_LMP_TAGINT,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_angle(fp,recvrow,buf,index);
index += recvrow;
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
- MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_INT,0,0,world);
+ MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_LMP_TAGINT,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Dihedrals section of data file
------------------------------------------------------------------------- */
void WriteData::dihedrals()
{
// communication buffer for all my Dihedral info
// max_size = largest buffer needed by any proc
int ncol = 5;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_dihedral = atom->num_dihedral;
- int **dihedral_atom2 = atom->dihedral_atom2;
+ tagint **dihedral_atom2 = atom->dihedral_atom2;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int sendrow = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
sendrow += num_dihedral[i];
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_dihedral[i]; j++)
if (tag[i] == dihedral_atom2[i][j]) sendrow++;
}
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
- int **buf;
+ tagint **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my dihedral data into buf
atom->avec->pack_dihedral(buf);
// write one chunk of info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
int index = 1;
if (me == 0) {
fprintf(fp,"\nDihedrals\n\n");
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
- MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_INT,iproc,0,world,&request);
+ MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_LMP_TAGINT,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
- MPI_Get_count(&status,MPI_INT,&recvrow);
+ MPI_Get_count(&status,MPI_LMP_TAGINT,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_dihedral(fp,recvrow,buf,index);
index += recvrow;
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
- MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_INT,0,0,world);
+ MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_LMP_TAGINT,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Impropers section of data file
------------------------------------------------------------------------- */
void WriteData::impropers()
{
// communication buffer for all my Improper info
// max_size = largest buffer needed by any proc
int ncol = 5;
- int *tag = atom->tag;
+ tagint *tag = atom->tag;
int *num_improper = atom->num_improper;
- int **improper_atom2 = atom->improper_atom2;
+ tagint **improper_atom2 = atom->improper_atom2;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
int i,j;
int sendrow = 0;
if (newton_bond) {
for (i = 0; i < nlocal; i++)
sendrow += num_improper[i];
} else {
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_improper[i]; j++)
if (tag[i] == improper_atom2[i][j]) sendrow++;
}
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
- int **buf;
+ tagint **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my improper data into buf
atom->avec->pack_improper(buf);
// write one chunk of info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
int index = 1;
if (me == 0) {
fprintf(fp,"\nImpropers\n\n");
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
- MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_INT,iproc,0,world,&request);
+ MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_LMP_TAGINT,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
- MPI_Get_count(&status,MPI_INT,&recvrow);
+ MPI_Get_count(&status,MPI_LMP_TAGINT,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
atom->avec->write_improper(fp,recvrow,buf,index);
index += recvrow;
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
- MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_INT,0,0,world);
+ MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_LMP_TAGINT,0,0,world);
}
memory->destroy(buf);
}
/* ----------------------------------------------------------------------
write out Mth section of data file owned by Fix ifix
------------------------------------------------------------------------- */
void WriteData::fix(int ifix, int mth)
{
// communication buffer for Fix info
int sendrow,ncol;
modify->fix[ifix]->write_data_section_size(mth,sendrow,ncol);
int maxrow;
MPI_Allreduce(&sendrow,&maxrow,1,MPI_INT,MPI_MAX,world);
double **buf;
if (me == 0) memory->create(buf,MAX(1,maxrow),ncol,"write_data:buf");
else memory->create(buf,MAX(1,sendrow),ncol,"write_data:buf");
// pack my fix data into buf
modify->fix[ifix]->write_data_section_pack(mth,buf);
// write one chunk of info per proc to file
// proc 0 pings each proc, receives its chunk, writes to file
// all other procs wait for ping, send their chunk to proc 0
int tmp,recvrow;
MPI_Status status;
MPI_Request request;
int index = 1;
if (me == 0) {
modify->fix[ifix]->write_data_section_keyword(mth,fp);
for (int iproc = 0; iproc < nprocs; iproc++) {
if (iproc) {
MPI_Irecv(&buf[0][0],maxrow*ncol,MPI_DOUBLE,iproc,0,world,&request);
MPI_Send(&tmp,0,MPI_INT,iproc,0,world);
MPI_Wait(&request,&status);
MPI_Get_count(&status,MPI_DOUBLE,&recvrow);
recvrow /= ncol;
} else recvrow = sendrow;
modify->fix[ifix]->write_data_section(mth,fp,recvrow,buf,index);
index += recvrow;
}
} else {
MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status);
MPI_Rsend(&buf[0][0],sendrow*ncol,MPI_DOUBLE,0,0,world);
}
memory->destroy(buf);
}

Event Timeline