diff --git a/doc/Manual.html b/doc/Manual.html index 84a071a6d..ac4f3e1af 100644 --- a/doc/Manual.html +++ b/doc/Manual.html @@ -1,435 +1,435 @@ <HTML> <HEAD> <TITLE>LAMMPS-ICMS Users Manual</TITLE> <META NAME="docnumber" CONTENT="24 Jan 2013 version"> <META NAME="author" CONTENT="http://lammps.sandia.gov - Sandia National Laboratories"> <META NAME="copyright" CONTENT="Copyright (2003) Sandia Corporation. This software and manual is distributed under the GNU General Public License."> </HEAD> <BODY> <CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> </CENTER> <HR> <H1></H1> <CENTER><H3>LAMMPS-ICMS Documentation </H3></CENTER> -<CENTER><H4>14 May 2013 version +<CENTER><H4>24 May 2013 version </H4></CENTER> <H4>Version info: </H4> <P>The LAMMPS "version" is the date when it was released, such as 1 May 2010. LAMMPS is updated continuously. Whenever we fix a bug or add a feature, we release it immediately, and post a notice on <A HREF = "http://lammps.sandia.gov/bug.html">this page of the WWW site</A>. Each dated copy of LAMMPS contains all the features and bug-fixes up to and including that version date. The version date is printed to the screen and logfile every time you run LAMMPS. It is also in the file src/version.h and in the LAMMPS directory name created when you unpack a tarball, and at the top of the first page of the manual (this page). </P> <P>LAMMPS-ICMS is an experimental variant of LAMMPS with additional features made available for testing before they will be submitted for inclusion into the official LAMMPS tree. The source code is based on the official LAMMPS svn repository mirror at the Institute for Computational Molecular Science at Temple University and generally kept up-to-date as much as possible. Sometimes, e.g. when additional development work is needed to adapt the upstream changes into LAMMPS-ICMS it can take longer until synchronization; and occasionally, e.g. in case of the rewrite of the multi-threading support, the development will be halted except for important bugfixes until all features of LAMMPS-ICMS fully compatible with the upstream version or replaced by alternate implementations. </P> <UL><LI>If you browse the HTML doc pages on the LAMMPS WWW site, they always describe the most current version of upstream LAMMPS, but may be missing some new features in LAMMPS-ICMS. <LI>If you browse the HTML doc pages included in your tarball, they describe the version you have, however, not all new features in LAMMPS-ICMS are documented immediately. <LI>The <A HREF = "Manual.pdf">PDF file</A> on the WWW site or in the tarball is updated about once per month. This is because it is large, and we don't want it to be part of every patch. <LI>There is also a <A HREF = "Developer.pdf">Developer.pdf</A> file in the doc directory, which describes the internal structure and algorithms of LAMMPS. </UL> <P>LAMMPS stands for Large-scale Atomic/Molecular Massively Parallel Simulator. </P> <P>LAMMPS is a classical molecular dynamics simulation code designed to run efficiently on parallel computers. It was developed at Sandia National Laboratories, a US Department of Energy facility, with funding from the DOE. It is an open-source code, distributed freely under the terms of the GNU Public License (GPL). </P> <P>The primary developers of LAMMPS are <A HREF = "http://www.sandia.gov/~sjplimp">Steve Plimpton</A>, Aidan Thompson, and Paul Crozier who can be contacted at sjplimp,athomps,pscrozi at sandia.gov. The <A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> at http://lammps.sandia.gov has more information about the code and its uses. </P> <HR> <P>The LAMMPS documentation is organized into the following sections. If you find errors or omissions in this manual or have suggestions for useful information to add, please send an email to the developers so we can improve the LAMMPS documentation. </P> <P>Once you are familiar with LAMMPS, you may want to bookmark <A HREF = "Section_commands.html#comm">this page</A> at Section_commands.html#comm since it gives quick access to documentation for all LAMMPS commands. </P> <P><A HREF = "Manual.pdf">PDF file</A> of the entire manual, generated by <A HREF = "http://www.easysw.com/htmldoc">htmldoc</A> </P> <OL><LI><A HREF = "Section_intro.html">Introduction</A> <UL> 1.1 <A HREF = "Section_intro.html#intro_1">What is LAMMPS</A> <BR> 1.2 <A HREF = "Section_intro.html#intro_2">LAMMPS features</A> <BR> 1.3 <A HREF = "Section_intro.html#intro_3">LAMMPS non-features</A> <BR> 1.4 <A HREF = "Section_intro.html#intro_4">Open source distribution</A> <BR> 1.5 <A HREF = "Section_intro.html#intro_5">Acknowledgments and citations</A> <BR></UL> <LI><A HREF = "Section_start.html">Getting started</A> <UL> 2.1 <A HREF = "Section_start.html#start_1">What's in the LAMMPS distribution</A> <BR> 2.2 <A HREF = "Section_start.html#start_2">Making LAMMPS</A> <BR> 2.3 <A HREF = "Section_start.html#start_3">Making LAMMPS with optional packages</A> <BR> 2.4 <A HREF = "Section_start.html#start_4">Building LAMMPS via the Make.py script</A> <BR> 2.5 <A HREF = "Section_start.html#start_5">Building LAMMPS as a library</A> <BR> 2.6 <A HREF = "Section_start.html#start_6">Running LAMMPS</A> <BR> 2.7 <A HREF = "Section_start.html#start_7">Command-line options</A> <BR> 2.8 <A HREF = "Section_start.html#start_8">Screen output</A> <BR> 2.9 <A HREF = "Section_start.html#start_9">Tips for users of previous versions</A> <BR></UL> <LI><A HREF = "Section_commands.html">Commands</A> <UL> 3.1 <A HREF = "Section_commands.html#cmd_1">LAMMPS input script</A> <BR> 3.2 <A HREF = "Section_commands.html#cmd_2">Parsing rules</A> <BR> 3.3 <A HREF = "Section_commands.html#cmd_3">Input script structure</A> <BR> 3.4 <A HREF = "Section_commands.html#cmd_4">Commands listed by category</A> <BR> 3.5 <A HREF = "Section_commands.html#cmd_5">Commands listed alphabetically</A> <BR></UL> <LI><A HREF = "Section_packages.html">Packages</A> <UL> 4.1 <A HREF = "Section_packages.html#pkg_1">Standard packages</A> <BR> 4.2 <A HREF = "Section_packages.html#pkg_2">User packages</A> <BR></UL> <LI><A HREF = "Section_accelerate.html">Accelerating LAMMPS performance</A> <UL> 5.1 <A HREF = "Section_accelerate.html#acc_1">Measuring performance</A> <BR> 5.2 <A HREF = "Section_accelerate.html#acc_2">General strategies</A> <BR> 5.3 <A HREF = "Section_accelerate.html#acc_3">Packages with optimized styles</A> <BR> 5.4 <A HREF = "Section_accelerate.html#acc_4">OPT package</A> <BR> 5.5 <A HREF = "Section_accelerate.html#acc_5">USER-OMP package</A> <BR> 5.6 <A HREF = "Section_accelerate.html#acc_6">GPU package</A> <BR> 5.7 <A HREF = "Section_accelerate.html#acc_7">USER-CUDA package</A> <BR> 5.8 <A HREF = "Section_accelerate.html#acc_8">Comparison of GPU and USER-CUDA packages</A> <BR></UL> <LI><A HREF = "Section_howto.html">How-to discussions</A> <UL> 6.1 <A HREF = "Section_howto.html#howto_1">Restarting a simulation</A> <BR> 6.2 <A HREF = "Section_howto.html#howto_2">2d simulations</A> <BR> 6.3 <A HREF = "Section_howto.html#howto_3">CHARMM and AMBER force fields</A> <BR> 6.4 <A HREF = "Section_howto.html#howto_4">Running multiple simulations from one input script</A> <BR> 6.5 <A HREF = "Section_howto.html#howto_5">Multi-replica simulations</A> <BR> 6.6 <A HREF = "Section_howto.html#howto_6">Granular models</A> <BR> 6.7 <A HREF = "Section_howto.html#howto_7">TIP3P water model</A> <BR> 6.8 <A HREF = "Section_howto.html#howto_8">TIP4P water model</A> <BR> 6.9 <A HREF = "Section_howto.html#howto_9">SPC water model</A> <BR> 6.10 <A HREF = "Section_howto.html#howto_10">Coupling LAMMPS to other codes</A> <BR> 6.11 <A HREF = "Section_howto.html#howto_11">Visualizing LAMMPS snapshots</A> <BR> 6.12 <A HREF = "Section_howto.html#howto_12">Triclinic (non-orthogonal) simulation boxes</A> <BR> 6.13 <A HREF = "Section_howto.html#howto_13">NEMD simulations</A> <BR> 6.14 <A HREF = "Section_howto.html#howto_14">Finite-size spherical and aspherical particles</A> <BR> 6.15 <A HREF = "Section_howto.html#howto_15">Output from LAMMPS (thermo, dumps, computes, fixes, variables)</A> <BR> 6.16 <A HREF = "Section_howto.html#howto_16">Thermostatting, barostatting, and compute temperature</A> <BR> 6.17 <A HREF = "Section_howto.html#howto_17">Walls</A> <BR> 6.18 <A HREF = "Section_howto.html#howto_18">Elastic constants</A> <BR> 6.19 <A HREF = "Section_howto.html#howto_19">Library interface to LAMMPS</A> <BR> 6.20 <A HREF = "Section_howto.html#howto_20">Calculating thermal conductivity</A> <BR> 6.21 <A HREF = "Section_howto.html#howto_21">Calculating viscosity</A> <BR></UL> <LI><A HREF = "Section_example.html">Example problems</A> <LI><A HREF = "Section_perf.html">Performance & scalability</A> <LI><A HREF = "Section_tools.html">Additional tools</A> <LI><A HREF = "Section_modify.html">Modifying & extending LAMMPS</A> <UL> 10.1 <A HREF = "Section_modify.html#mod_1">Atom styles</A> <BR> 10.2 <A HREF = "Section_modify.html#mod_2">Bond, angle, dihedral, improper potentials</A> <BR> 10.3 <A HREF = "Section_modify.html#mod_3">Compute styles</A> <BR> 10.4 <A HREF = "Section_modify.html#mod_4">Dump styles</A> <BR> 10.5 <A HREF = "Section_modify.html#mod_5">Dump custom output options</A> <BR> 10.6 <A HREF = "Section_modify.html#mod_6">Fix styles</A> <BR> 10.7 <A HREF = "Section_modify.html#mod_7">Input script commands</A> <BR> 10.8 <A HREF = "Section_modify.html#mod_8">Kspace computations</A> <BR> 10.9 <A HREF = "Section_modify.html#mod_9">Minimization styles</A> <BR> 10.10 <A HREF = "Section_modify.html#mod_10">Pairwise potentials</A> <BR> 10.11 <A HREF = "Section_modify.html#mod_11">Region styles</A> <BR> 10.12 <A HREF = "Section_modify.html#mod_12">Body styles</A> <BR> 10.13 <A HREF = "Section_modify.html#mod_13">Thermodynamic output options</A> <BR> 10.14 <A HREF = "Section_modify.html#mod_14">Variable options</A> <BR> 10.15 <A HREF = "Section_modify.html#mod_15">Submitting new features for inclusion in LAMMPS</A> <BR></UL> <LI><A HREF = "Section_python.html">Python interface</A> <UL> 11.1 <A HREF = "Section_python.html#py_1">Building LAMMPS as a shared library</A> <BR> 11.2 <A HREF = "Section_python.html#py_2">Installing the Python wrapper into Python</A> <BR> 11.3 <A HREF = "Section_python.html#py_3">Extending Python with MPI to run in parallel</A> <BR> 11.4 <A HREF = "Section_python.html#py_4">Testing the Python-LAMMPS interface</A> <BR> 11.5 <A HREF = "Section_python.html#py_5">Using LAMMPS from Python</A> <BR> 11.6 <A HREF = "Section_python.html#py_6">Example Python scripts that use LAMMPS</A> <BR></UL> <LI><A HREF = "Section_errors.html">Errors</A> <UL> 12.1 <A HREF = "Section_errors.html#err_1">Common problems</A> <BR> 12.2 <A HREF = "Section_errors.html#err_2">Reporting bugs</A> <BR> 12.3 <A HREF = "Section_errors.html#err_3">Error & warning messages</A> <BR></UL> <LI><A HREF = "Section_history.html">Future and history</A> <UL> 13.1 <A HREF = "Section_history.html#hist_1">Coming attractions</A> <BR> 13.2 <A HREF = "Section_history.html#hist_2">Past versions</A> <BR></UL> </OL> </BODY> </HTML> diff --git a/doc/Manual.txt b/doc/Manual.txt index 38f1f4c5d..8e0aa5aa1 100644 --- a/doc/Manual.txt +++ b/doc/Manual.txt @@ -1,273 +1,273 @@ <HEAD> <TITLE>LAMMPS-ICMS Users Manual</TITLE> <META NAME="docnumber" CONTENT="24 Jan 2013 version"> <META NAME="author" CONTENT="http://lammps.sandia.gov - Sandia National Laboratories"> <META NAME="copyright" CONTENT="Copyright (2003) Sandia Corporation. This software and manual is distributed under the GNU General Public License."> </HEAD> <BODY> "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line <H1></H1> LAMMPS-ICMS Documentation :c,h3 -14 May 2013 version :c,h4 +24 May 2013 version :c,h4 Version info: :h4 The LAMMPS "version" is the date when it was released, such as 1 May 2010. LAMMPS is updated continuously. Whenever we fix a bug or add a feature, we release it immediately, and post a notice on "this page of the WWW site"_bug. Each dated copy of LAMMPS contains all the features and bug-fixes up to and including that version date. The version date is printed to the screen and logfile every time you run LAMMPS. It is also in the file src/version.h and in the LAMMPS directory name created when you unpack a tarball, and at the top of the first page of the manual (this page). LAMMPS-ICMS is an experimental variant of LAMMPS with additional features made available for testing before they will be submitted for inclusion into the official LAMMPS tree. The source code is based on the official LAMMPS svn repository mirror at the Institute for Computational Molecular Science at Temple University and generally kept up-to-date as much as possible. Sometimes, e.g. when additional development work is needed to adapt the upstream changes into LAMMPS-ICMS it can take longer until synchronization; and occasionally, e.g. in case of the rewrite of the multi-threading support, the development will be halted except for important bugfixes until all features of LAMMPS-ICMS fully compatible with the upstream version or replaced by alternate implementations. If you browse the HTML doc pages on the LAMMPS WWW site, they always describe the most current version of upstream LAMMPS, but may be missing some new features in LAMMPS-ICMS. :ulb,l If you browse the HTML doc pages included in your tarball, they describe the version you have, however, not all new features in LAMMPS-ICMS are documented immediately. :l The "PDF file"_Manual.pdf on the WWW site or in the tarball is updated about once per month. This is because it is large, and we don't want it to be part of every patch. :l There is also a "Developer.pdf"_Developer.pdf file in the doc directory, which describes the internal structure and algorithms of LAMMPS. :ule,l LAMMPS stands for Large-scale Atomic/Molecular Massively Parallel Simulator. LAMMPS is a classical molecular dynamics simulation code designed to run efficiently on parallel computers. It was developed at Sandia National Laboratories, a US Department of Energy facility, with funding from the DOE. It is an open-source code, distributed freely under the terms of the GNU Public License (GPL). The primary developers of LAMMPS are "Steve Plimpton"_sjp, Aidan Thompson, and Paul Crozier who can be contacted at sjplimp,athomps,pscrozi at sandia.gov. The "LAMMPS WWW Site"_lws at http://lammps.sandia.gov has more information about the code and its uses. :link(bug,http://lammps.sandia.gov/bug.html) :link(sjp,http://www.sandia.gov/~sjplimp) :line The LAMMPS documentation is organized into the following sections. If you find errors or omissions in this manual or have suggestions for useful information to add, please send an email to the developers so we can improve the LAMMPS documentation. Once you are familiar with LAMMPS, you may want to bookmark "this page"_Section_commands.html#comm at Section_commands.html#comm since it gives quick access to documentation for all LAMMPS commands. "PDF file"_Manual.pdf of the entire manual, generated by "htmldoc"_http://www.easysw.com/htmldoc "Introduction"_Section_intro.html :olb,l 1.1 "What is LAMMPS"_intro_1 :ulb,b 1.2 "LAMMPS features"_intro_2 :b 1.3 "LAMMPS non-features"_intro_3 :b 1.4 "Open source distribution"_intro_4 :b 1.5 "Acknowledgments and citations"_intro_5 :ule,b "Getting started"_Section_start.html :l 2.1 "What's in the LAMMPS distribution"_start_1 :ulb,b 2.2 "Making LAMMPS"_start_2 :b 2.3 "Making LAMMPS with optional packages"_start_3 :b 2.4 "Building LAMMPS via the Make.py script"_start_4 :b 2.5 "Building LAMMPS as a library"_start_5 :b 2.6 "Running LAMMPS"_start_6 :b 2.7 "Command-line options"_start_7 :b 2.8 "Screen output"_start_8 :b 2.9 "Tips for users of previous versions"_start_9 :ule,b "Commands"_Section_commands.html :l 3.1 "LAMMPS input script"_cmd_1 :ulb,b 3.2 "Parsing rules"_cmd_2 :b 3.3 "Input script structure"_cmd_3 :b 3.4 "Commands listed by category"_cmd_4 :b 3.5 "Commands listed alphabetically"_cmd_5 :ule,b "Packages"_Section_packages.html :l 4.1 "Standard packages"_pkg_1 :ulb,b 4.2 "User packages"_pkg_2 :ule,b "Accelerating LAMMPS performance"_Section_accelerate.html :l 5.1 "Measuring performance"_acc_1 :ulb,b 5.2 "General strategies"_acc_2 :b 5.3 "Packages with optimized styles"_acc_3 :b 5.4 "OPT package"_acc_4 :b 5.5 "USER-OMP package"_acc_5 :b 5.6 "GPU package"_acc_6 :b 5.7 "USER-CUDA package"_acc_7 :b 5.8 "Comparison of GPU and USER-CUDA packages"_acc_8 :ule,b "How-to discussions"_Section_howto.html :l 6.1 "Restarting a simulation"_howto_1 :ulb,b 6.2 "2d simulations"_howto_2 :b 6.3 "CHARMM and AMBER force fields"_howto_3 :b 6.4 "Running multiple simulations from one input script"_howto_4 :b 6.5 "Multi-replica simulations"_howto_5 :b 6.6 "Granular models"_howto_6 :b 6.7 "TIP3P water model"_howto_7 :b 6.8 "TIP4P water model"_howto_8 :b 6.9 "SPC water model"_howto_9 :b 6.10 "Coupling LAMMPS to other codes"_howto_10 :b 6.11 "Visualizing LAMMPS snapshots"_howto_11 :b 6.12 "Triclinic (non-orthogonal) simulation boxes"_howto_12 :b 6.13 "NEMD simulations"_howto_13 :b 6.14 "Finite-size spherical and aspherical particles"_howto_14 :b 6.15 "Output from LAMMPS (thermo, dumps, computes, fixes, variables)"_howto_15 :b 6.16 "Thermostatting, barostatting, and compute temperature"_howto_16 :b 6.17 "Walls"_howto_17 :b 6.18 "Elastic constants"_howto_18 :b 6.19 "Library interface to LAMMPS"_howto_19 :b 6.20 "Calculating thermal conductivity"_howto_20 :b 6.21 "Calculating viscosity"_howto_21 :ule,b "Example problems"_Section_example.html :l "Performance & scalability"_Section_perf.html :l "Additional tools"_Section_tools.html :l "Modifying & extending LAMMPS"_Section_modify.html :l 10.1 "Atom styles"_mod_1 :ulb,b 10.2 "Bond, angle, dihedral, improper potentials"_mod_2 :b 10.3 "Compute styles"_mod_3 :b 10.4 "Dump styles"_mod_4 :b 10.5 "Dump custom output options"_mod_5 :b 10.6 "Fix styles"_mod_6 :b 10.7 "Input script commands"_mod_7 :b 10.8 "Kspace computations"_mod_8 :b 10.9 "Minimization styles"_mod_9 :b 10.10 "Pairwise potentials"_mod_10 :b 10.11 "Region styles"_mod_11 :b 10.12 "Body styles"_mod_12 :b 10.13 "Thermodynamic output options"_mod_13 :b 10.14 "Variable options"_mod_14 :b 10.15 "Submitting new features for inclusion in LAMMPS"_mod_15 :ule,b "Python interface"_Section_python.html :l 11.1 "Building LAMMPS as a shared library"_py_1 :ulb,b 11.2 "Installing the Python wrapper into Python"_py_2 :b 11.3 "Extending Python with MPI to run in parallel"_py_3 :b 11.4 "Testing the Python-LAMMPS interface"_py_4 :b 11.5 "Using LAMMPS from Python"_py_5 :b 11.6 "Example Python scripts that use LAMMPS"_py_6 :ule,b "Errors"_Section_errors.html :l 12.1 "Common problems"_err_1 :ulb,b 12.2 "Reporting bugs"_err_2 :b 12.3 "Error & warning messages"_err_3 :ule,b "Future and history"_Section_history.html :l 13.1 "Coming attractions"_hist_1 :ulb,b 13.2 "Past versions"_hist_2 :ule,b :ole :link(intro_1,Section_intro.html#intro_1) :link(intro_2,Section_intro.html#intro_2) :link(intro_3,Section_intro.html#intro_3) :link(intro_4,Section_intro.html#intro_4) :link(intro_5,Section_intro.html#intro_5) :link(start_1,Section_start.html#start_1) :link(start_2,Section_start.html#start_2) :link(start_3,Section_start.html#start_3) :link(start_4,Section_start.html#start_4) :link(start_5,Section_start.html#start_5) :link(start_6,Section_start.html#start_6) :link(start_7,Section_start.html#start_7) :link(start_8,Section_start.html#start_8) :link(start_9,Section_start.html#start_9) :link(cmd_1,Section_commands.html#cmd_1) :link(cmd_2,Section_commands.html#cmd_2) :link(cmd_3,Section_commands.html#cmd_3) :link(cmd_4,Section_commands.html#cmd_4) :link(cmd_5,Section_commands.html#cmd_5) :link(pkg_1,Section_packages.html#pkg_1) :link(pkg_2,Section_packages.html#pkg_2) :link(acc_1,Section_accelerate.html#acc_1) :link(acc_2,Section_accelerate.html#acc_2) :link(acc_3,Section_accelerate.html#acc_3) :link(acc_4,Section_accelerate.html#acc_4) :link(acc_5,Section_accelerate.html#acc_5) :link(acc_6,Section_accelerate.html#acc_6) :link(acc_7,Section_accelerate.html#acc_7) :link(acc_8,Section_accelerate.html#acc_8) :link(howto_1,Section_howto.html#howto_1) :link(howto_2,Section_howto.html#howto_2) :link(howto_3,Section_howto.html#howto_3) :link(howto_4,Section_howto.html#howto_4) :link(howto_5,Section_howto.html#howto_5) :link(howto_6,Section_howto.html#howto_6) :link(howto_7,Section_howto.html#howto_7) :link(howto_8,Section_howto.html#howto_8) :link(howto_9,Section_howto.html#howto_9) :link(howto_10,Section_howto.html#howto_10) :link(howto_11,Section_howto.html#howto_11) :link(howto_12,Section_howto.html#howto_12) :link(howto_13,Section_howto.html#howto_13) :link(howto_14,Section_howto.html#howto_14) :link(howto_15,Section_howto.html#howto_15) :link(howto_16,Section_howto.html#howto_16) :link(howto_17,Section_howto.html#howto_17) :link(howto_18,Section_howto.html#howto_18) :link(howto_19,Section_howto.html#howto_19) :link(howto_20,Section_howto.html#howto_20) :link(howto_21,Section_howto.html#howto_21) :link(mod_1,Section_modify.html#mod_1) :link(mod_2,Section_modify.html#mod_2) :link(mod_3,Section_modify.html#mod_3) :link(mod_4,Section_modify.html#mod_4) :link(mod_5,Section_modify.html#mod_5) :link(mod_6,Section_modify.html#mod_6) :link(mod_7,Section_modify.html#mod_7) :link(mod_8,Section_modify.html#mod_8) :link(mod_9,Section_modify.html#mod_9) :link(mod_10,Section_modify.html#mod_10) :link(mod_11,Section_modify.html#mod_11) :link(mod_12,Section_modify.html#mod_12) :link(mod_13,Section_modify.html#mod_13) :link(mod_14,Section_modify.html#mod_14) :link(mod_15,Section_modify.html#mod_15) :link(py_1,Section_python.html#py_1) :link(py_2,Section_python.html#py_2) :link(py_3,Section_python.html#py_3) :link(py_4,Section_python.html#py_4) :link(py_5,Section_python.html#py_5) :link(py_6,Section_python.html#py_6) :link(err_1,Section_errors.html#err_1) :link(err_2,Section_errors.html#err_2) :link(err_3,Section_errors.html#err_3) :link(hist_1,Section_history.html#hist_1) :link(hist_2,Section_history.html#hist_2) </BODY> diff --git a/doc/delete_atoms.html b/doc/delete_atoms.html index 02cc1e272..3ea9f9d36 100644 --- a/doc/delete_atoms.html +++ b/doc/delete_atoms.html @@ -1,113 +1,123 @@ <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>delete_atoms command </H3> <P><B>Syntax:</B> </P> <PRE>delete_atoms style args keyword value ... </PRE> <UL><LI>style = <I>group</I> or <I>region</I> or <I>overlap</I> or <I>porosity</I> <PRE> <I>group</I> args = group-ID <I>region</I> args = region-ID <I>overlap</I> args = cutoff group1-ID group2-ID cutoff = delete one atom from pairs of atoms within the cutoff (distance units) group1-ID = one atom in pair must be in this group group2-ID = other atom in pair must be in this group <I>porosity</I> args = region-ID fraction seed region-ID = region within which to perform deletions fraction = delete this fraction of atoms seed = random number seed (positive integer) </PRE> <LI>zero or more keyword/value pairs may be appended -<LI>keyword = <I>compress</I> +<LI>keyword = <I>compress</I> or <I>mol</I> -<PRE> <I>compress</I> value = <I>no</I> or <I>yes</I> +<PRE> <I>compress</I> value = <I>no</I> or <I>yes</I> + <I>mol</I> value = <I>no</I> or <I>yes</I> </PRE> </UL> <P><B>Examples:</B> </P> <PRE>delete_atoms group edge delete_atoms region sphere compress no delete_atoms overlap 0.3 all all delete_atoms overlap 0.5 solvent colloid delete_atoms porosity cube 0.1 482793 </PRE> <P><B>Description:</B> </P> <P>Delete the specified atoms. This command can be used to carve out voids from a block of material or to delete created atoms that are too close to each other (e.g. at a grain boundary). </P> <P>For style <I>group</I>, all atoms belonging to the group are deleted. </P> <P>For style <I>region</I>, all atoms in the region volume are deleted. +Additional atoms can be deleted if they are in a molecule for which +one or more atoms were deleted within the region; see the <I>mol</I> +keyword discussion below. </P> <P>For style <I>overlap</I> pairs of atoms whose distance of separation is within the specified cutoff distance are searched for, and one of the 2 atoms is deleted. Only pairs where one of the two atoms is in the first group specified and the other atom is in the second group are considered. The atom that is in the first group is the one that is deleted. </P> <P>Note that it is OK for the two group IDs to be the same (e.g. group <I>all</I>), or for some atoms to be members of both groups. In these cases, either atom in the pair may be deleted. Also note that if there are atoms which are members of both groups, the only guarantee is that at the end of the deletion operation, enough deletions will have occurred that no atom pairs within the cutoff will remain (subject to the group restriction). There is no guarantee that the minimum number of atoms will be deleted, or that the same atoms will be deleted when running on different numbers of processors. </P> <P>For style <I>porosity</I> a specified <I>fraction</I> of atoms are deleted within the specified region. For example, if fraction is 0.1, then 10% of the atoms will be deleted. The atoms to delete are chosen randomly. There is no guarantee that the exact fraction of atoms will be deleted, or that the same atoms will be deleted when running on different numbers of processors. </P> <P>If the <I>compress</I> keyword is set to <I>yes</I>, then after atoms are deleted, then atom IDs are re-assigned so that they run from 1 to the number of atoms in the system. This is not done for molecular systems (see the <A HREF = "atom_style.html">atom_style</A> command), regardless of the <I>compress</I> setting, since it would foul up the bond connectivity that has already been assigned. </P> +<P>It the <I>mol</I> keyword is set to <I>yes</I>, then for every atom that is +deleted, all other atoms in the same molecule will also be deleted. +This keyword is only used by the <I>region</I> style. It is a way to +insure that entire molecules are deleted instead of only a subset of +atoms in a bond or angle or dihedral interaction. +</P> <P><B>Restrictions:</B> </P> <P>The <I>overlap</I> styles requires inter-processor communication to acquire ghost atoms and build a neighbor list. This means that your system must be ready to perform a simulation before using this command (force fields setup, atom masses set, etc). Since a neighbor list is used to find overlapping atom pairs, it also means that you must define a <A HREF = "pair_style.html">pair style</A> with force cutoffs greater than or equal to the desired overlap cutoff between pairs of relevant atom types, even though the pair potential will not be evaluated. </P> <P>If the <A HREF = "special_bonds.html">special_bonds</A> command is used with a setting of 0, then a pair of bonded atoms (1-2, 1-3, or 1-4) will not appear in the neighbor list, and thus will not be considered for deletion by the <I>overlap</I> styles. You probably don't want to be deleting one atom in a bonded pair anyway. </P> <P><B>Related commands:</B> </P> <P><A HREF = "create_atoms.html">create_atoms</A> </P> <P><B>Default:</B> </P> -<P>The option defaults are compress = yes. +<P>The option defaults are compress = yes and mol = no. </P> </HTML> diff --git a/doc/delete_atoms.txt b/doc/delete_atoms.txt index 5a613a352..7c4bd2bcf 100644 --- a/doc/delete_atoms.txt +++ b/doc/delete_atoms.txt @@ -1,103 +1,113 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line delete_atoms command :h3 [Syntax:] delete_atoms style args keyword value ... :pre style = {group} or {region} or {overlap} or {porosity} :ulb,l {group} args = group-ID {region} args = region-ID {overlap} args = cutoff group1-ID group2-ID cutoff = delete one atom from pairs of atoms within the cutoff (distance units) group1-ID = one atom in pair must be in this group group2-ID = other atom in pair must be in this group {porosity} args = region-ID fraction seed region-ID = region within which to perform deletions fraction = delete this fraction of atoms seed = random number seed (positive integer) :pre zero or more keyword/value pairs may be appended :l -keyword = {compress} :l - {compress} value = {no} or {yes} :pre +keyword = {compress} or {mol} :l + {compress} value = {no} or {yes} + {mol} value = {no} or {yes} :pre :ule [Examples:] delete_atoms group edge delete_atoms region sphere compress no delete_atoms overlap 0.3 all all delete_atoms overlap 0.5 solvent colloid delete_atoms porosity cube 0.1 482793 :pre [Description:] Delete the specified atoms. This command can be used to carve out voids from a block of material or to delete created atoms that are too close to each other (e.g. at a grain boundary). For style {group}, all atoms belonging to the group are deleted. For style {region}, all atoms in the region volume are deleted. +Additional atoms can be deleted if they are in a molecule for which +one or more atoms were deleted within the region; see the {mol} +keyword discussion below. For style {overlap} pairs of atoms whose distance of separation is within the specified cutoff distance are searched for, and one of the 2 atoms is deleted. Only pairs where one of the two atoms is in the first group specified and the other atom is in the second group are considered. The atom that is in the first group is the one that is deleted. Note that it is OK for the two group IDs to be the same (e.g. group {all}), or for some atoms to be members of both groups. In these cases, either atom in the pair may be deleted. Also note that if there are atoms which are members of both groups, the only guarantee is that at the end of the deletion operation, enough deletions will have occurred that no atom pairs within the cutoff will remain (subject to the group restriction). There is no guarantee that the minimum number of atoms will be deleted, or that the same atoms will be deleted when running on different numbers of processors. For style {porosity} a specified {fraction} of atoms are deleted within the specified region. For example, if fraction is 0.1, then 10% of the atoms will be deleted. The atoms to delete are chosen randomly. There is no guarantee that the exact fraction of atoms will be deleted, or that the same atoms will be deleted when running on different numbers of processors. If the {compress} keyword is set to {yes}, then after atoms are deleted, then atom IDs are re-assigned so that they run from 1 to the number of atoms in the system. This is not done for molecular systems (see the "atom_style"_atom_style.html command), regardless of the {compress} setting, since it would foul up the bond connectivity that has already been assigned. +It the {mol} keyword is set to {yes}, then for every atom that is +deleted, all other atoms in the same molecule will also be deleted. +This keyword is only used by the {region} style. It is a way to +insure that entire molecules are deleted instead of only a subset of +atoms in a bond or angle or dihedral interaction. + [Restrictions:] The {overlap} styles requires inter-processor communication to acquire ghost atoms and build a neighbor list. This means that your system must be ready to perform a simulation before using this command (force fields setup, atom masses set, etc). Since a neighbor list is used to find overlapping atom pairs, it also means that you must define a "pair style"_pair_style.html with force cutoffs greater than or equal to the desired overlap cutoff between pairs of relevant atom types, even though the pair potential will not be evaluated. If the "special_bonds"_special_bonds.html command is used with a setting of 0, then a pair of bonded atoms (1-2, 1-3, or 1-4) will not appear in the neighbor list, and thus will not be considered for deletion by the {overlap} styles. You probably don't want to be deleting one atom in a bonded pair anyway. [Related commands:] "create_atoms"_create_atoms.html [Default:] -The option defaults are compress = yes. +The option defaults are compress = yes and mol = no. diff --git a/doc/fix_gcmc.html b/doc/fix_gcmc.html index c8a38e812..4be3248a4 100644 --- a/doc/fix_gcmc.html +++ b/doc/fix_gcmc.html @@ -1,259 +1,259 @@ <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>fix gcmc command </H3> <P><B>Syntax:</B> </P> <PRE>fix ID group-ID gcmc N X M type seed T mu displace keyword values ... </PRE> <UL><LI>ID, group-ID are documented in <A HREF = "fix.html">fix</A> command <LI>gcmc = style name of this fix command <LI>N = invoke this fix every N steps <LI>X = number of exchanges to attempt every N steps <LI>M = number of MC displacements to attempt every N steps <LI>type = atom type or molecule ID of exchanged gas <LI>seed = random # seed (positive integer) <LI>T = temperature of the ideal gas reservoir (temperature units) <LI>mu = chemical potential of the ideal gas reservoir (energy units) <LI>displace = maximum Monte Carlo displacement distance (length units) <LI>zero or more keyword/value pairs may be appended to args <LI>keyword = <I>molecule</I>, <I>region</I>, <I>maxangle</I>, <I>pressure</I>, or <I>fugacity_coeff</I> <PRE> <I>molecule</I> value = <I>no</I> or <I>yes</I> <I>region</I> value = region-ID region-ID = ID of region to use as an exchange/move volume <I>maxangle</I> value = maximum molecular rotation angle (degrees) <I>pressure</I> value = pressue of the gas reservoir (pressure units) <I>fugacity_coeff</I> value = fugacity coefficient of the gas reservoir (unitless) </PRE> </UL> <P><B>Examples:</B> </P> <PRE>fix 2 gas gcmc 10 1000 1000 2 29494 298.0 -0.5 0.01 -fix 3 Kr gcmc 10 100 100 1 3456543 3.0 -2.5 0.1 molecule yes maxrot 180 +fix 3 Kr gcmc 10 100 100 1 3456543 3.0 -2.5 0.1 molecule yes maxangle 180 fix 4 my_gas gcmc 1 10 10 1 123456543 300.0 -12.5 1.0 region disk </PRE> <P><B>Description:</B> </P> <P>This fix performs grand canonical Monte Carlo (GCMC) exchanges of atoms or molecules of the given type with an imaginary ideal gas reservoir at the specified T and chemical potential (mu) as discussed in <A HREF = "#Frenkel">(Frenkel)</A>. If used with the <A HREF = "fix_nh.html">fix nvt</A> command, simulations in the grand canonical enemble (muVT, constant chemical potential, constant volume, and constant temperature) can be performed. Specific uses include computing isotherms in microporous materials, or computing vapor-liquid coexistence curves. </P> <P>Perform up to X exchanges of gas atoms or molecules of the given type between the simulation domain and the imaginary reservoir every N timesteps. Also perform M Monte Carlo displacements or rotations (for molecules) of gas of the given type within the simulation domain. M should typically be chosen to be approximately equal to the expected number of gas atoms or molecules of the given type within the domain, which will result in roughly one MC translation per atom or molecule per MC cycle. </P> <P>For MC moves of molecular gasses, rotations and translations are each attempted with 50% probability. For MC moves of atomic gasses, translations are attempted 100% of the time. For MC exchanges of either molecular or atomic gasses, deletions and insertions are each attempted with 50% probability. </P> <P>This fix cannot be used to perform MC insertions of gas atoms or molecules other than the exchanged type, but MC deletions, translations, and rotations can be performed on any atom/molecule in the fix group. All atoms in the simulation domain can be moved using regular time integration displacements, e.g. via <A HREF = "fix_nvt.html">fix_nvt</A>, resulting in a hybrid GCMC+MD simulation. A smaller-than-usual timestep size may be needed when running such a hybrid simulation, especially if the inserted molecules are not well equilibrated. </P> <P>This command may optionally use the <I>region</I> keyword to define an exchange and move volume. The specified region must have been previously defined with a <A HREF = "region.html">region</A> command. It must be defined with side = <I>in</I>. Insertion attempts occur only within the specified region. Move and deletion attempt candidates are selected from gas atoms or molecules within the region. If no candidate can be found within the specified region after randomly selecting candidates 1000 times, the move or deletion attempt is considered a failure. Moves must start within the specified region, but may move the atom or molecule slightly outside of the region. </P> <P>If used with <A HREF = "fix_nvt.html">fix_nvt</A>, the temperature of the imaginary reservoir, T, should be set to be equivalent to the target temperature used in <A HREF = "fix_nvt.html">fix_nvt</A>. Otherwise, the imaginary reservoir will not be in thermal equilibrium with the simulation domain. </P> <P>Note that neighbor lists are re-built every timestep that this fix is invoked, so you should not set N to be too small. However, periodic rebuilds are necessary in order to avoid dangerous rebuilds and missed interactions. Specifically, avoid performing so many MC displacements per timestep that atoms can move beyond the neighbor list skin distance. See the <A HREF = "neighbor.html">neighbor</A> command for details. </P> <P>When an atom or molecule is to be inserted, its center-of-mass coordinates are chosen as a random position within the current simulation domain, and new atom velocities are randomly chosen from the specified temperature distribution given by T. Relative coordinates for atoms in a molecule are taken from the template molecule provided by the user. A random initial rotation is used in the case of molecule insertions. </P> <P>If the setting for the <I>molecule</I> keyword is <I>no</I>, then only single atoms are exchanged. In this case, you should ensure you do not delete only a portion of a molecule (only some of its atoms), or LAMMPS will soon generate an error when it tries to find those atoms. LAMMPS will warn you if any of the atoms eligible for deletion have a non-zero molecule ID, but does not check for this at the time of deletion. </P> <P>If the setting for the <I>molecule</I> keyword is <I>yes</I>, entire molecules are exchanged. The user must supply a model molecule in the data file to use as a template for exchanges, and that molecule's number must be given in the fix GCMC command as the "type" of the exchanged gas. Note that the model molecule must be present whenever the fix is initialized. This is a limitation that will likely be remedied in the not-to-distant future. </P> <P>Optionally, users may specify the maximum rotation angle for molecular rotations using the <I>maxangle</I> keyword and specifying the angle in degrees. The specified angle will apply to all three Euler angles used internally to define the rotation matrix for molecular rotations. The max angle can be set to zero, but rotations will be pointless. Note that the default is ten degrees for each Euler angle. </P> <P>For atomic gasses, inserted atoms have the specified atom type, but deleted atoms are any atoms that have been inserted or that belong to the user-specified fix group. For molecular gasses, exchanged molecules use the same atom types as in the template molecule supplied by the user. In both cases, exchanged atoms/molecules are assigned to two groups: the default group "all" and the group specified in the fix gcmc command (which can also be "all"). </P> <P>The gas reservoir pressure can be specified using the <I>pressure</I> keyword, in which case the user-specified chemical potential is ignored. For non-ideal gas reservoirs, the user may also specify the fugacity coefficient using the <I>fugacity_coeff</I> keyword. </P> <P>Use of this fix typically will cause the number of atoms to fluctuate, therefore, you will want to use the <A HREF = "compute_modify.html">compute_modify</A> command to insure that the current number of atoms is used as a normalizing factor each time temperature is computed. Here is the necessary command: </P> <PRE>compute_modify thermo_temp dynamic yes </PRE> <P>If LJ units are used, note that a value of 0.18292026 is used by this fix as the reduced value for Planck's constant. This value was derived from LJ paramters for argon, where h* = h/sqrt(sigma^2 * epsilon * mass), sigma = 3.429 angstroms, epsilon/k = 121.85 K, and mass = 39.948 amu. </P> <P><B>Restart, fix_modify, output, run start/stop, minimize info:</B> </P> <P>This fix writes the state of the deposition to <A HREF = "restart.html">binary restart files</A>. This includes information about the random number generator seed, the next timestep for MC exchanges, etc. See the <A HREF = "read_restart.html">read_restart</A> 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. </P> <P>None of the <A HREF = "fix_modify.html">fix_modify</A> options are relevant to this fix. </P> <P>This fix computes a global vector of length 6, which can be accessed by various <A HREF = "Section_howto.html#howto_15">output commands</A>. The vector values are the following global cummulative quantities: </P> <UL><LI>1 = displacement attempts <LI>2 = displacement successes <LI>3 = insertion attempts <LI>4 = insertion successes <LI>5 = deletion attempts <LI>6 = deletion successes <LI>7 = rotation attempts <LI>8 = rotation successes </UL> <P>The vector values calculated by this fix are "extensive". </P> <P>No parameter of this fix can be used with the <I>start/stop</I> keywords of the <A HREF = "run.html">run</A> command. This fix is not invoked during <A HREF = "minimize.html">energy minimization</A>. </P> <P><B>Restrictions:</B> </P> <P>This fix is part of the MC 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. </P> <P>Do not set "neigh_modify once yes" or else this fix will never be called. Reneighboring is required. </P> <P>Only pairwise interactions, as defined by the <A HREF = "pair_style.html">pair_style</A> command, are included in this calculation. Long-range interactions due to a <A HREF = "kspace_style.html">kspace_style</A> command are not included. Not all pair potentials can be evaluated in a pairwise mode as required by this fix. For example, 3-body potentials, such as <A HREF = "pair_tersoff.html">Tersoff</A> and <A HREF = "pair_sw.html">Stillinger-Weber</A> cannot be used. <A HREF = "pair_eam.html">EAM</A> potentials for metals only include the pair potential portion of the EAM interaction, not the embedding term. </P> <P>Can be run in parallel, but aspects of the GCMC part will not scale well in parallel. Only usable for 3D simulations with orthogonal simulation cells. </P> <P>Note that very lengthy simulations involving insertions/deletions of billions of gas molecules may run out of atom or molecule IDs and trigger an error, so it is better to run multiple shorter-duration simulations. Likewise, very large molecules have not been tested and may turn out to be problematic. </P> <P>Use of multiple fix gcmc commands in the same input script can be problematic if using a template molecule. The issue is that the user-referenced template molecule in the second fix gcmc command may no longer exist since it might have been deleted by the first fix gcmc command. An existing template molecule will need to be referenced by the user for each subsequent fix gcmc command. </P> <P><B>Related commands:</B> </P> <P><A HREF = "fix_nvt.html">fix_nvt</A>, <A HREF = "neighbor.html">neighbor</A>, <A HREF = "fix_deposit.html">fix_deposit</A>, <A HREF = "fix_evaporate.html">fix_evaporate</A>, <A HREF = "delete_atoms.html">delete_atoms</A> </P> <P><B>Default:</B> </P> <P>The option defaults are molecule = no, maxangle = 10. </P> <HR> <A NAME = "Frenkel"></A> <P><B>(Frenkel)</B> Frenkel and Smit, Understanding Molecular Simulation, Academic Press, London, 2002. </P> </HTML> diff --git a/doc/fix_gcmc.txt b/doc/fix_gcmc.txt index 02f879105..1f7af8d7a 100644 --- a/doc/fix_gcmc.txt +++ b/doc/fix_gcmc.txt @@ -1,240 +1,240 @@ "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 gcmc command :h3 [Syntax:] fix ID group-ID gcmc N X M type seed T mu displace keyword values ... :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l gcmc = style name of this fix command :l N = invoke this fix every N steps :l X = number of exchanges to attempt every N steps :l M = number of MC displacements to attempt every N steps :l type = atom type or molecule ID of exchanged gas :l seed = random # seed (positive integer) :l T = temperature of the ideal gas reservoir (temperature units) :l mu = chemical potential of the ideal gas reservoir (energy units) :l displace = maximum Monte Carlo displacement distance (length units) :l zero or more keyword/value pairs may be appended to args :l keyword = {molecule}, {region}, {maxangle}, {pressure}, or {fugacity_coeff} :l {molecule} value = {no} or {yes} {region} value = region-ID region-ID = ID of region to use as an exchange/move volume {maxangle} value = maximum molecular rotation angle (degrees) {pressure} value = pressue of the gas reservoir (pressure units) {fugacity_coeff} value = fugacity coefficient of the gas reservoir (unitless) :pre :ule [Examples:] fix 2 gas gcmc 10 1000 1000 2 29494 298.0 -0.5 0.01 -fix 3 Kr gcmc 10 100 100 1 3456543 3.0 -2.5 0.1 molecule yes maxrot 180 +fix 3 Kr gcmc 10 100 100 1 3456543 3.0 -2.5 0.1 molecule yes maxangle 180 fix 4 my_gas gcmc 1 10 10 1 123456543 300.0 -12.5 1.0 region disk :pre [Description:] This fix performs grand canonical Monte Carlo (GCMC) exchanges of atoms or molecules of the given type with an imaginary ideal gas reservoir at the specified T and chemical potential (mu) as discussed in "(Frenkel)"_#Frenkel. If used with the "fix nvt"_fix_nh.html command, simulations in the grand canonical enemble (muVT, constant chemical potential, constant volume, and constant temperature) can be performed. Specific uses include computing isotherms in microporous materials, or computing vapor-liquid coexistence curves. Perform up to X exchanges of gas atoms or molecules of the given type between the simulation domain and the imaginary reservoir every N timesteps. Also perform M Monte Carlo displacements or rotations (for molecules) of gas of the given type within the simulation domain. M should typically be chosen to be approximately equal to the expected number of gas atoms or molecules of the given type within the domain, which will result in roughly one MC translation per atom or molecule per MC cycle. For MC moves of molecular gasses, rotations and translations are each attempted with 50% probability. For MC moves of atomic gasses, translations are attempted 100% of the time. For MC exchanges of either molecular or atomic gasses, deletions and insertions are each attempted with 50% probability. This fix cannot be used to perform MC insertions of gas atoms or molecules other than the exchanged type, but MC deletions, translations, and rotations can be performed on any atom/molecule in the fix group. All atoms in the simulation domain can be moved using regular time integration displacements, e.g. via "fix_nvt"_fix_nvt.html, resulting in a hybrid GCMC+MD simulation. A smaller-than-usual timestep size may be needed when running such a hybrid simulation, especially if the inserted molecules are not well equilibrated. This command may optionally use the {region} keyword to define an exchange and move volume. The specified region must have been previously defined with a "region"_region.html command. It must be defined with side = {in}. Insertion attempts occur only within the specified region. Move and deletion attempt candidates are selected from gas atoms or molecules within the region. If no candidate can be found within the specified region after randomly selecting candidates 1000 times, the move or deletion attempt is considered a failure. Moves must start within the specified region, but may move the atom or molecule slightly outside of the region. If used with "fix_nvt"_fix_nvt.html, the temperature of the imaginary reservoir, T, should be set to be equivalent to the target temperature used in "fix_nvt"_fix_nvt.html. Otherwise, the imaginary reservoir will not be in thermal equilibrium with the simulation domain. Note that neighbor lists are re-built every timestep that this fix is invoked, so you should not set N to be too small. However, periodic rebuilds are necessary in order to avoid dangerous rebuilds and missed interactions. Specifically, avoid performing so many MC displacements per timestep that atoms can move beyond the neighbor list skin distance. See the "neighbor"_neighbor.html command for details. When an atom or molecule is to be inserted, its center-of-mass coordinates are chosen as a random position within the current simulation domain, and new atom velocities are randomly chosen from the specified temperature distribution given by T. Relative coordinates for atoms in a molecule are taken from the template molecule provided by the user. A random initial rotation is used in the case of molecule insertions. If the setting for the {molecule} keyword is {no}, then only single atoms are exchanged. In this case, you should ensure you do not delete only a portion of a molecule (only some of its atoms), or LAMMPS will soon generate an error when it tries to find those atoms. LAMMPS will warn you if any of the atoms eligible for deletion have a non-zero molecule ID, but does not check for this at the time of deletion. If the setting for the {molecule} keyword is {yes}, entire molecules are exchanged. The user must supply a model molecule in the data file to use as a template for exchanges, and that molecule's number must be given in the fix GCMC command as the "type" of the exchanged gas. Note that the model molecule must be present whenever the fix is initialized. This is a limitation that will likely be remedied in the not-to-distant future. Optionally, users may specify the maximum rotation angle for molecular rotations using the {maxangle} keyword and specifying the angle in degrees. The specified angle will apply to all three Euler angles used internally to define the rotation matrix for molecular rotations. The max angle can be set to zero, but rotations will be pointless. Note that the default is ten degrees for each Euler angle. For atomic gasses, inserted atoms have the specified atom type, but deleted atoms are any atoms that have been inserted or that belong to the user-specified fix group. For molecular gasses, exchanged molecules use the same atom types as in the template molecule supplied by the user. In both cases, exchanged atoms/molecules are assigned to two groups: the default group "all" and the group specified in the fix gcmc command (which can also be "all"). The gas reservoir pressure can be specified using the {pressure} keyword, in which case the user-specified chemical potential is ignored. For non-ideal gas reservoirs, the user may also specify the fugacity coefficient using the {fugacity_coeff} keyword. Use of this fix typically will cause the number of atoms to fluctuate, therefore, you will want to use the "compute_modify"_compute_modify.html command to insure that the current number of atoms is used as a normalizing factor each time temperature is computed. Here is the necessary command: compute_modify thermo_temp dynamic yes :pre If LJ units are used, note that a value of 0.18292026 is used by this fix as the reduced value for Planck's constant. This value was derived from LJ paramters for argon, where h* = h/sqrt(sigma^2 * epsilon * mass), sigma = 3.429 angstroms, epsilon/k = 121.85 K, and mass = 39.948 amu. [Restart, fix_modify, output, run start/stop, minimize info:] This fix writes the state of the deposition to "binary restart files"_restart.html. This includes information about the random number generator seed, the next timestep for MC exchanges, etc. 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. This fix computes a global vector of length 6, which can be accessed by various "output commands"_Section_howto.html#howto_15. The vector values are the following global cummulative quantities: 1 = displacement attempts 2 = displacement successes 3 = insertion attempts 4 = insertion successes 5 = deletion attempts 6 = deletion successes 7 = rotation attempts 8 = rotation successes :ul The vector values calculated by this fix are "extensive". No parameter of this fix can be used with the {start/stop} keywords of the "run"_run.html command. This fix is not invoked during "energy minimization"_minimize.html. [Restrictions:] This fix is part of the MC 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. Do not set "neigh_modify once yes" or else this fix will never be called. Reneighboring is required. Only pairwise interactions, as defined by the "pair_style"_pair_style.html command, are included in this calculation. Long-range interactions due to a "kspace_style"_kspace_style.html command are not included. Not all pair potentials can be evaluated in a pairwise mode as required by this fix. For example, 3-body potentials, such as "Tersoff"_pair_tersoff.html and "Stillinger-Weber"_pair_sw.html cannot be used. "EAM"_pair_eam.html potentials for metals only include the pair potential portion of the EAM interaction, not the embedding term. Can be run in parallel, but aspects of the GCMC part will not scale well in parallel. Only usable for 3D simulations with orthogonal simulation cells. Note that very lengthy simulations involving insertions/deletions of billions of gas molecules may run out of atom or molecule IDs and trigger an error, so it is better to run multiple shorter-duration simulations. Likewise, very large molecules have not been tested and may turn out to be problematic. Use of multiple fix gcmc commands in the same input script can be problematic if using a template molecule. The issue is that the user-referenced template molecule in the second fix gcmc command may no longer exist since it might have been deleted by the first fix gcmc command. An existing template molecule will need to be referenced by the user for each subsequent fix gcmc command. [Related commands:] "fix_nvt"_fix_nvt.html, "neighbor"_neighbor.html, "fix_deposit"_fix_deposit.html, "fix_evaporate"_fix_evaporate.html, "delete_atoms"_delete_atoms.html [Default:] The option defaults are molecule = no, maxangle = 10. :line :link(Frenkel) [(Frenkel)] Frenkel and Smit, Understanding Molecular Simulation, Academic Press, London, 2002. diff --git a/doc/fix_reax_bonds.html b/doc/fix_reax_bonds.html index b7c8e3659..dd25932e9 100644 --- a/doc/fix_reax_bonds.html +++ b/doc/fix_reax_bonds.html @@ -1,73 +1,73 @@ <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>fix reax/bonds command </H3> <H3>fix reax/c/bonds command </H3> <P><B>Syntax:</B> </P> <PRE>fix ID group-ID reax/bonds Nevery filename </PRE> <UL><LI>ID, group-ID are documented in <A HREF = "fix.html">fix</A> command <LI>reax/bonds = style name of this fix command <LI>Nevery = output interval in timesteps <LI>filename = name of output file </UL> <P><B>Examples:</B> </P> <PRE>fix 1 all reax/bonds 100 bonds.tatb fix 1 all reax/c/bonds 100 bonds.reaxc </PRE> <P><B>Description:</B> </P> <P>Write out the bond information computed by the ReaxFF potential -specified by <A HREF = "pair_reax.html">pair_style reax</A> or -<A HREF = "pair_reax_c.html">pair_style reax/c</A> in the exact same format as -the stand-alone ReaxFF code. The bond information -is written to <I>filename</I> on timesteps that are multiples of <I>Nevery</I>, -including timestep 0. For time-averaged chemical species analysis, +specified by <A HREF = "pair_reax.html">pair_style reax</A> or <A HREF = "pair_reax_c.html">pair_style +reax/c</A> in the exact same format as the original +stand-alone ReaxFF code of Adri van Duin. The bond information is +written to <I>filename</I> on timesteps that are multiples of <I>Nevery</I>, +including timestep 0. For time-averaged chemical species analysis, please see the <A HREF = "fix_species.html">fix species</A> command. </P> <P>The format of the output file should be self-explantory. </P> <HR> <P><B>Restart, fix_modify, output, run start/stop, minimize info:</B> </P> <P>No information about this fix is written to <A HREF = "restart.html">binary restart files</A>. None of the <A HREF = "fix_modify.html">fix_modify</A> options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various <A HREF = "Section_howto.html#howto_15">output commands</A>. No parameter of this fix can be used with the <I>start/stop</I> keywords of the <A HREF = "run.html">run</A> command. This fix is not invoked during <A HREF = "minimize.html">energy minimization</A>. </P> <P><B>Restrictions:</B> </P> <P>The fix reax/bonds command requires that the <A HREF = "pair_reax.html">pair_style reax</A> be invoked. This fix is part of the REAX package. It is only enabled if LAMMPS was built with that package, which also requires the REAX library be built and linked with LAMMPS. The fix reax/c/bonds command requires that the <A HREF = "pair_reax_c.html">pair_style -reax/c</A> be invoked. This fix is part of the USER-REAXC -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. +reax/c</A> be invoked. This fix is part of the +USER-REAXC 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. </P> <P><B>Related commands:</B> </P> <P><A HREF = "pair_reax.html">pair_style reax</A>, <A HREF = "pair_reax_c.html">pair_style reax/c</A>, <A HREF = "fix_reaxc_species.html">fix reax/c/species</A> </P> <P><B>Default:</B> none </P> </HTML> diff --git a/doc/fix_reax_bonds.txt b/doc/fix_reax_bonds.txt index d51e08ef5..cc8966db6 100644 --- a/doc/fix_reax_bonds.txt +++ b/doc/fix_reax_bonds.txt @@ -1,67 +1,67 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line fix reax/bonds command :h3 fix reax/c/bonds command :h3 [Syntax:] fix ID group-ID reax/bonds Nevery filename :pre ID, group-ID are documented in "fix"_fix.html command reax/bonds = style name of this fix command Nevery = output interval in timesteps filename = name of output file :ul [Examples:] fix 1 all reax/bonds 100 bonds.tatb fix 1 all reax/c/bonds 100 bonds.reaxc :pre [Description:] Write out the bond information computed by the ReaxFF potential -specified by "pair_style reax"_pair_reax.html or -"pair_style reax/c"_pair_reax_c.html in the exact same format as -the stand-alone ReaxFF code. The bond information -is written to {filename} on timesteps that are multiples of {Nevery}, -including timestep 0. For time-averaged chemical species analysis, +specified by "pair_style reax"_pair_reax.html or "pair_style +reax/c"_pair_reax_c.html in the exact same format as the original +stand-alone ReaxFF code of Adri van Duin. The bond information is +written to {filename} on timesteps that are multiples of {Nevery}, +including timestep 0. For time-averaged chemical species analysis, please see the "fix species"_fix_species.html command. The format of the output file should be self-explantory. :line [Restart, fix_modify, output, run start/stop, minimize info:] No information about this fix is written to "binary restart files"_restart.html. None of the "fix_modify"_fix_modify.html options are relevant to this fix. No global or per-atom quantities are stored by this fix for access by various "output commands"_Section_howto.html#howto_15. No parameter of this fix can be used with the {start/stop} keywords of the "run"_run.html command. This fix is not invoked during "energy minimization"_minimize.html. [Restrictions:] The fix reax/bonds command requires that the "pair_style reax"_pair_reax.html be invoked. This fix is part of the REAX package. It is only enabled if LAMMPS was built with that package, which also requires the REAX library be built and linked with LAMMPS. The fix reax/c/bonds command requires that the "pair_style -reax/c"_pair_reax_c.html be invoked. This fix is part of the USER-REAXC -package. It is only enabled if LAMMPS was built with that package. -See the "Making LAMMPS"_Section_start.html#start_3 section for more -info. +reax/c"_pair_reax_c.html be invoked. This fix is part of the +USER-REAXC package. It is only enabled if LAMMPS was built with that +package. See the "Making LAMMPS"_Section_start.html#start_3 section +for more info. [Related commands:] "pair_style reax"_pair_reax.html, "pair_style reax/c"_pair_reax_c.html, "fix reax/c/species"_fix_reaxc_species.html [Default:] none diff --git a/doc/fix_reaxc_species.html b/doc/fix_reaxc_species.html new file mode 100644 index 000000000..e1af71daa --- /dev/null +++ b/doc/fix_reaxc_species.html @@ -0,0 +1,143 @@ +<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>fix reax/c/species command +</H3> +<P><B>Syntax:</B> +</P> +<PRE>fix ID group-ID reax/c/species Nevery Nrepeat Nfreq filename keyword value ... +</PRE> +<UL><LI>ID, group-ID are documented in <A HREF = "fix.html">fix</A> command + +<LI>reax/c/species = style name of this command + +<LI>Nevery = sample bond-order every this many timesteps + +<LI>Nrepeat = # of bond-order samples used for calculating averages + +<LI>Nfreq = calculate average bond-order every this many timesteps + +<LI>filename = name of output file + +<LI>zero or more keyword/value pairs may be appended + +<LI>keyword = <I>cutoff</I> or <I>element</I> or <I>position</I> + +<PRE> <I>cutoff</I> value = I J Cutoff + I, J = atom types + Cutoff = Bond-order cutoff value for this pair of atom types + <I>element</I> value = Element1, Element2, ... + <I>position</I> value = posfreq filepos + posfreq = write position files every this many timestep + filepos = name of position output file +</PRE> + +</UL> +<P><B>Examples:</B> +</P> +<PRE>fix 1 all species 10 10 100 species.out +fix 1 all species 1 2 20 species.out cutoff 1 1 0.40 cutoff 1 2 0.55 +fix 1 all species 1 100 100 species.out element Au O H position 1000 AuOH.pos +</PRE> +<P><B>Description:</B> +</P> +<P>Write out the chemical species information computed by the ReaxFF potential +specified by <A HREF = "pair_reax_c.html">pair_style reax/c</A>. Bond-order values +(either averaged or instantaneous, depending on value of <I>Nrepeat</I>) +are used to determine chemical bonds. Every <I>Nfreq</I> timesteps, +chemical species information is written to <I>filename</I> as a two line output. +The first line is a header containing labels. The second line consists +of the following: timestep, total number of molecules, +total number of distinct species, number of molecules of each species. +The chemical formula of each species is given in the first line. +</P> +<P>Optional keyword <I>cutoff</I> can be assigned to change the minimum bond-order values +used in identifying chemical bonds between pairs of atoms. Bond-order cutoffs +should be carefully chosen, as bond-order cutoffs that are too small may include +too many bonds (which will result in an error), while too-large cutoffs will +result in fragmented molecules. The default cutoff of 0.3 usually gives good +estimate. +</P> +<P>Optional keyword <I>element</I> can be used to specify the chemical symbol printed for +each LAMMPS atom type. The number of symbols must match the number of LAMMPS atom types +and each symbol must consist of 1 or 2 alphanumeric characters. Normally, these +symbols should be chosen to match the chemical identity of each LAMMPS atom type, +as specified using the <A HREF = "pair_reax_c.html">reax/c pair_coeff</A> command and +the ReaxFF force field file. +</P> +<P>Optional keyword <I>position</I> writes center-of-mass positions of each identified +molecules to file <I>filepos</I> every <I>posfreq</I> timesteps. The first line contains +information on timestep, total number of molecules, total number of distinct +species, and box dimensions. The second line is a header containing labels. +From the third line downward, each molecule writes a line of output containing +the following information: molecule ID, number of atoms in this molecule, chemical +formula, total charge, and center-of-mass xyz positions of this molecule. The xyz +positions are in fractional coordinates relative to the box dimensions. +</P> +<P>Keyword <I>position</I> output file <I>filepos</I> can contain the wildcard character "*". +If the "*" character appears in <I>filepos</I>, then one file per snapshot is written +at <I>posfreq</I> and the "*" character is replaced with the timestep value. +For example, AuO.pos.* becomes AuO.pos.0, AuO.pos.1000, etc. +</P> +<HR> + +<P>The <I>Nevery</I>, <I>Nrepeat</I>, and <I>Nfreq</I> arguments specify on what +timesteps the bond-order values are sampled to get the average bond +order. The species analysis is performed using the average bond-order +on timesteps +that are a multiple of <I>Nfreq</I>. The average is over <I>Nrepeat</I> +bond-order samples, computed in the preceding portion of the simulation every +<I>Nevery</I> timesteps. <I>Nfreq</I> must be a multiple of <I>Nevery</I> and +<I>Nevery</I> must be non-zero even if <I>Nrepeat</I> is 1. Also, the timesteps +contributing to the average bond-order cannot overlap, i.e. Nfreq > +(Nrepeat-1)*Nevery is required. +</P> +<P>For example, if Nevery=2, Nrepeat=6, and Nfreq=100, then bond-order values on +timesteps 90,92,94,96,98,100 will be used to compute the average bond-order + for the species analysis output on timestep 100. +</P> +<HR> + +<P><B>Restart, fix_modify, output, run start/stop, minimize info:</B> +</P> +<P>No information about this fix is written to <A HREF = "restart.html">binary restart +files</A>. None of the <A HREF = "fix_modify.html">fix_modify</A> options +are relevant to this fix. No global or per-atom quantities are stored +by this fix for access by various <A HREF = "Section_howto.html#howto_15">output +commands</A>. No parameter of this fix can +be used with the <I>start/stop</I> keywords of the <A HREF = "run.html">run</A> command. +This fix is not invoked during <A HREF = "minimize.html">energy minimization</A>. +</P> +<P><B>Restrictions:</B> +</P> +<P>The fix species currently only works with +<A HREF = "pair_reax_c.html">pair_style reax/c</A> and it requires that the <A HREF = "pair_reax_c.html">pair_style +reax/c</A> be invoked. This fix is part of the +USER-REAXC 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. +</P> +<P>It should be possible to extend it to other reactive pair_styles (such as +<A HREF = "pair_airebo.html">rebo</A>, <A HREF = "pair_airebo.html">airebo</A>, +<A HREF = "pair_comb.html">comb</A>, and <A HREF = "pair_bop.html">bop</A>), but this has not yet been done. +</P> +<P><B>Related commands:</B> +</P> +<P><A HREF = "pair_reax_c.html">pair_style reax/c</A>, <A HREF = "fix_reax_bonds.html">fix +reax/bonds</A> +</P> +<P><B>Default:</B> +</P> +<P>The default values for bond-order cutoffs are 0.3 for all I-J pairs. The +default element symbols are C, H, O, N. Position files are not written +by default. +</P> +</HTML> diff --git a/doc/thermo_style.html b/doc/thermo_style.html index 8641eb138..78bcc3038 100644 --- a/doc/thermo_style.html +++ b/doc/thermo_style.html @@ -1,324 +1,334 @@ <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>thermo_style command </H3> <P><B>Syntax:</B> </P> <PRE>thermo_style style args </PRE> <UL><LI>style = <I>one</I> or <I>multi</I> or <I>custom</I> <LI>args = list of arguments for a particular style <PRE> <I>one</I> args = none <I>multi</I> args = none <I>custom</I> args = list of attributes - possible attributes = step, elapsed, elaplong, dt, cpu, tpcpu, spcpu, + possible attributes = step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu, atoms, temp, press, pe, ke, etotal, enthalpy, evdwl, ecoul, epair, ebond, eangle, edihed, eimp, emol, elong, etail, vol, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz, xlat, ylat, zlat, pxx, pyy, pzz, pxy, pxz, pyz, fmax, fnorm, cella, cellb, cellc, cellalpha, cellbeta, cellgamma, c_ID, c_ID[I], c_ID[I][J], f_ID, f_ID[I], f_ID[I][J], v_name step = timestep elapsed = timesteps since start of this run elaplong = timesteps since start of initial run in a series of runs dt = timestep size + time = simulation time cpu = elapsed CPU time in seconds tpcpu = time per CPU second spcpu = timesteps per CPU second atoms = # of atoms temp = temperature press = pressure pe = total potential energy ke = kinetic energy etotal = total energy (pe + ke) enthalpy = enthalpy (etotal + press*vol) evdwl = VanderWaal pairwise energy ecoul = Coulombic pairwise energy epair = pairwise energy (evdwl + ecoul + elong + etail) ebond = bond energy eangle = angle energy edihed = dihedral energy eimp = improper energy emol = molecular energy (ebond + eangle + edihed + eimp) elong = long-range kspace energy etail = VanderWaal energy long-range tail correction vol = volume lx,ly,lz = box lengths in x,y,z xlo,xhi,ylo,yhi,zlo,zhi = box boundaries xy,xz,yz = box tilt for triclinic (non-orthogonal) simulation boxes xlat,ylat,zlat = lattice spacings as calculated by <A HREF = "lattice.html">lattice</A> command pxx,pyy,pzz,pxy,pxz,pyz = 6 components of pressure tensor fmax = max component of force on any atom in any dimension fnorm = length of force vector for all atoms cella,cellb,cellc = periodic cell lattice constants a,b,c cellalpha, cellbeta, cellgamma = periodic cell angles alpha,beta,gamma c_ID = global scalar value calculated by a compute with ID c_ID[I] = Ith component of global vector calculated by a compute with ID c_ID[I][J] = I,J component of global array calculated by a compute with ID f_ID = global scalar value calculated by a fix with ID f_ID[I] = Ith component of global vector calculated by a fix with ID f_ID[I][J] = I,J component of global array calculated by a fix with ID v_name = scalar value calculated by an equal-style variable with name </PRE> </UL> <P><B>Examples:</B> </P> <PRE>thermo_style multi thermo_style custom step temp pe etotal press vol thermo_style custom step temp etotal c_myTemp v_abc </PRE> <P><B>Description:</B> </P> <P>Set the style and content for printing thermodynamic data to the screen and log file. </P> <P>Style <I>one</I> prints a one-line summary of thermodynamic info that is the equivalent of "thermo_style custom step temp epair emol etotal press". The line contains only numeric values. </P> <P>Style <I>multi</I> prints a multiple-line listing of thermodynamic info that is the equivalent of "thermo_style custom etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press". The listing contains numeric values and a string ID for each quantity. </P> <P>Style <I>custom</I> is the most general setting and allows you to specify which of the keywords listed above you want printed on each thermodynamic timestep. Note that the keywords c_ID, f_ID, v_name are references to <A HREF = "compute.html">computes</A>, <A HREF = "fix.html">fixes</A>, and equal-style <A HREF = "variable.html"">variables</A> that have been defined elsewhere in the input script or can even be new styles which users have added to LAMMPS (see the <A HREF = "Section_modify.html">Section_modify</A> section of the documentation). Thus the <I>custom</I> style provides a flexible means of outputting essentially any desired quantity as a simulation proceeds. </P> <P>All styles except <I>custom</I> have <I>vol</I> appended to their list of outputs if the simulation box volume changes during the simulation. </P> <P>The values printed by the various keywords are instantaneous values, calculated on the current timestep. Time-averaged quantities, which include values from previous timesteps, can be output by using the f_ID keyword and accessing a fix that does time-averaging such as the <A HREF = "fix_ave_time.html">fix ave/time</A> command. </P> <P>Options invoked by the <A HREF = "thermo_modify.html">thermo_modify</A> command can be used to set the one- or multi-line format of the print-out, the normalization of thermodynamic output (total values versus per-atom values for extensive quantities (ones which scale with the number of atoms in the system), and the numeric precision of each printed value. </P> <P>IMPORTANT NOTE: When you use a "thermo_style" command, all thermodynamic settings are restored to their default values, including those previously set by a <A HREF = "thermo_modify.html">thermo_modify</A> command. Thus if your input script specifies a thermo_style command, you should use the thermo_modify command after it. </P> <HR> <P>Several of the thermodynamic quantities require a temperature to be computed: "temp", "press", "ke", "etotal", "enthalpy", "pxx", etc. By default this is done by using a <I>temperature</I> compute which is created when LAMMPS starts up, as if this command had been issued: </P> <PRE>compute thermo_temp all temp </PRE> <P>See the <A HREF = "compute_temp.html">compute temp</A> command for details. Note that the ID of this compute is <I>thermo_temp</I> and the group is <I>all</I>. You can change the attributes of this temperature (e.g. its degrees-of-freedom) via the <A HREF = "compute_modify.html">compute_modify</A> command. Alternatively, you can directly assign a new compute (that calculates temperature) which you have defined, to be used for calculating any thermodynamic quantity that requires a temperature. This is done via the <A HREF = "thermo_modify.html">thermo_modify</A> command. </P> <P>Several of the thermodynamic quantities require a pressure to be computed: "press", "enthalpy", "pxx", etc. By default this is done by using a <I>pressure</I> compute which is created when LAMMPS starts up, as if this command had been issued: </P> <PRE>compute thermo_press all pressure thermo_temp </PRE> <P>See the <A HREF = "compute_pressure.html">compute pressure</A> command for details. Note that the ID of this compute is <I>thermo_press</I> and the group is <I>all</I>. You can change the attributes of this pressure via the <A HREF = "compute_modify.html">compute_modify</A> command. Alternatively, you can directly assign a new compute (that calculates pressure) which you have defined, to be used for calculating any thermodynamic quantity that requires a pressure. This is done via the <A HREF = "thermo_modify.html">thermo_modify</A> command. </P> <P>Several of the thermodynamic quantities require a potential energy to be computed: "pe", "etotal", "ebond", etc. This is done by using a <I>pe</I> compute which is created when LAMMPS starts up, as if this command had been issued: </P> <PRE>compute thermo_pe all pe </PRE> <P>See the <A HREF = "compute_pe.html">compute pe</A> command for details. Note that the ID of this compute is <I>thermo_pe</I> and the group is <I>all</I>. You can change the attributes of this potential energy via the <A HREF = "compute_modify.html">compute_modify</A> command. </P> <HR> <P>The kinetic energy of the system <I>ke</I> is inferred from the temperature of the system with 1/2 Kb T of energy for each degree of freedom. Thus, using different <A HREF = "compute.html">compute commands</A> for calculating temperature, via the <A HREF = "thermo_modify.html">thermo_modify temp</A> command, may yield different kinetic energies, since different computes that calculate temperature can subtract out different non-thermal components of velocity and/or include different degrees of freedom (translational, rotational, etc). </P> <P>The potential energy of the system <I>pe</I> will include contributions from fixes if the <A HREF = "fix_modify.html">fix_modify thermo</A> option is set for a fix that calculates such a contribution. For example, the <A HREF = "fix_wall.html">fix wall/lj93</A> fix calculates the energy of atoms interacting with the wall. See the doc pages for "individual fixes" to see which ones contribute. </P> <P>A long-range tail correction <I>etail</I> for the VanderWaal pairwise energy will be non-zero only if the <A HREF = "pair_modify.html">pair_modify tail</A> option is turned on. The <I>etail</I> contribution is included in <I>evdwl</I>, <I>pe</I>, and <I>etotal</I>, and the corresponding tail correction to the pressure is included in <I>press</I> and <I>pxx</I>, <I>pyy</I>, etc. </P> <HR> <P>The <I>step</I>, <I>elapsed</I>, and <I>elaplong</I> keywords refer to timestep count. <I>Step</I> is the current timestep, or iteration count when a <A HREF = "minimize.html">minimization</A> is being performed. <I>Elapsed</I> is the number of timesteps elapsed since the beginning of this run. <I>Elaplong</I> is the number of timesteps elapsed since the beginning of an initial run in a series of runs. See the <I>start</I> and <I>stop</I> keywords for the <A HREF = "run.html">run</A> for info on how to invoke a series of runs that keep track of an initial starting time. If these keywords are not used, then <I>elapsed</I> and <I>elaplong</I> are the same value. </P> +<P>The <I>dt</I> keyword is the current timestep size in time +<A HREF = "units.html">units</A>. The <I>time</I> keyword is the current elapsed +simulation time, also in time <A HREF = "units.html">units</A>, which is simply +(step*dt) if the timestep size has not changed and the timestep has +not been reset. If the timestep has changed (e.g. via <A HREF = "fix_dt_reset.html">fix +dt/reset</A>) or the timestep has been reset (e.g. via +the "reset_timestep" command), then the simulation time is effectively +a cummulative value up to the current point. +</P> <P>The <I>cpu</I> keyword is elapsed CPU seconds since the beginning of this run. The <I>tpcpu</I> and <I>spcpu</I> keywords are measures of how fast your simulation is currently running. The <I>tpcpu</I> keyword is simulation time per CPU second, where simulation time is in time <A HREF = "units.html">units</A>. E.g. for metal units, the <I>tpcpu</I> value would be picoseconds per CPU second. The <I>spcpu</I> keyword is the number of timesteps per CPU second. Both quantities are on-the-fly metrics, measured relative to the last time they were invoked. Thus if you are printing out thermodyamic output every 100 timesteps, the two keywords will continually output the time and timestep rate for the last 100 steps. The <I>tpcpu</I> keyword does not attempt to track any changes in timestep size, e.g. due to using the <A HREF = "fix_dt_reset.html">fix dt/reset</A> command. </P> <P>The <I>fmax</I> and <I>fnorm</I> keywords are useful for monitoring the progress of an <A HREF = "minimize.html">energy minimization</A>. The <I>fmax</I> keyword calculates the maximum force in any dimension on any atom in the system, or the infinity-norm of the force vector for the system. The <I>fnorm</I> keyword calculates the 2-norm or length of the force vector. </P> <P>The keywords <I>cella</I>, <I>cellb</I>, <I>cellc</I>, <I>cellalpha</I>, <I>cellbeta</I>, <I>cellgamma</I>, correspond to the usual crystallographic quantities that define the periodic unit cell of a crystal. See <A HREF = "Section_howto.html#howto_12">this section</A> of the doc pages for a geometric description of triclinic periodic cells, including a precise defintion of these quantities in terms of the internal LAMMPS cell dimensions <I>lx</I>, <I>ly</I>, <I>lz</I>, <I>yz</I>, <I>xz</I>, <I>xy</I>, </P> <HR> <P>The <I>c_ID</I> and <I>c_ID[I]</I> and <I>c_ID[I][J]</I> keywords allow global values calculated by a compute to be output. As discussed on the <A HREF = "compute.html">compute</A> doc page, computes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom compute values can be referenced in a <A HREF = "variable.html">variable</A> and the variable referenced by thermo_style custom, as discussed below. </P> <P>The ID in the keyword should be replaced by the actual ID of a compute that has been defined elsewhere in the input script. See the <A HREF = "compute.html">compute</A> command for details. If the compute calculates a global scalar, vector, or array, then the keyword formats with 0, 1, or 2 brackets will reference a scalar value from the compute. </P> <P>Note that some computes calculate "intensive" global quantities like temperature; others calculate "extensive" global quantities like kinetic energy that are summed over all atoms in the compute group. Intensive quantities are printed directly without normalization by thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the compute group) when output, depending on the <A HREF = "thermo_modify.html">thermo_modify norm</A> option being used. </P> <P>The <I>f_ID</I> and <I>f_ID[I]</I> and <I>f_ID[I][J]</I> keywords allow global values calculated by a fix to be output. As discussed on the <A HREF = "fix.html">fix</A> doc page, fixes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom fix values can be referenced in a <A HREF = "variable.html">variable</A> and the variable referenced by thermo_style custom, as discussed below. </P> <P>The ID in the keyword should be replaced by the actual ID of a fix that has been defined elsewhere in the input script. See the <A HREF = "fix.html">fix</A> command for details. If the fix calculates a global scalar, vector, or array, then the keyword formats with 0, 1, or 2 brackets will reference a scalar value from the fix. </P> <P>Note that some fixes calculate "intensive" global quantities like timestep size; others calculate "extensive" global quantities like energy that are summed over all atoms in the fix group. Intensive quantities are printed directly without normalization by thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the fix group) when output, depending on the <A HREF = "thermo_modify.html">thermo_modify norm</A> option being used. </P> <P>The <I>v_name</I> keyword allow the current value of a variable to be output. The name in the keyword should be replaced by the variable name that has been defined elsewhere in the input script. Only equal-style variables can be referenced. See the <A HREF = "variable.html">variable</A> command for details. Variables of style <I>equal</I> can reference per-atom properties or thermodynamic keywords, or they can invoke other computes, fixes, or variables when evaluated, so this is a very general means of creating thermodynamic output. </P> <P>See <A HREF = "Section_modify.html">Section_modify</A> for information on how to add new compute and fix styles to LAMMPS to calculate quantities that can then be referenced with these keywords to generate thermodynamic output. </P> <HR> <P><B>Restrictions:</B> </P> <P>This command must come after the simulation box is defined by a <A HREF = "read_data.html">read_data</A>, <A HREF = "read_restart.html">read_restart</A>, or <A HREF = "create_box.html">create_box</A> command. </P> <P><B>Related commands:</B> </P> <P><A HREF = "thermo.html">thermo</A>, <A HREF = "thermo_modify.html">thermo_modify</A>, <A HREF = "fix_modify.html">fix_modify</A>, <A HREF = "compute_temp.html">compute temp</A>, <A HREF = "compute_pressure.html">compute pressure</A> </P> <P><B>Default:</B> </P> <PRE>thermo_style one </PRE> </HTML> diff --git a/doc/thermo_style.txt b/doc/thermo_style.txt index 0e77cb728..29acefe6a 100644 --- a/doc/thermo_style.txt +++ b/doc/thermo_style.txt @@ -1,316 +1,326 @@ "LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c :link(lws,http://lammps.sandia.gov) :link(ld,Manual.html) :link(lc,Section_commands.html#comm) :line thermo_style command :h3 [Syntax:] thermo_style style args :pre style = {one} or {multi} or {custom} :ulb,l args = list of arguments for a particular style :l {one} args = none {multi} args = none {custom} args = list of attributes - possible attributes = step, elapsed, elaplong, dt, cpu, tpcpu, spcpu, + possible attributes = step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu, atoms, temp, press, pe, ke, etotal, enthalpy, evdwl, ecoul, epair, ebond, eangle, edihed, eimp, emol, elong, etail, vol, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz, xlat, ylat, zlat, pxx, pyy, pzz, pxy, pxz, pyz, fmax, fnorm, cella, cellb, cellc, cellalpha, cellbeta, cellgamma, c_ID, c_ID\[I\], c_ID\[I\]\[J\], f_ID, f_ID\[I\], f_ID\[I\]\[J\], v_name step = timestep elapsed = timesteps since start of this run elaplong = timesteps since start of initial run in a series of runs dt = timestep size + time = simulation time cpu = elapsed CPU time in seconds tpcpu = time per CPU second spcpu = timesteps per CPU second atoms = # of atoms temp = temperature press = pressure pe = total potential energy ke = kinetic energy etotal = total energy (pe + ke) enthalpy = enthalpy (etotal + press*vol) evdwl = VanderWaal pairwise energy ecoul = Coulombic pairwise energy epair = pairwise energy (evdwl + ecoul + elong + etail) ebond = bond energy eangle = angle energy edihed = dihedral energy eimp = improper energy emol = molecular energy (ebond + eangle + edihed + eimp) elong = long-range kspace energy etail = VanderWaal energy long-range tail correction vol = volume lx,ly,lz = box lengths in x,y,z xlo,xhi,ylo,yhi,zlo,zhi = box boundaries xy,xz,yz = box tilt for triclinic (non-orthogonal) simulation boxes xlat,ylat,zlat = lattice spacings as calculated by "lattice"_lattice.html command pxx,pyy,pzz,pxy,pxz,pyz = 6 components of pressure tensor fmax = max component of force on any atom in any dimension fnorm = length of force vector for all atoms cella,cellb,cellc = periodic cell lattice constants a,b,c cellalpha, cellbeta, cellgamma = periodic cell angles alpha,beta,gamma c_ID = global scalar value calculated by a compute with ID c_ID\[I\] = Ith component of global vector calculated by a compute with ID c_ID\[I\]\[J\] = I,J component of global array calculated by a compute with ID f_ID = global scalar value calculated by a fix with ID f_ID\[I\] = Ith component of global vector calculated by a fix with ID f_ID\[I\]\[J\] = I,J component of global array calculated by a fix with ID v_name = scalar value calculated by an equal-style variable with name :pre :ule [Examples:] thermo_style multi thermo_style custom step temp pe etotal press vol thermo_style custom step temp etotal c_myTemp v_abc :pre [Description:] Set the style and content for printing thermodynamic data to the screen and log file. Style {one} prints a one-line summary of thermodynamic info that is the equivalent of "thermo_style custom step temp epair emol etotal press". The line contains only numeric values. Style {multi} prints a multiple-line listing of thermodynamic info that is the equivalent of "thermo_style custom etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press". The listing contains numeric values and a string ID for each quantity. Style {custom} is the most general setting and allows you to specify which of the keywords listed above you want printed on each thermodynamic timestep. Note that the keywords c_ID, f_ID, v_name are references to "computes"_compute.html, "fixes"_fix.html, and equal-style "variables"_variable.html" that have been defined elsewhere in the input script or can even be new styles which users have added to LAMMPS (see the "Section_modify"_Section_modify.html section of the documentation). Thus the {custom} style provides a flexible means of outputting essentially any desired quantity as a simulation proceeds. All styles except {custom} have {vol} appended to their list of outputs if the simulation box volume changes during the simulation. The values printed by the various keywords are instantaneous values, calculated on the current timestep. Time-averaged quantities, which include values from previous timesteps, can be output by using the f_ID keyword and accessing a fix that does time-averaging such as the "fix ave/time"_fix_ave_time.html command. Options invoked by the "thermo_modify"_thermo_modify.html command can be used to set the one- or multi-line format of the print-out, the normalization of thermodynamic output (total values versus per-atom values for extensive quantities (ones which scale with the number of atoms in the system), and the numeric precision of each printed value. IMPORTANT NOTE: When you use a "thermo_style" command, all thermodynamic settings are restored to their default values, including those previously set by a "thermo_modify"_thermo_modify.html command. Thus if your input script specifies a thermo_style command, you should use the thermo_modify command after it. :line Several of the thermodynamic quantities require a temperature to be computed: "temp", "press", "ke", "etotal", "enthalpy", "pxx", etc. By default this is done by using a {temperature} compute which is created when LAMMPS starts up, as if this command had been issued: compute thermo_temp all temp :pre See the "compute temp"_compute_temp.html command for details. Note that the ID of this compute is {thermo_temp} and the group is {all}. You can change the attributes of this temperature (e.g. its degrees-of-freedom) via the "compute_modify"_compute_modify.html command. Alternatively, you can directly assign a new compute (that calculates temperature) which you have defined, to be used for calculating any thermodynamic quantity that requires a temperature. This is done via the "thermo_modify"_thermo_modify.html command. Several of the thermodynamic quantities require a pressure to be computed: "press", "enthalpy", "pxx", etc. By default this is done by using a {pressure} compute which is created when LAMMPS starts up, as if this command had been issued: compute thermo_press all pressure thermo_temp :pre See the "compute pressure"_compute_pressure.html command for details. Note that the ID of this compute is {thermo_press} and the group is {all}. You can change the attributes of this pressure via the "compute_modify"_compute_modify.html command. Alternatively, you can directly assign a new compute (that calculates pressure) which you have defined, to be used for calculating any thermodynamic quantity that requires a pressure. This is done via the "thermo_modify"_thermo_modify.html command. Several of the thermodynamic quantities require a potential energy to be computed: "pe", "etotal", "ebond", etc. This is done by using a {pe} compute which is created when LAMMPS starts up, as if this command had been issued: compute thermo_pe all pe :pre See the "compute pe"_compute_pe.html command for details. Note that the ID of this compute is {thermo_pe} and the group is {all}. You can change the attributes of this potential energy via the "compute_modify"_compute_modify.html command. :line The kinetic energy of the system {ke} is inferred from the temperature of the system with 1/2 Kb T of energy for each degree of freedom. Thus, using different "compute commands"_compute.html for calculating temperature, via the "thermo_modify temp"_thermo_modify.html command, may yield different kinetic energies, since different computes that calculate temperature can subtract out different non-thermal components of velocity and/or include different degrees of freedom (translational, rotational, etc). The potential energy of the system {pe} will include contributions from fixes if the "fix_modify thermo"_fix_modify.html option is set for a fix that calculates such a contribution. For example, the "fix wall/lj93"_fix_wall.html fix calculates the energy of atoms interacting with the wall. See the doc pages for "individual fixes" to see which ones contribute. A long-range tail correction {etail} for the VanderWaal pairwise energy will be non-zero only if the "pair_modify tail"_pair_modify.html option is turned on. The {etail} contribution is included in {evdwl}, {pe}, and {etotal}, and the corresponding tail correction to the pressure is included in {press} and {pxx}, {pyy}, etc. :line The {step}, {elapsed}, and {elaplong} keywords refer to timestep count. {Step} is the current timestep, or iteration count when a "minimization"_minimize.html is being performed. {Elapsed} is the number of timesteps elapsed since the beginning of this run. {Elaplong} is the number of timesteps elapsed since the beginning of an initial run in a series of runs. See the {start} and {stop} keywords for the "run"_run.html for info on how to invoke a series of runs that keep track of an initial starting time. If these keywords are not used, then {elapsed} and {elaplong} are the same value. +The {dt} keyword is the current timestep size in time +"units"_units.html. The {time} keyword is the current elapsed +simulation time, also in time "units"_units.html, which is simply +(step*dt) if the timestep size has not changed and the timestep has +not been reset. If the timestep has changed (e.g. via "fix +dt/reset"_fix_dt_reset.html) or the timestep has been reset (e.g. via +the "reset_timestep" command), then the simulation time is effectively +a cummulative value up to the current point. + The {cpu} keyword is elapsed CPU seconds since the beginning of this run. The {tpcpu} and {spcpu} keywords are measures of how fast your simulation is currently running. The {tpcpu} keyword is simulation time per CPU second, where simulation time is in time "units"_units.html. E.g. for metal units, the {tpcpu} value would be picoseconds per CPU second. The {spcpu} keyword is the number of timesteps per CPU second. Both quantities are on-the-fly metrics, measured relative to the last time they were invoked. Thus if you are printing out thermodyamic output every 100 timesteps, the two keywords will continually output the time and timestep rate for the last 100 steps. The {tpcpu} keyword does not attempt to track any changes in timestep size, e.g. due to using the "fix dt/reset"_fix_dt_reset.html command. The {fmax} and {fnorm} keywords are useful for monitoring the progress of an "energy minimization"_minimize.html. The {fmax} keyword calculates the maximum force in any dimension on any atom in the system, or the infinity-norm of the force vector for the system. The {fnorm} keyword calculates the 2-norm or length of the force vector. The keywords {cella}, {cellb}, {cellc}, {cellalpha}, {cellbeta}, {cellgamma}, correspond to the usual crystallographic quantities that define the periodic unit cell of a crystal. See "this section"_Section_howto.html#howto_12 of the doc pages for a geometric description of triclinic periodic cells, including a precise defintion of these quantities in terms of the internal LAMMPS cell dimensions {lx}, {ly}, {lz}, {yz}, {xz}, {xy}, :line The {c_ID} and {c_ID\[I\]} and {c_ID\[I\]\[J\]} keywords allow global values calculated by a compute to be output. As discussed on the "compute"_compute.html doc page, computes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom compute values can be referenced in a "variable"_variable.html and the variable referenced by thermo_style custom, as discussed below. The ID in the keyword should be replaced by the actual ID of a compute that has been defined elsewhere in the input script. See the "compute"_compute.html command for details. If the compute calculates a global scalar, vector, or array, then the keyword formats with 0, 1, or 2 brackets will reference a scalar value from the compute. Note that some computes calculate "intensive" global quantities like temperature; others calculate "extensive" global quantities like kinetic energy that are summed over all atoms in the compute group. Intensive quantities are printed directly without normalization by thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the compute group) when output, depending on the "thermo_modify norm"_thermo_modify.html option being used. The {f_ID} and {f_ID\[I\]} and {f_ID\[I\]\[J\]} keywords allow global values calculated by a fix to be output. As discussed on the "fix"_fix.html doc page, fixes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom fix values can be referenced in a "variable"_variable.html and the variable referenced by thermo_style custom, as discussed below. The ID in the keyword should be replaced by the actual ID of a fix that has been defined elsewhere in the input script. See the "fix"_fix.html command for details. If the fix calculates a global scalar, vector, or array, then the keyword formats with 0, 1, or 2 brackets will reference a scalar value from the fix. Note that some fixes calculate "intensive" global quantities like timestep size; others calculate "extensive" global quantities like energy that are summed over all atoms in the fix group. Intensive quantities are printed directly without normalization by thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the fix group) when output, depending on the "thermo_modify norm"_thermo_modify.html option being used. The {v_name} keyword allow the current value of a variable to be output. The name in the keyword should be replaced by the variable name that has been defined elsewhere in the input script. Only equal-style variables can be referenced. See the "variable"_variable.html command for details. Variables of style {equal} can reference per-atom properties or thermodynamic keywords, or they can invoke other computes, fixes, or variables when evaluated, so this is a very general means of creating thermodynamic output. See "Section_modify"_Section_modify.html for information on how to add new compute and fix styles to LAMMPS to calculate quantities that can then be referenced with these keywords to generate thermodynamic output. :line [Restrictions:] This command must come after the simulation box is defined by a "read_data"_read_data.html, "read_restart"_read_restart.html, or "create_box"_create_box.html command. [Related commands:] "thermo"_thermo.html, "thermo_modify"_thermo_modify.html, "fix_modify"_fix_modify.html, "compute temp"_compute_temp.html, "compute pressure"_compute_pressure.html [Default:] thermo_style one :pre diff --git a/src/MAKE/Makefile.mingw b/src/MAKE/Makefile.mingw deleted file mode 100644 index d322bc47a..000000000 --- a/src/MAKE/Makefile.mingw +++ /dev/null @@ -1,113 +0,0 @@ -# mingw = Windows 32bit, cross-compiled on Linux, gcc-4.4.1, MinGW x-compiler - -SHELL = /bin/sh - -# --------------------------------------------------------------------- -# compiler/linker settings -# specify flags and libraries needed for your compiler - -CC = i686-pc-mingw32-g++ -CCFLAGS = -O3 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -ffast-math -funroll-loops -fstrict-aliasing -Wall -W -Wno-uninitialized -SHFLAGS = -fPIC -DEPFLAGS = -M - -LINK = i686-pc-mingw32-g++ -LINKFLAGS = -O -LIB = -lwsock32 # -lwsock32 is needed for USER-IMD which uses tcp/ip sockets. -SIZE = i686-pc-mingw32-size - -ARCHIVE = ar -ARFLAGS = -rcsv -SHLIBFLAGS = -shared - -# --------------------------------------------------------------------- -# LAMMPS-specific settings -# specify settings for LAMMPS features you will use -# if you change any -D setting, do full re-compile after "make clean" - -# LAMMPS ifdef settings, OPTIONAL -# see possible settings in doc/Section_start.html#2_2 (step 4) - -LMP_INC = -DLAMMPS_XDR # -DLAMMPS_GZIP -DMALLOC_MEMALIGN=64 - -# MPI library, REQUIRED -# see discussion in doc/Section_start.html#2_2 (step 5) -# can point to dummy MPI library in src/STUBS as in Makefile.serial -# INC = path for mpi.h, MPI compiler settings -# PATH = path for MPI library -# LIB = name of MPI library - -MPI_INC = -I../STUBS -MPI_PATH = -MPI_LIB = mpi.o - -# FFT library, OPTIONAL -# see discussion in doc/Section_start.html#2_2 (step 6) -# can be left blank to use provided KISS FFT library -# INC = -DFFT setting, e.g. -DFFT_FFTW, FFT compiler settings -# PATH = path for FFT library -# LIB = name of FFT library - -FFT_INC = -DFFT_NONE #-DFFT_SINGLE -FFT_PATH = -FFT_LIB = #-lfftw - -# JPEG library, OPTIONAL -# see discussion in doc/Section_start.html#2_2 (step 7) -# only needed if -DLAMMPS_JPEG listed with LMP_INC -# INC = path for jpeglib.h -# PATH = path for JPEG library -# LIB = name of JPEG library - -JPG_INC = -JPG_PATH = -JPG_LIB = - -# --------------------------------------------------------------------- -# build rules and dependencies -# no need to edit this section - -include Makefile.package.settings -include Makefile.package - -EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PKG_SYSINC) -EXTRA_PATH = $(PKG_PATH) $(MPI_PATH) $(FFT_PATH) $(JPG_PATH) $(PKG_SYSPATH) -EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PKG_SYSLIB) - -# Path to src files - -vpath %.cpp .. -vpath %.h .. - -# Link target - -$(EXE): $(EXE).exe ../MAKE/mingw_cross.nsis - makensis ../MAKE/mingw_cross.nsis - (cd ..; zip -0 lammps-icms-win.zip lammps-icms-win.exe) - touch $(EXE) - -$(EXE).exe: $(OBJ) mpi.o - $(LINK) $(LINKFLAGS) $(EXTRA_PATH) $(OBJ) $(EXTRA_LIB) $(LIB) -o $(EXE).exe - $(SIZE) $(EXE).exe - -# Library target - -lib: $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(EXE) $(OBJ) - -# Compilation rules - -%.o:%.cpp - $(CC) $(CCFLAGS) $(EXTRA_INC) -c $< - -%.d:%.cpp - $(CC) $(CCFLAGS) $(EXTRA_INC) $(DEPFLAGS) $< > $@ - -# Individual dependencies - -mpi.o: ../STUBS/mpi.c ../STUBS/mpi.h - $(CC) $(CCFLAGS) $(EXTRA_INC) -c $< - -DEPENDS = $(OBJ:.o=.d) -sinclude $(DEPENDS) diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index a757d8975..5d331953c 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -1,1171 +1,1170 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "atom_vec_sphere.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "modify.h" #include "force.h" #include "fix.h" #include "fix_adapt.h" #include "math_const.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; using namespace MathConst; #define DELTA 10000 /* ---------------------------------------------------------------------- */ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; comm_x_only = 1; comm_f_only = 0; size_forward = 3; size_reverse = 6; size_border = 8; size_velocity = 6; size_data_atom = 7; size_data_vel = 7; xcol_data = 5; atom->sphere_flag = 1; atom->radius_flag = atom->rmass_flag = atom->omega_flag = atom->torque_flag = 1; } /* ---------------------------------------------------------------------- */ void AtomVecSphere::init() { AtomVec::init(); // set radvary if particle diameters are time-varying due to fix adapt radvary = 0; comm_x_only = 1; size_forward = 3; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"adapt") == 0) { FixAdapt *fix = (FixAdapt *) modify->fix[i]; if (fix->diamflag) { radvary = 1; comm_x_only = 0; size_forward = 5; } } } /* ---------------------------------------------------------------------- grow atom arrays n = 0 grows arrays by DELTA n > 0 allocates arrays to size n ------------------------------------------------------------------------- */ void AtomVecSphere::grow(int n) { if (n == 0) nmax += DELTA; else nmax = n; atom->nmax = nmax; if (nmax < 0 || nmax > MAXSMALLINT) error->one(FLERR,"Per-processor system is too big"); tag = memory->grow(atom->tag,nmax,"atom:tag"); type = memory->grow(atom->type,nmax,"atom:type"); mask = memory->grow(atom->mask,nmax,"atom:mask"); image = memory->grow(atom->image,nmax,"atom:image"); x = memory->grow(atom->x,nmax+1,3,"atom:x"); v = memory->grow(atom->v,nmax,3,"atom:v"); f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); radius = memory->grow(atom->radius,nmax,"atom:radius"); rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); omega = memory->grow(atom->omega,nmax,3,"atom:omega"); torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } /* ---------------------------------------------------------------------- reset local array ptrs ------------------------------------------------------------------------- */ void AtomVecSphere::grow_reset() { tag = atom->tag; type = atom->type; mask = atom->mask; image = atom->image; x = atom->x; v = atom->v; f = atom->f; radius = atom->radius; rmass = atom->rmass; omega = atom->omega; torque = atom->torque; } /* ---------------------------------------------------------------------- copy atom I info to atom J ------------------------------------------------------------------------- */ void AtomVecSphere::copy(int i, int j, int delflag) { tag[j] = tag[i]; type[j] = type[i]; mask[j] = mask[i]; image[j] = image[i]; x[j][0] = x[i][0]; x[j][1] = x[i][1]; x[j][2] = x[i][2]; v[j][0] = v[i][0]; v[j][1] = v[i][1]; v[j][2] = v[i][2]; radius[j] = radius[i]; rmass[j] = rmass[i]; omega[j][0] = omega[i][0]; omega[j][1] = omega[i][1]; omega[j][2] = omega[i][2]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; if (radvary == 0) { m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; } } } else { m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = radius[j]; buf[m++] = rmass[j]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = radius[j]; buf[m++] = rmass[j]; } } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz,dvx,dvy,dvz; if (radvary == 0) { m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } if (!deform_vremap) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; dvz = pbc[2]*h_rate[2]; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; if (mask[i] & deform_groupbit) { buf[m++] = v[j][0] + dvx; buf[m++] = v[j][1] + dvy; buf[m++] = v[j][2] + dvz; } else { buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } } } else { m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = radius[j]; buf[m++] = rmass[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; dz = pbc[2]*domain->zprd; } if (!deform_vremap) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = radius[j]; buf[m++] = rmass[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; dvz = pbc[2]*h_rate[2]; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = radius[j]; buf[m++] = rmass[j]; if (mask[i] & deform_groupbit) { buf[m++] = v[j][0] + dvx; buf[m++] = v[j][1] + dvy; buf[m++] = v[j][2] + dvz; } else { buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_comm_hybrid(int n, int *list, double *buf) { int i,j,m; if (radvary == 0) return 0; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = radius[j]; buf[m++] = rmass[j]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecSphere::unpack_comm(int n, int first, double *buf) { int i,m,last; if (radvary == 0) { m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; } } else { m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; radius[i] = buf[m++]; rmass[i] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ void AtomVecSphere::unpack_comm_vel(int n, int first, double *buf) { int i,m,last; if (radvary == 0) { m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } else { m = 0; last = first + n; for (i = first; i < last; i++) { x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; radius[i] = buf[m++]; rmass[i] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int AtomVecSphere::unpack_comm_hybrid(int n, int first, double *buf) { int i,m,last; if (radvary == 0) return 0; m = 0; last = first + n; for (i = first; i < last; i++) { radius[i] = buf[m++]; rmass[i] = buf[m++]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_reverse(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = f[i][0]; buf[m++] = f[i][1]; buf[m++] = f[i][2]; buf[m++] = torque[i][0]; buf[m++] = torque[i][1]; buf[m++] = torque[i][2]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_reverse_hybrid(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { buf[m++] = torque[i][0]; buf[m++] = torque[i][1]; buf[m++] = torque[i][2]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecSphere::unpack_reverse(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; f[j][0] += buf[m++]; f[j][1] += buf[m++]; f[j][2] += buf[m++]; torque[j][0] += buf[m++]; torque[j][1] += buf[m++]; torque[j][2] += buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecSphere::unpack_reverse_hybrid(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; torque[j][0] += buf[m++]; torque[j][1] += buf[m++]; torque[j][2] += buf[m++]; } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = radius[j]; buf[m++] = rmass[j]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = radius[j]; buf[m++] = rmass[j]; } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; double dx,dy,dz,dvx,dvy,dvz; m = 0; if (pbc_flag == 0) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0]; buf[m++] = x[j][1]; buf[m++] = x[j][2]; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = radius[j]; buf[m++] = rmass[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { if (domain->triclinic == 0) { dx = pbc[0]*domain->xprd; dy = pbc[1]*domain->yprd; dz = pbc[2]*domain->zprd; } else { dx = pbc[0]; dy = pbc[1]; dz = pbc[2]; } if (!deform_vremap) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = radius[j]; buf[m++] = rmass[j]; buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } else { dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; dvz = pbc[2]*h_rate[2]; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = x[j][0] + dx; buf[m++] = x[j][1] + dy; buf[m++] = x[j][2] + dz; buf[m++] = tag[j]; buf[m++] = type[j]; buf[m++] = mask[j]; buf[m++] = radius[j]; buf[m++] = rmass[j]; if (mask[i] & deform_groupbit) { buf[m++] = v[j][0] + dvx; buf[m++] = v[j][1] + dvy; buf[m++] = v[j][2] + dvz; } else { buf[m++] = v[j][0]; buf[m++] = v[j][1]; buf[m++] = v[j][2]; } buf[m++] = omega[j][0]; buf[m++] = omega[j][1]; buf[m++] = omega[j][2]; } } } return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::pack_border_hybrid(int n, int *list, double *buf) { int i,j,m; m = 0; for (i = 0; i < n; i++) { j = list[i]; buf[m++] = radius[j]; buf[m++] = rmass[j]; } return m; } /* ---------------------------------------------------------------------- */ void AtomVecSphere::unpack_border(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); radius[i] = buf[m++]; rmass[i] = buf[m++]; } } /* ---------------------------------------------------------------------- */ void AtomVecSphere::unpack_border_vel(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { if (i == nmax) grow(0); x[i][0] = buf[m++]; x[i][1] = buf[m++]; x[i][2] = buf[m++]; tag[i] = static_cast<int> (buf[m++]); type[i] = static_cast<int> (buf[m++]); mask[i] = static_cast<int> (buf[m++]); radius[i] = buf[m++]; rmass[i] = buf[m++]; v[i][0] = buf[m++]; v[i][1] = buf[m++]; v[i][2] = buf[m++]; omega[i][0] = buf[m++]; omega[i][1] = buf[m++]; omega[i][2] = buf[m++]; } } /* ---------------------------------------------------------------------- */ int AtomVecSphere::unpack_border_hybrid(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; for (i = first; i < last; i++) { radius[i] = buf[m++]; rmass[i] = buf[m++]; } return m; } /* ---------------------------------------------------------------------- pack data for atom I for sending to another proc xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ int AtomVecSphere::pack_exchange(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; *((tagint *) &buf[m++]) = image[i]; buf[m++] = radius[i]; buf[m++] = rmass[i]; buf[m++] = omega[i][0]; buf[m++] = omega[i][1]; buf[m++] = omega[i][2]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ int AtomVecSphere::unpack_exchange(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = *((tagint *) &buf[m++]); radius[nlocal] = buf[m++]; rmass[nlocal] = buf[m++]; omega[nlocal][0] = buf[m++]; omega[nlocal][1] = buf[m++]; omega[nlocal][2] = buf[m++]; if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal,&buf[m]); atom->nlocal++; return m; } /* ---------------------------------------------------------------------- size of restart data for all atoms owned by this proc include extra data stored by fixes ------------------------------------------------------------------------- */ int AtomVecSphere::size_restart() { int i; int nlocal = atom->nlocal; int n = 16 * nlocal; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); return n; } /* ---------------------------------------------------------------------- pack atom I's data for restart file including extra quantities xyz must be 1st 3 values, so that read_restart can test on them molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ int AtomVecSphere::pack_restart(int i, double *buf) { int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; buf[m++] = x[i][2]; buf[m++] = tag[i]; buf[m++] = type[i]; buf[m++] = mask[i]; *((tagint *) &buf[m++]) = image[i]; buf[m++] = v[i][0]; buf[m++] = v[i][1]; buf[m++] = v[i][2]; buf[m++] = radius[i]; buf[m++] = rmass[i]; buf[m++] = omega[i][0]; buf[m++] = omega[i][1]; buf[m++] = omega[i][2]; if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); buf[0] = m; return m; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities ------------------------------------------------------------------------- */ int AtomVecSphere::unpack_restart(double *buf) { int nlocal = atom->nlocal; if (nlocal == nmax) { grow(0); if (atom->nextra_store) memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); } int m = 1; x[nlocal][0] = buf[m++]; x[nlocal][1] = buf[m++]; x[nlocal][2] = buf[m++]; tag[nlocal] = static_cast<int> (buf[m++]); type[nlocal] = static_cast<int> (buf[m++]); mask[nlocal] = static_cast<int> (buf[m++]); image[nlocal] = *((tagint *) &buf[m++]); v[nlocal][0] = buf[m++]; v[nlocal][1] = buf[m++]; v[nlocal][2] = buf[m++]; radius[nlocal] = buf[m++]; rmass[nlocal] = buf[m++]; omega[nlocal][0] = buf[m++]; omega[nlocal][1] = buf[m++]; omega[nlocal][2] = buf[m++]; double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast<int> (buf[0]) - m; for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; } atom->nlocal++; return m; } /* ---------------------------------------------------------------------- create one atom of itype at coord set other values to defaults ------------------------------------------------------------------------- */ void AtomVecSphere::create_atom(int itype, double *coord) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = 0; type[nlocal] = itype; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; mask[nlocal] = 1; image[nlocal] = ((tagint) IMGMAX << IMG2BITS) | ((tagint) IMGMAX << IMGBITS) | IMGMAX; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; radius[nlocal] = 0.5; rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal]; omega[nlocal][0] = 0.0; omega[nlocal][1] = 0.0; omega[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecSphere::data_atom(double *coord, tagint imagetmp, char **values) { int nlocal = atom->nlocal; if (nlocal == nmax) grow(0); tag[nlocal] = atoi(values[0]); if (tag[nlocal] <= 0) error->one(FLERR,"Invalid atom ID in Atoms section of data file"); type[nlocal] = atoi(values[1]); if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one(FLERR,"Invalid atom type in Atoms section of data file"); radius[nlocal] = 0.5 * atof(values[2]); if (radius[nlocal] < 0.0) error->one(FLERR,"Invalid radius in Atoms section of data file"); double density = atof(values[3]); if (density <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); if (radius[nlocal] == 0.0) rmass[nlocal] = density; else rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density; x[nlocal][0] = coord[0]; x[nlocal][1] = coord[1]; x[nlocal][2] = coord[2]; image[nlocal] = imagetmp; mask[nlocal] = 1; v[nlocal][0] = 0.0; v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; omega[nlocal][0] = 0.0; omega[nlocal][1] = 0.0; omega[nlocal][2] = 0.0; atom->nlocal++; } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Atoms section of data file initialize other atom quantities for this sub-style ------------------------------------------------------------------------- */ int AtomVecSphere::data_atom_hybrid(int nlocal, char **values) { radius[nlocal] = 0.5 * atof(values[0]); if (radius[nlocal] < 0.0) error->one(FLERR,"Invalid radius in Atoms section of data file"); double density = atof(values[1]); if (density <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); if (radius[nlocal] == 0.0) rmass[nlocal] = density; else rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal] * density; return 2; } /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ void AtomVecSphere::data_vel(int m, char **values) { v[m][0] = atof(values[0]); v[m][1] = atof(values[1]); v[m][2] = atof(values[2]); omega[m][0] = atof(values[3]); omega[m][1] = atof(values[4]); omega[m][2] = atof(values[5]); } /* ---------------------------------------------------------------------- unpack hybrid quantities from one line in Velocities section of data file ------------------------------------------------------------------------- */ int AtomVecSphere::data_vel_hybrid(int m, char **values) { omega[m][0] = atof(values[0]); omega[m][1] = atof(values[1]); omega[m][2] = atof(values[2]); return 3; } /* ---------------------------------------------------------------------- pack atom info for data file including 3 image flags ------------------------------------------------------------------------- */ void AtomVecSphere::pack_data(double **buf) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { buf[i][0] = tag[i]; buf[i][1] = type[i]; buf[i][2] = 2.0*radius[i]; if (radius[i] == 0.0) buf[i][3] = rmass[i]; else buf[i][3] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); buf[i][4] = x[i][0]; - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = (image[i] & IMGMASK) - IMGMAX; - buf[i][9] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; - buf[i][10] = (image[i] >> IMG2BITS) - IMGMAX; + buf[i][5] = x[i][1]; + buf[i][6] = x[i][2]; + buf[i][7] = (image[i] & IMGMASK) - IMGMAX; + buf[i][8] = (image[i] >> IMGBITS & IMGMASK) - IMGMAX; + buf[i][9] = (image[i] >> IMG2BITS) - IMGMAX; } } /* ---------------------------------------------------------------------- pack hybrid atom info for data file ------------------------------------------------------------------------- */ int AtomVecSphere::pack_data_hybrid(int i, double *buf) { buf[0] = 2.0*radius[i]; if (radius[i] == 0.0) buf[1] = rmass[i]; else buf[1] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); return 2; } /* ---------------------------------------------------------------------- write atom info to data file including 3 image flags ------------------------------------------------------------------------- */ void AtomVecSphere::write_data(FILE *fp, int n, double **buf) { for (int i = 0; i < n; i++) fprintf(fp,"%d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", (int) buf[i][0],(int) buf[i][1], buf[i][2],buf[i][3], buf[i][4],buf[i][5],buf[i][6], (int) buf[i][7],(int) buf[i][8],(int) buf[i][9]); } /* ---------------------------------------------------------------------- write hybrid atom info to data file ------------------------------------------------------------------------- */ int AtomVecSphere::write_data_hybrid(FILE *fp, double *buf) { fprintf(fp," %-1.16e %-1.16e",buf[0],buf[1]); return 2; } /* ---------------------------------------------------------------------- pack velocity info for data file ------------------------------------------------------------------------- */ void AtomVecSphere::pack_vel(double **buf) { int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { buf[i][0] = tag[i]; buf[i][1] = v[i][0]; buf[i][2] = v[i][1]; buf[i][3] = v[i][2]; buf[i][4] = omega[i][0]; buf[i][5] = omega[i][1]; buf[i][6] = omega[i][2]; } } /* ---------------------------------------------------------------------- pack hybrid velocity info for data file ------------------------------------------------------------------------- */ int AtomVecSphere::pack_vel_hybrid(int i, double *buf) { buf[0] = omega[i][0]; buf[1] = omega[i][1]; buf[2] = omega[i][2]; return 3; } /* ---------------------------------------------------------------------- write velocity info to data file ------------------------------------------------------------------------- */ void AtomVecSphere::write_vel(FILE *fp, int n, double **buf) { for (int i = 0; i < n; i++) fprintf(fp,"%d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", (int) buf[i][0],buf[i][1],buf[i][2],buf[i][3], buf[i][4],buf[i][5],buf[i][6]); } /* ---------------------------------------------------------------------- write hybrid velocity info to data file ------------------------------------------------------------------------- */ int AtomVecSphere::write_vel_hybrid(FILE *fp, double *buf) { fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]); return 3; } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ bigint AtomVecSphere::memory_usage() { bigint bytes = 0; if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); if (atom->memcheck("type")) bytes += memory->usage(type,nmax); if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); if (atom->memcheck("image")) bytes += memory->usage(image,nmax); if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax); if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3); if (atom->memcheck("torque")) bytes += memory->usage(torque,nmax*comm->nthreads,3); return bytes; } diff --git a/src/comm.cpp b/src/comm.cpp index 4f4dfe75f..b15fc5a28 100644 --- a/src/comm.cpp +++ b/src/comm.cpp @@ -1,1861 +1,1863 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author (triclinic) : Pieter in 't Veld (SNL) ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "comm.h" #include "universe.h" #include "atom.h" #include "atom_vec.h" #include "force.h" #include "pair.h" #include "domain.h" #include "neighbor.h" #include "group.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "output.h" #include "dump.h" #include "procmap.h" #include "math_extra.h" #include "error.h" #include "memory.h" #ifdef _OPENMP #include "omp.h" #endif using namespace LAMMPS_NS; #define BUFFACTOR 1.5 #define BUFMIN 1000 #define BUFEXTRA 1000 #define BIG 1.0e20 enum{SINGLE,MULTI}; enum{MULTIPLE}; // same as in ProcMap enum{ONELEVEL,TWOLEVEL,NUMA,CUSTOM}; enum{CART,CARTREORDER,XYZ}; /* ---------------------------------------------------------------------- setup MPI and allocate buffer space ------------------------------------------------------------------------- */ Comm::Comm(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); user_procgrid[0] = user_procgrid[1] = user_procgrid[2] = 0; coregrid[0] = coregrid[1] = coregrid[2] = 1; gridflag = ONELEVEL; mapflag = CART; customfile = NULL; recv_from_partition = send_to_partition = -1; otherflag = 0; outfile = NULL; grid2proc = NULL; bordergroup = 0; style = SINGLE; uniform = 1; xsplit = ysplit = zsplit = NULL; multilo = multihi = NULL; cutghostmulti = NULL; cutghostuser = 0.0; ghost_velocity = 0; // use of OpenMP threads // query OpenMP for number of threads/process set by user at run-time // if the OMP_NUM_THREADS environment variable is not set, we default // to using 1 thread. This follows the principle of the least surprise, // while practically all OpenMP implementations violate it by using // as many threads as there are (virtual) CPU cores by default. nthreads = 1; #ifdef _OPENMP if (getenv("OMP_NUM_THREADS") == NULL) { nthreads = 1; if (me == 0) error->warning(FLERR,"OMP_NUM_THREADS environment is not set."); } else { nthreads = omp_get_max_threads(); } // enforce consistent number of threads across all MPI tasks MPI_Bcast(&nthreads,1,MPI_INT,0,world); omp_set_num_threads(nthreads); if (me == 0) { if (screen) fprintf(screen," using %d OpenMP thread(s) per MPI task\n",nthreads); if (logfile) fprintf(logfile," using %d OpenMP thread(s) per MPI task\n",nthreads); } #endif // initialize comm buffers & exchange memory maxsend = BUFMIN; memory->create(buf_send,maxsend+BUFEXTRA,"comm:buf_send"); maxrecv = BUFMIN; memory->create(buf_recv,maxrecv,"comm:buf_recv"); maxswap = 6; allocate_swap(maxswap); sendlist = (int **) memory->smalloc(maxswap*sizeof(int *),"comm:sendlist"); memory->create(maxsendlist,maxswap,"comm:maxsendlist"); for (int i = 0; i < maxswap; i++) { maxsendlist[i] = BUFMIN; memory->create(sendlist[i],BUFMIN,"comm:sendlist[i]"); } } /* ---------------------------------------------------------------------- */ Comm::~Comm() { memory->destroy(xsplit); memory->destroy(ysplit); memory->destroy(zsplit); delete [] customfile; delete [] outfile; memory->destroy(grid2proc); free_swap(); if (style == MULTI) { free_multi(); memory->destroy(cutghostmulti); } if (sendlist) for (int i = 0; i < maxswap; i++) memory->destroy(sendlist[i]); memory->sfree(sendlist); memory->destroy(maxsendlist); memory->destroy(buf_send); memory->destroy(buf_recv); } /* ---------------------------------------------------------------------- create 3d grid of procs based on Nprocs and box size & shape map processors to grid, setup xyz split for a uniform grid ------------------------------------------------------------------------- */ void Comm::set_proc_grid(int outflag) { // recv 3d proc grid of another partition if my 3d grid depends on it if (recv_from_partition >= 0) { MPI_Status status; if (me == 0) { MPI_Recv(other_procgrid,3,MPI_INT, universe->root_proc[recv_from_partition],0, universe->uworld,&status); MPI_Recv(other_coregrid,3,MPI_INT, universe->root_proc[recv_from_partition],0, universe->uworld,&status); } MPI_Bcast(other_procgrid,3,MPI_INT,0,world); MPI_Bcast(other_coregrid,3,MPI_INT,0,world); } // create ProcMap class to create 3d grid and map procs to it ProcMap *pmap = new ProcMap(lmp); // create 3d grid of processors // produces procgrid and coregrid (if relevant) if (gridflag == ONELEVEL) { pmap->onelevel_grid(nprocs,user_procgrid,procgrid, otherflag,other_style,other_procgrid,other_coregrid); } else if (gridflag == TWOLEVEL) { pmap->twolevel_grid(nprocs,user_procgrid,procgrid, ncores,user_coregrid,coregrid, otherflag,other_style,other_procgrid,other_coregrid); } else if (gridflag == NUMA) { pmap->numa_grid(nprocs,user_procgrid,procgrid,coregrid); } else if (gridflag == CUSTOM) { pmap->custom_grid(customfile,nprocs,user_procgrid,procgrid); } // error check on procgrid // should not be necessary due to ProcMap if (procgrid[0]*procgrid[1]*procgrid[2] != nprocs) error->all(FLERR,"Bad grid of processors"); if (domain->dimension == 2 && procgrid[2] != 1) error->all(FLERR,"Processor count in z must be 1 for 2d simulation"); // grid2proc[i][j][k] = proc that owns i,j,k location in 3d grid if (grid2proc) memory->destroy(grid2proc); memory->create(grid2proc,procgrid[0],procgrid[1],procgrid[2], "comm:grid2proc"); // map processor IDs to 3d processor grid // produces myloc, procneigh, grid2proc if (gridflag == ONELEVEL) { if (mapflag == CART) pmap->cart_map(0,procgrid,myloc,procneigh,grid2proc); else if (mapflag == CARTREORDER) pmap->cart_map(1,procgrid,myloc,procneigh,grid2proc); else if (mapflag == XYZ) pmap->xyz_map(xyz,procgrid,myloc,procneigh,grid2proc); } else if (gridflag == TWOLEVEL) { if (mapflag == CART) pmap->cart_map(0,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); else if (mapflag == CARTREORDER) pmap->cart_map(1,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); else if (mapflag == XYZ) pmap->xyz_map(xyz,procgrid,ncores,coregrid,myloc,procneigh,grid2proc); } else if (gridflag == NUMA) { pmap->numa_map(0,coregrid,myloc,procneigh,grid2proc); } else if (gridflag == CUSTOM) { pmap->custom_map(procgrid,myloc,procneigh,grid2proc); } // print 3d grid info to screen and logfile if (outflag && me == 0) { if (screen) { fprintf(screen," %d by %d by %d MPI processor grid\n", procgrid[0],procgrid[1],procgrid[2]); if (gridflag == NUMA || gridflag == TWOLEVEL) fprintf(screen," %d by %d by %d core grid within node\n", coregrid[0],coregrid[1],coregrid[2]); } if (logfile) { fprintf(logfile," %d by %d by %d MPI processor grid\n", procgrid[0],procgrid[1],procgrid[2]); if (gridflag == NUMA || gridflag == TWOLEVEL) fprintf(logfile," %d by %d by %d core grid within node\n", coregrid[0],coregrid[1],coregrid[2]); } } // print 3d grid details to outfile if (outfile) pmap->output(outfile,procgrid,grid2proc); // free ProcMap class delete pmap; // set xsplit,ysplit,zsplit for uniform spacings memory->destroy(xsplit); memory->destroy(ysplit); memory->destroy(zsplit); memory->create(xsplit,procgrid[0]+1,"comm:xsplit"); memory->create(ysplit,procgrid[1]+1,"comm:ysplit"); memory->create(zsplit,procgrid[2]+1,"comm:zsplit"); for (int i = 0; i < procgrid[0]; i++) xsplit[i] = i * 1.0/procgrid[0]; for (int i = 0; i < procgrid[1]; i++) ysplit[i] = i * 1.0/procgrid[1]; for (int i = 0; i < procgrid[2]; i++) zsplit[i] = i * 1.0/procgrid[2]; xsplit[procgrid[0]] = ysplit[procgrid[1]] = zsplit[procgrid[2]] = 1.0; // set lamda box params after procs are assigned // only set once unless load-balancing occurs if (domain->triclinic) domain->set_lamda_box(); // send my 3d proc grid to another partition if requested if (send_to_partition >= 0) { if (me == 0) { MPI_Send(procgrid,3,MPI_INT, universe->root_proc[send_to_partition],0, universe->uworld); MPI_Send(coregrid,3,MPI_INT, universe->root_proc[send_to_partition],0, universe->uworld); } } } /* ---------------------------------------------------------------------- */ void Comm::init() { triclinic = domain->triclinic; map_style = atom->map_style; // comm_only = 1 if only x,f are exchanged in forward/reverse comm // comm_x_only = 0 if ghost_velocity since velocities are added comm_x_only = atom->avec->comm_x_only; comm_f_only = atom->avec->comm_f_only; if (ghost_velocity) comm_x_only = 0; // set per-atom sizes for forward/reverse/border comm // augment by velocity quantities if needed size_forward = atom->avec->size_forward; size_reverse = atom->avec->size_reverse; size_border = atom->avec->size_border; if (ghost_velocity) size_forward += atom->avec->size_velocity; if (ghost_velocity) size_border += atom->avec->size_velocity; // maxforward = # of datums in largest forward communication // maxreverse = # of datums in largest reverse communication // query pair,fix,compute,dump for their requirements // pair style can force reverse comm even if newton off maxforward = MAX(size_forward,size_border); maxreverse = size_reverse; if (force->pair) maxforward = MAX(maxforward,force->pair->comm_forward); if (force->pair) maxreverse = MAX(maxreverse,force->pair->comm_reverse); for (int i = 0; i < modify->nfix; i++) { maxforward = MAX(maxforward,modify->fix[i]->comm_forward); maxreverse = MAX(maxreverse,modify->fix[i]->comm_reverse); } for (int i = 0; i < modify->ncompute; i++) { maxforward = MAX(maxforward,modify->compute[i]->comm_forward); maxreverse = MAX(maxreverse,modify->compute[i]->comm_reverse); } for (int i = 0; i < output->ndump; i++) { maxforward = MAX(maxforward,output->dump[i]->comm_forward); maxreverse = MAX(maxreverse,output->dump[i]->comm_reverse); } if (force->newton == 0) maxreverse = 0; if (force->pair) maxreverse = MAX(maxreverse,force->pair->comm_reverse_off); // memory for multi-style communication if (style == MULTI && multilo == NULL) { allocate_multi(maxswap); memory->create(cutghostmulti,atom->ntypes+1,3,"comm:cutghostmulti"); } if (style == SINGLE && multilo) { free_multi(); memory->destroy(cutghostmulti); } } /* ---------------------------------------------------------------------- setup spatial-decomposition communication patterns function of neighbor cutoff(s) & cutghostuser & current box size single style sets slab boundaries (slablo,slabhi) based on max cutoff multi style sets type-dependent slab boundaries (multilo,multihi) ------------------------------------------------------------------------- */ void Comm::setup() { // cutghost[] = max distance at which ghost atoms need to be acquired // for orthogonal: // cutghost is in box coords = neigh->cutghost in all 3 dims // for triclinic: // neigh->cutghost = distance between tilted planes in box coords // cutghost is in lamda coords = distance between those planes // for multi: // cutghostmulti = same as cutghost, only for each atom type int i; int ntypes = atom->ntypes; double *prd,*sublo,*subhi; double cut = MAX(neighbor->cutneighmax,cutghostuser); if (triclinic == 0) { prd = domain->prd; sublo = domain->sublo; subhi = domain->subhi; cutghost[0] = cutghost[1] = cutghost[2] = cut; if (style == MULTI) { double *cuttype = neighbor->cuttype; for (i = 1; i <= ntypes; i++) cutghostmulti[i][0] = cutghostmulti[i][1] = cutghostmulti[i][2] = cuttype[i]; } } else { prd = domain->prd_lamda; sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; double *h_inv = domain->h_inv; double length0,length1,length2; length0 = sqrt(h_inv[0]*h_inv[0] + h_inv[5]*h_inv[5] + h_inv[4]*h_inv[4]); cutghost[0] = cut * length0; length1 = sqrt(h_inv[1]*h_inv[1] + h_inv[3]*h_inv[3]); cutghost[1] = cut * length1; length2 = h_inv[2]; cutghost[2] = cut * length2; if (style == MULTI) { double *cuttype = neighbor->cuttype; for (i = 1; i <= ntypes; i++) { cutghostmulti[i][0] = cuttype[i] * length0; cutghostmulti[i][1] = cuttype[i] * length1; cutghostmulti[i][2] = cuttype[i] * length2; } } } // recvneed[idim][0/1] = # of procs away I recv atoms from, within cutghost // 0 = from left, 1 = from right // do not cross non-periodic boundaries, need[2] = 0 for 2d // sendneed[idim][0/1] = # of procs away I send atoms to // 0 = to left, 1 = to right // set equal to recvneed[idim][1/0] of neighbor proc // maxneed[idim] = max procs away any proc recvs atoms in either direction // uniform = 1 = uniform sized sub-domains: // maxneed is directly computable from sub-domain size // limit to procgrid-1 for non-PBC // recvneed = maxneed except for procs near non-PBC // sendneed = recvneed of neighbor on each side // uniform = 0 = non-uniform sized sub-domains: // compute recvneed via updown() which accounts for non-PBC // sendneed = recvneed of neighbor on each side // maxneed via Allreduce() of recvneed int *periodicity = domain->periodicity; int left,right; if (uniform) { maxneed[0] = static_cast<int> (cutghost[0] * procgrid[0] / prd[0]) + 1; maxneed[1] = static_cast<int> (cutghost[1] * procgrid[1] / prd[1]) + 1; maxneed[2] = static_cast<int> (cutghost[2] * procgrid[2] / prd[2]) + 1; if (domain->dimension == 2) maxneed[2] = 0; if (!periodicity[0]) maxneed[0] = MIN(maxneed[0],procgrid[0]-1); if (!periodicity[1]) maxneed[1] = MIN(maxneed[1],procgrid[1]-1); if (!periodicity[2]) maxneed[2] = MIN(maxneed[2],procgrid[2]-1); if (!periodicity[0]) { recvneed[0][0] = MIN(maxneed[0],myloc[0]); recvneed[0][1] = MIN(maxneed[0],procgrid[0]-myloc[0]-1); left = myloc[0] - 1; if (left < 0) left = procgrid[0] - 1; sendneed[0][0] = MIN(maxneed[0],procgrid[0]-left-1); right = myloc[0] + 1; if (right == procgrid[0]) right = 0; sendneed[0][1] = MIN(maxneed[0],right); } else recvneed[0][0] = recvneed[0][1] = sendneed[0][0] = sendneed[0][1] = maxneed[0]; if (!periodicity[1]) { recvneed[1][0] = MIN(maxneed[1],myloc[1]); recvneed[1][1] = MIN(maxneed[1],procgrid[1]-myloc[1]-1); left = myloc[1] - 1; if (left < 0) left = procgrid[1] - 1; sendneed[1][0] = MIN(maxneed[1],procgrid[1]-left-1); right = myloc[1] + 1; if (right == procgrid[1]) right = 0; sendneed[1][1] = MIN(maxneed[1],right); } else recvneed[1][0] = recvneed[1][1] = sendneed[1][0] = sendneed[1][1] = maxneed[1]; if (!periodicity[2]) { recvneed[2][0] = MIN(maxneed[2],myloc[2]); recvneed[2][1] = MIN(maxneed[2],procgrid[2]-myloc[2]-1); left = myloc[2] - 1; if (left < 0) left = procgrid[2] - 1; sendneed[2][0] = MIN(maxneed[2],procgrid[2]-left-1); right = myloc[2] + 1; if (right == procgrid[2]) right = 0; sendneed[2][1] = MIN(maxneed[2],right); } else recvneed[2][0] = recvneed[2][1] = sendneed[2][0] = sendneed[2][1] = maxneed[2]; } else { recvneed[0][0] = updown(0,0,myloc[0],prd[0],periodicity[0],xsplit); recvneed[0][1] = updown(0,1,myloc[0],prd[0],periodicity[0],xsplit); left = myloc[0] - 1; if (left < 0) left = procgrid[0] - 1; sendneed[0][0] = updown(0,1,left,prd[0],periodicity[0],xsplit); right = myloc[0] + 1; if (right == procgrid[0]) right = 0; sendneed[0][1] = updown(0,0,right,prd[0],periodicity[0],xsplit); recvneed[1][0] = updown(1,0,myloc[1],prd[1],periodicity[1],ysplit); recvneed[1][1] = updown(1,1,myloc[1],prd[1],periodicity[1],ysplit); left = myloc[1] - 1; if (left < 0) left = procgrid[1] - 1; sendneed[1][0] = updown(1,1,left,prd[1],periodicity[1],ysplit); right = myloc[1] + 1; if (right == procgrid[1]) right = 0; sendneed[1][1] = updown(1,0,right,prd[1],periodicity[1],ysplit); if (domain->dimension == 3) { recvneed[2][0] = updown(2,0,myloc[2],prd[2],periodicity[2],zsplit); recvneed[2][1] = updown(2,1,myloc[2],prd[2],periodicity[2],zsplit); left = myloc[2] - 1; if (left < 0) left = procgrid[2] - 1; sendneed[2][0] = updown(2,1,left,prd[2],periodicity[2],zsplit); right = myloc[2] + 1; if (right == procgrid[2]) right = 0; sendneed[2][1] = updown(2,0,right,prd[2],periodicity[2],zsplit); } else recvneed[2][0] = recvneed[2][1] = sendneed[2][0] = sendneed[2][1] = 0; int all[6]; MPI_Allreduce(&recvneed[0][0],all,6,MPI_INT,MPI_MAX,world); maxneed[0] = MAX(all[0],all[1]); maxneed[1] = MAX(all[2],all[3]); maxneed[2] = MAX(all[4],all[5]); - // if (me == 0) printf("MAXNEED %d %d %d\n",maxneed[0],maxneed[1],maxneed[2]); + //if (me == 0) + //printf("MAXNEED %d %d %d\n",maxneed[0],maxneed[1],maxneed[2]); } // allocate comm memory nswap = 2 * (maxneed[0]+maxneed[1]+maxneed[2]); if (nswap > maxswap) grow_swap(nswap); // setup parameters for each exchange: // sendproc = proc to send to at each swap // recvproc = proc to recv from at each swap // for style SINGLE: // slablo/slabhi = boundaries for slab of atoms to send at each swap // use -BIG/midpt/BIG to insure all atoms included even if round-off occurs // if round-off, atoms recvd across PBC can be < or > than subbox boundary // note that borders() only loops over subset of atoms during each swap // treat all as PBC here, non-PBC is handled in borders() via r/s need[][] // for style MULTI: // multilo/multihi is same, with slablo/slabhi for each atom type // pbc_flag: 0 = nothing across a boundary, 1 = something across a boundary // pbc = -1/0/1 for PBC factor in each of 3/6 orthogonal/triclinic dirs // for triclinic, slablo/hi and pbc_border will be used in lamda (0-1) coords // 1st part of if statement is sending to the west/south/down // 2nd part of if statement is sending to the east/north/up int dim,ineed; int iswap = 0; for (dim = 0; dim < 3; dim++) { for (ineed = 0; ineed < 2*maxneed[dim]; ineed++) { pbc_flag[iswap] = 0; pbc[iswap][0] = pbc[iswap][1] = pbc[iswap][2] = pbc[iswap][3] = pbc[iswap][4] = pbc[iswap][5] = 0; if (ineed % 2 == 0) { sendproc[iswap] = procneigh[dim][0]; recvproc[iswap] = procneigh[dim][1]; if (style == SINGLE) { if (ineed < 2) slablo[iswap] = -BIG; else slablo[iswap] = 0.5 * (sublo[dim] + subhi[dim]); slabhi[iswap] = sublo[dim] + cutghost[dim]; } else { for (i = 1; i <= ntypes; i++) { if (ineed < 2) multilo[iswap][i] = -BIG; else multilo[iswap][i] = 0.5 * (sublo[dim] + subhi[dim]); multihi[iswap][i] = sublo[dim] + cutghostmulti[i][dim]; } } if (myloc[dim] == 0) { pbc_flag[iswap] = 1; pbc[iswap][dim] = 1; if (triclinic) { if (dim == 1) pbc[iswap][5] = 1; else if (dim == 2) pbc[iswap][4] = pbc[iswap][3] = 1; } } } else { sendproc[iswap] = procneigh[dim][1]; recvproc[iswap] = procneigh[dim][0]; if (style == SINGLE) { slablo[iswap] = subhi[dim] - cutghost[dim]; if (ineed < 2) slabhi[iswap] = BIG; else slabhi[iswap] = 0.5 * (sublo[dim] + subhi[dim]); } else { for (i = 1; i <= ntypes; i++) { multilo[iswap][i] = subhi[dim] - cutghostmulti[i][dim]; if (ineed < 2) multihi[iswap][i] = BIG; else multihi[iswap][i] = 0.5 * (sublo[dim] + subhi[dim]); } } if (myloc[dim] == procgrid[dim]-1) { pbc_flag[iswap] = 1; pbc[iswap][dim] = -1; if (triclinic) { if (dim == 1) pbc[iswap][5] = -1; else if (dim == 2) pbc[iswap][4] = pbc[iswap][3] = -1; } } } iswap++; } } } /* ---------------------------------------------------------------------- walk up/down the extent of nearby processors in dim and dir loc = myloc of proc to start at dir = 0/1 = walk to left/right do not cross non-periodic boundaries is not called for z dim in 2d return how many procs away are needed to encompass cutghost away from loc ------------------------------------------------------------------------- */ int Comm::updown(int dim, int dir, int loc, double prd, int periodicity, double *split) { int index,count; double frac,delta; if (dir == 0) { frac = cutghost[dim]/prd; index = loc - 1; delta = 0.0; count = 0; while (delta < frac) { if (index < 0) { if (!periodicity) break; index = procgrid[dim] - 1; } count++; delta += split[index+1] - split[index]; index--; } } else { frac = cutghost[dim]/prd; index = loc + 1; delta = 0.0; count = 0; while (delta < frac) { if (index >= procgrid[dim]) { if (!periodicity) break; index = 0; } count++; delta += split[index+1] - split[index]; index++; } } return count; } /* ---------------------------------------------------------------------- forward communication of atom coords every timestep other per-atom attributes may also be sent via pack/unpack routines ------------------------------------------------------------------------- */ void Comm::forward_comm(int dummy) { int n; MPI_Request request; MPI_Status status; AtomVec *avec = atom->avec; double **x = atom->x; double *buf; // exchange data with another proc // if other proc is self, just copy // if comm_x_only set, exchange or copy directly to x, don't unpack for (int iswap = 0; iswap < nswap; iswap++) { if (sendproc[iswap] != me) { if (comm_x_only) { if (size_forward_recv[iswap]) buf = x[firstrecv[iswap]]; else buf = NULL; if (size_forward_recv[iswap]) MPI_Irecv(buf,size_forward_recv[iswap],MPI_DOUBLE, recvproc[iswap],0,world,&request); n = avec->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); if (n) MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world); if (size_forward_recv[iswap]) MPI_Wait(&request,&status); } else if (ghost_velocity) { if (size_forward_recv[iswap]) MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE, recvproc[iswap],0,world,&request); n = avec->pack_comm_vel(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); if (n) MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world); if (size_forward_recv[iswap]) MPI_Wait(&request,&status); avec->unpack_comm_vel(recvnum[iswap],firstrecv[iswap],buf_recv); } else { if (size_forward_recv[iswap]) MPI_Irecv(buf_recv,size_forward_recv[iswap],MPI_DOUBLE, recvproc[iswap],0,world,&request); n = avec->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); if (n) MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world); if (size_forward_recv[iswap]) MPI_Wait(&request,&status); avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_recv); } } else { if (comm_x_only) { if (sendnum[iswap]) n = avec->pack_comm(sendnum[iswap],sendlist[iswap], x[firstrecv[iswap]],pbc_flag[iswap], pbc[iswap]); } else if (ghost_velocity) { n = avec->pack_comm_vel(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); avec->unpack_comm_vel(recvnum[iswap],firstrecv[iswap],buf_send); } else { n = avec->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); avec->unpack_comm(recvnum[iswap],firstrecv[iswap],buf_send); } } } } /* ---------------------------------------------------------------------- reverse communication of forces on atoms every timestep other per-atom attributes may also be sent via pack/unpack routines ------------------------------------------------------------------------- */ void Comm::reverse_comm() { int n; MPI_Request request; MPI_Status status; AtomVec *avec = atom->avec; double **f = atom->f; double *buf; // exchange data with another proc // if other proc is self, just copy // if comm_f_only set, exchange or copy directly from f, don't pack for (int iswap = nswap-1; iswap >= 0; iswap--) { if (sendproc[iswap] != me) { if (comm_f_only) { if (size_reverse_recv[iswap]) MPI_Irecv(buf_recv,size_reverse_recv[iswap],MPI_DOUBLE, sendproc[iswap],0,world,&request); if (size_reverse_send[iswap]) buf = f[firstrecv[iswap]]; else buf = NULL; if (size_reverse_send[iswap]) MPI_Send(buf,size_reverse_send[iswap],MPI_DOUBLE, recvproc[iswap],0,world); if (size_reverse_recv[iswap]) MPI_Wait(&request,&status); } else { if (size_reverse_recv[iswap]) MPI_Irecv(buf_recv,size_reverse_recv[iswap],MPI_DOUBLE, sendproc[iswap],0,world,&request); n = avec->pack_reverse(recvnum[iswap],firstrecv[iswap],buf_send); if (n) MPI_Send(buf_send,n,MPI_DOUBLE,recvproc[iswap],0,world); if (size_reverse_recv[iswap]) MPI_Wait(&request,&status); } avec->unpack_reverse(sendnum[iswap],sendlist[iswap],buf_recv); } else { if (comm_f_only) { if (sendnum[iswap]) avec->unpack_reverse(sendnum[iswap],sendlist[iswap], f[firstrecv[iswap]]); } else { n = avec->pack_reverse(recvnum[iswap],firstrecv[iswap],buf_send); avec->unpack_reverse(sendnum[iswap],sendlist[iswap],buf_send); } } } } /* ---------------------------------------------------------------------- exchange: move atoms to correct processors atoms exchanged with all 6 stencil neighbors send out atoms that have left my box, receive ones entering my box atoms will be lost if not inside some proc's box can happen if atom moves outside of non-periodic bounary or if atom moves more than one proc away this routine called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before exchange is called ------------------------------------------------------------------------- */ void Comm::exchange() { int i,m,nsend,nrecv,nrecv1,nrecv2,nlocal; double lo,hi,value; double **x; double *sublo,*subhi,*buf; MPI_Request request; MPI_Status status; AtomVec *avec = atom->avec; // clear global->local map for owned and ghost atoms // b/c atoms migrate to new procs in exchange() and // new ghosts are created in borders() // map_set() is done at end of borders() // clear ghost count and any ghost bonus data internal to AtomVec if (map_style) atom->map_clear(); atom->nghost = 0; atom->avec->clear_bonus(); // subbox bounds for orthogonal or triclinic if (triclinic == 0) { sublo = domain->sublo; subhi = domain->subhi; } else { sublo = domain->sublo_lamda; subhi = domain->subhi_lamda; } // loop over dimensions for (int dim = 0; dim < 3; dim++) { // fill buffer with atoms leaving my box, using < and >= // when atom is deleted, fill it in with last atom x = atom->x; lo = sublo[dim]; hi = subhi[dim]; nlocal = atom->nlocal; i = nsend = 0; while (i < nlocal) { if (x[i][dim] < lo || x[i][dim] >= hi) { if (nsend > maxsend) grow_send(nsend,1); nsend += avec->pack_exchange(i,&buf_send[nsend]); avec->copy(nlocal-1,i,1); nlocal--; } else i++; } atom->nlocal = nlocal; // send/recv atoms in both directions // if 1 proc in dimension, no send/recv, set recv buf to send buf // if 2 procs in dimension, single send/recv // if more than 2 procs in dimension, send/recv to both neighbors if (procgrid[dim] == 1) { nrecv = nsend; buf = buf_send; } else { MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][0],0, &nrecv1,1,MPI_INT,procneigh[dim][1],0,world,&status); nrecv = nrecv1; if (procgrid[dim] > 2) { MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][1],0, &nrecv2,1,MPI_INT,procneigh[dim][0],0,world,&status); nrecv += nrecv2; } if (nrecv > maxrecv) grow_recv(nrecv); MPI_Irecv(buf_recv,nrecv1,MPI_DOUBLE,procneigh[dim][1],0, world,&request); MPI_Send(buf_send,nsend,MPI_DOUBLE,procneigh[dim][0],0,world); MPI_Wait(&request,&status); if (procgrid[dim] > 2) { MPI_Irecv(&buf_recv[nrecv1],nrecv2,MPI_DOUBLE,procneigh[dim][0],0, world,&request); MPI_Send(buf_send,nsend,MPI_DOUBLE,procneigh[dim][1],0,world); MPI_Wait(&request,&status); } buf = buf_recv; } // check incoming atoms to see if they are in my box // if so, add to my list m = 0; while (m < nrecv) { value = buf[m+dim+1]; if (value >= lo && value < hi) m += avec->unpack_exchange(&buf[m]); else m += static_cast<int> (buf[m]); } } if (atom->firstgroupname) atom->first_reorder(); } /* ---------------------------------------------------------------------- borders: list nearby atoms to send to neighboring procs at every timestep one list is created for every swap that will be made as list is made, actually do swaps this does equivalent of a communicate, so don't need to explicitly call communicate routine on reneighboring timestep this routine is called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before borders is called ------------------------------------------------------------------------- */ void Comm::borders() { int i,n,itype,iswap,dim,ineed,twoneed,smax,rmax; int nsend,nrecv,sendflag,nfirst,nlast,ngroup; double lo,hi; int *type; double **x; double *buf,*mlo,*mhi; MPI_Request request; MPI_Status status; AtomVec *avec = atom->avec; // do swaps over all 3 dimensions iswap = 0; smax = rmax = 0; for (dim = 0; dim < 3; dim++) { nlast = 0; twoneed = 2*maxneed[dim]; for (ineed = 0; ineed < twoneed; ineed++) { // find atoms within slab boundaries lo/hi using <= and >= // check atoms between nfirst and nlast // for first swaps in a dim, check owned and ghost // for later swaps in a dim, only check newly arrived ghosts // store sent atom indices in list for use in future timesteps x = atom->x; if (style == SINGLE) { lo = slablo[iswap]; hi = slabhi[iswap]; } else { type = atom->type; mlo = multilo[iswap]; mhi = multihi[iswap]; } if (ineed % 2 == 0) { nfirst = nlast; nlast = atom->nlocal + atom->nghost; } nsend = 0; // sendflag = 0 if I do not send on this swap // sendneed test indicates receiver no longer requires data // e.g. due to non-PBC or non-uniform sub-domains if (ineed/2 >= sendneed[dim][ineed % 2]) sendflag = 0; else sendflag = 1; // find send atoms according to SINGLE vs MULTI // all atoms eligible versus atoms in bordergroup // only need to limit loop to bordergroup for first sends (ineed < 2) // on these sends, break loop in two: owned (in group) and ghost if (sendflag) { if (!bordergroup || ineed >= 2) { if (style == SINGLE) { for (i = nfirst; i < nlast; i++) if (x[i][dim] >= lo && x[i][dim] <= hi) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } } else { for (i = nfirst; i < nlast; i++) { itype = type[i]; if (x[i][dim] >= mlo[itype] && x[i][dim] <= mhi[itype]) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } } } } else { if (style == SINGLE) { ngroup = atom->nfirst; for (i = 0; i < ngroup; i++) if (x[i][dim] >= lo && x[i][dim] <= hi) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } for (i = atom->nlocal; i < nlast; i++) if (x[i][dim] >= lo && x[i][dim] <= hi) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } } else { ngroup = atom->nfirst; for (i = 0; i < ngroup; i++) { itype = type[i]; if (x[i][dim] >= mlo[itype] && x[i][dim] <= mhi[itype]) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } } for (i = atom->nlocal; i < nlast; i++) { itype = type[i]; if (x[i][dim] >= mlo[itype] && x[i][dim] <= mhi[itype]) { if (nsend == maxsendlist[iswap]) grow_list(iswap,nsend); sendlist[iswap][nsend++] = i; } } } } } // pack up list of border atoms if (nsend*size_border > maxsend) grow_send(nsend*size_border,0); if (ghost_velocity) n = avec->pack_border_vel(nsend,sendlist[iswap],buf_send, pbc_flag[iswap],pbc[iswap]); else n = avec->pack_border(nsend,sendlist[iswap],buf_send, pbc_flag[iswap],pbc[iswap]); // swap atoms with other proc // no MPI calls except SendRecv if nsend/nrecv = 0 // put incoming ghosts at end of my atom arrays // if swapping with self, simply copy, no messages if (sendproc[iswap] != me) { MPI_Sendrecv(&nsend,1,MPI_INT,sendproc[iswap],0, &nrecv,1,MPI_INT,recvproc[iswap],0,world,&status); if (nrecv*size_border > maxrecv) grow_recv(nrecv*size_border); if (nrecv) MPI_Irecv(buf_recv,nrecv*size_border,MPI_DOUBLE, recvproc[iswap],0,world,&request); if (n) MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world); if (nrecv) MPI_Wait(&request,&status); buf = buf_recv; } else { nrecv = nsend; buf = buf_send; } // unpack buffer if (ghost_velocity) avec->unpack_border_vel(nrecv,atom->nlocal+atom->nghost,buf); else avec->unpack_border(nrecv,atom->nlocal+atom->nghost,buf); // set all pointers & counters smax = MAX(smax,nsend); rmax = MAX(rmax,nrecv); sendnum[iswap] = nsend; recvnum[iswap] = nrecv; size_forward_recv[iswap] = nrecv*size_forward; size_reverse_send[iswap] = nrecv*size_reverse; size_reverse_recv[iswap] = nsend*size_reverse; firstrecv[iswap] = atom->nlocal + atom->nghost; atom->nghost += nrecv; iswap++; } } // insure send/recv buffers are long enough for all forward & reverse comm int max = MAX(maxforward*smax,maxreverse*rmax); if (max > maxsend) grow_send(max,0); max = MAX(maxforward*rmax,maxreverse*smax); if (max > maxrecv) grow_recv(max); // reset global->local map if (map_style) atom->map_set(); } /* ---------------------------------------------------------------------- forward communication invoked by a Pair ------------------------------------------------------------------------- */ void Comm::forward_comm_pair(Pair *pair) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = 0; iswap < nswap; iswap++) { // pack buffer n = pair->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer pair->unpack_comm(recvnum[iswap],firstrecv[iswap],buf); } } /* ---------------------------------------------------------------------- reverse communication invoked by a Pair ------------------------------------------------------------------------- */ void Comm::reverse_comm_pair(Pair *pair) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = nswap-1; iswap >= 0; iswap--) { // pack buffer n = pair->pack_reverse_comm(recvnum[iswap],firstrecv[iswap],buf_send); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (sendnum[iswap]) MPI_Irecv(buf_recv,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0, world,&request); if (recvnum[iswap]) MPI_Send(buf_send,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0,world); if (sendnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer pair->unpack_reverse_comm(sendnum[iswap],sendlist[iswap],buf); } } /* ---------------------------------------------------------------------- forward communication invoked by a Fix n = constant number of datums per atom ------------------------------------------------------------------------- */ void Comm::forward_comm_fix(Fix *fix) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = 0; iswap < nswap; iswap++) { // pack buffer n = fix->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer fix->unpack_comm(recvnum[iswap],firstrecv[iswap],buf); } } /* ---------------------------------------------------------------------- reverse communication invoked by a Fix n = constant number of datums per atom ------------------------------------------------------------------------- */ void Comm::reverse_comm_fix(Fix *fix) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = nswap-1; iswap >= 0; iswap--) { // pack buffer n = fix->pack_reverse_comm(recvnum[iswap],firstrecv[iswap],buf_send); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (sendnum[iswap]) MPI_Irecv(buf_recv,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0, world,&request); if (recvnum[iswap]) MPI_Send(buf_send,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0,world); if (sendnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer fix->unpack_reverse_comm(sendnum[iswap],sendlist[iswap],buf); } } /* ---------------------------------------------------------------------- forward communication invoked by a Fix n = total datums for all atoms, allows for variable number/atom ------------------------------------------------------------------------- */ void Comm::forward_comm_variable_fix(Fix *fix) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = 0; iswap < nswap; iswap++) { // pack buffer n = fix->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,maxrecv,MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n,MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer fix->unpack_comm(recvnum[iswap],firstrecv[iswap],buf); } } /* ---------------------------------------------------------------------- reverse communication invoked by a Fix n = total datums for all atoms, allows for variable number/atom ------------------------------------------------------------------------- */ void Comm::reverse_comm_variable_fix(Fix *fix) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = nswap-1; iswap >= 0; iswap--) { // pack buffer n = fix->pack_reverse_comm(recvnum[iswap],firstrecv[iswap],buf_send); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (sendnum[iswap]) MPI_Irecv(buf_recv,maxrecv,MPI_DOUBLE,sendproc[iswap],0, world,&request); if (recvnum[iswap]) MPI_Send(buf_send,n,MPI_DOUBLE,recvproc[iswap],0,world); if (sendnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer fix->unpack_reverse_comm(sendnum[iswap],sendlist[iswap],buf); } } /* ---------------------------------------------------------------------- forward communication invoked by a Compute ------------------------------------------------------------------------- */ void Comm::forward_comm_compute(Compute *compute) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = 0; iswap < nswap; iswap++) { // pack buffer n = compute->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer compute->unpack_comm(recvnum[iswap],firstrecv[iswap],buf); } } /* ---------------------------------------------------------------------- reverse communication invoked by a Compute ------------------------------------------------------------------------- */ void Comm::reverse_comm_compute(Compute *compute) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = nswap-1; iswap >= 0; iswap--) { // pack buffer n = compute->pack_reverse_comm(recvnum[iswap],firstrecv[iswap],buf_send); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (sendnum[iswap]) MPI_Irecv(buf_recv,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0, world,&request); if (recvnum[iswap]) MPI_Send(buf_send,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0,world); if (sendnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer compute->unpack_reverse_comm(sendnum[iswap],sendlist[iswap],buf); } } /* ---------------------------------------------------------------------- forward communication invoked by a Dump ------------------------------------------------------------------------- */ void Comm::forward_comm_dump(Dump *dump) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = 0; iswap < nswap; iswap++) { // pack buffer n = dump->pack_comm(sendnum[iswap],sendlist[iswap], buf_send,pbc_flag[iswap],pbc[iswap]); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer dump->unpack_comm(recvnum[iswap],firstrecv[iswap],buf); } } /* ---------------------------------------------------------------------- reverse communication invoked by a Dump ------------------------------------------------------------------------- */ void Comm::reverse_comm_dump(Dump *dump) { int iswap,n; double *buf; MPI_Request request; MPI_Status status; for (iswap = nswap-1; iswap >= 0; iswap--) { // pack buffer n = dump->pack_reverse_comm(recvnum[iswap],firstrecv[iswap],buf_send); // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (sendnum[iswap]) MPI_Irecv(buf_recv,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0, world,&request); if (recvnum[iswap]) MPI_Send(buf_send,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0,world); if (sendnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer dump->unpack_reverse_comm(sendnum[iswap],sendlist[iswap],buf); } } /* ---------------------------------------------------------------------- forward communication of N values in array ------------------------------------------------------------------------- */ void Comm::forward_comm_array(int n, double **array) { int i,j,k,m,iswap,last; double *buf; MPI_Request request; MPI_Status status; // check that buf_send and buf_recv are big enough for (iswap = 0; iswap < nswap; iswap++) { // pack buffer m = 0; for (i = 0; i < sendnum[iswap]; i++) { j = sendlist[iswap][i]; for (k = 0; k < n; k++) buf_send[m++] = array[j][k]; } // exchange with another proc // if self, set recv buffer to send buffer if (sendproc[iswap] != me) { if (recvnum[iswap]) MPI_Irecv(buf_recv,n*recvnum[iswap],MPI_DOUBLE,recvproc[iswap],0, world,&request); if (sendnum[iswap]) MPI_Send(buf_send,n*sendnum[iswap],MPI_DOUBLE,sendproc[iswap],0,world); if (recvnum[iswap]) MPI_Wait(&request,&status); buf = buf_recv; } else buf = buf_send; // unpack buffer m = 0; last = firstrecv[iswap] + recvnum[iswap]; for (i = firstrecv[iswap]; i < last; i++) for (k = 0; k < n; k++) array[i][k] = buf[m++]; } } /* ---------------------------------------------------------------------- communicate inbuf around full ring of processors with messtag nbytes = size of inbuf = n datums * nper bytes callback() is invoked to allow caller to process/update each proc's inbuf - note that callback() is invoked on final iteration for original inbuf + if self=1 (default), then callback() is invoked on final iteration + using original inbuf, which may have been updated for non-NULL outbuf, final updated inbuf is copied to it - outbuf = inbuf is OK + outbuf = inbuf is OK ------------------------------------------------------------------------- */ void Comm::ring(int n, int nper, void *inbuf, int messtag, void (*callback)(int, char *), void *outbuf, int self) { MPI_Request request; MPI_Status status; int nbytes = n*nper; int maxbytes; MPI_Allreduce(&nbytes,&maxbytes,1,MPI_INT,MPI_MAX,world); char *buf,*bufcopy; memory->create(buf,maxbytes,"comm:buf"); memory->create(bufcopy,maxbytes,"comm:bufcopy"); memcpy(buf,inbuf,nbytes); int next = me + 1; int prev = me - 1; if (next == nprocs) next = 0; if (prev < 0) prev = nprocs - 1; for (int loop = 0; loop < nprocs; loop++) { if (me != next) { MPI_Irecv(bufcopy,maxbytes,MPI_CHAR,prev,messtag,world,&request); MPI_Send(buf,nbytes,MPI_CHAR,next,messtag,world); MPI_Wait(&request,&status); MPI_Get_count(&status,MPI_CHAR,&nbytes); memcpy(buf,bufcopy,nbytes); } if (self || loop < nprocs-1) callback(nbytes/nper,buf); } if (outbuf) memcpy(outbuf,buf,nbytes); memory->destroy(buf); memory->destroy(bufcopy); } /* ---------------------------------------------------------------------- realloc the size of the send buffer as needed with BUFFACTOR & BUFEXTRA if flag = 1, realloc if flag = 0, don't need to realloc with copy, just free/malloc ------------------------------------------------------------------------- */ void Comm::grow_send(int n, int flag) { maxsend = static_cast<int> (BUFFACTOR * n); if (flag) memory->grow(buf_send,(maxsend+BUFEXTRA),"comm:buf_send"); else { memory->destroy(buf_send); memory->create(buf_send,maxsend+BUFEXTRA,"comm:buf_send"); } } /* ---------------------------------------------------------------------- free/malloc the size of the recv buffer as needed with BUFFACTOR ------------------------------------------------------------------------- */ void Comm::grow_recv(int n) { maxrecv = static_cast<int> (BUFFACTOR * n); memory->destroy(buf_recv); memory->create(buf_recv,maxrecv,"comm:buf_recv"); } /* ---------------------------------------------------------------------- realloc the size of the iswap sendlist as needed with BUFFACTOR ------------------------------------------------------------------------- */ void Comm::grow_list(int iswap, int n) { maxsendlist[iswap] = static_cast<int> (BUFFACTOR * n); memory->grow(sendlist[iswap],maxsendlist[iswap],"comm:sendlist[iswap]"); } /* ---------------------------------------------------------------------- realloc the buffers needed for swaps ------------------------------------------------------------------------- */ void Comm::grow_swap(int n) { free_swap(); allocate_swap(n); if (style == MULTI) { free_multi(); allocate_multi(n); } sendlist = (int **) memory->srealloc(sendlist,n*sizeof(int *),"comm:sendlist"); memory->grow(maxsendlist,n,"comm:maxsendlist"); for (int i = maxswap; i < n; i++) { maxsendlist[i] = BUFMIN; memory->create(sendlist[i],BUFMIN,"comm:sendlist[i]"); } maxswap = n; } /* ---------------------------------------------------------------------- allocation of swap info ------------------------------------------------------------------------- */ void Comm::allocate_swap(int n) { memory->create(sendnum,n,"comm:sendnum"); memory->create(recvnum,n,"comm:recvnum"); memory->create(sendproc,n,"comm:sendproc"); memory->create(recvproc,n,"comm:recvproc"); memory->create(size_forward_recv,n,"comm:size"); memory->create(size_reverse_send,n,"comm:size"); memory->create(size_reverse_recv,n,"comm:size"); memory->create(slablo,n,"comm:slablo"); memory->create(slabhi,n,"comm:slabhi"); memory->create(firstrecv,n,"comm:firstrecv"); memory->create(pbc_flag,n,"comm:pbc_flag"); memory->create(pbc,n,6,"comm:pbc"); } /* ---------------------------------------------------------------------- allocation of multi-type swap info ------------------------------------------------------------------------- */ void Comm::allocate_multi(int n) { multilo = memory->create(multilo,n,atom->ntypes+1,"comm:multilo"); multihi = memory->create(multihi,n,atom->ntypes+1,"comm:multihi"); } /* ---------------------------------------------------------------------- free memory for swaps ------------------------------------------------------------------------- */ void Comm::free_swap() { memory->destroy(sendnum); memory->destroy(recvnum); memory->destroy(sendproc); memory->destroy(recvproc); memory->destroy(size_forward_recv); memory->destroy(size_reverse_send); memory->destroy(size_reverse_recv); memory->destroy(slablo); memory->destroy(slabhi); memory->destroy(firstrecv); memory->destroy(pbc_flag); memory->destroy(pbc); } /* ---------------------------------------------------------------------- free memory for multi-type swaps ------------------------------------------------------------------------- */ void Comm::free_multi() { memory->destroy(multilo); memory->destroy(multihi); } /* ---------------------------------------------------------------------- set communication style invoked from input script by communicate command ------------------------------------------------------------------------- */ void Comm::set(int narg, char **arg) { if (narg < 1) error->all(FLERR,"Illegal communicate command"); if (strcmp(arg[0],"single") == 0) style = SINGLE; else if (strcmp(arg[0],"multi") == 0) style = MULTI; else error->all(FLERR,"Illegal communicate command"); int iarg = 1; while (iarg < narg) { if (strcmp(arg[iarg],"group") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal communicate command"); bordergroup = group->find(arg[iarg+1]); if (bordergroup < 0) error->all(FLERR,"Invalid group in communicate command"); if (bordergroup && (atom->firstgroupname == NULL || strcmp(arg[iarg+1],atom->firstgroupname) != 0)) error->all(FLERR,"Communicate group != atom_modify first group"); iarg += 2; } else if (strcmp(arg[iarg],"cutoff") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal communicate command"); cutghostuser = atof(arg[iarg+1]); if (cutghostuser < 0.0) error->all(FLERR,"Invalid cutoff in communicate command"); iarg += 2; } else if (strcmp(arg[iarg],"vel") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal communicate command"); if (strcmp(arg[iarg+1],"yes") == 0) ghost_velocity = 1; else if (strcmp(arg[iarg+1],"no") == 0) ghost_velocity = 0; else error->all(FLERR,"Illegal communicate command"); iarg += 2; } else error->all(FLERR,"Illegal communicate command"); } } /* ---------------------------------------------------------------------- set dimensions for 3d grid of processors, and associated flags invoked from input script by processors command ------------------------------------------------------------------------- */ void Comm::set_processors(int narg, char **arg) { if (narg < 3) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[0],"*") == 0) user_procgrid[0] = 0; else user_procgrid[0] = atoi(arg[0]); if (strcmp(arg[1],"*") == 0) user_procgrid[1] = 0; else user_procgrid[1] = atoi(arg[1]); if (strcmp(arg[2],"*") == 0) user_procgrid[2] = 0; else user_procgrid[2] = atoi(arg[2]); if (user_procgrid[0] < 0 || user_procgrid[1] < 0 || user_procgrid[2] < 0) error->all(FLERR,"Illegal processors command"); int p = user_procgrid[0]*user_procgrid[1]*user_procgrid[2]; if (p && p != nprocs) error->all(FLERR,"Specified processors != physical processors"); int iarg = 3; while (iarg < narg) { if (strcmp(arg[iarg],"grid") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[iarg+1],"onelevel") == 0) { gridflag = ONELEVEL; } else if (strcmp(arg[iarg+1],"twolevel") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal processors command"); gridflag = TWOLEVEL; ncores = atoi(arg[iarg+2]); if (strcmp(arg[iarg+3],"*") == 0) user_coregrid[0] = 0; else user_coregrid[0] = atoi(arg[iarg+3]); if (strcmp(arg[iarg+4],"*") == 0) user_coregrid[1] = 0; else user_coregrid[1] = atoi(arg[iarg+4]); if (strcmp(arg[iarg+5],"*") == 0) user_coregrid[2] = 0; else user_coregrid[2] = atoi(arg[iarg+5]); if (ncores <= 0 || user_coregrid[0] < 0 || user_coregrid[1] < 0 || user_coregrid[2] < 0) error->all(FLERR,"Illegal processors command"); iarg += 4; } else if (strcmp(arg[iarg+1],"numa") == 0) { gridflag = NUMA; } else if (strcmp(arg[iarg],"custom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal processors command"); gridflag = CUSTOM; delete [] customfile; int n = strlen(arg[iarg+2]) + 1; customfile = new char[n]; strcpy(customfile,arg[iarg+2]); iarg += 1; } else error->all(FLERR,"Illegal processors command"); iarg += 2; } else if (strcmp(arg[iarg],"map") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); if (strcmp(arg[iarg+1],"cart") == 0) mapflag = CART; else if (strcmp(arg[iarg+1],"cart/reorder") == 0) mapflag = CARTREORDER; else if (strcmp(arg[iarg+1],"xyz") == 0 || strcmp(arg[iarg+1],"xzy") == 0 || strcmp(arg[iarg+1],"yxz") == 0 || strcmp(arg[iarg+1],"yzx") == 0 || strcmp(arg[iarg+1],"zxy") == 0 || strcmp(arg[iarg+1],"zyx") == 0) { mapflag = XYZ; strcpy(xyz,arg[iarg+1]); } else error->all(FLERR,"Illegal processors command"); iarg += 2; } else if (strcmp(arg[iarg],"part") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal processors command"); if (universe->nworlds == 1) error->all(FLERR, "Cannot use processors part command " "without using partitions"); int isend = atoi(arg[iarg+1]); int irecv = atoi(arg[iarg+2]); if (isend < 1 || isend > universe->nworlds || irecv < 1 || irecv > universe->nworlds || isend == irecv) error->all(FLERR,"Invalid partitions in processors part command"); if (isend-1 == universe->iworld) { if (send_to_partition >= 0) error->all(FLERR, "Sending partition in processors part command " "is already a sender"); send_to_partition = irecv-1; } if (irecv-1 == universe->iworld) { if (recv_from_partition >= 0) error->all(FLERR, "Receiving partition in processors part command " "is already a receiver"); recv_from_partition = isend-1; } // only receiver has otherflag dependency if (strcmp(arg[iarg+3],"multiple") == 0) { if (universe->iworld == irecv-1) { otherflag = 1; other_style = MULTIPLE; } } else error->all(FLERR,"Illegal processors command"); iarg += 4; } else if (strcmp(arg[iarg],"file") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal processors command"); delete [] outfile; int n = strlen(arg[iarg+1]) + 1; outfile = new char[n]; strcpy(outfile,arg[iarg+1]); iarg += 2; } else error->all(FLERR,"Illegal processors command"); } // error checks if (gridflag == NUMA && mapflag != CART) error->all(FLERR,"Processors grid numa and map style are incompatible"); if (otherflag && (gridflag == NUMA || gridflag == CUSTOM)) error->all(FLERR, "Processors part option and grid style are incompatible"); } /* ---------------------------------------------------------------------- return # of bytes of allocated memory ------------------------------------------------------------------------- */ bigint Comm::memory_usage() { bigint bytes = 0; bytes += nprocs * sizeof(int); // grid2proc for (int i = 0; i < nswap; i++) bytes += memory->usage(sendlist[i],maxsendlist[i]); bytes += memory->usage(buf_send,maxsend+BUFEXTRA); bytes += memory->usage(buf_recv,maxrecv); return bytes; } diff --git a/src/delete_atoms.cpp b/src/delete_atoms.cpp index dc70d8557..d2fa42192 100644 --- a/src/delete_atoms.cpp +++ b/src/delete_atoms.cpp @@ -1,360 +1,422 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "delete_atoms.h" #include "atom.h" #include "atom_vec.h" #include "comm.h" #include "domain.h" #include "force.h" #include "group.h" #include "region.h" #include "neighbor.h" #include "neigh_list.h" #include "neigh_request.h" #include "random_mars.h" #include "memory.h" #include "error.h" +#include <map> + using namespace LAMMPS_NS; +// allocate space for static class variable + +DeleteAtoms *DeleteAtoms::cptr; + /* ---------------------------------------------------------------------- */ DeleteAtoms::DeleteAtoms(LAMMPS *lmp) : Pointers(lmp) {} /* ---------------------------------------------------------------------- */ void DeleteAtoms::command(int narg, char **arg) { if (domain->box_exist == 0) error->all(FLERR,"Delete_atoms command before simulation box is defined"); if (narg < 1) error->all(FLERR,"Illegal delete_atoms command"); if (atom->tag_enable == 0) error->all(FLERR,"Cannot use delete_atoms unless atoms have IDs"); // store state before delete bigint natoms_previous = atom->natoms; // delete the atoms if (strcmp(arg[0],"group") == 0) delete_group(narg,arg); else if (strcmp(arg[0],"region") == 0) delete_region(narg,arg); else if (strcmp(arg[0],"overlap") == 0) delete_overlap(narg,arg); else if (strcmp(arg[0],"porosity") == 0) delete_porosity(narg,arg); else error->all(FLERR,"Illegal delete_atoms command"); // delete local atoms flagged in dlist // reset nlocal AtomVec *avec = atom->avec; int nlocal = atom->nlocal; int i = 0; while (i < nlocal) { if (dlist[i]) { avec->copy(nlocal-1,i,1); dlist[i] = dlist[nlocal-1]; nlocal--; } else i++; } atom->nlocal = nlocal; memory->destroy(dlist); // if non-molecular system and compress flag set, // reset atom tags to be contiguous // set all atom IDs to 0, call tag_extend() if (atom->molecular == 0 && compress_flag) { int *tag = atom->tag; for (i = 0; i < nlocal; i++) tag[i] = 0; atom->tag_extend(); } // reset atom->natoms // reset atom->map if it exists // set nghost to 0 so old ghosts of deleted atoms won't be mapped bigint nblocal = atom->nlocal; MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); if (atom->map_style) { atom->nghost = 0; atom->map_init(); atom->map_set(); } // print before and after atom count bigint ndelete = natoms_previous - atom->natoms; if (comm->me == 0) { if (screen) fprintf(screen,"Deleted " BIGINT_FORMAT " atoms, new total = " BIGINT_FORMAT "\n", ndelete,atom->natoms); if (logfile) fprintf(logfile,"Deleted " BIGINT_FORMAT " atoms, new total = " BIGINT_FORMAT "\n", ndelete,atom->natoms); } } /* ---------------------------------------------------------------------- delete all atoms in group group will still exist ------------------------------------------------------------------------- */ void DeleteAtoms::delete_group(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal delete_atoms command"); int igroup = group->find(arg[1]); if (igroup == -1) error->all(FLERR,"Could not find delete_atoms group ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; int *mask = atom->mask; int groupbit = group->bitmask[igroup]; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) dlist[i] = 1; } /* ---------------------------------------------------------------------- delete all atoms in region + if mol_flag is set, also delete atoms in molecules with any deletions ------------------------------------------------------------------------- */ void DeleteAtoms::delete_region(int narg, char **arg) { if (narg < 2) error->all(FLERR,"Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID"); options(narg-2,&arg[2]); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; double **x = atom->x; for (int i = 0; i < nlocal; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) dlist[i] = 1; + + if (mol_flag == 0) return; + + // delete entire molecules if any atom in molecule was deleted + // store list of molecule IDs I delete atoms from in list + // pass list from proc to proc via ring communication + + hash = new std::map<int,int>(); + + int *molecule = atom->molecule; + for (int i = 0; i < nlocal; i++) + if (dlist[i] && hash->find(molecule[i]) == hash->end()) + (*hash)[molecule[i]] = 1; + + int n = hash->size(); + int *list; + memory->create(list,n,"delete_atoms:list"); + + n = 0; + std::map<int,int>::iterator pos; + for (pos = hash->begin(); pos != hash->end(); ++pos) list[n++] = pos->first; + + cptr = this; + comm->ring(n,sizeof(int),list,1,molring,NULL); + + delete hash; + memory->destroy(list); +} + +/* ---------------------------------------------------------------------- + callback from comm->ring() + cbuf = list of N molecule IDs, put them in hash + loop over my atoms, if matches moleculed ID in hash, delete that atom +------------------------------------------------------------------------- */ + +void DeleteAtoms::molring(int n, char *cbuf) +{ + int *list = (int *) cbuf; + int *dlist = cptr->dlist; + std::map<int,int> *hash = cptr->hash; + int nlocal = cptr->atom->nlocal; + int *molecule = cptr->atom->molecule; + + hash->clear(); + for (int i = 0; i < n; i++) (*hash)[list[i]] = 1; + + for (int i = 0; i < nlocal; i++) + if (hash->find(molecule[i]) != hash->end()) dlist[i] = 1; } /* ---------------------------------------------------------------------- delete atoms so there are no pairs within cutoff which atoms are deleted depends on ordering of atoms within proc deletions can vary with processor count no guarantee that minimium number of atoms will be deleted ------------------------------------------------------------------------- */ void DeleteAtoms::delete_overlap(int narg, char **arg) { if (narg < 4) error->all(FLERR,"Illegal delete_atoms command"); // read args double cut = atof(arg[1]); double cutsq = cut*cut; int igroup1 = group->find(arg[2]); int igroup2 = group->find(arg[3]); if (igroup1 < 0 || igroup2 < 0) error->all(FLERR,"Could not find delete_atoms group ID"); options(narg-4,&arg[4]); int group1bit = group->bitmask[igroup1]; int group2bit = group->bitmask[igroup2]; if (comm->me == 0 && screen) fprintf(screen,"System init for delete_atoms ...\n"); // request a full neighbor list for use by this command int irequest = neighbor->request((void *) this); neighbor->requests[irequest]->pair = 0; neighbor->requests[irequest]->command = 1; neighbor->requests[irequest]->half = 0; neighbor->requests[irequest]->full = 1; neighbor->requests[irequest]->occasional = 1; // init entire system since comm->borders and neighbor->build is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc lmp->init(); // error check on cutoff // if no pair style, neighbor list will be empty if (force->pair == NULL) error->all(FLERR,"Delete_atoms requires a pair style be defined"); if (cut > neighbor->cutneighmax) error->all(FLERR,"Delete_atoms cutoff > neighbor cutoff"); // setup domain, communication and neighboring // acquire ghosts // build neighbor list based on earlier request if (domain->triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); comm->borders(); if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost); NeighList *list = neighbor->lists[irequest]; neighbor->build_one(irequest); // allocate and initialize deletion list // must be after exchange potentially changes nlocal int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; // double loop over owned atoms and their full neighbor list // at end of loop, there are no more overlaps // only ever delete owned atom I, never J even if owned int *tag = atom->tag; int *mask = atom->mask; double **x = atom->x; double *special_coul = force->special_coul; double *special_lj = force->special_lj; int i,j,ii,jj,inum,jnum; double xtmp,ytmp,ztmp,delx,dely,delz,rsq; int *ilist,*jlist,*numneigh,**firstneigh; double factor_lj,factor_coul; inum = list->inum; ilist = list->ilist; numneigh = list->numneigh; firstneigh = list->firstneigh; for (ii = 0; ii < inum; ii++) { i = ilist[ii]; xtmp = x[i][0]; ytmp = x[i][1]; ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; factor_lj = special_lj[sbmask(j)]; factor_coul = special_coul[sbmask(j)]; j &= NEIGHMASK; // if both weighting factors are 0, skip this pair // could be 0 and still be in neigh list for long-range Coulombics // want consistency with non-charged pairs which wouldn't be in list if (factor_lj == 0.0 && factor_coul == 0.0) continue; // only consider deletion if I,J distance < cutoff delx = xtmp - x[j][0]; dely = ytmp - x[j][1]; delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; if (rsq >= cutsq) continue; // only consider deletion if I,J are in groups 1,2 respectively // true whether J is owned or ghost atom if (!(mask[i] & group1bit)) continue; if (!(mask[j] & group2bit)) continue; // J is owned atom: // delete atom I if atom J has not already been deleted // J is ghost atom: // delete atom I if J,I is not a candidate deletion pair // due to being in groups 1,2 respectively // if they are candidate pair, then either: // another proc owns J and could delete J // J is a ghost of another of my owned atoms, and I could delete J // test on tags of I,J insures that only I or J is deleted if (j < nlocal) { if (dlist[j]) continue; } else if ((mask[i] & group2bit) && (mask[j] & group1bit)) { if (tag[i] > tag[j]) continue; } dlist[i] = 1; break; } } } /* ---------------------------------------------------------------------- create porosity by deleting atoms in a specified region ------------------------------------------------------------------------- */ void DeleteAtoms::delete_porosity(int narg, char **arg) { if (narg < 4) error->all(FLERR,"Illegal delete_atoms command"); int iregion = domain->find_region(arg[1]); if (iregion == -1) error->all(FLERR,"Could not find delete_atoms region ID"); double porosity_fraction = atof(arg[2]); int seed = atoi(arg[3]); options(narg-4,&arg[4]); RanMars *random = new RanMars(lmp,seed + comm->me); // allocate and initialize deletion list int nlocal = atom->nlocal; memory->create(dlist,nlocal,"delete_atoms:dlist"); for (int i = 0; i < nlocal; i++) dlist[i] = 0; double **x = atom->x; for (int i = 0; i < nlocal; i++) if (domain->regions[iregion]->match(x[i][0],x[i][1],x[i][2])) if (random->uniform() <= porosity_fraction) dlist[i] = 1; } /* ---------------------------------------------------------------------- process command options ------------------------------------------------------------------------- */ void DeleteAtoms::options(int narg, char **arg) { compress_flag = 1; + mol_flag = 0; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"compress") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal delete_bonds command"); if (strcmp(arg[iarg+1],"yes") == 0) compress_flag = 1; else if (strcmp(arg[iarg+1],"no") == 0) compress_flag = 0; else error->all(FLERR,"Illegal delete_bonds command"); iarg += 2; + } else if (strcmp(arg[iarg],"mol") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal delete_bonds command"); + if (strcmp(arg[iarg+1],"yes") == 0) mol_flag = 1; + else if (strcmp(arg[iarg+1],"no") == 0) mol_flag = 0; + else error->all(FLERR,"Illegal delete_bonds command"); + iarg += 2; } else error->all(FLERR,"Illegal delete_bonds command"); } } diff --git a/src/delete_atoms.h b/src/delete_atoms.h index aab02f41d..217401c97 100644 --- a/src/delete_atoms.h +++ b/src/delete_atoms.h @@ -1,87 +1,95 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef COMMAND_CLASS CommandStyle(delete_atoms,DeleteAtoms) #else #ifndef LMP_DELETE_ATOMS_H #define LMP_DELETE_ATOMS_H #include "pointers.h" +#include <map> namespace LAMMPS_NS { class DeleteAtoms : protected Pointers { public: DeleteAtoms(class LAMMPS *); void command(int, char **); private: int *dlist; - int compress_flag; + int compress_flag,mol_flag; + std::map<int,int> *hash; void delete_group(int, char **); void delete_region(int, char **); void delete_overlap(int, char **); void delete_porosity(int, char **); void options(int, char **); inline int sbmask(int j) { return j >> SBBITS & 3; } + + // static variable for ring communication callback to access class data + // callback functions for ring communication + + static DeleteAtoms *cptr; + static void molring(int, char *); }; } #endif #endif /* ERROR/WARNING messages: E: Delete_atoms command before simulation box is defined The delete_atoms command cannot be used before a read_data, read_restart, or create_box command. E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Cannot use delete_atoms unless atoms have IDs Your atoms do not have IDs, so the delete_atoms command cannot be used. E: Could not find delete_atoms group ID Group ID used in the delete_atoms command does not exist. E: Could not find delete_atoms region ID Region ID used in the delete_atoms command does not exist. E: Delete_atoms requires a pair style be defined This is because atom deletion within a cutoff uses a pairwise neighbor list. E: Delete_atoms cutoff > neighbor cutoff Cannot delete atoms further away than a processor knows about. */ diff --git a/src/fix_dt_reset.cpp b/src/fix_dt_reset.cpp index 60e9e0b44..79e9441f6 100644 --- a/src/fix_dt_reset.cpp +++ b/src/fix_dt_reset.cpp @@ -1,215 +1,204 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "math.h" #include "stdlib.h" #include "string.h" #include "fix_dt_reset.h" #include "atom.h" #include "update.h" #include "integrate.h" #include "domain.h" #include "lattice.h" #include "force.h" #include "pair.h" #include "modify.h" #include "fix.h" #include "output.h" #include "dump.h" #include "comm.h" #include "error.h" using namespace LAMMPS_NS; using namespace FixConst; #define BIG 1.0e20 /* ---------------------------------------------------------------------- */ FixDtReset::FixDtReset(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 7) error->all(FLERR,"Illegal fix dt/reset command"); // set time_depend, else elapsed time accumulation can be messed up time_depend = 1; scalar_flag = 1; vector_flag = 1; - size_vector = 2; + size_vector = 1; global_freq = 1; extscalar = 0; extvector = 0; nevery = atoi(arg[3]); if (nevery <= 0) error->all(FLERR,"Illegal fix dt/reset command"); minbound = maxbound = 1; tmin = tmax = 0.0; if (strcmp(arg[4],"NULL") == 0) minbound = 0; else tmin = atof(arg[4]); if (strcmp(arg[5],"NULL") == 0) maxbound = 0; else tmax = atof(arg[5]); xmax = atof(arg[6]); if (minbound && tmin < 0.0) error->all(FLERR,"Illegal fix dt/reset command"); if (maxbound && tmax < 0.0) error->all(FLERR,"Illegal fix dt/reset command"); if (minbound && maxbound && tmin >= tmax) error->all(FLERR,"Illegal fix dt/reset command"); if (xmax <= 0.0) error->all(FLERR,"Illegal fix dt/reset command"); int scaleflag = 1; int iarg = 7; while (iarg < narg) { if (strcmp(arg[iarg],"units") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal fix dt/reset command"); if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0; else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1; else error->all(FLERR,"Illegal fix dt/reset command"); iarg += 2; } else error->all(FLERR,"Illegal fix dt/reset command"); } // setup scaling, based on xlattice parameter if (scaleflag && domain->lattice == NULL) error->all(FLERR,"Use of fix dt/reset with undefined lattice"); if (scaleflag) xmax *= domain->lattice->xlattice; // initializations - t_elapsed = t_laststep = 0.0; + t_laststep = 0.0; laststep = update->ntimestep; } /* ---------------------------------------------------------------------- */ int FixDtReset::setmask() { int mask = 0; - mask |= INITIAL_INTEGRATE; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ void FixDtReset::init() { // set rRESPA flag respaflag = 0; if (strstr(update->integrate_style,"respa")) respaflag = 1; // check for DCD or XTC dumps for (int i = 0; i < output->ndump; i++) if ((strcmp(output->dump[i]->style,"dcd") == 0 || strcmp(output->dump[i]->style,"xtc") == 0) && comm->me == 0) error->warning(FLERR, "Dump dcd/xtc timestamp may be wrong with fix dt/reset"); ftm2v = force->ftm2v; dt = update->dt; } /* ---------------------------------------------------------------------- */ void FixDtReset::setup(int vflag) { end_of_step(); } /* ---------------------------------------------------------------------- */ -void FixDtReset::initial_integrate(int vflag) -{ - // calculate elapsed time based on previous reset timestep - - t_elapsed = t_laststep + (update->ntimestep-laststep)*dt; -} - -/* ---------------------------------------------------------------------- */ - void FixDtReset::end_of_step() { double dtv,dtf,dtsq; double vsq,fsq,massinv; double delx,dely,delz,delr; // compute vmax and amax of any atom in group double **v = atom->v; double **f = atom->f; double *mass = atom->mass; double *rmass = atom->rmass; int *type = atom->type; int *mask = atom->mask; int nlocal = atom->nlocal; double dtmin = BIG; for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { if (rmass) massinv = 1.0/rmass[i]; else massinv = 1.0/mass[type[i]]; vsq = v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]; fsq = f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2]; dtv = dtf = BIG; if (vsq > 0.0) dtv = xmax/sqrt(vsq); if (fsq > 0.0) dtf = sqrt(2.0*xmax/(ftm2v*sqrt(fsq)*massinv)); dt = MIN(dtv,dtf); dtsq = dt*dt; delx = dt*v[i][0] + 0.5*dtsq*massinv*f[i][0] * ftm2v; dely = dt*v[i][1] + 0.5*dtsq*massinv*f[i][1] * ftm2v; delz = dt*v[i][2] + 0.5*dtsq*massinv*f[i][2] * ftm2v; delr = sqrt(delx*delx + dely*dely + delz*delz); if (delr > xmax) dt *= xmax/delr; dtmin = MIN(dtmin,dt); } MPI_Allreduce(&dtmin,&dt,1,MPI_DOUBLE,MPI_MIN,world); if (minbound) dt = MAX(dt,tmin); if (maxbound) dt = MIN(dt,tmax); // if timestep didn't change, just return // else reset update->dt and other classes that depend on it // rRESPA, pair style, fixes if (dt == update->dt) return; - t_elapsed = t_laststep += (update->ntimestep-laststep)*update->dt; laststep = update->ntimestep; + update->update_time(); update->dt = dt; if (respaflag) update->integrate->reset_dt(); if (force->pair) force->pair->reset_dt(); for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt(); } /* ---------------------------------------------------------------------- */ double FixDtReset::compute_scalar() { return update->dt; } /* ---------------------------------------------------------------------- */ double FixDtReset::compute_vector(int n) { - if (n == 0) return t_elapsed; return (double) laststep; } diff --git a/src/fix_dt_reset.h b/src/fix_dt_reset.h index de97d147d..7084b5993 100644 --- a/src/fix_dt_reset.h +++ b/src/fix_dt_reset.h @@ -1,71 +1,70 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifdef FIX_CLASS FixStyle(dt/reset,FixDtReset) #else #ifndef LMP_FIX_DT_RESET_H #define LMP_FIX_DT_RESET_H #include "fix.h" namespace LAMMPS_NS { class FixDtReset : public Fix { public: FixDtReset(class LAMMPS *, int, char **); ~FixDtReset() {} int setmask(); void init(); void setup(int); - void initial_integrate(int); void end_of_step(); double compute_scalar(); double compute_vector(int); private: bigint laststep; int minbound,maxbound; double tmin,tmax,xmax; double ftm2v; - double dt,t_elapsed,t_laststep; + double dt,t_laststep; int respaflag; }; } #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: Use of fix dt/reset with undefined lattice Must use lattice command with fix dt/reset command if units option is set to lattice. W: Dump dcd/xtc timestamp may be wrong with fix dt/reset If the fix changes the timestep, the dump dcd file will not reflect the change. */ diff --git a/src/respa.cpp b/src/respa.cpp index 469b3d698..8e9288e35 100644 --- a/src/respa.cpp +++ b/src/respa.cpp @@ -1,720 +1,721 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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: Mark Stevens (SNL), Paul Crozier (SNL) ------------------------------------------------------------------------- */ #include "stdlib.h" #include "string.h" #include "respa.h" #include "neighbor.h" #include "atom.h" #include "domain.h" #include "comm.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "output.h" #include "update.h" #include "modify.h" #include "compute.h" #include "fix_respa.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Respa::Respa(LAMMPS *lmp, int narg, char **arg) : Integrate(lmp, narg, arg) { if (narg < 1) error->all(FLERR,"Illegal run_style respa command"); nlevels = atoi(arg[0]); if (nlevels < 1) error->all(FLERR,"Respa levels must be >= 1"); if (narg < nlevels) error->all(FLERR,"Illegal run_style respa command"); loop = new int[nlevels]; for (int iarg = 1; iarg < nlevels; iarg++) { loop[iarg-1] = atoi(arg[iarg]); if (loop[iarg-1] <= 0) error->all(FLERR,"Illegal run_style respa command"); } loop[nlevels-1] = 1; // set level at which each force is computed // argument settings override defaults level_bond = level_angle = level_dihedral = level_improper = -1; level_pair = level_kspace = -1; level_inner = level_middle = level_outer = -1; int iarg = nlevels; while (iarg < narg) { if (strcmp(arg[iarg],"bond") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_bond = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_angle = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"dihedral") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_dihedral = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"improper") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_improper = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"pair") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_pair = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"inner") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal run_style respa command"); level_inner = atoi(arg[iarg+1]) - 1; cutoff[0] = atof(arg[iarg+2]); cutoff[1] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"middle") == 0) { if (iarg+4 > narg) error->all(FLERR,"Illegal run_style respa command"); level_middle = atoi(arg[iarg+1]) - 1; cutoff[2] = atof(arg[iarg+2]); cutoff[3] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"outer") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_outer = atoi(arg[iarg+1]) - 1; iarg += 2; } else if (strcmp(arg[iarg],"kspace") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal run_style respa command"); level_kspace = atoi(arg[iarg+1]) - 1; iarg += 2; } else error->all(FLERR,"Illegal run_style respa command"); } // cannot specify both pair and inner/middle/outer if (level_pair >= 0 && (level_inner >= 0 || level_middle >= 0 || level_outer >= 0)) error->all(FLERR,"Cannot set both respa pair and inner/middle/outer"); // if either inner and outer is specified, then both must be if ((level_inner >= 0 && level_outer == -1) || (level_outer >= 0 && level_inner == -1)) error->all(FLERR,"Must set both respa inner and outer"); // middle cannot be set without inner/outer if (level_middle >= 0 && level_inner == -1) error->all(FLERR,"Cannot set respa middle without inner/outer"); // set defaults if user did not specify level // bond to innermost level // angle same as bond, dihedral same as angle, improper same as dihedral // pair to outermost level if no inner/middle/outer // inner/middle/outer have no defaults // kspace same as pair or outer if (level_bond == -1) level_bond = 0; if (level_angle == -1) level_angle = level_bond; if (level_dihedral == -1) level_dihedral = level_angle; if (level_improper == -1) level_improper = level_dihedral; if (level_pair == -1 && level_inner == -1) level_pair = nlevels-1; if (level_kspace == -1 && level_pair >= 0) level_kspace = level_pair; if (level_kspace == -1 && level_pair == -1) level_kspace = level_outer; // print respa levels if (comm->me == 0) { if (screen) { fprintf(screen,"Respa levels:\n"); for (int i = 0; i < nlevels; i++) { fprintf(screen," %d =",i+1); if (level_bond == i) fprintf(screen," bond"); if (level_angle == i) fprintf(screen," angle"); if (level_dihedral == i) fprintf(screen," dihedral"); if (level_improper == i) fprintf(screen," improper"); if (level_pair == i) fprintf(screen," pair"); if (level_inner == i) fprintf(screen," pair-inner"); if (level_middle == i) fprintf(screen," pair-middle"); if (level_outer == i) fprintf(screen," pair-outer"); if (level_kspace == i) fprintf(screen," kspace"); fprintf(screen,"\n"); } } if (logfile) { fprintf(logfile,"Respa levels:\n"); for (int i = 0; i < nlevels; i++) { fprintf(logfile," %d =",i+1); if (level_bond == i) fprintf(logfile," bond"); if (level_angle == i) fprintf(logfile," angle"); if (level_dihedral == i) fprintf(logfile," dihedral"); if (level_improper == i) fprintf(logfile," improper"); if (level_pair == i) fprintf(logfile," pair"); if (level_inner == i) fprintf(logfile," pair-inner"); if (level_middle == i) fprintf(logfile," pair-middle"); if (level_outer == i) fprintf(logfile," pair-outer"); if (level_kspace == i) fprintf(logfile," kspace"); fprintf(logfile,"\n"); } } } // check that levels are in correct order if (level_angle < level_bond || level_dihedral < level_angle || level_improper < level_dihedral) error->all(FLERR,"Invalid order of forces within respa levels"); if (level_pair >= 0) { if (level_pair < level_improper || level_kspace < level_pair) error->all(FLERR,"Invalid order of forces within respa levels"); } if (level_pair == -1 && level_middle == -1) { if (level_inner < level_improper || level_outer < level_inner || level_kspace < level_outer) error->all(FLERR,"Invalid order of forces within respa levels"); } if (level_pair == -1 && level_middle >= 0) { if (level_inner < level_improper || level_middle < level_inner || level_outer < level_inner || level_kspace < level_outer) error->all(FLERR,"Invalid order of forces within respa levels"); } // warn if any levels are devoid of forces int flag = 0; for (int i = 0; i < nlevels; i++) if (level_bond != i && level_angle != i && level_dihedral != i && level_improper != i && level_pair != i && level_inner != i && level_middle != i && level_outer != i && level_kspace != i) flag = 1; if (flag && comm->me == 0) error->warning(FLERR,"One or more respa levels compute no forces"); // check cutoff consistency if inner/middle/outer are enabled if (level_inner >= 0 && cutoff[1] < cutoff[0]) error->all(FLERR,"Respa inner cutoffs are invalid"); if (level_middle >= 0 && (cutoff[3] < cutoff[2] || cutoff[2] < cutoff[1])) error->all(FLERR,"Respa middle cutoffs are invalid"); // set outer pair of cutoffs to inner pair if middle is not enabled if (level_inner >= 0 && level_middle < 0) { cutoff[2] = cutoff[0]; cutoff[3] = cutoff[1]; } // allocate other needed arrays newton = new int[nlevels]; step = new double[nlevels]; } /* ---------------------------------------------------------------------- */ Respa::~Respa() { delete [] loop; delete [] newton; delete [] step; } /* ---------------------------------------------------------------------- initialization before run ------------------------------------------------------------------------- */ void Respa::init() { Integrate::init(); // warn if no fixes if (modify->nfix == 0 && comm->me == 0) error->warning(FLERR,"No fixes defined, atoms won't move"); // warn about incorrect pressures when using rRESPA with fix SHAKE int shakeflag = 0; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"shake") == 0) shakeflag = 1; if (shakeflag && comm->me == 0) error->warning(FLERR,"Fix shake with rRESPA computes invalid pressures"); // create fix needed for storing atom-based respa level forces // will delete it at end of run char **fixarg = new char*[4]; fixarg[0] = (char *) "RESPA"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "RESPA"; fixarg[3] = new char[8]; sprintf(fixarg[3],"%d",nlevels); modify->add_fix(4,fixarg); delete [] fixarg[3]; delete [] fixarg; fix_respa = (FixRespa *) modify->fix[modify->nfix-1]; // insure respa inner/middle/outer is using Pair class that supports it if (level_inner >= 0) if (force->pair && force->pair->respa_enable == 0) error->all(FLERR,"Pair style does not support rRESPA inner/middle/outer"); // virial_style = 1 (explicit) since never computed implicitly like Verlet virial_style = 1; // setup lists of computes for global and per-atom PE and pressure ev_setup(); // detect if fix omp is present and will clear force arrays for us int ifix = modify->find_fix("package_omp"); if (ifix >= 0) external_force_clear = 1; // set flags for what arrays to clear in force_clear() // need to clear additionals arrays if they exist torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 1; e_flag = 0; if (atom->e_flag) e_flag = 1; rho_flag = 0; if (atom->rho_flag) rho_flag = 1; // step[] = timestep for each level step[nlevels-1] = update->dt; for (int ilevel = nlevels-2; ilevel >= 0; ilevel--) step[ilevel] = step[ilevel+1]/loop[ilevel]; // set newton flag for each level for (int ilevel = 0; ilevel < nlevels; ilevel++) { newton[ilevel] = 0; if (force->newton_bond) { if (level_bond == ilevel || level_angle == ilevel || level_dihedral == ilevel || level_improper == ilevel) newton[ilevel] = 1; } if (force->newton_pair) { if (level_pair == ilevel || level_inner == ilevel || level_middle == ilevel || level_outer == ilevel) newton[ilevel] = 1; } } // orthogonal vs triclinic simulation box triclinic = domain->triclinic; } /* ---------------------------------------------------------------------- setup before run ------------------------------------------------------------------------- */ void Respa::setup() { if (comm->me == 0 && screen) fprintf(screen,"Setting up run ...\n"); update->setupflag = 1; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists atom->setup(); modify->setup_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); if (atom->sortfreq > 0) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); domain->image_check(); domain->box_too_small_check(); modify->setup_pre_neighbor(); neighbor->build(); neighbor->ncalls = 0; // compute all forces ev_set(update->ntimestep); for (int ilevel = 0; ilevel < nlevels; ilevel++) { force_clear(newton[ilevel]); modify->setup_pre_force_respa(vflag,ilevel); if (level_pair == ilevel && pair_compute_flag) force->pair->compute(eflag,vflag); if (level_inner == ilevel && pair_compute_flag) force->pair->compute_inner(); if (level_middle == ilevel && pair_compute_flag) force->pair->compute_middle(); if (level_outer == ilevel && pair_compute_flag) force->pair->compute_outer(eflag,vflag); if (level_bond == ilevel && force->bond) force->bond->compute(eflag,vflag); if (level_angle == ilevel && force->angle) force->angle->compute(eflag,vflag); if (level_dihedral == ilevel && force->dihedral) force->dihedral->compute(eflag,vflag); if (level_improper == ilevel && force->improper) force->improper->compute(eflag,vflag); if (level_kspace == ilevel && force->kspace) { force->kspace->setup(); if (kspace_compute_flag) force->kspace->compute(eflag,vflag); } if (newton[ilevel]) comm->reverse_comm(); copy_f_flevel(ilevel); } modify->setup(vflag); sum_flevel_f(); output->setup(); update->setupflag = 0; } /* ---------------------------------------------------------------------- setup without output flag = 0 = just force calculation flag = 1 = reneighbor and force calculation ------------------------------------------------------------------------- */ void Respa::setup_minimal(int flag) { update->setupflag = 1; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists if (flag) { modify->setup_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); domain->image_check(); domain->box_too_small_check(); modify->setup_pre_neighbor(); neighbor->build(); neighbor->ncalls = 0; } // compute all forces ev_set(update->ntimestep); for (int ilevel = 0; ilevel < nlevels; ilevel++) { force_clear(newton[ilevel]); modify->setup_pre_force_respa(vflag,ilevel); if (level_pair == ilevel && pair_compute_flag) force->pair->compute(eflag,vflag); if (level_inner == ilevel && pair_compute_flag) force->pair->compute_inner(); if (level_middle == ilevel && pair_compute_flag) force->pair->compute_middle(); if (level_outer == ilevel && pair_compute_flag) force->pair->compute_outer(eflag,vflag); if (level_bond == ilevel && force->bond) force->bond->compute(eflag,vflag); if (level_angle == ilevel && force->angle) force->angle->compute(eflag,vflag); if (level_dihedral == ilevel && force->dihedral) force->dihedral->compute(eflag,vflag); if (level_improper == ilevel && force->improper) force->improper->compute(eflag,vflag); if (level_kspace == ilevel && force->kspace) { force->kspace->setup(); if (kspace_compute_flag) force->kspace->compute(eflag,vflag); } if (newton[ilevel]) comm->reverse_comm(); copy_f_flevel(ilevel); } modify->setup(vflag); sum_flevel_f(); update->setupflag = 0; } /* ---------------------------------------------------------------------- run for N steps ------------------------------------------------------------------------- */ void Respa::run(int n) { bigint ntimestep; for (int i = 0; i < n; i++) { ntimestep = ++update->ntimestep; ev_set(ntimestep); recurse(nlevels-1); if (modify->n_end_of_step) { timer->stamp(); modify->end_of_step(); timer->stamp(Timer::MODIFY); } if (ntimestep == output->next) { timer->stamp(); sum_flevel_f(); output->write(update->ntimestep); timer->stamp(Timer::OUTPUT); } } } /* ---------------------------------------------------------------------- delete rRESPA fix at end of run, so its atom arrays won't persist ------------------------------------------------------------------------- */ void Respa::cleanup() { modify->post_run(); modify->delete_fix("RESPA"); domain->box_too_small_check(); + update->update_time(); } /* ---------------------------------------------------------------------- */ void Respa::reset_dt() { step[nlevels-1] = update->dt; for (int ilevel = nlevels-2; ilevel >= 0; ilevel--) step[ilevel] = step[ilevel+1]/loop[ilevel]; } /* ---------------------------------------------------------------------- */ void Respa::recurse(int ilevel) { copy_flevel_f(ilevel); for (int iloop = 0; iloop < loop[ilevel]; iloop++) { timer->stamp(); modify->initial_integrate_respa(vflag,ilevel,iloop); if (modify->n_post_integrate_respa) modify->post_integrate_respa(ilevel,iloop); timer->stamp(Timer::MODIFY); if (ilevel) recurse(ilevel-1); // at outermost level, check on rebuilding neighbor list // at innermost level, communicate // at middle levels, do nothing if (ilevel == nlevels-1) { int nflag = neighbor->decide(); if (nflag) { if (modify->n_pre_exchange) { timer->stamp(); modify->pre_exchange(); timer->stamp(Timer::MODIFY); } if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (atom->sortfreq > 0 && update->ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(Timer::COMM); if (modify->n_pre_neighbor) { modify->pre_neighbor(); timer->stamp(Timer::MODIFY); } neighbor->build(); timer->stamp(Timer::NEIGHBOR); } else if (ilevel == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(Timer::COMM); } } else if (ilevel == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(Timer::COMM); } // force computations // important that ordering is same as Verlet // so that any order dependencies are the same // when potentials are invoked at same level force_clear(newton[ilevel]); if (modify->n_pre_force_respa) { timer->stamp(); modify->pre_force_respa(vflag,ilevel,iloop); timer->stamp(Timer::MODIFY); } timer->stamp(); if (level_pair == ilevel && pair_compute_flag) { force->pair->compute(eflag,vflag); timer->stamp(Timer::PAIR); } if (level_inner == ilevel && pair_compute_flag) { force->pair->compute_inner(); timer->stamp(Timer::PAIR); } if (level_middle == ilevel && pair_compute_flag) { force->pair->compute_middle(); timer->stamp(Timer::PAIR); } if (level_outer == ilevel && pair_compute_flag) { force->pair->compute_outer(eflag,vflag); timer->stamp(Timer::PAIR); } if (level_bond == ilevel && force->bond) { force->bond->compute(eflag,vflag); timer->stamp(Timer::BOND); } if (level_angle == ilevel && force->angle) { force->angle->compute(eflag,vflag); timer->stamp(Timer::BOND); } if (level_dihedral == ilevel && force->dihedral) { force->dihedral->compute(eflag,vflag); timer->stamp(Timer::BOND); } if (level_improper == ilevel && force->improper) { force->improper->compute(eflag,vflag); timer->stamp(Timer::BOND); } if (level_kspace == ilevel && kspace_compute_flag) { force->kspace->compute(eflag,vflag); timer->stamp(Timer::KSPACE); } if (newton[ilevel]) { comm->reverse_comm(); timer->stamp(Timer::COMM); } timer->stamp(); if (modify->n_post_force_respa) modify->post_force_respa(vflag,ilevel,iloop); modify->final_integrate_respa(ilevel,iloop); timer->stamp(Timer::MODIFY); } copy_f_flevel(ilevel); } /* ---------------------------------------------------------------------- clear force on own & ghost atoms ------------------------------------------------------------------------- */ void Respa::force_clear(int newtonflag) { if (external_force_clear) return; // clear global force array // nall includes ghosts only if newton flag is set int nall; if (newtonflag) nall = atom->nlocal + atom->nghost; else nall = atom->nlocal; size_t nbytes = sizeof(double) * nall; if (nbytes > 0 ) { memset(&(atom->f[0][0]),0,3*nbytes); if (torqueflag) memset(&(atom->torque[0][0]),0,3*nbytes); if (erforceflag) memset(&(atom->erforce[0]), 0, nbytes); if (e_flag) memset(&(atom->de[0]), 0, nbytes); if (rho_flag) memset(&(atom->drho[0]), 0, nbytes); } } /* ---------------------------------------------------------------------- copy force components from atom->f to FixRespa->f_level ------------------------------------------------------------------------- */ void Respa::copy_f_flevel(int ilevel) { double ***f_level = fix_respa->f_level; double **f = atom->f; int n = atom->nlocal; for (int i = 0; i < n; i++) { f_level[i][ilevel][0] = f[i][0]; f_level[i][ilevel][1] = f[i][1]; f_level[i][ilevel][2] = f[i][2]; } } /* ---------------------------------------------------------------------- copy force components from FixRespa->f_level to atom->f ------------------------------------------------------------------------- */ void Respa::copy_flevel_f(int ilevel) { double ***f_level = fix_respa->f_level; double **f = atom->f; int n = atom->nlocal; for (int i = 0; i < n; i++) { f[i][0] = f_level[i][ilevel][0]; f[i][1] = f_level[i][ilevel][1]; f[i][2] = f_level[i][ilevel][2]; } } /* ---------------------------------------------------------------------- sum all force components from FixRespa->f_level to create full atom->f ------------------------------------------------------------------------- */ void Respa::sum_flevel_f() { copy_flevel_f(0); double ***f_level = fix_respa->f_level; double **f = atom->f; int n = atom->nlocal; for (int ilevel = 1; ilevel < nlevels; ilevel++) { for (int i = 0; i < n; i++) { f[i][0] += f_level[i][ilevel][0]; f[i][1] += f_level[i][ilevel][1]; f[i][2] += f_level[i][ilevel][2]; } } } diff --git a/src/thermo.cpp b/src/thermo.cpp index 1b9ce64ba..634fc420f 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -1,1959 +1,1971 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "lmptype.h" #include "mpi.h" #include "math.h" #include "stdlib.h" #include "string.h" #include "thermo.h" #include "atom.h" #include "update.h" #include "comm.h" #include "domain.h" #include "lattice.h" #include "modify.h" #include "fix.h" #include "compute.h" #include "input.h" #include "variable.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "output.h" #include "timer.h" #include "math_const.h" #include "memory.h" #include "error.h" #include "math_const.h" using namespace LAMMPS_NS; using namespace MathConst; // customize a new keyword by adding to this list: -// step, elapsed, elaplong, dt, cpu, tpcpu, spcpu +// step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu // atoms, temp, press, pe, ke, etotal, enthalpy // evdwl, ecoul, epair, ebond, eangle, edihed, eimp, emol, elong, etail // vol, lx, ly, lz, xlo, xhi, ylo, yhi, zlo, zhi, xy, xz, yz, xlat, ylat, zlat // pxx, pyy, pzz, pxy, pxz, pyz // fmax, fnorm // cella, cellb, cellc, cellalpha, cellbeta, cellgamma // customize a new thermo style by adding a DEFINE to this list // also insure allocation of line string is correct in constructor #define ONE "step temp epair emol etotal press" #define MULTI "etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press" enum{IGNORE,WARN,ERROR}; // same as write_restart.cpp enum{ONELINE,MULTILINE}; enum{INT,FLOAT,BIGINT}; enum{SCALAR,VECTOR,ARRAY}; #define INVOKED_SCALAR 1 #define INVOKED_VECTOR 2 #define INVOKED_ARRAY 4 #define DELTA 8 /* ---------------------------------------------------------------------- */ Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) { MPI_Comm_rank(world,&me); int n = strlen(arg[0]) + 1; style = new char[n]; strcpy(style,arg[0]); // set thermo_modify defaults modified = 0; normuserflag = 0; lineflag = ONELINE; lostflag = ERROR; lostbefore = 0; flushflag = 0; // set style and corresponding lineflag // custom style builds its own line of keywords // customize a new thermo style by adding to if statement // allocate line string used for 3 tasks // concat of custom style args // one-time thermo output of header line // each line of numeric thermo output // 256 = extra for ONE or MULTI string or multi formatting // 64 = max per-arg chars in header or numeric output if (strcmp(style,"one") == 0) { line = new char[256+6*64]; strcpy(line,ONE); } else if (strcmp(style,"multi") == 0) { line = new char[256+12*64]; strcpy(line,MULTI); lineflag = MULTILINE; } else if (strcmp(style,"custom") == 0) { if (narg == 1) error->all(FLERR,"Illegal thermo style custom command"); line = new char[256+narg*64]; line[0] = '\0'; for (int iarg = 1; iarg < narg; iarg++) { strcat(line,arg[iarg]); strcat(line," "); } line[strlen(line)-1] = '\0'; } else error->all(FLERR,"Illegal thermo style command"); // ptrs, flags, IDs for compute objects thermo may use or create temperature = NULL; pressure = NULL; pe = NULL; index_temp = index_press_scalar = index_press_vector = index_pe = -1; id_temp = (char *) "thermo_temp"; id_press = (char *) "thermo_press"; id_pe = (char *) "thermo_pe"; // count fields in line // allocate per-field memory // process line of keywords nfield_initial = atom->count_words(line); allocate(); parse_fields(line); // format strings char *bigint_format = (char *) BIGINT_FORMAT; char *fformat_multi = (char *) "---------------- Step %%8%s ----- " "CPU = %%11.4f (sec) ----------------"; sprintf(format_multi,fformat_multi,&bigint_format[1]); format_float_one_def = (char *) "%12.8g"; format_float_multi_def = (char *) "%14.4f"; format_int_one_def = (char *) "%8d"; format_int_multi_def = (char *) "%14d"; sprintf(format_bigint_one_def,"%%8%s",&bigint_format[1]); sprintf(format_bigint_multi_def,"%%14%s",&bigint_format[1]); format_float_user = NULL; format_int_user = NULL; format_bigint_user = NULL; } /* ---------------------------------------------------------------------- */ Thermo::~Thermo() { delete [] style; delete [] line; deallocate(); // format strings delete [] format_float_user; delete [] format_int_user; delete [] format_bigint_user; } /* ---------------------------------------------------------------------- */ void Thermo::init() { int i,n; // set normvalue to default setting unless user has specified it if (normuserflag) normvalue = normuser; else if (strcmp(update->unit_style,"lj") == 0) normvalue = 1; else normvalue = 0; // add Volume field if volume changes and not style = custom // this check must come after domain init, so box_change is set nfield = nfield_initial; if (domain->box_change && strcmp(style,"custom") != 0) addfield("Volume",&Thermo::compute_vol,FLOAT); // set format string for each field // include keyword if lineflag = MULTILINE // add '/n' every 3 values if lineflag = MULTILINE // add trailing '/n' to last value char *ptr; for (i = 0; i < nfield; i++) { format[i][0] = '\0'; if (lineflag == MULTILINE && i % 3 == 0) strcat(format[i],"\n"); if (format_user[i]) ptr = format_user[i]; else if (vtype[i] == FLOAT) { if (format_float_user) ptr = format_float_user; else if (lineflag == ONELINE) ptr = format_float_one_def; else if (lineflag == MULTILINE) ptr = format_float_multi_def; } else if (vtype[i] == INT) { if (format_int_user) ptr = format_int_user; else if (lineflag == ONELINE) ptr = format_int_one_def; else if (lineflag == MULTILINE) ptr = format_int_multi_def; } else if (vtype[i] == BIGINT) { if (format_bigint_user) ptr = format_bigint_user; else if (lineflag == ONELINE) ptr = format_bigint_one_def; else if (lineflag == MULTILINE) ptr = format_bigint_multi_def; } n = strlen(format[i]); if (lineflag == ONELINE) sprintf(&format[i][n],"%s ",ptr); else sprintf(&format[i][n],"%-8s = %s ",keyword[i],ptr); if (i == nfield-1) strcat(format[i],"\n"); } // find current ptr for each Compute ID // cudable = 0 if any compute used by Thermo is non-CUDA cudable = 1; int icompute; for (i = 0; i < ncompute; i++) { icompute = modify->find_compute(id_compute[i]); if (icompute < 0) error->all(FLERR,"Could not find thermo compute ID"); computes[i] = modify->compute[icompute]; cudable = cudable && computes[i]->cudable; } // find current ptr for each Fix ID // check that fix frequency is acceptable with thermo output frequency int ifix; for (i = 0; i < nfix; i++) { ifix = modify->find_fix(id_fix[i]); if (ifix < 0) error->all(FLERR,"Could not find thermo fix ID"); fixes[i] = modify->fix[ifix]; if (output->thermo_every % fixes[i]->global_freq) error->all(FLERR,"Thermo and fix not computed at compatible times"); } // find current ptr for each Variable ID int ivariable; for (i = 0; i < nvariable; i++) { ivariable = input->variable->find(id_variable[i]); if (ivariable < 0) error->all(FLERR,"Could not find thermo variable name"); variables[i] = ivariable; } // set ptrs to keyword-specific Compute objects if (index_temp >= 0) temperature = computes[index_temp]; if (index_press_scalar >= 0) pressure = computes[index_press_scalar]; if (index_press_vector >= 0) pressure = computes[index_press_vector]; if (index_pe >= 0) pe = computes[index_pe]; } /* ---------------------------------------------------------------------- */ void Thermo::header() { if (lineflag == MULTILINE) return; int loc = 0; for (int i = 0; i < nfield; i++) loc += sprintf(&line[loc],"%s ",keyword[i]); sprintf(&line[loc],"\n"); if (me == 0) { if (screen) fprintf(screen,"%s",line); if (logfile) fprintf(logfile,"%s",line); } } /* ---------------------------------------------------------------------- */ void Thermo::compute(int flag) { int i; firststep = flag; bigint ntimestep = update->ntimestep; // check for lost atoms // turn off normflag if natoms = 0 to avoid divide by 0 natoms = lost_check(); if (natoms == 0) normflag = 0; else normflag = normvalue; // invoke Compute methods needed for thermo keywords for (i = 0; i < ncompute; i++) if (compute_which[i] == SCALAR) { if (!(computes[i]->invoked_flag & INVOKED_SCALAR)) { computes[i]->compute_scalar(); computes[i]->invoked_flag |= INVOKED_SCALAR; } } else if (compute_which[i] == VECTOR) { if (!(computes[i]->invoked_flag & INVOKED_VECTOR)) { computes[i]->compute_vector(); computes[i]->invoked_flag |= INVOKED_VECTOR; } } else if (compute_which[i] == ARRAY) { if (!(computes[i]->invoked_flag & INVOKED_ARRAY)) { computes[i]->compute_array(); computes[i]->invoked_flag |= INVOKED_ARRAY; } } // if lineflag = MULTILINE, prepend step/cpu header line int loc = 0; if (lineflag == MULTILINE) { double cpu; if (flag) cpu = timer->elapsed(Timer::LOOP); else cpu = 0.0; loc = sprintf(&line[loc],format_multi,ntimestep,cpu); } // add each thermo value to line with its specific format for (ifield = 0; ifield < nfield; ifield++) { (this->*vfunc[ifield])(); if (vtype[ifield] == FLOAT) loc += sprintf(&line[loc],format[ifield],dvalue); else if (vtype[ifield] == INT) loc += sprintf(&line[loc],format[ifield],ivalue); else if (vtype[ifield] == BIGINT) { loc += sprintf(&line[loc],format[ifield],bivalue); } } // print line to screen and logfile if (me == 0) { if (screen) fprintf(screen,"%s",line); if (logfile) { fprintf(logfile,"%s",line); if (flushflag) fflush(logfile); } } } /* ---------------------------------------------------------------------- check for lost atoms, return current number of atoms ------------------------------------------------------------------------- */ bigint Thermo::lost_check() { // ntotal = current # of atoms bigint ntotal; bigint nblocal = atom->nlocal; MPI_Allreduce(&nblocal,&ntotal,1,MPI_LMP_BIGINT,MPI_SUM,world); if (ntotal < 0 || ntotal > MAXBIGINT) error->all(FLERR,"Too many total atoms"); if (ntotal == atom->natoms) return ntotal; // if not checking or already warned, just return // reset total atom count if (lostflag == IGNORE) return ntotal; if (lostflag == WARN && lostbefore == 1) { atom->natoms = ntotal; return ntotal; } // error message if (lostflag == ERROR) { char str[64]; sprintf(str, "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT, atom->natoms,ntotal); error->all(FLERR,str); } // warning message char str[64]; sprintf(str, "Lost atoms: original " BIGINT_FORMAT " current " BIGINT_FORMAT, atom->natoms,ntotal); if (me == 0) error->warning(FLERR,str,0); // reset total atom count atom->natoms = ntotal; lostbefore = 1; return ntotal; } /* ---------------------------------------------------------------------- modify thermo parameters ------------------------------------------------------------------------- */ void Thermo::modify_params(int narg, char **arg) { if (narg == 0) error->all(FLERR,"Illegal thermo_modify command"); modified = 1; int iarg = 0; while (iarg < narg) { if (strcmp(arg[iarg],"temp") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (index_temp < 0) error->all(FLERR,"Thermo style does not use temp"); delete [] id_compute[index_temp]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_temp] = new char[n]; strcpy(id_compute[index_temp],arg[iarg+1]); int icompute = modify->find_compute(arg[iarg+1]); if (icompute < 0) error->all(FLERR,"Could not find thermo_modify temperature ID"); temperature = modify->compute[icompute]; if (temperature->tempflag == 0) error->all(FLERR,"Thermo_modify temperature ID does not " "compute temperature"); if (temperature->igroup != 0 && comm->me == 0) error->warning(FLERR, "Temperature for thermo pressure is not for group all"); // reset id_temp of pressure to new temperature ID // either pressure currently being used by thermo or "thermo_press" if (index_press_scalar >= 0) { icompute = modify->find_compute(id_compute[index_press_scalar]); if (icompute < 0) error->all(FLERR, "Pressure ID for thermo does not exist"); } else if (index_press_vector >= 0) { icompute = modify->find_compute(id_compute[index_press_vector]); if (icompute < 0) error->all(FLERR, "Pressure ID for thermo does not exist"); } else icompute = modify->find_compute((char *) "thermo_press"); modify->compute[icompute]->reset_extra_compute_fix(arg[iarg+1]); iarg += 2; } else if (strcmp(arg[iarg],"press") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (index_press_scalar < 0 && index_press_vector < 0) error->all(FLERR,"Thermo style does not use press"); if (index_press_scalar >= 0) { delete [] id_compute[index_press_scalar]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_press_scalar] = new char[n]; strcpy(id_compute[index_press_scalar],arg[iarg+1]); } if (index_press_vector >= 0) { delete [] id_compute[index_press_vector]; int n = strlen(arg[iarg+1]) + 1; id_compute[index_press_vector] = new char[n]; strcpy(id_compute[index_press_vector],arg[iarg+1]); } int icompute = modify->find_compute(arg[iarg+1]); if (icompute < 0) error->all(FLERR, "Could not find thermo_modify pressure ID"); pressure = modify->compute[icompute]; if (pressure->pressflag == 0) error->all(FLERR,"Thermo_modify pressure ID does not compute pressure"); iarg += 2; } else if (strcmp(arg[iarg],"lost") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"ignore") == 0) lostflag = IGNORE; else if (strcmp(arg[iarg+1],"warn") == 0) lostflag = WARN; else if (strcmp(arg[iarg+1],"error") == 0) lostflag = ERROR; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"norm") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); normuserflag = 1; if (strcmp(arg[iarg+1],"no") == 0) normuser = 0; else if (strcmp(arg[iarg+1],"yes") == 0) normuser = 1; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"flush") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"no") == 0) flushflag = 0; else if (strcmp(arg[iarg+1],"yes") == 0) flushflag = 1; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"line") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"one") == 0) lineflag = ONELINE; else if (strcmp(arg[iarg+1],"multi") == 0) lineflag = MULTILINE; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; } else if (strcmp(arg[iarg],"format") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"int") == 0) { if (format_int_user) delete [] format_int_user; int n = strlen(arg[iarg+2]) + 1; format_int_user = new char[n]; strcpy(format_int_user,arg[iarg+2]); if (format_bigint_user) delete [] format_bigint_user; n = strlen(format_int_user) + 3; format_bigint_user = new char[n]; char *ptr = strchr(format_int_user,'d'); if (ptr == NULL) error->all(FLERR, "Thermo_modify int format does not contain d character"); *ptr = '\0'; sprintf(format_bigint_user,"%s%s%s",format_int_user, BIGINT_FORMAT,ptr+1); *ptr = 'd'; } else if (strcmp(arg[iarg+1],"float") == 0) { if (format_float_user) delete [] format_float_user; int n = strlen(arg[iarg+2]) + 1; format_float_user = new char[n]; strcpy(format_float_user,arg[iarg+2]); } else { int i = atoi(arg[iarg+1]) - 1; if (i < 0 || i >= nfield_initial) error->all(FLERR,"Illegal thermo_modify command"); if (format_user[i]) delete [] format_user[i]; int n = strlen(arg[iarg+2]) + 1; format_user[i] = new char[n]; strcpy(format_user[i],arg[iarg+2]); } iarg += 3; } else error->all(FLERR,"Illegal thermo_modify command"); } } /* ---------------------------------------------------------------------- allocate all per-field memory ------------------------------------------------------------------------- */ void Thermo::allocate() { // n = specified fields + Volume field (added at run time) int n = nfield_initial + 1; keyword = new char*[n]; for (int i = 0; i < n; i++) keyword[i] = new char[32]; vfunc = new FnPtr[n]; vtype = new int[n]; format = new char*[n]; for (int i = 0; i < n; i++) format[i] = new char[32]; format_user = new char*[n]; for (int i = 0; i < n; i++) format_user[i] = NULL; field2index = new int[n]; argindex1 = new int[n]; argindex2 = new int[n]; // factor of 3 is max number of computes a single field can add ncompute = 0; id_compute = new char*[3*n]; compute_which = new int[3*n]; computes = new Compute*[3*n]; nfix = 0; id_fix = new char*[n]; fixes = new Fix*[n]; nvariable = 0; id_variable = new char*[n]; variables = new int[n]; } /* ---------------------------------------------------------------------- deallocate all per-field memory ------------------------------------------------------------------------- */ void Thermo::deallocate() { int n = nfield_initial + 1; for (int i = 0; i < n; i++) delete [] keyword[i]; delete [] keyword; delete [] vfunc; delete [] vtype; for (int i = 0; i < n; i++) delete [] format[i]; delete [] format; for (int i = 0; i < n; i++) delete [] format_user[i]; delete [] format_user; delete [] field2index; delete [] argindex1; delete [] argindex2; for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; delete [] id_compute; delete [] compute_which; delete [] computes; for (int i = 0; i < nfix; i++) delete [] id_fix[i]; delete [] id_fix; delete [] fixes; for (int i = 0; i < nvariable; i++) delete [] id_variable[i]; delete [] id_variable; delete [] variables; } /* ---------------------------------------------------------------------- parse list of thermo keywords from str set compute flags (temp, press, pe, etc) ------------------------------------------------------------------------- */ void Thermo::parse_fields(char *str) { nfield = 0; // customize a new keyword by adding to if statement char *word = strtok(str," \0"); while (word) { if (strcmp(word,"step") == 0) { addfield("Step",&Thermo::compute_step,BIGINT); } else if (strcmp(word,"elapsed") == 0) { addfield("Elapsed",&Thermo::compute_elapsed,BIGINT); } else if (strcmp(word,"elaplong") == 0) { addfield("Elaplong",&Thermo::compute_elapsed_long,BIGINT); } else if (strcmp(word,"dt") == 0) { addfield("Dt",&Thermo::compute_dt,FLOAT); + } else if (strcmp(word,"time") == 0) { + addfield("Time",&Thermo::compute_time,FLOAT); } else if (strcmp(word,"cpu") == 0) { addfield("CPU",&Thermo::compute_cpu,FLOAT); } else if (strcmp(word,"tpcpu") == 0) { addfield("T/CPU",&Thermo::compute_tpcpu,FLOAT); } else if (strcmp(word,"spcpu") == 0) { addfield("S/CPU",&Thermo::compute_spcpu,FLOAT); } else if (strcmp(word,"atoms") == 0) { addfield("Atoms",&Thermo::compute_atoms,BIGINT); } else if (strcmp(word,"temp") == 0) { addfield("Temp",&Thermo::compute_temp,FLOAT); index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"press") == 0) { addfield("Press",&Thermo::compute_press,FLOAT); index_press_scalar = add_compute(id_press,SCALAR); } else if (strcmp(word,"pe") == 0) { addfield("PotEng",&Thermo::compute_pe,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ke") == 0) { addfield("KinEng",&Thermo::compute_ke,FLOAT); index_temp = add_compute(id_temp,SCALAR); } else if (strcmp(word,"etotal") == 0) { addfield("TotEng",&Thermo::compute_etotal,FLOAT); index_temp = add_compute(id_temp,SCALAR); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"enthalpy") == 0) { addfield("Enthalpy",&Thermo::compute_enthalpy,FLOAT); index_temp = add_compute(id_temp,SCALAR); index_press_scalar = add_compute(id_press,SCALAR); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"evdwl") == 0) { addfield("E_vdwl",&Thermo::compute_evdwl,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ecoul") == 0) { addfield("E_coul",&Thermo::compute_ecoul,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"epair") == 0) { addfield("E_pair",&Thermo::compute_epair,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"ebond") == 0) { addfield("E_bond",&Thermo::compute_ebond,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eangle") == 0) { addfield("E_angle",&Thermo::compute_eangle,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"edihed") == 0) { addfield("E_dihed",&Thermo::compute_edihed,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"eimp") == 0) { addfield("E_impro",&Thermo::compute_eimp,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"emol") == 0) { addfield("E_mol",&Thermo::compute_emol,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"elong") == 0) { addfield("E_long",&Thermo::compute_elong,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"etail") == 0) { addfield("E_tail",&Thermo::compute_etail,FLOAT); index_pe = add_compute(id_pe,SCALAR); } else if (strcmp(word,"vol") == 0) { addfield("Volume",&Thermo::compute_vol,FLOAT); } else if (strcmp(word,"lx") == 0) { addfield("Lx",&Thermo::compute_lx,FLOAT); } else if (strcmp(word,"ly") == 0) { addfield("Ly",&Thermo::compute_ly,FLOAT); } else if (strcmp(word,"lz") == 0) { addfield("Lz",&Thermo::compute_lz,FLOAT); } else if (strcmp(word,"xlo") == 0) { addfield("Xlo",&Thermo::compute_xlo,FLOAT); } else if (strcmp(word,"xhi") == 0) { addfield("Xhi",&Thermo::compute_xhi,FLOAT); } else if (strcmp(word,"ylo") == 0) { addfield("Ylo",&Thermo::compute_ylo,FLOAT); } else if (strcmp(word,"yhi") == 0) { addfield("Yhi",&Thermo::compute_yhi,FLOAT); } else if (strcmp(word,"zlo") == 0) { addfield("Zlo",&Thermo::compute_zlo,FLOAT); } else if (strcmp(word,"zhi") == 0) { addfield("Zhi",&Thermo::compute_zhi,FLOAT); } else if (strcmp(word,"xy") == 0) { addfield("Xy",&Thermo::compute_xy,FLOAT); } else if (strcmp(word,"xz") == 0) { addfield("Xz",&Thermo::compute_xz,FLOAT); } else if (strcmp(word,"yz") == 0) { addfield("Yz",&Thermo::compute_yz,FLOAT); } else if (strcmp(word,"xlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Xlat",&Thermo::compute_xlat,FLOAT); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Ylat",&Thermo::compute_ylat,FLOAT); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword requires lattice be defined"); addfield("Zlat",&Thermo::compute_zlat,FLOAT); } else if (strcmp(word,"pxx") == 0) { addfield("Pxx",&Thermo::compute_pxx,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyy") == 0) { addfield("Pyy",&Thermo::compute_pyy,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pzz") == 0) { addfield("Pzz",&Thermo::compute_pzz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxy") == 0) { addfield("Pxy",&Thermo::compute_pxy,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pxz") == 0) { addfield("Pxz",&Thermo::compute_pxz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"pyz") == 0) { addfield("Pyz",&Thermo::compute_pyz,FLOAT); index_press_vector = add_compute(id_press,VECTOR); } else if (strcmp(word,"fmax") == 0) { addfield("Fmax",&Thermo::compute_fmax,FLOAT); } else if (strcmp(word,"fnorm") == 0) { addfield("Fnorm",&Thermo::compute_fnorm,FLOAT); } else if (strcmp(word,"cella") == 0) { addfield("Cella",&Thermo::compute_cella,FLOAT); } else if (strcmp(word,"cellb") == 0) { addfield("Cellb",&Thermo::compute_cellb,FLOAT); } else if (strcmp(word,"cellc") == 0) { addfield("Cellc",&Thermo::compute_cellc,FLOAT); } else if (strcmp(word,"cellalpha") == 0) { addfield("CellAlpha",&Thermo::compute_cellalpha,FLOAT); } else if (strcmp(word,"cellbeta") == 0) { addfield("CellBeta",&Thermo::compute_cellbeta,FLOAT); } else if (strcmp(word,"cellgamma") == 0) { addfield("CellGamma",&Thermo::compute_cellgamma,FLOAT); // compute value = c_ID, fix value = f_ID, variable value = v_ID // count trailing [] and store int arguments // copy = at most 8 chars of ID to pass to addfield } else if ((strncmp(word,"c_",2) == 0) || (strncmp(word,"f_",2) == 0) || (strncmp(word,"v_",2) == 0)) { int n = strlen(word); char *id = new char[n]; strcpy(id,&word[2]); char copy[9]; strncpy(copy,id,8); copy[8] = '\0'; // parse zero or one or two trailing brackets from ID // argindex1,argindex2 = int inside each bracket pair, 0 if no bracket char *ptr = strchr(id,'['); if (ptr == NULL) argindex1[nfield] = 0; else { *ptr = '\0'; argindex1[nfield] = input->variable->int_between_brackets(ptr); ptr++; if (*ptr == '[') { argindex2[nfield] = input->variable->int_between_brackets(ptr); ptr++; } else argindex2[nfield] = 0; } if (word[0] == 'c') { n = modify->find_compute(id); if (n < 0) error->all(FLERR,"Could not find thermo custom compute ID"); if (argindex1[nfield] == 0 && modify->compute[n]->scalar_flag == 0) error->all(FLERR,"Thermo compute does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->compute[n]->vector_flag == 0) error->all(FLERR,"Thermo compute does not compute vector"); if (argindex1[nfield] > modify->compute[n]->size_vector) error->all(FLERR,"Thermo compute vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->compute[n]->array_flag == 0) error->all(FLERR,"Thermo compute does not compute array"); if (argindex1[nfield] > modify->compute[n]->size_array_rows || argindex2[nfield] > modify->compute[n]->size_array_cols) error->all(FLERR,"Thermo compute array is accessed out-of-range"); } if (argindex1[nfield] == 0) field2index[nfield] = add_compute(id,SCALAR); else if (argindex2[nfield] == 0) field2index[nfield] = add_compute(id,VECTOR); else field2index[nfield] = add_compute(id,ARRAY); addfield(copy,&Thermo::compute_compute,FLOAT); } else if (word[0] == 'f') { n = modify->find_fix(id); if (n < 0) error->all(FLERR,"Could not find thermo custom fix ID"); if (argindex1[nfield] == 0 && modify->fix[n]->scalar_flag == 0) error->all(FLERR,"Thermo fix does not compute scalar"); if (argindex1[nfield] > 0 && argindex2[nfield] == 0) { if (modify->fix[n]->vector_flag == 0) error->all(FLERR,"Thermo fix does not compute vector"); if (argindex1[nfield] > modify->fix[n]->size_vector) error->all(FLERR,"Thermo fix vector is accessed out-of-range"); } if (argindex1[nfield] > 0 && argindex2[nfield] > 0) { if (modify->fix[n]->array_flag == 0) error->all(FLERR,"Thermo fix does not compute array"); if (argindex1[nfield] > modify->fix[n]->size_array_rows || argindex2[nfield] > modify->fix[n]->size_array_cols) error->all(FLERR,"Thermo fix array is accessed out-of-range"); } field2index[nfield] = add_fix(id); addfield(copy,&Thermo::compute_fix,FLOAT); } else if (word[0] == 'v') { n = input->variable->find(id); if (n < 0) error->all(FLERR,"Could not find thermo custom variable name"); if (input->variable->equalstyle(n) == 0) error->all(FLERR, "Thermo custom variable is not equal-style variable"); if (argindex1[nfield]) error->all(FLERR,"Thermo custom variable cannot be indexed"); field2index[nfield] = add_variable(id); addfield(copy,&Thermo::compute_variable,FLOAT); } delete [] id; } else error->all(FLERR,"Invalid keyword in thermo_style custom command"); word = strtok(NULL," \0"); } } /* ---------------------------------------------------------------------- add field to list of quantities to print ------------------------------------------------------------------------- */ void Thermo::addfield(const char *key, FnPtr func, int typeflag) { strcpy(keyword[nfield],key); vfunc[nfield] = func; vtype[nfield] = typeflag; nfield++; } /* ---------------------------------------------------------------------- add compute ID to list of Compute objects to call return location of where this Compute is in list if already in list with same which, do not add, just return index ------------------------------------------------------------------------- */ int Thermo::add_compute(const char *id, int which) { int icompute; for (icompute = 0; icompute < ncompute; icompute++) if ((strcmp(id,id_compute[icompute]) == 0) && which == compute_which[icompute]) break; if (icompute < ncompute) return icompute; int n = strlen(id) + 1; id_compute[ncompute] = new char[n]; strcpy(id_compute[ncompute],id); compute_which[ncompute] = which; ncompute++; return ncompute-1; } /* ---------------------------------------------------------------------- add fix ID to list of Fix objects to call ------------------------------------------------------------------------- */ int Thermo::add_fix(const char *id) { int n = strlen(id) + 1; id_fix[nfix] = new char[n]; strcpy(id_fix[nfix],id); nfix++; return nfix-1; } /* ---------------------------------------------------------------------- add variable ID to list of Variables to evaluate ------------------------------------------------------------------------- */ int Thermo::add_variable(const char *id) { int n = strlen(id) + 1; id_variable[nvariable] = new char[n]; strcpy(id_variable[nvariable],id); nvariable++; return nvariable-1; } /* ---------------------------------------------------------------------- compute a single thermodyanmic value, word is any keyword in custom list called when a variable is evaluated by Variable class return value as double in answer return 0 if str is recoginzed keyword, 1 if unrecognized customize a new keyword by adding to if statement ------------------------------------------------------------------------- */ int Thermo::evaluate_keyword(char *word, double *answer) { // turn off normflag if natoms = 0 to avoid divide by 0 // normflag must be set for lo-level thermo routines that may be invoked natoms = atom->natoms; if (natoms == 0) normflag = 0; else normflag = normvalue; // invoke a lo-level thermo routine to compute the variable value // if keyword requires a compute, error if thermo doesn't use the compute // if inbetween runs and needed compute is not current, error // if in middle of run and needed compute is not current, invoke it // for keywords that use pe indirectly (evdwl, ebond, etc): // check if energy was tallied on this timestep and set pe->invoked_flag // this will trigger next timestep for energy tallying via addstep() if (strcmp(word,"step") == 0) { compute_step(); dvalue = bivalue; } else if (strcmp(word,"elapsed") == 0) { if (update->whichflag == 0) error->all(FLERR, "This variable thermo keyword cannot be used between runs"); compute_elapsed(); dvalue = bivalue; } else if (strcmp(word,"elaplong") == 0) { if (update->whichflag == 0) error->all(FLERR, "This variable thermo keyword cannot be used between runs"); compute_elapsed_long(); dvalue = bivalue; } else if (strcmp(word,"dt") == 0) { compute_dt(); + } else if (strcmp(word,"time") == 0) { + compute_time(); + } else if (strcmp(word,"cpu") == 0) { if (update->whichflag == 0) error->all(FLERR, "This variable thermo keyword cannot be used between runs"); compute_cpu(); } else if (strcmp(word,"tpcpu") == 0) { if (update->whichflag == 0) error->all(FLERR, "This variable thermo keyword cannot be used between runs"); compute_tpcpu(); } else if (strcmp(word,"spcpu") == 0) { if (update->whichflag == 0) error->all(FLERR, "This variable thermo keyword cannot be used between runs"); compute_spcpu(); } else if (strcmp(word,"atoms") == 0) { compute_atoms(); dvalue = bivalue; } else if (strcmp(word,"temp") == 0) { if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_temp(); } else if (strcmp(word,"press") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) { pressure->compute_scalar(); pressure->invoked_flag |= INVOKED_SCALAR; } compute_press(); } else if (strcmp(word,"pe") == 0) { if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } compute_pe(); } else if (strcmp(word,"ke") == 0) { if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_ke(); } else if (strcmp(word,"etotal") == 0) { if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } compute_etotal(); } else if (strcmp(word,"enthalpy") == 0) { if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); if (update->whichflag == 0) { if (pe->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pe->invoked_flag & INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= INVOKED_SCALAR; } if (!temperature) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init temp"); if (update->whichflag == 0) { if (temperature->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(temperature->invoked_flag & INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= INVOKED_SCALAR; } if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_scalar != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_SCALAR)) { pressure->compute_scalar(); pressure->invoked_flag |= INVOKED_SCALAR; } compute_enthalpy(); } else if (strcmp(word,"evdwl") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_evdwl(); } else if (strcmp(word,"ecoul") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_ecoul(); } else if (strcmp(word,"epair") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_epair(); } else if (strcmp(word,"ebond") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_ebond(); } else if (strcmp(word,"eangle") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_eangle(); } else if (strcmp(word,"edihed") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_edihed(); } else if (strcmp(word,"eimp") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_eimp(); } else if (strcmp(word,"emol") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_emol(); } else if (strcmp(word,"elong") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_elong(); } else if (strcmp(word,"etail") == 0) { if (update->eflag_global != update->ntimestep) error->all(FLERR,"Energy was not tallied on needed timestep"); if (!pe) error->all(FLERR, "Thermo keyword in variable requires thermo to use/init pe"); pe->invoked_flag |= INVOKED_SCALAR; compute_etail(); } else if (strcmp(word,"vol") == 0) compute_vol(); else if (strcmp(word,"lx") == 0) compute_lx(); else if (strcmp(word,"ly") == 0) compute_ly(); else if (strcmp(word,"lz") == 0) compute_lz(); else if (strcmp(word,"xlo") == 0) compute_xlo(); else if (strcmp(word,"xhi") == 0) compute_xhi(); else if (strcmp(word,"ylo") == 0) compute_ylo(); else if (strcmp(word,"yhi") == 0) compute_yhi(); else if (strcmp(word,"zlo") == 0) compute_zlo(); else if (strcmp(word,"zhi") == 0) compute_zhi(); else if (strcmp(word,"xy") == 0) compute_xy(); else if (strcmp(word,"xz") == 0) compute_xz(); else if (strcmp(word,"yz") == 0) compute_yz(); else if (strcmp(word,"xlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_xlat(); } else if (strcmp(word,"ylat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_ylat(); } else if (strcmp(word,"zlat") == 0) { if (domain->lattice == NULL) error->all(FLERR,"Thermo keyword in variable requires lattice be defined"); compute_zlat(); } else if (strcmp(word,"pxx") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxx(); } else if (strcmp(word,"pyy") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pyy(); } else if (strcmp(word,"pzz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pzz(); } else if (strcmp(word,"pxy") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxy(); } else if (strcmp(word,"pxz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pxz(); } else if (strcmp(word,"pyz") == 0) { if (!pressure) error->all(FLERR,"Thermo keyword in variable requires " "thermo to use/init press"); if (update->whichflag == 0) { if (pressure->invoked_vector != update->ntimestep) error->all(FLERR,"Compute used in variable thermo keyword between runs " "is not current"); } else if (!(pressure->invoked_flag & INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= INVOKED_VECTOR; } compute_pyz(); } else if (strcmp(word,"fmax") == 0) compute_fmax(); else if (strcmp(word,"fnorm") == 0) compute_fnorm(); else if (strcmp(word,"cella") == 0) compute_cella(); else if (strcmp(word,"cellb") == 0) compute_cellb(); else if (strcmp(word,"cellc") == 0) compute_cellc(); else if (strcmp(word,"cellalpha") == 0) compute_cellalpha(); else if (strcmp(word,"cellbeta") == 0) compute_cellbeta(); else if (strcmp(word,"cellgamma") == 0) compute_cellgamma(); else return 1; *answer = dvalue; return 0; } /* ---------------------------------------------------------------------- extraction of Compute, Fix, Variable results compute/fix are normalized by atoms if returning extensive value variable value is not normalized (formula should normalize if desired) ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ void Thermo::compute_compute() { int m = field2index[ifield]; Compute *compute = computes[m]; if (compute_which[m] == SCALAR) { dvalue = compute->scalar; if (normflag && compute->extscalar) dvalue /= natoms; } else if (compute_which[m] == VECTOR) { dvalue = compute->vector[argindex1[ifield]-1]; if (normflag) { if (compute->extvector == 0) return; else if (compute->extvector == 1) dvalue /= natoms; else if (compute->extlist[argindex1[ifield]-1]) dvalue /= natoms; } } else { dvalue = compute->array[argindex1[ifield]-1][argindex2[ifield]-1]; if (normflag && compute->extarray) dvalue /= natoms; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_fix() { int m = field2index[ifield]; Fix *fix = fixes[m]; if (argindex1[ifield] == 0) { dvalue = fix->compute_scalar(); if (normflag && fix->extscalar) dvalue /= natoms; } else if (argindex2[ifield] == 0) { dvalue = fix->compute_vector(argindex1[ifield]-1); if (normflag) { if (fix->extvector == 0) return; else if (fix->extvector == 1) dvalue /= natoms; else if (fix->extlist[argindex1[ifield]-1]) dvalue /= natoms; } } else { dvalue = fix->compute_array(argindex1[ifield]-1,argindex2[ifield]-1); if (normflag && fix->extarray) dvalue /= natoms; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_variable() { dvalue = input->variable->compute_equal(variables[field2index[ifield]]); } /* ---------------------------------------------------------------------- one method for every keyword thermo can output called by compute() or evaluate_keyword() compute will have already been called set ivalue/dvalue/bivalue if value is int/double/bigint customize a new keyword by adding a method ------------------------------------------------------------------------- */ void Thermo::compute_step() { bivalue = update->ntimestep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed() { bivalue = update->ntimestep - update->firststep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elapsed_long() { bivalue = update->ntimestep - update->beginstep; } /* ---------------------------------------------------------------------- */ void Thermo::compute_dt() { dvalue = update->dt; } /* ---------------------------------------------------------------------- */ +void Thermo::compute_time() +{ + dvalue = update->atime + (update->ntimestep-update->atimestep)*update->dt; +} + +/* ---------------------------------------------------------------------- */ + void Thermo::compute_cpu() { if (firststep == 0) dvalue = 0.0; else dvalue = timer->elapsed(Timer::LOOP); } /* ---------------------------------------------------------------------- */ void Thermo::compute_tpcpu() { double new_cpu; double new_time = update->ntimestep * update->dt; if (firststep == 0) { new_cpu = 0.0; dvalue = 0.0; } else { new_cpu = timer->elapsed(Timer::LOOP); double cpu_diff = new_cpu - last_tpcpu; double time_diff = new_time - last_time; if (time_diff > 0.0 && cpu_diff > 0.0) dvalue = time_diff/cpu_diff; else dvalue = 0.0; } last_time = new_time; last_tpcpu = new_cpu; } /* ---------------------------------------------------------------------- */ void Thermo::compute_spcpu() { double new_cpu; int new_step = update->ntimestep; if (firststep == 0) { new_cpu = 0.0; dvalue = 0.0; } else { new_cpu = timer->elapsed(Timer::LOOP); double cpu_diff = new_cpu - last_spcpu; int step_diff = new_step - last_step; if (cpu_diff > 0.0) dvalue = step_diff/cpu_diff; else dvalue = 0.0; } last_step = new_step; last_spcpu = new_cpu; } /* ---------------------------------------------------------------------- */ void Thermo::compute_atoms() { bivalue = atom->natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_temp() { dvalue = temperature->scalar; } /* ---------------------------------------------------------------------- */ void Thermo::compute_press() { dvalue = pressure->scalar; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pe() { dvalue = pe->scalar; if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ke() { dvalue = temperature->scalar; dvalue *= 0.5 * temperature->dof * force->boltz; if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_etotal() { compute_pe(); double ke = temperature->scalar; ke *= 0.5 * temperature->dof * force->boltz; if (normflag) ke /= natoms; dvalue += ke; } /* ---------------------------------------------------------------------- */ void Thermo::compute_enthalpy() { compute_etotal(); double etmp = dvalue; compute_vol(); double vtmp = dvalue; if (normflag) vtmp /= natoms; compute_press(); double ptmp = dvalue; dvalue = etmp + ptmp*vtmp/(force->nktv2p); } /* ---------------------------------------------------------------------- */ void Thermo::compute_evdwl() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_vdwl; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue += force->pair->etail / volume; } if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ecoul() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_coul; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_epair() { double tmp = 0.0; if (force->pair) tmp += force->pair->eng_vdwl + force->pair->eng_coul; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (force->kspace) dvalue += force->kspace->energy; if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue += force->pair->etail / volume; } if (normflag) dvalue /= natoms; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ebond() { if (force->bond) { double tmp = force->bond->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_eangle() { if (force->angle) { double tmp = force->angle->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_edihed() { if (force->dihedral) { double tmp = force->dihedral->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_eimp() { if (force->improper) { double tmp = force->improper->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_emol() { double tmp = 0.0; if (atom->molecular) { if (force->bond) tmp += force->bond->energy; if (force->angle) tmp += force->angle->energy; if (force->dihedral) tmp += force->dihedral->energy; if (force->improper) tmp += force->improper->energy; MPI_Allreduce(&tmp,&dvalue,1,MPI_DOUBLE,MPI_SUM,world); if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_elong() { if (force->kspace) { dvalue = force->kspace->energy; if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_etail() { if (force->pair && force->pair->tail_flag) { double volume = domain->xprd * domain->yprd * domain->zprd; dvalue = force->pair->etail / volume; if (normflag) dvalue /= natoms; } else dvalue = 0.0; } /* ---------------------------------------------------------------------- */ void Thermo::compute_vol() { if (domain->dimension == 3) dvalue = domain->xprd * domain->yprd * domain->zprd; else dvalue = domain->xprd * domain->yprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_lx() { dvalue = domain->xprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ly() { dvalue = domain->yprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_lz() { dvalue = domain->zprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xlo() { dvalue = domain->boxlo[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xhi() { dvalue = domain->boxhi[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ylo() { dvalue = domain->boxlo[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_yhi() { dvalue = domain->boxhi[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zlo() { dvalue = domain->boxlo[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zhi() { dvalue = domain->boxhi[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xy() { dvalue = domain->xy; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xz() { dvalue = domain->xz; } /* ---------------------------------------------------------------------- */ void Thermo::compute_yz() { dvalue = domain->yz; } /* ---------------------------------------------------------------------- */ void Thermo::compute_xlat() { dvalue = domain->lattice->xlattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_ylat() { dvalue = domain->lattice->ylattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_zlat() { dvalue = domain->lattice->zlattice; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxx() { dvalue = pressure->vector[0]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pyy() { dvalue = pressure->vector[1]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pzz() { dvalue = pressure->vector[2]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxy() { dvalue = pressure->vector[3]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pxz() { dvalue = pressure->vector[4]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_pyz() { dvalue = pressure->vector[5]; } /* ---------------------------------------------------------------------- */ void Thermo::compute_fmax() { double **f = atom->f; int nlocal = atom->nlocal; double max = 0.0; for (int i = 0; i < nlocal; i++) { max = MAX(max,fabs(f[i][0])); max = MAX(max,fabs(f[i][1])); max = MAX(max,fabs(f[i][2])); } double maxall; MPI_Allreduce(&max,&maxall,1,MPI_DOUBLE,MPI_MAX,world); dvalue = maxall; } /* ---------------------------------------------------------------------- */ void Thermo::compute_fnorm() { double **f = atom->f; int nlocal = atom->nlocal; double dot = 0.0; for (int i = 0; i < nlocal; i++) dot += f[i][0]*f[i][0] + f[i][1]*f[i][1] + f[i][2]*f[i][2]; double dotall; MPI_Allreduce(&dot,&dotall,1,MPI_DOUBLE,MPI_SUM,world); dvalue = sqrt(dotall); } /* ---------------------------------------------------------------------- */ void Thermo::compute_cella() { dvalue = domain->xprd; } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellb() { if (!domain->triclinic) dvalue = domain->yprd; else { double* h = domain->h; dvalue = sqrt(h[1]*h[1]+h[5]*h[5]); } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellc() { if (!domain->triclinic) dvalue = domain->zprd; else { double* h = domain->h; dvalue = sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]); } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellalpha() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(alpha) = (xy.xz + ly.yz)/(b.c) double* h = domain->h; double cosalpha = (h[5]*h[4]+h[1]*h[3])/ sqrt((h[1]*h[1]+h[5]*h[5])*(h[2]*h[2]+h[3]*h[3]+h[4]*h[4])); dvalue = acos(cosalpha)*180.0/MY_PI; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellbeta() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(beta) = xz/c double* h = domain->h; double cosbeta = h[4]/sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]); dvalue = acos(cosbeta)*180.0/MY_PI; } } /* ---------------------------------------------------------------------- */ void Thermo::compute_cellgamma() { if (!domain->triclinic) dvalue = 90.0; else { // Cos(gamma) = xy/b double* h = domain->h; double cosgamma = h[5]/sqrt(h[1]*h[1]+h[5]*h[5]); dvalue = acos(cosgamma)*180.0/MY_PI; } } diff --git a/src/thermo.h b/src/thermo.h index 173e7239d..e0a10ea0d 100644 --- a/src/thermo.h +++ b/src/thermo.h @@ -1,392 +1,393 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_THERMO_H #define LMP_THERMO_H #include "pointers.h" namespace LAMMPS_NS { class Thermo : protected Pointers { friend class WriteRestart; // accesses lostflag friend class WriteData; // accesses lostflag friend class MinCG; // accesses compute_pe public: char *style; int normflag; // 0 if do not normalize by atoms, 1 if normalize int modified; // 1 if thermo_modify has been used, else 0 int cudable; // 1 if all computes used are cudable Thermo(class LAMMPS *, int, char **); ~Thermo(); void init(); bigint lost_check(); void modify_params(int, char **); void header(); void compute(int); int evaluate_keyword(char *, double *); private: char *line; char **keyword; int *vtype; int nfield,nfield_initial; int me; char **format,**format_user; char *format_float_one_def,*format_float_multi_def; char *format_int_one_def,*format_int_multi_def; char *format_float_user,*format_int_user,*format_bigint_user; char format_multi[128]; char format_bigint_one_def[8],format_bigint_multi_def[8]; int normvalue; // use this for normflag unless natoms = 0 int normuserflag; // 0 if user has not set, 1 if has int normuser; int firststep; int lostflag,lostbefore; int flushflag,lineflag; double last_tpcpu,last_spcpu; double last_time; bigint last_step; bigint natoms; // data used by routines that compute single values int ivalue; // integer value to print double dvalue; // double value to print bigint bivalue; // big integer value to print int ifield; // which field in thermo output is being computed int *field2index; // which compute,fix,variable calcs this field int *argindex1; // indices into compute,fix scalar,vector int *argindex2; // data for keyword-specific Compute objects // index = where they are in computes list // id = ID of Compute objects // Compute * = ptrs to the Compute objects int index_temp,index_press_scalar,index_press_vector,index_pe; char *id_temp,*id_press,*id_pe; class Compute *temperature,*pressure,*pe; int ncompute; // # of Compute objects called by thermo char **id_compute; // their IDs int *compute_which; // 0/1/2 if should call scalar,vector,array class Compute **computes; // list of ptrs to the Compute objects int nfix; // # of Fix objects called by thermo char **id_fix; // their IDs class Fix **fixes; // list of ptrs to the Fix objects int nvariable; // # of variables evaulated by thermo char **id_variable; // list of variable names int *variables; // list of Variable indices // private methods void allocate(); void deallocate(); void parse_fields(char *); int add_compute(const char *, int); int add_fix(const char *); int add_variable(const char *); typedef void (Thermo::*FnPtr)(); void addfield(const char *, FnPtr, int); FnPtr *vfunc; // list of ptrs to functions void compute_compute(); // functions that compute a single value void compute_fix(); // via calls to Compute,Fix,Variable classes void compute_variable(); // functions that compute a single value // customize a new keyword by adding a method prototype void compute_step(); void compute_elapsed(); void compute_elapsed_long(); void compute_dt(); + void compute_time(); void compute_cpu(); void compute_tpcpu(); void compute_spcpu(); void compute_atoms(); void compute_temp(); void compute_press(); void compute_pe(); void compute_ke(); void compute_etotal(); void compute_enthalpy(); void compute_evdwl(); void compute_ecoul(); void compute_epair(); void compute_ebond(); void compute_eangle(); void compute_edihed(); void compute_eimp(); void compute_emol(); void compute_elong(); void compute_etail(); void compute_vol(); void compute_lx(); void compute_ly(); void compute_lz(); void compute_xlo(); void compute_xhi(); void compute_ylo(); void compute_yhi(); void compute_zlo(); void compute_zhi(); void compute_xy(); void compute_xz(); void compute_yz(); void compute_xlat(); void compute_ylat(); void compute_zlat(); void compute_pxx(); void compute_pyy(); void compute_pzz(); void compute_pxy(); void compute_pyz(); void compute_pxz(); void compute_fmax(); void compute_fnorm(); void compute_cella(); void compute_cellb(); void compute_cellc(); void compute_cellalpha(); void compute_cellbeta(); void compute_cellgamma(); }; } #endif /* ERROR/WARNING messages: E: Illegal ... command Self-explanatory. Check the input script syntax and compare to the documentation for the command. You can use -echo screen as a command-line option when running LAMMPS to see the offending line. E: Could not find thermo compute ID Compute ID specified in thermo_style command does not exist. E: Could not find thermo fix ID Fix ID specified in thermo_style command does not exist. E: Thermo and fix not computed at compatible times Fixes generate values on specific timesteps. The thermo output does not match these timesteps. E: Could not find thermo variable name Self-explanatory. E: Too many total atoms See the setting for bigint in the src/lmptype.h file. E: Lost atoms: original %ld current %ld Lost atoms are checked for each time thermo output is done. See the thermo_modify lost command for options. Lost atoms usually indicate bad dynamics, e.g. atoms have been blown far out of the simulation box, or moved futher than one processor's sub-domain away before reneighboring. W: Lost atoms: original %ld current %ld Lost atoms are checked for each time thermo output is done. See the thermo_modify lost command for options. Lost atoms usually indicate bad dynamics, e.g. atoms have been blown far out of the simulation box, or moved futher than one processor's sub-domain away before reneighboring. E: Thermo style does not use temp Cannot use thermo_modify to set this parameter since the thermo_style is not computing this quantity. E: Could not find thermo_modify temperature ID The compute ID needed by thermo style custom to compute temperature does not exist. E: Thermo_modify temperature ID does not compute temperature The specified compute ID does not compute temperature. W: Temperature for thermo pressure is not for group all User-assigned temperature to thermo via the thermo_modify command does not compute temperature for all atoms. Since thermo computes a global pressure, the kinetic energy contribution from the temperature is assumed to also be for all atoms. Thus the pressure printed by thermo could be inaccurate. E: Pressure ID for thermo does not exist The compute ID needed to compute pressure for thermodynamics does not exist. E: Thermo style does not use press Cannot use thermo_modify to set this parameter since the thermo_style is not computing this quantity. E: Could not find thermo_modify pressure ID The compute ID needed by thermo style custom to compute pressure does not exist. E: Thermo_modify pressure ID does not compute pressure The specified compute ID does not compute pressure. E: Thermo_modify int format does not contain d character Self-explanatory. E: Thermo keyword requires lattice be defined The xlat, ylat, zlat keywords refer to lattice properties. E: Could not find thermo custom compute ID The compute ID needed by thermo style custom to compute a requested quantity does not exist. E: Thermo compute does not compute scalar Self-explanatory. E: Thermo compute does not compute vector Self-explanatory. E: Thermo compute vector is accessed out-of-range Self-explanatory. E: Thermo compute does not compute array Self-explanatory. E: Thermo compute array is accessed out-of-range Self-explanatory. E: Could not find thermo custom fix ID The fix ID needed by thermo style custom to compute a requested quantity does not exist. E: Thermo fix does not compute scalar Self-explanatory. E: Thermo fix does not compute vector Self-explanatory. E: Thermo fix vector is accessed out-of-range Self-explanatory. E: Thermo fix does not compute array Self-explanatory. E: Thermo fix array is accessed out-of-range Self-explanatory. E: Could not find thermo custom variable name Self-explanatory. E: Thermo custom variable is not equal-style variable Only equal-style variables can be output with thermodynamics, not atom-style variables. E: Thermo custom variable cannot be indexed Self-explanatory. E: Invalid keyword in thermo_style custom command One or more specified keywords are not recognized. E: This variable thermo keyword cannot be used between runs Keywords that refer to time (such as cpu, elapsed) do not make sense in between runs. E: Thermo keyword in variable requires thermo to use/init temp You are using a thermo keyword in a variable that requires temperature to be calculated, but your thermo output does not use it. Add it to your thermo output. E: Compute used in variable thermo keyword between runs is not current Some thermo keywords rely on a compute to calculate their value(s). Computes cannot be invoked by a variable in between runs. Thus they must have been evaluated on the last timestep of the previous run in order for their value(s) to be accessed. See the doc page for the variable command for more info. E: Thermo keyword in variable requires thermo to use/init press You are using a thermo keyword in a variable that requires pressure to be calculated, but your thermo output does not use it. Add it to your thermo output. E: Thermo keyword in variable requires thermo to use/init pe You are using a thermo keyword in a variable that requires potential energy to be calculated, but your thermo output does not use it. Add it to your thermo output. E: Energy was not tallied on needed timestep You are using a thermo keyword that requires potentials to have tallied energy, but they didn't on this timestep. See the variable doc page for ideas on how to make this work. E: Thermo keyword in variable requires lattice be defined The xlat, ylat, zlat keywords refer to lattice properties. */ diff --git a/src/update.cpp b/src/update.cpp index b502822c8..ad5884293 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -1,413 +1,429 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "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; if (lmp->cuda) { str = (char *) "verlet/cuda"; create_integrate(1,&str,NULL); } else { str = (char *) "verlet"; create_integrate(1,&str,NULL); } 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 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"); + atimestep = ntimestep; + 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); } eflag_global = vflag_global = -1; 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; } for (int i = 0; i < modify->ncompute; i++) if (modify->compute[i]->timeflag) modify->compute[i]->clearstep(); // 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/update.h b/src/update.h index f94ac92d9..1f347d7d0 100644 --- a/src/update.h +++ b/src/update.h @@ -1,105 +1,108 @@ /* -*- c++ -*- ---------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #ifndef LMP_UPDATE_H #define LMP_UPDATE_H #include "pointers.h" namespace LAMMPS_NS { class Update : protected Pointers { public: double dt; // timestep double etol,ftol; // minimizer tolerances on energy/force bigint ntimestep; // current step (dynamics or min iterations) int nsteps; // # of steps to run (dynamics or min iter) int whichflag; // 0 for unset, 1 for dynamics, 2 for min + double atime; // simulation time at atime_step + bigint atimestep; // last timestep atime was updated bigint firststep,laststep; // 1st & last step of this run bigint beginstep,endstep; // 1st and last step of multiple runs int first_update; // 0 before initial update, 1 after int max_eval; // max force evaluations for minimizer int restrict_output; // 1 if output should not write dump/restart int setupflag; // set when setup() is computing forces int multireplica; // 1 if min across replicas, else 0 bigint eflag_global,eflag_atom; // timestep global/peratom eng is tallied on bigint vflag_global,vflag_atom; // ditto for virial char *unit_style; class Integrate *integrate; char *integrate_style; class Min *minimize; char *minimize_style; Update(class LAMMPS *); ~Update(); void init(); void set_units(const char *); void create_integrate(int, char **, char *); void create_minimize(int, char **); void reset_timestep(int, char **); void reset_timestep(bigint); + void update_time(); bigint memory_usage(); private: void new_integrate(char *, int, char **, char *, int &); }; } #endif /* ERROR/WARNING messages: E: USER-CUDA mode requires CUDA variant of run style CUDA mode is enabled, so the run style must include a cuda suffix. E: USER-CUDA mode requires CUDA variant of min style CUDA mode is enabled, so the min style must include a cuda suffix. 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: Illegal integrate style Self-explanatory. E: Timestep must be >= 0 Specified timestep is invalid. E: Too big a timestep Specified timestep is too large. E: Cannot reset timestep with a time-dependent fix defined You cannot reset the timestep when a fix that keeps track of elapsed time is in place. E: Cannot reset timestep with a dynamic region defined Dynamic regions (see the region command) have a time dependence. Thus you cannot change the timestep when one or more of these are defined. */ diff --git a/src/verlet.cpp b/src/verlet.cpp index 9020c9399..966d14dba 100644 --- a/src/verlet.cpp +++ b/src/verlet.cpp @@ -1,441 +1,442 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain 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 "verlet.h" #include "neighbor.h" #include "domain.h" #include "comm.h" #include "atom.h" #include "force.h" #include "pair.h" #include "bond.h" #include "angle.h" #include "dihedral.h" #include "improper.h" #include "kspace.h" #include "output.h" #include "update.h" #include "modify.h" #include "compute.h" #include "fix.h" #include "timer.h" #include "memory.h" #include "error.h" using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ Verlet::Verlet(LAMMPS *lmp, int narg, char **arg) : Integrate(lmp, narg, arg) {} /* ---------------------------------------------------------------------- initialization before run ------------------------------------------------------------------------- */ void Verlet::init() { Integrate::init(); // warn if no fixes if (modify->nfix == 0 && comm->me == 0) error->warning(FLERR,"No fixes defined, atoms won't move"); // virial_style: // 1 if computed explicitly by pair->compute via sum over pair interactions // 2 if computed implicitly by pair->virial_fdotr_compute via sum over ghosts if (force->newton_pair) virial_style = 2; else virial_style = 1; // setup lists of computes for global and per-atom PE and pressure ev_setup(); // detect if fix omp is present for clearing force arrays int ifix = modify->find_fix("package_omp"); if (ifix >= 0) external_force_clear = 1; // set flags for what arrays to clear in force_clear() // need to clear additionals arrays if they exist torqueflag = 0; if (atom->torque_flag) torqueflag = 1; erforceflag = 0; if (atom->erforce_flag) erforceflag = 1; e_flag = 0; if (atom->e_flag) e_flag = 1; rho_flag = 0; if (atom->rho_flag) rho_flag = 1; // orthogonal vs triclinic simulation box triclinic = domain->triclinic; } /* ---------------------------------------------------------------------- setup before run ------------------------------------------------------------------------- */ void Verlet::setup() { if (comm->me == 0 && screen) fprintf(screen,"Setting up run ...\n"); update->setupflag = 1; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists atom->setup(); modify->setup_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); if (atom->sortfreq > 0) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); domain->image_check(); domain->box_too_small_check(); modify->setup_pre_neighbor(); neighbor->build(); neighbor->ncalls = 0; // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (pair_compute_flag) force->pair->compute(eflag,vflag); else if (force->pair) force->pair->compute_dummy(eflag,vflag); if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); } if (force->kspace) { force->kspace->setup(); if (kspace_compute_flag) force->kspace->compute(eflag,vflag); else force->kspace->compute_dummy(eflag,vflag); } if (force->newton) comm->reverse_comm(); modify->setup(vflag); output->setup(); update->setupflag = 0; } /* ---------------------------------------------------------------------- setup without output flag = 0 = just force calculation flag = 1 = reneighbor and force calculation ------------------------------------------------------------------------- */ void Verlet::setup_minimal(int flag) { update->setupflag = 1; // setup domain, communication and neighboring // acquire ghosts // build neighbor lists if (flag) { modify->setup_pre_exchange(); if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); comm->exchange(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); domain->image_check(); domain->box_too_small_check(); modify->setup_pre_neighbor(); neighbor->build(); neighbor->ncalls = 0; } // compute all forces ev_set(update->ntimestep); force_clear(); modify->setup_pre_force(vflag); if (pair_compute_flag) force->pair->compute(eflag,vflag); else if (force->pair) force->pair->compute_dummy(eflag,vflag); if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); } if (force->kspace) { force->kspace->setup(); if (kspace_compute_flag) force->kspace->compute(eflag,vflag); else force->kspace->compute_dummy(eflag,vflag); } if (force->newton) comm->reverse_comm(); modify->setup(vflag); update->setupflag = 0; } /* ---------------------------------------------------------------------- run for N steps ------------------------------------------------------------------------- */ void Verlet::run(int n) { bigint ntimestep; int nflag,sortflag; int n_post_integrate = modify->n_post_integrate; int n_pre_exchange = modify->n_pre_exchange; int n_pre_neighbor = modify->n_pre_neighbor; int n_pre_force = modify->n_pre_force; int n_post_force = modify->n_post_force; int n_end_of_step = modify->n_end_of_step; if (atom->sortfreq > 0) sortflag = 1; else sortflag = 0; for (int i = 0; i < n; i++) { ntimestep = ++update->ntimestep; ev_set(ntimestep); // initial time integration timer->stamp(); modify->initial_integrate(vflag); if (n_post_integrate) modify->post_integrate(); timer->stamp(Timer::MODIFY); // regular communication vs neighbor list rebuild nflag = neighbor->decide(); if (nflag == 0) { timer->stamp(); comm->forward_comm(); timer->stamp(Timer::COMM); } else { if (n_pre_exchange) { timer->stamp(); modify->pre_exchange(); timer->stamp(Timer::MODIFY); } if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); if (domain->box_change) { domain->reset_box(); comm->setup(); if (neighbor->style) neighbor->setup_bins(); } timer->stamp(); comm->exchange(); if (sortflag && ntimestep >= atom->nextsort) atom->sort(); comm->borders(); if (triclinic) domain->lamda2x(atom->nlocal+atom->nghost); timer->stamp(Timer::COMM); if (n_pre_neighbor) { modify->pre_neighbor(); timer->stamp(Timer::MODIFY); } neighbor->build(); timer->stamp(Timer::NEIGHBOR); } // force computations // important for pair to come before bonded contributions // since some bonded potentials tally pairwise energy/virial // and Pair:ev_tally() needs to be called before any tallying force_clear(); timer->stamp(); if (n_pre_force) { modify->pre_force(vflag); timer->stamp(Timer::MODIFY); } if (pair_compute_flag) { force->pair->compute(eflag,vflag); timer->stamp(Timer::PAIR); } if (atom->molecular) { if (force->bond) force->bond->compute(eflag,vflag); if (force->angle) force->angle->compute(eflag,vflag); if (force->dihedral) force->dihedral->compute(eflag,vflag); if (force->improper) force->improper->compute(eflag,vflag); timer->stamp(Timer::BOND); } if (kspace_compute_flag) { force->kspace->compute(eflag,vflag); timer->stamp(Timer::KSPACE); } // reverse communication of forces if (force->newton) { comm->reverse_comm(); timer->stamp(Timer::COMM); } // force modifications, final time integration, diagnostics if (n_post_force) modify->post_force(vflag); modify->final_integrate(); if (n_end_of_step) modify->end_of_step(); timer->stamp(Timer::MODIFY); // all output if (ntimestep == output->next) { timer->stamp(); output->write(ntimestep); timer->stamp(Timer::OUTPUT); } } } /* ---------------------------------------------------------------------- */ void Verlet::cleanup() { modify->post_run(); domain->box_too_small_check(); + update->update_time(); } /* ---------------------------------------------------------------------- clear force on own & ghost atoms clear other arrays as needed ------------------------------------------------------------------------- */ void Verlet::force_clear() { int i; if (external_force_clear) return; // clear force on all particles // if either newton flag is set, also include ghosts // when using threads always clear all forces. if (neighbor->includegroup == 0) { int nall; if (force->newton) nall = atom->nlocal + atom->nghost; else nall = atom->nlocal; size_t nbytes = sizeof(double) * nall; if (nbytes > 0) { memset(&(atom->f[0][0]),0,3*nbytes); if (torqueflag) memset(&(atom->torque[0][0]),0,3*nbytes); if (erforceflag) memset(&(atom->erforce[0]), 0, nbytes); if (e_flag) memset(&(atom->de[0]), 0, nbytes); if (rho_flag) memset(&(atom->drho[0]), 0, nbytes); } // neighbor includegroup flag is set // clear force only on initial nfirst particles // if either newton flag is set, also include ghosts } else { int nall = atom->nfirst; double **f = atom->f; for (i = 0; i < nall; i++) { f[i][0] = 0.0; f[i][1] = 0.0; f[i][2] = 0.0; } if (torqueflag) { double **torque = atom->torque; for (i = 0; i < nall; i++) { torque[i][0] = 0.0; torque[i][1] = 0.0; torque[i][2] = 0.0; } } if (erforceflag) { double *erforce = atom->erforce; for (i = 0; i < nall; i++) erforce[i] = 0.0; } if (e_flag) { double *de = atom->de; for (i = 0; i < nall; i++) de[i] = 0.0; } if (rho_flag) { double *drho = atom->drho; for (i = 0; i < nall; i++) drho[i] = 0.0; } if (force->newton) { nall = atom->nlocal + atom->nghost; for (i = atom->nlocal; i < nall; i++) { f[i][0] = 0.0; f[i][1] = 0.0; f[i][2] = 0.0; } if (torqueflag) { double **torque = atom->torque; for (i = atom->nlocal; i < nall; i++) { torque[i][0] = 0.0; torque[i][1] = 0.0; torque[i][2] = 0.0; } } if (erforceflag) { double *erforce = atom->erforce; for (i = atom->nlocal; i < nall; i++) erforce[i] = 0.0; } if (e_flag) { double *de = atom->de; for (i = 0; i < nall; i++) de[i] = 0.0; } if (rho_flag) { double *drho = atom->drho; for (i = 0; i < nall; i++) drho[i] = 0.0; } } } } diff --git a/src/version.h b/src/version.h index 81efb3170..5d67f892b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "14 May 2013" +#define LAMMPS_VERSION "24 May 2013"