diff --git a/doc/Manual.html b/doc/Manual.html index f23b5a0cf..43e96bec9 100644 --- a/doc/Manual.html +++ b/doc/Manual.html @@ -1,441 +1,441 @@ <HTML> <HEAD> <TITLE>LAMMPS-ICMS Users Manual</TITLE> -<META NAME="docnumber" CONTENT="11 Jul 2014 version"> +<META NAME="docnumber" CONTENT="22 Jul 2014 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>11 Jul 2014 version +<CENTER><H4>22 Jul 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">KOKKOS package</A> <BR> 5.9 <A HREF = "Section_accelerate.html#acc_9">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> 6.22 <A HREF = "howto_22">Calculating a diffusion coefficient</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 4dbbe43c9..28755def0 100644 --- a/doc/Manual.txt +++ b/doc/Manual.txt @@ -1,276 +1,276 @@ <HEAD> <TITLE>LAMMPS-ICMS Users Manual</TITLE> -<META NAME="docnumber" CONTENT="11 Jul 2014 version"> +<META NAME="docnumber" CONTENT="22 Jul 2014 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 -11 Jul 2014 version :c,h4 +22 Jul 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 "KOKKOS package"_acc_8 :b 5.9 "Comparison of GPU and USER-CUDA packages"_acc_9 :ule,b "How-to discussions"_Section_howto.html :l 6.1 "Restarting a simulation"_howto_1 :ulb,b 6.2 "2d simulations"_howto_2 :b 6.3 "CHARMM and AMBER force fields"_howto_3 :b 6.4 "Running multiple simulations from one input script"_howto_4 :b 6.5 "Multi-replica simulations"_howto_5 :b 6.6 "Granular models"_howto_6 :b 6.7 "TIP3P water model"_howto_7 :b 6.8 "TIP4P water model"_howto_8 :b 6.9 "SPC water model"_howto_9 :b 6.10 "Coupling LAMMPS to other codes"_howto_10 :b 6.11 "Visualizing LAMMPS snapshots"_howto_11 :b 6.12 "Triclinic (non-orthogonal) simulation boxes"_howto_12 :b 6.13 "NEMD simulations"_howto_13 :b 6.14 "Finite-size spherical and aspherical particles"_howto_14 :b 6.15 "Output from LAMMPS (thermo, dumps, computes, fixes, variables)"_howto_15 :b 6.16 "Thermostatting, barostatting, and compute temperature"_howto_16 :b 6.17 "Walls"_howto_17 :b 6.18 "Elastic constants"_howto_18 :b 6.19 "Library interface to LAMMPS"_howto_19 :b 6.20 "Calculating thermal conductivity"_howto_20 :b 6.21 "Calculating viscosity"_howto_21 :b 6.22 "Calculating a diffusion coefficient"_howto_22 :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(acc_9,Section_accelerate.html#acc_9) :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/compute_property_atom.html b/doc/compute_property_atom.html index 62a7e04da..d22e65c54 100644 --- a/doc/compute_property_atom.html +++ b/doc/compute_property_atom.html @@ -1,167 +1,168 @@ <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> <HR> <H3>compute property/atom command </H3> <P><B>Syntax:</B> </P> <PRE>compute ID group-ID property/atom input1 input2 ... </PRE> <UL><LI>ID, group-ID are documented in <A HREF = "compute.html">compute</A> command <LI>property/atom = style name of this compute command <LI>input = one or more atom attributes -<PRE> possible attributes = id, mol, type, mass, +<PRE> possible attributes = id, mol, proc, type, mass, x, y, z, xs, ys, zs, xu, yu, zu, ix, iy, iz, vx, vy, vz, fx, fy, fz, q, mux, muy, muz, mu, radius, diameter, omegax, omegay, omegaz, angmomx, angmomy, angmomz, shapex,shapey, shapez, quatw, quati, quatj, quatk, tqx, tqy, tqz, end1x, end1y, end1z, end2x, end2y, end2z, corner1x, corner1y, corner1z, corner2x, corner2y, corner2z, corner3x, corner3y, corner3z, nbonds, vfrac, s0, spin, eradius, ervel, erforce, rho, drho, e, de, cv, i_name, d_name </PRE> <PRE> id = atom ID mol = molecule ID + proc = ID of processor that owns atom type = atom type mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipole moment of atom mu = magnitude of dipole moment of atom radius,diameter = radius,diameter of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle shapex,shapey,shapez = 3 diameters of aspherical particle quatw,quati,quatj,quatk = quaternion components for aspherical or body particles tqx,tqy,tqz = torque on finite-size particles end12x, end12y, end12z = end points of line segment corner123x, corner123y, corner123z = corner points of triangle nbonds = number of bonds </PRE> <PRE> PERI package per-atom properties: vfrac = ??? s0 = ??? </PRE> <PRE> USER-EFF and USER-AWPMD package per-atom properties: spin = electron spin eradius = electron radius ervel = electron radial velocity erforce = electron radial force </PRE> <PRE> USER-SPH package per-atom properties: rho = ??? drho = ??? e = ??? de = ??? cv = ??? </PRE> <PRE> <A HREF = "fix_property_atom.html">fix property/atom</A> per-atom properties: i_name = custom integer vector with name d_name = custom integer vector with name </PRE> </UL> <P><B>Examples:</B> </P> <PRE>compute 1 all property/atom xs vx fx mux compute 2 all property/atom type compute 1 all property/atom ix iy iz </PRE> <P><B>Description:</B> </P> <P>Define a computation that simply stores atom attributes for each atom in the group. This is useful so that the values can be used by other <A HREF = "Section_howto.html#howto_15">output commands</A> that take computes as inputs. See for example, the <A HREF = "compute_reduce.html">compute reduce</A>, <A HREF = "fix_ave_atom.html">fix ave/atom</A>, <A HREF = "fix_ave_histo.html">fix ave/histo</A>, <A HREF = "fix_ave_spatial.html">fix ave/spatial</A>, and <A HREF = "variable.html">atom-style variable</A> commands. </P> <P>The list of possible attributes is the same as that used by the <A HREF = "dump.html">dump custom</A> command, which describes their meaning, with some additional quantities that are only defined for certain <A HREF = "atom_style.html">atom -styles</A>. Basically, this list gives your input script -access to any per-atom quantity stored by LAMMPS. +styles</A>. Basically, this augmented list gives an +input script access to any per-atom quantity stored by LAMMPS. </P> <P>The values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group or for quantities that are not defined for a particular particle in the group (e.g. <I>shapex</I> if the particle is not an ellipsoid). </P> <P>The additional quantities only accessible via this command, and not directly via the <A HREF = "dump.html">dump custom</A> command, are as follows. </P> <P><I>Shapex</I>, <I>shapey</I>, and <I>shapez</I> are defined for ellipsoidal particles and define the 3d shape of each particle. </P> <P><I>Quatw</I>, <I>quati</I>, <I>quatj</I>, and <I>quatk</I> are defined for ellipsoidal particles and body particles and store the 4-vector quaternion representing the orientation of each particle. See the <A HREF = "set.html">set</A> command for an explanation of the quaternion vector. </P> <P><I>End1x</I>, <I>end1y</I>, <I>end1z</I>, <I>end2x</I>, <I>end2y</I>, <I>end2z</I>, are defined for line segment particles and define the end points of each line segment. </P> <P><I>Corner1x</I>, <I>corner1y</I>, <I>corner1z</I>, <I>corner2x</I>, <I>corner2y</I>, <I>corner2z</I>, <I>corner3x</I>, <I>corner3y</I>, <I>corner3z</I>, are defined for triangular particles and define the corner points of each triangle. </P> <P><I>nbonds</I> is available for all molecular atom styles and refers to the number of explicit bonds attached to an atom. </P> <P>The <I>i_name</I> and <I>d_name</I> attributes refer to custom integer and floating-point properties that have been added to each atom via the <A HREF = "fix_property_atom.html">fix property/atom</A> command. When that command is used specific names are given to each attribute which are what is specified as the "name" portion of <I>i_name</I> or <I>d_name</I>. </P> <P><B>Output info:</B> </P> <P>This compute calculates a per-atom vector or per-atom array depending on the number of input values. If a single input is specified, a per-atom vector is produced. If two or more inputs are specified, a per-atom array is produced where the number of columns = the number of inputs. The vector or array can be accessed by any command that uses per-atom values from a compute as input. See <A HREF = "Section_howto.html#howto_15">this section</A> for an overview of LAMMPS output options. </P> <P>The vector or array values will be in whatever <A HREF = "units.html">units</A> the corresponding attribute is in, e.g. velocity units for vx, charge units for q, etc. </P> <P><B>Restrictions:</B> none </P> <P><B>Related commands:</B> </P> <P><A HREF = "dump.html">dump custom</A>, <A HREF = "compute_reduce.html">compute reduce</A>, <A HREF = "fix_ave_atom.html">fix ave/atom</A>, <A HREF = "fix_ave_spatial.html">fix ave/spatial</A>, <A HREF = "fix_property_atom.html">fix property/atom</A> </P> <P><B>Default:</B> none </P> </HTML> diff --git a/doc/compute_property_atom.txt b/doc/compute_property_atom.txt index b6c1cc2f0..82f6e651b 100644 --- a/doc/compute_property_atom.txt +++ b/doc/compute_property_atom.txt @@ -1,157 +1,158 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line compute property/atom command :h3 [Syntax:] compute ID group-ID property/atom input1 input2 ... :pre ID, group-ID are documented in "compute"_compute.html command :ulb,l property/atom = style name of this compute command :l input = one or more atom attributes :l - possible attributes = id, mol, type, mass, + possible attributes = id, mol, proc, type, mass, x, y, z, xs, ys, zs, xu, yu, zu, ix, iy, iz, vx, vy, vz, fx, fy, fz, q, mux, muy, muz, mu, radius, diameter, omegax, omegay, omegaz, angmomx, angmomy, angmomz, shapex,shapey, shapez, quatw, quati, quatj, quatk, tqx, tqy, tqz, end1x, end1y, end1z, end2x, end2y, end2z, corner1x, corner1y, corner1z, corner2x, corner2y, corner2z, corner3x, corner3y, corner3z, nbonds, vfrac, s0, spin, eradius, ervel, erforce, rho, drho, e, de, cv, i_name, d_name :pre id = atom ID mol = molecule ID + proc = ID of processor that owns atom type = atom type mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipole moment of atom mu = magnitude of dipole moment of atom radius,diameter = radius,diameter of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle shapex,shapey,shapez = 3 diameters of aspherical particle quatw,quati,quatj,quatk = quaternion components for aspherical or body particles tqx,tqy,tqz = torque on finite-size particles end12x, end12y, end12z = end points of line segment corner123x, corner123y, corner123z = corner points of triangle nbonds = number of bonds :pre PERI package per-atom properties: vfrac = ??? s0 = ??? :pre USER-EFF and USER-AWPMD package per-atom properties: spin = electron spin eradius = electron radius ervel = electron radial velocity erforce = electron radial force :pre USER-SPH package per-atom properties: rho = ??? drho = ??? e = ??? de = ??? cv = ??? :pre "fix property/atom"_fix_property_atom.html per-atom properties: i_name = custom integer vector with name d_name = custom integer vector with name :pre :ule [Examples:] compute 1 all property/atom xs vx fx mux compute 2 all property/atom type compute 1 all property/atom ix iy iz :pre [Description:] Define a computation that simply stores atom attributes for each atom in the group. This is useful so that the values can be used by other "output commands"_Section_howto.html#howto_15 that take computes as inputs. See for example, the "compute reduce"_compute_reduce.html, "fix ave/atom"_fix_ave_atom.html, "fix ave/histo"_fix_ave_histo.html, "fix ave/spatial"_fix_ave_spatial.html, and "atom-style variable"_variable.html commands. The list of possible attributes is the same as that used by the "dump custom"_dump.html command, which describes their meaning, with some additional quantities that are only defined for certain "atom -styles"_atom_style.html. Basically, this list gives your input script -access to any per-atom quantity stored by LAMMPS. +styles"_atom_style.html. Basically, this augmented list gives an +input script access to any per-atom quantity stored by LAMMPS. The values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group or for quantities that are not defined for a particular particle in the group (e.g. {shapex} if the particle is not an ellipsoid). The additional quantities only accessible via this command, and not directly via the "dump custom"_dump.html command, are as follows. {Shapex}, {shapey}, and {shapez} are defined for ellipsoidal particles and define the 3d shape of each particle. {Quatw}, {quati}, {quatj}, and {quatk} are defined for ellipsoidal particles and body particles and store the 4-vector quaternion representing the orientation of each particle. See the "set"_set.html command for an explanation of the quaternion vector. {End1x}, {end1y}, {end1z}, {end2x}, {end2y}, {end2z}, are defined for line segment particles and define the end points of each line segment. {Corner1x}, {corner1y}, {corner1z}, {corner2x}, {corner2y}, {corner2z}, {corner3x}, {corner3y}, {corner3z}, are defined for triangular particles and define the corner points of each triangle. {nbonds} is available for all molecular atom styles and refers to the number of explicit bonds attached to an atom. The {i_name} and {d_name} attributes refer to custom integer and floating-point properties that have been added to each atom via the "fix property/atom"_fix_property_atom.html command. When that command is used specific names are given to each attribute which are what is specified as the "name" portion of {i_name} or {d_name}. [Output info:] This compute calculates a per-atom vector or per-atom array depending on the number of input values. If a single input is specified, a per-atom vector is produced. If two or more inputs are specified, a per-atom array is produced where the number of columns = the number of inputs. The vector or array can be accessed by any command that uses per-atom values from a compute as input. See "this section"_Section_howto.html#howto_15 for an overview of LAMMPS output options. The vector or array values will be in whatever "units"_units.html the corresponding attribute is in, e.g. velocity units for vx, charge units for q, etc. [Restrictions:] none [Related commands:] "dump custom"_dump.html, "compute reduce"_compute_reduce.html, "fix ave/atom"_fix_ave_atom.html, "fix ave/spatial"_fix_ave_spatial.html, "fix property/atom"_fix_property_atom.html [Default:] none diff --git a/doc/dump.html b/doc/dump.html index 5527540cc..e83d9f5c5 100644 --- a/doc/dump.html +++ b/doc/dump.html @@ -1,609 +1,611 @@ <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> <HR> <H3>dump command </H3> <H3><A HREF = "dump_image.html">dump image</A> command </H3> <H3><A HREF = "dump_image.html">dump movie</A> command </H3> <H3><A HREF = "dump_molfile.html">dump molfile</A> command </H3> <P><B>Syntax:</B> </P> <PRE>dump ID group-ID style N file args </PRE> <UL><LI>ID = user-assigned name for the dump <LI>group-ID = ID of the group of atoms to be dumped <LI>style = <I>atom</I> or <I>atom/mpiio</I> or <I>cfg</I> or <I>dcd</I> or <I>xtc</I> or <I>xyz</I> or <I>xyz/mpiio</I> or <I>image</I> or <I>movie</I> or <I>molfile</I> or <I>local</I> or <I>custom</I> or <I>custom/mpiio</I> <LI>N = dump every this many timesteps <LI>file = name of file to write dump info to <LI>args = list of arguments for a particular style <PRE> <I>atom</I> args = none <I>atom/mpiio</I> args = none <I>cfg</I> args = same as <I>custom</I> args, see below <I>dcd</I> args = none <I>xtc</I> args = none <I>xyz</I> args = none </PRE> <PRE> <I>xyz/mpiio</I> args = none </PRE> <PRE> <I>image</I> args = discussed on <A HREF = "dump_image.html">dump image</A> doc page </PRE> <PRE> <I>movie</I> args = discussed on <A HREF = "dump_image.html">dump image</A> doc page </PRE> <PRE> <I>molfile</I> args = discussed on <A HREF = "dump_molfile.html">dump molfile</A> doc page </PRE> <PRE> <I>local</I> args = list of local attributes possible attributes = index, c_ID, c_ID[N], f_ID, f_ID[N] index = enumeration of local values c_ID = local vector calculated by a compute with ID c_ID[N] = Nth column of local array calculated by a compute with ID f_ID = local vector calculated by a fix with ID f_ID[N] = Nth column of local array calculated by a fix with ID </PRE> <PRE> <I>custom</I> of <I>custom/mpiio</I> args = list of atom attributes possible attributes = id, mol, type, element, mass, x, y, z, xs, ys, zs, xu, yu, zu, xsu, ysu, zsu, 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, c_ID, c_ID[N], f_ID, f_ID[N], v_name </PRE> <PRE> id = atom ID mol = molecule ID + proc = ID of processor that owns atom type = atom type element = name of atom element, as defined by <A HREF = "dump_modify.html">dump_modify</A> command mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates xsu,ysu,zsu = scaled unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipole moment of atom mu = magnitude of dipole moment of atom radius,diameter = radius,diameter of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle tqx,tqy,tqz = torque on finite-size particles c_ID = per-atom vector calculated by a compute with ID c_ID[N] = Nth column of per-atom array calculated by a compute with ID f_ID = per-atom vector calculated by a fix with ID f_ID[N] = Nth column of per-atom array calculated by a fix with ID v_name = per-atom vector calculated by an atom-style variable with name </PRE> </UL> <P><B>Examples:</B> </P> <PRE>dump myDump all atom 100 dump.atom dump myDump all atom/mpiio 100 dump.atom.mpiio dump 2 subgroup atom 50 dump.run.bin dump 2 subgroup atom 50 dump.run.mpiio.bin dump 4a all custom 100 dump.myforce.* id type x y vx fx dump 4b flow custom 100 dump.%.myforce id type c_myF[3] v_ke dump 2 inner cfg 10 dump.snap.*.cfg mass type xs ys zs vx vy vz dump snap all cfg 100 dump.config.*.cfg mass type xs ys zs id type c_Stress[2] dump 1 all xtc 1000 file.xtc </PRE> <P><B>Description:</B> </P> <P>Dump a snapshot of atom quantities to one or more files every N timesteps in one of several styles. The <I>image</I> and <I>movie</I> styles are the exception: the <I>image</I> style renders a JPG, PNG, or PPM image file of the atom configuration every N timesteps while the <I>movie</I> style combines and compresses them into a movie file; both are discussed in detail on the <A HREF = "dump_image.html">dump image</A> doc page. The timesteps on which dump output is written can also be controlled by a variable. See the <A HREF = "dump_modify.html">dump_modify every</A> command. </P> <P>Only information for atoms in the specified group is dumped. The <A HREF = "dump_modify.html">dump_modify thresh and region</A> commands can also alter what atoms are included. Not all styles support all these options; see details below. </P> <P>As described below, the filename determines the kind of output (text or binary or gzipped, one big file or one per timestep, one big file or multiple smaller files). </P> <P>IMPORTANT NOTE: Because periodic boundary conditions are enforced only on timesteps when neighbor lists are rebuilt, the coordinates of an atom written to a dump file may be slightly outside the simulation box. </P> <P>IMPORTANT NOTE: Unless the <A HREF = "dump_modify.html">dump_modify sort</A> option is invoked, the lines of atom information written to dump files (typically one line per atom) will be in an indeterminate order for each snapshot. This is even true when running on a single processor, if the <A HREF = "atom_modify.html">atom_modify sort</A> option is on, which it is by default. In this case atoms are re-ordered periodically during a simulation, due to spatial sorting. It is also true when running in parallel, because data for a single snapshot is collected from multiple processors, each of which owns a subset of the atoms. </P> <P>For the <I>atom</I>, <I>custom</I>, <I>cfg</I>, and <I>local</I> styles, sorting is off by default. For the <I>dcd</I>, <I>xtc</I>, <I>xyz</I>, and <I>molfile</I> styles, sorting by atom ID is on by default. See the <A HREF = "dump_modify.html">dump_modify</A> doc page for details. </P> <P>As explained below, the <I>atom/mpiio</I>, <I>custom/mpiio</I>, and <I>xyz/mpiio</I> styles are identical in command syntax and in the format of the dump files they create, to the corresponding styles without "mpiio", except the single dump file they produce is written in parallel via the MPI-IO library. For the remainder of this doc page, you should thus consider the <I>atom</I> and <I>atom/mpiio</I> styles (etc) to be inter-changeable. The one exception is how the filename is specified for the MPI-IO styles, as explained below. </P> <HR> <P>The <I>style</I> keyword determines what atom quantities are written to the file and in what format. Settings made via the <A HREF = "dump_modify.html">dump_modify</A> command can also alter the format of individual values and the file itself. </P> <P>The <I>atom</I>, <I>local</I>, and <I>custom</I> styles create files in a simple text format that is self-explanatory when viewing a dump file. Many of the LAMMPS <A HREF = "Section_tools.html">post-processing tools</A>, including <A HREF = "http://www.sandia.gov/~sjplimp/pizza.html">Pizza.py</A>, work with this format, as does the <A HREF = "rerun.html">rerun</A> command. </P> <P>For post-processing purposes the <I>atom</I>, <I>local</I>, and <I>custom</I> text files are self-describing in the following sense. </P> <P>The dimensions of the simulation box are included in each snapshot. For an orthogonal simulation box this information is is formatted as: </P> <PRE>ITEM: BOX BOUNDS xx yy zz xlo xhi ylo yhi zlo zhi </PRE> <P>where xlo,xhi are the maximum extents of the simulation box in the x-dimension, and similarly for y and z. The "xx yy zz" represent 6 characters that encode the style of boundary for each of the 6 simulation box boundaries (xlo,xhi and ylo,yhi and zlo,zhi). Each of the 6 characters is either p = periodic, f = fixed, s = shrink wrap, or m = shrink wrapped with a minimum value. See the <A HREF = "boundary.html">boundary</A> command for details. </P> <P>For triclinic simulation boxes (non-orthogonal), an orthogonal bounding box which encloses the triclinic simulation box is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic box, formatted as follows: </P> <PRE>ITEM: BOX BOUNDS xy xz yz xx yy zz xlo_bound xhi_bound xy ylo_bound yhi_bound xz zlo_bound zhi_bound yz </PRE> <P>The presence of the text "xy xz yz" in the ITEM line indicates that the 3 tilt factors will be included on each of the 3 following lines. This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above. </P> <P>Note that the first two numbers on each line are now xlo_bound instead of xlo, etc, since they repesent a bounding box. See <A HREF = "Section_howto.html#howto_12">this section</A> of the doc pages for a geometric description of triclinic boxes, as defined by LAMMPS, simple formulas for how the 6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations. </P> <P>The "ITEM: ATOMS" line in each snapshot lists column descriptors for the per-atom lines that follow. For example, the descriptors would be "id type xs ys zs" for the default <I>atom</I> style, and would be the atom attributes you specify in the dump command for the <I>custom</I> style. </P> <P>For style <I>atom</I>, atom coordinates are written to the file, along with the atom ID and atom type. By default, atom coords are written in a scaled format (from 0 to 1). I.e. an x value of 0.25 means the atom is at a location 1/4 of the distance from xlo to xhi of the box boundaries. The format can be changed to unscaled coords via the <A HREF = "dump_modify.html">dump_modify</A> settings. Image flags can also be added for each atom via dump_modify. </P> <P>Style <I>custom</I> allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are listed above and will appear in the order specified. You cannot specify a quantity that is not defined for a particular simulation - such as <I>q</I> for atom style <I>bond</I>, since that atom style doesn't assign charges. Dumps occur at the very end of a timestep, so atom attributes will include effects due to fixes that are applied during the timestep. An explanation of the possible dump custom attributes is given below. </P> <P>For style <I>local</I>, local output generated by <A HREF = "compute.html">computes</A> and <A HREF = "fix.html">fixes</A> is used to generate lines of output that is written to the dump file. This local data is typically calculated by each processor based on the atoms it owns, but there may be zero or more entities per atom, e.g. a list of bond distances. An explanation of the possible dump local attributes is given below. Note that by using input from the <A HREF = "compute_property_local.html">compute property/local</A> command with dump local, it is possible to generate information on bonds, angles, etc that can be cut and pasted directly into a data file read by the <A HREF = "read_data.html">read_data</A> command. </P> <P>Style <I>cfg</I> has the same command syntax as style <I>custom</I> and writes extended CFG format files, as used by the <A HREF = "http://mt.seas.upenn.edu/Archive/Graphics/A">AtomEye</A> visualization package. Since the extended CFG format uses a single snapshot of the system per file, a wildcard "*" must be included in the filename, as discussed below. The list of atom attributes for style <I>cfg</I> must begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" since these quantities are needed to write the CFG files in the appropriate format (though the "mass" and "type" fields do not appear explicitly in the file). Any remaining attributes will be stored as "auxiliary properties" in the CFG files. Note that you will typically want to use the <A HREF = "dump_modify.html">dump_modify element</A> command with CFG-formatted files, to associate element names with atom types, so that AtomEye can render atoms appropriately. When unwrapped coordinates <I>xsu</I>, <I>ysu</I>, and <I>zsu</I> are requested, the nominal AtomEye periodic cell dimensions are expanded by a large factor UNWRAPEXPAND = 10.0, which ensures atoms that are displayed correctly for up to UNWRAPEXPAND/2 periodic boundary crossings in any direction. Beyond this, AtomEye will rewrap the unwrapped coordinates. The expansion causes the atoms to be drawn farther away from the viewer, but it is easy to zoom the atoms closer, and the interatomic distances are unaffected. </P> <P>The <I>dcd</I> style writes DCD files, a standard atomic trajectory format used by the CHARMM, NAMD, and XPlor molecular dynamics packages. DCD files are binary and thus may not be portable to different machines. The number of atoms per snapshot cannot change with the <I>dcd</I> style. The <I>unwrap</I> option of the <A HREF = "dump_modify.html">dump_modify</A> command allows DCD coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed through a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. </P> <P>The <I>xtc</I> style writes XTC files, a compressed trajectory format used by the GROMACS molecular dynamics package, and described <A HREF = "http://manual.gromacs.org/current/online/xtc.html">here</A>. The precision used in XTC files can be adjusted via the <A HREF = "dump_modify.html">dump_modify</A> command. The default value of 1000 means that coordinates are stored to 1/1000 nanometer accuracy. XTC files are portable binary files written in the NFS XDR data format, so that any machine which supports XDR should be able to read them. The number of atoms per snapshot cannot change with the <I>xtc</I> style. The <I>unwrap</I> option of the <A HREF = "dump_modify.html">dump_modify</A> command allows XTC coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. </P> <P>The <I>xyz</I> style writes XYZ files, which is a simple text-based coordinate format that many codes can read. Specifically it has a line with the number of atoms, then a comment line that is usually ignored followed by one line per atom with the atom type and the x-, y-, and z-coordinate of that atom. You can use the <A HREF = "dump_modify.html">dump_modify element</A> option to change the output from using the (numerical) atom type to an element name (or some other label). This will help many visualization programs to guess bonds and colors. </P> <P>Note that <I>atom</I>, <I>custom</I>, <I>dcd</I>, <I>xtc</I>, and <I>xyz</I> style dump files can be read directly by <A HREF = "http://www.ks.uiuc.edu/Research/vmd">VMD</A>, a popular molecular viewing program. See <A HREF = "Section_tools.html#vmd">Section tools</A> of the manual and the tools/lmp2vmd/README.txt file for more information about support in VMD for reading and visualizing LAMMPS dump files. </P> <HR> <P>Dumps are performed on timesteps that are a multiple of N (including timestep 0) and on the last timestep of a minimization if the minimization converges. Note that this means a dump will not be performed on the initial timestep after the dump command is invoked, if the current timestep is not a multiple of N. This behavior can be changed via the <A HREF = "dump_modify.html">dump_modify first</A> command, which can also be useful if the dump command is invoked after a minimization ended on an arbitrary timestep. N can be changed between runs by using the <A HREF = "dump_modify.html">dump_modify every</A> command (not allowed for <I>dcd</I> style). The <A HREF = "dump_modify.html">dump_modify every</A> command also allows a variable to be used to determine the sequence of timesteps on which dump files are written. In this mode a dump on the first timestep of a run will also not be written unless the <A HREF = "dump_modify.html">dump_modify first</A> command is used. </P> <P>The specified filename determines how the dump file(s) is written. The default is to write one large text file, which is opened when the dump command is invoked and closed when an <A HREF = "undump.html">undump</A> command is used or when LAMMPS exits. For the <I>dcd</I> and <I>xtc</I> styles, this is a single large binary file. </P> <P>Dump filenames can contain two wildcard characters. If a "*" character appears in the filename, then one file per snapshot is written and the "*" character is replaced with the timestep value. For example, tmp.dump.* becomes tmp.dump.0, tmp.dump.10000, tmp.dump.20000, etc. This option is not available for the <I>dcd</I> and <I>xtc</I> styles. Note that the <A HREF = "dump_modify.html">dump_modify pad</A> command can be used to insure all timestep numbers are the same length (e.g. 00010), which can make it easier to read a series of dump files in order with some post-processing tools. </P> <P>If a "%" character appears in the filename, then each of P processors writes a portion of the dump file, and the "%" character is replaced with the processor ID from 0 to P-1. For example, tmp.dump.% becomes tmp.dump.0, tmp.dump.1, ... tmp.dump.P-1, etc. This creates smaller files and can be a fast mode of output on parallel machines that support parallel I/O for output. This option is not available for the <I>dcd</I>, <I>xtc</I>, and <I>xyz</I> styles. </P> <P>By default, P = the number of processors meaning one file per processor, but P can be set to a smaller value via the <I>nfile</I> or <I>fileper</I> keywords of the <A HREF = "dump_modify.html">dump_modify</A> command. These options can be the most efficient way of writing out dump files when running on large numbers of processors. </P> <P>Note that using the "*" and "%" characters together can produce a large number of small dump files! </P> <P>For the <I>atom/mpiio</I>, <I>custom/mpiio</I>, and <I>xyz/mpiio</I> styles, a single dump file is written in parallel via the MPI-IO library, which is part of the MPI standard for versions 2.0 and above. Using MPI-IO requires two steps. First, build LAMMPS with its MPIIO package installed, e.g. </P> <PRE>make yes-mpiio # installs the MPIIO package make g++ # build LAMMPS for your platform </PRE> <P>Second, use a dump filename which contains ".mpiio". Note that it does not have to end in ".mpiio", just contain those characters. Unlike MPI-IO restart files, which must be both written and read using MPI-IO, the dump files produced by these MPI-IO styles are identical in format to the files produced by their non-MPI-IO style counterparts. This means you can write a dump file using MPI-IO and use the <A HREF = "read_dump.html">read_dump</A> command or perform other post-processing, just as if the dump file was not written using MPI-IO. </P> <P>Note that MPI-IO dump files are one large file which all processors write to. You thus cannot use the "%" wildcard character described above in the filename since that specifies generation of multiple files. You can use the ".bin" suffix described below in an MPI-IO dump file; again this file will be written in parallel and have the same binary format as if it were written without MPI-IO. </P> <P>If the filename ends with ".bin", the dump file (or files, if "*" or "%" is also used) is written in binary format. A binary dump file will be about the same size as a text version, but will typically write out much faster. Of course, when post-processing, you will need to convert it back to text format (see the <A HREF = "Section_tools.html#binary">binary2txt tool</A>) or write your own code to read the binary file. The format of the binary file can be understood by looking at the tools/binary2txt.cpp file. This option is only available for the <I>atom</I> and <I>custom</I> styles. </P> <P>If the filename ends with ".gz", the dump file (or files, if "*" or "%" is also used) is written in gzipped format. A gzipped dump file will be about 3x smaller than the text version, but will also take longer to write. This option is not available for the <I>dcd</I> and <I>xtc</I> styles. </P> <HR> <P>This section explains the local attributes that can be specified as part of the <I>local</I> style. </P> <P>The <I>index</I> attribute can be used to generate an index number from 1 to N for each line written into the dump file, where N is the total number of local datums from all processors, or lines of output that will appear in the snapshot. Note that because data from different processors depend on what atoms they currently own, and atoms migrate between processor, there is no guarantee that the same index will be used for the same info (e.g. a particular bond) in successive snapshots. </P> <P>The <I>c_ID</I> and <I>c_ID[N]</I> attributes allow local vectors or arrays calculated by a <A HREF = "compute.html">compute</A> to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the <A HREF = "compute.html">compute</A> command for details. There are computes for calculating local information such as indices, types, and energies for bonds and angles. </P> <P>Note that computes which calculate global or per-atom quantities, as opposed to local quantities, cannot be output in a dump local command. Instead, global quantities can be output by the <A HREF = "thermo_style.html">thermo_style custom</A> command, and per-atom quantities can be output by the dump custom command. </P> <P>If <I>c_ID</I> is used as a attribute, then the local vector calculated by the compute is printed. If <I>c_ID[N]</I> is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the compute. </P> <P>The <I>f_ID</I> and <I>f_ID[N]</I> attributes allow local vectors or arrays calculated by a <A HREF = "fix.html">fix</A> to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. </P> <P>If <I>f_ID</I> is used as a attribute, then the local vector calculated by the fix is printed. If <I>f_ID[N]</I> is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the fix. </P> <P>Here is an example of how to dump bond info for a system, including the distance and energy of each bond: </P> <PRE>compute 1 all property/local batom1 batom2 btype compute 2 all bond/local dist eng dump 1 all local 1000 tmp.dump index c_1[1] c_1[2] c_1[3] c_2[1] c_2[2] </PRE> <HR> <P>This section explains the atom attributes that can be specified as part of the <I>custom</I> and <I>cfg</I> styles. </P> -<P>The <I>id</I>, <I>mol</I>, <I>type</I>, <I>element</I>, <I>mass</I>, <I>vx</I>, <I>vy</I>, <I>vz</I>, <I>fx</I>, <I>fy</I>, -<I>fz</I>, <I>q</I> attributes are self-explanatory. +<P>The <I>id</I>, <I>mol</I>, <I>proc</I>, <I>type</I>, <I>element</I>, <I>mass</I>, <I>vx</I>, <I>vy</I>, <I>vz</I>, +<I>fx</I>, <I>fy</I>, <I>fz</I>, <I>q</I> attributes are self-explanatory. </P> <P><I>Id</I> is the atom ID. <I>Mol</I> is the molecule ID, included in the data -file for molecular systems. <I>Type</I> is the atom type. <I>Element</I> is -typically the chemical name of an element, which you must assign to -each type via the <A HREF = "dump_modify.html">dump_modify element</A> command. -More generally, it can be any string you wish to associated with an -atom type. <I>Mass</I> is the atom mass. <I>Vx</I>, <I>vy</I>, <I>vz</I>, <I>fx</I>, <I>fy</I>, -<I>fz</I>, and <I>q</I> are components of atom velocity and force and atomic -charge. +file for molecular systems. <I>Proc</I> is the ID of the processor (0 to +Nprocs-1) that currently owns the atom. <I>Type</I> is the atom type. +<I>Element</I> is typically the chemical name of an element, which you must +assign to each type via the <A HREF = "dump_modify.html">dump_modify element</A> +command. More generally, it can be any string you wish to associated +with an atom type. <I>Mass</I> is the atom mass. <I>Vx</I>, <I>vy</I>, <I>vz</I>, <I>fx</I>, +<I>fy</I>, <I>fz</I>, and <I>q</I> are components of atom velocity and force and +atomic charge. </P> <P>There are several options for outputting atom coordinates. The <I>x</I>, <I>y</I>, <I>z</I> attributes write atom coordinates "unscaled", in the appropriate distance <A HREF = "units.html">units</A> (Angstroms, sigma, etc). Use <I>xs</I>, <I>ys</I>, <I>zs</I> if you want the coordinates "scaled" to the box size, so that each value is 0.0 to 1.0. If the simulation box is triclinic (tilted), then all atom coords will still be between 0.0 and 1.0. Use <I>xu</I>, <I>yu</I>, <I>zu</I> if you want the coordinates "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that using <I>xu</I>, <I>yu</I>, <I>zu</I> means that the coordinate values may be far outside the box bounds printed with the snapshot. Using <I>xsu</I>, <I>ysu</I>, <I>zsu</I> is similar to using <I>xu</I>, <I>yu</I>, <I>zu</I>, except that the unwrapped coordinates are scaled by the box size. Atoms that have passed through a periodic boundary will have the corresponding cooordinate increased or decreased by 1.0. </P> <P>The image flags can be printed directly using the <I>ix</I>, <I>iy</I>, <I>iz</I> attributes. For periodic dimensions, they specify which image of the simulation box the atom is considered to be in. An image of 0 means it is inside the box as defined. A value of 2 means add 2 box lengths to get the true value. A value of -1 means subtract 1 box length to get the true value. LAMMPS updates these flags as atoms cross periodic boundaries during the simulation. </P> <P>The <I>mux</I>, <I>muy</I>, <I>muz</I> attributes are specific to dipolar systems defined with an atom style of <I>dipole</I>. They give the orientation of the atom's point dipole moment. The <I>mu</I> attribute gives the magnitude of the atom's dipole moment. </P> <P>The <I>radius</I> and <I>diameter</I> attributes are specific to spherical particles that have a finite size, such as those defined with an atom style of <I>sphere</I>. </P> <P>The <I>omegax</I>, <I>omegay</I>, and <I>omegaz</I> attributes are specific to finite-size spherical particles that have an angular velocity. Only certain atom styles, such as <I>sphere</I> define this quantity. </P> <P>The <I>angmomx</I>, <I>angmomy</I>, and <I>angmomz</I> attributes are specific to finite-size aspherical particles that have an angular momentum. Only the <I>ellipsoid</I> atom style defines this quantity. </P> <P>The <I>tqx</I>, <I>tqy</I>, <I>tqz</I> attributes are for finite-size particles that can sustain a rotational torque due to interactions with other particles. </P> <P>The <I>c_ID</I> and <I>c_ID[N]</I> attributes allow per-atom vectors or arrays calculated by a <A HREF = "compute.html">compute</A> to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the <A HREF = "compute.html">compute</A> command for details. There are computes for calculating the per-atom energy, stress, centro-symmetry parameter, and coordination number of individual atoms. </P> <P>Note that computes which calculate global or local quantities, as opposed to per-atom quantities, cannot be output in a dump custom command. Instead, global quantities can be output by the <A HREF = "thermo_style.html">thermo_style custom</A> command, and local quantities can be output by the dump local command. </P> <P>If <I>c_ID</I> is used as a attribute, then the per-atom vector calculated by the compute is printed. If <I>c_ID[N]</I> is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the compute. </P> <P>The <I>f_ID</I> and <I>f_ID[N]</I> attributes allow vector or array per-atom quantities calculated by a <A HREF = "fix.html">fix</A> to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. The <A HREF = "fix_ave_atom.html">fix ave/atom</A> command is one that calculates per-atom quantities. Since it can time-average per-atom quantities produced by any <A HREF = "compute.html">compute</A>, <A HREF = "fix.html">fix</A>, or atom-style <A HREF = "variable.html">variable</A>, this allows those time-averaged results to be written to a dump file. </P> <P>If <I>f_ID</I> is used as a attribute, then the per-atom vector calculated by the fix is printed. If <I>f_ID[N]</I> is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the fix. </P> <P>The <I>v_name</I> attribute allows per-atom vectors calculated by a <A HREF = "variable.html">variable</A> to be output. The name in the attribute should be replaced by the actual name of the variable that has been defined previously in the input script. Only an atom-style variable can be referenced, since it is the only style that generates per-atom values. Variables of style <I>atom</I> can reference individual atom attributes, per-atom atom attributes, thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of creating quantities to output to a dump file. </P> <P>See <A HREF = "Section_modify.html">Section_modify</A> of the manual for information on how to add new compute and fix styles to LAMMPS to calculate per-atom quantities which could then be output into dump files. </P> <HR> <P><B>Restrictions:</B> </P> <P>To write gzipped dump files, you must compile LAMMPS with the -DLAMMPS_GZIP option - see the <A HREF = "Section_start.html#start_2">Making LAMMPS</A> section of the documentation. </P> <P>The <I>atom/mpiio</I>, <I>custom/mpiio</I>, and <I>xyz/mpiio</I> styles are part of the MPIIO package. They are only enabled if LAMMPS was built with that package. See the <A HREF = "Section_start.html#start_3">Making LAMMPS</A> section for more info. </P> <P>The <I>xtc</I> style is part of the XTC package. It is only enabled if LAMMPS was built with that package. See the <A HREF = "Section_start.html#start_3">Making LAMMPS</A> section for more info. This is because some machines may not support the low-level XDR data format that XTC files are written with, which will result in a compile-time error when a low-level include file is not found. Putting this style in a package makes it easy to exclude from a LAMMPS build for those machines. However, the XTC package also includes two compatibility header files and associated functions, which should be a suitable substitute on machines that do not have the appropriate native header files. This option can be invoked at build time by adding -DLAMMPS_XDR to the CCFLAGS variable in the appropriate low-level Makefile, e.g. src/MAKE/Makefile.foo. This compatibility mode has been tested successfully on Cray XT3/XT4/XT5 and IBM BlueGene/L machines and should also work on IBM BG/P, and Windows XP/Vista/7 machines. </P> <P><B>Related commands:</B> </P> <P><A HREF = "dump_image.html">dump image</A>, <A HREF = "dump_modify.html">dump_modify</A>, <A HREF = "undump.html">undump</A> </P> <P><B>Default:</B> </P> <P>The defaults for the image style are listed on the <A HREF = "dump_image.html">dump image</A> doc page. </P> </HTML> diff --git a/doc/dump.txt b/doc/dump.txt index 5d1be5881..3f83f217c 100644 --- a/doc/dump.txt +++ b/doc/dump.txt @@ -1,592 +1,600 @@ "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 dump command :h3 "dump image"_dump_image.html command :h3 "dump movie"_dump_image.html command :h3 "dump molfile"_dump_molfile.html command :h3 [Syntax:] dump ID group-ID style N file args :pre ID = user-assigned name for the dump :ulb,l group-ID = ID of the group of atoms to be dumped :l style = {atom} or {atom/mpiio} or {cfg} or {dcd} or {xtc} or {xyz} or {xyz/mpiio} or {image} or {movie} or {molfile} or {local} or {custom} or {custom/mpiio} :l N = dump every this many timesteps :l file = name of file to write dump info to :l args = list of arguments for a particular style :l {atom} args = none {atom/mpiio} args = none {cfg} args = same as {custom} args, see below {dcd} args = none {xtc} args = none {xyz} args = none :pre {xyz/mpiio} args = none :pre {image} args = discussed on "dump image"_dump_image.html doc page :pre {movie} args = discussed on "dump image"_dump_image.html doc page :pre {molfile} args = discussed on "dump molfile"_dump_molfile.html doc page :pre {local} args = list of local attributes possible attributes = index, c_ID, c_ID\[N\], f_ID, f_ID\[N\] index = enumeration of local values c_ID = local vector calculated by a compute with ID c_ID\[N\] = Nth column of local array calculated by a compute with ID f_ID = local vector calculated by a fix with ID f_ID\[N\] = Nth column of local array calculated by a fix with ID :pre {custom} of {custom/mpiio} args = list of atom attributes possible attributes = id, mol, type, element, mass, x, y, z, xs, ys, zs, xu, yu, zu, xsu, ysu, zsu, 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, c_ID, c_ID\[N\], f_ID, f_ID\[N\], v_name :pre id = atom ID mol = molecule ID + proc = ID of processor that owns atom type = atom type element = name of atom element, as defined by "dump_modify"_dump_modify.html command mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates xsu,ysu,zsu = scaled unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipole moment of atom mu = magnitude of dipole moment of atom radius,diameter = radius,diameter of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle tqx,tqy,tqz = torque on finite-size particles c_ID = per-atom vector calculated by a compute with ID c_ID\[N\] = Nth column of per-atom array calculated by a compute with ID f_ID = per-atom vector calculated by a fix with ID f_ID\[N\] = Nth column of per-atom array calculated by a fix with ID - v_name = per-atom vector calculated by an atom-style variable with name :pre + v_name = per-atom vector calculated by an atom-style variable with name + d_name = per-atom floating point vector with name managed by fix property/atom + i_name = per-atom integer vector with name managed by fix property/atom :pre :ule [Examples:] dump myDump all atom 100 dump.atom dump myDump all atom/mpiio 100 dump.atom.mpiio dump 2 subgroup atom 50 dump.run.bin dump 2 subgroup atom 50 dump.run.mpiio.bin dump 4a all custom 100 dump.myforce.* id type x y vx fx dump 4b flow custom 100 dump.%.myforce id type c_myF\[3\] v_ke dump 2 inner cfg 10 dump.snap.*.cfg mass type xs ys zs vx vy vz dump snap all cfg 100 dump.config.*.cfg mass type xs ys zs id type c_Stress\[2\] dump 1 all xtc 1000 file.xtc :pre [Description:] Dump a snapshot of atom quantities to one or more files every N timesteps in one of several styles. The {image} and {movie} styles are the exception: the {image} style renders a JPG, PNG, or PPM image file of the atom configuration every N timesteps while the {movie} style combines and compresses them into a movie file; both are discussed in detail on the "dump image"_dump_image.html doc page. The timesteps on which dump output is written can also be controlled by a variable. See the "dump_modify every"_dump_modify.html command. Only information for atoms in the specified group is dumped. The "dump_modify thresh and region"_dump_modify.html commands can also alter what atoms are included. Not all styles support all these options; see details below. As described below, the filename determines the kind of output (text or binary or gzipped, one big file or one per timestep, one big file or one per processor). IMPORTANT NOTE: Because periodic boundary conditions are enforced only on timesteps when neighbor lists are rebuilt, the coordinates of an atom written to a dump file may be slightly outside the simulation box. IMPORTANT NOTE: Unless the "dump_modify sort"_dump_modify.html option is invoked, the lines of atom information written to dump files (typically one line per atom) will be in an indeterminate order for each snapshot. This is even true when running on a single processor, if the "atom_modify sort"_atom_modify.html option is on, which it is by default. In this case atoms are re-ordered periodically during a simulation, due to spatial sorting. It is also true when running in parallel, because data for a single snapshot is collected from multiple processors. For the {atom}, {custom}, {cfg}, and {local} styles, sorting is off by default. For the {dcd}, {xtc}, {xyz}, and {molfile} styles, sorting by atom ID is on by default. See the "dump_modify"_dump_modify.html doc page for details. As explained below, the {atom/mpiio}, {custom/mpiio}, and {xyz/mpiio} styles are identical in command syntax and in the format of the dump files they create, to the corresponding styles without "mpiio", except the single dump file they produce is written in parallel via the MPI-IO library. For the remainder of this doc page, you should thus consider the {atom} and {atom/mpiio} styles (etc) to be inter-changeable. The one exception is how the filename is specified for the MPI-IO styles, as explained below. :line The {style} keyword determines what atom quantities are written to the file and in what format. Settings made via the "dump_modify"_dump_modify.html command can also alter the format of individual values and the file itself. The {atom}, {local}, and {custom} styles create files in a simple text format that is self-explanatory when viewing a dump file. Many of the LAMMPS "post-processing tools"_Section_tools.html, including "Pizza.py"_http://www.sandia.gov/~sjplimp/pizza.html, work with this format, as does the "rerun"_rerun.html command. For post-processing purposes the {atom}, {local}, and {custom} text files are self-describing in the following sense. The dimensions of the simulation box are included in each snapshot. For an orthogonal simulation box this information is is formatted as: ITEM: BOX BOUNDS xx yy zz xlo xhi ylo yhi zlo zhi :pre where xlo,xhi are the maximum extents of the simulation box in the x-dimension, and similarly for y and z. The "xx yy zz" represent 6 characters that encode the style of boundary for each of the 6 simulation box boundaries (xlo,xhi and ylo,yhi and zlo,zhi). Each of the 6 characters is either p = periodic, f = fixed, s = shrink wrap, or m = shrink wrapped with a minimum value. See the "boundary"_boundary.html command for details. For triclinic simulation boxes (non-orthogonal), an orthogonal bounding box which encloses the triclinic simulation box is output, along with the 3 tilt factors (xy, xz, yz) of the triclinic box, formatted as follows: ITEM: BOX BOUNDS xy xz yz xx yy zz xlo_bound xhi_bound xy ylo_bound yhi_bound xz zlo_bound zhi_bound yz :pre The presence of the text "xy xz yz" in the ITEM line indicates that the 3 tilt factors will be included on each of the 3 following lines. This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above. Note that the first two numbers on each line are now xlo_bound instead of xlo, etc, since they repesent a bounding box. See "this section"_Section_howto.html#howto_12 of the doc pages for a geometric description of triclinic boxes, as defined by LAMMPS, simple formulas for how the 6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations. The "ITEM: ATOMS" line in each snapshot lists column descriptors for the per-atom lines that follow. For example, the descriptors would be "id type xs ys zs" for the default {atom} style, and would be the atom attributes you specify in the dump command for the {custom} style. For style {atom}, atom coordinates are written to the file, along with the atom ID and atom type. By default, atom coords are written in a scaled format (from 0 to 1). I.e. an x value of 0.25 means the atom is at a location 1/4 of the distance from xlo to xhi of the box boundaries. The format can be changed to unscaled coords via the "dump_modify"_dump_modify.html settings. Image flags can also be added for each atom via dump_modify. Style {custom} allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are listed above and will appear in the order specified. You cannot specify a quantity that is not defined for a particular simulation - such as {q} for atom style {bond}, since that atom style doesn't assign charges. Dumps occur at the very end of a timestep, so atom attributes will include effects due to fixes that are applied during the timestep. An explanation of the possible dump custom attributes is given below. For style {local}, local output generated by "computes"_compute.html and "fixes"_fix.html is used to generate lines of output that is written to the dump file. This local data is typically calculated by each processor based on the atoms it owns, but there may be zero or more entities per atom, e.g. a list of bond distances. An explanation of the possible dump local attributes is given below. Note that by using input from the "compute property/local"_compute_property_local.html command with dump local, it is possible to generate information on bonds, angles, etc that can be cut and pasted directly into a data file read by the "read_data"_read_data.html command. Style {cfg} has the same command syntax as style {custom} and writes extended CFG format files, as used by the "AtomEye"_http://mt.seas.upenn.edu/Archive/Graphics/A visualization package. Since the extended CFG format uses a single snapshot of the system per file, a wildcard "*" must be included in the filename, as discussed below. The list of atom attributes for style {cfg} must begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" since these quantities are needed to write the CFG files in the appropriate format (though the "mass" and "type" fields do not appear explicitly in the file). Any remaining attributes will be stored as "auxiliary properties" in the CFG files. Note that you will typically want to use the "dump_modify element"_dump_modify.html command with CFG-formatted files, to associate element names with atom types, so that AtomEye can render atoms appropriately. When unwrapped coordinates {xsu}, {ysu}, and {zsu} are requested, the nominal AtomEye periodic cell dimensions are expanded by a large factor UNWRAPEXPAND = 10.0, which ensures atoms that are displayed correctly for up to UNWRAPEXPAND/2 periodic boundary crossings in any direction. Beyond this, AtomEye will rewrap the unwrapped coordinates. The expansion causes the atoms to be drawn farther away from the viewer, but it is easy to zoom the atoms closer, and the interatomic distances are unaffected. The {dcd} style writes DCD files, a standard atomic trajectory format used by the CHARMM, NAMD, and XPlor molecular dynamics packages. DCD files are binary and thus may not be portable to different machines. The number of atoms per snapshot cannot change with the {dcd} style. The {unwrap} option of the "dump_modify"_dump_modify.html command allows DCD coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed through a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. The {xtc} style writes XTC files, a compressed trajectory format used by the GROMACS molecular dynamics package, and described "here"_http://manual.gromacs.org/current/online/xtc.html. The precision used in XTC files can be adjusted via the "dump_modify"_dump_modify.html command. The default value of 1000 means that coordinates are stored to 1/1000 nanometer accuracy. XTC files are portable binary files written in the NFS XDR data format, so that any machine which supports XDR should be able to read them. The number of atoms per snapshot cannot change with the {xtc} style. The {unwrap} option of the "dump_modify"_dump_modify.html command allows XTC coordinates to be written "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that these coordinates may thus be far outside the box size stored with the snapshot. The {xyz} style writes XYZ files, which is a simple text-based coordinate format that many codes can read. Specifically it has a line with the number of atoms, then a comment line that is usually ignored followed by one line per atom with the atom type and the x-, y-, and z-coordinate of that atom. You can use the "dump_modify element"_dump_modify.html option to change the output from using the (numerical) atom type to an element name (or some other label). This will help many visualization programs to guess bonds and colors. Note that {atom}, {custom}, {dcd}, {xtc}, and {xyz} style dump files can be read directly by "VMD"_http://www.ks.uiuc.edu/Research/vmd (a popular molecular viewing program). See "Section tools"_Section_tools.html#vmd of the manual and the tools/lmp2vmd/README.txt file for more information about support in VMD for reading and visualizing LAMMPS dump files. :line Dumps are performed on timesteps that are a multiple of N (including timestep 0) and on the last timestep of a minimization if the minimization converges. Note that this means a dump will not be performed on the initial timestep after the dump command is invoked, if the current timestep is not a multiple of N. This behavior can be changed via the "dump_modify first"_dump_modify.html command, which can also be useful if the dump command is invoked after a minimization ended on an arbitrary timestep. N can be changed between runs by using the "dump_modify every"_dump_modify.html command (not allowed for {dcd} style). The "dump_modify every"_dump_modify.html command also allows a variable to be used to determine the sequence of timesteps on which dump files are written. In this mode a dump on the first timestep of a run will also not be written unless the "dump_modify first"_dump_modify.html command is used. The specified filename determines how the dump file(s) is written. The default is to write one large text file, which is opened when the dump command is invoked and closed when an "undump"_undump.html command is used or when LAMMPS exits. For the {dcd} and {xtc} styles, this is a single large binary file. Dump filenames can contain two wildcard characters. If a "*" character appears in the filename, then one file per snapshot is written and the "*" character is replaced with the timestep value. For example, tmp.dump.* becomes tmp.dump.0, tmp.dump.10000, tmp.dump.20000, etc. This option is not available for the {dcd} and {xtc} styles. Note that the "dump_modify pad"_dump_modify.html command can be used to insure all timestep numbers are the same length (e.g. 00010), which can make it easier to read a series of dump files in order by some post-processing tools. If a "%" character appears in the filename, then each of P processors writes a portion of the dump file, and the "%" character is replaced with the processor ID from 0 to P-1. For example, tmp.dump.% becomes tmp.dump.0, tmp.dump.1, ... tmp.dump.P-1, etc. This creates smaller files and can be a fast mode of output on parallel machines that support parallel I/O for output. This option is not available for the {dcd}, {xtc}, and {xyz} styles. By default, P = the number of processors meaning one file per processor, but P can be set to a smaller value via the {nfile} or {fileper} keywords of the "dump_modify"_dump_modify.html command. These options can be the most efficient way of writing out dump files when running on large numbers of processors. Note that using the "*" and "%" characters together can produce a large number of small dump files! For the {atom/mpiio}, {custom/mpiio}, and {xyz/mpiio} styles, a single dump file is written in parallel via the MPI-IO library, which is part of the MPI standard for versions 2.0 and above. Using MPI-IO requires two steps. First, build LAMMPS with its MPIIO package installed, e.g. make yes-mpiio # installs the MPIIO package make g++ # build LAMMPS for your platform :pre Second, use a dump filename which contains ".mpiio". Note that it does not have to end in ".mpiio", just contain those characters. Unlike MPI-IO restart files, which must be both written and read using MPI-IO, the dump files produced by these MPI-IO styles are identical in format to the files produced by their non-MPI-IO style counterparts. This means you can write a dump file using MPI-IO and use the "read_dump"_read_dump.html command or perform other post-processing, just as if the dump file was not written using MPI-IO. Note that MPI-IO dump files are one large file which all processors write to. You thus cannot use the "%" wildcard character described above in the filename since that specifies generation of multiple files. You can use the ".bin" suffix described below in an MPI-IO dump file; again this file will be written in parallel and have the same binary format as if it were written without MPI-IO. If the filename ends with ".bin", the dump file (or files, if "*" or "%" is also used) is written in binary format. A binary dump file will be about the same size as a text version, but will typically write out much faster. Of course, when post-processing, you will need to convert it back to text format (see the "binary2txt tool"_Section_tools.html#binary) or write your own code to read the binary file. The format of the binary file can be understood by looking at the tools/binary2txt.cpp file. This option is only available for the {atom} and {custom} styles. If the filename ends with ".gz", the dump file (or files, if "*" or "%" is also used) is written in gzipped format. A gzipped dump file will be about 3x smaller than the text version, but will also take longer to write. This option is not available for the {dcd} and {xtc} styles. :line This section explains the local attributes that can be specified as part of the {local} style. The {index} attribute can be used to generate an index number from 1 to N for each line written into the dump file, where N is the total number of local datums from all processors, or lines of output that will appear in the snapshot. Note that because data from different processors depend on what atoms they currently own, and atoms migrate between processor, there is no guarantee that the same index will be used for the same info (e.g. a particular bond) in successive snapshots. The {c_ID} and {c_ID\[N\]} attributes allow local vectors or arrays calculated by a "compute"_compute.html to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the "compute"_compute.html command for details. There are computes for calculating local information such as indices, types, and energies for bonds and angles. Note that computes which calculate global or per-atom quantities, as opposed to local quantities, cannot be output in a dump local command. Instead, global quantities can be output by the "thermo_style custom"_thermo_style.html command, and per-atom quantities can be output by the dump custom command. If {c_ID} is used as a attribute, then the local vector calculated by the compute is printed. If {c_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the compute. The {f_ID} and {f_ID\[N\]} attributes allow local vectors or arrays calculated by a "fix"_fix.html to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. If {f_ID} is used as a attribute, then the local vector calculated by the fix is printed. If {f_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length local array calculated by the fix. Here is an example of how to dump bond info for a system, including the distance and energy of each bond: compute 1 all property/local batom1 batom2 btype compute 2 all bond/local dist eng dump 1 all local 1000 tmp.dump index c_1\[1\] c_1\[2\] c_1\[3\] c_2\[1\] c_2\[2\] :pre :line This section explains the atom attributes that can be specified as part of the {custom} and {cfg} styles. -The {id}, {mol}, {type}, {element}, {mass}, {vx}, {vy}, {vz}, {fx}, {fy}, -{fz}, {q} attributes are self-explanatory. +The {id}, {mol}, {proc}, {type}, {element}, {mass}, {vx}, {vy}, {vz}, +{fx}, {fy}, {fz}, {q} attributes are self-explanatory. {Id} is the atom ID. {Mol} is the molecule ID, included in the data -file for molecular systems. {Type} is the atom type. {Element} is -typically the chemical name of an element, which you must assign to -each type via the "dump_modify element"_dump_modify.html command. -More generally, it can be any string you wish to associated with an -atom type. {Mass} is the atom mass. {Vx}, {vy}, {vz}, {fx}, {fy}, -{fz}, and {q} are components of atom velocity and force and atomic -charge. +file for molecular systems. {Proc} is the ID of the processor (0 to +Nprocs-1) that currently owns the atom. {Type} is the atom type. +{Element} is typically the chemical name of an element, which you must +assign to each type via the "dump_modify element"_dump_modify.html +command. More generally, it can be any string you wish to associated +with an atom type. {Mass} is the atom mass. {Vx}, {vy}, {vz}, {fx}, +{fy}, {fz}, and {q} are components of atom velocity and force and +atomic charge. There are several options for outputting atom coordinates. The {x}, {y}, {z} attributes write atom coordinates "unscaled", in the appropriate distance "units"_units.html (Angstroms, sigma, etc). Use {xs}, {ys}, {zs} if you want the coordinates "scaled" to the box size, so that each value is 0.0 to 1.0. If the simulation box is triclinic (tilted), then all atom coords will still be between 0.0 and 1.0. Use {xu}, {yu}, {zu} if you want the coordinates "unwrapped" by the image flags for each atom. Unwrapped means that if the atom has passed thru a periodic boundary one or more times, the value is printed for what the coordinate would be if it had not been wrapped back into the periodic box. Note that using {xu}, {yu}, {zu} means that the coordinate values may be far outside the box bounds printed with the snapshot. Using {xsu}, {ysu}, {zsu} is similar to using {xu}, {yu}, {zu}, except that the unwrapped coordinates are scaled by the box size. Atoms that have passed through a periodic boundary will have the corresponding cooordinate increased or decreased by 1.0. The image flags can be printed directly using the {ix}, {iy}, {iz} attributes. For periodic dimensions, they specify which image of the simulation box the atom is considered to be in. An image of 0 means it is inside the box as defined. A value of 2 means add 2 box lengths to get the true value. A value of -1 means subtract 1 box length to get the true value. LAMMPS updates these flags as atoms cross periodic boundaries during the simulation. The {mux}, {muy}, {muz} attributes are specific to dipolar systems defined with an atom style of {dipole}. They give the orientation of the atom's point dipole moment. The {mu} attribute gives the magnitude of the atom's dipole moment. The {radius} and {diameter} attributes are specific to spherical particles that have a finite size, such as those defined with an atom style of {sphere}. The {omegax}, {omegay}, and {omegaz} attributes are specific to finite-size spherical particles that have an angular velocity. Only certain atom styles, such as {sphere} define this quantity. The {angmomx}, {angmomy}, and {angmomz} attributes are specific to finite-size aspherical particles that have an angular momentum. Only the {ellipsoid} atom style defines this quantity. The {tqx}, {tqy}, {tqz} attributes are for finite-size particles that can sustain a rotational torque due to interactions with other particles. The {c_ID} and {c_ID\[N\]} attributes allow per-atom vectors or arrays calculated by a "compute"_compute.html to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the "compute"_compute.html command for details. There are computes for calculating the per-atom energy, stress, centro-symmetry parameter, and coordination number of individual atoms. Note that computes which calculate global or local quantities, as opposed to per-atom quantities, cannot be output in a dump custom command. Instead, global quantities can be output by the "thermo_style custom"_thermo_style.html command, and local quantities can be output by the dump local command. If {c_ID} is used as a attribute, then the per-atom vector calculated by the compute is printed. If {c_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the compute. The {f_ID} and {f_ID\[N\]} attributes allow vector or array per-atom quantities calculated by a "fix"_fix.html to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. The "fix ave/atom"_fix_ave_atom.html command is one that calculates per-atom quantities. Since it can time-average per-atom quantities produced by any "compute"_compute.html, "fix"_fix.html, or atom-style "variable"_variable.html, this allows those time-averaged results to be written to a dump file. If {f_ID} is used as a attribute, then the per-atom vector calculated by the fix is printed. If {f_ID\[N\]} is used, then N must be in the range from 1-M, which will print the Nth column of the M-length per-atom array calculated by the fix. The {v_name} attribute allows per-atom vectors calculated by a "variable"_variable.html to be output. The name in the attribute should be replaced by the actual name of the variable that has been defined previously in the input script. Only an atom-style variable can be referenced, since it is the only style that generates per-atom values. Variables of style {atom} can reference individual atom attributes, per-atom atom attributes, thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of creating quantities to output to a dump file. +The {d_name} and {i_name} attributes allow to output custom per atom +floating point or integer properties that are managed by +"fix property/atom"_fix_property_atom.html. + See "Section_modify"_Section_modify.html of the manual for information on how to add new compute and fix styles to LAMMPS to calculate per-atom quantities which could then be output into dump files. :line [Restrictions:] To write gzipped dump files, you must compile LAMMPS with the -DLAMMPS_GZIP option - see the "Making LAMMPS"_Section_start.html#start_2 section of the documentation. The {atom/mpiio}, {custom/mpiio}, and {xyz/mpiio} styles are part of the MPIIO package. They are only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. The {xtc} style is part of the XTC package. It is only enabled if LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. This is because some machines may not support the low-level XDR data format that XTC files are written with, which will result in a compile-time error when a low-level include file is not found. Putting this style in a package makes it easy to exclude from a LAMMPS build for those machines. However, the XTC package also includes two compatibility header files and associated functions, which should be a suitable substitute on machines that do not have the appropriate native header files. This option can be invoked at build time by adding -DLAMMPS_XDR to the CCFLAGS variable in the appropriate low-level Makefile, e.g. src/MAKE/Makefile.foo. This compatibility mode has been tested successfully on Cray XT3/XT4/XT5 and IBM BlueGene/L machines and should also work on IBM BG/P, and Windows XP/Vista/7 machines. [Related commands:] "dump image"_dump_image.html, "dump_modify"_dump_modify.html, "undump"_undump.html [Default:] The defaults for the {image} and {movie} styles are listed on the "dump image"_dump_image.html doc page. diff --git a/doc/fix_store_state.txt b/doc/fix_store_state.txt index bc3e9d2d8..e40a0f49c 100644 --- a/doc/fix_store_state.txt +++ b/doc/fix_store_state.txt @@ -1,127 +1,131 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line fix store/state command :h3 [Syntax:] fix ID group-ID store/state N input1 input2 ... keyword value ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l store/state = style name of this fix command :l N = store atom attributes every N steps, N = 0 for initial store only :l input = one or more atom attributes :l possible attributes = id, mol, type, mass, x, y, z, xs, ys, zs, xu, yu, zu, ix, iy, iz, vx, vy, vz, fx, fy, fz, q, mux, muy, muz, radius, omegax, omegay, omegaz, - angmomx, angmomy, angmomz, tqx, tqy, tqz - c_ID, c_ID\[N\], f_ID, f_ID\[N\], v_name :pre + angmomx, angmomy, angmomz, tqx, tqy, tqz, + c_ID, c_ID\[N\], f_ID, f_ID\[N\], v_name, + d_name, i_name :pre id = atom ID mol = molecule ID type = atom type mass = atom mass x,y,z = unscaled atom coordinates xs,ys,zs = scaled atom coordinates xu,yu,zu = unwrapped atom coordinates ix,iy,iz = box image that the atom is in vx,vy,vz = atom velocities fx,fy,fz = forces on atoms q = atom charge mux,muy,muz = orientation of dipolar atom radius = radius of spherical particle omegax,omegay,omegaz = angular velocity of spherical particle angmomx,angmomy,angmomz = angular momentum of aspherical particle tqx,tqy,tqz = torque on finite-size particles c_ID = per-atom vector calculated by a compute with ID c_ID\[I\] = Ith column of per-atom array calculated by a compute with ID f_ID = per-atom vector calculated by a fix with ID f_ID\[I\] = Ith column of per-atom array calculated by a fix with ID - v_name = per-atom vector calculated by an atom-style variable with name :pre + v_name = per-atom vector calculated by an atom-style variable with name + d_name = per-atom floating point vector managed by fix property/atom + i_name = per-atom integer vector managed by fix property/atom :pre zero or more keyword/value pairs may be appended :l keyword = {com} :l {com} value = {yes} or {no} :pre :ule [Examples:] fix 1 all store/state 0 x y z fix 1 all store/state 0 xu yu zu com yes fix 2 all store/state 1000 vx vy vz :pre [Description:] Define a fix that stores attributes for each atom in the group at the time the fix is defined. If {N} is 0, then the values are never updated, so this is a way of archiving an atom attribute at a given time for future use in a calculation or output. See the discussion of "output commands"_Section_howto.html#howto_15 that take fixes as inputs. And see for example, the "compute reduce"_compute_reduce.html, "fix ave/atom"_fix_ave_atom.html, "fix ave/histo"_fix_ave_histo.html, "fix ave/spatial"_fix_ave_spatial.html, and "atom-style variable"_variable.html commands. If {N} is not zero, then the attributes will be updated every {N} steps. IMPORTANT NOTE: Actually, only atom attributes specified by keywords like {xu} or {vy} are initially stored immediately at the point in your input script when the fix is defined. Attributes specified by a compute, fix, or variable are not initially stored until the first run following the fix definition begins. This is because calculating those attributes may require quantities that are not defined in between runs. The list of possible attributes is the same as that used by the "dump custom"_dump.html command, which describes their meaning. If the {com} keyword is set to {yes} then the {xu}, {yu}, and {zu} inputs store the position of each atom relative to the center-of-mass of the group of atoms, instead of storing the absolute position. This option is used by the "compute msd"_compute_msd.html command. The requested values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group. [Restart, fix_modify, output, run start/stop, minimize info:] This fix writes the per-atom values it stores to "binary restart files"_restart.html, so that the values can be restored when a simulation is restarted. See the "read_restart"_read_restart.html command for info on how to re-specify a fix in an input script that reads a restart file, so that the operation of the fix continues in an uninterrupted fashion. None of the "fix_modify"_fix_modify.html options are relevant to this fix. If a single input is specified, this fix produces a per-atom vector. If multiple inputs are specified, a per-atom array is produced where the number of columns for each atom is the number of inputs. These can be accessed by various "output commands"_Section_howto.html#howto_15. The per-atom values be accessed on any timestep. No parameter of this fix can be used with the {start/stop} keywords of the "run"_run.html command. This fix is not invoked during "energy minimization"_minimize.html. [Restrictions:] none [Related commands:] "dump custom"_dump.html, "compute -property/atom"_compute_property_atom.html, "variable"_variable.html +property/atom"_compute_property_atom.html, +"fix property/atom"_fix_property_atom.html, "variable"_variable.html [Default:] The option default is com = no. diff --git a/doc/molecule.html b/doc/molecule.html index 270a3742d..46c1cf346 100644 --- a/doc/molecule.html +++ b/doc/molecule.html @@ -1,399 +1,405 @@ <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> <HR> <H3>molecule command </H3> <P><B>Syntax:</B> </P> <PRE>molecule ID file1 file2 ... </PRE> <UL><LI>ID = user-assigned name for the molecule template <LI>file1,file2,... = names of files containing molecule descriptions </UL> <P><B>Examples:</B> </P> <PRE>molecule 1 mymol molecule 1 co2.txt h2o.txt molecule CO2 co2.txt </PRE> <P><B>Description:</B> </P> <P>Define a molecule template that can be used as part of other LAMMPS commands, typically to define a collection of particles as a bonded molecule or a rigid body. Commands that currently use molecule -templates (or will in the future) include: +templates include: </P> <UL><LI><A HREF = "fix_deposit.html">fix deposit</A> <LI><A HREF = "fix_pour.html">fix pour</A> <LI><A HREF = "fix_rigid.html">fix rigid/small</A> <LI><A HREF = "fix_shake.html">fix shake</A> <LI><A HREF = "fix_gcmc.html">fix gcmc</A> <LI><A HREF = "create_atoms.html">create_atoms</A> <LI><A HREF = "atom_style.html">atom_style template</A> </UL> <P>The ID of a molecule template can only contain alphanumeric characters and underscores. </P> <P>A single template can contain multiple molecules, listed one per file. Many of the commands listed above currently use only the first molecule in the template, and will issue a warning if the template contains multiple molecules. The <A HREF = "atom_style.html">atom_style template</A> command allows multiple-molecule templates to define a system with more than one templated molecule. </P> <P>IMPORTANT NOTE: When using the <A HREF = "atom_style.html">atom_style template</A> command with a molecule template that contains multiple molecules, you should insure the atom types, bond types, angle_types, etc in all the molecules are consistent. E.g. if one molecule represents H2O and another CO2, then you probably do not want each molecule file to define 2 atom types and a single bond type, because they will conflict with each other when a mixture system of H2O and CO2 molecules is defined, e.g. by the <A HREF = "read_data.html">read_data</A> command. Rather the H2O molecule should define atom types 1 and 2, and bond type 1. And the CO2 molecule should define atom types 3 and 4 (or atom types 3 and 2 if a single oxygen type is desired), and bond type 2. </P> <P>The format of an individual molecule file is similar to the data file read by the <A HREF = "read_data.html">read_data</A> commands, and is as follows. </P> <P>A molecule file has a header and a body. The header appears first. The first line of the header is always skipped; it typically contains a description of the file. Then lines are read one at a time. Lines can have a trailing comment starting with '#' that is ignored. If the line is blank (only whitespace after comment is deleted), it is skipped. If the line contains a header keyword, the corresponding value(s) is read from the line. If it doesn't contain a header keyword, the line begins the body of the file. </P> <P>The body of the file contains zero or more sections. The first line of a section has only a keyword. The next line is skipped. The remaining lines of the section contain values. The number of lines depends on the section keyword as described below. Zero or more blank lines can be used between sections. Sections can appear in any order, with a few exceptions as noted below. </P> <P>These are the recognized header keywords. Header lines can come in any order. The numeric value(s) are read from the beginning of the line. The keyword should appear at the end of the line. All these settings have default values, as explained below. A line need only appear if the value(s) are different than the default. </P> <UL><LI>N <I>atoms</I> = # of atoms N in molecule, default = 0 <LI>Nb <I>bonds</I> = # of bonds Nb in molecule, default = 0 <LI>Na <I>angles</I> = # of angles Na in molecule, default = 0 <LI>Nd <I>dihedrals</I> = # of dihedrals Nd in molecule, default = 0 <LI>Ni <I>impropers</I> = # of impropers Ni in molecule, default = 0 <LI>Mtotal <I>mass</I> = total mass of molecule <LI>Xc Yc Zc <I>com</I> = coordinates of center-of-mass of molecule <LI>Ixx Iyy Izz Ixy Ixz Iyz <I>inertia</I> = 6 components of inertia tensor of molecule </UL> <P>For <I>mass</I>, <I>com</I>, and <I>inertia</I>, the default is for LAMMPS to calculate this quantity itself if needed, assuming the molecules consists of a set of point particles. You typically only need to specify these values for a rigid body consisting of overlapping finite-size particles. </P> <P>The mass and center-of-mass coordinates (Xc,Yc,Zc) are self-explanatory. The 6 moments of inertia (ixx,iyy,izz,ixy,ixz,iyz) should be the values consistent with the current orientation of the rigid body around its center of mass. The values are with respect to the simulation box XYZ axes, not with respect to the prinicpal axes of the rigid body itself. LAMMPS performs the latter calculation internally. </P> <P>These are the allowed section keywords for the body of the file. </P> <UL><LI><I>Coords, Types, Charges, Diameters, Masses</I> = atom-property sections <LI><I>Bonds, Angles, Dihedrals, Impropers</I> = molecular topology sections <LI><I>Special Bond Counts, Special Bonds</I> = special neighbor info <LI><I>Shake Flags, Shake Atoms, Shake Bond Types</I> = SHAKE info </UL> +<P>If a Bonds section is specified then the Special Bond Counts and +Special Bonds sections must be also, since the latter is needed for +LAMMPS to properly exclude or weight bonded pairwise interactions +between bonded atoms. See the <A HREF = "special_bonds.html">special_bonds</A> +command for more details. +</P> <P>IMPORTANT NOTE: Whether a section is required depends on how the molecule template is used by other LAMMPS commands. For example, to add a molecule via the <A HREF = "fix_deposit.html">fix deposit</A> command, the Coords and Types sections are required. To add a rigid body via the <A HREF = "fix_pout.html">fix pour</A> command, the Bonds (Angles, etc) sections are not required, since the molecule will be treated as a rigid body. Some sections are optional. For example, the <A HREF = "fix_pour.html">fix pour</A> command can be used to add "molecules" which are clusters of finite-size granular particles. If the Diameters section is not specified, each particle in the molecule will have a default diameter of 1.0. See the doc pages for LAMMPS commands that use molecule templates for more details. </P> <P>Each section is listed below in alphabetic order. The format of each section is described including the number of lines it must contain and rules (if any) for whether it can appear in the data file. In each case the ID is ignored; it is simply included for readability, and should be a number from 1 to Nlines for the section, indicating which atom (or bond, etc) the entry applies to. The lines are assumed to be listed in order from 1 to Nlines, but LAMMPS does not check for this. </P> <HR> <P><I>Coords</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID x y z <LI>x,y,z = coordinate of atom </UL> <HR> <P><I>Types</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID type <LI>type = atom type of atom </UL> <HR> <P><I>Charges</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID q <LI>q = charge on atom </UL> <P>This section is only allowed for <A HREF = "atom_style.html">atom styles</A> that support charge. If this section is not included, the default charge on each atom in the molecule is 0.0. </P> <HR> <P><I>Diameters</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID diam <LI>diam = diameter of atom </UL> <P>This section is only allowed for <A HREF = "atom_style.html">atom styles</A> that support finite-size spherical particles, e.g. atom_style sphere. If not listed, the default diameter of each atom in the molecule is 1.0. </P> <HR> <P><I>Masses</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID mass <LI>mass = mass of atom </UL> <P>This section is only allowed for <A HREF = "atom_style.html">atom styles</A> that support per-atom mass, as opposed to per-type mass. See the <A HREF = "mass.html">mass</A> command for details. If this section is not included, the default mass for each atom is derived from its volume (see Diameters section) and a default density of 1.0, in <A HREF = "units.html">units</A> of mass/volume. </P> <HR> <P><I>Bonds</I> section: </P> <UL><LI>one line per bond <LI>line syntax: ID type atom1 atom2 <LI>type = bond type (1-Nbondtype) <LI>atom1,atom2 = IDs of atoms in bond </UL> <P>The IDs for the two atoms in each bond should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. </P> <HR> <P><I>Angles</I> section: </P> <UL><LI>one line per angle <LI>line syntax: ID type atom1 atom2 atom3 <LI>type = angle type (1-Nangletype) <LI>atom1,atom2,atom3 = IDs of atoms in angle </UL> <P>The IDs for the three atoms in each angle should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The 3 atoms are ordered linearly within the angle. Thus the central atom (around which the angle is computed) is the atom2 in the list. </P> <HR> <P><I>Dihedrals</I> section: </P> <UL><LI>one line per dihedral <LI>line syntax: ID type atom1 atom2 atom3 atom4 <LI>type = dihedral type (1-Ndihedraltype) <LI>atom1,atom2,atom3,atom4 = IDs of atoms in dihedral </UL> <P>The IDs for the four atoms in each dihedral should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The 4 atoms are ordered linearly within the dihedral. </P> <HR> <P><I>Impropers</I> section: </P> <UL><LI>one line per improper <LI>line syntax: ID type atom1 atom2 atom3 atom4 <LI>type = improper type (1-Nimpropertype) <LI>atom1,atom2,atom3,atom4 = IDs of atoms in improper </UL> <P>The IDs for the four atoms in each improper should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The ordering of the 4 atoms determines the definition of the improper angle used in the formula for the defined <A HREF = "improper_style.html">improper style</A>. See the doc pages for individual styles for details. </P> <HR> <P><I>Special Bond Counts</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID N1 N2 N3 <LI>N1 = # of 1-2 bonds <LI>N2 = # of 1-3 bonds <LI>N3 = # of 1-4 bonds </UL> <P>N1, N2, N3 are the number of 1-2, 1-3, 1-4 neighbors respectively of this atom within the topology of the molecule. See the <A HREF = "special_bonds.html">special_bonds</A> doc page for more discussion of 1-2, 1-3, 1-4 neighbors. If this section appears, the Special Bonds section must also appear. If this section is not specied, the atoms in the molecule will have no special bonds. </P> <HR> <P><I>Special Bonds</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID a b c d ... <LI>a,b,c,d,... = IDs of atoms in N1+N2+N3 special bonds </UL> <P>A, b, c, d, etc are the IDs of the n1+n2+n3 atoms that are 1-2, 1-3, 1-4 neighbors of this atom. The IDs should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The first N1 values should be the 1-2 neighbors, the next N2 should be the 1-3 neighbors, the last N3 should be the 1-4 neighbors. No atom ID should appear more than once. See the <A HREF = "special_bonds.html">special_bonds</A> doc page for more discussion of 1-2, 1-3, 1-4 neighbors. If this section appears, the Special Bond Counts section must also appear. If this section is not specied, the atoms in the molecule will have no special bonds. </P> <HR> <P><I>Shake Flags</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID flag <LI>flag = 0,1,2,3,4 </UL> <P>This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file, following this one. </P> <P>The meaning of the flag for each atom is as follows. See the <A HREF = "fix_shake.html">fix shake</A> doc page for a further description of SHAKE clusters. </P> <UL><LI>0 = not part of a SHAKE cluster <LI>1 = part of a SHAKE angle cluster (two bonds and the angle they form) <LI>2 = part of a 2-atom SHAKE cluster with a single bond <LI>3 = part of a 3-atom SHAKE cluster with two bonds <LI>4 = part of a 4-atom SHAKE cluster with three bonds </UL> <HR> <P><I>Shake Atoms</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID a b c d <LI>a,b,c,d = IDs of atoms in cluster </UL> <P>This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file. </P> <P>The a,b,c,d values are atom IDs (from 1 to Natoms) for all the atoms in the SHAKE cluster that this atom belongs to. The number of values that must appear is determined by the shake flag for the atom (see the Shake Flags section above). All atoms in a particular cluster should list their a,b,c,d values identically. </P> <P>If flag = 0, no a,b,c,d values are listed on the line, just the (ignored) ID. </P> <P>If flag = 1, a,b,c are listed, where a = ID of central atom in the angle, and b,c the other two atoms in the angle. </P> <P>If flag = 2, a,b are listed, where a = ID of atom in bond with the the lowest ID, and b = ID of atom in bond with the highest ID. </P> <P>If flag = 3, a,b,c are listed, where a = ID of central atom, and b,c = IDs of other two atoms bonded to the central atom. </P> <P>If flag = 4, a,b,c,d are listed, where a = ID of central atom, and b,c,d = IDs of other three atoms bonded to the central atom. </P> <P>See the <A HREF = "fix_shake.html">fix shake</A> doc page for a further description of SHAKE clusters. </P> <HR> <P><I>Shake Bond Types</I> section: </P> <UL><LI>one line per atom <LI>line syntax: ID a b c <LI>a,b,c = bond types (or angle type) of bonds (or angle) in cluster </UL> <P>This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file. </P> <P>The a,b,c values are bond types (from 1 to Nbondtypes) for all bonds in the SHAKE cluster that this atom belongs to. The number of values that must appear is determined by the shake flag for the atom (see the Shake Flags section above). All atoms in a particular cluster should list their a,b,c values identically. </P> <P>If flag = 0, no a,b,c values are listed on the line, just the (ignored) ID. </P> <P>If flag = 1, a,b,c are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section), and c = the angle type (1 to Nangletypes) of the angle between the 3 atoms. </P> <P>If flag = 2, only a is listed, where a = bondtype of the bond between the 2 atoms in the cluster. </P> <P>If flag = 3, a,b are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), and b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section). </P> <P>If flag = 4, a,b,c are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section), and c = bondtype of the bond between the central atom and the 3rd non-central atom (value d in the Shake Atoms section). </P> <P>See the <A HREF = "fix_shake.html">fix shake</A> doc page for a further description of SHAKE clusters. </P> <HR> <P><B>Restrictions:</B> none </P> <P><B>Related commands:</B> </P> <P><A HREF = "fix_deposit.html">fix deposit</A>, <A HREF = "fix_pour.html">fix pour</A>, <A HREF = "fix_gcmc.html">fix_gcmc</A> </P> <P><B>Default:</B> none </P> </HTML> diff --git a/doc/molecule.txt b/doc/molecule.txt index 1af3078c6..f43722285 100644 --- a/doc/molecule.txt +++ b/doc/molecule.txt @@ -1,394 +1,400 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line molecule command :h3 [Syntax:] molecule ID file1 file2 ... :pre ID = user-assigned name for the molecule template file1,file2,... = names of files containing molecule descriptions :ul [Examples:] molecule 1 mymol molecule 1 co2.txt h2o.txt molecule CO2 co2.txt :pre [Description:] Define a molecule template that can be used as part of other LAMMPS commands, typically to define a collection of particles as a bonded molecule or a rigid body. Commands that currently use molecule -templates (or will in the future) include: +templates include: "fix deposit"_fix_deposit.html "fix pour"_fix_pour.html "fix rigid/small"_fix_rigid.html "fix shake"_fix_shake.html "fix gcmc"_fix_gcmc.html "create_atoms"_create_atoms.html "atom_style template"_atom_style.html :ul The ID of a molecule template can only contain alphanumeric characters and underscores. A single template can contain multiple molecules, listed one per file. Many of the commands listed above currently use only the first molecule in the template, and will issue a warning if the template contains multiple molecules. The "atom_style template"_atom_style.html command allows multiple-molecule templates to define a system with more than one templated molecule. IMPORTANT NOTE: When using the "atom_style template"_atom_style.html command with a molecule template that contains multiple molecules, you should insure the atom types, bond types, angle_types, etc in all the molecules are consistent. E.g. if one molecule represents H2O and another CO2, then you probably do not want each molecule file to define 2 atom types and a single bond type, because they will conflict with each other when a mixture system of H2O and CO2 molecules is defined, e.g. by the "read_data"_read_data.html command. Rather the H2O molecule should define atom types 1 and 2, and bond type 1. And the CO2 molecule should define atom types 3 and 4 (or atom types 3 and 2 if a single oxygen type is desired), and bond type 2. The format of an individual molecule file is similar to the data file read by the "read_data"_read_data.html commands, and is as follows. A molecule file has a header and a body. The header appears first. The first line of the header is always skipped; it typically contains a description of the file. Then lines are read one at a time. Lines can have a trailing comment starting with '#' that is ignored. If the line is blank (only whitespace after comment is deleted), it is skipped. If the line contains a header keyword, the corresponding value(s) is read from the line. If it doesn't contain a header keyword, the line begins the body of the file. The body of the file contains zero or more sections. The first line of a section has only a keyword. The next line is skipped. The remaining lines of the section contain values. The number of lines depends on the section keyword as described below. Zero or more blank lines can be used between sections. Sections can appear in any order, with a few exceptions as noted below. These are the recognized header keywords. Header lines can come in any order. The numeric value(s) are read from the beginning of the line. The keyword should appear at the end of the line. All these settings have default values, as explained below. A line need only appear if the value(s) are different than the default. N {atoms} = # of atoms N in molecule, default = 0 Nb {bonds} = # of bonds Nb in molecule, default = 0 Na {angles} = # of angles Na in molecule, default = 0 Nd {dihedrals} = # of dihedrals Nd in molecule, default = 0 Ni {impropers} = # of impropers Ni in molecule, default = 0 Mtotal {mass} = total mass of molecule Xc Yc Zc {com} = coordinates of center-of-mass of molecule Ixx Iyy Izz Ixy Ixz Iyz {inertia} = 6 components of inertia tensor of molecule :ul For {mass}, {com}, and {inertia}, the default is for LAMMPS to calculate this quantity itself if needed, assuming the molecules consists of a set of point particles. You typically only need to specify these values for a rigid body consisting of overlapping finite-size particles. The mass and center-of-mass coordinates (Xc,Yc,Zc) are self-explanatory. The 6 moments of inertia (ixx,iyy,izz,ixy,ixz,iyz) should be the values consistent with the current orientation of the rigid body around its center of mass. The values are with respect to the simulation box XYZ axes, not with respect to the prinicpal axes of the rigid body itself. LAMMPS performs the latter calculation internally. These are the allowed section keywords for the body of the file. {Coords, Types, Charges, Diameters, Masses} = atom-property sections {Bonds, Angles, Dihedrals, Impropers} = molecular topology sections {Special Bond Counts, Special Bonds} = special neighbor info {Shake Flags, Shake Atoms, Shake Bond Types} = SHAKE info :ul +If a Bonds section is specified then the Special Bond Counts and +Special Bonds sections must be also, since the latter is needed for +LAMMPS to properly exclude or weight bonded pairwise interactions +between bonded atoms. See the "special_bonds"_special_bonds.html +command for more details. + IMPORTANT NOTE: Whether a section is required depends on how the molecule template is used by other LAMMPS commands. For example, to add a molecule via the "fix deposit"_fix_deposit.html command, the Coords and Types sections are required. To add a rigid body via the "fix pour"_fix_pout.html command, the Bonds (Angles, etc) sections are not required, since the molecule will be treated as a rigid body. Some sections are optional. For example, the "fix pour"_fix_pour.html command can be used to add "molecules" which are clusters of finite-size granular particles. If the Diameters section is not specified, each particle in the molecule will have a default diameter of 1.0. See the doc pages for LAMMPS commands that use molecule templates for more details. Each section is listed below in alphabetic order. The format of each section is described including the number of lines it must contain and rules (if any) for whether it can appear in the data file. In each case the ID is ignored; it is simply included for readability, and should be a number from 1 to Nlines for the section, indicating which atom (or bond, etc) the entry applies to. The lines are assumed to be listed in order from 1 to Nlines, but LAMMPS does not check for this. :line {Coords} section: one line per atom line syntax: ID x y z x,y,z = coordinate of atom :ul :line {Types} section: one line per atom line syntax: ID type type = atom type of atom :ul :line {Charges} section: one line per atom line syntax: ID q q = charge on atom :ul This section is only allowed for "atom styles"_atom_style.html that support charge. If this section is not included, the default charge on each atom in the molecule is 0.0. :line {Diameters} section: one line per atom line syntax: ID diam diam = diameter of atom :ul This section is only allowed for "atom styles"_atom_style.html that support finite-size spherical particles, e.g. atom_style sphere. If not listed, the default diameter of each atom in the molecule is 1.0. :line {Masses} section: one line per atom line syntax: ID mass mass = mass of atom :ul This section is only allowed for "atom styles"_atom_style.html that support per-atom mass, as opposed to per-type mass. See the "mass"_mass.html command for details. If this section is not included, the default mass for each atom is derived from its volume (see Diameters section) and a default density of 1.0, in "units"_units.html of mass/volume. :line {Bonds} section: one line per bond line syntax: ID type atom1 atom2 type = bond type (1-Nbondtype) atom1,atom2 = IDs of atoms in bond :ul The IDs for the two atoms in each bond should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. :line {Angles} section: one line per angle line syntax: ID type atom1 atom2 atom3 type = angle type (1-Nangletype) atom1,atom2,atom3 = IDs of atoms in angle :ul The IDs for the three atoms in each angle should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The 3 atoms are ordered linearly within the angle. Thus the central atom (around which the angle is computed) is the atom2 in the list. :line {Dihedrals} section: one line per dihedral line syntax: ID type atom1 atom2 atom3 atom4 type = dihedral type (1-Ndihedraltype) atom1,atom2,atom3,atom4 = IDs of atoms in dihedral :ul The IDs for the four atoms in each dihedral should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The 4 atoms are ordered linearly within the dihedral. :line {Impropers} section: one line per improper line syntax: ID type atom1 atom2 atom3 atom4 type = improper type (1-Nimpropertype) atom1,atom2,atom3,atom4 = IDs of atoms in improper :ul The IDs for the four atoms in each improper should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The ordering of the 4 atoms determines the definition of the improper angle used in the formula for the defined "improper style"_improper_style.html. See the doc pages for individual styles for details. :line {Special Bond Counts} section: one line per atom line syntax: ID N1 N2 N3 N1 = # of 1-2 bonds N2 = # of 1-3 bonds N3 = # of 1-4 bonds :ul N1, N2, N3 are the number of 1-2, 1-3, 1-4 neighbors respectively of this atom within the topology of the molecule. See the "special_bonds"_special_bonds.html doc page for more discussion of 1-2, 1-3, 1-4 neighbors. If this section appears, the Special Bonds section must also appear. If this section is not specied, the atoms in the molecule will have no special bonds. :line {Special Bonds} section: one line per atom line syntax: ID a b c d ... a,b,c,d,... = IDs of atoms in N1+N2+N3 special bonds :ul A, b, c, d, etc are the IDs of the n1+n2+n3 atoms that are 1-2, 1-3, 1-4 neighbors of this atom. The IDs should be values from 1 to Natoms, where Natoms = # of atoms in the molecule. The first N1 values should be the 1-2 neighbors, the next N2 should be the 1-3 neighbors, the last N3 should be the 1-4 neighbors. No atom ID should appear more than once. See the "special_bonds"_special_bonds.html doc page for more discussion of 1-2, 1-3, 1-4 neighbors. If this section appears, the Special Bond Counts section must also appear. If this section is not specied, the atoms in the molecule will have no special bonds. :line {Shake Flags} section: one line per atom line syntax: ID flag flag = 0,1,2,3,4 :ul This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file, following this one. The meaning of the flag for each atom is as follows. See the "fix shake"_fix_shake.html doc page for a further description of SHAKE clusters. 0 = not part of a SHAKE cluster 1 = part of a SHAKE angle cluster (two bonds and the angle they form) 2 = part of a 2-atom SHAKE cluster with a single bond 3 = part of a 3-atom SHAKE cluster with two bonds 4 = part of a 4-atom SHAKE cluster with three bonds :ul :line {Shake Atoms} section: one line per atom line syntax: ID a b c d a,b,c,d = IDs of atoms in cluster :ul This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file. The a,b,c,d values are atom IDs (from 1 to Natoms) for all the atoms in the SHAKE cluster that this atom belongs to. The number of values that must appear is determined by the shake flag for the atom (see the Shake Flags section above). All atoms in a particular cluster should list their a,b,c,d values identically. If flag = 0, no a,b,c,d values are listed on the line, just the (ignored) ID. If flag = 1, a,b,c are listed, where a = ID of central atom in the angle, and b,c the other two atoms in the angle. If flag = 2, a,b are listed, where a = ID of atom in bond with the the lowest ID, and b = ID of atom in bond with the highest ID. If flag = 3, a,b,c are listed, where a = ID of central atom, and b,c = IDs of other two atoms bonded to the central atom. If flag = 4, a,b,c,d are listed, where a = ID of central atom, and b,c,d = IDs of other three atoms bonded to the central atom. See the "fix shake"_fix_shake.html doc page for a further description of SHAKE clusters. :line {Shake Bond Types} section: one line per atom line syntax: ID a b c a,b,c = bond types (or angle type) of bonds (or angle) in cluster :ul This section is only needed when molecules created using the template will be constrained by SHAKE via the "fix shake" command. The other two Shake sections must also appear in the file. The a,b,c values are bond types (from 1 to Nbondtypes) for all bonds in the SHAKE cluster that this atom belongs to. The number of values that must appear is determined by the shake flag for the atom (see the Shake Flags section above). All atoms in a particular cluster should list their a,b,c values identically. If flag = 0, no a,b,c values are listed on the line, just the (ignored) ID. If flag = 1, a,b,c are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section), and c = the angle type (1 to Nangletypes) of the angle between the 3 atoms. If flag = 2, only a is listed, where a = bondtype of the bond between the 2 atoms in the cluster. If flag = 3, a,b are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), and b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section). If flag = 4, a,b,c are listed, where a = bondtype of the bond between the central atom and the first non-central atom (value b in the Shake Atoms section), b = bondtype of the bond between the central atom and the 2nd non-central atom (value c in the Shake Atoms section), and c = bondtype of the bond between the central atom and the 3rd non-central atom (value d in the Shake Atoms section). See the "fix shake"_fix_shake.html doc page for a further description of SHAKE clusters. :line [Restrictions:] none [Related commands:] "fix deposit"_fix_deposit.html, "fix pour"_fix_pour.html, "fix_gcmc"_fix_gcmc.html [Default:] none diff --git a/examples/COUPLE/lammps_quest/lmpqst.cpp b/examples/COUPLE/lammps_quest/lmpqst.cpp index a9f364a23..e7f2d92c1 100644 --- a/examples/COUPLE/lammps_quest/lmpqst.cpp +++ b/examples/COUPLE/lammps_quest/lmpqst.cpp @@ -1,264 +1,270 @@ // lmpqst = umbrella driver to couple LAMMPS + Quest // for MD using quantum forces // Syntax: lmpqst Niter in.lammps in.quest // Niter = # of MD iterations // in.lammps = LAMMPS input script // in.quest = Quest input script #include "mpi.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "stdint.h" #include "many2one.h" #include "one2many.h" #include "files.h" #include "memory.h" #include "error.h" #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) #include "lmppath.h" #include QUOTE(LMPPATH/src/lammps.h) #include QUOTE(LMPPATH/src/library.h) #include QUOTE(LMPPATH/src/input.h) #include QUOTE(LMPPATH/src/modify.h) #include QUOTE(LMPPATH/src/fix.h) #include QUOTE(LMPPATH/src/fix_external.h) #include "qstexe.h" using namespace LAMMPS_NS; #define ANGSTROM_per_BOHR 0.529 #define EV_per_RYDBERG 13.6056923 void quest_callback(void *, bigint, int, int *, double **, double **); struct Info { int me; Memory *memory; LAMMPS *lmp; char *quest_input; }; /* ---------------------------------------------------------------------- */ int main(int narg, char **arg) { int n; char str[128]; // setup MPI MPI_Init(&narg,&arg); MPI_Comm comm = MPI_COMM_WORLD; int me,nprocs; MPI_Comm_rank(comm,&me); MPI_Comm_size(comm,&nprocs); Memory *memory = new Memory(comm); Error *error = new Error(comm); // command-line args if (narg != 4) error->all("Syntax: lmpqst Niter in.lammps in.quest"); int niter = atoi(arg[1]); n = strlen(arg[2]) + 1; char *lammps_input = new char[n]; strcpy(lammps_input,arg[2]); n = strlen(arg[3]) + 1; char *quest_input = new char[n]; strcpy(quest_input,arg[3]); // instantiate LAMMPS LAMMPS *lmp = new LAMMPS(0,NULL,MPI_COMM_WORLD); // create simulation in LAMMPS from in.lammps lmp->input->file(lammps_input); // make info avaiable to callback function Info info; info.me = me; info.memory = memory; info.lmp = lmp; info.quest_input = quest_input; // set callback to Quest inside fix external // this could also be done thru Python, using a ctypes callback int ifix = lmp->modify->find_fix("2"); FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix]; fix->set_callback(quest_callback,&info); // run LAMMPS for Niter // each time it needs forces, it will invoke quest_callback sprintf(str,"run %d",niter); lmp->input->one(str); // clean up delete lmp; delete memory; delete error; delete [] lammps_input; delete [] quest_input; MPI_Finalize(); } /* ---------------------------------------------------------------------- callback to Quest with atom IDs and coords from each proc invoke Quest to compute forces, load them into f for LAMMPS to use f can be NULL if proc owns no atoms ------------------------------------------------------------------------- */ void quest_callback(void *ptr, bigint ntimestep, int nlocal, int *id, double **x, double **f) { int i,j; char str[128]; Info *info = (Info *) ptr; // boxlines = LAMMPS box size converted into Quest lattice vectors char **boxlines = NULL; if (info->me == 0) { boxlines = new char*[3]; for (i = 0; i < 3; i++) boxlines[i] = new char[128]; } double boxxlo = *((double *) lammps_extract_global(info->lmp,"boxxlo")); double boxxhi = *((double *) lammps_extract_global(info->lmp,"boxxhi")); double boxylo = *((double *) lammps_extract_global(info->lmp,"boxylo")); double boxyhi = *((double *) lammps_extract_global(info->lmp,"boxyhi")); double boxzlo = *((double *) lammps_extract_global(info->lmp,"boxzlo")); double boxzhi = *((double *) lammps_extract_global(info->lmp,"boxzhi")); + double boxxy = *((double *) lammps_extract_global(info->lmp,"xy")); + double boxxz = *((double *) lammps_extract_global(info->lmp,"xz")); + double boxyz = *((double *) lammps_extract_global(info->lmp,"yz")); double xprd = (boxxhi-boxxlo)/ANGSTROM_per_BOHR; double yprd = (boxyhi-boxylo)/ANGSTROM_per_BOHR; double zprd = (boxzhi-boxzlo)/ANGSTROM_per_BOHR; + double xy = boxxy/ANGSTROM_per_BOHR; + double xz = boxxz/ANGSTROM_per_BOHR; + double yz = boxyz/ANGSTROM_per_BOHR; if (info->me == 0) { sprintf(boxlines[0],"%g %g %g\n",xprd,0.0,0.0); - sprintf(boxlines[1],"%g %g %g\n",0.0,yprd,0.0); - sprintf(boxlines[2],"%g %g %g\n",0.0,0.0,zprd); + sprintf(boxlines[1],"%g %g %g\n",xy,yprd,0.0); + sprintf(boxlines[2],"%g %g %g\n",xz,yz,zprd); } // xlines = x for atoms on each proc converted to text lines // xlines is suitable for insertion into Quest input file // convert LAMMPS Angstroms to Quest bohr int natoms; MPI_Allreduce(&nlocal,&natoms,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD); Many2One *lmp2qst = new Many2One(MPI_COMM_WORLD); lmp2qst->setup(nlocal,id,natoms); char **xlines = NULL; double **xquest = NULL; if (info->me == 0) { xquest = info->memory->create_2d_double_array(natoms,3,"lmpqst:xquest"); xlines = new char*[natoms]; for (i = 0; i < natoms; i++) xlines[i] = new char[128]; } if (info->me == 0) lmp2qst->gather(&x[0][0],3,&xquest[0][0]); else lmp2qst->gather(&x[0][0],3,NULL); if (info->me == 0) { for (i = 0; i < natoms; i++) { xquest[i][0] /= ANGSTROM_per_BOHR; xquest[i][1] /= ANGSTROM_per_BOHR; xquest[i][2] /= ANGSTROM_per_BOHR; } for (i = 0; i < natoms; i++) { sprintf(xlines[i],"%d %d %g %g %g\n",i+1,1, xquest[i][0],xquest[i][1],xquest[i][2]); } } // one-processor tasks: // whack all lcao.* files // cp quest_input to lcao.in // replace atom coords section of lcao.in with new atom coords // run Quest on one proc, save screen output to file // flines = atom forces extracted from Quest screen file // fquest = atom forces // convert Quest Ryd/bohr to LAMMPS eV/Angstrom char **flines = NULL; double **fquest = NULL; if (info->me == 0) { fquest = info->memory->create_2d_double_array(natoms,3,"lmpqst:fquest"); flines = new char*[natoms]; for (i = 0; i < natoms; i++) flines[i] = new char[128]; } if (info->me == 0) { system("rm lcao.*"); sprintf(str,"cp %s lcao.in",info->quest_input); system(str); sprintf(str,"cp %s lcao.x",QUOTE(QUEST)); system(str); replace("lcao.in","primitive lattice vectors",3,boxlines); replace("lcao.in","atom, type, position vector",natoms,xlines); system("lcao.x > lcao.screen"); extract("lcao.screen","atom x force " "y force z force",natoms,flines); int itmp; for (i = 0; i < natoms; i++) sscanf(flines[i],"%d %lg %lg %lg",&itmp, &fquest[i][0],&fquest[i][1],&fquest[i][2]); for (i = 0; i < natoms; i++) { fquest[i][0] *= EV_per_RYDBERG / ANGSTROM_per_BOHR; fquest[i][1] *= EV_per_RYDBERG / ANGSTROM_per_BOHR; fquest[i][2] *= EV_per_RYDBERG / ANGSTROM_per_BOHR; } } // convert fquest on one proc into f for atoms on each proc One2Many *qst2lmp = new One2Many(MPI_COMM_WORLD); qst2lmp->setup(natoms,nlocal,id); double *fvec = NULL; if (f) fvec = &f[0][0]; if (info->me == 0) qst2lmp->scatter(&fquest[0][0],3,fvec); else qst2lmp->scatter(NULL,3,fvec); // clean up // some data only exists on proc 0 delete lmp2qst; delete qst2lmp; info->memory->destroy_2d_double_array(xquest); info->memory->destroy_2d_double_array(fquest); if (boxlines) { for (i = 0; i < 3; i++) delete [] boxlines[i]; delete [] boxlines; } if (xlines) { for (i = 0; i < natoms; i++) delete [] xlines[i]; delete [] xlines; } if (flines) { for (i = 0; i < natoms; i++) delete [] flines[i]; delete [] flines; } } diff --git a/src/KSPACE/pppm.cpp b/src/KSPACE/pppm.cpp index 5f3f8ce2d..4d45ef222 100644 --- a/src/KSPACE/pppm.cpp +++ b/src/KSPACE/pppm.cpp @@ -1,3488 +1,3493 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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: Roy Pollock (LLNL), Paul Crozier (SNL) per-atom energy/virial & group/group energy/force added by Stan Moore (BYU) analytic diff (2 FFT) option added by Rolf Isele-Holder (Aachen University) triclinic added by Stan Moore (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "math.h" #include "pppm.h" #include "atom.h" #include "comm.h" #include "gridcomm.h" #include "neighbor.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "domain.h" #include "fft3d_wrap.h" #include "remap_wrap.h" #include "memory.h" #include "error.h" #include "math_const.h" #include "math_special.h" using namespace LAMMPS_NS; using namespace MathConst; using namespace MathSpecial; #define MAXORDER 7 #define OFFSET 16384 #define LARGE 10000.0 #define SMALL 0.00001 #define EPS_HOC 1.0e-7 enum{REVERSE_RHO}; enum{FORWARD_IK,FORWARD_AD,FORWARD_IK_PERATOM,FORWARD_AD_PERATOM}; #ifdef FFT_SINGLE #define ZEROF 0.0f #define ONEF 1.0f #else #define ZEROF 0.0 #define ONEF 1.0 #endif /* ---------------------------------------------------------------------- */ PPPM::PPPM(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg) { if (narg < 1) error->all(FLERR,"Illegal kspace_style pppm command"); pppmflag = 1; group_group_enable = 1; accuracy_relative = fabs(force->numeric(FLERR,arg[0])); nfactors = 3; factors = new int[nfactors]; factors[0] = 2; factors[1] = 3; factors[2] = 5; MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); density_brick = vdx_brick = vdy_brick = vdz_brick = NULL; density_fft = NULL; u_brick = NULL; v0_brick = v1_brick = v2_brick = v3_brick = v4_brick = v5_brick = NULL; greensfn = NULL; work1 = work2 = NULL; vg = NULL; fkx = fky = fkz = NULL; sf_precoeff1 = sf_precoeff2 = sf_precoeff3 = sf_precoeff4 = sf_precoeff5 = sf_precoeff6 = NULL; density_A_brick = density_B_brick = NULL; density_A_fft = density_B_fft = NULL; gf_b = NULL; rho1d = rho_coeff = drho1d = drho_coeff = NULL; fft1 = fft2 = NULL; remap = NULL; cg = NULL; cg_peratom = NULL; nmax = 0; part2grid = NULL; peratom_allocate_flag = 0; group_allocate_flag = 0; // define acons coefficients for estimation of kspace errors // see JCP 109, pg 7698 for derivation of coefficients // higher order coefficients may be computed if needed memory->create(acons,8,7,"pppm:acons"); acons[1][0] = 2.0 / 3.0; acons[2][0] = 1.0 / 50.0; acons[2][1] = 5.0 / 294.0; acons[3][0] = 1.0 / 588.0; acons[3][1] = 7.0 / 1440.0; acons[3][2] = 21.0 / 3872.0; acons[4][0] = 1.0 / 4320.0; acons[4][1] = 3.0 / 1936.0; acons[4][2] = 7601.0 / 2271360.0; acons[4][3] = 143.0 / 28800.0; acons[5][0] = 1.0 / 23232.0; acons[5][1] = 7601.0 / 13628160.0; acons[5][2] = 143.0 / 69120.0; acons[5][3] = 517231.0 / 106536960.0; acons[5][4] = 106640677.0 / 11737571328.0; acons[6][0] = 691.0 / 68140800.0; acons[6][1] = 13.0 / 57600.0; acons[6][2] = 47021.0 / 35512320.0; acons[6][3] = 9694607.0 / 2095994880.0; acons[6][4] = 733191589.0 / 59609088000.0; acons[6][5] = 326190917.0 / 11700633600.0; acons[7][0] = 1.0 / 345600.0; acons[7][1] = 3617.0 / 35512320.0; acons[7][2] = 745739.0 / 838397952.0; acons[7][3] = 56399353.0 / 12773376000.0; acons[7][4] = 25091609.0 / 1560084480.0; acons[7][5] = 1755948832039.0 / 36229939200000.0; acons[7][6] = 4887769399.0 / 37838389248.0; } /* ---------------------------------------------------------------------- free all memory ------------------------------------------------------------------------- */ PPPM::~PPPM() { delete [] factors; deallocate(); if (peratom_allocate_flag) deallocate_peratom(); if (group_allocate_flag) deallocate_groups(); memory->destroy(part2grid); memory->destroy(acons); } /* ---------------------------------------------------------------------- called once before run ------------------------------------------------------------------------- */ void PPPM::init() { if (me == 0) { if (screen) fprintf(screen,"PPPM initialization ...\n"); if (logfile) fprintf(logfile,"PPPM initialization ...\n"); } // error check triclinic_check(); if (domain->triclinic && differentiation_flag == 1) error->all(FLERR,"Cannot (yet) use PPPM with triclinic box " "and kspace_modify diff ad"); if (domain->triclinic && slabflag) error->all(FLERR,"Cannot (yet) use PPPM with triclinic box and " "slab correction"); if (domain->dimension == 2) error->all(FLERR, "Cannot use PPPM with 2d simulation"); if (!atom->q_flag) error->all(FLERR,"Kspace style requires atom attribute q"); if (slabflag == 0 && domain->nonperiodic > 0) error->all(FLERR,"Cannot use nonperiodic boundaries with PPPM"); if (slabflag) { if (domain->xperiodic != 1 || domain->yperiodic != 1 || domain->boundary[2][0] != 1 || domain->boundary[2][1] != 1) error->all(FLERR,"Incorrect boundaries with slab PPPM"); } if (order < 2 || order > MAXORDER) { char str[128]; sprintf(str,"PPPM order cannot be < 2 or > than %d",MAXORDER); error->all(FLERR,str); } // extract short-range Coulombic cutoff from pair style triclinic = domain->triclinic; pair_check(); int itmp = 0; double *p_cutoff = (double *) force->pair->extract("cut_coul",itmp); if (p_cutoff == NULL) error->all(FLERR,"KSpace style is incompatible with Pair style"); cutoff = *p_cutoff; + // a TIP4P pair style requires a matching long-range solver + if (!tip4pflag && force->pair->tip4pflag) + error->all(FLERR,"Using a TIP4P pair style without a " + "compatible kspace style"); + // if kspace is TIP4P, extract TIP4P params from pair style // bond/angle are not yet init(), so insure equilibrium request is valid qdist = 0.0; if (tip4pflag) { double *p_qdist = (double *) force->pair->extract("qdist",itmp); int *p_typeO = (int *) force->pair->extract("typeO",itmp); int *p_typeH = (int *) force->pair->extract("typeH",itmp); int *p_typeA = (int *) force->pair->extract("typeA",itmp); int *p_typeB = (int *) force->pair->extract("typeB",itmp); if (!p_qdist || !p_typeO || !p_typeH || !p_typeA || !p_typeB) error->all(FLERR,"KSpace style is incompatible with Pair style"); qdist = *p_qdist; typeO = *p_typeO; typeH = *p_typeH; int typeA = *p_typeA; int typeB = *p_typeB; if (force->angle == NULL || force->bond == NULL || force->angle->setflag == NULL || force->bond->setflag == NULL) error->all(FLERR,"Bond and angle potentials must be defined for TIP4P"); if (typeA < 1 || typeA > atom->nangletypes || force->angle->setflag[typeA] == 0) error->all(FLERR,"Bad TIP4P angle type for PPPM/TIP4P"); if (typeB < 1 || typeB > atom->nbondtypes || force->bond->setflag[typeB] == 0) error->all(FLERR,"Bad TIP4P bond type for PPPM/TIP4P"); double theta = force->angle->equilibrium_angle(typeA); double blen = force->bond->equilibrium_distance(typeB); alpha = qdist / (cos(0.5*theta) * blen); if (domain->triclinic) error->all(FLERR,"Cannot (yet) use PPPM with triclinic box and TIP4P"); } // compute qsum & qsqsum and warn if not charge-neutral scale = 1.0; qqrd2e = force->qqrd2e; qsum_qsq(0); natoms_original = atom->natoms; // set accuracy (force units) from accuracy_relative or accuracy_absolute if (accuracy_absolute >= 0.0) accuracy = accuracy_absolute; else accuracy = accuracy_relative * two_charge_force; // free all arrays previously allocated deallocate(); if (peratom_allocate_flag) deallocate_peratom(); if (group_allocate_flag) deallocate_groups(); // setup FFT grid resolution and g_ewald // normally one iteration thru while loop is all that is required // if grid stencil does not extend beyond neighbor proc // or overlap is allowed, then done // else reduce order and try again int (*procneigh)[2] = comm->procneigh; GridComm *cgtmp = NULL; int iteration = 0; while (order >= minorder) { if (iteration && me == 0) error->warning(FLERR,"Reducing PPPM order b/c stencil extends " "beyond nearest neighbor processor"); if (stagger_flag && !differentiation_flag) compute_gf_denom(); set_grid_global(); set_grid_local(); if (overlap_allowed) break; cgtmp = new GridComm(lmp,world,1,1, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out, procneigh[0][0],procneigh[0][1],procneigh[1][0], procneigh[1][1],procneigh[2][0],procneigh[2][1]); cgtmp->ghost_notify(); if (!cgtmp->ghost_overlap()) break; delete cgtmp; order--; iteration++; } if (order < minorder) error->all(FLERR,"PPPM order < minimum allowed order"); if (!overlap_allowed && cgtmp->ghost_overlap()) error->all(FLERR,"PPPM grid stencil extends " "beyond nearest neighbor processor"); if (cgtmp) delete cgtmp; // adjust g_ewald if (!gewaldflag) adjust_gewald(); // calculate the final accuracy double estimated_accuracy = final_accuracy(); // print stats int ngrid_max,nfft_both_max; MPI_Allreduce(&ngrid,&ngrid_max,1,MPI_INT,MPI_MAX,world); MPI_Allreduce(&nfft_both,&nfft_both_max,1,MPI_INT,MPI_MAX,world); if (me == 0) { #ifdef FFT_SINGLE const char fft_prec[] = "single"; #else const char fft_prec[] = "double"; #endif if (screen) { fprintf(screen," G vector (1/distance) = %g\n",g_ewald); fprintf(screen," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm); fprintf(screen," stencil order = %d\n",order); fprintf(screen," estimated absolute RMS force accuracy = %g\n", estimated_accuracy); fprintf(screen," estimated relative force accuracy = %g\n", estimated_accuracy/two_charge_force); fprintf(screen," using %s precision FFTs\n",fft_prec); fprintf(screen," 3d grid and FFT values/proc = %d %d\n", ngrid_max,nfft_both_max); } if (logfile) { fprintf(logfile," G vector (1/distance) = %g\n",g_ewald); fprintf(logfile," grid = %d %d %d\n",nx_pppm,ny_pppm,nz_pppm); fprintf(logfile," stencil order = %d\n",order); fprintf(logfile," estimated absolute RMS force accuracy = %g\n", estimated_accuracy); fprintf(logfile," estimated relative force accuracy = %g\n", estimated_accuracy/two_charge_force); fprintf(logfile," using %s precision FFTs\n",fft_prec); fprintf(logfile," 3d grid and FFT values/proc = %d %d\n", ngrid_max,nfft_both_max); } } // allocate K-space dependent memory // don't invoke allocate peratom() or group(), will be allocated when needed allocate(); cg->ghost_notify(); cg->setup(); // pre-compute Green's function denomiator expansion // pre-compute 1d charge distribution coefficients compute_gf_denom(); if (differentiation_flag == 1) compute_sf_precoeff(); compute_rho_coeff(); } /* ---------------------------------------------------------------------- adjust PPPM coeffs, called initially and whenever volume has changed ------------------------------------------------------------------------- */ void PPPM::setup() { if (triclinic) { setup_triclinic(); return; } int i,j,k,n; double *prd; // volume-dependent factors // adjust z dimension for 2d slab PPPM // z dimension for 3d PPPM is zprd since slab_volfactor = 1.0 if (triclinic == 0) prd = domain->prd; else prd = domain->prd_lamda; double xprd = prd[0]; double yprd = prd[1]; double zprd = prd[2]; double zprd_slab = zprd*slab_volfactor; volume = xprd * yprd * zprd_slab; delxinv = nx_pppm/xprd; delyinv = ny_pppm/yprd; delzinv = nz_pppm/zprd_slab; delvolinv = delxinv*delyinv*delzinv; double unitkx = (MY_2PI/xprd); double unitky = (MY_2PI/yprd); double unitkz = (MY_2PI/zprd_slab); // fkx,fky,fkz for my FFT grid pts double per; for (i = nxlo_fft; i <= nxhi_fft; i++) { per = i - nx_pppm*(2*i/nx_pppm); fkx[i] = unitkx*per; } for (i = nylo_fft; i <= nyhi_fft; i++) { per = i - ny_pppm*(2*i/ny_pppm); fky[i] = unitky*per; } for (i = nzlo_fft; i <= nzhi_fft; i++) { per = i - nz_pppm*(2*i/nz_pppm); fkz[i] = unitkz*per; } // virial coefficients double sqk,vterm; n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) { for (j = nylo_fft; j <= nyhi_fft; j++) { for (i = nxlo_fft; i <= nxhi_fft; i++) { sqk = fkx[i]*fkx[i] + fky[j]*fky[j] + fkz[k]*fkz[k]; if (sqk == 0.0) { vg[n][0] = 0.0; vg[n][1] = 0.0; vg[n][2] = 0.0; vg[n][3] = 0.0; vg[n][4] = 0.0; vg[n][5] = 0.0; } else { vterm = -2.0 * (1.0/sqk + 0.25/(g_ewald*g_ewald)); vg[n][0] = 1.0 + vterm*fkx[i]*fkx[i]; vg[n][1] = 1.0 + vterm*fky[j]*fky[j]; vg[n][2] = 1.0 + vterm*fkz[k]*fkz[k]; vg[n][3] = vterm*fkx[i]*fky[j]; vg[n][4] = vterm*fkx[i]*fkz[k]; vg[n][5] = vterm*fky[j]*fkz[k]; } n++; } } } if (differentiation_flag == 1) compute_gf_ad(); else compute_gf_ik(); } /* ---------------------------------------------------------------------- adjust PPPM coeffs, called initially and whenever volume has changed for a triclinic system ------------------------------------------------------------------------- */ void PPPM::setup_triclinic() { int i,j,k,n; double *prd; // volume-dependent factors // adjust z dimension for 2d slab PPPM // z dimension for 3d PPPM is zprd since slab_volfactor = 1.0 prd = domain->prd; double xprd = prd[0]; double yprd = prd[1]; double zprd = prd[2]; double zprd_slab = zprd*slab_volfactor; volume = xprd * yprd * zprd_slab; // use lamda (0-1) coordinates delxinv = nx_pppm; delyinv = ny_pppm; delzinv = nz_pppm; delvolinv = delxinv*delyinv*delzinv/volume; // fkx,fky,fkz for my FFT grid pts double per_i,per_j,per_k; n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) { per_k = k - nz_pppm*(2*k/nz_pppm); for (j = nylo_fft; j <= nyhi_fft; j++) { per_j = j - ny_pppm*(2*j/ny_pppm); for (i = nxlo_fft; i <= nxhi_fft; i++) { per_i = i - nx_pppm*(2*i/nx_pppm); double unitk_lamda[3]; unitk_lamda[0] = 2.0*MY_PI*per_i; unitk_lamda[1] = 2.0*MY_PI*per_j; unitk_lamda[2] = 2.0*MY_PI*per_k; x2lamdaT(&unitk_lamda[0],&unitk_lamda[0]); fkx[n] = unitk_lamda[0]; fky[n] = unitk_lamda[1]; fkz[n] = unitk_lamda[2]; n++; } } } // virial coefficients double sqk,vterm; for (n = 0; n < nfft; n++) { sqk = fkx[n]*fkx[n] + fky[n]*fky[n] + fkz[n]*fkz[n]; if (sqk == 0.0) { vg[n][0] = 0.0; vg[n][1] = 0.0; vg[n][2] = 0.0; vg[n][3] = 0.0; vg[n][4] = 0.0; vg[n][5] = 0.0; } else { vterm = -2.0 * (1.0/sqk + 0.25/(g_ewald*g_ewald)); vg[n][0] = 1.0 + vterm*fkx[n]*fkx[n]; vg[n][1] = 1.0 + vterm*fky[n]*fky[n]; vg[n][2] = 1.0 + vterm*fkz[n]*fkz[n]; vg[n][3] = vterm*fkx[n]*fky[n]; vg[n][4] = vterm*fkx[n]*fkz[n]; vg[n][5] = vterm*fky[n]*fkz[n]; } } compute_gf_ik_triclinic(); } /* ---------------------------------------------------------------------- reset local grid arrays and communication stencils called by fix balance b/c it changed sizes of processor sub-domains ------------------------------------------------------------------------- */ void PPPM::setup_grid() { // free all arrays previously allocated deallocate(); if (peratom_allocate_flag) deallocate_peratom(); if (group_allocate_flag) deallocate_groups(); // reset portion of global grid that each proc owns set_grid_local(); // reallocate K-space dependent memory // check if grid communication is now overlapping if not allowed // don't invoke allocate peratom() or group(), will be allocated when needed allocate(); cg->ghost_notify(); if (overlap_allowed == 0 && cg->ghost_overlap()) error->all(FLERR,"PPPM grid stencil extends " "beyond nearest neighbor processor"); cg->setup(); // pre-compute Green's function denomiator expansion // pre-compute 1d charge distribution coefficients compute_gf_denom(); if (differentiation_flag == 1) compute_sf_precoeff(); compute_rho_coeff(); // pre-compute volume-dependent coeffs setup(); } /* ---------------------------------------------------------------------- compute the PPPM long-range force, energy, virial ------------------------------------------------------------------------- */ void PPPM::compute(int eflag, int vflag) { int i,j; // set energy/virial flags // invoke allocate_peratom() if needed for first time if (eflag || vflag) ev_setup(eflag,vflag); else evflag = evflag_atom = eflag_global = vflag_global = eflag_atom = vflag_atom = 0; if (evflag_atom && !peratom_allocate_flag) { allocate_peratom(); cg_peratom->ghost_notify(); cg_peratom->setup(); } // convert atoms from box to lamda coords if (triclinic == 0) boxlo = domain->boxlo; else { boxlo = domain->boxlo_lamda; domain->x2lamda(atom->nlocal); } // extend size of per-atom arrays if necessary if (atom->nlocal > nmax) { memory->destroy(part2grid); nmax = atom->nmax; memory->create(part2grid,nmax,3,"pppm:part2grid"); } // find grid points for all my particles // map my particle charge onto my local 3d density grid particle_map(); make_rho(); // all procs communicate density values from their ghost cells // to fully sum contribution in their 3d bricks // remap from 3d decomposition to FFT decomposition cg->reverse_comm(this,REVERSE_RHO); brick2fft(); // compute potential gradient on my FFT grid and // portion of e_long on this proc's FFT grid // return gradients (electric fields) in 3d brick decomposition // also performs per-atom calculations via poisson_peratom() poisson(); // all procs communicate E-field values // to fill ghost cells surrounding their 3d bricks if (differentiation_flag == 1) cg->forward_comm(this,FORWARD_AD); else cg->forward_comm(this,FORWARD_IK); // extra per-atom energy/virial communication if (evflag_atom) { if (differentiation_flag == 1 && vflag_atom) cg_peratom->forward_comm(this,FORWARD_AD_PERATOM); else if (differentiation_flag == 0) cg_peratom->forward_comm(this,FORWARD_IK_PERATOM); } // calculate the force on my particles fieldforce(); // extra per-atom energy/virial communication if (evflag_atom) fieldforce_peratom(); // sum global energy across procs and add in volume-dependent term // reset qsum and qsqsum if atom count has changed const double qscale = qqrd2e * scale; if (eflag_global) { double energy_all; MPI_Allreduce(&energy,&energy_all,1,MPI_DOUBLE,MPI_SUM,world); energy = energy_all; if (atom->natoms != natoms_original) { qsum_qsq(0); natoms_original = atom->natoms; } energy *= 0.5*volume; energy -= g_ewald*qsqsum/MY_PIS + MY_PI2*qsum*qsum / (g_ewald*g_ewald*volume); energy *= qscale; } // sum global virial across procs if (vflag_global) { double virial_all[6]; MPI_Allreduce(virial,virial_all,6,MPI_DOUBLE,MPI_SUM,world); for (i = 0; i < 6; i++) virial[i] = 0.5*qscale*volume*virial_all[i]; } // per-atom energy/virial // energy includes self-energy correction // notal accounts for TIP4P tallying eatom/vatom for ghost atoms if (evflag_atom) { double *q = atom->q; int nlocal = atom->nlocal; int ntotal = nlocal; if (tip4pflag) ntotal += atom->nghost; if (eflag_atom) { for (i = 0; i < nlocal; i++) { eatom[i] *= 0.5; eatom[i] -= g_ewald*q[i]*q[i]/MY_PIS + MY_PI2*q[i]*qsum / (g_ewald*g_ewald*volume); eatom[i] *= qscale; } for (i = nlocal; i < ntotal; i++) eatom[i] *= 0.5*qscale; } if (vflag_atom) { for (i = 0; i < ntotal; i++) for (j = 0; j < 6; j++) vatom[i][j] *= 0.5*qscale; } } // 2d slab correction if (slabflag == 1) slabcorr(); // convert atoms back from lamda to box coords if (triclinic) domain->lamda2x(atom->nlocal); } /* ---------------------------------------------------------------------- allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::allocate() { memory->create3d_offset(density_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:density_brick"); memory->create(density_fft,nfft_both,"pppm:density_fft"); memory->create(greensfn,nfft_both,"pppm:greensfn"); memory->create(work1,2*nfft_both,"pppm:work1"); memory->create(work2,2*nfft_both,"pppm:work2"); memory->create(vg,nfft_both,6,"pppm:vg"); if (triclinic == 0) { memory->create1d_offset(fkx,nxlo_fft,nxhi_fft,"pppm:fkx"); memory->create1d_offset(fky,nylo_fft,nyhi_fft,"pppm:fky"); memory->create1d_offset(fkz,nzlo_fft,nzhi_fft,"pppm:fkz"); } else { memory->create(fkx,nfft_both,"pppm:fkx"); memory->create(fky,nfft_both,"pppm:fky"); memory->create(fkz,nfft_both,"pppm:fkz"); } if (differentiation_flag == 1) { memory->create3d_offset(u_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:u_brick"); memory->create(sf_precoeff1,nfft_both,"pppm:sf_precoeff1"); memory->create(sf_precoeff2,nfft_both,"pppm:sf_precoeff2"); memory->create(sf_precoeff3,nfft_both,"pppm:sf_precoeff3"); memory->create(sf_precoeff4,nfft_both,"pppm:sf_precoeff4"); memory->create(sf_precoeff5,nfft_both,"pppm:sf_precoeff5"); memory->create(sf_precoeff6,nfft_both,"pppm:sf_precoeff6"); } else { memory->create3d_offset(vdx_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:vdx_brick"); memory->create3d_offset(vdy_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:vdy_brick"); memory->create3d_offset(vdz_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:vdz_brick"); } // summation coeffs order_allocated = order; if (!stagger_flag) memory->create(gf_b,order,"pppm:gf_b"); memory->create2d_offset(rho1d,3,-order/2,order/2,"pppm:rho1d"); memory->create2d_offset(drho1d,3,-order/2,order/2,"pppm:drho1d"); memory->create2d_offset(rho_coeff,order,(1-order)/2,order/2,"pppm:rho_coeff"); memory->create2d_offset(drho_coeff,order,(1-order)/2,order/2, "pppm:drho_coeff"); // create 2 FFTs and a Remap // 1st FFT keeps data in FFT decompostion // 2nd FFT returns data in 3d brick decomposition // remap takes data from 3d brick to FFT decomposition int tmp; fft1 = new FFT3d(lmp,world,nx_pppm,ny_pppm,nz_pppm, nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft, nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft, 0,0,&tmp,collective_flag); fft2 = new FFT3d(lmp,world,nx_pppm,ny_pppm,nz_pppm, nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, 0,0,&tmp,collective_flag); remap = new Remap(lmp,world, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_fft,nxhi_fft,nylo_fft,nyhi_fft,nzlo_fft,nzhi_fft, 1,0,0,FFT_PRECISION,collective_flag); // create ghost grid object for rho and electric field communication int (*procneigh)[2] = comm->procneigh; if (differentiation_flag == 1) cg = new GridComm(lmp,world,1,1, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out, procneigh[0][0],procneigh[0][1],procneigh[1][0], procneigh[1][1],procneigh[2][0],procneigh[2][1]); else cg = new GridComm(lmp,world,3,1, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out, procneigh[0][0],procneigh[0][1],procneigh[1][0], procneigh[1][1],procneigh[2][0],procneigh[2][1]); } /* ---------------------------------------------------------------------- deallocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::deallocate() { memory->destroy3d_offset(density_brick,nzlo_out,nylo_out,nxlo_out); if (differentiation_flag == 1) { memory->destroy3d_offset(u_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy(sf_precoeff1); memory->destroy(sf_precoeff2); memory->destroy(sf_precoeff3); memory->destroy(sf_precoeff4); memory->destroy(sf_precoeff5); memory->destroy(sf_precoeff6); } else { memory->destroy3d_offset(vdx_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(vdy_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(vdz_brick,nzlo_out,nylo_out,nxlo_out); } memory->destroy(density_fft); memory->destroy(greensfn); memory->destroy(work1); memory->destroy(work2); memory->destroy(vg); if (triclinic == 0) { memory->destroy1d_offset(fkx,nxlo_fft); memory->destroy1d_offset(fky,nylo_fft); memory->destroy1d_offset(fkz,nzlo_fft); } else { memory->destroy(fkx); memory->destroy(fky); memory->destroy(fkz); } memory->destroy(gf_b); if (stagger_flag) gf_b = NULL; memory->destroy2d_offset(rho1d,-order_allocated/2); memory->destroy2d_offset(drho1d,-order_allocated/2); memory->destroy2d_offset(rho_coeff,(1-order_allocated)/2); memory->destroy2d_offset(drho_coeff,(1-order_allocated)/2); delete fft1; delete fft2; delete remap; delete cg; } /* ---------------------------------------------------------------------- allocate per-atom memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::allocate_peratom() { peratom_allocate_flag = 1; if (differentiation_flag != 1) memory->create3d_offset(u_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:u_brick"); memory->create3d_offset(v0_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v0_brick"); memory->create3d_offset(v1_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v1_brick"); memory->create3d_offset(v2_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v2_brick"); memory->create3d_offset(v3_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v3_brick"); memory->create3d_offset(v4_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v4_brick"); memory->create3d_offset(v5_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:v5_brick"); // create ghost grid object for rho and electric field communication int (*procneigh)[2] = comm->procneigh; if (differentiation_flag == 1) cg_peratom = new GridComm(lmp,world,6,1, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out, procneigh[0][0],procneigh[0][1],procneigh[1][0], procneigh[1][1],procneigh[2][0],procneigh[2][1]); else cg_peratom = new GridComm(lmp,world,7,1, nxlo_in,nxhi_in,nylo_in,nyhi_in,nzlo_in,nzhi_in, nxlo_out,nxhi_out,nylo_out,nyhi_out,nzlo_out,nzhi_out, procneigh[0][0],procneigh[0][1],procneigh[1][0], procneigh[1][1],procneigh[2][0],procneigh[2][1]); } /* ---------------------------------------------------------------------- deallocate per-atom memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::deallocate_peratom() { peratom_allocate_flag = 0; memory->destroy3d_offset(v0_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(v1_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(v2_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(v3_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(v4_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(v5_brick,nzlo_out,nylo_out,nxlo_out); if (differentiation_flag != 1) memory->destroy3d_offset(u_brick,nzlo_out,nylo_out,nxlo_out); delete cg_peratom; } /* ---------------------------------------------------------------------- set global size of PPPM grid = nx,ny,nz_pppm used for charge accumulation, FFTs, and electric field interpolation ------------------------------------------------------------------------- */ void PPPM::set_grid_global() { // use xprd,yprd,zprd (even if triclinic, and then scale later) // adjust z dimension for 2d slab PPPM // 3d PPPM just uses zprd since slab_volfactor = 1.0 double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double zprd_slab = zprd*slab_volfactor; // make initial g_ewald estimate // based on desired accuracy and real space cutoff // fluid-occupied volume used to estimate real-space error // zprd used rather than zprd_slab double h; bigint natoms = atom->natoms; if (!gewaldflag) { if (accuracy <= 0.0) error->all(FLERR,"KSpace accuracy must be > 0"); g_ewald = accuracy*sqrt(natoms*cutoff*xprd*yprd*zprd) / (2.0*q2); if (g_ewald >= 1.0) g_ewald = (1.35 - 0.15*log(accuracy))/cutoff; else g_ewald = sqrt(-log(g_ewald)) / cutoff; } // set optimal nx_pppm,ny_pppm,nz_pppm based on order and accuracy // nz_pppm uses extended zprd_slab instead of zprd // reduce it until accuracy target is met if (!gridflag) { if (differentiation_flag == 1 || stagger_flag) { h = h_x = h_y = h_z = 4.0/g_ewald; int count = 0; while (1) { // set grid dimension nx_pppm = static_cast<int> (xprd/h_x); ny_pppm = static_cast<int> (yprd/h_y); nz_pppm = static_cast<int> (zprd_slab/h_z); if (nx_pppm <= 1) nx_pppm = 2; if (ny_pppm <= 1) ny_pppm = 2; if (nz_pppm <= 1) nz_pppm = 2; //set local grid dimension int npey_fft,npez_fft; if (nz_pppm >= nprocs) { npey_fft = 1; npez_fft = nprocs; } else procs2grid2d(nprocs,ny_pppm,nz_pppm,&npey_fft,&npez_fft); int me_y = me % npey_fft; int me_z = me / npey_fft; nxlo_fft = 0; nxhi_fft = nx_pppm - 1; nylo_fft = me_y*ny_pppm/npey_fft; nyhi_fft = (me_y+1)*ny_pppm/npey_fft - 1; nzlo_fft = me_z*nz_pppm/npez_fft; nzhi_fft = (me_z+1)*nz_pppm/npez_fft - 1; double df_kspace = compute_df_kspace(); count++; // break loop if the accuracy has been reached or // too many loops have been performed if (df_kspace <= accuracy) break; if (count > 500) error->all(FLERR, "Could not compute grid size"); h *= 0.95; h_x = h_y = h_z = h; } } else { double err; h_x = h_y = h_z = 1.0/g_ewald; nx_pppm = static_cast<int> (xprd/h_x) + 1; ny_pppm = static_cast<int> (yprd/h_y) + 1; nz_pppm = static_cast<int> (zprd_slab/h_z) + 1; err = estimate_ik_error(h_x,xprd,natoms); while (err > accuracy) { err = estimate_ik_error(h_x,xprd,natoms); nx_pppm++; h_x = xprd/nx_pppm; } err = estimate_ik_error(h_y,yprd,natoms); while (err > accuracy) { err = estimate_ik_error(h_y,yprd,natoms); ny_pppm++; h_y = yprd/ny_pppm; } err = estimate_ik_error(h_z,zprd_slab,natoms); while (err > accuracy) { err = estimate_ik_error(h_z,zprd_slab,natoms); nz_pppm++; h_z = zprd_slab/nz_pppm; } } // scale grid for triclinic skew if (triclinic) { double tmp[3]; tmp[0] = nx_pppm/xprd; tmp[1] = ny_pppm/yprd; tmp[2] = nz_pppm/zprd; lamda2xT(&tmp[0],&tmp[0]); nx_pppm = static_cast<int>(tmp[0]) + 1; ny_pppm = static_cast<int>(tmp[1]) + 1; nz_pppm = static_cast<int>(tmp[2]) + 1; } } // boost grid size until it is factorable while (!factorable(nx_pppm)) nx_pppm++; while (!factorable(ny_pppm)) ny_pppm++; while (!factorable(nz_pppm)) nz_pppm++; if (triclinic == 0) { h_x = xprd/nx_pppm; h_y = yprd/ny_pppm; h_z = zprd_slab/nz_pppm; } else { double tmp[3]; tmp[0] = nx_pppm; tmp[1] = ny_pppm; tmp[2] = nz_pppm; x2lamdaT(&tmp[0],&tmp[0]); h_x = 1.0/tmp[0]; h_y = 1.0/tmp[1]; h_z = 1.0/tmp[2]; } if (nx_pppm >= OFFSET || ny_pppm >= OFFSET || nz_pppm >= OFFSET) error->all(FLERR,"PPPM grid is too large"); } /* ---------------------------------------------------------------------- check if all factors of n are in list of factors return 1 if yes, 0 if no ------------------------------------------------------------------------- */ int PPPM::factorable(int n) { int i; while (n > 1) { for (i = 0; i < nfactors; i++) { if (n % factors[i] == 0) { n /= factors[i]; break; } } if (i == nfactors) return 0; } return 1; } /* ---------------------------------------------------------------------- compute estimated kspace force error ------------------------------------------------------------------------- */ double PPPM::compute_df_kspace() { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; double zprd_slab = zprd*slab_volfactor; bigint natoms = atom->natoms; double df_kspace = 0.0; if (differentiation_flag == 1 || stagger_flag) { double qopt = compute_qopt(); df_kspace = sqrt(qopt/natoms)*q2/(xprd*yprd*zprd_slab); } else { double lprx = estimate_ik_error(h_x,xprd,natoms); double lpry = estimate_ik_error(h_y,yprd,natoms); double lprz = estimate_ik_error(h_z,zprd_slab,natoms); df_kspace = sqrt(lprx*lprx + lpry*lpry + lprz*lprz) / sqrt(3.0); } return df_kspace; } /* ---------------------------------------------------------------------- compute qopt ------------------------------------------------------------------------- */ double PPPM::compute_qopt() { double qopt = 0.0; double *prd = domain->prd; const double xprd = prd[0]; const double yprd = prd[1]; const double zprd = prd[2]; const double zprd_slab = zprd*slab_volfactor; volume = xprd * yprd * zprd_slab; const double unitkx = (MY_2PI/xprd); const double unitky = (MY_2PI/yprd); const double unitkz = (MY_2PI/zprd_slab); double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz; double u1, u2, sqk; double sum1,sum2,sum3,sum4,dot2; int k,l,m,nx,ny,nz; const int twoorder = 2*order; for (m = nzlo_fft; m <= nzhi_fft; m++) { const int mper = m - nz_pppm*(2*m/nz_pppm); for (l = nylo_fft; l <= nyhi_fft; l++) { const int lper = l - ny_pppm*(2*l/ny_pppm); for (k = nxlo_fft; k <= nxhi_fft; k++) { const int kper = k - nx_pppm*(2*k/nx_pppm); sqk = square(unitkx*kper) + square(unitky*lper) + square(unitkz*mper); if (sqk != 0.0) { sum1 = 0.0; sum2 = 0.0; sum3 = 0.0; sum4 = 0.0; for (nx = -2; nx <= 2; nx++) { qx = unitkx*(kper+nx_pppm*nx); sx = exp(-0.25*square(qx/g_ewald)); argx = 0.5*qx*xprd/nx_pppm; wx = powsinxx(argx,twoorder); qx *= qx; for (ny = -2; ny <= 2; ny++) { qy = unitky*(lper+ny_pppm*ny); sy = exp(-0.25*square(qy/g_ewald)); argy = 0.5*qy*yprd/ny_pppm; wy = powsinxx(argy,twoorder); qy *= qy; for (nz = -2; nz <= 2; nz++) { qz = unitkz*(mper+nz_pppm*nz); sz = exp(-0.25*square(qz/g_ewald)); argz = 0.5*qz*zprd_slab/nz_pppm; wz = powsinxx(argz,twoorder); qz *= qz; dot2 = qx+qy+qz; u1 = sx*sy*sz; u2 = wx*wy*wz; sum1 += u1*u1/dot2*MY_4PI*MY_4PI; sum2 += u1 * u2 * MY_4PI; sum3 += u2; sum4 += dot2*u2; } } } sum2 *= sum2; qopt += sum1 - sum2/(sum3*sum4); } } } } double qopt_all; MPI_Allreduce(&qopt,&qopt_all,1,MPI_DOUBLE,MPI_SUM,world); return qopt_all; } /* ---------------------------------------------------------------------- estimate kspace force error for ik method ------------------------------------------------------------------------- */ double PPPM::estimate_ik_error(double h, double prd, bigint natoms) { double sum = 0.0; for (int m = 0; m < order; m++) sum += acons[order][m] * pow(h*g_ewald,2.0*m); double value = q2 * pow(h*g_ewald,(double)order) * sqrt(g_ewald*prd*sqrt(MY_2PI)*sum/natoms) / (prd*prd); return value; } /* ---------------------------------------------------------------------- adjust the g_ewald parameter to near its optimal value using a Newton-Raphson solver ------------------------------------------------------------------------- */ void PPPM::adjust_gewald() { double dx; for (int i = 0; i < LARGE; i++) { dx = newton_raphson_f() / derivf(); g_ewald -= dx; if (fabs(newton_raphson_f()) < SMALL) return; } char str[128]; sprintf(str, "Could not compute g_ewald"); error->all(FLERR, str); } /* ---------------------------------------------------------------------- calculate f(x) using Newton-Raphson solver ------------------------------------------------------------------------- */ double PPPM::newton_raphson_f() { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; bigint natoms = atom->natoms; double df_rspace = 2.0*q2*exp(-g_ewald*g_ewald*cutoff*cutoff) / sqrt(natoms*cutoff*xprd*yprd*zprd); double df_kspace = compute_df_kspace(); return df_rspace - df_kspace; } /* ---------------------------------------------------------------------- calculate numerical derivative f'(x) using forward difference [f(x + h) - f(x)] / h ------------------------------------------------------------------------- */ double PPPM::derivf() { double h = 0.000001; //Derivative step-size double df,f1,f2,g_ewald_old; f1 = newton_raphson_f(); g_ewald_old = g_ewald; g_ewald += h; f2 = newton_raphson_f(); g_ewald = g_ewald_old; df = (f2 - f1)/h; return df; } /* ---------------------------------------------------------------------- calculate the final estimate of the accuracy ------------------------------------------------------------------------- */ double PPPM::final_accuracy() { double xprd = domain->xprd; double yprd = domain->yprd; double zprd = domain->zprd; bigint natoms = atom->natoms; double df_kspace = compute_df_kspace(); double q2_over_sqrt = q2 / sqrt(natoms*cutoff*xprd*yprd*zprd); double df_rspace = 2.0 * q2_over_sqrt * exp(-g_ewald*g_ewald*cutoff*cutoff); double df_table = estimate_table_accuracy(q2_over_sqrt,df_rspace); double estimated_accuracy = sqrt(df_kspace*df_kspace + df_rspace*df_rspace + df_table*df_table); return estimated_accuracy; } /* ---------------------------------------------------------------------- set local subset of PPPM/FFT grid that I own n xyz lo/hi in = 3d brick that I own (inclusive) n xyz lo/hi out = 3d brick + ghost cells in 6 directions (inclusive) n xyz lo/hi fft = FFT columns that I own (all of x dim, 2d decomp in yz) ------------------------------------------------------------------------- */ void PPPM::set_grid_local() { // global indices of PPPM grid range from 0 to N-1 // nlo_in,nhi_in = lower/upper limits of the 3d sub-brick of // global PPPM grid that I own without ghost cells // for slab PPPM, assign z grid as if it were not extended nxlo_in = static_cast<int> (comm->xsplit[comm->myloc[0]] * nx_pppm); nxhi_in = static_cast<int> (comm->xsplit[comm->myloc[0]+1] * nx_pppm) - 1; nylo_in = static_cast<int> (comm->ysplit[comm->myloc[1]] * ny_pppm); nyhi_in = static_cast<int> (comm->ysplit[comm->myloc[1]+1] * ny_pppm) - 1; nzlo_in = static_cast<int> (comm->zsplit[comm->myloc[2]] * nz_pppm/slab_volfactor); nzhi_in = static_cast<int> (comm->zsplit[comm->myloc[2]+1] * nz_pppm/slab_volfactor) - 1; // nlower,nupper = stencil size for mapping particles to PPPM grid nlower = -(order-1)/2; nupper = order/2; // shift values for particle <-> grid mapping // add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1 if (order % 2) shift = OFFSET + 0.5; else shift = OFFSET; if (order % 2) shiftone = 0.0; else shiftone = 0.5; // nlo_out,nhi_out = lower/upper limits of the 3d sub-brick of // global PPPM grid that my particles can contribute charge to // effectively nlo_in,nhi_in + ghost cells // nlo,nhi = global coords of grid pt to "lower left" of smallest/largest // position a particle in my box can be at // dist[3] = particle position bound = subbox + skin/2.0 + qdist // qdist = offset due to TIP4P fictitious charge // convert to triclinic if necessary // nlo_out,nhi_out = nlo,nhi + stencil size for particle mapping // for slab PPPM, assign z grid as if it were not extended double *prd,*sublo,*subhi; if (triclinic == 0) { prd = domain->prd; boxlo = domain->boxlo; sublo = domain->sublo; subhi = domain->subhi; } else { prd = domain->prd_lamda; boxlo = domain->boxlo_lamda; sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } double xprd = prd[0]; double yprd = prd[1]; double zprd = prd[2]; double zprd_slab = zprd*slab_volfactor; double dist[3]; double cuthalf = 0.5*neighbor->skin + qdist; if (triclinic == 0) dist[0] = dist[1] = dist[2] = cuthalf; else kspacebbox(cuthalf,&dist[0]); int nlo,nhi; nlo = static_cast<int> ((sublo[0]-dist[0]-boxlo[0]) * nx_pppm/xprd + shift) - OFFSET; nhi = static_cast<int> ((subhi[0]+dist[0]-boxlo[0]) * nx_pppm/xprd + shift) - OFFSET; nxlo_out = nlo + nlower; nxhi_out = nhi + nupper; nlo = static_cast<int> ((sublo[1]-dist[1]-boxlo[1]) * ny_pppm/yprd + shift) - OFFSET; nhi = static_cast<int> ((subhi[1]+dist[1]-boxlo[1]) * ny_pppm/yprd + shift) - OFFSET; nylo_out = nlo + nlower; nyhi_out = nhi + nupper; nlo = static_cast<int> ((sublo[2]-dist[2]-boxlo[2]) * nz_pppm/zprd_slab + shift) - OFFSET; nhi = static_cast<int> ((subhi[2]+dist[2]-boxlo[2]) * nz_pppm/zprd_slab + shift) - OFFSET; nzlo_out = nlo + nlower; nzhi_out = nhi + nupper; if (stagger_flag) { nxhi_out++; nyhi_out++; nzhi_out++; } // for slab PPPM, change the grid boundary for processors at +z end // to include the empty volume between periodically repeating slabs // for slab PPPM, want charge data communicated from -z proc to +z proc, // but not vice versa, also want field data communicated from +z proc to // -z proc, but not vice versa // this is accomplished by nzhi_in = nzhi_out on +z end (no ghost cells) // also insure no other procs use ghost cells beyond +z limit if (slabflag == 1) { if (comm->myloc[2] == comm->procgrid[2]-1) nzhi_in = nzhi_out = nz_pppm - 1; nzhi_out = MIN(nzhi_out,nz_pppm-1); } // decomposition of FFT mesh // global indices range from 0 to N-1 // proc owns entire x-dimension, clumps of columns in y,z dimensions // npey_fft,npez_fft = # of procs in y,z dims // if nprocs is small enough, proc can own 1 or more entire xy planes, // else proc owns 2d sub-blocks of yz plane // me_y,me_z = which proc (0-npe_fft-1) I am in y,z dimensions // nlo_fft,nhi_fft = lower/upper limit of the section // of the global FFT mesh that I own int npey_fft,npez_fft; if (nz_pppm >= nprocs) { npey_fft = 1; npez_fft = nprocs; } else procs2grid2d(nprocs,ny_pppm,nz_pppm,&npey_fft,&npez_fft); int me_y = me % npey_fft; int me_z = me / npey_fft; nxlo_fft = 0; nxhi_fft = nx_pppm - 1; nylo_fft = me_y*ny_pppm/npey_fft; nyhi_fft = (me_y+1)*ny_pppm/npey_fft - 1; nzlo_fft = me_z*nz_pppm/npez_fft; nzhi_fft = (me_z+1)*nz_pppm/npez_fft - 1; // PPPM grid pts owned by this proc, including ghosts ngrid = (nxhi_out-nxlo_out+1) * (nyhi_out-nylo_out+1) * (nzhi_out-nzlo_out+1); // FFT grids owned by this proc, without ghosts // nfft = FFT points in FFT decomposition on this proc // nfft_brick = FFT points in 3d brick-decomposition on this proc // nfft_both = greater of 2 values nfft = (nxhi_fft-nxlo_fft+1) * (nyhi_fft-nylo_fft+1) * (nzhi_fft-nzlo_fft+1); int nfft_brick = (nxhi_in-nxlo_in+1) * (nyhi_in-nylo_in+1) * (nzhi_in-nzlo_in+1); nfft_both = MAX(nfft,nfft_brick); } /* ---------------------------------------------------------------------- pre-compute Green's function denominator expansion coeffs, Gamma(2n) ------------------------------------------------------------------------- */ void PPPM::compute_gf_denom() { int k,l,m; for (l = 1; l < order; l++) gf_b[l] = 0.0; gf_b[0] = 1.0; for (m = 1; m < order; m++) { for (l = m; l > 0; l--) gf_b[l] = 4.0 * (gf_b[l]*(l-m)*(l-m-0.5)-gf_b[l-1]*(l-m-1)*(l-m-1)); gf_b[0] = 4.0 * (gf_b[0]*(l-m)*(l-m-0.5)); } bigint ifact = 1; for (k = 1; k < 2*order; k++) ifact *= k; double gaminv = 1.0/ifact; for (l = 0; l < order; l++) gf_b[l] *= gaminv; } /* ---------------------------------------------------------------------- pre-compute modified (Hockney-Eastwood) Coulomb Green's function ------------------------------------------------------------------------- */ void PPPM::compute_gf_ik() { const double * const prd = domain->prd; const double xprd = prd[0]; const double yprd = prd[1]; const double zprd = prd[2]; const double zprd_slab = zprd*slab_volfactor; const double unitkx = (MY_2PI/xprd); const double unitky = (MY_2PI/yprd); const double unitkz = (MY_2PI/zprd_slab); double snx,sny,snz; double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz; double sum1,dot1,dot2; double numerator,denominator; double sqk; int k,l,m,n,nx,ny,nz,kper,lper,mper; const int nbx = static_cast<int> ((g_ewald*xprd/(MY_PI*nx_pppm)) * pow(-log(EPS_HOC),0.25)); const int nby = static_cast<int> ((g_ewald*yprd/(MY_PI*ny_pppm)) * pow(-log(EPS_HOC),0.25)); const int nbz = static_cast<int> ((g_ewald*zprd_slab/(MY_PI*nz_pppm)) * pow(-log(EPS_HOC),0.25)); const int twoorder = 2*order; n = 0; for (m = nzlo_fft; m <= nzhi_fft; m++) { mper = m - nz_pppm*(2*m/nz_pppm); snz = square(sin(0.5*unitkz*mper*zprd_slab/nz_pppm)); for (l = nylo_fft; l <= nyhi_fft; l++) { lper = l - ny_pppm*(2*l/ny_pppm); sny = square(sin(0.5*unitky*lper*yprd/ny_pppm)); for (k = nxlo_fft; k <= nxhi_fft; k++) { kper = k - nx_pppm*(2*k/nx_pppm); snx = square(sin(0.5*unitkx*kper*xprd/nx_pppm)); sqk = square(unitkx*kper) + square(unitky*lper) + square(unitkz*mper); if (sqk != 0.0) { numerator = 12.5663706/sqk; denominator = gf_denom(snx,sny,snz); sum1 = 0.0; for (nx = -nbx; nx <= nbx; nx++) { qx = unitkx*(kper+nx_pppm*nx); sx = exp(-0.25*square(qx/g_ewald)); argx = 0.5*qx*xprd/nx_pppm; wx = powsinxx(argx,twoorder); for (ny = -nby; ny <= nby; ny++) { qy = unitky*(lper+ny_pppm*ny); sy = exp(-0.25*square(qy/g_ewald)); argy = 0.5*qy*yprd/ny_pppm; wy = powsinxx(argy,twoorder); for (nz = -nbz; nz <= nbz; nz++) { qz = unitkz*(mper+nz_pppm*nz); sz = exp(-0.25*square(qz/g_ewald)); argz = 0.5*qz*zprd_slab/nz_pppm; wz = powsinxx(argz,twoorder); dot1 = unitkx*kper*qx + unitky*lper*qy + unitkz*mper*qz; dot2 = qx*qx+qy*qy+qz*qz; sum1 += (dot1/dot2) * sx*sy*sz * wx*wy*wz; } } } greensfn[n++] = numerator*sum1/denominator; } else greensfn[n++] = 0.0; } } } } /* ---------------------------------------------------------------------- pre-compute modified (Hockney-Eastwood) Coulomb Green's function for a triclinic system ------------------------------------------------------------------------- */ void PPPM::compute_gf_ik_triclinic() { double snx,sny,snz; double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz; double sum1,dot1,dot2; double numerator,denominator; double sqk; int k,l,m,n,nx,ny,nz,kper,lper,mper; double tmp[3]; tmp[0] = (g_ewald/(MY_PI*nx_pppm)) * pow(-log(EPS_HOC),0.25); tmp[1] = (g_ewald/(MY_PI*ny_pppm)) * pow(-log(EPS_HOC),0.25); tmp[2] = (g_ewald/(MY_PI*nz_pppm)) * pow(-log(EPS_HOC),0.25); lamda2xT(&tmp[0],&tmp[0]); const int nbx = static_cast<int> (tmp[0]); const int nby = static_cast<int> (tmp[1]); const int nbz = static_cast<int> (tmp[2]); const int twoorder = 2*order; n = 0; for (m = nzlo_fft; m <= nzhi_fft; m++) { mper = m - nz_pppm*(2*m/nz_pppm); snz = square(sin(MY_PI*mper/nz_pppm)); for (l = nylo_fft; l <= nyhi_fft; l++) { lper = l - ny_pppm*(2*l/ny_pppm); sny = square(sin(MY_PI*lper/ny_pppm)); for (k = nxlo_fft; k <= nxhi_fft; k++) { kper = k - nx_pppm*(2*k/nx_pppm); snx = square(sin(MY_PI*kper/nx_pppm)); double unitk_lamda[3]; unitk_lamda[0] = 2.0*MY_PI*kper; unitk_lamda[1] = 2.0*MY_PI*lper; unitk_lamda[2] = 2.0*MY_PI*mper; x2lamdaT(&unitk_lamda[0],&unitk_lamda[0]); sqk = square(unitk_lamda[0]) + square(unitk_lamda[1]) + square(unitk_lamda[2]); if (sqk != 0.0) { numerator = 12.5663706/sqk; denominator = gf_denom(snx,sny,snz); sum1 = 0.0; for (nx = -nbx; nx <= nbx; nx++) { argx = MY_PI*kper/nx_pppm + MY_PI*nx; wx = powsinxx(argx,twoorder); for (ny = -nby; ny <= nby; ny++) { argy = MY_PI*lper/ny_pppm + MY_PI*ny; wy = powsinxx(argy,twoorder); for (nz = -nbz; nz <= nbz; nz++) { argz = MY_PI*mper/nz_pppm + MY_PI*nz; wz = powsinxx(argz,twoorder); double b[3]; b[0] = 2.0*MY_PI*nx_pppm*nx; b[1] = 2.0*MY_PI*ny_pppm*ny; b[2] = 2.0*MY_PI*nz_pppm*nz; x2lamdaT(&b[0],&b[0]); qx = unitk_lamda[0]+b[0]; sx = exp(-0.25*square(qx/g_ewald)); qy = unitk_lamda[1]+b[1]; sy = exp(-0.25*square(qy/g_ewald)); qz = unitk_lamda[2]+b[2]; sz = exp(-0.25*square(qz/g_ewald)); dot1 = unitk_lamda[0]*qx + unitk_lamda[1]*qy + unitk_lamda[2]*qz; dot2 = qx*qx+qy*qy+qz*qz; sum1 += (dot1/dot2) * sx*sy*sz * wx*wy*wz; } } } greensfn[n++] = numerator*sum1/denominator; } else greensfn[n++] = 0.0; } } } } /* ---------------------------------------------------------------------- compute optimized Green's function for energy calculation ------------------------------------------------------------------------- */ void PPPM::compute_gf_ad() { const double * const prd = domain->prd; const double xprd = prd[0]; const double yprd = prd[1]; const double zprd = prd[2]; const double zprd_slab = zprd*slab_volfactor; const double unitkx = (MY_2PI/xprd); const double unitky = (MY_2PI/yprd); const double unitkz = (MY_2PI/zprd_slab); double snx,sny,snz,sqk; double argx,argy,argz,wx,wy,wz,sx,sy,sz,qx,qy,qz; double numerator,denominator; int k,l,m,n,kper,lper,mper; const int twoorder = 2*order; for (int i = 0; i < 6; i++) sf_coeff[i] = 0.0; n = 0; for (m = nzlo_fft; m <= nzhi_fft; m++) { mper = m - nz_pppm*(2*m/nz_pppm); qz = unitkz*mper; snz = square(sin(0.5*qz*zprd_slab/nz_pppm)); sz = exp(-0.25*square(qz/g_ewald)); argz = 0.5*qz*zprd_slab/nz_pppm; wz = powsinxx(argz,twoorder); for (l = nylo_fft; l <= nyhi_fft; l++) { lper = l - ny_pppm*(2*l/ny_pppm); qy = unitky*lper; sny = square(sin(0.5*qy*yprd/ny_pppm)); sy = exp(-0.25*square(qy/g_ewald)); argy = 0.5*qy*yprd/ny_pppm; wy = powsinxx(argy,twoorder); for (k = nxlo_fft; k <= nxhi_fft; k++) { kper = k - nx_pppm*(2*k/nx_pppm); qx = unitkx*kper; snx = square(sin(0.5*qx*xprd/nx_pppm)); sx = exp(-0.25*square(qx/g_ewald)); argx = 0.5*qx*xprd/nx_pppm; wx = powsinxx(argx,twoorder); sqk = qx*qx + qy*qy + qz*qz; if (sqk != 0.0) { numerator = MY_4PI/sqk; denominator = gf_denom(snx,sny,snz); greensfn[n] = numerator*sx*sy*sz*wx*wy*wz/denominator; sf_coeff[0] += sf_precoeff1[n]*greensfn[n]; sf_coeff[1] += sf_precoeff2[n]*greensfn[n]; sf_coeff[2] += sf_precoeff3[n]*greensfn[n]; sf_coeff[3] += sf_precoeff4[n]*greensfn[n]; sf_coeff[4] += sf_precoeff5[n]*greensfn[n]; sf_coeff[5] += sf_precoeff6[n]*greensfn[n]; n++; } else { greensfn[n] = 0.0; sf_coeff[0] += sf_precoeff1[n]*greensfn[n]; sf_coeff[1] += sf_precoeff2[n]*greensfn[n]; sf_coeff[2] += sf_precoeff3[n]*greensfn[n]; sf_coeff[3] += sf_precoeff4[n]*greensfn[n]; sf_coeff[4] += sf_precoeff5[n]*greensfn[n]; sf_coeff[5] += sf_precoeff6[n]*greensfn[n]; n++; } } } } // compute the coefficients for the self-force correction double prex, prey, prez; prex = prey = prez = MY_PI/volume; prex *= nx_pppm/xprd; prey *= ny_pppm/yprd; prez *= nz_pppm/zprd_slab; sf_coeff[0] *= prex; sf_coeff[1] *= prex*2; sf_coeff[2] *= prey; sf_coeff[3] *= prey*2; sf_coeff[4] *= prez; sf_coeff[5] *= prez*2; // communicate values with other procs double tmp[6]; MPI_Allreduce(sf_coeff,tmp,6,MPI_DOUBLE,MPI_SUM,world); for (n = 0; n < 6; n++) sf_coeff[n] = tmp[n]; } /* ---------------------------------------------------------------------- compute self force coefficients for ad-differentiation scheme ------------------------------------------------------------------------- */ void PPPM::compute_sf_precoeff() { int i,k,l,m,n; int nx,ny,nz,kper,lper,mper; double wx0[5],wy0[5],wz0[5],wx1[5],wy1[5],wz1[5],wx2[5],wy2[5],wz2[5]; double qx0,qy0,qz0,qx1,qy1,qz1,qx2,qy2,qz2; double u0,u1,u2,u3,u4,u5,u6; double sum1,sum2,sum3,sum4,sum5,sum6; n = 0; for (m = nzlo_fft; m <= nzhi_fft; m++) { mper = m - nz_pppm*(2*m/nz_pppm); for (l = nylo_fft; l <= nyhi_fft; l++) { lper = l - ny_pppm*(2*l/ny_pppm); for (k = nxlo_fft; k <= nxhi_fft; k++) { kper = k - nx_pppm*(2*k/nx_pppm); sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = 0.0; for (i = 0; i < 5; i++) { qx0 = MY_2PI*(kper+nx_pppm*(i-2)); qx1 = MY_2PI*(kper+nx_pppm*(i-1)); qx2 = MY_2PI*(kper+nx_pppm*(i )); wx0[i] = powsinxx(0.5*qx0/nx_pppm,order); wx1[i] = powsinxx(0.5*qx1/nx_pppm,order); wx2[i] = powsinxx(0.5*qx2/nx_pppm,order); qy0 = MY_2PI*(lper+ny_pppm*(i-2)); qy1 = MY_2PI*(lper+ny_pppm*(i-1)); qy2 = MY_2PI*(lper+ny_pppm*(i )); wy0[i] = powsinxx(0.5*qy0/ny_pppm,order); wy1[i] = powsinxx(0.5*qy1/ny_pppm,order); wy2[i] = powsinxx(0.5*qy2/ny_pppm,order); qz0 = MY_2PI*(mper+nz_pppm*(i-2)); qz1 = MY_2PI*(mper+nz_pppm*(i-1)); qz2 = MY_2PI*(mper+nz_pppm*(i )); wz0[i] = powsinxx(0.5*qz0/nz_pppm,order); wz1[i] = powsinxx(0.5*qz1/nz_pppm,order); wz2[i] = powsinxx(0.5*qz2/nz_pppm,order); } for (nx = 0; nx < 5; nx++) { for (ny = 0; ny < 5; ny++) { for (nz = 0; nz < 5; nz++) { u0 = wx0[nx]*wy0[ny]*wz0[nz]; u1 = wx1[nx]*wy0[ny]*wz0[nz]; u2 = wx2[nx]*wy0[ny]*wz0[nz]; u3 = wx0[nx]*wy1[ny]*wz0[nz]; u4 = wx0[nx]*wy2[ny]*wz0[nz]; u5 = wx0[nx]*wy0[ny]*wz1[nz]; u6 = wx0[nx]*wy0[ny]*wz2[nz]; sum1 += u0*u1; sum2 += u0*u2; sum3 += u0*u3; sum4 += u0*u4; sum5 += u0*u5; sum6 += u0*u6; } } } // store values sf_precoeff1[n] = sum1; sf_precoeff2[n] = sum2; sf_precoeff3[n] = sum3; sf_precoeff4[n] = sum4; sf_precoeff5[n] = sum5; sf_precoeff6[n++] = sum6; } } } } /* ---------------------------------------------------------------------- find center grid pt for each of my particles check that full stencil for the particle will fit in my 3d brick store central grid pt indices in part2grid array ------------------------------------------------------------------------- */ void PPPM::particle_map() { int nx,ny,nz; double **x = atom->x; int nlocal = atom->nlocal; int flag = 0; for (int i = 0; i < nlocal; i++) { // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // current particle coord can be outside global and local box // add/subtract OFFSET to avoid int(-0.75) = 0 when want it to be -1 nx = static_cast<int> ((x[i][0]-boxlo[0])*delxinv+shift) - OFFSET; ny = static_cast<int> ((x[i][1]-boxlo[1])*delyinv+shift) - OFFSET; nz = static_cast<int> ((x[i][2]-boxlo[2])*delzinv+shift) - OFFSET; part2grid[i][0] = nx; part2grid[i][1] = ny; part2grid[i][2] = nz; // check that entire stencil around nx,ny,nz will fit in my 3d brick if (nx+nlower < nxlo_out || nx+nupper > nxhi_out || ny+nlower < nylo_out || ny+nupper > nyhi_out || nz+nlower < nzlo_out || nz+nupper > nzhi_out) flag = 1; } if (flag) error->one(FLERR,"Out of range atoms - cannot compute PPPM"); } /* ---------------------------------------------------------------------- create discretized "density" on section of global grid due to my particles density(x,y,z) = charge "density" at grid points of my 3d brick (nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts) in global grid ------------------------------------------------------------------------- */ void PPPM::make_rho() { int l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz,x0,y0,z0; // clear 3d density array memset(&(density_brick[nzlo_out][nylo_out][nxlo_out]),0, ngrid*sizeof(FFT_SCALAR)); // loop over my charges, add their contribution to nearby grid points // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // (dx,dy,dz) = distance to "lower left" grid pt // (mx,my,mz) = global coords of moving stencil pt double *q = atom->q; double **x = atom->x; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { nx = part2grid[i][0]; ny = part2grid[i][1]; nz = part2grid[i][2]; dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv; dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv; dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv; compute_rho1d(dx,dy,dz); z0 = delvolinv * q[i]; for (n = nlower; n <= nupper; n++) { mz = n+nz; y0 = z0*rho1d[2][n]; for (m = nlower; m <= nupper; m++) { my = m+ny; x0 = y0*rho1d[1][m]; for (l = nlower; l <= nupper; l++) { mx = l+nx; density_brick[mz][my][mx] += x0*rho1d[0][l]; } } } } } /* ---------------------------------------------------------------------- remap density from 3d brick decomposition to FFT decomposition ------------------------------------------------------------------------- */ void PPPM::brick2fft() { int n,ix,iy,iz; // copy grabs inner portion of density from 3d brick // remap could be done as pre-stage of FFT, // but this works optimally on only double values, not complex values n = 0; for (iz = nzlo_in; iz <= nzhi_in; iz++) for (iy = nylo_in; iy <= nyhi_in; iy++) for (ix = nxlo_in; ix <= nxhi_in; ix++) density_fft[n++] = density_brick[iz][iy][ix]; remap->perform(density_fft,density_fft,work1); } /* ---------------------------------------------------------------------- FFT-based Poisson solver ------------------------------------------------------------------------- */ void PPPM::poisson() { if (differentiation_flag == 1) poisson_ad(); else poisson_ik(); } /* ---------------------------------------------------------------------- FFT-based Poisson solver for ik ------------------------------------------------------------------------- */ void PPPM::poisson_ik() { int i,j,k,n; double eng; // transform charge density (r -> k) n = 0; for (i = 0; i < nfft; i++) { work1[n++] = density_fft[i]; work1[n++] = ZEROF; } fft1->compute(work1,work1,1); // global energy and virial contribution double scaleinv = 1.0/(nx_pppm*ny_pppm*nz_pppm); double s2 = scaleinv*scaleinv; if (eflag_global || vflag_global) { if (vflag_global) { n = 0; for (i = 0; i < nfft; i++) { eng = s2 * greensfn[i] * (work1[n]*work1[n] + work1[n+1]*work1[n+1]); for (j = 0; j < 6; j++) virial[j] += eng*vg[i][j]; if (eflag_global) energy += eng; n += 2; } } else { n = 0; for (i = 0; i < nfft; i++) { energy += s2 * greensfn[i] * (work1[n]*work1[n] + work1[n+1]*work1[n+1]); n += 2; } } } // scale by 1/total-grid-pts to get rho(k) // multiply by Green's function to get V(k) n = 0; for (i = 0; i < nfft; i++) { work1[n++] *= scaleinv * greensfn[i]; work1[n++] *= scaleinv * greensfn[i]; } // extra FFTs for per-atom energy/virial if (evflag_atom) poisson_peratom(); // triclinic system if (triclinic) { poisson_ik_triclinic(); return; } // compute gradients of V(r) in each of 3 dims by transformimg -ik*V(k) // FFT leaves data in 3d brick decomposition // copy it into inner portion of vdx,vdy,vdz arrays // x direction gradient n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { work2[n] = fkx[i]*work1[n+1]; work2[n+1] = -fkx[i]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdx_brick[k][j][i] = work2[n]; n += 2; } // y direction gradient n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { work2[n] = fky[j]*work1[n+1]; work2[n+1] = -fky[j]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdy_brick[k][j][i] = work2[n]; n += 2; } // z direction gradient n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { work2[n] = fkz[k]*work1[n+1]; work2[n+1] = -fkz[k]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdz_brick[k][j][i] = work2[n]; n += 2; } } /* ---------------------------------------------------------------------- FFT-based Poisson solver for ik for a triclinic system ------------------------------------------------------------------------- */ void PPPM::poisson_ik_triclinic() { int i,j,k,n; // compute gradients of V(r) in each of 3 dims by transformimg -ik*V(k) // FFT leaves data in 3d brick decomposition // copy it into inner portion of vdx,vdy,vdz arrays // x direction gradient n = 0; for (i = 0; i < nfft; i++) { work2[n] = fkx[i]*work1[n+1]; work2[n+1] = -fkx[i]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdx_brick[k][j][i] = work2[n]; n += 2; } // y direction gradient n = 0; for (i = 0; i < nfft; i++) { work2[n] = fky[i]*work1[n+1]; work2[n+1] = -fky[i]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdy_brick[k][j][i] = work2[n]; n += 2; } // z direction gradient n = 0; for (i = 0; i < nfft; i++) { work2[n] = fkz[i]*work1[n+1]; work2[n+1] = -fkz[i]*work1[n]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { vdz_brick[k][j][i] = work2[n]; n += 2; } } /* ---------------------------------------------------------------------- FFT-based Poisson solver for ad ------------------------------------------------------------------------- */ void PPPM::poisson_ad() { int i,j,k,n; double eng; // transform charge density (r -> k) n = 0; for (i = 0; i < nfft; i++) { work1[n++] = density_fft[i]; work1[n++] = ZEROF; } fft1->compute(work1,work1,1); // global energy and virial contribution double scaleinv = 1.0/(nx_pppm*ny_pppm*nz_pppm); double s2 = scaleinv*scaleinv; if (eflag_global || vflag_global) { if (vflag_global) { n = 0; for (i = 0; i < nfft; i++) { eng = s2 * greensfn[i] * (work1[n]*work1[n] + work1[n+1]*work1[n+1]); for (j = 0; j < 6; j++) virial[j] += eng*vg[i][j]; if (eflag_global) energy += eng; n += 2; } } else { n = 0; for (i = 0; i < nfft; i++) { energy += s2 * greensfn[i] * (work1[n]*work1[n] + work1[n+1]*work1[n+1]); n += 2; } } } // scale by 1/total-grid-pts to get rho(k) // multiply by Green's function to get V(k) n = 0; for (i = 0; i < nfft; i++) { work1[n++] *= scaleinv * greensfn[i]; work1[n++] *= scaleinv * greensfn[i]; } // extra FFTs for per-atom energy/virial if (vflag_atom) poisson_peratom(); n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]; work2[n+1] = work1[n+1]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { u_brick[k][j][i] = work2[n]; n += 2; } } /* ---------------------------------------------------------------------- FFT-based Poisson solver for per-atom energy/virial ------------------------------------------------------------------------- */ void PPPM::poisson_peratom() { int i,j,k,n; // energy if (eflag_atom && differentiation_flag != 1) { n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]; work2[n+1] = work1[n+1]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { u_brick[k][j][i] = work2[n]; n += 2; } } // 6 components of virial in v0 thru v5 if (!vflag_atom) return; n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][0]; work2[n+1] = work1[n+1]*vg[i][0]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v0_brick[k][j][i] = work2[n]; n += 2; } n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][1]; work2[n+1] = work1[n+1]*vg[i][1]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v1_brick[k][j][i] = work2[n]; n += 2; } n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][2]; work2[n+1] = work1[n+1]*vg[i][2]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v2_brick[k][j][i] = work2[n]; n += 2; } n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][3]; work2[n+1] = work1[n+1]*vg[i][3]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v3_brick[k][j][i] = work2[n]; n += 2; } n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][4]; work2[n+1] = work1[n+1]*vg[i][4]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v4_brick[k][j][i] = work2[n]; n += 2; } n = 0; for (i = 0; i < nfft; i++) { work2[n] = work1[n]*vg[i][5]; work2[n+1] = work1[n+1]*vg[i][5]; n += 2; } fft2->compute(work2,work2,-1); n = 0; for (k = nzlo_in; k <= nzhi_in; k++) for (j = nylo_in; j <= nyhi_in; j++) for (i = nxlo_in; i <= nxhi_in; i++) { v5_brick[k][j][i] = work2[n]; n += 2; } } /* ---------------------------------------------------------------------- interpolate from grid to get electric field & force on my particles ------------------------------------------------------------------------- */ void PPPM::fieldforce() { if (differentiation_flag == 1) fieldforce_ad(); else fieldforce_ik(); } /* ---------------------------------------------------------------------- interpolate from grid to get electric field & force on my particles for ik ------------------------------------------------------------------------- */ void PPPM::fieldforce_ik() { int i,l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz,x0,y0,z0; FFT_SCALAR ekx,eky,ekz; // loop over my charges, interpolate electric field from nearby grid points // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // (dx,dy,dz) = distance to "lower left" grid pt // (mx,my,mz) = global coords of moving stencil pt // ek = 3 components of E-field on particle double *q = atom->q; double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { nx = part2grid[i][0]; ny = part2grid[i][1]; nz = part2grid[i][2]; dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv; dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv; dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv; compute_rho1d(dx,dy,dz); ekx = eky = ekz = ZEROF; for (n = nlower; n <= nupper; n++) { mz = n+nz; z0 = rho1d[2][n]; for (m = nlower; m <= nupper; m++) { my = m+ny; y0 = z0*rho1d[1][m]; for (l = nlower; l <= nupper; l++) { mx = l+nx; x0 = y0*rho1d[0][l]; ekx -= x0*vdx_brick[mz][my][mx]; eky -= x0*vdy_brick[mz][my][mx]; ekz -= x0*vdz_brick[mz][my][mx]; } } } // convert E-field to force const double qfactor = qqrd2e * scale * q[i]; f[i][0] += qfactor*ekx; f[i][1] += qfactor*eky; if (slabflag != 2) f[i][2] += qfactor*ekz; } } /* ---------------------------------------------------------------------- interpolate from grid to get electric field & force on my particles for ad ------------------------------------------------------------------------- */ void PPPM::fieldforce_ad() { int i,l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz; FFT_SCALAR ekx,eky,ekz; double s1,s2,s3; double sf = 0.0; double *prd; prd = domain->prd; double xprd = prd[0]; double yprd = prd[1]; double zprd = prd[2]; double hx_inv = nx_pppm/xprd; double hy_inv = ny_pppm/yprd; double hz_inv = nz_pppm/zprd; // loop over my charges, interpolate electric field from nearby grid points // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // (dx,dy,dz) = distance to "lower left" grid pt // (mx,my,mz) = global coords of moving stencil pt // ek = 3 components of E-field on particle double *q = atom->q; double **x = atom->x; double **f = atom->f; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { nx = part2grid[i][0]; ny = part2grid[i][1]; nz = part2grid[i][2]; dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv; dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv; dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv; compute_rho1d(dx,dy,dz); compute_drho1d(dx,dy,dz); ekx = eky = ekz = ZEROF; for (n = nlower; n <= nupper; n++) { mz = n+nz; for (m = nlower; m <= nupper; m++) { my = m+ny; for (l = nlower; l <= nupper; l++) { mx = l+nx; ekx += drho1d[0][l]*rho1d[1][m]*rho1d[2][n]*u_brick[mz][my][mx]; eky += rho1d[0][l]*drho1d[1][m]*rho1d[2][n]*u_brick[mz][my][mx]; ekz += rho1d[0][l]*rho1d[1][m]*drho1d[2][n]*u_brick[mz][my][mx]; } } } ekx *= hx_inv; eky *= hy_inv; ekz *= hz_inv; // convert E-field to force and substract self forces const double qfactor = qqrd2e * scale; s1 = x[i][0]*hx_inv; s2 = x[i][1]*hy_inv; s3 = x[i][2]*hz_inv; sf = sf_coeff[0]*sin(2*MY_PI*s1); sf += sf_coeff[1]*sin(4*MY_PI*s1); sf *= 2*q[i]*q[i]; f[i][0] += qfactor*(ekx*q[i] - sf); sf = sf_coeff[2]*sin(2*MY_PI*s2); sf += sf_coeff[3]*sin(4*MY_PI*s2); sf *= 2*q[i]*q[i]; f[i][1] += qfactor*(eky*q[i] - sf); sf = sf_coeff[4]*sin(2*MY_PI*s3); sf += sf_coeff[5]*sin(4*MY_PI*s3); sf *= 2*q[i]*q[i]; if (slabflag != 2) f[i][2] += qfactor*(ekz*q[i] - sf); } } /* ---------------------------------------------------------------------- interpolate from grid to get per-atom energy/virial ------------------------------------------------------------------------- */ void PPPM::fieldforce_peratom() { int i,l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz,x0,y0,z0; FFT_SCALAR u,v0,v1,v2,v3,v4,v5; // loop over my charges, interpolate from nearby grid points // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // (dx,dy,dz) = distance to "lower left" grid pt // (mx,my,mz) = global coords of moving stencil pt double *q = atom->q; double **x = atom->x; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { nx = part2grid[i][0]; ny = part2grid[i][1]; nz = part2grid[i][2]; dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv; dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv; dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv; compute_rho1d(dx,dy,dz); u = v0 = v1 = v2 = v3 = v4 = v5 = ZEROF; for (n = nlower; n <= nupper; n++) { mz = n+nz; z0 = rho1d[2][n]; for (m = nlower; m <= nupper; m++) { my = m+ny; y0 = z0*rho1d[1][m]; for (l = nlower; l <= nupper; l++) { mx = l+nx; x0 = y0*rho1d[0][l]; if (eflag_atom) u += x0*u_brick[mz][my][mx]; if (vflag_atom) { v0 += x0*v0_brick[mz][my][mx]; v1 += x0*v1_brick[mz][my][mx]; v2 += x0*v2_brick[mz][my][mx]; v3 += x0*v3_brick[mz][my][mx]; v4 += x0*v4_brick[mz][my][mx]; v5 += x0*v5_brick[mz][my][mx]; } } } } if (eflag_atom) eatom[i] += q[i]*u; if (vflag_atom) { vatom[i][0] += q[i]*v0; vatom[i][1] += q[i]*v1; vatom[i][2] += q[i]*v2; vatom[i][3] += q[i]*v3; vatom[i][4] += q[i]*v4; vatom[i][5] += q[i]*v5; } } } /* ---------------------------------------------------------------------- pack own values to buf to send to another proc ------------------------------------------------------------------------- */ void PPPM::pack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; if (flag == FORWARD_IK) { FFT_SCALAR *xsrc = &vdx_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *ysrc = &vdy_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *zsrc = &vdz_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { buf[n++] = xsrc[list[i]]; buf[n++] = ysrc[list[i]]; buf[n++] = zsrc[list[i]]; } } else if (flag == FORWARD_AD) { FFT_SCALAR *src = &u_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) buf[i] = src[list[i]]; } else if (flag == FORWARD_IK_PERATOM) { FFT_SCALAR *esrc = &u_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v0src = &v0_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v1src = &v1_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v2src = &v2_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v3src = &v3_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v4src = &v4_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v5src = &v5_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { if (eflag_atom) buf[n++] = esrc[list[i]]; if (vflag_atom) { buf[n++] = v0src[list[i]]; buf[n++] = v1src[list[i]]; buf[n++] = v2src[list[i]]; buf[n++] = v3src[list[i]]; buf[n++] = v4src[list[i]]; buf[n++] = v5src[list[i]]; } } } else if (flag == FORWARD_AD_PERATOM) { FFT_SCALAR *v0src = &v0_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v1src = &v1_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v2src = &v2_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v3src = &v3_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v4src = &v4_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v5src = &v5_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { buf[n++] = v0src[list[i]]; buf[n++] = v1src[list[i]]; buf[n++] = v2src[list[i]]; buf[n++] = v3src[list[i]]; buf[n++] = v4src[list[i]]; buf[n++] = v5src[list[i]]; } } } /* ---------------------------------------------------------------------- unpack another proc's own values from buf and set own ghost values ------------------------------------------------------------------------- */ void PPPM::unpack_forward(int flag, FFT_SCALAR *buf, int nlist, int *list) { int n = 0; if (flag == FORWARD_IK) { FFT_SCALAR *xdest = &vdx_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *ydest = &vdy_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *zdest = &vdz_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { xdest[list[i]] = buf[n++]; ydest[list[i]] = buf[n++]; zdest[list[i]] = buf[n++]; } } else if (flag == FORWARD_AD) { FFT_SCALAR *dest = &u_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) dest[list[i]] = buf[i]; } else if (flag == FORWARD_IK_PERATOM) { FFT_SCALAR *esrc = &u_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v0src = &v0_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v1src = &v1_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v2src = &v2_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v3src = &v3_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v4src = &v4_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v5src = &v5_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { if (eflag_atom) esrc[list[i]] = buf[n++]; if (vflag_atom) { v0src[list[i]] = buf[n++]; v1src[list[i]] = buf[n++]; v2src[list[i]] = buf[n++]; v3src[list[i]] = buf[n++]; v4src[list[i]] = buf[n++]; v5src[list[i]] = buf[n++]; } } } else if (flag == FORWARD_AD_PERATOM) { FFT_SCALAR *v0src = &v0_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v1src = &v1_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v2src = &v2_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v3src = &v3_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v4src = &v4_brick[nzlo_out][nylo_out][nxlo_out]; FFT_SCALAR *v5src = &v5_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) { v0src[list[i]] = buf[n++]; v1src[list[i]] = buf[n++]; v2src[list[i]] = buf[n++]; v3src[list[i]] = buf[n++]; v4src[list[i]] = buf[n++]; v5src[list[i]] = buf[n++]; } } } /* ---------------------------------------------------------------------- pack ghost values into buf to send to another proc ------------------------------------------------------------------------- */ void PPPM::pack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) { if (flag == REVERSE_RHO) { FFT_SCALAR *src = &density_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) buf[i] = src[list[i]]; } } /* ---------------------------------------------------------------------- unpack another proc's ghost values from buf and add to own values ------------------------------------------------------------------------- */ void PPPM::unpack_reverse(int flag, FFT_SCALAR *buf, int nlist, int *list) { if (flag == REVERSE_RHO) { FFT_SCALAR *dest = &density_brick[nzlo_out][nylo_out][nxlo_out]; for (int i = 0; i < nlist; i++) dest[list[i]] += buf[i]; } } /* ---------------------------------------------------------------------- map nprocs to NX by NY grid as PX by PY procs - return optimal px,py ------------------------------------------------------------------------- */ void PPPM::procs2grid2d(int nprocs, int nx, int ny, int *px, int *py) { // loop thru all possible factorizations of nprocs // surf = surface area of largest proc sub-domain // innermost if test minimizes surface area and surface/volume ratio int bestsurf = 2 * (nx + ny); int bestboxx = 0; int bestboxy = 0; int boxx,boxy,surf,ipx,ipy; ipx = 1; while (ipx <= nprocs) { if (nprocs % ipx == 0) { ipy = nprocs/ipx; boxx = nx/ipx; if (nx % ipx) boxx++; boxy = ny/ipy; if (ny % ipy) boxy++; surf = boxx + boxy; if (surf < bestsurf || (surf == bestsurf && boxx*boxy > bestboxx*bestboxy)) { bestsurf = surf; bestboxx = boxx; bestboxy = boxy; *px = ipx; *py = ipy; } } ipx++; } } /* ---------------------------------------------------------------------- charge assignment into rho1d dx,dy,dz = distance of particle from "lower left" grid point ------------------------------------------------------------------------- */ void PPPM::compute_rho1d(const FFT_SCALAR &dx, const FFT_SCALAR &dy, const FFT_SCALAR &dz) { int k,l; FFT_SCALAR r1,r2,r3; for (k = (1-order)/2; k <= order/2; k++) { r1 = r2 = r3 = ZEROF; for (l = order-1; l >= 0; l--) { r1 = rho_coeff[l][k] + r1*dx; r2 = rho_coeff[l][k] + r2*dy; r3 = rho_coeff[l][k] + r3*dz; } rho1d[0][k] = r1; rho1d[1][k] = r2; rho1d[2][k] = r3; } } /* ---------------------------------------------------------------------- charge assignment into drho1d dx,dy,dz = distance of particle from "lower left" grid point ------------------------------------------------------------------------- */ void PPPM::compute_drho1d(const FFT_SCALAR &dx, const FFT_SCALAR &dy, const FFT_SCALAR &dz) { int k,l; FFT_SCALAR r1,r2,r3; for (k = (1-order)/2; k <= order/2; k++) { r1 = r2 = r3 = ZEROF; for (l = order-2; l >= 0; l--) { r1 = drho_coeff[l][k] + r1*dx; r2 = drho_coeff[l][k] + r2*dy; r3 = drho_coeff[l][k] + r3*dz; } drho1d[0][k] = r1; drho1d[1][k] = r2; drho1d[2][k] = r3; } } /* ---------------------------------------------------------------------- generate coeffients for the weight function of order n (n-1) Wn(x) = Sum wn(k,x) , Sum is over every other integer k=-(n-1) For k=-(n-1),-(n-1)+2, ....., (n-1)-2,n-1 k is odd integers if n is even and even integers if n is odd --- | n-1 | Sum a(l,j)*(x-k/2)**l if abs(x-k/2) < 1/2 wn(k,x) = < l=0 | | 0 otherwise --- a coeffients are packed into the array rho_coeff to eliminate zeros rho_coeff(l,((k+mod(n+1,2))/2) = a(l,k) ------------------------------------------------------------------------- */ void PPPM::compute_rho_coeff() { int j,k,l,m; FFT_SCALAR s; FFT_SCALAR **a; memory->create2d_offset(a,order,-order,order,"pppm:a"); for (k = -order; k <= order; k++) for (l = 0; l < order; l++) a[l][k] = 0.0; a[0][0] = 1.0; for (j = 1; j < order; j++) { for (k = -j; k <= j; k += 2) { s = 0.0; for (l = 0; l < j; l++) { a[l+1][k] = (a[l][k+1]-a[l][k-1]) / (l+1); #ifdef FFT_SINGLE s += powf(0.5,(float) l+1) * (a[l][k-1] + powf(-1.0,(float) l) * a[l][k+1]) / (l+1); #else s += pow(0.5,(double) l+1) * (a[l][k-1] + pow(-1.0,(double) l) * a[l][k+1]) / (l+1); #endif } a[0][k] = s; } } m = (1-order)/2; for (k = -(order-1); k < order; k += 2) { for (l = 0; l < order; l++) rho_coeff[l][m] = a[l][k]; for (l = 1; l < order; l++) drho_coeff[l-1][m] = l*a[l][k]; m++; } memory->destroy2d_offset(a,-order); } /* ---------------------------------------------------------------------- Slab-geometry correction term to dampen inter-slab interactions between periodically repeating slabs. Yields good approximation to 2D Ewald if adequate empty space is left between repeating slabs (J. Chem. Phys. 111, 3155). Slabs defined here to be parallel to the xy plane. Also extended to non-neutral systems (J. Chem. Phys. 131, 094107). ------------------------------------------------------------------------- */ void PPPM::slabcorr() { // compute local contribution to global dipole moment double *q = atom->q; double **x = atom->x; double zprd = domain->zprd; int nlocal = atom->nlocal; double dipole = 0.0; for (int i = 0; i < nlocal; i++) dipole += q[i]*x[i][2]; // sum local contributions to get global dipole moment double dipole_all; MPI_Allreduce(&dipole,&dipole_all,1,MPI_DOUBLE,MPI_SUM,world); // need to make non-neutral systems and/or // per-atom energy translationally invariant double dipole_r2 = 0.0; if (eflag_atom || fabs(qsum) > SMALL) { for (int i = 0; i < nlocal; i++) dipole_r2 += q[i]*x[i][2]*x[i][2]; // sum local contributions double tmp; MPI_Allreduce(&dipole_r2,&tmp,1,MPI_DOUBLE,MPI_SUM,world); dipole_r2 = tmp; } // compute corrections const double e_slabcorr = MY_2PI*(dipole_all*dipole_all - qsum*dipole_r2 - qsum*qsum*zprd*zprd/12.0)/volume; const double qscale = qqrd2e * scale; if (eflag_global) energy += qscale * e_slabcorr; // per-atom energy if (eflag_atom) { double efact = qscale * MY_2PI/volume; for (int i = 0; i < nlocal; i++) eatom[i] += efact * q[i]*(x[i][2]*dipole_all - 0.5*(dipole_r2 + qsum*x[i][2]*x[i][2]) - qsum*zprd*zprd/12.0); } // add on force corrections double ffact = qscale * (-4.0*MY_PI/volume); double **f = atom->f; for (int i = 0; i < nlocal; i++) f[i][2] += ffact * q[i]*(dipole_all - qsum*x[i][2]); } /* ---------------------------------------------------------------------- perform and time the 1d FFTs required for N timesteps ------------------------------------------------------------------------- */ int PPPM::timing_1d(int n, double &time1d) { double time1,time2; for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); time1 = MPI_Wtime(); for (int i = 0; i < n; i++) { fft1->timing1d(work1,nfft_both,1); fft2->timing1d(work1,nfft_both,-1); if (differentiation_flag != 1) { fft2->timing1d(work1,nfft_both,-1); fft2->timing1d(work1,nfft_both,-1); } } MPI_Barrier(world); time2 = MPI_Wtime(); time1d = time2 - time1; if (differentiation_flag) return 2; return 4; } /* ---------------------------------------------------------------------- perform and time the 3d FFTs required for N timesteps ------------------------------------------------------------------------- */ int PPPM::timing_3d(int n, double &time3d) { double time1,time2; for (int i = 0; i < 2*nfft_both; i++) work1[i] = ZEROF; MPI_Barrier(world); time1 = MPI_Wtime(); for (int i = 0; i < n; i++) { fft1->compute(work1,work1,1); fft2->compute(work1,work1,-1); if (differentiation_flag != 1) { fft2->compute(work1,work1,-1); fft2->compute(work1,work1,-1); } } MPI_Barrier(world); time2 = MPI_Wtime(); time3d = time2 - time1; if (differentiation_flag) return 2; return 4; } /* ---------------------------------------------------------------------- memory usage of local arrays ------------------------------------------------------------------------- */ double PPPM::memory_usage() { double bytes = nmax*3 * sizeof(double); int nbrick = (nxhi_out-nxlo_out+1) * (nyhi_out-nylo_out+1) * (nzhi_out-nzlo_out+1); if (differentiation_flag == 1) { bytes += 2 * nbrick * sizeof(FFT_SCALAR); } else { bytes += 4 * nbrick * sizeof(FFT_SCALAR); } if (triclinic) bytes += 3 * nfft_both * sizeof(double); bytes += 6 * nfft_both * sizeof(double); bytes += nfft_both * sizeof(double); bytes += nfft_both*5 * sizeof(FFT_SCALAR); if (peratom_allocate_flag) bytes += 6 * nbrick * sizeof(FFT_SCALAR); if (group_allocate_flag) { bytes += 2 * nbrick * sizeof(FFT_SCALAR); bytes += 2 * nfft_both * sizeof(FFT_SCALAR);; } bytes += cg->memory_usage(); return bytes; } /* ---------------------------------------------------------------------- group-group interactions ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- compute the PPPM total long-range force and energy for groups A and B ------------------------------------------------------------------------- */ void PPPM::compute_group_group(int groupbit_A, int groupbit_B, int AA_flag) { if (slabflag && triclinic) error->all(FLERR,"Cannot (yet) use K-space slab " "correction with compute group/group for triclinic systems"); if (differentiation_flag) error->all(FLERR,"Cannot (yet) use kspace_modify " "diff ad with compute group/group"); if (!group_allocate_flag) allocate_groups(); // convert atoms from box to lamda coords if (triclinic == 0) boxlo = domain->boxlo; else { boxlo = domain->boxlo_lamda; domain->x2lamda(atom->nlocal); } e2group = 0.0; //energy f2group[0] = 0.0; //force in x-direction f2group[1] = 0.0; //force in y-direction f2group[2] = 0.0; //force in z-direction // map my particle charge onto my local 3d density grid make_rho_groups(groupbit_A,groupbit_B,AA_flag); // all procs communicate density values from their ghost cells // to fully sum contribution in their 3d bricks // remap from 3d decomposition to FFT decomposition // temporarily store and switch pointers so we can // use brick2fft() for groups A and B (without // writing an additional function) FFT_SCALAR ***density_brick_real = density_brick; FFT_SCALAR *density_fft_real = density_fft; // group A density_brick = density_A_brick; density_fft = density_A_fft; cg->reverse_comm(this,REVERSE_RHO); brick2fft(); // group B density_brick = density_B_brick; density_fft = density_B_fft; cg->reverse_comm(this,REVERSE_RHO); brick2fft(); // switch back pointers density_brick = density_brick_real; density_fft = density_fft_real; // compute potential gradient on my FFT grid and // portion of group-group energy/force on this proc's FFT grid poisson_groups(AA_flag); const double qscale = qqrd2e * scale; // total group A <--> group B energy // self and boundary correction terms are in compute_group_group.cpp double e2group_all; MPI_Allreduce(&e2group,&e2group_all,1,MPI_DOUBLE,MPI_SUM,world); e2group = e2group_all; e2group *= qscale*0.5*volume; // total group A <--> group B force double f2group_all[3]; MPI_Allreduce(f2group,f2group_all,3,MPI_DOUBLE,MPI_SUM,world); f2group[0] = qscale*volume*f2group_all[0]; f2group[1] = qscale*volume*f2group_all[1]; if (slabflag != 2) f2group[2] = qscale*volume*f2group_all[2]; // convert atoms back from lamda to box coords if (triclinic) domain->lamda2x(atom->nlocal); if (slabflag == 1) slabcorr_groups(groupbit_A, groupbit_B, AA_flag); } /* ---------------------------------------------------------------------- allocate group-group memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::allocate_groups() { group_allocate_flag = 1; memory->create3d_offset(density_A_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:density_A_brick"); memory->create3d_offset(density_B_brick,nzlo_out,nzhi_out,nylo_out,nyhi_out, nxlo_out,nxhi_out,"pppm:density_B_brick"); memory->create(density_A_fft,nfft_both,"pppm:density_A_fft"); memory->create(density_B_fft,nfft_both,"pppm:density_B_fft"); } /* ---------------------------------------------------------------------- deallocate group-group memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ void PPPM::deallocate_groups() { group_allocate_flag = 0; memory->destroy3d_offset(density_A_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy3d_offset(density_B_brick,nzlo_out,nylo_out,nxlo_out); memory->destroy(density_A_fft); memory->destroy(density_B_fft); } /* ---------------------------------------------------------------------- create discretized "density" on section of global grid due to my particles density(x,y,z) = charge "density" at grid points of my 3d brick (nxlo:nxhi,nylo:nyhi,nzlo:nzhi) is extent of my brick (including ghosts) in global grid for group-group interactions ------------------------------------------------------------------------- */ void PPPM::make_rho_groups(int groupbit_A, int groupbit_B, int AA_flag) { int l,m,n,nx,ny,nz,mx,my,mz; FFT_SCALAR dx,dy,dz,x0,y0,z0; // clear 3d density arrays memset(&(density_A_brick[nzlo_out][nylo_out][nxlo_out]),0, ngrid*sizeof(FFT_SCALAR)); memset(&(density_B_brick[nzlo_out][nylo_out][nxlo_out]),0, ngrid*sizeof(FFT_SCALAR)); // loop over my charges, add their contribution to nearby grid points // (nx,ny,nz) = global coords of grid pt to "lower left" of charge // (dx,dy,dz) = distance to "lower left" grid pt // (mx,my,mz) = global coords of moving stencil pt double *q = atom->q; double **x = atom->x; int nlocal = atom->nlocal; int *mask = atom->mask; for (int i = 0; i < nlocal; i++) { if (!((mask[i] & groupbit_A) && (mask[i] & groupbit_B))) if (AA_flag) continue; if ((mask[i] & groupbit_A) || (mask[i] & groupbit_B)) { nx = part2grid[i][0]; ny = part2grid[i][1]; nz = part2grid[i][2]; dx = nx+shiftone - (x[i][0]-boxlo[0])*delxinv; dy = ny+shiftone - (x[i][1]-boxlo[1])*delyinv; dz = nz+shiftone - (x[i][2]-boxlo[2])*delzinv; compute_rho1d(dx,dy,dz); z0 = delvolinv * q[i]; for (n = nlower; n <= nupper; n++) { mz = n+nz; y0 = z0*rho1d[2][n]; for (m = nlower; m <= nupper; m++) { my = m+ny; x0 = y0*rho1d[1][m]; for (l = nlower; l <= nupper; l++) { mx = l+nx; // group A if (mask[i] & groupbit_A) density_A_brick[mz][my][mx] += x0*rho1d[0][l]; // group B if (mask[i] & groupbit_B) density_B_brick[mz][my][mx] += x0*rho1d[0][l]; } } } } } } /* ---------------------------------------------------------------------- FFT-based Poisson solver for group-group interactions ------------------------------------------------------------------------- */ void PPPM::poisson_groups(int AA_flag) { int i,j,k,n; // reuse memory (already declared) FFT_SCALAR *work_A = work1; FFT_SCALAR *work_B = work2; // transform charge density (r -> k) // group A n = 0; for (i = 0; i < nfft; i++) { work_A[n++] = density_A_fft[i]; work_A[n++] = ZEROF; } fft1->compute(work_A,work_A,1); // group B n = 0; for (i = 0; i < nfft; i++) { work_B[n++] = density_B_fft[i]; work_B[n++] = ZEROF; } fft1->compute(work_B,work_B,1); // group-group energy and force contribution, // keep everything in reciprocal space so // no inverse FFTs needed double scaleinv = 1.0/(nx_pppm*ny_pppm*nz_pppm); double s2 = scaleinv*scaleinv; // energy n = 0; for (i = 0; i < nfft; i++) { e2group += s2 * greensfn[i] * (work_A[n]*work_B[n] + work_A[n+1]*work_B[n+1]); n += 2; } if (AA_flag) return; // multiply by Green's function and s2 // (only for work_A so it is not squared below) n = 0; for (i = 0; i < nfft; i++) { work_A[n++] *= s2 * greensfn[i]; work_A[n++] *= s2 * greensfn[i]; } // triclinic system if (triclinic) { poisson_groups_triclinic(); return; } double partial_group; // force, x direction n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[0] += fkx[i] * partial_group; n += 2; } // force, y direction n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[1] += fky[j] * partial_group; n += 2; } // force, z direction n = 0; for (k = nzlo_fft; k <= nzhi_fft; k++) for (j = nylo_fft; j <= nyhi_fft; j++) for (i = nxlo_fft; i <= nxhi_fft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[2] += fkz[k] * partial_group; n += 2; } } /* ---------------------------------------------------------------------- FFT-based Poisson solver for group-group interactions for a triclinic system ------------------------------------------------------------------------- */ void PPPM::poisson_groups_triclinic() { int i,n; // reuse memory (already declared) FFT_SCALAR *work_A = work1; FFT_SCALAR *work_B = work2; double partial_group; // force, x direction n = 0; for (i = 0; i < nfft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[0] += fkx[i] * partial_group; n += 2; } // force, y direction n = 0; for (i = 0; i < nfft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[1] += fky[i] * partial_group; n += 2; } // force, z direction n = 0; for (i = 0; i < nfft; i++) { partial_group = work_A[n+1]*work_B[n] - work_A[n]*work_B[n+1]; f2group[2] += fkz[i] * partial_group; n += 2; } } /* ---------------------------------------------------------------------- Slab-geometry correction term to dampen inter-slab interactions between periodically repeating slabs. Yields good approximation to 2D Ewald if adequate empty space is left between repeating slabs (J. Chem. Phys. 111, 3155). Slabs defined here to be parallel to the xy plane. Also extended to non-neutral systems (J. Chem. Phys. 131, 094107). ------------------------------------------------------------------------- */ void PPPM::slabcorr_groups(int groupbit_A, int groupbit_B, int AA_flag) { // compute local contribution to global dipole moment double *q = atom->q; double **x = atom->x; double zprd = domain->zprd; int *mask = atom->mask; int nlocal = atom->nlocal; double qsum_A = 0.0; double qsum_B = 0.0; double dipole_A = 0.0; double dipole_B = 0.0; double dipole_r2_A = 0.0; double dipole_r2_B = 0.0; for (int i = 0; i < nlocal; i++) { if (!((mask[i] & groupbit_A) && (mask[i] & groupbit_B))) if (AA_flag) continue; if (mask[i] & groupbit_A) { qsum_A += q[i]; dipole_A += q[i]*x[i][2]; dipole_r2_A += q[i]*x[i][2]*x[i][2]; } if (mask[i] & groupbit_B) { qsum_B += q[i]; dipole_B += q[i]*x[i][2]; dipole_r2_B += q[i]*x[i][2]*x[i][2]; } } // sum local contributions to get total charge and global dipole moment // for each group double tmp; MPI_Allreduce(&qsum_A,&tmp,1,MPI_DOUBLE,MPI_SUM,world); qsum_A = tmp; MPI_Allreduce(&qsum_B,&tmp,1,MPI_DOUBLE,MPI_SUM,world); qsum_B = tmp; MPI_Allreduce(&dipole_A,&tmp,1,MPI_DOUBLE,MPI_SUM,world); dipole_A = tmp; MPI_Allreduce(&dipole_B,&tmp,1,MPI_DOUBLE,MPI_SUM,world); dipole_B = tmp; MPI_Allreduce(&dipole_r2_A,&tmp,1,MPI_DOUBLE,MPI_SUM,world); dipole_r2_A = tmp; MPI_Allreduce(&dipole_r2_B,&tmp,1,MPI_DOUBLE,MPI_SUM,world); dipole_r2_B = tmp; // compute corrections const double qscale = qqrd2e * scale; const double efact = qscale * MY_2PI/volume; e2group += efact * (dipole_A*dipole_B - 0.5*(qsum_A*dipole_r2_B + qsum_B*dipole_r2_A) - qsum_A*qsum_B*zprd*zprd/12.0); // add on force corrections const double ffact = qscale * (-4.0*MY_PI/volume); f2group[2] += ffact * (qsum_A*dipole_B - qsum_B*dipole_A); } diff --git a/src/compute_property_atom.cpp b/src/compute_property_atom.cpp index 0c20744a5..56282052c 100644 --- a/src/compute_property_atom.cpp +++ b/src/compute_property_atom.cpp @@ -1,1671 +1,1689 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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.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 "comm.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],"proc") == 0) { + pack_choice[i] = &ComputePropertyAtom::pack_proc; } 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],"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 (strcmp(arg[iarg],"nbonds") == 0) { if (!atom->molecule_flag) error->all(FLERR,"Compute property/atom for " "atom property that isn't allocated"); pack_choice[i] = &ComputePropertyAtom::pack_nbonds; } 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; // check if atom style recognizes keyword } else { index[i] = atom->avec->property_atom(arg[iarg]); if (index[i] < 0) error->all(FLERR,"Invalid keyword in compute property/atom command"); pack_choice[i] = &ComputePropertyAtom::pack_property_atom; } } 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) { 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) { tagint *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_proc(int n) +{ + int *mask = atom->mask; + int nlocal = atom->nlocal; + int me = comm->me; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) buf[n] = me; + 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_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_nbonds(int n) { int *num_bond = atom->num_bond; int *mask = atom->mask; int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = num_bond[i]; 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; } } /* ---------------------------------------------------------------------- */ void ComputePropertyAtom::pack_property_atom(int n) { atom->avec->pack_property_atom(index[n],&buf[n],nvalues,groupbit); } diff --git a/src/compute_property_atom.h b/src/compute_property_atom.h index a1a4faa97..e9e957918 100644 --- a/src/compute_property_atom.h +++ b/src/compute_property_atom.h @@ -1,159 +1,160 @@ /* -*- 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 COMPUTE_CLASS ComputeStyle(property/atom,ComputePropertyAtom) #else #ifndef LMP_COMPUTE_PROPERTY_ATOM_H #define LMP_COMPUTE_PROPERTY_ATOM_H #include "compute.h" namespace LAMMPS_NS { class ComputePropertyAtom : public Compute { public: ComputePropertyAtom(class LAMMPS *, int, char **); ~ComputePropertyAtom(); void init(); void compute_peratom(); double memory_usage(); private: int nvalues; int nmax; int *index; double *vector; double **array; double *buf; class AtomVecEllipsoid *avec_ellipsoid; class AtomVecLine *avec_line; class AtomVecTri *avec_tri; class AtomVecBody *avec_body; typedef void (ComputePropertyAtom::*FnPtrPack)(int); FnPtrPack *pack_choice; // ptrs to pack functions void pack_id(int); void pack_molecule(int); + void pack_proc(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_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_shapex(int); void pack_shapey(int); void pack_shapez(int); void pack_quatw(int); void pack_quati(int); void pack_quatj(int); void pack_quatk(int); void pack_tqx(int); void pack_tqy(int); void pack_tqz(int); void pack_end1x(int); void pack_end1y(int); void pack_end1z(int); void pack_end2x(int); void pack_end2y(int); void pack_end2z(int); void pack_corner1x(int); void pack_corner1y(int); void pack_corner1z(int); void pack_corner2x(int); void pack_corner2y(int); void pack_corner2z(int); void pack_corner3x(int); void pack_corner3y(int); void pack_corner3z(int); void pack_nbonds(int); void pack_iname(int); void pack_dname(int); void pack_property_atom(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: Compute property/atom for atom property that isn't allocated Self-explanatory. E: Compute property/atom floating point vector does not exist The command is accessing a vector added by the fix property/atom command, that does not exist. E: Compute property/atom integer vector does not exist The command is accessing a vector added by the fix property/atom command, that does not exist. E: Invalid keyword in compute property/atom command Self-explanatory. */ diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index 860f08405..f1cb9379f 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -1,2367 +1,2560 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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, +enum{ID,MOL,PROC,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, - COMPUTE,FIX,VARIABLE}; + COMPUTE,FIX,VARIABLE,INAME,DNAME}; enum{LT,LE,GT,GE,EQ,NEQ}; 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; + ncustom = 0; + id_custom = NULL; + flag_custom = 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; + for (int i = 0; i < ncustom; i++) delete [] id_custom[i]; + memory->sfree(id_custom); + delete [] flag_custom; + 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; } + int icustom; + for (int i = 0; i < ncustom; i++) { + icustom = atom->find_custom(id_custom[i],flag_custom[i]); + if (icustom < 0) + error->all(FLERR,"Could not find custom per-atom property ID"); + } + // 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]; region->prematch(); 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) { 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"); tagint *molecule = atom->molecule; for (i = 0; i < nlocal; i++) dchoose[i] = molecule[i]; ptr = dchoose; nstride = 1; + } else if (thresh_array[ithresh] == PROC) { + for (i = 0; i < nlocal; i++) dchoose[i] = me; + 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] == 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; + + } else if (thresh_array[ithresh] == DNAME) { + int iwhich,tmp; + i = nfield + ithresh; + iwhich = atom->find_custom(id_custom[field2index[i]],tmp); + ptr = atom->dvector[iwhich]; + nstride = 1; + + } else if (thresh_array[ithresh] == INAME) { + int iwhich,tmp; + i = nfield + ithresh; + iwhich = atom->find_custom(id_custom[field2index[i]],tmp); + + int *ivector = atom->ivector[iwhich]; + for (i = 0; i < nlocal; i++) + dchoose[i] = ivector[i]; + ptr = dchoose; + 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(tagint *ids) { for (int n = 0; n < size_one; n++) (this->*pack_choice[n])(n); if (ids) { 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; 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],"proc") == 0) { + pack_choice[i] = &DumpCustom::pack_proc; + 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; // 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; + // custom per-atom floating point value = d_ID + + } else if (strncmp(arg[iarg],"d_",2) == 0) { + pack_choice[i] = &DumpCustom::pack_custom; + vtype[i] = DOUBLE; + + int n = strlen(arg[iarg]); + char *suffix = new char[n]; + strcpy(suffix,&arg[iarg][2]); + argindex[i] = 0; + + int tmp = -1; + n = atom->find_custom(suffix,tmp); + if (n < 0) + error->all(FLERR,"Could not find custom per-atom property ID"); + + if (tmp != 1) + error->all(FLERR,"Custom per-atom property ID is not floating point"); + + field2index[i] = add_custom(suffix,1); + delete [] suffix; + + // custom per-atom integer value = i_ID + + } else if (strncmp(arg[iarg],"i_",2) == 0) { + pack_choice[i] = &DumpCustom::pack_custom; + vtype[i] = INT; + + int n = strlen(arg[iarg]); + char *suffix = new char[n]; + strcpy(suffix,&arg[iarg][2]); + argindex[i] = 0; + + int tmp = -1; + n = atom->find_custom(suffix,tmp); + if (n < 0) + error->all(FLERR,"Could not find custom per-atom property ID"); + + if (tmp != 0) + error->all(FLERR,"Custom per-atom property ID is not integer"); + + field2index[i] = add_custom(suffix,0); + 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; } +/* ---------------------------------------------------------------------- + add custom atom property to list used by dump + return index of where this property is in list + if already in list, do not add, just return index, else add to list +------------------------------------------------------------------------- */ + +int DumpCustom::add_custom(char *id, int flag) +{ + int icustom; + for (icustom = 0; icustom < ncustom; icustom++) + if ((strcmp(id,id_custom[icustom]) == 0) + && (flag == flag_custom[icustom])) break; + if (icustom < ncustom) return icustom; + + id_custom = (char **) + memory->srealloc(id_custom,(ncustom+1)*sizeof(char *),"dump:id_custom"); + flag_custom = (int *) + memory->srealloc(flag_custom,(ncustom+1)*sizeof(int),"dump:flag_custom"); + + int n = strlen(id) + 1; + id_custom[ncustom] = new char[n]; + strcpy(id_custom[ncustom],id); + flag_custom[ncustom] = flag; + + ncustom++; + return ncustom-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],"proc") == 0) thresh_array[nthresh] = PROC; 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; // 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; + // custom per atom floating point value = d_ID + // must grow field2index and argindex arrays, since access is beyond nfield + + } else if (strncmp(arg[1],"d_",2) == 0) { + thresh_array[nthresh] = DNAME; + 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; + + int tmp = -1; + n = atom->find_custom(suffix,tmp); + if ((n < 0) || (tmp != 1)) + error->all(FLERR,"Could not find dump modify " + "custom atom floating point property ID"); + + field2index[nfield+nthresh] = add_custom(suffix,1); + delete [] suffix; + + // custom per atom integer value = i_ID + // must grow field2index and argindex arrays, since access is beyond nfield + + } else if (strncmp(arg[1],"i_",2) == 0) { + thresh_array[nthresh] = INAME; + 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; + + int tmp = -1; + n = atom->find_custom(suffix,tmp); + if ((n < 0) || (tmp != 0)) + error->all(FLERR,"Could not find dump modify " + "custom atom integer property ID"); + + field2index[nfield+nthresh] = add_custom(suffix,0); + 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; } } +/* ---------------------------------------------------------------------- */ + +void DumpCustom::pack_custom(int n) +{ + + int index = field2index[n]; + + if (flag_custom[index] == 0) { // integer + int iwhich,tmp; + iwhich = atom->find_custom(id_custom[index],tmp); + + int *ivector = atom->ivector[iwhich]; + for (int i = 0; i < nchoose; i++) { + buf[n] = ivector[clist[i]]; + n += size_one; + } + } else if (flag_custom[index] == 1) { // double + int iwhich,tmp; + iwhich = atom->find_custom(id_custom[index],tmp); + + double *dvector = atom->dvector[iwhich]; + for (int i = 0; i < nchoose; i++) { + buf[n] = dvector[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) { 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) { tagint *molecule = atom->molecule; for (int i = 0; i < nchoose; i++) { buf[n] = molecule[clist[i]]; n += size_one; } } /* ---------------------------------------------------------------------- */ +void DumpCustom::pack_proc(int n) +{ + for (int i = 0; i < nchoose; i++) { + buf[n] = me; + 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; } } diff --git a/src/dump_custom.h b/src/dump_custom.h index b0153faf2..c483d5b7e 100644 --- a/src/dump_custom.h +++ b/src/dump_custom.h @@ -1,337 +1,344 @@ /* -*- 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 ncustom; // # of custom atom properties + char **id_custom; // their names + int *flag_custom; // their data type + 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(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 *); + int add_custom(char *, int); 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_custom(int); void pack_id(int); void pack_molecule(int); + void pack_proc(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); }; } #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 Self-explanatory. 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/library.cpp b/src/library.cpp index 2ca41aa96..2018c0ee7 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -1,534 +1,537 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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,"xy") == 0) return (void *) &lmp->domain->xy; + if (strcmp(name,"xz") == 0) return (void *) &lmp->domain->xz; + if (strcmp(name,"yz") == 0) return (void *) &lmp->domain->yz; 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; lammps_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; lammps_free(dptr); e.g. for atom-style variables double *vector = (double *) lammps_extract_variable(); use the vector values lammps_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; 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; 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/molecule.cpp b/src/molecule.cpp index c118431f9..af2dfaf60 100644 --- a/src/molecule.cpp +++ b/src/molecule.cpp @@ -1,1431 +1,1433 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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, char *idarg, char *file) : Pointers(lmp) { me = comm->me; int n = strlen(idarg) + 1; id = new char[n]; strcpy(id,idarg); for (int i = 0; i < n-1; i++) if (!isalnum(id[i]) && id[i] != '_') error->all(FLERR,"Molecule template ID must be " "alphanumeric or underscore characters"); // 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->mass[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->mass[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 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"); } // 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 = 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 = 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 = 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 = 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 = 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 = 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 ((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 (!specialflag && bondflag) + error->all(FLERR,"Molecule file has bonds but no special flags"); 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 ntypes = 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) error->all(FLERR,"Invalid atom type in molecule file"); for (int i = 0; i < natoms; i++) ntypes = MAX(ntypes,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 set nbondtypes = max type of any bond 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 tmp,itype; tagint m,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 " TAGINT_FORMAT " " TAGINT_FORMAT, &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) error->one(FLERR,"Invalid bond type in Bonds section of molecule file"); if (flag) { m = atom1-1; nbondtypes = MAX(nbondtypes,itype); 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 tmp,itype; tagint m,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 " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, &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) error->one(FLERR,"Invalid angle type in Angles section of molecule file"); if (flag) { m = atom2-1; nangletypes = MAX(nangletypes,itype); 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 tmp,itype; tagint m,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 " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " ", &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) error->one(FLERR, "Invalid dihedral type in dihedrals section of molecule file"); if (flag) { m = atom2-1; ndihedraltypes = MAX(ndihedraltypes,itype); 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) { 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; dihedral_atom4[m][num_dihedral[m]] = atom4; 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; dihedral_atom4[m][num_dihedral[m]] = atom4; 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; dihedral_atom4[m][num_dihedral[m]] = atom4; 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 tmp,itype; tagint m,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 " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " ", &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) error->one(FLERR, "Invalid improper type in impropers section of molecule file"); if (flag) { m = atom2-1; nimpropertypes = MAX(nimpropertypes,itype); 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) { 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; improper_atom4[m][num_improper[m]] = atom4; 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; improper_atom4[m][num_improper[m]] = atom4; 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; improper_atom4[m][num_improper[m]] = atom4; 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] = ATOTAGINT(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 " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, &tmp,&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]); else if (shake_flag[i] == 2) sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT, &tmp,&shake_atom[i][0],&shake_atom[i][1]); else if (shake_flag[i] == 3) sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, &tmp,&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]); else if (shake_flag[i] == 4) sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, &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) error->all(FLERR,"Invalid shake bond type in molecule file"); if (shake_flag[i] == 1) if (shake_type[i][2] <= 0) error->all(FLERR,"Invalid shake angle type in molecule file"); } } /* ---------------------------------------------------------------------- error check molecule attributes and topology against system settings flag = 0, just check this molecule flag = 1, check all molecules in set, this is 1st molecule in set ------------------------------------------------------------------------- */ void Molecule::check_attributes(int flag) { int n = 1; if (flag) n = nset; int imol = atom->find_molecule(id); for (int i = imol; i < imol+n; i++) { Molecule *onemol = atom->molecules[imol]; // check per-atom attributes of molecule // warn if not a match int mismatch = 0; if (onemol->qflag && !atom->q_flag) mismatch = 1; if (onemol->radiusflag && !atom->radius_flag) mismatch = 1; if (onemol->rmassflag && !atom->rmass_flag) mismatch = 1; if (mismatch && me == 0) error->warning(FLERR, "Molecule attributes do not match system attributes"); // for all atom styles, check nbondtype,etc mismatch = 0; if (atom->nbondtypes < onemol->nbondtypes) mismatch = 1; if (atom->nangletypes < onemol->nangletypes) mismatch = 1; if (atom->ndihedraltypes < onemol->ndihedraltypes) mismatch = 1; if (atom->nimpropertypes < onemol->nimpropertypes) mismatch = 1; if (mismatch) error->all(FLERR,"Molecule topology type exceeds system topology type"); // for molecular atom styles, check bond_per_atom,etc + maxspecial // do not check for atom style template, since nothing stored per atom if (atom->molecular == 1) { if (atom->avec->bonds_allow && atom->bond_per_atom < onemol->bond_per_atom) mismatch = 1; if (atom->avec->angles_allow && atom->angle_per_atom < onemol->angle_per_atom) mismatch = 1; if (atom->avec->dihedrals_allow && atom->dihedral_per_atom < onemol->dihedral_per_atom) mismatch = 1; if (atom->avec->impropers_allow && atom->improper_per_atom < onemol->improper_per_atom) mismatch = 1; if (atom->maxspecial < onemol->maxspecial) mismatch = 1; if (mismatch) error->all(FLERR,"Molecule toplogy/atom exceeds system topology/atom"); } // warn if molecule topology defined but no special settings if (onemol->bondflag && !onemol->specialflag) if (me == 0) error->warning(FLERR,"Molecule has bond topology " "but no special bond settings"); } } /* ---------------------------------------------------------------------- init all data structures to empty ------------------------------------------------------------------------- */ void Molecule::initialize() { natoms = 0; nbonds = nangles = ndihedrals = nimpropers = 0; ntypes = 0; nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 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 = NULL; shake_type = NULL; dx = NULL; dxcom = NULL; dxbody = NULL; } /* ---------------------------------------------------------------------- allocate all data structures also initialize values for data structures that are always allocated ------------------------------------------------------------------------- */ 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"); // always allocate num_bond,num_angle,etc and nspecial even if not in file // initialize to 0 even if not in molecule file // this is so methods that use these arrays don't have to check they exist memory->create(num_bond,natoms,"molecule:num_bond"); for (int i = 0; i < natoms; i++) num_bond[i] = 0; memory->create(num_angle,natoms,"molecule:num_angle"); for (int i = 0; i < natoms; i++) num_angle[i] = 0; memory->create(num_dihedral,natoms,"molecule:num_dihedral"); for (int i = 0; i < natoms; i++) num_dihedral[i] = 0; memory->create(num_improper,natoms,"molecule:num_improper"); for (int i = 0; i < natoms; i++) num_improper[i] = 0; memory->create(nspecial,natoms,3,"molecule:nspecial"); for (int i = 0; i < natoms; i++) nspecial[i][0] = nspecial[i][1] = nspecial[i][2] = 0; if (bondflag) { 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(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(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(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 (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/update.cpp b/src/update.cpp index aac3e7382..a2017db06 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -1,466 +1,478 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "stdlib.h" #include "update.h" #include "integrate.h" #include "min.h" #include "style_integrate.h" #include "style_minimize.h" #include "neighbor.h" +#include "neigh_list.h" #include "force.h" #include "modify.h" #include "fix.h" #include "domain.h" #include "region.h" #include "compute.h" #include "output.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Update::Update(LAMMPS *lmp) : Pointers(lmp) { char *str; ntimestep = 0; atime = 0.0; atimestep = 0; first_update = 0; whichflag = 0; firststep = laststep = 0; beginstep = endstep = 0; setupflag = 0; multireplica = 0; restrict_output = 0; eflag_global = vflag_global = -1; unit_style = NULL; set_units("lj"); integrate_style = NULL; integrate = NULL; minimize_style = NULL; minimize = NULL; str = (char *) "verlet"; create_integrate(1,&str,lmp->suffix); str = (char *) "cg"; create_minimize(1,&str); } /* ---------------------------------------------------------------------- */ Update::~Update() { delete [] unit_style; delete [] integrate_style; delete integrate; delete [] minimize_style; delete minimize; } /* ---------------------------------------------------------------------- */ void Update::init() { // if USER-CUDA mode is enabled: // integrate/minimize style must be CUDA variant if (whichflag == 1 && lmp->cuda) if (strstr(integrate_style,"cuda") == NULL) error->all(FLERR,"USER-CUDA mode requires CUDA variant of run style"); if (whichflag == 2 && lmp->cuda) if (strstr(minimize_style,"cuda") == NULL) error->all(FLERR,"USER-CUDA mode requires CUDA variant of min style"); // init the appropriate integrate and/or minimize class // if neither (e.g. from write_restart) then just return if (whichflag == 0) return; if (whichflag == 1) integrate->init(); else if (whichflag == 2) minimize->init(); // only set first_update if a run or minimize is being performed first_update = 1; } /* ---------------------------------------------------------------------- */ void Update::set_units(const char *style) { // physical constants from: // http://physics.nist.gov/cuu/Constants/Table/allascii.txt // using thermochemical calorie = 4.184 J if (strcmp(style,"lj") == 0) { force->boltz = 1.0; force->hplanck = 0.18292026; // using LJ parameters for argon force->mvv2e = 1.0; force->ftm2v = 1.0; force->mv2d = 1.0; force->nktv2p = 1.0; force->qqr2e = 1.0; force->qe2f = 1.0; force->vxmu2f = 1.0; force->xxt2kmu = 1.0; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0; force->femtosecond = 1.0; force->qelectron = 1.0; dt = 0.005; neighbor->skin = 0.3; } else if (strcmp(style,"real") == 0) { force->boltz = 0.0019872067; force->hplanck = 95.306976368; force->mvv2e = 48.88821291 * 48.88821291; force->ftm2v = 1.0 / 48.88821291 / 48.88821291; force->mv2d = 1.0 / 0.602214179; force->nktv2p = 68568.415; force->qqr2e = 332.06371; force->qe2f = 23.060549; force->vxmu2f = 1.4393264316e4; force->xxt2kmu = 0.1; force->e_mass = 1.0/1836.1527556560675; force->hhmrr2e = 0.0957018663603261; force->mvh2r = 1.5339009481951; force->angstrom = 1.0; force->femtosecond = 1.0; force->qelectron = 1.0; dt = 1.0; neighbor->skin = 2.0; } else if (strcmp(style,"metal") == 0) { force->boltz = 8.617343e-5; force->hplanck = 4.135667403e-3; force->mvv2e = 1.0364269e-4; force->ftm2v = 1.0 / 1.0364269e-4; force->mv2d = 1.0 / 0.602214179; force->nktv2p = 1.6021765e6; force->qqr2e = 14.399645; force->qe2f = 1.0; force->vxmu2f = 0.6241509647; force->xxt2kmu = 1.0e-4; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0; force->femtosecond = 1.0e-3; force->qelectron = 1.0; dt = 0.001; neighbor->skin = 2.0; } else if (strcmp(style,"si") == 0) { force->boltz = 1.3806504e-23; force->hplanck = 6.62606896e-34; force->mvv2e = 1.0; force->ftm2v = 1.0; force->mv2d = 1.0; force->nktv2p = 1.0; force->qqr2e = 8.9876e9; force->qe2f = 1.0; force->vxmu2f = 1.0; force->xxt2kmu = 1.0; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0e-10; force->femtosecond = 1.0e-15; force->qelectron = 1.6021765e-19; dt = 1.0e-8; neighbor->skin = 0.001; } else if (strcmp(style,"cgs") == 0) { force->boltz = 1.3806504e-16; force->hplanck = 6.62606896e-27; force->mvv2e = 1.0; force->ftm2v = 1.0; force->mv2d = 1.0; force->nktv2p = 1.0; force->qqr2e = 1.0; force->qe2f = 1.0; force->vxmu2f = 1.0; force->xxt2kmu = 1.0; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0e-8; force->femtosecond = 1.0e-15; force->qelectron = 4.8032044e-10; dt = 1.0e-8; neighbor->skin = 0.1; } else if (strcmp(style,"electron") == 0) { force->boltz = 3.16681534e-6; force->hplanck = 0.1519829846; force->mvv2e = 1.06657236; force->ftm2v = 0.937582899; force->mv2d = 1.0; force->nktv2p = 2.94210108e13; force->qqr2e = 1.0; force->qe2f = 1.94469051e-10; force->vxmu2f = 3.39893149e1; force->xxt2kmu = 3.13796367e-2; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.88972612; force->femtosecond = 0.0241888428; force->qelectron = 1.0; dt = 0.001; neighbor->skin = 2.0; } else if (strcmp(style,"micro") == 0) { force->boltz = 1.3806504e-8; force->hplanck = 6.62606896e-13; force->mvv2e = 1.0; force->ftm2v = 1.0; force->mv2d = 1.0; force->nktv2p = 1.0; force->qqr2e = 8.987556e6; force->qe2f = 1.0; force->vxmu2f = 1.0; force->xxt2kmu = 1.0; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0e-4; force->femtosecond = 1.0e-9; force->qelectron = 1.6021765e-7; dt = 2.0; neighbor->skin = 0.1; } else if (strcmp(style,"nano") == 0) { force->boltz = 0.013806504; force->hplanck = 6.62606896e-4; force->mvv2e = 1.0; force->ftm2v = 1.0; force->mv2d = 1.0; force->nktv2p = 1.0; force->qqr2e = 230.7078669; force->qe2f = 1.0; force->vxmu2f = 1.0; force->xxt2kmu = 1.0; force->e_mass = 0.0; // not yet set force->hhmrr2e = 0.0; force->mvh2r = 0.0; force->angstrom = 1.0e-1; force->femtosecond = 1.0e-6; force->qelectron = 1.0; dt = 0.00045; neighbor->skin = 0.1; } else error->all(FLERR,"Illegal units command"); delete [] unit_style; int n = strlen(style) + 1; unit_style = new char[n]; strcpy(unit_style,style); } /* ---------------------------------------------------------------------- */ void Update::create_integrate(int narg, char **arg, char *suffix) { if (narg < 1) error->all(FLERR,"Illegal run_style command"); delete [] integrate_style; delete integrate; int sflag; new_integrate(arg[0],narg-1,&arg[1],suffix,sflag); if (sflag) { char estyle[256]; sprintf(estyle,"%s/%s",arg[0],suffix); int n = strlen(estyle) + 1; integrate_style = new char[n]; strcpy(integrate_style,estyle); } else { int n = strlen(arg[0]) + 1; integrate_style = new char[n]; strcpy(integrate_style,arg[0]); } } /* ---------------------------------------------------------------------- create the Integrate style, first with suffix appended ------------------------------------------------------------------------- */ void Update::new_integrate(char *style, int narg, char **arg, char *suffix, int &sflag) { int success = 0; if (suffix && lmp->suffix_enable) { sflag = 1; char estyle[256]; sprintf(estyle,"%s/%s",style,suffix); success = 1; if (0) return; #define INTEGRATE_CLASS #define IntegrateStyle(key,Class) \ else if (strcmp(estyle,#key) == 0) integrate = new Class(lmp,narg,arg); #include "style_integrate.h" #undef IntegrateStyle #undef INTEGRATE_CLASS else success = 0; } if (!success) { sflag = 0; if (0) return; #define INTEGRATE_CLASS #define IntegrateStyle(key,Class) \ else if (strcmp(style,#key) == 0) integrate = new Class(lmp,narg,arg); #include "style_integrate.h" #undef IntegrateStyle #undef INTEGRATE_CLASS else error->all(FLERR,"Illegal integrate style"); } } /* ---------------------------------------------------------------------- */ void Update::create_minimize(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal min_style command"); delete [] minimize_style; delete minimize; if (0) return; // dummy line to enable else-if macro expansion #define MINIMIZE_CLASS #define MinimizeStyle(key,Class) \ else if (strcmp(arg[0],#key) == 0) minimize = new Class(lmp); #include "style_minimize.h" #undef MINIMIZE_CLASS else error->all(FLERR,"Illegal min_style command"); int n = strlen(arg[0]) + 1; minimize_style = new char[n]; strcpy(minimize_style,arg[0]); } /* ---------------------------------------------------------------------- reset timestep as called from input script ------------------------------------------------------------------------- */ void Update::reset_timestep(int narg, char **arg) { if (narg != 1) error->all(FLERR,"Illegal reset_timestep command"); bigint newstep = ATOBIGINT(arg[0]); reset_timestep(newstep); } /* ---------------------------------------------------------------------- reset timestep - set atimestep to new timestep, so future update_time() calls will be correct - trigger reset of timestep for output and for fixes that require it - do not allow any timestep-dependent fixes to be defined - reset eflag/vflag global so nothing will think eng/virial are current - reset invoked flags of computes, - so nothing will think they are current between runs - clear timestep list of computes that store future invocation times called from rerun command and input script (indirectly) ------------------------------------------------------------------------- */ void Update::reset_timestep(bigint newstep) { ntimestep = newstep; if (ntimestep < 0) error->all(FLERR,"Timestep must be >= 0"); if (ntimestep > MAXBIGINT) error->all(FLERR,"Too big a timestep"); + // set atimestep to new timestep + // so future update_time() calls will be correct + atimestep = ntimestep; + // trigger reset of timestep for output and for fixes that require it + // do not allow any timestep-dependent fixes to be defined + output->reset_timestep(ntimestep); for (int i = 0; i < modify->nfix; i++) { if (modify->fix[i]->time_depend) error->all(FLERR, "Cannot reset timestep with a time-dependent fix defined"); modify->fix[i]->reset_timestep(ntimestep); } + // reset eflag/vflag global so no commands will think eng/virial are current + eflag_global = vflag_global = -1; + // reset invoked flags of computes, + // so no commands will think they are current between runs + for (int i = 0; i < modify->ncompute; i++) { modify->compute[i]->invoked_scalar = -1; modify->compute[i]->invoked_vector = -1; modify->compute[i]->invoked_array = -1; modify->compute[i]->invoked_peratom = -1; modify->compute[i]->invoked_local = -1; } + // clear timestep list of computes that store future invocation times + for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); + // set last_build of all neigh lists to -1 to force rebuild + + for (int i = 0; i < neighbor->nlist; i++) + neighbor->lists[i]->last_build = -1; + // NOTE: 7Jun12, adding rerun command, don't think this is required //for (int i = 0; i < domain->nregion; i++) // if (domain->regions[i]->dynamic_check()) // error->all(FLERR,"Cannot reset timestep with a dynamic region defined"); } /* ---------------------------------------------------------------------- update elapsed simulation time called at end of runs or when timestep size changes ------------------------------------------------------------------------- */ void Update::update_time() { atime += (ntimestep-atimestep) * dt; atimestep = ntimestep; } /* ---------------------------------------------------------------------- memory usage of update and integrate/minimize ------------------------------------------------------------------------- */ bigint Update::memory_usage() { bigint bytes = 0; if (whichflag == 1) bytes += integrate->memory_usage(); else if (whichflag == 2) bytes += minimize->memory_usage(); return bytes; } diff --git a/src/version.h b/src/version.h index 7e1adf092..25d90d961 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "11 Jul 2014" +#define LAMMPS_VERSION "22 Jul 2014"